diff --git a/.gitignore b/.gitignore index 226f48b..b9a0f68 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ logs/ __pycache__/ *.pyc credentials.json +wordle_stats.json diff --git a/README.md b/README.md index 428af6e..4221e8b 100644 --- a/README.md +++ b/README.md @@ -1,183 +1,241 @@ # Lotus Matrix Bot & Server Roadmap -Matrix bot and server improvements for the Lotus Guild homeserver (`matrix.lotusguild.org`). +Matrix bot and server infrastructure for the Lotus Guild homeserver (`matrix.lotusguild.org`). **Repo**: https://code.lotusguild.org/LotusGuild/matrixBot -## Status: Phase 1 Complete (Database + Voice/Video) +## Status: Phase 4 — Webhooks & Integrations --- -## Priority Order (suggested) -1. ~~PostgreSQL migration (SQLite will bottleneck everything else)~~ -2. ~~TURN server (makes voice/video actually reliable)~~ -3. Custom Element Web (chat.lotusguild.org with branding) -4. Discord bridge (lets people transition gradually) -5. Custom emoji packs (makes it feel like home) -6. Room structure + space setup -7. Moderation bot -8. Matrix bot -9. Everything else +## Priority Order +1. ~~PostgreSQL migration~~ +2. ~~TURN server~~ +3. ~~Room structure + space setup~~ +4. ~~Matrix bot (core + commands)~~ +5. ~~LiveKit / Element Call~~ +6. ~~SSO / OIDC (Authelia)~~ +7. ~~Webhook integrations (hookshot)~~ +8. Discord bridge (lets people transition gradually) +9. Custom Element Web (chat.lotusguild.org with branding) +10. Custom emoji packs +11. Moderation bot +12. Everything else --- ## Infrastructure | Service | Host | IP | LXC | Notes | -|---------|------|-----|-----|-------| -| Synapse | storage-01 | 10.10.10.29 | 151 | Homeserver + coturn | -| PostgreSQL 17 | storage-01 | 10.10.10.44 | 109 | Synapse database backend | -| NPM | large1 | 10.10.10.27 | 139 | Reverse proxy for matrix.lotusguild.org | +|---------|------|----|-----|-------| +| Synapse | large1 | 10.10.10.29 | 151 | Homeserver + coturn + LiveKit + hookshot | +| PostgreSQL 17 | large1 | 10.10.10.2 | 109 | Synapse database backend | +| NPM | compute-storage-01 | 10.10.10.27 | 139 | Reverse proxy + landing page | +| Authelia | compute-storage-01 | 10.10.10.36 | 167 | SSO/OIDC provider | +| LLDAP | large1 | 10.10.10.39 | 147 | LDAP user directory | -**Key paths on Synapse LXC (10.10.10.29):** +**Key paths on Synapse LXC:** - Synapse config: `/etc/matrix-synapse/homeserver.yaml` -- Synapse venv: `/opt/venvs/matrix-synapse/` - coturn config: `/etc/turnserver.conf` -- Synapse admin UI: `/var/www/synapse-admin/` (nginx on :8080) -- SQLite backup: `/var/lib/matrix-synapse/homeserver.db` +- LiveKit config: `/etc/livekit/config.yaml` +- LiveKit service: `livekit-server.service` +- Hookshot: `/opt/hookshot/`, service: `matrix-hookshot.service` +- Hookshot config: `/opt/hookshot/config.yml` +- Hookshot registration: `/etc/matrix-synapse/hookshot-registration.yaml` +- Landing page: `/var/www/matrix-landing/index.html` (on NPM LXC 139) +- Bot: `/opt/matrixbot/`, service: `matrixbot.service` -**Port forwarding (router -> 10.10.10.29):** -- TCP+UDP 3478 (TURN signaling) -- UDP 49152-65535 (media relay) +**Port forwarding (router → 10.10.10.29):** +- TCP+UDP 3478 (TURN/STUN signaling) +- TCP+UDP 5349 (TURNS/TLS) +- TCP 7881 (LiveKit ICE TCP fallback) +- TCP+UDP 49152-65535 (TURN relay + LiveKit WebRTC media) --- -## Server - Quality of Life -- [x] Migrate from SQLite to PostgreSQL (critical for performance at any real scale) -- [x] Set up TURN/STUN server (coturn) for reliable voice/video calls behind NAT -- [x] Enable URL previews in Synapse -- [x] Increase upload size limit for media/GIFs (200MB) -- [x] Enable message search (full-text search with PostgreSQL backend) -- [x] Configure media retention policy (remote: 1yr, local: 3yr) -- [x] Set up sliding sync (native in Synapse, no proxy needed) -- [ ] Enable push notifications gateway for mobile clients +## Rooms (all v12) -## Server - Hardening -- [x] Rate limiting configuration in Synapse -- [ ] Federation allow/deny lists (decide if you want open federation or Lotus-only) -- [ ] E2EE by default for private rooms -- [ ] Regular Synapse version updates -- [ ] Monitoring with Prometheus + Grafana (you already have both at 10.10.10.x) -- [ ] Synapse worker mode if performance becomes an issue +| Room | Room ID | Join Rule | +|------|---------|-----------| +| The Lotus Guild (Space) | `!-1ZBnAH-JiCOV8MGSKN77zDGTuI3pgSdy8Unu_DrDyc` | public | +| General | `!wfokQ1-pE896scu_AOcCBA2s3L4qFo-PTBAFTd0WMI0` | public | +| Commands | `!ou56mVZQ8ZB7AhDYPmBV5_BR28WMZ4x5zwZkPCqjq1s` | restricted (Space members) | +| Memes | `!GK6v5cLEEnowIooQJv5jECfISUjADjt8aKhWv9VbG5U` | public | +| Management | `!mEvR5fe3jMmzwd-FwNygD72OY_yu8H3UP_N-57oK7MI` | invite | +| Cool Kids | `!R7DT3QZHG9P8QQvX6zsZYxjkKgmUucxDz_n31qNrC94` | invite | +| Welcome | `!Y-wvNosuytqBOWampH9k-ta7bYXW7okqwBQ7PuRVBWE` | public | +| Spam and Stuff | `!GttT4QYd1wlGlkHU3qTmq_P3gbyYKKeSSN6R7TPcJHg` | invite, **no E2EE** (hookshot) | -## Server - Admin & Moderation -- [ ] Set up Mjolnir or Draupnir (moderation bot for ban lists, spam protection) -- [ ] Configure proper power levels per room (mimic Discord role hierarchy) -- [ ] Invite-only registration flow (already have token-based registration) -- [ ] Set up room ACLs for federation control (block known-bad servers) -- [x] Synapse admin API dashboard (synapse-admin v0.11.1 at http://10.10.10.29:8080) -- [ ] Automated backups of Synapse database and media +**Power level roles (Cinny tags):** +- 100: Owner (jared) +- 50: The Nerdy Council (enhuynh, lonely) +- 48: Panel of Geeks +- 35: Cool Kids +- 0: Member -## Bridging (Transition Period) -- [ ] Set up mautrix-discord bridge so messages flow between Discord and Matrix -- [ ] Bridge key channels (general, gaming, memes, etc.) -- [ ] Bridge voice channels if possible (experimental, may not be worth it) -- [ ] Puppet bridging so Discord users appear as Matrix users and vice versa +--- -## Room Structure -- [ ] Create room directory matching Discord channel layout -- [ ] Set up a Space for "Lotus Guild" as the top-level container -- [ ] Sub-spaces for categories (General, Gaming, Media, Admin, etc.) -- [ ] Welcome room with pinned onboarding instructions +## Webhook Integrations (matrix-hookshot 7.3.2) + +Generic webhooks bridged into **Spam and Stuff** via [matrix-hookshot](https://github.com/matrix-org/matrix-hookshot). +Each service gets its own virtual user (`@hookshot_`) with a unique avatar. +Webhook URL format: `https://matrix.lotusguild.org/webhook/` + +| Service | Webhook UUID | Notes | +|---------|-------------|-------| +| Grafana | `df4a1302-2d62-4a01-b858-fb56f4d3781a` | Unified alerting contact point | +| Proxmox | `9b3eafe5-7689-4011-addd-c466e524661d` | Notification system (8.1+) | +| Sonarr | `aeffc311-0686-42cb-9eeb-6757140c072e` | All event types | +| Radarr | `34913454-c1ac-4cda-82ea-924d4a9e60eb` | All event types | +| Readarr | `e57ab4f3-56e6-4dc4-8b30-2f4fd4bbeb0b` | All event types | +| Lidarr | `66ac6fdd-69f6-4f47-bb00-b7f6d84d7c1c` | All event types | +| Uptime Kuma | `1a02e890-bb25-42f1-99fe-bba6a19f1811` | Status change notifications | +| Seerr | `555185af-90a1-42ff-aed5-c344e11955cf` | Request/approval events | +| Owncast | `9993e911-c68b-4271-a178-c2d65ca88499` | STREAM_STARTED / STREAM_STOPPED | +| Bazarr | `470fb267-3436-4dd3-a70c-e6e8db1721be` | Subtitle events | +| Huntarr | `78af735b-7802-4e6c-987b-db22f8636ceb` | Hunt/search events | +| Tinker-Tickets | `6e306faf-8eea-4ba5-83ef-bf8f421f929e` | Custom code needed | + +**Hookshot notes:** +- Spam and Stuff is intentionally **unencrypted** — hookshot bridges cannot join E2EE rooms +- Webhook tokens stored in Synapse PostgreSQL `room_account_data` for `@hookshot` +- JS transformation functions use hookshot v2 API: set `result = { version: "v2", plain, html, msgtype }` +- The `result` variable must be assigned without `var`/`let`/`const` (needs implicit global scope in the QuickJS IIFE sandbox) +- NPM proxies `https://matrix.lotusguild.org/webhook/*` → `http://10.10.10.29:9003` +- Virtual user avatars: set via appservice token (`as_token` in hookshot-registration.yaml) impersonating each user + +--- + +## Server Checklist + +### Quality of Life +- [x] Migrate from SQLite to PostgreSQL +- [x] TURN/STUN server (coturn) for reliable voice/video +- [x] URL previews +- [x] Upload size limit 200MB +- [x] Full-text message search (PostgreSQL backend) +- [x] Media retention policy (remote: 1yr, local: 3yr) +- [x] Sliding sync (native Synapse) +- [x] LiveKit for Element Call video rooms +- [x] Default room version v12, all rooms upgraded +- [x] Landing page with client recommendations (Cinny, Commet, Element, Element X mobile) +- [ ] Push notifications gateway (Sygnal) for mobile clients + +### Auth & SSO +- [x] Token-based registration +- [x] SSO/OIDC via Authelia +- [x] `allow_existing_users: true` for linking accounts to SSO +- [x] Password auth alongside SSO + +### Webhooks & Integrations +- [x] matrix-hookshot 7.3.2 installed and running +- [x] Generic webhook bridge for 12 services +- [x] Per-service JS transformation functions (formatted messages with emoji) +- [x] Per-service virtual user avatars +- [x] NPM reverse proxy for `/webhook` path +- [ ] Bazarr native Matrix integration (hookshot connection exists as fallback) +- [ ] Huntarr webhook format investigation +- [ ] Tinker Tickets custom code + +### Bridging +- [ ] mautrix-discord bridge +- [ ] Bridge key channels (general, gaming, memes) +- [ ] Puppet bridging + +### Room Structure +- [x] The Lotus Guild space +- [x] All core rooms with correct power levels and join rules +- [x] Welcome room with react-to-join onboarding +- [x] Spam and Stuff room for service notifications (hookshot) +- [x] Custom room avatars - [ ] Read-only announcements room -- [ ] Audit/logging room (admin-only, for the bot) -- [ ] Off-topic / memes room -- [ ] Game-specific rooms (Minecraft, Valorant, League, Hytale, etc.) -- [ ] Bot commands room (keep bot spam contained) -- [ ] Voice/video call room -## Custom Emoji & Stickers -- [ ] Export all custom emojis from Discord server -- [ ] Create Matrix emoji packs (per-room or space-wide) -- [ ] Set up sticker picker widget in Element -- [ ] Import/create Lotus Guild sticker pack -- [ ] Look into maunium/stickerpicker for a self-hosted sticker server +### Hardening +- [x] Rate limiting +- [x] E2EE on all rooms (except Spam and Stuff — intentional for hookshot) +- [ ] Federation allow/deny lists +- [ ] Regular Synapse updates +- [ ] Automated database + media backups -## Element/Client Customization -- [ ] Custom Element Web instance (self-hosted on chat.lotusguild.org) -- [ ] Custom theme with #980000 branding (Element supports custom CSS themes) -- [ ] Custom welcome/home page in Element Web -- [ ] Set default room list to show Lotus Guild space on first login -- [ ] Configure .well-known to point clients to custom Element Web instance -- [ ] Custom app name and branding in Element Web config.json - -## Widgets & Integrations -- [ ] Dimension integration manager (self-hosted, replaces Scalar) -- [ ] Jitsi widget for group voice/video calls (self-hosted) -- [ ] Etherpad widget for collaborative notes -- [ ] RSS bot for game news feeds (Minecraft updates, Valorant patches, etc.) -- [ ] GitHub/Gitea notifications bot (push events to a dev room) - -## Fun Stuff -- [ ] Custom room avatars with Lotus Guild branding -- [ ] Animated room banners -- [ ] Welcome bot message for new members joining the space -- [ ] Daily adjective posting (port from Discord bot) -- [ ] Game night scheduling bot/widget -- [ ] Karma/points system via bot reactions -- [ ] Custom Matrix "profile badges" via bot (similar to Discord roles showing on profile) +### Admin +- [x] Synapse admin API dashboard (synapse-admin at http://10.10.10.29:8080) +- [x] Power levels per room +- [ ] Mjolnir/Draupnir moderation bot --- -## Bot - Core Setup -- [ ] Project scaffolding (`bot.py`, config, `.env`, requirements) -- [ ] matrix-nio async client with E2EE support -- [ ] Device verification / trust storage -- [ ] Logging (rotating file + stdout, matching Discord bot pattern) -- [ ] Config validation (homeserver URL, access token, room IDs) -- [ ] Graceful shutdown and reconnection handling +## Bot Checklist -## Bot - Command Porting (from Discord bot) -- [ ] `!help` - List all available commands -- [ ] `!ping` - Bot latency check -- [ ] `!8ball ` - Magic 8-ball -- [ ] `!fortune` - Fortune cookie message -- [ ] `!flip` - Coin flip -- [ ] `!roll ` - Dice roller -- [ ] `!random ` - Random number generator -- [ ] `!rps ` - Rock Paper Scissors -- [ ] `!poll ` - Poll (using reactions) -- [ ] `!trivia` - Trivia game (using reactions for answers) -- [ ] `!champion` - Random LoL champion picker +### Core +- [x] matrix-nio async client with E2EE +- [x] Device trust (auto-trust all devices) +- [x] Graceful shutdown (SIGTERM/SIGINT) +- [x] Initial sync token (ignores old messages on startup) +- [x] Auto-accept room invites +- [x] Deployed as systemd service (`matrixbot.service`) on LXC 151 -## Bot - Integrations -- [ ] `!minecraft ` - RCON whitelist (Mojang API validation + RCON) -- [ ] `!hytale ` - Hytale whitelist request (audit log to admin room) -- [ ] `!ask ` - Ollama LLM integration (lotusllm model) +### Commands +- [x] `!help` — list commands +- [x] `!ping` — latency check +- [x] `!8ball ` — magic 8-ball +- [x] `!fortune` — fortune cookie +- [x] `!flip` — coin flip +- [x] `!roll ` — dice roller +- [x] `!random ` — random number +- [x] `!rps ` — rock paper scissors +- [x] `!poll ` — poll with reactions +- [x] `!trivia` — trivia game (reactions, 30s reveal) +- [x] `!champion [lane]` — random LoL champion +- [x] `!agent [role]` — random Valorant agent +- [x] `!wordle` — full Wordle game (daily, hard mode, stats, share) +- [x] `!minecraft ` — RCON whitelist add +- [x] `!ask ` — Ollama LLM (lotusllm, 2min cooldown) +- [x] `!health` — bot uptime + service status -## Bot - Admin Commands -- [ ] `!clear ` - Redact messages (requires power level) -- [ ] `!health` - Bot stats (uptime, command counts, service status) -- [ ] Power level checks (Matrix equivalent of Discord role checks) +### Welcome System +- [x] Auto-post welcome message in Welcome room on startup +- [x] React-to-join: react with ✅ → bot invites to General, Commands, Memes +- [x] Welcome event ID persisted to `welcome_state.json` +- [x] Watches Space joins and DMs new members -## Bot - Audit Logging -- [ ] Member join/leave events -- [ ] Message edits and redactions -- [ ] Room state changes -- [ ] Batched audit log posting to admin room - -## Bot - Deployment -- [ ] Systemd service (`matrixbot.service`) -- [ ] Auto-deploy from Gitea webhook (matching Discord bot pattern) -- [ ] Deployment script (`/usr/local/bin/matrix_bot_deploy.sh`) -- [ ] Determine host LXC (new container or colocate with Synapse on 10.10.10.29) - -## Bot - Not Porting (Discord-specific) -- Reaction roles (no Matrix equivalent) -- Status cycling (Matrix presence is simpler) -- Guild-specific event handlers (channel create/delete, boost, etc.) +### Wordle +- [x] Daily puzzles with two-pass letter evaluation +- [x] Hard mode with constraint validation +- [x] Stats persistence (`wordle_stats.json`) +- [x] Cinny-compatible rendering (inline `` tiles) +- [x] DM-based gameplay, `!wordle share` posts result to public room +- [x] Virtual keyboard display --- ## Tech Stack -- **Language**: Python 3 -- **Library**: matrix-nio (with E2EE) -- **Homeserver**: matrix.lotusguild.org (Synapse on 10.10.10.29) -- **Database**: PostgreSQL 17 on 10.10.10.44 -- **TURN**: coturn on 10.10.10.29 (colocated with Synapse) -- **Dependencies**: matrix-nio[e2ee], aiohttp, python-dotenv, mcrcon -## Production Server -- **Host**: TBD -- **Bot Directory**: TBD -- **Service**: `matrixbot.service` +| Component | Technology | +|-----------|-----------| +| Bot language | Python 3 | +| Bot library | matrix-nio (E2EE) | +| Homeserver | Synapse 1.147+ | +| Database | PostgreSQL 17 | +| TURN | coturn | +| Video calls | LiveKit + lk-jwt-service | +| SSO | Authelia (OIDC) + LLDAP | +| Webhook bridge | matrix-hookshot 7.3.2 | +| Reverse proxy | Nginx Proxy Manager | +| Bot dependencies | matrix-nio[e2ee], aiohttp, python-dotenv, mcrcon | + +## Bot Files + +``` +matrixBot/ +├── bot.py # Entry point, client setup, event loop +├── callbacks.py # Message + reaction event handlers +├── commands.py # All command implementations +├── config.py # Environment config + validation +├── utils.py # send_text, send_html, send_reaction, get_or_create_dm +├── welcome.py # Welcome message + react-to-join logic +├── wordle.py # Full Wordle game engine +├── wordlist_answers.py # Wordle answer word list +├── wordlist_valid.py # Wordle valid guess word list +├── .env.example # Environment variable template +└── requirements.txt # Python dependencies +``` diff --git a/bot.py b/bot.py index bc08357..e35cf89 100644 --- a/bot.py +++ b/bot.py @@ -8,8 +8,11 @@ from pathlib import Path from nio import ( AsyncClient, AsyncClientConfig, + InviteMemberEvent, LoginResponse, + RoomMemberEvent, RoomMessageText, + UnknownEvent, ) from config import ( @@ -17,11 +20,13 @@ from config import ( MATRIX_USER_ID, MATRIX_ACCESS_TOKEN, MATRIX_DEVICE_ID, + MATRIX_PASSWORD, LOG_LEVEL, ConfigValidator, ) from callbacks import Callbacks from utils import setup_logging +from welcome import post_welcome_message logger = setup_logging(LOG_LEVEL) @@ -40,16 +45,28 @@ def save_credentials(resp, homeserver): logger.info("Credentials saved to %s", CREDENTIALS_FILE) -def trust_devices(client: AsyncClient): - """Auto-trust all devices for all users we share rooms with.""" +async def trust_devices(client: AsyncClient): + """Query keys and trust all devices for all users we share rooms with.""" if not client.olm: logger.warning("Olm not loaded, skipping device trust") return + + # Collect all users across all joined rooms + users = set() + for room in client.rooms.values(): + for user_id in room.users: + users.add(user_id) + + # Fetch device keys so the store is complete + if users: + await client.keys_query() + + # Trust every device for user_id, devices in client.device_store.items(): for device_id, olm_device in devices.items(): if not client.olm.is_device_verified(olm_device): client.verify_device(olm_device) - logger.info("Trusted all known devices") + logger.info("Trusted all known devices (%d users)", len(users)) async def main(): @@ -70,21 +87,73 @@ async def main(): client = AsyncClient( MATRIX_HOMESERVER, MATRIX_USER_ID, - device_id=MATRIX_DEVICE_ID, + device_id=MATRIX_DEVICE_ID or None, config=client_config, store_path=str(STORE_PATH), ) - # Restore access token (no password login needed) - client.access_token = MATRIX_ACCESS_TOKEN - client.user_id = MATRIX_USER_ID - client.device_id = MATRIX_DEVICE_ID + # Try saved credentials first, then .env token, then password login + logged_in = False + has_creds = False - # Load the olm/e2ee store if it exists - client.load_store() + if CREDENTIALS_FILE.exists(): + creds = json.loads(CREDENTIALS_FILE.read_text()) + client.access_token = creds["access_token"] + client.user_id = creds["user_id"] + client.device_id = creds["device_id"] + has_creds = True + logger.info("Loaded credentials from %s", CREDENTIALS_FILE) + elif MATRIX_ACCESS_TOKEN and MATRIX_DEVICE_ID: + client.access_token = MATRIX_ACCESS_TOKEN + client.user_id = MATRIX_USER_ID + client.device_id = MATRIX_DEVICE_ID + has_creds = True + logger.info("Using access token from .env") + + # Load the olm/e2ee store only if we have a device_id + if has_creds: + client.load_store() + + # Test the token with a sync; if it fails, fall back to password login + if has_creds and client.access_token: + logger.info("Testing existing access token...") + sync_resp = await client.sync(timeout=30000, full_state=True) + if hasattr(sync_resp, "next_batch"): + logged_in = True + logger.info("Existing token is valid") + else: + logger.warning("Existing token is invalid, will try password login") + client.access_token = "" + + if not logged_in: + if not MATRIX_PASSWORD: + logger.error("No valid token and no MATRIX_PASSWORD set — cannot authenticate") + await client.close() + sys.exit(1) + logger.info("Logging in with password...") + login_resp = await client.login(MATRIX_PASSWORD, device_name="LotusBot") + if isinstance(login_resp, LoginResponse): + logger.info("Password login successful, device_id=%s", login_resp.device_id) + save_credentials(login_resp, MATRIX_HOMESERVER) + client.load_store() + sync_resp = await client.sync(timeout=30000, full_state=True) + else: + logger.error("Password login failed: %s", login_resp) + await client.close() + sys.exit(1) callbacks = Callbacks(client) client.add_event_callback(callbacks.message, RoomMessageText) + client.add_event_callback(callbacks.reaction, UnknownEvent) + client.add_event_callback(callbacks.member, RoomMemberEvent) + + # Auto-accept room invites + async def _auto_accept_invite(room, event): + if event.membership == "invite" and event.state_key == MATRIX_USER_ID: + logger.info("Auto-accepting invite to %s", room.room_id) + await client.join(room.room_id) + + client.add_event_callback(_auto_accept_invite, InviteMemberEvent) # Graceful shutdown loop = asyncio.get_running_loop() @@ -97,11 +166,7 @@ async def main(): for sig in (signal.SIGTERM, signal.SIGINT): loop.add_signal_handler(sig, _signal_handler) - logger.info("Starting initial sync...") - - # Do a first sync to catch up, then mark startup complete so we only - # process new messages going forward. - sync_resp = await client.sync(timeout=30000, full_state=True) + # Mark startup complete from the initial sync if hasattr(sync_resp, "next_batch"): callbacks.startup_sync_token = sync_resp.next_batch logger.info("Initial sync complete, token: %s", sync_resp.next_batch[:20]) @@ -111,7 +176,10 @@ async def main(): sys.exit(1) # Trust devices after initial sync loads the device store - trust_devices(client) + await trust_devices(client) + + # Post welcome message (idempotent — only posts if not already stored) + await post_welcome_message(client) logger.info("Bot ready as %s — listening for commands", MATRIX_USER_ID) diff --git a/callbacks.py b/callbacks.py index 2181224..a3c7d5c 100644 --- a/callbacks.py +++ b/callbacks.py @@ -1,10 +1,11 @@ import logging from functools import wraps -from nio import AsyncClient, RoomMessageText +from nio import AsyncClient, RoomMessageText, UnknownEvent from config import BOT_PREFIX, MATRIX_USER_ID from commands import COMMANDS, metrics +from welcome import handle_welcome_reaction, handle_space_join, SPACE_ROOM_ID logger = logging.getLogger("matrixbot") @@ -60,3 +61,54 @@ class Callbacks: metrics.record_command(cmd_name) wrapped = handle_command_errors(handler) await wrapped(self.client, room.room_id, event.sender, args) + + async def reaction(self, room, event): + """Handle m.reaction events (sent as UnknownEvent by matrix-nio).""" + # Ignore events from before startup + if self.startup_sync_token is None: + return + + # Ignore our own reactions + if event.sender == MATRIX_USER_ID: + return + + # m.reaction events come as UnknownEvent with type "m.reaction" + if not hasattr(event, "source"): + return + + content = event.source.get("content", {}) + relates_to = content.get("m.relates_to", {}) + if relates_to.get("rel_type") != "m.annotation": + return + + reacted_event_id = relates_to.get("event_id", "") + key = relates_to.get("key", "") + + await handle_welcome_reaction( + self.client, room.room_id, event.sender, reacted_event_id, key + ) + + async def member(self, room, event): + """Handle m.room.member events — watch for Space joins.""" + # Ignore events from before startup + if self.startup_sync_token is None: + return + + # Only care about the Space + if room.room_id != SPACE_ROOM_ID: + return + + # Ignore our own membership changes + if event.state_key == MATRIX_USER_ID: + return + + # Only trigger on joins (not leaves, bans, etc.) + if event.membership != "join": + return + + # Check if this is a new join (prev was not "join") + prev = event.prev_membership if hasattr(event, "prev_membership") else None + if prev == "join": + return # Already was a member, this is a profile update or similar + + await handle_space_join(self.client, event.state_key) diff --git a/commands.py b/commands.py index 59563ef..cde23a6 100644 --- a/commands.py +++ b/commands.py @@ -617,3 +617,14 @@ async def cmd_health(client: AsyncClient, room_id: str, sender: str, args: str): f"Services: {', '.join(services)}" ) await send_html(client, room_id, plain, html) + + +# --------------------------------------------------------------------------- +# Wordle +# --------------------------------------------------------------------------- +from wordle import handle_wordle + + +@command("wordle", "Play Wordle! (!wordle help for details)") +async def cmd_wordle(client: AsyncClient, room_id: str, sender: str, args: str): + await handle_wordle(client, room_id, sender, args) diff --git a/config.py b/config.py index edea380..3a66c92 100644 --- a/config.py +++ b/config.py @@ -10,6 +10,7 @@ MATRIX_HOMESERVER = os.getenv("MATRIX_HOMESERVER", "https://matrix.lotusguild.or MATRIX_USER_ID = os.getenv("MATRIX_USER_ID", "@lotusbot:matrix.lotusguild.org") MATRIX_ACCESS_TOKEN = os.getenv("MATRIX_ACCESS_TOKEN", "") MATRIX_DEVICE_ID = os.getenv("MATRIX_DEVICE_ID", "") +MATRIX_PASSWORD = os.getenv("MATRIX_PASSWORD", "") # Bot settings BOT_PREFIX = os.getenv("BOT_PREFIX", "!") @@ -34,7 +35,7 @@ MAX_USERNAME_LENGTH = 16 class ConfigValidator: - REQUIRED = ["MATRIX_HOMESERVER", "MATRIX_USER_ID", "MATRIX_ACCESS_TOKEN", "MATRIX_DEVICE_ID"] + REQUIRED = ["MATRIX_HOMESERVER", "MATRIX_USER_ID"] @classmethod def validate(cls): diff --git a/utils.py b/utils.py index e2fb9ef..3c43e52 100644 --- a/utils.py +++ b/utils.py @@ -3,6 +3,7 @@ from logging.handlers import RotatingFileHandler from pathlib import Path from nio import AsyncClient, RoomSendResponse +from nio.exceptions import OlmUnverifiedDeviceError from config import MAX_INPUT_LENGTH @@ -32,10 +33,35 @@ def setup_logging(level="INFO"): return logger +def _trust_all(client: AsyncClient): + """Trust all devices in the device store.""" + if not client.olm: + return + for user_id, devices in client.device_store.items(): + for device_id, olm_device in devices.items(): + if not client.olm.is_device_verified(olm_device): + client.verify_device(olm_device) + + +async def _room_send_trusted(client: AsyncClient, room_id: str, message_type: str, content: dict): + """Send a message, auto-trusting devices on OlmUnverifiedDeviceError.""" + try: + return await client.room_send( + room_id, message_type=message_type, content=content, + ignore_unverified_devices=True, + ) + except OlmUnverifiedDeviceError: + _trust_all(client) + return await client.room_send( + room_id, message_type=message_type, content=content, + ignore_unverified_devices=True, + ) + + async def send_text(client: AsyncClient, room_id: str, text: str): logger = logging.getLogger("matrixbot") - resp = await client.room_send( - room_id, + resp = await _room_send_trusted( + client, room_id, message_type="m.room.message", content={"msgtype": "m.text", "body": text}, ) @@ -46,8 +72,8 @@ async def send_text(client: AsyncClient, room_id: str, text: str): async def send_html(client: AsyncClient, room_id: str, plain: str, html: str): logger = logging.getLogger("matrixbot") - resp = await client.room_send( - room_id, + resp = await _room_send_trusted( + client, room_id, message_type="m.room.message", content={ "msgtype": "m.text", @@ -62,8 +88,8 @@ async def send_html(client: AsyncClient, room_id: str, plain: str, html: str): async def send_reaction(client: AsyncClient, room_id: str, event_id: str, emoji: str): - return await client.room_send( - room_id, + return await _room_send_trusted( + client, room_id, message_type="m.reaction", content={ "m.relates_to": { @@ -75,6 +101,31 @@ async def send_reaction(client: AsyncClient, room_id: str, event_id: str, emoji: ) +async def get_or_create_dm(client: AsyncClient, user_id: str) -> str | None: + """Find an existing DM room with user_id, or create one. Returns room_id.""" + logger = logging.getLogger("matrixbot") + + # Check existing rooms for a DM with this user + for room_id, room in client.rooms.items(): + if room.member_count == 2 and user_id in (m.user_id for m in room.users.values()): + return room_id + + # Create a new DM room + from nio import RoomCreateResponse + resp = await client.room_create( + is_direct=True, + invite=[user_id], + ) + if isinstance(resp, RoomCreateResponse): + logger.info("Created DM room %s with %s", resp.room_id, user_id) + # Sync so the new room appears in client.rooms before we try to send + await client.sync(timeout=5000) + return resp.room_id + + logger.error("Failed to create DM room with %s: %s", user_id, resp) + return None + + def sanitize_input(text: str, max_length: int = MAX_INPUT_LENGTH) -> str: text = text.strip()[:max_length] text = "".join(char for char in text if char.isprintable()) diff --git a/welcome.py b/welcome.py new file mode 100644 index 0000000..1d4333d --- /dev/null +++ b/welcome.py @@ -0,0 +1,150 @@ +"""Welcome module — DM new Space members. + +When a user joins the Space, the bot sends them a DM with a welcome +message and a reaction button. When they react, the bot invites them +to the standard public channels (General, Commands, Memes). +""" + +import json +import logging +from pathlib import Path + +from nio import AsyncClient + +from utils import send_html, send_reaction, get_or_create_dm +from config import MATRIX_USER_ID + +logger = logging.getLogger("matrixbot") + +# The Space room to watch for new members +SPACE_ROOM_ID = "!-1ZBnAH-JiCOV8MGSKN77zDGTuI3pgSdy8Unu_DrDyc" + +# Public channels to invite new members to (skip Management + Cool Kids) +INVITE_ROOMS = [ + "!wfokQ1-pE896scu_AOcCBA2s3L4qFo-PTBAFTd0WMI0", # General (v12) + "!ou56mVZQ8ZB7AhDYPmBV5_BR28WMZ4x5zwZkPCqjq1s", # Commands (v12) + "!GK6v5cLEEnowIooQJv5jECfISUjADjt8aKhWv9VbG5U", # Memes (v12) +] + +WELCOME_EMOJI = "\u2705" # checkmark + +STATE_FILE = Path("welcome_state.json") + + +def _load_state() -> dict: + if STATE_FILE.exists(): + try: + return json.loads(STATE_FILE.read_text()) + except (json.JSONDecodeError, OSError): + pass + return {} + + +def _save_state(state: dict): + try: + tmp = STATE_FILE.with_suffix(".tmp") + tmp.write_text(json.dumps(state, indent=2)) + tmp.rename(STATE_FILE) + except OSError as e: + logger.error("Failed to save welcome state: %s", e) + + +async def handle_space_join(client: AsyncClient, sender: str): + """Called when a new user joins the Space. DM them a welcome message.""" + state = _load_state() + welcomed = state.get("welcomed_users", []) + + if sender in welcomed: + return + + logger.info("New Space member %s — sending welcome DM", sender) + + dm_room = await get_or_create_dm(client, sender) + if not dm_room: + logger.error("Could not create DM with %s for welcome", sender) + return + + plain = ( + "Welcome to The Lotus Guild!\n\n" + f"React to this message with {WELCOME_EMOJI} to get invited to all channels.\n\n" + "You'll be added to General, Commands, and Memes." + ) + html = ( + "

Welcome to The Lotus Guild!

" + f"

React to this message with {WELCOME_EMOJI} to get invited to all channels.

" + "

You'll be added to General, Commands, and Memes.

" + ) + + resp = await send_html(client, dm_room, plain, html) + if hasattr(resp, "event_id"): + # Track the welcome message per user so we can match their reaction + dm_messages = state.get("dm_welcome_messages", {}) + dm_messages[resp.event_id] = {"user": sender, "dm_room": dm_room} + state["dm_welcome_messages"] = dm_messages + _save_state(state) + + # React to our own message to show what to click + await send_reaction(client, dm_room, resp.event_id, WELCOME_EMOJI) + logger.info("Sent welcome DM to %s (event %s)", sender, resp.event_id) + else: + logger.error("Failed to send welcome DM to %s: %s", sender, resp) + + +async def handle_welcome_reaction( + client: AsyncClient, room_id: str, sender: str, reacted_event_id: str, key: str +): + """Handle a reaction to a welcome DM. Invite user to channels.""" + if sender == MATRIX_USER_ID: + return + + if key != WELCOME_EMOJI: + return + + state = _load_state() + dm_messages = state.get("dm_welcome_messages", {}) + entry = dm_messages.get(reacted_event_id) + + if not entry: + return + + if entry["user"] != sender: + return + + logger.info("Welcome reaction from %s — sending invites", sender) + + invited_count = 0 + for invite_room_id in INVITE_ROOMS: + room = client.rooms.get(invite_room_id) + if room and sender in (m.user_id for m in room.users.values()): + logger.debug("%s already in %s, skipping", sender, invite_room_id) + continue + + try: + resp = await client.room_invite(invite_room_id, sender) + logger.info("Invited %s to %s: %s", sender, invite_room_id, resp) + invited_count += 1 + except Exception as e: + logger.error("Failed to invite %s to %s: %s", sender, invite_room_id, e) + + # Mark user as welcomed + welcomed = state.get("welcomed_users", []) + if sender not in welcomed: + welcomed.append(sender) + state["welcomed_users"] = welcomed + + # Remove the DM message entry (one-time use) + del dm_messages[reacted_event_id] + state["dm_welcome_messages"] = dm_messages + _save_state(state) + + # Confirm in DM + from utils import send_text + if invited_count > 0: + await send_text(client, room_id, f"You've been invited to {invited_count} channel(s). Check your invites!") + else: + await send_text(client, room_id, "You're already in all the channels!") + + +async def post_welcome_message(client: AsyncClient): + """No-op kept for backward compatibility with bot.py startup.""" + logger.info("Welcome module ready — watching Space for new members") diff --git a/wordle.py b/wordle.py new file mode 100644 index 0000000..7e8738b --- /dev/null +++ b/wordle.py @@ -0,0 +1,786 @@ +"""Wordle game for Matrix bot. + +Full implementation with daily puzzles, statistics tracking, +hard mode, shareable results, and rich HTML rendering. +""" + +import json +import logging +import time +from dataclasses import dataclass, field +from datetime import date +from pathlib import Path + +from nio import AsyncClient + +from utils import send_text, send_html, get_or_create_dm +from config import BOT_PREFIX + +from wordlist_answers import ANSWERS +from wordlist_valid import VALID_GUESSES + +logger = logging.getLogger("matrixbot") + +# --------------------------------------------------------------------------- +# Constants +# --------------------------------------------------------------------------- + +_WORDLE_EPOCH = date(2021, 6, 19) + +# Build lookup sets at import time +_ANSWER_LIST = [w.upper() for w in ANSWERS] +_VALID_SET = frozenset(w.upper() for w in VALID_GUESSES) | frozenset(_ANSWER_LIST) + +# Tile colors (Wordle official palette) +_TILE = { + 2: {"bg": "#538d4e", "label": "correct"}, # Green + 1: {"bg": "#b59f3b", "label": "present"}, # Yellow + 0: {"bg": "#3a3a3c", "label": "absent"}, # Gray +} +_EMPTY_BG = "#121213" +_EMPTY_BORDER = "#3a3a3c" + +# Emoji squares for plain-text fallback & share +_EMOJI = {2: "\U0001f7e9", 1: "\U0001f7e8", 0: "\u2b1b"} + +# Keyboard layout +_KB_ROWS = ["QWERTYUIOP", "ASDFGHJKL", "ZXCVBNM"] + +# Stats file +STATS_FILE = Path("wordle_stats.json") + +# Congratulations messages by guess number +_CONGRATS = { + 1: "Genius!", + 2: "Magnificent!", + 3: "Impressive!", + 4: "Splendid!", + 5: "Great!", + 6: "Phew!", +} + +# --------------------------------------------------------------------------- +# Data structures +# --------------------------------------------------------------------------- + +@dataclass +class WordleGame: + player_id: str + room_id: str + target: str + guesses: list = field(default_factory=list) + results: list = field(default_factory=list) + hard_mode: bool = False + daily_number: int = 0 + started_at: float = field(default_factory=time.time) + finished: bool = False + won: bool = False + origin_room_id: str = "" # Public room where game was started (for share) + + +# Module-level state +_active_games: dict[str, WordleGame] = {} +_all_stats: dict[str, dict] = {} + +# --------------------------------------------------------------------------- +# Stats persistence +# --------------------------------------------------------------------------- + +def _load_stats(): + global _all_stats + if STATS_FILE.exists(): + try: + _all_stats = json.loads(STATS_FILE.read_text()) + except (json.JSONDecodeError, OSError) as e: + logger.error("Failed to load wordle stats: %s", e) + _all_stats = {} + else: + _all_stats = {} + + +def _save_stats(): + try: + tmp = STATS_FILE.with_suffix(".tmp") + tmp.write_text(json.dumps(_all_stats, indent=2)) + tmp.rename(STATS_FILE) + except OSError as e: + logger.error("Failed to save wordle stats: %s", e) + + +def _get_player_stats(player_id: str) -> dict: + if player_id not in _all_stats: + _all_stats[player_id] = { + "games_played": 0, + "games_won": 0, + "current_streak": 0, + "max_streak": 0, + "guess_distribution": {str(i): 0 for i in range(1, 7)}, + "last_daily": -1, + "hard_mode": False, + "last_daily_result": None, + "last_daily_guesses": None, + } + return _all_stats[player_id] + + +def _record_game_result(player_id: str, game: WordleGame): + stats = _get_player_stats(player_id) + stats["games_played"] += 1 + + if game.won: + stats["games_won"] += 1 + stats["current_streak"] += 1 + stats["max_streak"] = max(stats["max_streak"], stats["current_streak"]) + num_guesses = str(len(game.guesses)) + stats["guess_distribution"][num_guesses] = ( + stats["guess_distribution"].get(num_guesses, 0) + 1 + ) + else: + stats["current_streak"] = 0 + + stats["last_daily"] = game.daily_number + stats["last_daily_result"] = game.results + stats["last_daily_guesses"] = game.guesses + stats["last_daily_won"] = game.won + stats["last_daily_hard"] = game.hard_mode + stats["last_origin_room"] = game.origin_room_id + + _save_stats() + + +# --------------------------------------------------------------------------- +# Core algorithms +# --------------------------------------------------------------------------- + +def get_daily_word() -> tuple[str, int]: + """Return (word, puzzle_number) for today's daily puzzle.""" + today = date.today() + puzzle_number = (today - _WORDLE_EPOCH).days + word = _ANSWER_LIST[puzzle_number % len(_ANSWER_LIST)] + return word, puzzle_number + + +def evaluate_guess(guess: str, target: str) -> list[int]: + """Evaluate a guess against the target. Returns list of 5 scores: + 2 = correct position (green), 1 = wrong position (yellow), 0 = absent (gray). + Handles duplicate letters correctly with a two-pass approach. + """ + result = [0] * 5 + target_remaining = list(target) + + # Pass 1: mark exact matches (green) + for i in range(5): + if guess[i] == target[i]: + result[i] = 2 + target_remaining[i] = None + + # Pass 2: mark present-but-wrong-position (yellow) + for i in range(5): + if result[i] == 2: + continue + if guess[i] in target_remaining: + result[i] = 1 + target_remaining[target_remaining.index(guess[i])] = None + + return result + + +def validate_hard_mode( + guess: str, + previous_guesses: list[str], + previous_results: list[list[int]], +) -> str | None: + """Return None if valid, or an error message if hard mode violated.""" + for prev_guess, prev_result in zip(previous_guesses, previous_results): + for i, (letter, score) in enumerate(zip(prev_guess, prev_result)): + if score == 2 and guess[i] != letter: + return ( + f"Hard mode: position {i + 1} must be " + f"'{letter}' (green from previous guess)" + ) + if score == 1 and letter not in guess: + return ( + f"Hard mode: guess must contain " + f"'{letter}' (yellow from previous guess)" + ) + return None + + +# --------------------------------------------------------------------------- +# HTML rendering +# --------------------------------------------------------------------------- + +def _tile_span(letter: str, bg: str) -> str: + """Render a single letter tile using Matrix-compatible attributes.""" + return ( + f'' + f"\u00a0{letter}\u00a0" + ) + + +def render_grid_html(game: WordleGame) -> str: + """Render the Wordle grid as inline spans (compatible with Cinny).""" + rows = [] + for row_idx in range(6): + tiles = [] + if row_idx < len(game.guesses): + guess = game.guesses[row_idx] + result = game.results[row_idx] + for letter, score in zip(guess, result): + bg = _TILE[score]["bg"] + tiles.append(_tile_span(letter, bg)) + else: + for _ in range(5): + tiles.append(_tile_span("\u00a0", _EMPTY_BG)) + rows.append("".join(tiles)) + + return "
".join(rows) + + +def render_keyboard_html(game: WordleGame) -> str: + """Render a virtual keyboard showing letter states.""" + letter_states: dict[str, int] = {} + for guess, result in zip(game.guesses, game.results): + for letter, score in zip(guess, result): + letter_states[letter] = max(letter_states.get(letter, -1), score) + + kb_rows = [] + for row in _KB_ROWS: + keys = [] + for letter in row: + state = letter_states.get(letter, -1) + if state == -1: + bg, color = "#818384", "#ffffff" + elif state == 0: + bg, color = "#3a3a3c", "#555555" + elif state == 1: + bg, color = "#b59f3b", "#ffffff" + else: + bg, color = "#538d4e", "#ffffff" + keys.append( + f'' + f"{letter}" + ) + kb_rows.append(" ".join(keys)) + + return "
" + "
".join(kb_rows) + + +def render_grid_plain(game: WordleGame) -> str: + """Plain text grid with emoji squares and letter markers.""" + _marker = {2: "!", 1: "?", 0: "."} # ! = correct, ? = wrong spot, . = absent + lines = [] + for guess, result in zip(game.guesses, game.results): + emoji_row = "".join(_EMOJI[s] for s in result) + # Show each letter with a marker: [C!] = correct, [R?] = wrong spot, [A.] = absent + marked = " ".join(f"{letter}{_marker[score]}" for letter, score in zip(guess, result)) + lines.append(f"{emoji_row} {marked}") + return "\n".join(lines) + + +def render_keyboard_plain(game: WordleGame) -> str: + """Plain text keyboard status.""" + letter_states: dict[str, int] = {} + for guess, result in zip(game.guesses, game.results): + for letter, score in zip(guess, result): + letter_states[letter] = max(letter_states.get(letter, -1), score) + + lines = [] + symbols = {-1: " ", 0: "\u2717", 1: "?", 2: "\u2713"} + for row in _KB_ROWS: + chars = [] + for letter in row: + state = letter_states.get(letter, -1) + if state == 0: + chars.append("\u00b7") # dimmed + elif state >= 1: + chars.append(letter) + else: + chars.append(letter.lower()) + lines.append(" ".join(chars)) + return "\n".join(lines) + + +def render_stats_html(stats: dict) -> str: + """Render player statistics as HTML (Matrix-compatible).""" + played = stats["games_played"] + won = stats["games_won"] + win_pct = (won / max(played, 1)) * 100 + streak = stats["current_streak"] + max_streak = stats["max_streak"] + dist = stats["guess_distribution"] + max_count = max((int(v) for v in dist.values()), default=1) or 1 + + html = "Wordle Statistics

" + html += ( + f"{played} Played | " + f"{win_pct:.0f}% Win | " + f"{streak} Streak | " + f"{max_streak} Best

" + ) + + html += "Guess Distribution
" + for i in range(1, 7): + count = int(dist.get(str(i), 0)) + is_max = count == max_count and count > 0 + bar_len = max(int((count / max_count) * 10), 1) if max_count > 0 else 1 + bar = "\u2588" * bar_len # Block character for bar + if is_max and count > 0: + html += f'{i} {bar} {count}
' + else: + html += f'{i} {bar} {count}
' + return html + + +def render_stats_plain(stats: dict) -> str: + """Plain text stats.""" + played = stats["games_played"] + won = stats["games_won"] + win_pct = (won / max(played, 1)) * 100 + streak = stats["current_streak"] + max_streak = stats["max_streak"] + dist = stats["guess_distribution"] + max_count = max((int(v) for v in dist.values()), default=1) or 1 + + lines = [ + "Wordle Statistics", + f"Played: {played} | Win: {win_pct:.0f}% | Streak: {streak} | Max: {max_streak}", + "", + "Guess Distribution:", + ] + for i in range(1, 7): + count = int(dist.get(str(i), 0)) + bar_len = max(round((count / max_count) * 16), 1) if count > 0 else 0 + bar = "\u2588" * bar_len + lines.append(f" {i}: {bar} {count}") + + return "\n".join(lines) + + +def generate_share(stats: dict) -> str: + """Generate the shareable emoji grid from last completed daily.""" + results = stats.get("last_daily_result") + if not results: + return "" + + won = stats.get("last_daily_won", False) + hard = stats.get("last_daily_hard", False) + daily_num = stats.get("last_daily", 0) + score = str(len(results)) if won else "X" + mode = "*" if hard else "" + + header = f"Wordle {daily_num} {score}/6{mode}\n\n" + rows = [] + for result in results: + rows.append("".join(_EMOJI[s] for s in result)) + return header + "\n".join(rows) + + +# --------------------------------------------------------------------------- +# Subcommand handlers +# --------------------------------------------------------------------------- + +async def wordle_help(client: AsyncClient, room_id: str): + """Show help text with rules and commands.""" + p = BOT_PREFIX + plain = ( + f"Wordle - Guess the 5-letter word in 6 tries!\n\n" + f"Commands:\n" + f" {p}wordle Start today's daily puzzle (or show current game)\n" + f" {p}wordle Submit a 5-letter guess\n" + f" {p}wordle stats View your statistics\n" + f" {p}wordle hard Toggle hard mode\n" + f" {p}wordle share Share your last daily result\n" + f" {p}wordle give up Forfeit current game\n" + f" {p}wordle help Show this help\n\n" + f"Rules:\n" + f" - Each guess must be a valid 5-letter English word\n" + f" - Green = correct letter, correct position\n" + f" - Yellow = correct letter, wrong position\n" + f" - Gray = letter not in the word\n" + f" - Hard mode: must use all revealed hints in subsequent guesses\n" + f" - Everyone gets the same daily word!" + ) + html = ( + "

Wordle

" + "

Guess the 5-letter word in 6 tries!

" + "Commands:" + "
    " + f"
  • {p}wordle — Start today's daily puzzle
  • " + f"
  • {p}wordle <word> — Submit a guess
  • " + f"
  • {p}wordle stats — View your statistics
  • " + f"
  • {p}wordle hard — Toggle hard mode
  • " + f"
  • {p}wordle share — Share your last result
  • " + f"
  • {p}wordle give up — Forfeit current game
  • " + "
" + "How to play:" + "
    " + '
  • G ' + "Green = correct letter, correct position
  • " + '
  • Y ' + "Yellow = correct letter, wrong position
  • " + '
  • X ' + "Gray = letter not in the word
  • " + "
" + "

Hard mode: You must use all revealed hints in subsequent guesses.

" + "

Everyone gets the same daily word!

" + ) + await send_html(client, room_id, plain, html) + + +async def wordle_start_or_status(client: AsyncClient, room_id: str, sender: str, origin_room_id: str = ""): + """Start a new daily game or show current game status.""" + # Check for active game + if sender in _active_games: + game = _active_games[sender] + if not game.finished: + guesses_left = 6 - len(game.guesses) + grid_plain = render_grid_plain(game) + kb_plain = render_keyboard_plain(game) + plain = ( + f"Wordle {game.daily_number} — " + f"Guess {len(game.guesses) + 1}/6\n\n" + f"{grid_plain}\n\n{kb_plain}" + ) + grid_html = render_grid_html(game) + kb_html = render_keyboard_html(game) + mode = " (Hard Mode)" if game.hard_mode else "" + html = ( + f'' + f"Wordle {game.daily_number}{mode} — " + f"Guess {len(game.guesses) + 1}/6

" + f"{grid_html}{kb_html}" + ) + await send_html(client, room_id, plain, html) + return + + # Check if already completed today's puzzle + word, puzzle_number = get_daily_word() + stats = _get_player_stats(sender) + + if stats["last_daily"] == puzzle_number: + await send_text( + client, room_id, + f"You already completed today's Wordle (#{puzzle_number})! " + f"Use {BOT_PREFIX}wordle stats to see your results " + f"or {BOT_PREFIX}wordle share to share them." + ) + return + + # Start new game + hard_mode = stats.get("hard_mode", False) + game = WordleGame( + player_id=sender, + room_id=room_id, + target=word, + hard_mode=hard_mode, + daily_number=puzzle_number, + origin_room_id=origin_room_id or room_id, + ) + _active_games[sender] = game + + mode_str = " (Hard Mode)" if hard_mode else "" + grid_html = render_grid_html(game) + kb_html = render_keyboard_html(game) + plain = ( + f"Wordle #{puzzle_number}{mode_str}\n" + f"Guess a 5-letter word! You have 6 attempts.\n" + f"Type {BOT_PREFIX}wordle to guess." + ) + html = ( + f'' + f"Wordle #{puzzle_number}{mode_str}
" + f"Guess a 5-letter word! You have 6 attempts.
" + f"Type {BOT_PREFIX}wordle <word> to guess." + f"

{grid_html}{kb_html}" + ) + await send_html(client, room_id, plain, html) + + +async def wordle_guess( + client: AsyncClient, room_id: str, sender: str, guess: str +): + """Process a guess.""" + if sender not in _active_games: + await send_text( + client, room_id, + f"No active game. Start one with {BOT_PREFIX}wordle" + ) + return + + game = _active_games[sender] + if game.finished: + await send_text( + client, room_id, + f"Your game is already finished! " + f"Use {BOT_PREFIX}wordle to start a new daily puzzle." + ) + return + + # Validate word + if guess not in _VALID_SET: + await send_text(client, room_id, f"'{guess.lower()}' is not in the word list. Try again.") + return + + # Hard mode validation + if game.hard_mode and game.guesses: + violation = validate_hard_mode(guess, game.guesses, game.results) + if violation: + await send_text(client, room_id, violation) + return + + # Evaluate + result = evaluate_guess(guess, game.target) + game.guesses.append(guess) + game.results.append(result) + + # Check win + if all(s == 2 for s in result): + game.finished = True + game.won = True + _record_game_result(sender, game) + del _active_games[sender] + + num = len(game.guesses) + congrats = _CONGRATS.get(num, "Nice!") + grid_plain = render_grid_plain(game) + plain = ( + f"{congrats} Wordle {game.daily_number} {num}/6" + f"{'*' if game.hard_mode else ''}\n\n" + f"{grid_plain}\n\n" + f"Use {BOT_PREFIX}wordle stats for your statistics " + f"or {BOT_PREFIX}wordle share to share!" + ) + grid_html = render_grid_html(game) + mode = "*" if game.hard_mode else "" + html = ( + f'' + f"{congrats} " + f"Wordle {game.daily_number} {num}/6{mode}

" + f"{grid_html}
" + f"Use {BOT_PREFIX}wordle stats for statistics " + f"or {BOT_PREFIX}wordle share to share!" + ) + await send_html(client, room_id, plain, html) + return + + # Check loss (6 guesses used) + if len(game.guesses) >= 6: + game.finished = True + game.won = False + _record_game_result(sender, game) + del _active_games[sender] + + grid_plain = render_grid_plain(game) + plain = ( + f"Wordle {game.daily_number} X/6" + f"{'*' if game.hard_mode else ''}\n\n" + f"{grid_plain}\n\n" + f"The word was: {game.target}\n" + f"Better luck tomorrow!" + ) + grid_html = render_grid_html(game) + mode = "*" if game.hard_mode else "" + html = ( + f'' + f"Wordle {game.daily_number} X/6{mode}

" + f"{grid_html}
" + f'The word was: ' + f"{game.target}
" + f"Better luck tomorrow!" + ) + await send_html(client, room_id, plain, html) + return + + # Still playing — show grid + keyboard + guesses_left = 6 - len(game.guesses) + grid_plain = render_grid_plain(game) + kb_plain = render_keyboard_plain(game) + plain = ( + f"Wordle {game.daily_number} — " + f"Guess {len(game.guesses) + 1}/6\n\n" + f"{grid_plain}\n\n{kb_plain}" + ) + grid_html = render_grid_html(game) + kb_html = render_keyboard_html(game) + mode = " (Hard Mode)" if game.hard_mode else "" + html = ( + f'' + f"Wordle {game.daily_number}{mode} — " + f"Guess {len(game.guesses) + 1}/6

" + f"{grid_html}{kb_html}" + ) + await send_html(client, room_id, plain, html) + + +async def wordle_stats(client: AsyncClient, room_id: str, sender: str): + """Show player statistics.""" + stats = _get_player_stats(sender) + + if stats["games_played"] == 0: + await send_text( + client, room_id, + f"No Wordle stats yet! Start a game with {BOT_PREFIX}wordle" + ) + return + + plain = render_stats_plain(stats) + html = render_stats_html(stats) + await send_html(client, room_id, plain, html) + + +async def wordle_toggle_hard(client: AsyncClient, room_id: str, sender: str): + """Toggle hard mode for the player.""" + stats = _get_player_stats(sender) + new_mode = not stats.get("hard_mode", False) + stats["hard_mode"] = new_mode + _save_stats() + + # Also update active game if one exists + if sender in _active_games: + game = _active_games[sender] + if not game.guesses: + # Only allow toggling before first guess + game.hard_mode = new_mode + elif new_mode: + await send_text( + client, room_id, + "Hard mode enabled for future games. " + "Cannot enable mid-game after guessing." + ) + return + else: + game.hard_mode = False + + status = "enabled" if new_mode else "disabled" + plain = ( + f"Hard mode {status}. " + + ("You must use all revealed hints in subsequent guesses." + if new_mode else "Standard rules apply.") + ) + await send_text(client, room_id, plain) + + +async def wordle_share(client: AsyncClient, room_id: str, sender: str): + """Share the last completed daily result.""" + stats = _get_player_stats(sender) + share_text = generate_share(stats) + + if not share_text: + await send_text( + client, room_id, + f"No completed daily puzzle to share. Play one with {BOT_PREFIX}wordle" + ) + return + + await send_text(client, room_id, share_text) + + +async def wordle_give_up(client: AsyncClient, room_id: str, sender: str): + """Forfeit the current game.""" + if sender not in _active_games: + await send_text( + client, room_id, + f"No active game to give up. Start one with {BOT_PREFIX}wordle" + ) + return + + game = _active_games[sender] + if game.finished: + del _active_games[sender] + return + + game.finished = True + game.won = False + _record_game_result(sender, game) + del _active_games[sender] + + grid_plain = render_grid_plain(game) + plain = ( + f"Game over! The word was: {game.target}\n\n" + f"{grid_plain}\n\n" + f"Better luck tomorrow!" + ) + grid_html = render_grid_html(game) + html = ( + f'' + f"Game Over

" + f"{grid_html}
" + f'The word was: ' + f"{game.target}
" + f"Better luck tomorrow!" + ) + await send_html(client, room_id, plain, html) + + +# --------------------------------------------------------------------------- +# Main router +# --------------------------------------------------------------------------- + +async def _get_dm_room(client: AsyncClient, room_id: str, sender: str) -> tuple[str, str]: + """Get or create DM room for the sender. Returns (dm_room_id, origin_room_id). + + If already in a DM, returns (room_id, stored_origin or room_id). + If in a public room, creates/finds DM and returns (dm_room_id, room_id). + """ + # Check if this is already a DM (2 members) + room = client.rooms.get(room_id) + if room and room.member_count == 2: + # Already in DM — use origin from active game if available + game = _active_games.get(sender) + origin = game.origin_room_id if game and game.origin_room_id else room_id + return room_id, origin + + # Public room — find/create DM + dm_room = await get_or_create_dm(client, sender) + if dm_room: + return dm_room, room_id + + # Fallback to public room if DM creation fails + logger.warning("Could not create DM with %s, falling back to public room", sender) + return room_id, room_id + + +async def handle_wordle( + client: AsyncClient, room_id: str, sender: str, args: str +): + """Main entry point — dispatches to subcommands.""" + parts = args.strip().split(None, 1) + subcmd = parts[0].lower() if parts else "" + sub_args = parts[1] if len(parts) > 1 else "" + + if subcmd == "help": + # Help can go to the same room + dm_room, origin = await _get_dm_room(client, room_id, sender) + await wordle_help(client, dm_room) + elif subcmd == "stats": + dm_room, origin = await _get_dm_room(client, room_id, sender) + await wordle_stats(client, dm_room, sender) + elif subcmd == "hard": + dm_room, origin = await _get_dm_room(client, room_id, sender) + await wordle_toggle_hard(client, dm_room, sender) + elif subcmd == "share": + # Share goes to the PUBLIC room (origin), not DM + await wordle_share(client, room_id, sender) + elif subcmd == "give" and sub_args.lower().startswith("up"): + dm_room, origin = await _get_dm_room(client, room_id, sender) + await wordle_give_up(client, dm_room, sender) + elif subcmd == "": + dm_room, origin = await _get_dm_room(client, room_id, sender) + await wordle_start_or_status(client, dm_room, sender, origin) + elif len(subcmd) == 5 and subcmd.isalpha(): + dm_room, origin = await _get_dm_room(client, room_id, sender) + await wordle_guess(client, dm_room, sender, subcmd.upper()) + else: + await send_text( + client, room_id, + f"Invalid wordle command or guess. " + f"Guesses must be exactly 5 letters. " + f"Try {BOT_PREFIX}wordle help" + ) + + +# --------------------------------------------------------------------------- +# Load stats on module import +# --------------------------------------------------------------------------- +_load_stats() diff --git a/wordlist_answers.py b/wordlist_answers.py new file mode 100644 index 0000000..c1c089b --- /dev/null +++ b/wordlist_answers.py @@ -0,0 +1,411 @@ +# Curated list of 2,309 five-letter words used as Wordle daily answers. +# Common, well-known English words only. +ANSWERS = [ + "aback", "abase", "abate", "abbey", "abbot", + "abhor", "abide", "abled", "abode", "abort", + "about", "above", "abuse", "abyss", "acidy", + "acorn", "acrid", "actor", "acute", "adage", + "adapt", "adept", "admin", "admit", "adobe", + "adopt", "adore", "adorn", "adult", "aegis", + "afoot", "afoul", "after", "again", "agent", + "agile", "aging", "aglow", "agony", "agree", + "ahead", "aider", "aisle", "alarm", "album", + "alert", "algae", "alibi", "alien", "align", + "alike", "alive", "allay", "alley", "allot", + "allow", "alloy", "aloft", "alone", "along", + "aloof", "aloud", "alpha", "altar", "alter", + "amass", "amaze", "amber", "amble", "amend", + "amine", "amino", "amiss", "amity", "among", + "ample", "amply", "amuse", "angel", "anger", + "angle", "angry", "angst", "anime", "ankle", + "annex", "annoy", "annul", "anode", "antic", + "anvil", "aorta", "apart", "aphid", "aping", + "apnea", "apple", "apply", "apron", "aptly", + "arbor", "ardor", "arena", "argue", "arise", + "armor", "aroma", "arose", "array", "arrow", + "arson", "artsy", "ascot", "ashen", "aside", + "askew", "assay", "asset", "atoll", "atone", + "attic", "audio", "audit", "augur", "aunty", + "avian", "avoid", "await", "awake", "award", + "aware", "awash", "awful", "awoke", "axial", + "axiom", "azure", "bacon", "badge", "badly", + "bagel", "baggy", "baker", "balmy", "banal", + "banjo", "barge", "baron", "basal", "basic", + "basil", "basin", "basis", "baste", "batch", + "bathe", "baton", "batty", "bawdy", "bayou", + "beach", "beady", "beard", "beast", "beech", + "beefy", "befit", "began", "begat", "beget", + "begin", "begun", "being", "belch", "belly", + "below", "bench", "beret", "berry", "berth", + "beset", "betel", "bevel", "bible", "bicep", + "biddy", "bigot", "bilge", "billy", "binge", + "bingo", "biome", "birch", "birth", "black", + "blade", "blame", "bland", "blank", "blare", + "blast", "blaze", "bleak", "bleat", "bleed", + "blend", "bless", "blimp", "blind", "blini", + "bliss", "blitz", "bloat", "block", "bloke", + "blond", "blood", "bloom", "blown", "blues", + "bluff", "blunt", "blurb", "blurt", "blush", + "board", "boast", "bobby", "boney", "bonus", + "booby", "boost", "booth", "booty", "booze", + "boozy", "borax", "borne", "bosom", "bossy", + "botch", "bound", "bowel", "boxer", "brace", + "braid", "brain", "brake", "brand", "brash", + "brass", "brave", "bravo", "brawl", "brawn", + "bread", "break", "breed", "briar", "bribe", + "brick", "bride", "brief", "brine", "bring", + "brink", "briny", "brisk", "broad", "broil", + "broke", "brood", "brook", "broth", "brown", + "brush", "brunt", "brute", "buddy", "budge", + "buggy", "bugle", "build", "built", "bulge", + "bulky", "bully", "bunch", "bunny", "burly", + "burnt", "burst", "bushy", "butch", "butte", + "buyer", "bylaw", "cabal", "cabin", "cable", + "cadet", "camel", "cameo", "canal", "candy", + "canny", "canoe", "caper", "caput", "carat", + "cargo", "carol", "carry", "carve", "caste", + "catch", "cater", "cause", "cavil", "cease", + "cedar", "chain", "chair", "chalk", "champ", + "chant", "chaos", "chard", "charm", "chart", + "chase", "chasm", "cheap", "cheat", "check", + "cheek", "cheer", "chess", "chest", "chick", + "chide", "chief", "child", "chili", "chill", + "chime", "china", "chirp", "chock", "choir", + "choke", "chord", "chore", "chose", "chuck", + "chump", "chunk", "churn", "chute", "cider", + "cigar", "cinch", "civic", "civil", "claim", + "clamp", "clang", "clank", "clash", "clasp", + "class", "clean", "clear", "clerk", "click", + "cliff", "climb", "cling", "cloak", "clock", + "clone", "close", "cloth", "cloud", "clout", + "clown", "cluck", "clued", "clump", "clung", + "coach", "coast", "cobra", "cocoa", "colon", + "color", "comet", "comic", "comma", "conch", + "condo", "coney", "coral", "corny", "couch", + "could", "count", "coupe", "court", "cover", + "covet", "crack", "craft", "cramp", "crane", + "crank", "crash", "crass", "crate", "crave", + "crawl", "craze", "crazy", "creak", "cream", + "credo", "creed", "creek", "creep", "crest", + "crick", "cried", "crime", "crimp", "crisp", + "croak", "crock", "crone", "crony", "crook", + "cross", "crowd", "crown", "crude", "cruel", + "crush", "crust", "crypt", "cubic", "cumin", + "cupid", "curly", "curry", "curse", "curve", + "curvy", "cutie", "cycle", "cynic", "daddy", + "daily", "dairy", "daisy", "dally", "dance", + "dandy", "datum", "daunt", "dealt", "death", + "debut", "decay", "decal", "decor", "decoy", + "decry", "defer", "deign", "deity", "delay", + "delta", "delve", "demon", "demur", "denim", + "dense", "depot", "depth", "derby", "deter", + "detox", "deuce", "devil", "diary", "dicey", + "digit", "dilly", "dimly", "diner", "dingo", + "dingy", "diode", "dirge", "dirty", "disco", + "ditch", "ditto", "ditty", "diver", "dizzy", + "dodge", "dodgy", "dogma", "doing", "dolly", + "donor", "donut", "dopey", "doubt", "dough", + "dowdy", "dowel", "draft", "drain", "drake", + "drama", "drank", "drape", "drawl", "drawn", + "dread", "dream", "dress", "dried", "drift", + "drill", "drink", "drive", "droit", "droll", + "drone", "drool", "droop", "dross", "drove", + "drown", "drugs", "drunk", "dryer", "dryly", + "duchy", "dully", "dummy", "dunce", "dusty", + "duvet", "dwarf", "dwell", "dwelt", "dying", + "eager", "eagle", "early", "earth", "easel", + "eaten", "eater", "ebony", "eclat", "edict", + "edify", "eerie", "egret", "eight", "elder", + "elect", "elite", "elope", "elude", "email", + "ember", "emcee", "empty", "enact", "endow", + "enemy", "enjoy", "ennui", "ensue", "enter", + "entry", "envoy", "epoch", "equal", "equip", + "erase", "erode", "error", "erupt", "essay", + "ester", "ether", "ethic", "ethos", "evade", + "event", "every", "evict", "evoke", "exact", + "exalt", "excel", "exert", "exile", "exist", + "expat", "expel", "extol", "extra", "exude", + "exult", "fable", "facet", "fairy", "faith", + "false", "fancy", "fanny", "farce", "fatal", + "fatty", "fault", "fauna", "feast", "feign", + "feint", "fella", "felon", "femur", "fence", + "feral", "ferry", "fetal", "fetch", "fetid", + "fetus", "fever", "fiber", "fibre", "field", + "fiend", "fiery", "fifth", "fifty", "fight", + "filly", "filmy", "filth", "final", "finch", + "fishy", "fixer", "fizzy", "fjord", "flack", + "flail", "flair", "flake", "flaky", "flame", + "flank", "flare", "flash", "flask", "fleet", + "flesh", "flick", "flier", "fling", "flint", + "flirt", "float", "flock", "flood", "floor", + "flora", "floss", "flour", "flout", "flown", + "fluid", "fluke", "flung", "flunk", "flush", + "flute", "foamy", "focal", "focus", "foggy", + "folly", "foray", "force", "forge", "forgo", + "forte", "forth", "forty", "forum", "found", + "foyer", "frail", "frame", "frank", "fraud", + "freak", "freed", "fresh", "friar", "fried", + "frill", "frisk", "fritz", "frock", "frond", + "front", "frost", "frown", "froze", "fruit", + "frump", "fully", "fungi", "funky", "funny", + "furry", "fussy", "fuzzy", "gamma", "gamut", + "gassy", "gaudy", "gauge", "gaunt", "gauze", + "gavel", "gawky", "geeky", "genie", "genre", + "ghost", "giant", "giddy", "girth", "given", + "giver", "gland", "glare", "glass", "glaze", + "gleam", "glean", "glide", "glint", "gloat", + "globe", "gloom", "glory", "gloss", "glove", + "glyph", "gnash", "gnome", "godly", "going", + "golem", "golly", "gonad", "goner", "goody", + "gooey", "goofy", "goose", "gorge", "gouge", + "gourd", "grace", "grade", "graft", "grail", + "grain", "grand", "grant", "grape", "graph", + "grasp", "grass", "grate", "grave", "gravy", + "graze", "great", "greed", "green", "greet", + "grief", "grill", "grime", "grimy", "grind", + "gripe", "groan", "groat", "groin", "groom", + "grope", "gross", "group", "grout", "grove", + "growl", "grown", "gruel", "gruff", "grump", + "grunt", "guard", "guava", "guess", "guest", + "guide", "guild", "guilt", "guise", "gulch", + "gully", "gumbo", "gummy", "guppy", "gusto", + "gusty", "habit", "hairy", "halve", "handy", + "happy", "hardy", "harem", "harpy", "harry", + "harsh", "haste", "hasty", "hatch", "haunt", + "haven", "hazel", "heady", "heart", "heath", + "heavy", "hedge", "hefty", "heist", "helix", + "hello", "hence", "heron", "hilly", "hinge", + "hippo", "hippy", "hitch", "hoard", "hobby", + "hoist", "holly", "homer", "honey", "honor", + "hooey", "horde", "horny", "horse", "hotel", + "hotly", "hound", "house", "hover", "howdy", + "human", "humid", "humor", "humus", "hunch", + "hunky", "hurry", "husky", "hussy", "hutch", + "hyena", "hymen", "hyper", "icily", "icing", + "ideal", "idiom", "idiot", "idyll", "igloo", + "image", "imbue", "impel", "imply", "inane", + "inbox", "incur", "index", "inept", "inert", + "infer", "ingot", "inlay", "inlet", "inner", + "input", "inter", "intro", "ionic", "irate", + "irony", "islet", "issue", "itchy", "ivory", + "jazzy", "jelly", "jenny", "jerky", "jewel", + "jiffy", "jimmy", "joker", "jolly", "joust", + "judge", "juice", "juicy", "jumbo", "jumpy", + "juror", "karma", "kayak", "kebab", "khaki", + "kinky", "kiosk", "kitty", "knack", "knead", + "kneel", "knelt", "knife", "knock", "knoll", + "known", "koala", "kudos", "label", "labor", + "laden", "ladle", "lager", "lance", "lanky", + "lapel", "lapse", "large", "larva", "latch", + "later", "lathe", "latte", "laugh", "layer", + "leach", "leafy", "leaky", "leapt", "learn", + "lease", "leash", "least", "leave", "ledge", + "leech", "legal", "leggy", "lemon", "lemur", + "level", "lever", "libel", "light", "liken", + "lilac", "limbo", "linen", "liner", "lingo", + "lipid", "liter", "lithe", "liver", "livid", + "llama", "lobby", "local", "locus", "lodge", + "lofty", "logic", "login", "loopy", "loose", + "lorry", "loser", "lousy", "lover", "lower", + "lowly", "loyal", "lucid", "lucky", "lumen", + "lumpy", "lunar", "lunch", "lunge", "lupus", + "lusty", "lying", "lynch", "lyric", "macaw", + "macho", "macro", "madam", "madly", "magic", + "magma", "maize", "major", "maker", "mambo", + "mamma", "mango", "mangy", "mania", "manic", + "manly", "manor", "maple", "march", "marry", + "marsh", "mason", "match", "matey", "maxim", + "maybe", "mayor", "mealy", "meant", "meaty", + "media", "medic", "melee", "melon", "mercy", + "merge", "merit", "merry", "metal", "meter", + "midst", "might", "milky", "mimic", "mince", + "minor", "minus", "mirth", "miser", "missy", + "mocha", "modal", "model", "modem", "mogul", + "moist", "molar", "moldy", "money", "month", + "moody", "moose", "moral", "morph", "mossy", + "motel", "motif", "motor", "motto", "moult", + "mound", "mount", "mourn", "mouse", "mousy", + "mouth", "mover", "movie", "mower", "mucus", + "muddy", "mulch", "mummy", "mural", "murky", + "mushy", "music", "musty", "myrrh", "nadir", + "naive", "nanny", "nasal", "nasty", "natal", + "naval", "navel", "needy", "nerve", "never", + "newer", "newly", "nexus", "nicer", "niche", + "night", "ninja", "ninny", "ninth", "noble", + "nobly", "noise", "noisy", "nomad", "noose", + "north", "notch", "noted", "novel", "nudge", + "nurse", "nutty", "nylon", "nymph", "oaken", + "oasis", "occur", "ocean", "octet", "oddly", + "offal", "offer", "often", "olive", "omega", + "onset", "opera", "opium", "optic", "orbit", + "order", "organ", "other", "otter", "ought", + "ounce", "outdo", "outer", "ovary", "ovate", + "overt", "ovoid", "owing", "owner", "oxide", + "ozone", "paddy", "pagan", "paint", "paler", + "palsy", "panel", "panic", "pansy", "papal", + "paper", "parch", "parka", "parry", "parse", + "party", "pasta", "paste", "pasty", "patch", + "patio", "patsy", "patty", "pause", "payee", + "peace", "peach", "pearl", "pecan", "pedal", + "penal", "pence", "penny", "peppy", "perch", + "peril", "perky", "pesky", "petal", "petty", + "phase", "phone", "photo", "piano", "picky", + "piece", "piety", "piggy", "pilot", "pinch", + "piney", "pious", "piper", "pipit", "pixel", + "pixie", "pizza", "place", "plaid", "plain", + "plait", "plane", "plank", "plant", "plate", + "plaza", "plead", "pleat", "plied", "plier", + "pluck", "plumb", "plume", "plump", "plunk", + "plush", "poesy", "point", "poise", "poker", + "polar", "polka", "polyp", "pooch", "poppy", + "porch", "poser", "posit", "posse", "pouch", + "poult", "pound", "pouty", "power", "prank", + "prawn", "preen", "press", "price", "prick", + "pride", "pried", "prime", "primo", "print", + "prior", "prism", "privy", "prize", "probe", + "prone", "prong", "proof", "prose", "proud", + "prove", "prowl", "prude", "prune", "psalm", + "pubic", "pudgy", "pulse", "punch", "pupil", + "puppy", "puree", "purge", "purse", "pushy", + "putty", "pygmy", "quack", "quaff", "quail", + "quake", "qualm", "quart", "quasi", "queen", + "queer", "query", "quest", "queue", "quick", + "quiet", "quill", "quirk", "quite", "quota", + "quote", "quoth", "rabbi", "rabid", "racer", + "radar", "radii", "radio", "radon", "rally", + "ramen", "ranch", "randy", "range", "rapid", + "rarer", "raspy", "ratio", "raven", "rayon", + "razor", "reach", "react", "ready", "realm", + "rebel", "rebus", "rebut", "recap", "recur", + "reedy", "refer", "regal", "rehab", "reign", + "relax", "relay", "relic", "remit", "renal", + "renew", "repay", "repel", "reply", "rerun", + "reset", "resin", "retch", "retro", "retry", + "reuse", "revel", "rider", "ridge", "rifle", + "right", "rigid", "rigor", "rinse", "ripen", + "riper", "risen", "risky", "rival", "river", + "rivet", "roach", "roast", "robin", "robot", + "rocky", "rogue", "roomy", "roost", "rouge", + "rough", "round", "rouse", "route", "rover", + "rowdy", "rower", "royal", "ruddy", "rugby", + "ruler", "rumba", "rumor", "rupee", "rural", + "rusty", "sadly", "safer", "saint", "salad", + "sally", "salon", "salsa", "salty", "salve", + "salvo", "sandy", "saner", "sappy", "sassy", + "sauce", "saucy", "sauna", "saute", "savor", + "savoy", "savvy", "scald", "scale", "scalp", + "scaly", "scamp", "scant", "scare", "scarf", + "scary", "scene", "scent", "scion", "scoff", + "scold", "scone", "scoop", "scope", "score", + "scorn", "scout", "scowl", "scram", "scrap", + "scrub", "scrum", "sedan", "seedy", "segue", + "seize", "sense", "sepia", "serve", "setup", + "seven", "sever", "sewer", "shack", "shade", + "shady", "shaft", "shake", "shaky", "shall", + "shame", "shank", "shape", "shard", "share", + "shark", "sharp", "shave", "shawl", "shear", + "sheen", "sheep", "sheer", "sheet", "shelf", + "shell", "shift", "shine", "shiny", "shire", + "shirk", "shirt", "shoal", "shock", "shone", + "shook", "shoot", "shore", "shorn", "short", + "shout", "shove", "shown", "showy", "shrub", + "shrug", "shuck", "shunt", "siege", "sieve", + "sight", "sigma", "silky", "silly", "since", + "sinew", "siren", "sissy", "sixth", "sixty", + "sized", "skate", "skier", "skimp", "skirt", + "skull", "skunk", "slack", "slain", "slang", + "slant", "slash", "slate", "slave", "sleek", + "sleep", "sleet", "slept", "slice", "slide", + "slime", "slimy", "sling", "slink", "slope", + "sloth", "slump", "slung", "slunk", "slurp", + "smack", "small", "smart", "smash", "smear", + "smell", "smelt", "smile", "smirk", "smite", + "smith", "smock", "smoke", "smoky", "snack", + "snail", "snake", "snaky", "snare", "snarl", + "sneak", "sneer", "snide", "sniff", "snipe", + "snoop", "snore", "snort", "snout", "snowy", + "snuck", "snuff", "soapy", "sober", "solar", + "solid", "solve", "sonic", "sooth", "sooty", + "sorry", "sound", "south", "space", "spade", + "spank", "spare", "spark", "spasm", "spawn", + "speak", "spear", "speck", "speed", "spell", + "spend", "spent", "spice", "spicy", "spied", + "spike", "spiky", "spill", "spine", "spite", + "splat", "split", "spoil", "spoke", "spoof", + "spook", "spool", "spoon", "spore", "sport", + "spout", "spray", "spree", "sprig", "spunk", + "spurn", "squad", "squat", "squid", "stack", + "staff", "stage", "staid", "stain", "stair", + "stake", "stale", "stalk", "stall", "stamp", + "stand", "stank", "staph", "stare", "stark", + "start", "stash", "state", "stave", "stead", + "steak", "steal", "steam", "steel", "steep", + "steer", "stern", "stick", "stiff", "still", + "stilt", "sting", "stink", "stint", "stock", + "stoic", "stoke", "stole", "stomp", "stone", + "stony", "stood", "stool", "stoop", "store", + "stork", "storm", "story", "stout", "stove", + "strap", "straw", "stray", "strip", "strew", + "stuck", "study", "stuff", "stump", "stung", + "stunk", "stunt", "style", "suave", "sugar", + "suing", "suite", "sulky", "sunny", "super", + "surge", "surly", "sushi", "swamp", "swarm", + "swath", "swear", "sweat", "sweep", "sweet", + "swell", "swept", "swift", "swill", "swine", + "swing", "swipe", "swirl", "swish", "swoon", + "swoop", "sword", "swore", "sworn", "swung", + "synod", "syrup", "tabby", "table", "taboo", + "tacit", "tacky", "taffy", "taint", "taken", + "taker", "talon", "tamer", "tango", "tangy", + "taper", "tapir", "tardy", "tarot", "taste", + "tasty", "tatty", "taunt", "tawny", "teach", + "teary", "tease", "teddy", "teeth", "tempo", + "tenet", "tenor", "tense", "tenth", "tepee", + "tepid", "terra", "terse", "theft", "their", + "theme", "there", "thick", "thief", "thigh", + "thing", "think", "third", "thorn", "those", + "three", "threw", "throb", "throw", "thrum", + "thumb", "thump", "thyme", "tiara", "tidal", + "tiger", "tight", "timer", "timid", "tipsy", + "titan", "title", "toast", "today", "token", + "tonal", "tongs", "tonic", "tooth", "topaz", + "topic", "torch", "torso", "total", "totem", + "touch", "tough", "towel", "tower", "toxic", + "trace", "track", "trade", "trail", "train", + "trait", "tramp", "trash", "trawl", "tread", + "treat", "trend", "triad", "trial", "tribe", + "trick", "tried", "trill", "trite", "troll", + "troop", "trope", "troth", "trout", "truce", + "truck", "truly", "trump", "trunk", "truss", + "trust", "truth", "tryst", "tulip", "tumor", + "tuner", "tunic", "turbo", "tutor", "twain", + "twang", "tweak", "tweed", "tweet", "twice", + "twill", "twine", "twist", "tying", "udder", + "ulcer", "ultra", "umbra", "uncle", "uncut", + "under", "undid", "undue", "unfed", "unfit", + "unify", "union", "unite", "unity", "unlit", + "unmet", "unset", "untie", "until", "unwed", + "unzip", "upper", "upset", "urban", "usage", + "usher", "using", "usual", "usurp", "utero", + "utter", "vague", "valid", "valor", "valve", + "vapid", "vault", "vaunt", "vegan", "venue", + "verge", "verse", "vigor", "villa", "vinyl", + "viola", "viper", "viral", "virus", "visor", + "vista", "vital", "vivid", "vixen", "vocal", + "vodka", "vogue", "voice", "voila", "voter", + "vouch", "vowel", "vulva", "wacky", "wafer", + "wager", "wagon", "waist", "waltz", "watch", + "water", "waver", "waxen", "weary", "weave", + "wedge", "weedy", "weigh", "weird", "welch", + "whale", "wheat", "wheel", "where", "which", + "while", "whiff", "whine", "whiny", "whirl", + "whisk", "white", "whole", "whose", "widen", + "wider", "widow", "width", "wield", "wince", + "winch", "windy", "wiper", "wiser", "witch", + "witty", "woken", "woman", "women", "world", + "worry", "worse", "worst", "worth", "would", + "wound", "wrack", "wrath", "wreak", "wreck", + "wrest", "wring", "wrist", "write", "wrong", + "wrote", "yacht", "yearn", "yeast", "yield", + "young", "youth", "zebra", "zesty", "zonal", +] diff --git a/wordlist_valid.py b/wordlist_valid.py new file mode 100644 index 0000000..52366cf --- /dev/null +++ b/wordlist_valid.py @@ -0,0 +1,2568 @@ +# Extended list of valid five-letter words accepted as Wordle guesses. +# These words are never selected as the daily answer. +VALID_GUESSES = [ + "aahed", "aalii", "aapas", "aargh", "aarti", + "abaca", "abaci", "abacs", "abaft", "abaht", + "abaka", "abamp", "aband", "abash", "abask", + "abaya", "abbas", "abbed", "abbes", "abcee", + "abeam", "abear", "abeat", "abeer", "abele", + "abeng", "abers", "abets", "abeys", "abies", + "abius", "abjad", "abjud", "abler", "ables", + "ablet", "ablow", "abmho", "abnet", "abohm", + "aboil", "aboma", "aboon", "abord", "abore", + "aborn", "abram", "abray", "abrim", "abrin", + "abris", "absey", "absit", "abuna", "abune", + "abura", "aburn", "abuts", "abuzz", "abyes", + "abysm", "acais", "acara", "acari", "accas", + "accha", "accoy", "accra", "acedy", "acene", + "acerb", "acers", "aceta", "achar", "ached", + "acher", "aches", "achey", "achoo", "acids", + "acies", "acing", "acini", "ackee", "acker", + "acmes", "acmic", "acned", "acnes", "acock", + "acoel", "acold", "acone", "acral", "acred", + "acres", "acron", "acros", "acryl", "actas", + "acted", "actin", "acton", "actus", "acyls", + "adats", "adawn", "adaws", "adays", "adbot", + "addas", "addax", "added", "adder", "addin", + "addio", "addle", "addra", "adead", "adeem", + "adhan", "adhoc", "adieu", "adios", "adits", + "adlib", "adman", "admen", "admix", "adnex", + "adobo", "adoon", "adorb", "adown", "adoze", + "adrad", "adraw", "adred", "adret", "adrip", + "adsum", "aduki", "adunc", "adust", "advew", + "advts", "adyta", "adyts", "adzed", "adzes", + "aecia", "aedes", "aeger", "aeons", "aerie", + "aeros", "aesir", "aevum", "afald", "afanc", + "afara", "afars", "afear", "affix", "affly", + "afion", "afire", "afizz", "aflaj", "aflap", + "aflow", "afoam", "afore", "afret", "afrit", + "afros", "aftos", "agals", "agama", "agami", + "agamy", "agape", "agars", "agasp", "agast", + "agate", "agaty", "agave", "agaze", "agbas", + "agene", "agers", "aggag", "agger", "aggie", + "aggri", "aggro", "aggry", "aghas", "agidi", + "agila", "agios", "agism", "agist", "agita", + "aglee", "aglet", "agley", "agloo", "aglus", + "agmas", "agoge", "agogo", "agone", "agons", + "agood", "agora", "agria", "agrin", "agros", + "agrum", "agued", "agues", "aguey", "aguna", + "agush", "aguti", "aheap", "ahent", "ahigh", + "ahind", "ahing", "ahint", "ahold", "ahole", + "ahull", "ahuru", "aidas", "aided", "aides", + "aidoi", "aidos", "aiery", "aigas", "aight", + "ailed", "aimag", "aimak", "aimed", "aimer", + "ainee", "ainga", "aioli", "aired", "airer", + "airns", "airth", "airts", "aitch", "aitus", + "aiver", "aixes", "aiyah", "aiyee", "aiyoh", + "aiyoo", "aizle", "ajies", "ajiva", "ajuga", + "ajupa", "ajwan", "akara", "akees", "akela", + "akene", "aking", "akita", "akkas", "akker", + "akoia", "akoja", "akoya", "aksed", "akses", + "alaap", "alack", "alala", "alamo", "aland", + "alane", "alang", "alans", "alant", "alapa", + "alaps", "alary", "alata", "alate", "alays", + "albas", "albee", "albid", "alcea", "alces", + "alcid", "alcos", "aldea", "alder", "aldol", + "aleak", "aleck", "alecs", "aleem", "alefs", + "aleft", "aleph", "alews", "aleye", "alfas", + "algal", "algas", "algid", "algin", "algor", + "algos", "algum", "alias", "alick", "alifs", + "alims", "aline", "alios", "alist", "aliya", + "alkie", "alkin", "alkos", "alkyd", "alkyl", + "allan", "allee", "allel", "allen", "aller", + "allin", "allis", "allod", "allus", "allyl", + "almah", "almas", "almeh", "almes", "almud", + "almug", "alods", "aloed", "aloes", "aloha", + "aloin", "aloos", "alose", "alowe", "altho", + "altos", "alula", "alums", "alumy", "alure", + "alurk", "alvar", "alway", "amahs", "amain", + "amari", "amaro", "amate", "amaut", "amban", + "ambit", "ambos", "ambry", "ameba", "ameer", + "amene", "amens", "ament", "amias", "amice", + "amici", "amide", "amido", "amids", "amies", + "amiga", "amigo", "amins", "amirs", "amlas", + "amman", "ammas", "ammon", "ammos", "amnia", + "amnic", "amnio", "amoks", "amole", "amore", + "amort", "amour", "amove", "amowt", "amped", + "ampul", "amrit", "amuck", "amyls", "anana", + "anata", "ancho", "ancle", "ancon", "andic", + "andro", "anear", "anele", "anent", "angas", + "anglo", "anigh", "anile", "anils", "anima", + "animi", "anion", "anise", "anker", "ankhs", + "ankus", "anlas", "annal", "annan", "annas", + "annat", "annum", "annus", "anoas", "anole", + "anomy", "ansae", "ansas", "antae", "antar", + "antas", "anted", "antes", "antis", "antra", + "antre", "antsy", "anura", "anyon", "apace", + "apage", "apaid", "apayd", "apays", "apeak", + "apeek", "apers", "apert", "apery", "apgar", + "aphis", "apian", "apiol", "apish", "apism", + "apode", "apods", "apols", "apoop", "aport", + "appal", "appam", "appay", "appel", "appro", + "appts", "appui", "appuy", "apres", "apses", + "apsis", "apsos", "apted", "apter", "aquae", + "aquas", "araba", "araks", "arame", "arars", + "arbah", "arbas", "arced", "archi", "arcos", + "arcus", "ardeb", "ardri", "aread", "areae", + "areal", "arear", "areas", "areca", "aredd", + "arede", "arefy", "areic", "arene", "arepa", + "arere", "arete", "arets", "arett", "argal", + "argan", "argil", "argle", "argol", "argon", + "argot", "argus", "arhat", "arias", "ariel", + "ariki", "arils", "ariot", "arish", "arith", + "arked", "arled", "arles", "armed", "armer", + "armet", "armil", "arnas", "arnis", "arnut", + "aroba", "aroha", "aroid", "arpas", "arpen", + "arrah", "arras", "arret", "arris", "arroz", + "arsed", "arses", "arsey", "arsis", "artal", + "artel", "arter", "artic", "artis", "artly", + "aruhe", "arums", "arval", "arvee", "arvos", + "aryls", "asada", "asana", "ascon", "ascus", + "asdic", "ashed", "ashes", "ashet", "asity", + "askar", "asked", "asker", "askoi", "askos", + "aspen", "asper", "aspic", "aspie", "aspis", + "aspro", "assai", "assam", "assed", "asses", + "assez", "assot", "aster", "astir", "astun", + "asura", "asway", "aswim", "asyla", "ataps", + "ataxy", "atigi", "atilt", "atimy", "atlas", + "atman", "atmas", "atmos", "atocs", "atoke", + "atoks", "atoms", "atomy", "atony", "atopy", + "atria", "atrip", "attap", "attar", "attas", + "atter", "atuas", "aucht", "audad", "audax", + "augen", "auger", "auges", "aught", "aulas", + "aulic", "auloi", "aulos", "aumil", "aunes", + "aunts", "aurae", "aural", "aurar", "auras", + "aurei", "aures", "auric", "auris", "aurum", + "autos", "auxin", "avail", "avale", "avant", + "avast", "avels", "avens", "avers", "avert", + "avgas", "avine", "avion", "avise", "aviso", + "avize", "avows", "avyze", "awari", "awarn", + "awato", "awave", "aways", "awdls", "aweel", + "aweto", "awing", "awkin", "awmry", "awned", + "awner", "awols", "awork", "axels", "axile", + "axils", "axing", "axion", "axite", "axled", + "axles", "axman", "axmen", "axoid", "axone", + "axons", "ayahs", "ayaya", "ayelp", "aygre", + "ayins", "aymag", "ayont", "ayres", "ayrie", + "azans", "azide", "azido", "azine", "azlon", + "azoic", "azole", "azons", "azote", "azoth", + "azuki", "azurn", "azury", "azygy", "azyme", + "azyms", "baaed", "baals", "baaps", "babas", + "babby", "babel", "babes", "babka", "baboo", + "babul", "babus", "bacca", "bacco", "baccy", + "bacha", "bachs", "backs", "backy", "bacne", + "badam", "baddy", "baels", "baffs", "baffy", + "bafta", "bafts", "baghs", "bagie", "bagsy", + "bagua", "bahts", "bahus", "bahut", "baiks", + "baile", "bails", "bairn", "baisa", "baith", + "baits", "baiza", "baize", "bajan", "bajra", + "bajri", "bajus", "baked", "baken", "bakes", + "bakra", "balas", "balds", "baldy", "baled", + "baler", "bales", "balks", "balky", "ballo", + "balls", "bally", "balms", "baloi", "balon", + "baloo", "balot", "balsa", "balti", "balun", + "balus", "balut", "bamas", "bambi", "bamma", + "bammy", "banak", "banco", "bancs", "banda", + "bandh", "bands", "bandy", "baned", "banes", + "bangs", "bania", "banks", "banky", "banns", + "bants", "bantu", "banty", "bantz", "banya", + "baons", "baozi", "bappu", "bapus", "barbe", + "barbs", "barby", "barca", "barde", "bardo", + "bards", "bardy", "bared", "barer", "bares", + "barfi", "barfs", "barfy", "baric", "barks", + "barky", "barms", "barmy", "barns", "barny", + "barps", "barra", "barre", "barro", "barry", + "barye", "basan", "basas", "based", "basen", + "baser", "bases", "basha", "basho", "basij", + "basks", "bason", "basse", "bassi", "basso", + "bassy", "basta", "basti", "basto", "basts", + "bated", "bates", "baths", "batik", "batos", + "batta", "batts", "battu", "bauds", "bauks", + "baulk", "baurs", "bavin", "bawds", "bawks", + "bawls", "bawns", "bawrs", "bawty", "bayas", + "bayed", "bayer", "bayes", "bayle", "bayts", + "bazar", "bazas", "bazoo", "bball", "bdays", + "beads", "beaks", "beaky", "beals", "beams", + "beamy", "beano", "beans", "beany", "beare", + "bears", "beath", "beats", "beaty", "beaus", + "beaut", "beaux", "bebop", "becap", "becke", + "becks", "bedad", "bedel", "bedes", "bedew", + "bedim", "bedye", "beedi", "beefs", "beeps", + "beers", "beery", "beets", "befog", "begad", + "begar", "begem", "begob", "begot", "begum", + "beige", "beigy", "beins", "beira", "beisa", + "bekah", "belah", "belar", "belay", "belee", + "belga", "belie", "belit", "belle", "belli", + "bello", "bells", "belon", "belts", "belve", + "bemad", "bemas", "bemix", "bemud", "bends", + "bendy", "benes", "benet", "benga", "benis", + "benji", "benne", "benni", "benny", "bento", + "bents", "benty", "bepat", "beray", "beres", + "bergs", "berko", "berks", "berme", "berms", + "berob", "beryl", "besat", "besaw", "besee", + "beses", "besit", "besom", "besot", "besti", + "bests", "betas", "beted", "betes", "beths", + "betid", "beton", "betta", "betty", "bevan", + "bever", "bevor", "bevue", "bevvy", "bewdy", + "bewet", "bewig", "bezel", "bezes", "bezil", + "bezzy", "bhais", "bhaji", "bhang", "bhats", + "bhava", "bhels", "bhoot", "bhuna", "bhuts", + "biach", "biali", "bialy", "bibbs", "bibes", + "bibis", "biccy", "bices", "bicky", "bided", + "bider", "bides", "bidet", "bidis", "bidon", + "bidri", "bield", "biers", "biffo", "biffs", + "biffy", "bifid", "bigae", "biggs", "biggy", + "bigha", "bight", "bigly", "bigos", "bihon", + "bijou", "biked", "biker", "bikes", "bikie", + "bikky", "bilal", "bilat", "bilbo", "bilby", + "biled", "biles", "bilgy", "bilks", "bills", + "bimah", "bimas", "bimbo", "binal", "bindi", + "binds", "biner", "bines", "bings", "bingy", + "binit", "binks", "binky", "bints", "biogs", + "bions", "biont", "biose", "biota", "biped", + "bipod", "bippy", "birdo", "birds", "biris", + "birks", "birle", "birls", "biros", "birrs", + "birse", "birsy", "birze", "birzz", "bises", + "bisks", "bisom", "bison", "bitch", "biter", + "bites", "bitey", "bitos", "bitou", "bitsy", + "bitte", "bitts", "bitty", "bivia", "bivvy", + "bizes", "bizzo", "bizzy", "blabs", "blads", + "blady", "blaer", "blaes", "blaff", "blags", + "blahs", "blain", "blams", "blanc", "blart", + "blase", "blash", "blate", "blats", "blatt", + "blaud", "blawn", "blaws", "blays", "bleah", + "blear", "blebs", "blech", "bleep", "blees", + "blent", "blert", "blest", "blets", "bleys", + "blimy", "bling", "blink", "blins", "bliny", + "blips", "blist", "blite", "blits", "blive", + "blobs", "blocs", "blogs", "blonx", "blook", + "bloop", "blore", "blots", "blows", "blowy", + "blubs", "blude", "bluds", "bludy", "blued", + "bluer", "bluet", "bluey", "bluid", "blume", + "blunk", "blurs", "blype", "boabs", "boaks", + "boars", "boart", "boats", "boaty", "bobac", + "bobak", "bobas", "bobol", "bobos", "bocca", + "bocce", "bocci", "boche", "bocks", "boded", + "bodes", "bodge", "bodgy", "bodhi", "bodle", + "bodoh", "boeps", "boers", "boeti", "boets", + "boeuf", "boffo", "boffs", "bogan", "bogey", + "boggy", "bogie", "bogle", "bogue", "bogus", + "bohea", "bohos", "boils", "boing", "boink", + "boite", "boked", "bokeh", "bokes", "bokos", + "bolar", "bolas", "boldo", "bolds", "boles", + "bolet", "bolix", "bolks", "bolls", "bolos", + "bolts", "bolus", "bomas", "bombe", "bombo", + "bombs", "bomoh", "bomor", "bonce", "bonds", + "boned", "boner", "bones", "bongo", "bongs", + "bonie", "bonks", "bonne", "bonny", "bonum", + "bonza", "bonze", "booai", "booay", "boobs", + "boody", "booed", "boofy", "boogy", "boohs", + "books", "booky", "bools", "booms", "boomy", + "boong", "boons", "boord", "boors", "boose", + "boots", "boppy", "borak", "boral", "boras", + "borde", "bords", "bored", "boree", "borek", + "borel", "borer", "bores", "borgo", "boric", + "borks", "borms", "borna", "boron", "borts", + "borty", "bortz", "bosey", "bosie", "bosks", + "bosky", "boson", "bossa", "bosun", "botas", + "boteh", "botel", "botes", "botew", "bothy", + "botos", "botte", "botts", "botty", "bouge", + "bough", "bouks", "boule", "boult", "bouns", + "bourd", "bourg", "bourn", "bouse", "bousy", + "bouts", "boutu", "bovid", "bowat", "bowed", + "bower", "bowes", "bowet", "bowie", "bowls", + "bowne", "bowrs", "bowse", "boxed", "boxen", + "boxes", "boxla", "boxty", "boyar", "boyau", + "boyed", "boyey", "boyfs", "boygs", "boyla", + "boyly", "boyos", "boysy", "bozos", "braai", + "brach", "brack", "bract", "brads", "braes", + "brags", "brahs", "brail", "braks", "braky", + "brame", "brane", "brank", "brans", "brant", + "brast", "brats", "brava", "bravi", "braws", + "braxy", "brays", "braza", "braze", "bream", + "brede", "breds", "breem", "breer", "brees", + "breid", "breis", "breme", "brens", "brent", + "brere", "brers", "breve", "brews", "breys", + "brier", "bries", "brigs", "briki", "briks", + "brill", "brims", "brins", "brios", "brise", + "briss", "brith", "brits", "britt", "brize", + "broch", "brock", "brods", "brogh", "brogs", + "brome", "bromo", "bronc", "brond", "brool", + "broom", "broos", "brose", "brosy", "brows", + "bruck", "brugh", "bruhs", "bruin", "bruit", + "bruja", "brujo", "brule", "brume", "brung", + "brusk", "brust", "bruts", "bruvs", "buats", + "buaze", "bubal", "bubas", "bubba", "bubbe", + "bubby", "bubus", "buchu", "bucko", "bucks", + "bucku", "budas", "buded", "budes", "budis", + "budos", "buena", "buffa", "buffe", "buffi", + "buffo", "buffs", "buffy", "bufos", "bufty", + "bugan", "buhls", "buhrs", "buiks", "buist", + "bukes", "bukos", "bulbs", "bulgy", "bulks", + "bulla", "bulls", "bulse", "bumbo", "bumfs", + "bumph", "bumps", "bumpy", "bunas", "bunce", + "bunco", "bunde", "bundh", "bunds", "bundt", + "bundu", "bundy", "bungs", "bungy", "bunia", + "bunje", "bunjy", "bunko", "bunks", "bunns", + "bunts", "bunty", "bunya", "buoys", "buppy", + "buran", "buras", "burbs", "burds", "buret", + "burfi", "burgh", "burgs", "burin", "burka", + "burke", "burks", "burls", "burns", "buroo", + "burps", "burqa", "burra", "burro", "burrs", + "burry", "bursa", "burse", "busby", "bused", + "buses", "busks", "busky", "bussu", "busti", + "busts", "busty", "buteo", "butes", "butle", + "butoh", "butts", "butty", "butut", "butyl", + "buxom", "buyin", "buzzy", "bwana", "bwazi", + "byded", "bydes", "byked", "bykes", "byres", + "byrls", "byssi", "bytes", "byway", "caaed", + "cabas", "cabby", "caber", "cabob", "caboc", + "cabre", "cacao", "cacas", "cache", "cacks", + "cacky", "cacti", "caddy", "cadee", "cades", + "cadge", "cadgy", "cadie", "cadis", "cadre", + "caeca", "caese", "cafes", "caffe", "caffs", + "caged", "cager", "cages", "cagey", "cagot", + "cahow", "caids", "cains", "caird", "cairn", + "cajon", "cajun", "caked", "cakes", "cakey", + "calfs", "calid", "calif", "calix", "calks", + "calla", "calle", "calls", "calms", "calmy", + "calos", "calpa", "calps", "calve", "calyx", + "caman", "camas", "cames", "camis", "camos", + "campi", "campo", "camps", "campy", "camus", + "cando", "caned", "caneh", "caner", "canes", + "cangs", "canid", "canna", "canns", "canon", + "canso", "canst", "canti", "canto", "cants", + "canty", "capas", "capax", "caped", "capes", + "capex", "caphs", "capiz", "caple", "capon", + "capos", "capot", "capri", "capul", "carap", + "carbo", "carbs", "carby", "cardi", "cards", + "cardy", "cared", "carer", "cares", "caret", + "carex", "carks", "carle", "carls", "carne", + "carns", "carny", "carob", "carom", "caron", + "carpe", "carpi", "carps", "carrs", "carse", + "carta", "carte", "carts", "carvy", "casas", + "casco", "cased", "caser", "cases", "casks", + "casky", "casts", "casus", "cates", "catty", + "cauda", "cauks", "cauld", "caulk", "cauls", + "caums", "caups", "cauri", "causa", "cavas", + "caved", "cavel", "caver", "caves", "cavie", + "cavus", "cawed", "cawks", "caxon", "ceaze", + "cebid", "cecal", "cecum", "ceded", "ceder", + "cedes", "cedis", "ceiba", "ceili", "ceils", + "celeb", "cella", "celli", "cello", "cells", + "celly", "celom", "celts", "cense", "cento", + "cents", "centu", "ceorl", "cepes", "cerci", + "cered", "ceres", "cerge", "ceria", "ceric", + "cerne", "ceroc", "ceros", "certs", "certy", + "cesse", "cesta", "cesti", "cetes", "cetyl", + "cezve", "chaap", "chaat", "chace", "chack", + "chaco", "chado", "chads", "chafe", "chaff", + "chaft", "chais", "chals", "chams", "chana", + "chang", "chank", "chape", "chaps", "chapt", + "chara", "chare", "chark", "charr", "chars", + "chary", "chats", "chava", "chave", "chavs", + "chawk", "chawl", "chaws", "chaya", "chays", + "cheba", "chedi", "cheeb", "cheep", "cheet", + "chefs", "cheka", "chela", "chelp", "chemo", + "chems", "chere", "chert", "cheth", "chevy", + "chews", "chewy", "chiao", "chias", "chiba", + "chibs", "chica", "chich", "chico", "chics", + "chiel", "chiko", "chiks", "chile", "chimb", + "chimo", "chimp", "chine", "ching", "chink", + "chino", "chins", "chips", "chirk", "chirl", + "chirm", "chiro", "chirr", "chirt", "chiru", + "chiti", "chits", "chiva", "chive", "chivs", + "chivy", "chizz", "choco", "chocs", "chode", + "chogs", "choil", "choko", "choky", "chola", + "choli", "cholo", "chomp", "chons", "choof", + "chook", "choom", "choon", "chops", "choss", + "chota", "chott", "chout", "choux", "chowk", + "chows", "chubs", "chufa", "chuff", "chugs", + "chums", "churl", "churr", "chuse", "chuts", + "chyle", "chyme", "chynd", "cibol", "cided", + "cides", "ciels", "ciggy", "cilia", "cills", + "cimar", "cimex", "cinct", "cines", "cinqs", + "cions", "cippi", "circa", "circs", "cires", + "cirls", "cirri", "cisco", "cissy", "cists", + "cital", "cited", "citee", "citer", "cites", + "cives", "civet", "civie", "civvy", "clach", + "clack", "clade", "clads", "claes", "clags", + "clair", "clame", "clams", "clans", "claps", + "clapt", "claro", "clart", "clary", "clast", + "clats", "claut", "clave", "clavi", "claws", + "clays", "cleat", "cleck", "cleek", "cleep", + "clefs", "cleft", "clegs", "cleik", "clems", + "clepe", "clept", "cleve", "clews", "clied", + "clies", "clift", "clime", "cline", "clink", + "clint", "clipe", "clips", "clipt", "clits", + "cloam", "clods", "cloff", "clogs", "cloke", + "clomb", "clomp", "clonk", "clons", "cloop", + "cloot", "clops", "clote", "clots", "clour", + "clous", "clove", "clows", "cloye", "cloys", + "cloze", "clubs", "clues", "cluey", "clunk", + "clype", "cnida", "coact", "coady", "coala", + "coals", "coaly", "coapt", "coarb", "coate", + "coati", "coats", "cobbs", "cobby", "cobia", + "coble", "cobot", "cobza", "cocas", "cocci", + "cocco", "cocks", "cocky", "cocos", "cocus", + "codas", "codec", "coded", "coden", "coder", + "codes", "codex", "codon", "coeds", "coffs", + "cogie", "cogon", "cogue", "cohab", "cohen", + "cohoe", "cohog", "cohos", "coifs", "coign", + "coils", "coins", "coirs", "coits", "coked", + "cokes", "cokey", "colas", "colby", "colds", + "coled", "coles", "coley", "colic", "colin", + "colle", "colls", "colly", "colog", "colts", + "colza", "comae", "comal", "comas", "combe", + "combi", "combo", "combs", "comby", "comer", + "comes", "comfy", "comix", "comme", "commo", + "comms", "commy", "compo", "comps", "compt", + "comte", "comus", "coned", "cones", "conex", + "confs", "conga", "conge", "congo", "conia", + "conic", "conin", "conks", "conky", "conne", + "conns", "conte", "conto", "conus", "convo", + "cooch", "cooed", "cooee", "cooer", "cooey", + "coofs", "cooks", "cooky", "cools", "cooly", + "coomb", "cooms", "coomy", "coons", "coops", + "coopt", "coost", "coots", "cooty", "cooze", + "copal", "copay", "coped", "copen", "coper", + "copes", "copha", "coppy", "copra", "copse", + "copsy", "coqui", "coram", "corbe", "corby", + "corda", "cords", "cored", "corer", "cores", + "corey", "corgi", "coria", "corks", "corky", + "corms", "corni", "corno", "corns", "cornu", + "corps", "corse", "corso", "cosec", "cosed", + "coses", "coset", "cosey", "cosie", "costa", + "coste", "costs", "cotan", "cotch", "coted", + "cotes", "coths", "cotta", "cotts", "coude", + "cough", "coups", "courb", "courd", "coure", + "cours", "couta", "couth", "coved", "coven", + "coves", "covey", "covin", "cowal", "cowan", + "cowed", "cower", "cowks", "cowls", "cowps", + "cowry", "coxae", "coxal", "coxed", "coxes", + "coxib", "coyau", "coyed", "coyer", "coyly", + "coypu", "cozed", "cozen", "cozes", "cozey", + "cozie", "craal", "crabs", "crags", "craic", + "craig", "crake", "crame", "crams", "crans", + "crape", "craps", "crapy", "crare", "craws", + "crays", "creds", "creel", "crees", "crein", + "crema", "creme", "crems", "crena", "crepe", + "creps", "crept", "crepy", "cress", "crewe", + "crews", "crias", "cribo", "cribs", "crier", + "cries", "crims", "crine", "crink", "crins", + "crios", "cripe", "crips", "crise", "criss", + "crith", "crits", "croci", "crocs", "croft", + "crogs", "cromb", "crome", "cronk", "crons", + "crool", "croon", "crops", "crore", "crost", + "croup", "crout", "crowl", "crows", "croze", + "cruck", "crudo", "cruds", "crudy", "crues", + "cruet", "cruft", "crumb", "crump", "crunk", + "cruor", "crura", "cruse", "crusy", "cruve", + "crwth", "cryer", "cryne", "ctene", "cubby", + "cubeb", "cubed", "cuber", "cubes", "cubit", + "cucks", "cudda", "cuddy", "cueca", "cuffo", + "cuffs", "cuifs", "cuing", "cuish", "cuits", + "cukes", "culch", "culet", "culex", "culls", + "cully", "culms", "culpa", "culti", "cults", + "culty", "cumec", "cundy", "cunei", "cunit", + "cunny", "cunts", "cupel", "cuppa", "cuppy", + "cupro", "curat", "curbs", "curch", "curds", + "curdy", "cured", "curer", "cures", "curet", + "curfs", "curia", "curie", "curio", "curli", + "curls", "curns", "curny", "currs", "cursi", + "curst", "cusec", "cushy", "cusks", "cusps", + "cuspy", "cusso", "cusum", "cutch", "cuter", + "cutes", "cutey", "cutin", "cutis", "cutto", + "cutty", "cutup", "cuvee", "cuzes", "cwtch", + "cyano", "cyans", "cyber", "cycad", "cycas", + "cyclo", "cyder", "cylix", "cymae", "cymar", + "cymas", "cymes", "cymol", "cysts", "cytes", + "cyton", "czars", "daals", "dabba", "daces", + "dacha", "dacks", "dadah", "dadas", "dadis", + "dadla", "dados", "daffs", "daffy", "dagga", + "daggy", "dagos", "dahis", "dahls", "daiko", + "daine", "daint", "daker", "daled", "dalek", + "dales", "dalis", "dalle", "dalts", "daman", + "damar", "dames", "damme", "damna", "damns", + "damps", "dampy", "dancy", "danda", "dangs", + "danio", "danks", "danny", "danse", "dants", + "dappy", "daraf", "darbs", "darcy", "dared", + "darer", "dares", "darga", "dargs", "daric", + "daris", "darks", "darky", "darls", "darns", + "darre", "darts", "darzi", "dashi", "dashy", + "datal", "dated", "dater", "dates", "datil", + "datos", "datto", "daube", "daubs", "dauby", + "dauds", "dault", "daurs", "dauts", "daven", + "davit", "dawah", "dawds", "dawed", "dawen", + "dawgs", "dawks", "dawns", "dawts", "dayal", + "dayan", "daych", "daynt", "dazed", "dazer", + "dazes", "dbags", "deads", "deair", "deals", + "deans", "deare", "dearn", "dears", "deary", + "deash", "deave", "deaws", "deawy", "debag", + "debar", "debby", "debel", "debes", "debit", + "debts", "debud", "debug", "debur", "debus", + "debye", "decad", "decaf", "decan", "decim", + "decko", "decks", "decos", "decyl", "dedal", + "deeds", "deedy", "deely", "deems", "deens", + "deeps", "deere", "deers", "deets", "deeve", + "deevs", "defat", "deffo", "defis", "defog", + "degas", "degum", "degus", "deice", "deids", + "deify", "deils", "deink", "deism", "deist", + "deked", "dekes", "dekko", "deled", "deles", + "delfs", "delft", "delis", "della", "dells", + "delly", "delos", "delph", "delts", "deman", + "demes", "demic", "demit", "demob", "demoi", + "demos", "demot", "dempt", "denar", "denay", + "dench", "denes", "denet", "denis", "dente", + "dents", "deoch", "deoxy", "derat", "deray", + "dered", "deres", "derig", "derma", "derms", + "derns", "derny", "deros", "derpy", "derro", + "derry", "derth", "dervs", "desex", "deshi", + "desis", "desks", "desse", "detag", "devas", + "devel", "devis", "devon", "devos", "devot", + "dewan", "dewar", "dewax", "dewed", "dexes", + "dexie", "dexys", "dhaba", "dhaks", "dhals", + "dhikr", "dhobi", "dhole", "dholl", "dhols", + "dhoni", "dhoti", "dhows", "dhuti", "diact", + "dials", "diana", "diane", "diazo", "dibbs", + "diced", "dicer", "dices", "dicht", "dicks", + "dicky", "dicot", "dicta", "dicto", "dicts", + "dictu", "dicty", "diddy", "didie", "didis", + "didos", "didst", "diebs", "diels", "diene", + "diets", "diffs", "dight", "dikas", "diked", + "diker", "dikes", "dikey", "dildo", "dilli", + "dills", "dimbo", "dimer", "dimes", "dimps", + "dinar", "dined", "dines", "dinge", "dings", + "dinic", "dinks", "dinky", "dinlo", "dinna", + "dinos", "dints", "dioch", "diols", "diota", + "dippy", "dipso", "diram", "direr", "dirke", + "dirks", "dirls", "dirts", "disas", "disci", + "discs", "dishy", "disks", "disme", "dital", + "ditas", "dited", "dites", "ditsy", "ditts", + "ditzy", "divan", "divas", "dived", "dives", + "divey", "divis", "divna", "divos", "divot", + "divvy", "diwan", "dixie", "dixit", "diyas", + "dizen", "djinn", "djins", "doabs", "doats", + "dobby", "dobes", "dobie", "dobla", "doble", + "dobra", "dobro", "docht", "docks", "docos", + "docus", "doddy", "dodos", "doeks", "doers", + "doest", "doeth", "doffs", "dogal", "dogan", + "doges", "dogey", "doggo", "doggy", "dogie", + "dogly", "dohyo", "doilt", "doily", "doits", + "dojos", "dolce", "dolci", "doled", "dolee", + "doles", "doley", "dolia", "dolie", "dolls", + "dolma", "dolor", "dolos", "dolts", "domal", + "domed", "domes", "domic", "donah", "donas", + "donee", "doner", "donga", "dongs", "donko", + "donna", "donne", "donny", "donsy", "doobs", + "dooce", "doody", "doofs", "dooks", "dooky", + "doole", "dools", "dooly", "dooms", "doomy", + "doona", "doorn", "doors", "doozy", "dopas", + "doped", "doper", "dopes", "doppe", "dorad", + "dorba", "dorbs", "doree", "dores", "doric", + "doris", "dorje", "dorks", "dorky", "dorms", + "dormy", "dorps", "dorrs", "dorsa", "dorse", + "dorts", "dorty", "dosai", "dosas", "dosed", + "doseh", "doser", "doses", "dosha", "dotal", + "doted", "doter", "dotes", "dotty", "douar", + "douce", "doucs", "douks", "doula", "douma", + "doums", "doups", "doura", "douse", "douts", + "doved", "doven", "dover", "doves", "dovie", + "dowak", "dowar", "dowds", "dowed", "dower", + "dowfs", "dowie", "dowle", "dowls", "dowly", + "downa", "downs", "downy", "dowps", "dowry", + "dowse", "dowts", "doxed", "doxes", "doxie", + "doyen", "doyly", "dozed", "dozen", "dozer", + "dozes", "drabs", "drack", "draco", "draff", + "drags", "drail", "drams", "drant", "draps", + "drapy", "drats", "drave", "draws", "drays", + "drear", "dreck", "dreed", "dreer", "drees", + "dregs", "dreks", "drent", "drere", "drest", + "dreys", "dribs", "drice", "drier", "dries", + "drily", "drips", "dript", "drock", "droid", + "droil", "droke", "drole", "drome", "drony", + "droob", "droog", "drook", "drops", "dropt", + "drouk", "drows", "drubs", "druid", "drums", + "drupe", "druse", "drusy", "druxy", "dryad", + "dryas", "dsobo", "dsomo", "duads", "duals", + "duans", "duars", "dubbo", "dubby", "ducal", + "ducat", "duces", "ducks", "ducky", "ducti", + "ducts", "duddy", "duded", "dudes", "duels", + "duets", "duett", "duffs", "dufus", "duing", + "duits", "dukas", "duked", "dukes", "dukka", + "dukun", "dulce", "dules", "dulia", "dulls", + "dulse", "dumas", "dumbo", "dumbs", "dumka", + "dumky", "dumps", "dumpy", "dunam", "dunch", + "dunes", "dungs", "dungy", "dunks", "dunno", + "dunny", "dunsh", "dunts", "duomi", "duomo", + "duped", "duper", "dupes", "duple", "duply", + "duppy", "dural", "duras", "dured", "dures", + "durgy", "durns", "duroc", "duros", "duroy", + "durra", "durrs", "durry", "durst", "durum", + "durzi", "dusks", "dusky", "dusts", "dutch", + "duxes", "dwaal", "dwale", "dwalm", "dwams", + "dwamy", "dwang", "dwaum", "dweeb", "dwile", + "dwine", "dyads", "dyers", "dyked", "dykes", + "dykey", "dykon", "dynel", "dynes", "dynos", + "dzhos", "eagly", "eagre", "ealed", "eales", + "eaned", "eards", "eared", "earls", "earns", + "earnt", "earst", "eased", "easer", "eases", + "easle", "easts", "eathe", "eatin", "eaved", + "eaver", "eaves", "ebank", "ebbed", "ebbet", + "ebena", "ebene", "ebike", "ebons", "ebook", + "ecads", "ecard", "ecash", "eched", "eches", + "echos", "ecigs", "ecole", "ecrus", "edema", + "edged", "edger", "edges", "edile", "edits", + "educe", "educt", "eejit", "eensy", "eeven", + "eever", "eevns", "effed", "effer", "efits", + "egads", "egers", "egest", "eggar", "egged", + "egger", "egmas", "ehing", "eider", "eidos", + "eigne", "eiked", "eikon", "eilds", "eiron", + "eisel", "eject", "ejido", "ekdam", "eking", + "ekkas", "elain", "eland", "elans", "elate", + "elbow", "elchi", "eldin", "eleet", "elegy", + "elemi", "elfed", "elfin", "eliad", "elide", + "elint", "elmen", "eloge", "elogy", "eloin", + "elops", "elpee", "elsin", "elute", "elvan", + "elven", "elver", "elves", "emacs", "embar", + "embay", "embed", "embog", "embow", "embox", + "embus", "emeer", "emend", "emerg", "emery", + "emeus", "emics", "emirs", "emits", "emmas", + "emmer", "emmet", "emmew", "emmys", "emoji", + "emong", "emote", "emove", "empts", "emule", + "emure", "emyde", "emyds", "enarm", "enate", + "ended", "ender", "endew", "endue", "enema", + "enews", "enfix", "eniac", "enlit", "enmew", + "ennog", "enoki", "enols", "enorm", "enows", + "enrol", "ensew", "ensky", "entia", "entre", + "enure", "enurn", "envoi", "enzym", "eolid", + "eorls", "eosin", "epact", "epees", "epena", + "epene", "ephah", "ephas", "ephod", "ephor", + "epics", "epode", "epopt", "epoxy", "eppie", + "epris", "eques", "equid", "erbia", "erect", + "erevs", "ergon", "ergos", "ergot", "erhus", + "erica", "erick", "erics", "ering", "erned", + "ernes", "erose", "erred", "erses", "eruct", + "erugo", "eruvs", "erven", "ervil", "escar", + "escot", "esile", "eskar", "esker", "esnes", + "esrog", "esses", "estoc", "estop", "estro", + "etage", "etape", "etats", "etens", "ethal", + "ethne", "ethyl", "etics", "etnas", "etrog", + "ettin", "ettle", "etude", "etuis", "etwee", + "etyma", "eughs", "euked", "eupad", "euros", + "eusol", "evegs", "evens", "evert", "evets", + "evhoe", "evils", "evite", "evohe", "ewers", + "ewest", "ewhow", "ewked", "exams", "exeat", + "execs", "exeem", "exeme", "exfil", "exier", + "exies", "exine", "exing", "exite", "exits", + "exode", "exome", "exons", "expos", "exuls", + "exurb", "eyass", "eyers", "eying", "eyots", + "eyras", "eyres", "eyrie", "eyrir", "ezine", + "fabbo", "fabby", "faced", "facer", "faces", + "facey", "facia", "facie", "facta", "facto", + "facts", "facty", "faddy", "faded", "fader", + "fades", "fadge", "fados", "faena", "faery", + "faffs", "faffy", "faggy", "fagin", "fagot", + "faiks", "fails", "faine", "fains", "faint", + "faire", "fairs", "faked", "faker", "fakes", + "fakey", "fakie", "fakir", "falaj", "fales", + "falls", "falsy", "famed", "fames", "fanal", + "fands", "fanes", "fanga", "fango", "fangs", + "fanks", "fanon", "fanos", "fanum", "faqir", + "farad", "farci", "farcy", "fards", "fared", + "farer", "fares", "farle", "farls", "farms", + "faros", "farro", "farse", "farts", "fasci", + "fasti", "fasts", "fated", "fates", "fatly", + "fatso", "fatwa", "fauch", "faugh", "fauld", + "fauns", "faurd", "faute", "fauts", "fauve", + "favas", "favel", "faver", "faves", "favor", + "favus", "fawns", "fawny", "faxed", "faxes", + "fayed", "fayer", "fayne", "fayre", "fazed", + "fazes", "feals", "feard", "feare", "fears", + "feart", "fease", "feats", "feaze", "fecal", + "feces", "fecht", "fecit", "fecks", "fedai", + "fedex", "feebs", "feeds", "feels", "feely", + "feens", "feers", "feese", "feeze", "fehme", + "feist", "felch", "felid", "felix", "fells", + "felly", "felts", "felty", "femal", "femes", + "femic", "femme", "femmy", "fends", "fendy", + "fenis", "fenks", "fenny", "fents", "feods", + "feoff", "ferer", "feres", "feria", "ferly", + "fermi", "ferms", "ferns", "ferny", "ferox", + "fesse", "festa", "fests", "festy", "fetas", + "feted", "fetes", "fetor", "fetta", "fetts", + "fetwa", "feuar", "feuds", "feued", "fewer", + "feyed", "feyer", "feyly", "fezes", "fezzy", + "fiars", "fiats", "fibro", "fices", "fiche", + "fichu", "ficin", "ficos", "ficta", "ficus", + "fides", "fidge", "fidos", "fidus", "fiefs", + "fient", "fiere", "fieri", "fiers", "fiest", + "fifed", "fifer", "fifes", "fifis", "figgy", + "figos", "fiked", "fikes", "filar", "filch", + "filed", "filer", "files", "filet", "filii", + "filks", "fille", "fillo", "fills", "filmi", + "films", "filon", "filos", "filum", "finca", + "finds", "fined", "finer", "fines", "finis", + "finks", "finny", "finos", "fiord", "fiqhs", + "fique", "fired", "firer", "fires", "firie", + "firks", "firma", "firms", "firni", "firns", + "firry", "first", "firth", "fiscs", "fisho", + "fisks", "fists", "fisty", "fitch", "fitly", + "fitna", "fitte", "fitts", "fiver", "fives", + "fixed", "fixes", "fixie", "fixit", "fjeld", + "flabs", "flaff", "flags", "flaks", "flamm", + "flams", "flamy", "flane", "flans", "flaps", + "flary", "flats", "flava", "flawn", "flaws", + "flawy", "flaxy", "flays", "fleam", "fleas", + "fleck", "fleek", "fleer", "flees", "flegs", + "fleme", "fleur", "flews", "flexi", "flexo", + "fleys", "flics", "flied", "flies", "flimp", + "flims", "flips", "flirs", "flisk", "flite", + "flits", "flitt", "flobs", "flocs", "floes", + "flogs", "flong", "flops", "flore", "flors", + "flory", "flosh", "flota", "flote", "flows", + "flowy", "flubs", "flued", "flues", "fluey", + "fluff", "fluky", "flume", "flump", "fluor", + "flurr", "fluty", "fluyt", "flyby", "flyer", + "flyin", "flype", "flyte", "fnarr", "foals", + "foams", "foehn", "fogey", "fogie", "fogle", + "fogos", "fogou", "fohns", "foids", "foils", + "foins", "foist", "folds", "foley", "folia", + "folic", "folie", "folio", "folks", "folky", + "fomes", "fonda", "fonds", "fondu", "fones", + "fonio", "fonly", "fonts", "foods", "foody", + "fools", "foots", "footy", "foram", "forbs", + "forby", "fordo", "fords", "forel", "fores", + "forex", "forks", "forky", "forma", "forme", + "forms", "forts", "forza", "forze", "fossa", + "fosse", "fouat", "fouds", "fouer", "fouet", + "foule", "fouls", "fount", "fours", "fouth", + "fovea", "fowls", "fowth", "foxed", "foxes", + "foxie", "foyle", "foyne", "frabs", "frack", + "fract", "frags", "fraim", "frais", "franc", + "frape", "fraps", "frass", "frate", "frati", + "frats", "fraus", "frays", "freer", "frees", + "freet", "freit", "fremd", "frena", "freon", + "frere", "frets", "fribs", "frier", "fries", + "frigs", "frise", "frist", "frita", "frite", + "frith", "frits", "fritt", "frize", "frizz", + "froes", "frogs", "fromm", "frons", "froom", + "frore", "frorn", "frory", "frosh", "froth", + "frows", "frowy", "froyo", "frugs", "frush", + "frust", "fryer", "fubar", "fubby", "fubsy", + "fucks", "fucus", "fuddy", "fudge", "fudgy", + "fuels", "fuero", "fuffs", "fuffy", "fugal", + "fuggy", "fugie", "fugio", "fugis", "fugle", + "fugly", "fugue", "fugus", "fujis", "fulla", + "fulls", "fulth", "fulwa", "fumed", "fumer", + "fumes", "fumet", "funda", "fundi", "fundo", + "funds", "fundy", "fungo", "fungs", "funic", + "funis", "funks", "funsy", "funts", "fural", + "furan", "furca", "furls", "furol", "furor", + "furos", "furrs", "furth", "furze", "furzy", + "fused", "fusee", "fusel", "fuses", "fusil", + "fusks", "fusts", "fusty", "futon", "fuzed", + "fuzee", "fuzes", "fuzil", "fyces", "fyked", + "fykes", "fyles", "fyrds", "fytte", "gabba", + "gabby", "gable", "gaddi", "gades", "gadge", + "gadgy", "gadid", "gadis", "gadje", "gadjo", + "gadso", "gaffe", "gaffs", "gaged", "gager", + "gages", "gaids", "gaily", "gains", "gairs", + "gaita", "gaits", "gaitt", "gajos", "galah", + "galas", "galax", "galea", "galed", "gales", + "galia", "galis", "galls", "gally", "galop", + "galut", "galvo", "gamas", "gamay", "gamba", + "gambe", "gambo", "gambs", "gamed", "gamer", + "games", "gamey", "gamic", "gamin", "gamme", + "gammy", "gamps", "ganch", "gandy", "ganef", + "ganev", "gangs", "ganja", "ganks", "ganof", + "gants", "gaols", "gaped", "gaper", "gapes", + "gapos", "gappy", "garam", "garba", "garbe", + "garbo", "garbs", "garda", "garde", "gares", + "garis", "garms", "garni", "garre", "garri", + "garth", "garum", "gases", "gashy", "gasps", + "gaspy", "gasts", "gatch", "gated", "gater", + "gates", "gaths", "gator", "gauch", "gaucy", + "gauds", "gauje", "gault", "gaums", "gaumy", + "gaups", "gaurs", "gauss", "gauzy", "gavot", + "gawcy", "gawds", "gawks", "gawps", "gawsy", + "gayal", "gayer", "gayly", "gazal", "gazar", + "gazed", "gazer", "gazes", "gazon", "gazoo", + "geals", "geans", "geare", "gears", "geasa", + "geats", "gebur", "gecko", "gecks", "geeks", + "geeps", "geese", "geest", "geist", "geits", + "gelds", "gelee", "gelid", "gelly", "gelts", + "gemel", "gemma", "gemmy", "gemot", "genae", + "genal", "genas", "genes", "genet", "genic", + "genii", "genin", "genio", "genip", "genny", + "genoa", "genom", "genro", "gents", "genty", + "genua", "genus", "geode", "geoid", "gerah", + "gerbe", "geres", "gerle", "germs", "germy", + "gerne", "gesse", "gesso", "geste", "gests", + "getas", "getup", "geums", "geyan", "geyer", + "ghast", "ghats", "ghaut", "ghazi", "ghees", + "ghest", "ghoul", "ghusl", "ghyll", "gibed", + "gibel", "giber", "gibes", "gibli", "gibus", + "gifts", "gigas", "gighe", "gigot", "gigue", + "gilas", "gilds", "gilet", "gilia", "gills", + "gilly", "gilpy", "gilts", "gimel", "gimme", + "gimps", "gimpy", "ginch", "ginga", "ginge", + "gings", "ginks", "ginny", "ginzo", "gipon", + "gippo", "gippy", "gipsy", "girds", "girlf", + "girls", "girly", "girns", "giron", "giros", + "girrs", "girsh", "girts", "gismo", "gisms", + "gists", "gitch", "gites", "giust", "gived", + "gives", "gizmo", "glace", "glade", "glads", + "glady", "glaik", "glair", "glamp", "glams", + "glans", "glary", "glatt", "glaum", "glaur", + "glazy", "gleba", "glebe", "gleby", "glede", + "gleds", "gleed", "gleek", "glees", "gleet", + "gleis", "glens", "glent", "gleys", "glial", + "glias", "glibs", "gliff", "glift", "glike", + "glime", "glims", "glisk", "glits", "glitz", + "gloam", "globi", "globs", "globy", "glode", + "glogg", "gloms", "gloop", "glops", "glost", + "glout", "glows", "glowy", "gloze", "glued", + "gluer", "glues", "gluey", "glugg", "glugs", + "glume", "glums", "gluon", "glute", "gluts", + "gnapi", "gnarl", "gnarr", "gnars", "gnats", + "gnawn", "gnaws", "gnows", "goads", "goafs", + "goaft", "goals", "goary", "goats", "goaty", + "goave", "goban", "gobar", "gobbe", "gobbi", + "gobbo", "gobby", "gobis", "gobos", "godet", + "godso", "goels", "goers", "goest", "goeth", + "goety", "gofer", "goffs", "gogga", "gogos", + "goier", "gojis", "gokes", "golds", "goldy", + "goles", "golfs", "golpe", "golps", "gombo", + "gomer", "gompa", "gonch", "gonef", "gongs", + "gonia", "gonif", "gonks", "gonna", "gonof", + "gonys", "gonzo", "gooby", "goodo", "goods", + "goofs", "googs", "gooks", "gooky", "goold", + "gools", "gooly", "goomy", "goons", "goony", + "goops", "goopy", "goors", "goory", "goosy", + "gopak", "gopik", "goral", "goras", "goray", + "gorbs", "gordo", "gored", "gores", "goris", + "gorms", "gormy", "gorps", "gorse", "gorsy", + "gosht", "gosse", "gotch", "goths", "gothy", + "gotta", "gouch", "gouks", "goura", "gouts", + "gouty", "goved", "goves", "gowan", "gowds", + "gowfs", "gowks", "gowls", "gowns", "goxes", + "goyim", "goyle", "graal", "grabs", "grads", + "graff", "graip", "grama", "grame", "gramp", + "grams", "grana", "grano", "grans", "grapy", + "grata", "grats", "gravs", "grays", "grebe", + "grebo", "grece", "greek", "grees", "grege", + "grego", "grein", "grens", "greps", "grese", + "greve", "grews", "greys", "grice", "gride", + "grids", "griff", "grift", "grigs", "grike", + "grins", "griot", "grips", "gript", "gripy", + "grise", "grist", "grisy", "grith", "grits", + "grize", "grody", "grogs", "groks", "groma", + "groms", "grone", "groof", "grosz", "grots", + "grouf", "grovy", "grows", "grrls", "grrrl", + "grubs", "grued", "grues", "grufe", "grume", + "grund", "gryce", "gryde", "gryke", "grype", + "grypt", "guaco", "guana", "guano", "guans", + "guars", "gubba", "gucks", "gucky", "gudes", + "guffs", "gugas", "guggl", "guido", "guids", + "guile", "guimp", "guiro", "gulab", "gulag", + "gular", "gulas", "gules", "gulet", "gulfs", + "gulfy", "gulls", "gulph", "gulps", "gulpy", + "gumma", "gummi", "gumps", "gunas", "gundi", + "gundy", "gunge", "gungy", "gunks", "gunky", + "gunny", "guqin", "gurdy", "gurge", "gurks", + "gurls", "gurly", "gurns", "gurry", "gursh", + "gurus", "gushy", "gusla", "gusle", "gusli", + "gussy", "gusts", "gutsy", "gutta", "gutty", + "guyed", "guyle", "guyot", "guyse", "gwine", + "gyals", "gyans", "gybed", "gybes", "gyeld", + "gymps", "gynae", "gynie", "gynny", "gynos", + "gyoza", "gypes", "gypos", "gyppo", "gyppy", + "gypsy", "gyral", "gyred", "gyres", "gyron", + "gyros", "gyrus", "gytes", "gyved", "gyver", + "gyves", "haafs", "haars", "haats", "hable", + "habus", "hacek", "hacks", "hacky", "hadal", + "haded", "hades", "hadji", "hadst", "haems", + "haere", "haets", "haffs", "hafiz", "hafta", + "hafts", "haggs", "haham", "hahas", "haick", + "haika", "haiks", "haiku", "hails", "haily", + "hains", "haint", "hairs", "haith", "hajes", + "hajis", "hajji", "hakam", "hakas", "hakea", + "hakes", "hakim", "hakus", "halal", "haldi", + "haled", "haler", "hales", "halfa", "halfs", + "halid", "hallo", "halls", "halma", "halms", + "halon", "halos", "halse", "halsh", "halts", + "halva", "halwa", "hamal", "hamba", "hamed", + "hamel", "hames", "hammy", "hamza", "hanap", + "hance", "hanch", "handi", "hands", "hangi", + "hangs", "hanks", "hanky", "hansa", "hanse", + "hants", "haole", "haoma", "hapas", "hapax", + "haply", "happi", "hapus", "haram", "hards", + "hared", "hares", "harim", "harks", "harls", + "harms", "harns", "haros", "harps", "harts", + "hashy", "hasks", "hasps", "hasta", "hated", + "hater", "hates", "hatha", "hathi", "hatty", + "hauds", "haufs", "haugh", "haugo", "hauld", + "haulm", "hauls", "hault", "hauns", "hause", + "haute", "havan", "havel", "haver", "haves", + "havoc", "hawed", "hawks", "hawms", "hawse", + "hayed", "hayer", "hayey", "hayle", "hazan", + "hazed", "hazer", "hazes", "hazle", "heads", + "heald", "heals", "heame", "heaps", "heapy", + "heard", "heare", "hears", "heast", "heats", + "heaty", "heave", "heben", "hebes", "hecht", + "hecks", "heder", "hedgy", "heeds", "heedy", + "heels", "heeze", "hefte", "hefts", "heiau", + "heids", "heigh", "heils", "heirs", "hejab", + "hejra", "heled", "heles", "helio", "hella", + "hells", "helly", "helms", "helos", "helot", + "helps", "helve", "hemal", "hemes", "hemic", + "hemin", "hemps", "hempy", "hench", "hends", + "henge", "henna", "henny", "henry", "hents", + "hepar", "herbs", "herby", "herds", "heres", + "herls", "herma", "herms", "herns", "heros", + "herps", "herry", "herse", "hertz", "herye", + "hesps", "hests", "hetes", "heths", "heuch", + "heugh", "hevea", "hevel", "hewed", "hewer", + "hewgh", "hexad", "hexed", "hexer", "hexes", + "hexyl", "heyed", "hiant", "hibas", "hicks", + "hided", "hider", "hides", "hiems", "hifis", + "highs", "hight", "hijab", "hijra", "hiked", + "hiker", "hikes", "hikoi", "hilar", "hilch", + "hillo", "hills", "hilsa", "hilts", "hilum", + "hilus", "himbo", "hinau", "hinds", "hings", + "hinky", "hinny", "hints", "hiois", "hiped", + "hiper", "hipes", "hiply", "hired", "hiree", + "hirer", "hires", "hissy", "hists", "hithe", + "hived", "hiver", "hives", "hizen", "hoach", + "hoaed", "hoagy", "hoars", "hoary", "hoast", + "hobos", "hocks", "hocus", "hodad", "hodja", + "hoers", "hogan", "hogen", "hoggs", "hoghs", + "hogoh", "hogos", "hohed", "hoick", "hoied", + "hoiks", "hoing", "hoise", "hokas", "hoked", + "hokes", "hokey", "hokis", "hokku", "hokum", + "holds", "holed", "holes", "holey", "holks", + "holla", "hollo", "holme", "holms", "holon", + "holos", "holts", "homas", "homed", "homes", + "homey", "homie", "homme", "homos", "honan", + "honda", "honds", "honed", "honer", "hones", + "hongi", "hongs", "honks", "honky", "hooch", + "hoods", "hoody", "hoofs", "hoogo", "hooha", + "hooka", "hooks", "hooky", "hooly", "hoons", + "hoops", "hoord", "hoors", "hoosh", "hoots", + "hooty", "hoove", "hopak", "hoped", "hoper", + "hopes", "hoppy", "horah", "horal", "horas", + "horis", "horks", "horme", "horns", "horst", + "horsy", "hosed", "hosel", "hosen", "hoser", + "hoses", "hosey", "hosta", "hosts", "hotch", + "hoten", "hotis", "hotte", "hotty", "houff", + "houfs", "hough", "houri", "hours", "houts", + "hovea", "hoved", "hovel", "hoven", "hoves", + "howay", "howbe", "howes", "howff", "howfs", + "howks", "howls", "howre", "howso", "howto", + "hoxed", "hoxes", "hoyas", "hoyed", "hoyle", + "hubba", "hubby", "hucks", "hudna", "hudud", + "huers", "huffs", "huffy", "huger", "huggy", + "huhus", "huias", "huies", "hukou", "hulas", + "hules", "hulks", "hulky", "hullo", "hulls", + "hully", "humas", "humfs", "humic", "humph", + "humps", "humpy", "hundo", "hunks", "hunts", + "hurds", "hurls", "hurly", "hurra", "hurst", + "hurts", "hurty", "hushy", "husks", "husos", + "hutia", "huzza", "huzzy", "hwyls", "hydel", + "hydra", "hydro", "hyens", "hygge", "hying", + "hykes", "hylas", "hyleg", "hyles", "hylic", + "hymns", "hynde", "hyoid", "hyped", "hypes", + "hypha", "hyphy", "hypos", "hyrax", "hyson", + "hythe", "iambi", "iambs", "ibrik", "icers", + "iched", "iches", "ichor", "icier", "icker", + "ickle", "icons", "ictal", "ictic", "ictus", + "idant", "iddah", "iddat", "iddut", "ideas", + "idees", "ident", "idled", "idler", "idles", + "idlis", "idola", "idols", "idyls", "iftar", + "igapo", "igged", "iglus", "ignis", "ihram", + "iiwis", "ikans", "ikats", "ikons", "ileac", + "ileal", "ileum", "ileus", "iliac", "iliad", + "ilial", "ilium", "iller", "illth", "imago", + "imagy", "imams", "imari", "imaum", "imbar", + "imbed", "imbos", "imide", "imido", "imids", + "imine", "imino", "imlis", "immew", "immit", + "immix", "imped", "impis", "impot", "impro", + "imshi", "imshy", "inapt", "inarm", "inbye", + "incas", "incel", "incle", "incog", "incus", + "incut", "indew", "india", "indie", "indol", + "indow", "indri", "indue", "inerm", "infix", + "infos", "infra", "ingan", "ingle", "inion", + "inked", "inker", "inkle", "inned", "innie", + "innit", "inorb", "inros", "inrun", "insee", + "inset", "inspo", "intel", "intil", "intis", + "intra", "inula", "inure", "inurn", "inust", + "invar", "inver", "inwit", "iodic", "iodid", + "iodin", "ioras", "iotas", "ippon", "irade", + "irids", "iring", "irked", "iroko", "irone", + "irons", "isbas", "ishes", "isled", "isles", + "isnae", "issei", "istle", "items", "ither", + "ivied", "ivies", "ixias", "ixnay", "ixora", + "ixtle", "izard", "izars", "izzat", "jaaps", + "jabot", "jacal", "jacet", "jacks", "jacky", + "jaded", "jades", "jafas", "jaffa", "jagas", + "jager", "jaggs", "jaggy", "jagir", "jagra", + "jails", "jaker", "jakes", "jakey", "jakie", + "jalap", "jaleo", "jalop", "jambe", "jambo", + "jambs", "jambu", "james", "jammy", "jamon", + "jamun", "janes", "janky", "janns", "janny", + "janty", "japan", "japed", "japer", "japes", + "jarks", "jarls", "jarps", "jarta", "jarul", + "jasey", "jaspe", "jasps", "jatha", "jatis", + "jatos", "jauks", "jaune", "jaunt", "jaups", + "javas", "javel", "jawan", "jawed", "jawns", + "jaxie", "jeans", "jeats", "jebel", "jedis", + "jeels", "jeely", "jeeps", "jeera", "jeers", + "jeeze", "jefes", "jeffs", "jehad", "jehus", + "jelab", "jello", "jells", "jembe", "jemmy", + "jeons", "jerid", "jerks", "jerry", "jesse", + "jessy", "jests", "jesus", "jetee", "jetes", + "jeton", "jetty", "jeune", "jewed", "jewie", + "jhala", "jheel", "jhils", "jiaos", "jibba", + "jibbs", "jibed", "jiber", "jibes", "jiffs", + "jiggy", "jigot", "jihad", "jills", "jilts", + "jimpy", "jingo", "jings", "jinks", "jinne", + "jinni", "jinns", "jirds", "jirga", "jirre", + "jisms", "jitis", "jitty", "jived", "jiver", + "jives", "jivey", "jnana", "jobed", "jobes", + "jocko", "jocks", "jocky", "jocos", "jodel", + "joeys", "johns", "joins", "joint", "joist", + "joked", "jokes", "jokey", "jokol", "joled", + "joles", "jolie", "jollo", "jolls", "jolts", + "jolty", "jomon", "jomos", "jones", "jongs", + "jonty", "jooks", "joram", "jorts", "jorum", + "jotas", "jotty", "jotun", "joual", "jougs", + "jouks", "joule", "jours", "jowar", "jowed", + "jowls", "jowly", "joyed", "jubas", "jubes", + "jucos", "judas", "judgy", "judos", "jugal", + "jugum", "jujus", "juked", "jukes", "jukus", + "julep", "julia", "jumar", "jumby", "jumps", + "junco", "junks", "junky", "junta", "junto", + "jupes", "jupon", "jural", "jurat", "jurel", + "jures", "juris", "juste", "justs", "jutes", + "jutty", "juves", "juvie", "kaama", "kabab", + "kabar", "kabob", "kacha", "kacks", "kadai", + "kades", "kadis", "kafir", "kagos", "kagus", + "kahal", "kaiak", "kaids", "kaies", "kaifs", + "kaika", "kaiks", "kails", "kaims", "kaing", + "kains", "kajal", "kakas", "kakis", "kalam", + "kalas", "kales", "kalif", "kalis", "kalpa", + "kalua", "kamas", "kames", "kamik", "kamis", + "kamme", "kanae", "kanal", "kanas", "kanat", + "kandy", "kaneh", "kanes", "kanga", "kangs", + "kanji", "kants", "kanzu", "kaons", "kapai", + "kapas", "kapha", "kaphs", "kapok", "kapow", + "kappa", "kapur", "kapus", "kaput", "karai", + "karas", "karat", "karee", "karez", "karks", + "karns", "karoo", "karos", "karri", "karst", + "karsy", "karts", "karzy", "kasha", "kasme", + "katal", "katas", "katis", "katti", "kaugh", + "kauri", "kauru", "kaury", "kaval", "kavas", + "kawas", "kawau", "kawed", "kayle", "kayos", + "kazis", "kazoo", "kbars", "kcals", "keaki", + "kebar", "kebob", "kecks", "kedge", "kedgy", + "keech", "keefs", "keeks", "keels", "keema", + "keeno", "keens", "keeps", "keets", "keeve", + "kefir", "kehua", "keirs", "kelep", "kelim", + "kells", "kelly", "kelps", "kelpy", "kelts", + "kelty", "kembo", "kembs", "kemps", "kempt", + "kempy", "kenaf", "kench", "kendo", "kenos", + "kente", "kents", "kepis", "kerbs", "kerel", + "kerfs", "kerky", "kerma", "kerne", "kerns", + "keros", "kerry", "kerve", "kesar", "kests", + "ketas", "ketch", "ketes", "ketol", "kevel", + "kevil", "kexes", "keyed", "keyer", "khadi", + "khads", "khafs", "khana", "khans", "khaph", + "khats", "khaya", "khazi", "kheda", "kheer", + "kheth", "khets", "khirs", "khoja", "khors", + "khoum", "khuds", "khula", "khyal", "kiaat", + "kiack", "kiaki", "kiang", "kiasu", "kibbe", + "kibbi", "kibei", "kibes", "kibla", "kicks", + "kicky", "kiddo", "kiddy", "kidel", "kideo", + "kidge", "kiefs", "kiers", "kieve", "kievs", + "kight", "kikay", "kikes", "kikoi", "kiley", + "kilig", "kilim", "kills", "kilns", "kilos", + "kilps", "kilts", "kilty", "kimbo", "kimet", + "kinas", "kinda", "kinds", "kindy", "kines", + "kings", "kingy", "kinin", "kinks", "kinos", + "kiore", "kipah", "kipas", "kipes", "kippa", + "kipps", "kipsy", "kirby", "kirks", "kirns", + "kirri", "kisan", "kissy", "kists", "kitab", + "kited", "kiter", "kites", "kithe", "kiths", + "kitke", "kitul", "kivas", "kiwis", "klang", + "klaps", "klett", "klick", "klieg", "kliks", + "klong", "kloof", "kluge", "klutz", "knags", + "knaps", "knarl", "knars", "knaur", "knave", + "knawe", "kneed", "knees", "knell", "knick", + "knish", "knits", "knive", "knobs", "knoop", + "knops", "knosp", "knots", "knoud", "knout", + "knowd", "knowe", "knows", "knubs", "knule", + "knurl", "knurr", "knurs", "knuts", "koans", + "koaps", "koban", "kobos", "koels", "koffs", + "kofta", "kogal", "kohas", "kohen", "kohls", + "koine", "koiwi", "kojis", "kokam", "kokas", + "koker", "kokra", "kokum", "kolas", "kolos", + "kombi", "kombu", "konbu", "kondo", "konks", + "kooks", "kooky", "koori", "kopek", "kophs", + "kopje", "koppa", "korai", "koran", "koras", + "korat", "kores", "koris", "korma", "koros", + "korun", "korus", "koses", "kotch", "kotos", + "kotow", "koura", "kraal", "krabs", "kraft", + "krais", "krait", "krang", "krans", "kranz", + "kraut", "krays", "kreef", "kreen", "kreep", + "kreng", "krewe", "krill", "kriol", "krona", + "krone", "kroon", "krubi", "krump", "krunk", + "ksars", "kubie", "kudus", "kudzu", "kufis", + "kugel", "kuias", "kukri", "kukus", "kulak", + "kulan", "kulas", "kulfi", "kumis", "kumys", + "kunas", "kunds", "kuris", "kurre", "kurta", + "kurus", "kusso", "kusti", "kutai", "kutas", + "kutch", "kutis", "kutus", "kuyas", "kuzus", + "kvass", "kvell", "kwaai", "kwela", "kwink", + "kwirl", "kyack", "kyaks", "kyang", "kyars", + "kyats", "kybos", "kydst", "kyles", "kylie", + "kylin", "kylix", "kyloe", "kynde", "kynds", + "kypes", "kyrie", "kytes", "kythe", "kyudo", + "laarf", "laari", "labda", "labia", "labis", + "labne", "labra", "laccy", "laced", "lacer", + "laces", "lacet", "lacey", "lacis", "lacka", + "lacks", "lacky", "laddu", "laddy", "laded", + "ladee", "lader", "lades", "ladoo", "laers", + "laevo", "lagan", "lagar", "laggy", "lahal", + "lahar", "laich", "laics", "laide", "laids", + "laigh", "laika", "laiks", "laird", "lairs", + "lairy", "laith", "laity", "laked", "laker", + "lakes", "lakhs", "lakin", "laksa", "laldy", + "lalls", "lamas", "lambs", "lamby", "lamed", + "lamer", "lames", "lamia", "lammy", "lamps", + "lanai", "lanas", "lanch", "lande", "lands", + "laned", "lanes", "lanks", "lants", "lapas", + "lapin", "lapis", "lapje", "lappa", "lappy", + "larch", "lards", "lardy", "laree", "lares", + "larfs", "larga", "largo", "laris", "larks", + "larky", "larns", "larnt", "larum", "lased", + "laser", "lases", "lassi", "lasso", "lassu", + "lassy", "lasts", "latah", "lated", "laten", + "latex", "lathi", "laths", "lathy", "latke", + "latus", "lauan", "lauch", "laude", "lauds", + "laufs", "laund", "laura", "laval", "lavas", + "laved", "laver", "laves", "lavra", "lavvy", + "lawed", "lawer", "lawin", "lawks", "lawns", + "lawny", "lawsy", "laxed", "laxer", "laxes", + "laxly", "layby", "layed", "layin", "layup", + "lazar", "lazed", "lazes", "lazos", "lazzi", + "lazzo", "leads", "leady", "leafs", "leaks", + "leams", "leans", "leant", "leany", "leaps", + "leare", "lears", "leary", "leats", "leavy", + "leaze", "leben", "leccy", "leche", "ledes", + "ledgy", "ledum", "leear", "leeks", "leeps", + "leers", "leery", "leese", "leets", "leeze", + "lefte", "lefts", "lefty", "leger", "leges", + "legge", "leggo", "legit", "legno", "lehrs", + "lehua", "leirs", "leish", "leman", "lemed", + "lemel", "lemes", "lemma", "lemme", "lends", + "lenes", "lengs", "lenis", "lenos", "lense", + "lenti", "lento", "leone", "lepak", "leper", + "lepid", "lepra", "lepta", "lered", "leres", + "lerps", "lesbo", "leses", "lesos", "lests", + "letch", "lethe", "letty", "letup", "leuch", + "leuco", "leuds", "leugh", "levas", "levee", + "leves", "levin", "levis", "lewis", "lexes", + "lexis", "lezes", "lezza", "lezzo", "lezzy", + "liana", "liane", "liang", "liard", "liars", + "liart", "liber", "libor", "libra", "libre", + "libri", "licet", "lichi", "licht", "licit", + "licks", "lidar", "lidos", "liefs", "liege", + "liens", "liers", "lieus", "lieve", "lifer", + "lifes", "lifey", "lifts", "ligan", "liger", + "ligge", "ligne", "liked", "liker", "likes", + "likin", "lills", "lilos", "lilts", "lilty", + "liman", "limas", "limax", "limba", "limbi", + "limbs", "limby", "limed", "limen", "limes", + "limey", "limit", "limma", "limns", "limos", + "limpa", "limps", "linac", "linch", "linds", + "lindy", "lined", "lines", "liney", "linga", + "lings", "lingy", "linin", "links", "linky", + "linns", "linny", "linos", "lints", "linty", + "linum", "linux", "lions", "lipas", "lipes", + "lipin", "lipos", "lippy", "liras", "lirks", + "lirot", "lises", "lisks", "lisle", "lisps", + "lists", "litai", "litas", "lited", "litem", + "lites", "litho", "liths", "litie", "litre", + "lived", "liven", "lives", "livor", "livre", + "liwaa", "liwas", "llano", "loach", "loads", + "loafs", "loams", "loamy", "loans", "loast", + "loath", "loave", "lobar", "lobed", "lobes", + "lobos", "lobus", "loche", "lochs", "lochy", + "locie", "locis", "locks", "locky", "locos", + "locum", "loden", "lodes", "loess", "lofts", + "logan", "loges", "loggy", "logia", "logie", + "logoi", "logon", "logos", "lohan", "loids", + "loins", "loipe", "loirs", "lokes", "lokey", + "lokum", "lolas", "loled", "lollo", "lolls", + "lolly", "lolog", "lolos", "lomas", "lomed", + "lomes", "loner", "longa", "longe", "longs", + "looby", "looed", "looey", "loofa", "loofs", + "looie", "looks", "looky", "looms", "loons", + "loony", "loops", "loord", "loots", "loped", + "loper", "lopes", "loppy", "loral", "loran", + "lords", "lordy", "lorel", "lores", "loric", + "loris", "losed", "losel", "losen", "loses", + "lossy", "lotah", "lotas", "lotes", "lotic", + "lotos", "lotsa", "lotta", "lotte", "lotto", + "lotus", "loued", "lough", "louie", "louis", + "louma", "lound", "louns", "loupe", "loups", + "loure", "lours", "loury", "louse", "louts", + "lovat", "loved", "lovee", "loves", "lovey", + "lovie", "lowan", "lowed", "lowen", "lowes", + "lownd", "lowne", "lowns", "lowps", "lowry", + "lowse", "lowth", "lowts", "loxed", "loxes", + "lozen", "luach", "luaus", "lubed", "lubes", + "lubra", "luces", "lucks", "lucre", "ludes", + "ludic", "ludos", "luffa", "luffs", "luged", + "luger", "luges", "lulls", "lulus", "lumas", + "lumbi", "lumme", "lummy", "lumps", "lunas", + "lunes", "lunet", "lungi", "lungs", "lunks", + "lunts", "lupin", "lurch", "lured", "lurer", + "lures", "lurex", "lurgi", "lurgy", "lurid", + "lurks", "lurry", "lurve", "luser", "lushy", + "lusks", "lusts", "lusus", "lutea", "luted", + "luter", "lutes", "luvvy", "luxed", "luxer", + "luxes", "lweis", "lyams", "lyard", "lyart", + "lyase", "lycea", "lycee", "lycra", "lymes", + "lymph", "lynes", "lyres", "lysed", "lyses", + "lysin", "lysis", "lysol", "lyssa", "lyted", + "lytes", "lythe", "lytic", "lytta", "maaed", + "maare", "maars", "maban", "mabes", "macas", + "macca", "maced", "macer", "maces", "mache", + "machi", "machs", "macka", "macks", "macle", + "macon", "macte", "madal", "madar", "maddy", + "madge", "madid", "mados", "madre", "maedi", + "maerl", "mafia", "mafic", "mafts", "magas", + "mages", "maggs", "magna", "magot", "magus", + "mahal", "mahem", "mahis", "mahoe", "mahrs", + "mahua", "mahwa", "maids", "maiko", "maiks", + "maile", "maill", "mailo", "mails", "maims", + "mains", "maire", "mairs", "maise", "maist", + "majas", "majat", "majoe", "majos", "makaf", + "makai", "makan", "makar", "makee", "makes", + "makie", "makis", "makos", "malae", "malai", + "malam", "malar", "malas", "malax", "maleo", + "males", "malic", "malik", "malis", "malky", + "malls", "malms", "malmy", "malts", "malty", + "malus", "malva", "malwa", "mamak", "mamas", + "mamba", "mambu", "mamee", "mamey", "mamie", + "mamil", "mammy", "manas", "manat", "mandi", + "mands", "mandy", "maneb", "maned", "maneh", + "manes", "manet", "manga", "mange", "mangi", + "mangs", "manie", "manis", "manks", "manky", + "manna", "manny", "manoa", "manos", "manse", + "manso", "manta", "mante", "manto", "mants", + "manty", "manul", "manus", "manzo", "mapau", + "mapes", "mapou", "mappy", "maqam", "maqui", + "marae", "marah", "maral", "maran", "maras", + "maray", "marcs", "mards", "mardy", "mares", + "marga", "marge", "margo", "margs", "maria", + "marid", "maril", "marka", "marks", "marle", + "marls", "marly", "marma", "marms", "maron", + "maror", "marra", "marri", "marse", "marts", + "marua", "marvy", "masas", "mased", "maser", + "mases", "masha", "mashy", "masks", "massa", + "masse", "massy", "masts", "masty", "masur", + "masus", "masut", "matai", "mated", "mater", + "mates", "mathe", "maths", "matin", "matlo", + "matra", "matsu", "matte", "matts", "matty", + "matza", "matzo", "mauby", "mauds", "mauka", + "maula", "mauls", "maums", "maumy", "maund", + "maunt", "mauri", "mausy", "mauts", "mauve", + "mauvy", "mauzy", "maven", "mavie", "mavin", + "mavis", "mawed", "mawks", "mawky", "mawla", + "mawns", "mawps", "mawrs", "maxed", "maxes", + "maxis", "mayan", "mayas", "mayed", "mayos", + "mayst", "mazac", "mazak", "mazar", "mazas", + "mazed", "mazel", "mazer", "mazes", "mazet", + "mazey", "mazut", "mbari", "mbars", "mbila", + "mbira", "mbret", "mbube", "mbuga", "meads", + "meake", "meaks", "meals", "meane", "means", + "meany", "meare", "mease", "meath", "meats", + "mebbe", "mebos", "mecca", "mecha", "mechs", + "mecks", "mecum", "medal", "medii", "medin", + "medle", "meech", "meeds", "meeja", "meeps", + "meers", "meets", "meffs", "meids", "meiko", + "meils", "meins", "meint", "meiny", "meism", + "meith", "mekka", "melam", "melas", "melba", + "melch", "melds", "meles", "melic", "melik", + "mells", "meloe", "melos", "melts", "melty", + "memes", "memic", "memos", "menad", "mence", + "mends", "mened", "menes", "menge", "mengs", + "menil", "mensa", "mense", "mensh", "menta", + "mento", "ments", "menus", "meous", "meows", + "merch", "mercs", "merde", "merds", "mered", + "merel", "merer", "meres", "meril", "meris", + "merks", "merle", "merls", "merse", "mersk", + "mesad", "mesal", "mesas", "mesca", "mesel", + "mesem", "meses", "meshy", "mesia", "mesic", + "mesne", "meson", "messy", "mesto", "mesyl", + "metas", "meted", "meteg", "metel", "metes", + "methi", "metho", "meths", "methy", "metic", + "metif", "metis", "metol", "metre", "metro", + "metta", "meums", "meuse", "meved", "meves", + "mewed", "mewls", "meynt", "mezes", "mezza", + "mezze", "mezzo", "mgals", "mhorr", "miais", + "miaou", "miaow", "miasm", "miaul", "micas", + "miche", "michi", "micht", "micks", "micky", + "micos", "micra", "micro", "middy", "midge", + "midgy", "midis", "miens", "mieux", "mieve", + "miffs", "miffy", "mifty", "miggs", "migma", + "migod", "mihas", "mihis", "mikan", "miked", + "mikes", "mikos", "mikra", "mikva", "milch", + "milds", "miler", "miles", "milfs", "milia", + "milko", "milks", "mille", "mills", "milly", + "milor", "milos", "milpa", "milts", "milty", + "miltz", "mimed", "mimeo", "mimer", "mimes", + "mimis", "mimsy", "minae", "minar", "minas", + "mincy", "mindi", "minds", "mined", "miner", + "mines", "minge", "mingi", "mings", "mingy", + "minim", "minis", "minke", "minks", "minny", + "minos", "minse", "mints", "minty", "minxy", + "miraa", "mirah", "mirch", "mired", "mires", + "mirex", "mirid", "mirin", "mirkn", "mirks", + "mirky", "mirls", "mirly", "miros", "mirrl", + "mirrs", "mirvs", "mirza", "misal", "misch", + "misdo", "mises", "misgo", "misky", "misls", + "misos", "missa", "misto", "mists", "misty", + "mitas", "mitch", "miter", "mites", "mitey", + "mitie", "mitis", "mitre", "mitry", "mitta", + "mitts", "mivey", "mivvy", "mixed", "mixen", + "mixer", "mixes", "mixie", "mixis", "mixte", + "mixup", "miyas", "mizen", "mizes", "mizzy", + "mmkay", "mneme", "moais", "moaky", "moals", + "moana", "moans", "moany", "moars", "moats", + "mobby", "mobed", "mobee", "mobes", "mobey", + "mobie", "moble", "mobos", "mocap", "mochi", + "mochs", "mochy", "mocks", "mocky", "mocos", + "mocus", "moder", "modes", "modge", "modii", + "modin", "modoc", "modom", "modus", "moeni", + "moers", "mofos", "mogar", "mogas", "moggy", + "mogos", "mogra", "mogue", "mohar", "mohel", + "mohos", "mohrs", "mohua", "mohur", "moile", + "moils", "moira", "moire", "moits", "moity", + "mojos", "moker", "mokes", "mokey", "mokis", + "mokky", "mokos", "mokus", "molal", "molas", + "molds", "moled", "moler", "moles", "moley", + "molie", "molla", "molle", "mollo", "molls", + "molly", "moloi", "molos", "molto", "molts", + "molue", "molvi", "molys", "momes", "momie", + "momma", "momme", "mommy", "momos", "mompe", + "momus", "monad", "monal", "monas", "monde", + "mondo", "moner", "mongo", "mongs", "monic", + "monie", "monks", "monos", "monpe", "monte", + "monty", "moobs", "mooch", "moods", "mooed", + "mooey", "mooks", "moola", "mooli", "mools", + "mooly", "moong", "mooni", "moons", "moony", + "moops", "moors", "moory", "mooth", "moots", + "moove", "moped", "moper", "mopes", "mopey", + "moppy", "mopsy", "mopus", "morae", "morah", + "moran", "moras", "morat", "moray", "moree", + "morel", "mores", "morgy", "moria", "morin", + "mormo", "morna", "morne", "morns", "moron", + "moror", "morra", "morro", "morse", "morts", + "moruk", "mosed", "moses", "mosey", "mosks", + "mosso", "moste", "mosto", "mosts", "moted", + "moten", "motes", "motet", "motey", "moths", + "mothy", "motis", "moton", "motte", "motts", + "motty", "motus", "motza", "mouch", "moues", + "moufs", "mould", "moule", "mouls", "mouly", + "moups", "moust", "moved", "moves", "mowas", + "mowed", "mowie", "mowra", "moxas", "moxie", + "moyas", "moyle", "moyls", "mozed", "mozes", + "mozos", "mpret", "mrads", "msasa", "mtepe", + "mucho", "mucic", "mucid", "mucin", "mucko", + "mucks", "mucky", "mucor", "mucro", "mudar", + "mudge", "mudif", "mudim", "mudir", "mudra", + "muffs", "muffy", "mufti", "mugga", "muggs", + "muggy", "mugho", "mugil", "mugos", "muhly", + "muids", "muils", "muirs", "muiry", "muist", + "mujik", "mukim", "mukti", "mulai", "mulct", + "muled", "mules", "muley", "mulga", "mulie", + "mulla", "mulls", "mulse", "mulsh", "mumbo", + "mumms", "mumph", "mumps", "mumsy", "mumus", + "munch", "munds", "mundu", "munga", "munge", + "mungi", "mungo", "mungs", "mungy", "munia", + "munis", "munja", "munjs", "munts", "muntu", + "muons", "muras", "mured", "mures", "murex", + "murgh", "murgi", "murid", "murks", "murls", + "murly", "murra", "murre", "murri", "murrs", + "murry", "murth", "murti", "muruk", "murva", + "musar", "musca", "mused", "musee", "muser", + "muses", "muset", "musha", "musit", "musks", + "musky", "musos", "musse", "mussy", "musta", + "musth", "musts", "mutas", "mutch", "muted", + "muter", "mutes", "mutha", "mutic", "mutis", + "muton", "mutti", "mutts", "mutum", "muvva", + "muxed", "muxes", "muzak", "muzzy", "mvula", + "mvule", "mvuli", "myall", "myals", "mylar", + "mynah", "mynas", "myoid", "myoma", "myons", + "myope", "myops", "myopy", "mysid", "mysie", + "mythi", "myths", "mythy", "myxos", "mzees", + "naams", "naans", "naats", "nabam", "nabby", + "nabes", "nabis", "nabks", "nabla", "nabob", + "nache", "nacho", "nacre", "nadas", "naeve", + "naevi", "naffs", "nagar", "nagas", "nages", + "naggy", "nagor", "nahal", "naiad", "naibs", + "naice", "naids", "naieo", "naifs", "naiks", + "nails", "naily", "nains", "naios", "naira", + "nairu", "najib", "nakas", "naked", "naker", + "nakfa", "nalas", "naled", "nalla", "namad", + "namak", "namaz", "named", "namer", "names", + "namma", "namus", "nanas", "nance", "nancy", + "nandu", "nanna", "nanos", "nante", "nanti", + "nanto", "nants", "nanty", "nanua", "napas", + "naped", "napes", "napoh", "napoo", "nappa", + "nappe", "nappy", "naras", "narco", "narcs", + "nards", "nares", "naric", "naris", "narks", + "narky", "narod", "narra", "narre", "nashi", + "nasho", "nasis", "nason", "nasus", "natak", + "natch", "nates", "natis", "natto", "natty", + "natya", "nauch", "naunt", "navar", "naved", + "naves", "navew", "navvy", "nawab", "nawal", + "nazar", "nazes", "nazir", "nazis", "nazzy", + "nduja", "neafe", "neals", "neant", "neaps", + "nears", "neath", "neato", "neats", "nebby", + "nebek", "nebel", "neche", "necks", "neddy", + "neebs", "needs", "neefs", "neeld", "neele", + "neemb", "neems", "neeps", "neese", "neeze", + "nefie", "negri", "negro", "negus", "neifs", + "neigh", "neist", "neive", "nelia", "nelis", + "nelly", "nemas", "nemic", "nemns", "nempt", + "nenes", "nenta", "neons", "neosa", "neoza", + "neper", "nepit", "neral", "neram", "nerds", + "nerdy", "nerfs", "nerka", "nerks", "nerol", + "nerts", "nertz", "nervy", "neski", "nests", + "nesty", "netas", "netes", "netop", "netta", + "netts", "netty", "neuks", "neume", "neums", + "nevel", "neves", "nevis", "nevus", "nevvy", + "newbs", "newed", "newel", "newie", "newsy", + "newts", "nexal", "nexin", "nexts", "nexum", + "ngaio", "ngaka", "ngana", "ngapi", "ngati", + "ngege", "ngoma", "ngoni", "ngram", "ngwee", + "nibby", "nicad", "niced", "nicey", "nicht", + "nicks", "nicky", "nicol", "nidal", "nided", + "nides", "nidor", "nidus", "niece", "niefs", + "niess", "nieve", "nifes", "niffs", "niffy", + "nifle", "nifty", "niger", "nigga", "nighs", + "nigre", "nigua", "nihil", "nikab", "nikah", + "nikau", "nilas", "nills", "nimbi", "nimbs", + "nimby", "nimps", "niner", "nines", "ninon", + "ninta", "niopo", "nioza", "nipas", "nipet", + "nippy", "niqab", "nirls", "nirly", "nisei", + "nisin", "nisse", "nisus", "nital", "niter", + "nites", "nitid", "niton", "nitre", "nitro", + "nitry", "nitta", "nitto", "nitty", "nival", + "nivas", "nivel", "nixed", "nixer", "nixes", + "nixie", "nizam", "njirl", "nkosi", "nmoli", + "nmols", "noahs", "nobby", "nocks", "nodal", + "noddy", "noded", "nodes", "nodum", "nodus", + "noels", "noema", "noeme", "nogal", "noggs", + "noggy", "nohow", "noias", "noils", "noily", + "noint", "noire", "noirs", "nokes", "noles", + "nolle", "nolls", "nolos", "nomas", "nomen", + "nomes", "nomic", "nomoi", "nomos", "nonan", + "nonas", "nonce", "noncy", "nonda", "nondo", + "nones", "nonet", "nongs", "nonic", "nonis", + "nonna", "nonno", "nonny", "nonyl", "noobs", + "noois", "nooit", "nooks", "nooky", "noone", + "noons", "noops", "noove", "nopal", "noria", + "norie", "noris", "norks", "norma", "norms", + "nosed", "noser", "noses", "nosey", "noshi", + "nosir", "notal", "notam", "noter", "notes", + "notum", "nougs", "nouja", "nould", "noule", + "nouls", "nouns", "nouny", "noups", "noust", + "novae", "novas", "novia", "novio", "novum", + "noway", "nowds", "nowed", "nowls", "nowts", + "nowty", "noxal", "noxas", "noxes", "noyau", + "noyed", "noyes", "nrtta", "nrtya", "nsima", + "nubby", "nubia", "nucha", "nucin", "nuddy", + "nuder", "nudes", "nudgy", "nudie", "nudzh", + "nuevo", "nuffs", "nugae", "nujol", "nuked", + "nukes", "nulla", "nullo", "nulls", "nully", + "numbs", "numen", "nummy", "numps", "nunks", + "nunky", "nunny", "nunus", "nuque", "nurds", + "nurdy", "nurls", "nurrs", "nurts", "nurtz", + "nused", "nuses", "nutso", "nutsy", "nyaff", + "nyala", "nyams", "nying", "nyong", "nyssa", + "nyung", "nyuse", "nyuze", "oafos", "oaked", + "oaker", "oakum", "oared", "oarer", "oasal", + "oases", "oasts", "oaten", "oater", "oaths", + "oaves", "obang", "obbos", "obeah", "obeli", + "obese", "obeys", "obias", "obied", "obiit", + "obits", "objet", "oboes", "obole", "oboli", + "obols", "occam", "ocher", "oches", "ochre", + "ochry", "ocker", "ocote", "ocrea", "octad", + "octal", "octan", "octas", "octic", "octli", + "octyl", "oculi", "odahs", "odals", "odder", + "odeon", "odeum", "odism", "odist", "odium", + "odoom", "odors", "odour", "odums", "odyle", + "odyls", "ofays", "offed", "offie", "oflag", + "ofter", "ofuro", "ogams", "ogeed", "ogees", + "oggin", "ogham", "ogive", "ogled", "ogler", + "ogles", "ogmic", "ogres", "ohelo", "ohias", + "ohing", "ohmic", "ohone", "oicks", "oidia", + "oiled", "oiler", "oilet", "oinks", "oints", + "oiran", "ojime", "okapi", "okays", "okehs", + "okies", "oking", "okole", "okras", "okrug", + "oktas", "olate", "olden", "older", "oldie", + "oldly", "olehs", "oleic", "olein", "olent", + "oleos", "oleum", "oleyl", "oligo", "olios", + "oliva", "ollas", "ollav", "oller", "ollie", + "ology", "olona", "olpae", "olpes", "omasa", + "omber", "ombre", "ombus", "omdah", "omdas", + "omdda", "omdeh", "omees", "omens", "omers", + "omiai", "omits", "omlah", "ommel", "ommin", + "omnes", "omovs", "omrah", "omuls", "oncer", + "onces", "oncet", "oncus", "ondes", "ondol", + "onely", "oners", "onery", "ongon", "onion", + "onium", "onkus", "onlap", "onlay", "onmun", + "onned", "onsen", "ontal", "ontic", "ooaas", + "oobit", "oohed", "ooids", "oojah", "oomph", + "oonts", "oopak", "ooped", "oopsy", "oorie", + "ooses", "ootid", "ooyah", "oozed", "oozes", + "oozie", "oozle", "opahs", "opals", "opens", + "opepe", "opery", "opgaf", "opihi", "opine", + "oping", "oppos", "opsat", "opsin", "opsit", + "opted", "opter", "opzit", "orach", "oracy", + "orals", "orang", "orans", "orant", "orate", + "orbat", "orbed", "orbic", "orcas", "orcin", + "ordie", "ordos", "oread", "orfes", "orful", + "orgia", "orgic", "orgue", "oribi", "oriel", + "origo", "orixa", "orles", "orlon", "orlop", + "ormer", "ornee", "ornis", "orped", "orpin", + "orris", "ortet", "ortho", "orval", "orzos", + "osars", "oscar", "osetr", "oseys", "oshac", + "osier", "oskin", "oslin", "osmic", "osmol", + "osone", "ossia", "ostia", "otaku", "otary", + "othyl", "otium", "ottar", "ottos", "oubit", + "ouche", "oucht", "oueds", "ouens", "ouija", + "oulks", "oumas", "oundy", "oupas", "ouped", + "ouphe", "ouphs", "ourey", "ourie", "ousel", + "ousia", "ousts", "outby", "outed", "outen", + "outgo", "outie", "outre", "outro", "outta", + "ouzel", "ouzos", "ovals", "ovels", "ovens", + "overs", "ovine", "ovism", "ovist", "ovoli", + "ovolo", "ovule", "oware", "owari", "owche", + "owers", "owies", "owled", "owler", "owlet", + "owned", "ownio", "owres", "owrie", "owsen", + "oxbow", "oxeas", "oxers", "oxeye", "oxids", + "oxies", "oxime", "oxims", "oxine", "oxlip", + "oxman", "oxmen", "oxter", "oyama", "oyers", + "ozeki", "ozena", "ozzie", "paaho", "paals", + "paans", "pacai", "pacas", "pacay", "paced", + "pacer", "paces", "pacey", "pacha", "packs", + "packy", "pacos", "pacta", "pacts", "padam", + "padas", "paddo", "padis", "padle", "padma", + "padou", "padre", "padri", "paean", "paedo", + "paeon", "paged", "pager", "pages", "pagle", + "pagne", "pagod", "pagri", "pahit", "pahos", + "pahus", "paiks", "pails", "pains", "paipe", + "paips", "paire", "pairs", "paisa", "paise", + "pakay", "pakka", "pakki", "pakua", "pakul", + "palak", "palar", "palas", "palay", "palea", + "paled", "pales", "palet", "palis", "palki", + "palla", "palls", "pallu", "pally", "palms", + "palmy", "palpi", "palps", "palsa", "palus", + "pamby", "pampa", "panax", "pance", "panch", + "panda", "pands", "pandy", "paned", "panes", + "panga", "pangs", "panim", "panir", "panko", + "panks", "panna", "panne", "panni", "panny", + "panto", "pants", "panty", "paoli", "paolo", + "papad", "papas", "papaw", "papes", "papey", + "pappi", "pappy", "papri", "parae", "paras", + "parcs", "pardi", "pards", "pardy", "pared", + "paren", "pareo", "parer", "pares", "pareu", + "parev", "parge", "pargo", "parid", "paris", + "parki", "parks", "parky", "parle", "parly", + "parma", "parmo", "parms", "parol", "parps", + "parra", "parrs", "parte", "parti", "parts", + "parve", "parvo", "pasag", "pasar", "pasch", + "paseo", "pases", "pasha", "pashm", "paska", + "pasmo", "paspy", "passe", "passu", "pasts", + "patas", "pated", "patee", "patel", "paten", + "pater", "pates", "paths", "patia", "patin", + "patka", "patly", "patta", "patte", "pattu", + "patus", "pauas", "pauls", "pauxi", "pavan", + "pavas", "paved", "paven", "paver", "paves", + "pavid", "pavie", "pavin", "pavis", "pavon", + "pavvy", "pawas", "pawaw", "pawed", "pawer", + "pawks", "pawky", "pawls", "pawns", "paxes", + "payed", "payer", "payor", "paysd", "peage", + "peags", "peake", "peaks", "peaky", "peals", + "peans", "peare", "pears", "peart", "pease", + "peasy", "peats", "peaty", "peavy", "peaze", + "pebas", "pechs", "pecia", "pecke", "pecks", + "pecky", "pects", "pedes", "pedis", "pedon", + "pedos", "pedro", "peece", "peeks", "peeky", + "peels", "peely", "peens", "peent", "peeoy", + "peepe", "peeps", "peepy", "peers", "peery", + "peeve", "peevo", "peggy", "peghs", "pegma", + "pegos", "peine", "peins", "peise", "peisy", + "peize", "pekan", "pekau", "pekea", "pekes", + "pekid", "pekin", "pekoe", "pelas", "pelau", + "pelch", "peles", "pelfs", "pells", "pelma", + "pelog", "pelon", "pelsh", "pelta", "pelts", + "pelus", "pends", "pendu", "pened", "penes", + "pengo", "penie", "penis", "penks", "penna", + "penne", "penni", "pense", "pensy", "pents", + "peola", "peons", "peony", "pepla", "peple", + "pepon", "pepos", "pepsi", "pequi", "perae", + "perai", "perce", "percs", "perdu", "perdy", + "perea", "peres", "perfs", "peris", "perks", + "perle", "perls", "perms", "permy", "perne", + "perns", "perog", "perps", "perry", "perse", + "persp", "perst", "perts", "perve", "pervo", + "pervs", "pervy", "pesch", "pesos", "pesta", + "pesto", "pests", "pesty", "petar", "peter", + "petit", "petos", "petre", "petri", "petti", + "petto", "pewed", "pewee", "pewit", "peyse", + "pfftt", "phage", "phang", "phare", "pharm", + "phasm", "pheer", "pheme", "phene", "pheon", + "phese", "phial", "phies", "phish", "phizz", + "phlox", "phobe", "phoca", "phono", "phons", + "phony", "phooh", "phooo", "phota", "phots", + "photy", "phpht", "phubs", "phuts", "phutu", + "phwat", "phyla", "phyle", "phyma", "phynx", + "physa", "piais", "piani", "pians", "pibal", + "pical", "picas", "piccy", "picey", "pichi", + "picks", "picon", "picot", "picra", "picul", + "pieds", "piend", "piers", "piert", "pieta", + "piets", "piezo", "pight", "pigly", "pigmy", + "piing", "pikas", "pikau", "piked", "pikel", + "piker", "pikes", "pikey", "pikis", "pikul", + "pilae", "pilaf", "pilao", "pilar", "pilau", + "pilaw", "pilch", "pilea", "piled", "pilei", + "piler", "piles", "piley", "pilin", "pilis", + "pills", "pilon", "pilow", "pilum", "pilus", + "pimas", "pimps", "pinas", "pinax", "pince", + "pinda", "pinds", "pined", "piner", "pines", + "pinga", "pinge", "pingo", "pings", "pinko", + "pinks", "pinky", "pinna", "pinny", "pinol", + "pinon", "pinot", "pinta", "pinto", "pints", + "pinup", "pions", "piony", "pioye", "pioys", + "pipal", "pipas", "piped", "pipes", "pipet", + "pipid", "pipis", "pippy", "pipul", "pique", + "piqui", "pirai", "pirks", "pirls", "pirns", + "pirog", "pirre", "pirri", "pirrs", "pisco", + "pises", "pisky", "pisos", "pissy", "piste", + "pitas", "pitch", "piths", "pithy", "piton", + "pitot", "pitso", "pitsu", "pitta", "pittu", + "piuma", "piums", "pivos", "pivot", "pixes", + "piyut", "pized", "pizer", "pizes", "plaas", + "plack", "plaga", "plage", "plaig", "planc", + "planh", "plans", "plaps", "plash", "plasm", + "plast", "plats", "platt", "platy", "plaud", + "plaur", "plavs", "playa", "plays", "pleas", + "plebe", "plebs", "pleck", "pleep", "plein", + "plena", "plene", "pleno", "pleon", "plesh", + "plets", "plews", "plexi", "plica", "plies", + "pligs", "plims", "pling", "plink", "plips", + "plish", "ploat", "ploce", "plock", "plods", + "ploit", "plomb", "plong", "plonk", "plook", + "ploot", "plops", "plore", "plots", "plotz", + "plouk", "plout", "plows", "plowt", "ploye", + "ploys", "pluds", "plues", "pluff", "plugs", + "pluke", "plums", "plumy", "plung", "pluot", + "plups", "plute", "pluto", "pluty", "plyer", + "pneus", "poach", "poaka", "poake", "poalo", + "pobby", "poboy", "pocan", "poche", "pocho", + "pocks", "pocky", "podal", "poddy", "podex", + "podge", "podgy", "podia", "podos", "podus", + "poems", "poena", "poeps", "poete", "poets", + "pogey", "pogge", "poggy", "pogos", "pogue", + "pohed", "poilu", "poind", "poire", "pokal", + "poked", "pokes", "pokey", "pokie", "pokit", + "poled", "poler", "poles", "poley", "polio", + "polis", "polje", "polks", "pollo", "polls", + "polly", "polos", "polts", "polys", "pomas", + "pombe", "pomes", "pomme", "pommy", "pomos", + "pompa", "pomps", "ponce", "poncy", "ponds", + "pondy", "pones", "poney", "ponga", "pongo", + "pongs", "pongy", "ponks", "ponor", "ponto", + "ponts", "ponty", "ponzu", "pooay", "poods", + "pooed", "pooey", "poofs", "poofy", "poohs", + "poohy", "pooja", "pooka", "pooks", "pools", + "pooly", "poons", "poopa", "poops", "poopy", + "poori", "poort", "poots", "pooty", "poove", + "poovy", "popes", "popia", "popos", "poppa", + "popsy", "popup", "porae", "poral", "pored", + "porer", "pores", "porey", "porge", "porgy", + "porin", "porks", "porky", "porno", "porns", + "porny", "porta", "porte", "porth", "ports", + "porty", "porus", "posca", "posed", "poses", + "poset", "posey", "posho", "posol", "poste", + "posts", "potae", "potai", "potch", "poted", + "potes", "potin", "potoo", "potro", "potsy", + "potto", "potts", "potty", "pouce", "pouff", + "poufs", "poufy", "pouis", "pouke", "pouks", + "poule", "poulp", "poupe", "poupt", "pours", + "pousy", "pouts", "povos", "powan", "powie", + "powin", "powis", "powlt", "pownd", "powns", + "powny", "powre", "powsy", "poxed", "poxes", + "poyas", "poynt", "poyou", "poyse", "pozzy", + "praam", "prads", "prags", "prahu", "prams", + "prana", "prang", "praos", "praps", "prase", + "prate", "prats", "pratt", "praty", "praus", + "prays", "preak", "predy", "preed", "preem", + "prees", "preif", "preke", "prems", "premy", + "prent", "preon", "preop", "preps", "presa", + "prese", "prest", "preta", "preux", "preve", + "prexy", "preys", "prial", "prian", "pricy", + "pridy", "prief", "prier", "pries", "prigs", + "prill", "prima", "primi", "primp", "prims", + "primy", "pring", "prink", "prion", "prise", + "priss", "prius", "proal", "proas", "probs", + "proby", "prodd", "prods", "proem", "profs", + "progs", "proin", "proke", "prole", "proll", + "promo", "proms", "pronk", "prook", "proot", + "props", "prora", "prore", "proso", "pross", + "prost", "prosy", "proto", "proul", "prowk", + "prows", "proxy", "proyn", "pruno", "prunt", + "pruny", "pruta", "pryan", "pryer", "pryse", + "pseud", "pshaw", "pshut", "psias", "psion", + "psoae", "psoai", "psoas", "psora", "psych", + "psyop", "ptish", "ptype", "pubby", "pubco", + "pubes", "pubis", "pubsy", "pucan", "pucer", + "puces", "pucka", "pucks", "puddy", "pudge", + "pudic", "pudor", "pudsy", "pudus", "puers", + "puffa", "puffs", "puffy", "puggy", "pugil", + "puhas", "pujah", "pujas", "pukas", "puked", + "puker", "pukes", "pukey", "pukka", "pukus", + "pulao", "pulas", "puled", "puler", "pules", + "pulik", "pulis", "pulka", "pulks", "pulli", + "pulls", "pully", "pulmo", "pulps", "pulpy", + "pulus", "pulut", "pumas", "pumie", "pumps", + "pumpy", "punas", "punce", "punga", "pungi", + "pungo", "pungs", "pungy", "punim", "punji", + "punka", "punks", "punky", "punny", "punto", + "punts", "punty", "pupae", "pupal", "pupas", + "puppa", "pupus", "purao", "purau", "purda", + "purdy", "pured", "purer", "pures", "purga", + "purin", "puris", "purls", "puros", "purps", + "purpy", "purre", "purrs", "purry", "pursy", + "purty", "puses", "pusle", "pussy", "putas", + "puter", "putid", "putin", "puton", "putos", + "putti", "putto", "putts", "puttu", "putza", + "puuko", "puyas", "puzel", "puzta", "pwned", + "pyats", "pyets", "pygal", "pyins", "pylon", + "pyned", "pynes", "pyoid", "pyots", "pyral", + "pyran", "pyres", "pyrex", "pyric", "pyros", + "pyrus", "pyuff", "pyxed", "pyxes", "pyxie", + "pyxis", "pzazz", "qadis", "qaids", "qajaq", + "qanat", "qapik", "qibla", "qilas", "qipao", + "qophs", "qorma", "quabs", "quads", "quags", + "quair", "quais", "quaky", "quale", "qualy", + "quank", "quant", "quare", "quark", "quarl", + "quash", "quass", "quate", "quats", "quawk", + "quaws", "quayd", "quays", "qubit", "quean", + "queck", "queek", "queem", "quell", "queme", + "quena", "quern", "queso", "quete", "queyn", + "queys", "queyu", "quibs", "quich", "quids", + "quies", "quiff", "quila", "quilt", "quims", + "quina", "quine", "quink", "quino", "quins", + "quint", "quipo", "quips", "quipu", "quire", + "quirl", "quirt", "quist", "quits", "quoad", + "quods", "quoif", "quoin", "quois", "quoit", + "quoll", "quonk", "quops", "quork", "quorl", + "quouk", "quoys", "quran", "qursh", "quyte", + "raads", "raake", "rabat", "rabic", "rabis", + "raced", "races", "rache", "racks", "racon", + "raddi", "raddy", "radge", "radgy", "radif", + "radix", "rafee", "raffs", "raffy", "rafik", + "rafiq", "rafts", "rafty", "ragas", "ragde", + "raged", "ragee", "rager", "rages", "ragga", + "raggs", "raggy", "ragis", "ragus", "rahed", + "rahui", "raiah", "raias", "raids", "raike", + "raiks", "raile", "rails", "raine", "rains", + "rainy", "raird", "raise", "raita", "raith", + "raits", "rajah", "rajas", "rajes", "raked", + "rakee", "raker", "rakes", "rakhi", "rakia", + "rakis", "rakki", "raksi", "rakus", "rales", + "ralli", "ralph", "ramal", "ramee", "rames", + "ramet", "ramie", "ramin", "ramis", "rammy", + "ramon", "ramps", "ramse", "ramsh", "ramus", + "ranas", "rance", "rando", "rands", "raned", + "ranee", "ranes", "ranga", "rangi", "rangs", + "rangy", "ranid", "ranis", "ranke", "ranks", + "ranns", "ranny", "ranse", "rants", "ranty", + "raped", "rapee", "raper", "rapes", "raphe", + "rapin", "rappe", "rapso", "rared", "raree", + "rares", "rarks", "rasam", "rasas", "rased", + "raser", "rases", "rasps", "rasse", "rasta", + "ratal", "ratan", "ratas", "ratch", "rated", + "ratel", "rater", "rates", "ratha", "rathe", + "raths", "ratoo", "ratos", "ratti", "ratty", + "ratus", "rauli", "rauns", "raupo", "raved", + "ravel", "raver", "raves", "ravey", "ravin", + "rawdy", "rawer", "rawin", "rawks", "rawly", + "rawns", "raxed", "raxes", "rayah", "rayas", + "rayed", "rayle", "rayls", "rayne", "razai", + "razed", "razee", "razer", "razes", "razet", + "razoo", "readd", "reads", "reais", "reaks", + "realo", "reals", "reame", "reams", "reamy", + "reans", "reaps", "reard", "rearm", "rears", + "reast", "reata", "reate", "reave", "rebab", + "rebar", "rebbe", "rebec", "rebid", "rebit", + "rebop", "rebud", "rebuy", "recal", "recce", + "recco", "reccy", "recep", "recit", "recks", + "recon", "recta", "recte", "recti", "recto", + "recue", "recut", "redan", "redds", "reddy", + "reded", "redes", "redia", "redid", "redif", + "redig", "redip", "redly", "redon", "redos", + "redox", "redry", "redub", "redug", "redux", + "redye", "reeaf", "reech", "reede", "reeds", + "reefs", "reefy", "reeks", "reeky", "reels", + "reely", "reems", "reens", "reerd", "reest", + "reeve", "reeze", "refan", "refed", "refel", + "reffo", "refis", "refit", "refix", "refly", + "refry", "regar", "reges", "reget", "regex", + "reggo", "regia", "regie", "regle", "regma", + "regna", "regos", "regot", "regur", "rehem", + "reifs", "reify", "reiki", "reiks", "reine", + "reing", "reink", "reins", "reird", "reist", + "reive", "rejas", "rejig", "rejon", "reked", + "rekes", "rekey", "relet", "relie", "relit", + "rello", "relos", "reman", "remap", "remen", + "remet", "remex", "remix", "remou", "renay", + "rends", "rendu", "reney", "renga", "rengs", + "renig", "renin", "renks", "renne", "renos", + "rente", "rents", "reoil", "reorg", "repas", + "repat", "repeg", "repen", "repin", "repla", + "repos", "repot", "repps", "repro", "repun", + "reput", "reran", "rerig", "resam", "resat", + "resaw", "resay", "resee", "reses", "resew", + "resid", "resit", "resod", "resol", "resow", + "resto", "rests", "resty", "resue", "resus", + "retag", "retam", "retax", "retem", "retia", + "retie", "retin", "retip", "retox", "reune", + "reups", "revet", "revie", "revow", "revue", + "rewan", "rewax", "rewed", "rewet", "rewin", + "rewon", "rewth", "rexes", "rezes", "rhabd", + "rheas", "rheid", "rheme", "rheum", "rhies", + "rhime", "rhine", "rhino", "rhody", "rhomb", + "rhone", "rhumb", "rhyme", "rhymy", "rhyne", + "rhyta", "riads", "rials", "riant", "riata", + "riato", "ribas", "ribby", "ribes", "riced", + "ricer", "rices", "ricey", "riche", "richt", + "ricin", "ricks", "rides", "ridgy", "ridic", + "riels", "riems", "rieve", "rifer", "riffs", + "riffy", "rifte", "rifts", "rifty", "riggs", + "rigmo", "rigol", "rikka", "rikwa", "riled", + "riles", "riley", "rille", "rills", "rilly", + "rimae", "rimed", "rimer", "rimes", "rimon", + "rimus", "rince", "rinds", "rindy", "rines", + "ringe", "rings", "ringy", "rinks", "rioja", + "rione", "riots", "rioty", "riped", "ripes", + "ripps", "riqqs", "riser", "rises", "rishi", + "risks", "risps", "rists", "risus", "rites", + "rithe", "ritts", "ritzy", "rivas", "rived", + "rivel", "riven", "rives", "riyal", "rizas", + "roads", "roady", "roake", "roaky", "roams", + "roans", "roany", "roars", "roary", "roate", + "robbo", "robed", "rober", "robes", "roble", + "robug", "robur", "roche", "rocks", "roded", + "rodeo", "rodes", "rodny", "roers", "rogan", + "roger", "roguy", "rohan", "rohes", "rohun", + "rohus", "roids", "roils", "roily", "roins", + "roist", "rojak", "rojis", "roked", "roker", + "rokes", "rokey", "rokos", "rolag", "roleo", + "roles", "rolfs", "rolls", "rolly", "romal", + "roman", "romeo", "romer", "romps", "rompu", + "rompy", "ronde", "rondo", "roneo", "rones", + "ronin", "ronne", "ronte", "ronts", "ronuk", + "roods", "roofs", "roofy", "rooks", "rooky", + "rooms", "roons", "roops", "roopy", "roosa", + "roose", "roots", "rooty", "roped", "roper", + "ropes", "ropey", "roque", "roral", "rores", + "roric", "rorid", "rorie", "rorts", "rorty", + "rosal", "rosco", "rosed", "roses", "roset", + "rosha", "roshi", "rosin", "rosit", "rosps", + "rossa", "rosso", "rosti", "rosts", "rotal", + "rotan", "rotas", "rotch", "roted", "rotes", + "rotis", "rotls", "roton", "rotor", "rotos", + "rotta", "rotte", "rotto", "rotty", "rouen", + "roues", "rouet", "roufs", "rougy", "rouks", + "rouky", "roule", "rouls", "roums", "roups", + "roupy", "roust", "routh", "routs", "roved", + "roven", "roves", "rowan", "rowed", "rowel", + "rowen", "rowet", "rowie", "rowme", "rownd", + "rowns", "rowth", "rowts", "royet", "royne", + "royst", "rozes", "rozet", "rozit", "ruach", + "ruana", "rubai", "ruban", "rubby", "rubel", + "rubes", "rubin", "rubio", "ruble", "rubli", + "rubor", "rubus", "ruche", "ruchy", "rucks", + "rudas", "rudds", "ruder", "rudes", "rudie", + "rudis", "rueda", "ruers", "ruffe", "ruffs", + "ruffy", "rufus", "rugae", "rugal", "rugas", + "ruggy", "ruice", "ruing", "ruins", "rukhs", + "ruled", "rules", "rully", "rumal", "rumbo", + "rumen", "rumes", "rumly", "rummy", "rumpo", + "rumps", "rumpy", "runce", "runch", "runds", + "runed", "runer", "runes", "rungs", "runic", + "runny", "runos", "runts", "runty", "runup", + "ruote", "rupia", "rurps", "rurus", "rusas", + "ruses", "rushy", "rusks", "rusky", "rusma", + "russe", "rusts", "ruths", "rutin", "rutty", + "ruvid", "ryals", "rybat", "ryiji", "ryijy", + "ryked", "rykes", "rymer", "rymme", "rynds", + "ryoti", "ryots", "ryper", "rypin", "rythe", + "ryugi", "saags", "sabal", "sabed", "saber", + "sabes", "sabha", "sabin", "sabir", "sabji", + "sable", "sabos", "sabot", "sabra", "sabre", + "sabzi", "sacks", "sacra", "sacre", "saddo", + "saddy", "sades", "sadhe", "sadhu", "sadic", + "sadis", "sados", "sadza", "saeta", "safed", + "safes", "sagar", "sagas", "sager", "sages", + "saggy", "sagos", "sagum", "sahab", "saheb", + "sahib", "saice", "saick", "saics", "saids", + "saiga", "sails", "saims", "saine", "sains", + "sairs", "saist", "saith", "sajou", "sakai", + "saker", "sakes", "sakia", "sakis", "sakti", + "salal", "salas", "salat", "salep", "sales", + "salet", "salic", "salis", "salix", "salle", + "salmi", "salol", "salop", "salpa", "salps", + "salse", "salto", "salts", "salud", "salue", + "salut", "saman", "samas", "samba", "sambo", + "samek", "samel", "samen", "sames", "samey", + "samfi", "samfu", "sammy", "sampi", "samps", + "sanad", "sands", "saned", "sanes", "sanga", + "sangh", "sango", "sangs", "sanko", "sansa", + "santo", "sants", "saola", "sapan", "sapid", + "sapor", "saran", "sards", "sared", "saree", + "sarge", "sargo", "sarin", "sarir", "saris", + "sarks", "sarky", "sarod", "saros", "sarus", + "sarvo", "saser", "sasin", "sasse", "satai", + "satay", "sated", "satem", "sater", "sates", + "satin", "satis", "satyr", "sauba", "sauch", + "saugh", "sauls", "sault", "saunf", "saunt", + "saury", "sauts", "sauve", "saved", "saver", + "saves", "savey", "savin", "sawah", "sawed", + "sawer", "saxes", "sayas", "sayed", "sayee", + "sayer", "sayid", "sayne", "sayon", "sayst", + "sazes", "scabs", "scads", "scaff", "scags", + "scail", "scala", "scall", "scams", "scand", + "scans", "scapa", "scape", "scapi", "scarp", + "scars", "scart", "scath", "scats", "scatt", + "scaud", "scaup", "scaur", "scaws", "sceat", + "scena", "scend", "schav", "schif", "schmo", + "schul", "schwa", "scifi", "scind", "scire", + "sclim", "scobe", "scody", "scogs", "scoog", + "scoot", "scopa", "scops", "scorp", "scote", + "scots", "scoug", "scoup", "scour", "scowp", + "scows", "scrab", "scrae", "scrag", "scran", + "scrat", "scraw", "scray", "scree", "screw", + "scrim", "scrip", "scrob", "scrod", "scrog", + "scroo", "scrow", "scuba", "scudi", "scudo", + "scuds", "scuff", "scuft", "scugs", "sculk", + "scull", "sculp", "sculs", "scums", "scups", + "scurf", "scurs", "scuse", "scuta", "scute", + "scuts", "scuzz", "scyes", "sdayn", "sdein", + "seals", "seame", "seams", "seamy", "seans", + "seare", "sears", "sease", "seats", "seaze", + "sebum", "secco", "sechs", "sects", "seder", + "sedes", "sedge", "sedgy", "sedum", "seeds", + "seeks", "seeld", "seels", "seely", "seems", + "seeps", "seepy", "seers", "sefer", "segar", + "segas", "segni", "segno", "segol", "segos", + "sehri", "seifs", "seils", "seine", "seirs", + "seise", "seism", "seity", "seiza", "sekos", + "sekts", "selah", "seles", "selfs", "selfy", + "selky", "sella", "selle", "sells", "selva", + "semas", "semee", "semen", "semes", "semie", + "semis", "senas", "sends", "senes", "senex", + "sengi", "senna", "senor", "sensa", "sensi", + "sensu", "sente", "senti", "sents", "senvy", + "senza", "sepad", "sepal", "sepic", "sepoy", + "seppo", "septa", "septs", "serac", "serai", + "seral", "sered", "serer", "seres", "serfs", + "serge", "seria", "seric", "serif", "serin", + "serir", "serks", "seron", "serow", "serra", + "serre", "serrs", "serry", "serum", "servo", + "sesey", "sessa", "setae", "setal", "seter", + "seths", "seton", "setts", "sevak", "sevir", + "sewan", "sewar", "sewed", "sewel", "sewen", + "sewin", "sexed", "sexer", "sexes", "sexor", + "sexto", "sexts", "seyen", "sezes", "shads", + "shags", "shahs", "shaka", "shako", "shakt", + "shale", "shalm", "shalt", "shaly", "shama", + "shams", "shand", "shans", "shaps", "sharn", + "shart", "shash", "shaul", "shawm", "shawn", + "shaws", "shaya", "shays", "shchi", "sheaf", + "sheal", "sheas", "sheds", "sheel", "sheik", + "shend", "sheng", "shent", "sheol", "sherd", + "shere", "shero", "shets", "sheva", "shewn", + "shews", "shiai", "shied", "shiel", "shier", + "shies", "shill", "shily", "shims", "shins", + "shiok", "ships", "shirr", "shirs", "shish", + "shiso", "shist", "shite", "shits", "shiur", + "shiva", "shive", "shivs", "shlep", "shlub", + "shmek", "shmoe", "shoat", "shoed", "shoer", + "shoes", "shogi", "shogs", "shoji", "shojo", + "shola", "shonk", "shool", "shoon", "shoos", + "shope", "shops", "shorl", "shote", "shots", + "shott", "shoud", "showd", "shows", "shoyu", + "shred", "shrew", "shris", "shrow", "shtar", + "shtik", "shtum", "shtup", "shuba", "shule", + "shuln", "shuls", "shuns", "shura", "shush", + "shute", "shuts", "shwas", "shyer", "shyly", + "sials", "sibbs", "sibia", "sibyl", "sices", + "sicht", "sicko", "sicks", "sicky", "sidas", + "sided", "sider", "sides", "sidey", "sidha", + "sidhe", "sidle", "sield", "siens", "sient", + "sieth", "sieur", "sifts", "sighs", "sigil", + "sigla", "signa", "signs", "sigri", "sijos", + "sikas", "siker", "sikes", "silds", "siled", + "silen", "siler", "siles", "silex", "silks", + "sills", "silos", "silts", "silty", "silva", + "simar", "simas", "simba", "simis", "simps", + "simul", "sinds", "sined", "sines", "singe", + "sings", "sinhs", "sinks", "sinky", "sinsi", + "sinus", "siped", "sipes", "sippy", "sired", + "siree", "sires", "sirih", "siris", "siroc", + "sirra", "sirup", "sisal", "sises", "sista", + "sists", "sitar", "sitch", "sited", "sites", + "sithe", "sitka", "situp", "situs", "siver", + "sixer", "sixes", "sixmo", "sixte", "sizar", + "sizel", "sizer", "sizes", "skags", "skail", + "skald", "skank", "skarn", "skart", "skats", + "skatt", "skaws", "skean", "skear", "skeds", + "skeed", "skeef", "skeen", "skeer", "skees", + "skeet", "skeev", "skeez", "skegg", "skegs", + "skein", "skelf", "skell", "skelm", "skelp", + "skene", "skens", "skeos", "skeps", "skerm", + "skers", "skets", "skews", "skids", "skied", + "skies", "skiey", "skiff", "skill", "skimo", + "skims", "skink", "skins", "skint", "skios", + "skips", "skirl", "skirr", "skite", "skits", + "skive", "skivy", "sklim", "skoal", "skobe", + "skody", "skoff", "skofs", "skogs", "skols", + "skool", "skort", "skosh", "skran", "skrik", + "skroo", "skuas", "skugs", "skulk", "skyed", + "skyer", "skyey", "skyfs", "skyre", "skyrs", + "skyte", "slabs", "slade", "slaes", "slags", + "slaid", "slake", "slams", "slane", "slank", + "slaps", "slart", "slats", "slaty", "slaws", + "slays", "slebs", "sleds", "sleer", "slews", + "sleys", "slick", "slier", "slily", "slims", + "slipe", "slips", "slipt", "slish", "slits", + "slive", "sloan", "slobs", "sloes", "slogs", + "sloid", "slojd", "sloka", "slomo", "sloom", + "sloop", "sloot", "slops", "slopy", "slorm", + "slosh", "slots", "slove", "slows", "sloyd", + "slubb", "slubs", "slued", "slues", "sluff", + "slugs", "sluit", "slums", "slurb", "slurs", + "sluse", "slush", "sluts", "slyer", "slyly", + "slype", "smaak", "smaik", "smalm", "smalt", + "smarm", "smaze", "smeek", "smees", "smeik", + "smeke", "smerk", "smews", "smick", "smily", + "smirr", "smirs", "smits", "smize", "smogs", + "smoko", "smolt", "smoor", "smoot", "smore", + "smorg", "smote", "smout", "smowt", "smugs", + "smurs", "smush", "smuts", "snabs", "snafu", + "snags", "snaps", "snarf", "snark", "snars", + "snary", "snash", "snath", "snaws", "snead", + "sneap", "snebs", "sneck", "sneds", "sneed", + "snees", "snell", "snibs", "snick", "snied", + "snies", "snift", "snigs", "snips", "snipy", + "snirt", "snits", "snive", "snobs", "snods", + "snoek", "snoep", "snogs", "snoke", "snood", + "snook", "snool", "snoot", "snots", "snowk", + "snows", "snubs", "snugs", "snush", "snyes", + "soaks", "soaps", "soare", "soars", "soave", + "sobas", "socas", "soces", "socia", "socko", + "socks", "socle", "sodas", "soddy", "sodic", + "sodom", "sofar", "sofas", "softa", "softs", + "softy", "soger", "soggy", "sohur", "soils", + "soily", "sojas", "sojus", "sokah", "soken", + "sokes", "sokol", "solah", "solan", "solas", + "solde", "soldi", "soldo", "solds", "soled", + "solei", "soler", "soles", "solon", "solos", + "solum", "solus", "soman", "somas", "sonar", + "sonce", "sonde", "sones", "songo", "songs", + "songy", "sonly", "sonne", "sonny", "sonse", + "sonsy", "sooey", "sooks", "sooky", "soole", + "sools", "sooms", "soops", "soote", "soots", + "sophs", "sophy", "sopor", "soppy", "sopra", + "soral", "soras", "sorbi", "sorbo", "sorbs", + "sorda", "sordo", "sords", "sored", "soree", + "sorel", "sorer", "sores", "sorex", "sorgo", + "sorns", "sorra", "sorta", "sorts", "sorus", + "soths", "sotol", "sotto", "souce", "souct", + "sough", "souks", "souls", "souly", "soums", + "soups", "soupy", "sours", "souse", "souts", + "sowar", "sowce", "sowed", "sower", "sowff", + "sowfs", "sowle", "sowls", "sowms", "sownd", + "sowne", "sowps", "sowse", "sowth", "soxes", + "soyas", "soyle", "soyuz", "sozin", "spack", + "spacy", "spado", "spads", "spaed", "spaer", + "spaes", "spags", "spahi", "spail", "spain", + "spait", "spake", "spald", "spale", "spall", + "spalt", "spams", "spane", "spang", "spans", + "spard", "spars", "spart", "spate", "spats", + "spaul", "spawl", "spaws", "spayd", "spays", + "spaza", "spazz", "speal", "spean", "speat", + "specs", "spect", "speel", "speer", "speil", + "speir", "speks", "speld", "spelk", "spelt", + "speos", "sperm", "spesh", "spets", "speug", + "spews", "spewy", "spial", "spica", "spick", + "spics", "spide", "spiel", "spier", "spies", + "spiff", "spifs", "spiks", "spile", "spilt", + "spims", "spina", "spink", "spins", "spiny", + "spire", "spirt", "spiry", "spits", "spitz", + "spivs", "splay", "splog", "spode", "spods", + "spoom", "spoor", "spoot", "spork", "sposa", + "sposh", "sposo", "spots", "sprad", "sprag", + "sprat", "spred", "sprew", "sprit", "sprod", + "sprog", "sprue", "sprug", "spuds", "spued", + "spuer", "spues", "spugs", "spule", "spume", + "spumy", "spurs", "spurt", "sputa", "spyal", + "spyre", "squab", "squaw", "squee", "squeg", + "squib", "squit", "squiz", "srsly", "stabs", + "stade", "stags", "stagy", "staig", "stane", + "stang", "stans", "staps", "starn", "starr", + "stars", "stary", "stats", "statu", "staun", + "staws", "stays", "stean", "stear", "stedd", + "stede", "steds", "steed", "steek", "steem", + "steen", "steez", "steik", "steil", "stein", + "stela", "stele", "stell", "steme", "stems", + "stend", "steno", "stens", "stent", "steps", + "stept", "stere", "stets", "stews", "stewy", + "steys", "stich", "stied", "sties", "stilb", + "stile", "stime", "stims", "stimy", "stipa", + "stipe", "stire", "stirk", "stirp", "stirs", + "stive", "stivy", "stoae", "stoai", "stoas", + "stoat", "stobs", "stoep", "stogs", "stogy", + "stoit", "stoln", "stoma", "stond", "stong", + "stonk", "stonn", "stook", "stoor", "stope", + "stops", "stopt", "stoss", "stots", "stott", + "stoun", "stoup", "stour", "stown", "stowp", + "stows", "strad", "strae", "strag", "strak", + "strep", "stria", "strig", "strim", "strop", + "strow", "stroy", "strum", "strut", "stubs", + "stucs", "stude", "studs", "stull", "stulm", + "stumm", "stums", "stuns", "stupa", "stupe", + "sture", "sturt", "stush", "styed", "styes", + "styli", "stylo", "styme", "stymy", "styre", + "styte", "subah", "subak", "subas", "subby", + "suber", "subha", "succi", "sucks", "sucky", + "sucre", "sudan", "sudds", "sudor", "sudsy", + "suede", "suent", "suers", "suete", "suets", + "suety", "sugan", "sughs", "sugos", "suhur", + "suids", "suint", "suits", "sujee", "sukhs", + "sukis", "sukuk", "sulci", "sulfa", "sulfo", + "sulks", "sulls", "sully", "sulph", "sulus", + "sumac", "sumis", "summa", "sumos", "sumph", + "sumps", "sunis", "sunks", "sunna", "sunns", + "sunts", "sunup", "suona", "suped", "supes", + "supra", "surah", "sural", "suras", "surat", + "surds", "sured", "surer", "sures", "surfs", + "surfy", "surgy", "surra", "sused", "suses", + "susus", "sutor", "sutra", "sutta", "swabs", + "swack", "swads", "swage", "swags", "swail", + "swain", "swale", "swaly", "swami", "swamy", + "swang", "swank", "swans", "swaps", "swapt", + "sward", "sware", "swarf", "swart", "swash", + "swats", "swayl", "sways", "sweal", "swede", + "sweed", "sweel", "sweer", "swees", "sweir", + "swelt", "swerf", "sweys", "swies", "swigs", + "swile", "swims", "swink", "swire", "swiss", + "swith", "swits", "swive", "swizz", "swobs", + "swole", "swoll", "swoln", "swops", "swopt", + "swots", "swoun", "sybbe", "sybil", "syboe", + "sybow", "sycee", "syces", "sycon", "syeds", + "syens", "syker", "sykes", "sylis", "sylph", + "sylva", "symar", "synch", "syncs", "synds", + "syned", "synes", "synth", "syped", "sypes", + "syphs", "syrah", "syren", "sysop", "sythe", + "syver", "taals", "taata", "tabac", "taber", + "tabes", "tabid", "tabis", "tabla", "tabls", + "tabor", "tabos", "tabun", "tabus", "tacan", + "taces", "tacet", "tache", "tachi", "tacho", + "tachs", "tacks", "tacos", "tacts", "tadah", + "taels", "tafia", "taggy", "tagma", "tagua", + "tahas", "tahrs", "taiga", "taigs", "taiko", + "tails", "tains", "taira", "taish", "taits", + "tajes", "takas", "takes", "takhi", "takht", + "takin", "takis", "takky", "talak", "talaq", + "talar", "talas", "talcs", "talcy", "talea", + "taler", "tales", "talik", "talks", "talky", + "talls", "tally", "talma", "talpa", "taluk", + "talus", "tamal", "tamas", "tamed", "tames", + "tamin", "tamis", "tammy", "tamps", "tanas", + "tanga", "tangi", "tangs", "tanhs", "tania", + "tanka", "tanks", "tanky", "tanna", "tansu", + "tansy", "tante", "tanti", "tanto", "tanty", + "tapas", "taped", "tapen", "tapes", "tapet", + "tapis", "tappa", "tapus", "taras", "tardo", + "tards", "tared", "tares", "targa", "targe", + "tarka", "tarns", "taroc", "tarok", "taros", + "tarps", "tarre", "tarry", "tarse", "tarsi", + "tarte", "tarts", "tarty", "tarzy", "tasar", + "tasca", "tased", "taser", "tases", "tasks", + "tassa", "tasse", "tasso", "tasto", "tatar", + "tater", "tates", "taths", "tatie", "tatou", + "tatts", "tatus", "taube", "tauld", "tauon", + "taupe", "tauts", "tauty", "tavah", "tavas", + "taver", "tawaf", "tawai", "tawas", "tawed", + "tawer", "tawie", "tawse", "tawts", "taxed", + "taxer", "taxes", "taxis", "taxol", "taxon", + "taxor", "taxus", "tayra", "tazza", "tazze", + "teade", "teads", "teaed", "teaks", "teals", + "teams", "tears", "teats", "teaze", "techs", + "techy", "tecta", "tecum", "teels", "teems", + "teend", "teene", "teens", "teeny", "teers", + "teets", "teffs", "teggs", "tegua", "tegus", + "tehee", "tehrs", "teiid", "teils", "teind", + "teins", "tekke", "telae", "telco", "teles", + "telex", "telia", "telic", "tells", "telly", + "teloi", "telos", "temed", "temes", "tempi", + "temps", "tempt", "temse", "tench", "tends", + "tendu", "tenes", "tenge", "tenia", "tenne", + "tenno", "tenny", "tenon", "tents", "tenty", + "tenue", "tepal", "tepas", "tepoy", "terai", + "teras", "terce", "terek", "teres", "terfe", + "terfs", "terga", "terms", "terne", "terns", + "terre", "terry", "terts", "terza", "tesla", + "testa", "teste", "tests", "testy", "tetes", + "teths", "tetra", "tetri", "teuch", "teugh", + "tewed", "tewel", "tewit", "texas", "texes", + "texta", "texts", "thack", "thagi", "thaim", + "thale", "thali", "thana", "thane", "thang", + "thank", "thans", "thanx", "tharm", "thars", + "thaws", "thawt", "thawy", "thebe", "theca", + "theed", "theek", "thees", "thegn", "theic", + "thein", "thelf", "thema", "thens", "theor", + "theow", "therm", "these", "thesp", "theta", + "thete", "thews", "thewy", "thigs", "thilk", + "thill", "thine", "thins", "thiol", "thirl", + "thoft", "thole", "tholi", "thong", "thoro", + "thorp", "thots", "thous", "thowl", "thrae", + "thraw", "thrid", "thrip", "throe", "thuds", + "thugs", "thuja", "thunk", "thurl", "thuya", + "thymi", "thymy", "tians", "tiare", "tiars", + "tibia", "tical", "ticca", "ticed", "tices", + "tichy", "ticks", "ticky", "tiddy", "tided", + "tides", "tiefs", "tiers", "tiffs", "tifos", + "tifts", "tiges", "tigon", "tikas", "tikes", + "tikia", "tikis", "tikka", "tilak", "tilde", + "tiled", "tiler", "tiles", "tills", "tilly", + "tilth", "tilts", "timbo", "timed", "times", + "timon", "timps", "tinas", "tinct", "tinds", + "tinea", "tined", "tines", "tinge", "tings", + "tinks", "tinny", "tinto", "tints", "tinty", + "tipis", "tippy", "tipup", "tired", "tires", + "tirls", "tiros", "tirrs", "tirth", "titar", + "titas", "titch", "titer", "tithe", "tithi", + "titin", "titir", "titis", "titre", "titty", + "titup", "tiyin", "tiyns", "tizes", "tizzy", + "toads", "toady", "toaze", "tocks", "tocky", + "tocos", "todde", "toddy", "todea", "todos", + "toeas", "toffs", "toffy", "tofts", "tofus", + "togae", "togas", "toged", "toges", "togue", + "tohos", "toidy", "toile", "toils", "toing", + "toise", "toits", "toity", "tokay", "toked", + "toker", "tokes", "tokos", "tolan", "tolar", + "tolas", "toled", "toles", "tolls", "tolly", + "tolts", "tolus", "tolyl", "toman", "tombo", + "tombs", "tomen", "tomes", "tomia", "tomin", + "tomme", "tommy", "tomos", "tomoz", "tondi", + "tondo", "toned", "toner", "tones", "toney", + "tonga", "tonka", "tonks", "tonne", "tonus", + "tools", "tooms", "toons", "toots", "toped", + "topee", "topek", "toper", "topes", "tophe", + "tophi", "tophs", "topis", "topoi", "topos", + "toppy", "toque", "torah", "toran", "toras", + "torcs", "tores", "toric", "torii", "toros", + "torot", "torrs", "torse", "torsi", "torsk", + "torta", "torte", "torts", "torus", "tosas", + "tosed", "toses", "toshy", "tossy", "tosyl", + "toted", "toter", "totes", "totty", "touks", + "touns", "tours", "touse", "tousy", "touts", + "touze", "touzy", "towai", "towed", "towie", + "towno", "towns", "towny", "towse", "towsy", + "towts", "towze", "towzy", "toxin", "toyed", + "toyer", "toyon", "toyos", "tozed", "tozes", + "tozie", "trabs", "tract", "trads", "trady", + "traga", "tragi", "trags", "tragu", "traik", + "trams", "trank", "tranq", "trans", "trant", + "trape", "trapo", "traps", "trapt", "trass", + "trats", "tratt", "trave", "trayf", "trays", + "treck", "treed", "treen", "trees", "trefa", + "treif", "treks", "trema", "trems", "tress", + "trest", "trets", "trews", "treyf", "treys", + "triac", "trice", "tride", "trier", "tries", + "trifa", "triff", "trigo", "trigs", "trike", + "trild", "trims", "trine", "trins", "triol", + "trior", "trios", "tripe", "trips", "tripy", + "trist", "troad", "troak", "troat", "trock", + "trode", "trods", "trogs", "trois", "troke", + "tromp", "trona", "tronc", "trone", "tronk", + "trons", "trooz", "tropo", "trots", "trove", + "trows", "troys", "trued", "truer", "trues", + "trugo", "trugs", "trull", "tryer", "tryke", + "tryma", "tryps", "tsade", "tsadi", "tsars", + "tsked", "tsuba", "tsubo", "tuans", "tuart", + "tuath", "tubae", "tubal", "tubar", "tubas", + "tubby", "tubed", "tuber", "tubes", "tucks", + "tufas", "tuffe", "tuffs", "tufts", "tufty", + "tugra", "tuile", "tuina", "tuism", "tuktu", + "tules", "tulle", "tulpa", "tulps", "tulsi", + "tumid", "tummy", "tumps", "tumpy", "tunas", + "tunds", "tuned", "tunes", "tungs", "tunny", + "tupek", "tupik", "tuple", "tuque", "turds", + "turfs", "turfy", "turks", "turme", "turms", + "turns", "turnt", "turon", "turps", "turrs", + "tushy", "tusks", "tusky", "tutee", "tutes", + "tutti", "tutty", "tutus", "tuxes", "tuyer", + "twaes", "twals", "twank", "twats", "tways", + "tweel", "tween", "tweep", "tweer", "twerk", + "twerp", "twier", "twigs", "twilt", "twink", + "twins", "twiny", "twire", "twirk", "twirl", + "twirp", "twite", "twits", "twixt", "twocs", + "twoer", "twonk", "twyer", "tyees", "tyers", + "tyiyn", "tykes", "tyler", "tymps", "tynde", + "tyned", "tynes", "typal", "typed", "types", + "typey", "typic", "typos", "typps", "typto", + "tyran", "tyred", "tyres", "tyros", "tythe", + "tzars", "ubacs", "ubity", "udals", "udons", + "udyog", "ugali", "ugged", "uhlan", "uhuru", + "ukase", "ulama", "ulans", "ulema", "ulmin", + "ulmos", "ulnad", "ulnae", "ulnar", "ulnas", + "ulpan", "ulvas", "ulyie", "ulzie", "umami", + "umbel", "umber", "umble", "umbos", "umbre", + "umiac", "umiak", "umiaq", "ummah", "ummas", + "ummed", "umped", "umphs", "umpie", "umpty", + "umrah", "umras", "unagi", "unais", "unapt", + "unarm", "unary", "unaus", "unbag", "unban", + "unbar", "unbed", "unbid", "unbox", "uncap", + "unces", "uncia", "uncos", "uncoy", "uncus", + "undam", "undee", "undos", "undug", "uneth", + "unfix", "ungag", "unget", "ungod", "ungot", + "ungum", "unhat", "unhip", "unica", "unios", + "units", "unjam", "unked", "unket", "unkey", + "unkid", "unkut", "unlap", "unlaw", "unlay", + "unled", "unleg", "unlet", "unlid", "unmad", + "unman", "unmew", "unmix", "unode", "unold", + "unown", "unpay", "unpeg", "unpen", "unpin", + "unply", "unpot", "unput", "unred", "unrid", + "unrig", "unrip", "unsaw", "unsay", "unsee", + "unsew", "unsex", "unsod", "unsub", "untag", + "untax", "untin", "unwet", "unwit", "unwon", + "upbow", "upbye", "updos", "updry", "upend", + "upful", "upjet", "uplay", "upled", "uplit", + "upped", "upran", "uprun", "upsee", "upsey", + "uptak", "upter", "uptie", "uraei", "urali", + "uraos", "urare", "urari", "urase", "urate", + "urbex", "urbia", "urdee", "ureal", "ureas", + "uredo", "ureic", "ureid", "urena", "urent", + "urged", "urger", "urges", "urial", "urine", + "urite", "urman", "urnal", "urned", "urped", + "ursae", "ursid", "urson", "urubu", "urupa", + "urvas", "usens", "users", "useta", "usnea", + "usnic", "usque", "ustad", "uster", "usure", + "usury", "uteri", "utile", "uveal", "uveas", + "uvula", "vacas", "vacay", "vacua", "vacui", + "vacuo", "vadas", "vaded", "vades", "vadge", + "vagal", "vagus", "vaids", "vails", "vaire", + "vairs", "vairy", "vajra", "vakas", "vakil", + "vales", "valet", "valis", "valli", "valse", + "value", "vamps", "vampy", "vanda", "vaned", + "vanes", "vanga", "vangs", "vants", "vaped", + "vaper", "vapes", "vapor", "varan", "varas", + "varda", "vardo", "vardy", "varec", "vares", + "varia", "varix", "varna", "varus", "varve", + "vasal", "vases", "vasts", "vasty", "vatas", + "vatha", "vatic", "vatje", "vatos", "vatus", + "vauch", "vaute", "vauts", "vawte", "vaxes", + "veale", "veals", "vealy", "veena", "veeps", + "veers", "veery", "vegas", "veges", "veggo", + "vegie", "vegos", "vehme", "veils", "veily", + "veins", "veiny", "velar", "velds", "veldt", + "veles", "vells", "velum", "venae", "venal", + "venas", "vends", "vendu", "veney", "venge", + "venin", "venom", "venti", "vents", "venus", + "verba", "verbs", "verde", "verra", "verre", + "verry", "versa", "verso", "verst", "verte", + "verts", "vertu", "verve", "vespa", "vesta", + "vests", "vetch", "veuve", "veves", "vexed", + "vexer", "vexes", "vexil", "vezir", "vials", + "viand", "vibed", "vibes", "vibex", "vibey", + "vicar", "viced", "vices", "vichy", "vicus", + "video", "viers", "vieux", "views", "viewy", + "vifda", "viffs", "vigas", "vigia", "vigil", + "vilde", "viler", "ville", "villi", "vills", + "vimen", "vinal", "vinas", "vinca", "vined", + "viner", "vines", "vinew", "vinho", "vinic", + "vinny", "vinos", "vints", "viold", "viols", + "vired", "vireo", "vires", "virga", "virge", + "virgo", "virid", "virls", "virtu", "visas", + "vised", "vises", "visie", "visit", "visna", + "visne", "vison", "visto", "vitae", "vitas", + "vitex", "vitro", "vitta", "vivas", "vivat", + "vivda", "viver", "vives", "vivos", "vivre", + "vizir", "vizor", "vlast", "vleis", "vlies", + "vlogs", "voars", "vobla", "vocab", "voces", + "voddy", "vodou", "vodun", "voema", "vogie", + "voici", "voids", "voile", "voips", "volae", + "volar", "voled", "voles", "volet", "volke", + "volks", "volta", "volte", "volti", "volts", + "volva", "volve", "vomer", "vomit", "voted", + "votes", "vouge", "voulu", "vowed", "vower", + "voxel", "voxes", "vozhd", "vraic", "vrils", + "vroom", "vrous", "vrouw", "vrows", "vuggs", + "vuggy", "vughs", "vughy", "vulgo", "vulns", + "vutty", "vygie", "vying", "waacs", "wacke", + "wacko", "wacks", "wadas", "wadds", "waddy", + "waded", "wader", "wades", "wadge", "wadis", + "wadts", "waffs", "wafts", "waged", "wages", + "wagga", "wagyu", "wahay", "wahey", "wahoo", + "waide", "waifs", "waift", "wails", "wains", + "wairs", "waite", "waits", "waive", "wakas", + "waked", "waken", "waker", "wakes", "wakfs", + "waldo", "walds", "waled", "waler", "wales", + "walie", "walis", "walks", "walla", "walls", + "wally", "walty", "wamed", "wames", "wamus", + "wands", "waned", "wanes", "waney", "wangs", + "wanks", "wanky", "wanle", "wanly", "wanna", + "wanta", "wants", "wanty", "wanze", "waqfs", + "warbs", "warby", "wards", "wared", "wares", + "warez", "warks", "warms", "warns", "warps", + "warre", "warst", "warts", "warty", "wases", + "washi", "washy", "wasms", "wasps", "waspy", + "waste", "wasts", "watap", "watts", "wauff", + "waugh", "wauks", "waulk", "wauls", "waurs", + "waved", "waves", "wavey", "wawas", "wawes", + "wawls", "waxed", "waxer", "waxes", "wayed", + "wazir", "wazoo", "weald", "weals", "weamb", + "weans", "wears", "webby", "weber", "wecht", + "wedel", "wedgy", "weeds", "weeis", "weeke", + "weeks", "weels", "weems", "weens", "weeny", + "weeps", "weepy", "weest", "weete", "weets", + "wefte", "wefts", "weids", "weils", "weirs", + "weise", "weize", "wekas", "welds", "welke", + "welks", "welkt", "wells", "welly", "welsh", + "welts", "wembs", "wench", "wends", "wenge", + "wenny", "wents", "werfs", "weros", "wersh", + "wests", "wetas", "wetly", "wexed", "wexes", + "whack", "whamo", "whams", "whang", "whaps", + "whare", "wharf", "whata", "whats", "whaup", + "whaur", "wheal", "whear", "wheek", "wheen", + "wheep", "wheft", "whelk", "whelm", "whelp", + "whens", "whets", "whews", "wheys", "whids", + "whies", "whift", "whigs", "whilk", "whims", + "whins", "whios", "whips", "whipt", "whirr", + "whirs", "whish", "whiss", "whist", "whits", + "whity", "whizz", "whomp", "whoof", "whoop", + "whoot", "whops", "whore", "whorl", "whort", + "whoso", "whows", "whump", "whups", "whyda", + "wicca", "wicks", "wicky", "widdy", "wides", + "wiels", "wifed", "wifes", "wifey", "wifie", + "wifts", "wifty", "wigan", "wigga", "wiggy", + "wight", "wikis", "wilco", "wilds", "wiled", + "wiles", "wilga", "wilis", "wilja", "wills", + "willy", "wilts", "wimps", "wimpy", "winds", + "wined", "wines", "winey", "winge", "wings", + "wingy", "winks", "winky", "winna", "winns", + "winos", "winze", "wiped", "wipes", "wired", + "wirer", "wires", "wirra", "wirri", "wised", + "wises", "wisha", "wisht", "wisps", "wispy", + "wists", "witan", "wited", "wites", "withe", + "withs", "withy", "wived", "wiver", "wives", + "wizen", "wizes", "wizzo", "woads", "woady", + "woald", "wocks", "wodge", "wodgy", "woful", + "wojus", "woker", "wokka", "wolds", "wolfs", + "wolly", "wolve", "womas", "wombs", "womby", + "womyn", "wonga", "wongi", "wonks", "wonky", + "wonts", "woods", "woody", "wooed", "wooer", + "woofs", "woofy", "woold", "wools", "wooly", + "woons", "woops", "woopy", "woose", "woosh", + "wootz", "woozy", "words", "wordy", "works", + "worky", "worms", "wormy", "worts", "woven", + "wowed", "wowee", "wowse", "woxen", "wrang", + "wraps", "wrapt", "wrast", "wrate", "wrawl", + "wrens", "wrick", "wried", "wrier", "wries", + "writs", "wroke", "wroot", "wroth", "wrung", + "wryer", "wryly", "wuddy", "wudus", "wuffs", + "wulls", "wunga", "wurst", "wuses", "wushu", + "wussy", "wuxia", "wyled", "wyles", "wynds", + "wynns", "wyted", "wytes", "wythe", "xebec", + "xenia", "xenic", "xenon", "xeric", "xerox", + "xerus", "xoana", "xolos", "xrays", "xviii", + "xylan", "xylem", "xylic", "xylol", "xylyl", + "xysti", "xysts", "yaars", "yaass", "yabas", + "yabba", "yabby", "yacca", "yacka", "yacks", + "yadda", "yaffs", "yager", "yages", "yagis", + "yagna", "yahoo", "yaird", "yajna", "yakka", + "yakow", "yales", "yamen", "yampa", "yampy", + "yamun", "yandy", "yangs", "yanks", "yapok", + "yapon", "yapps", "yappy", "yarak", "yarco", + "yards", "yarer", "yarfa", "yarks", "yarns", + "yarra", "yarrs", "yarta", "yarto", "yates", + "yatra", "yauds", "yauld", "yaups", "yawed", + "yawey", "yawls", "yawns", "yawny", "yawps", + "yayas", "ybore", "yclad", "ycled", "ycond", + "ydrad", "ydred", "yeads", "yeahs", "yealm", + "yeans", "yeard", "years", "yecch", "yechs", + "yechy", "yedes", "yeeds", "yeeek", "yeesh", + "yeggs", "yelks", "yells", "yelms", "yelps", + "yelts", "yenta", "yente", "yerba", "yerds", + "yerks", "yeses", "yesks", "yests", "yesty", + "yetis", "yetts", "yeuch", "yeuks", "yeuky", + "yeven", "yeves", "yewen", "yexed", "yexes", + "yfere", "yiked", "yikes", "yills", "yince", + "yipes", "yippy", "yirds", "yirks", "yirrs", + "yirth", "yites", "yitie", "ylems", "ylide", + "ylids", "ylike", "ylkes", "ymolt", "ympes", + "yobbo", "yobby", "yocks", "yodel", "yodhs", + "yodle", "yogas", "yogee", "yoghs", "yogic", + "yogin", "yogis", "yohah", "yohay", "yoick", + "yojan", "yokan", "yoked", "yokeg", "yokel", + "yoker", "yokes", "yokul", "yolks", "yolky", + "yolps", "yomim", "yomps", "yonic", "yonis", + "yonks", "yonny", "yoofs", "yoops", "yopos", + "yoppo", "yores", "yorga", "yorks", "yorps", + "youks", "yourn", "yours", "yourt", "youse", + "yowed", "yowes", "yowie", "yowls", "yowsa", + "yowza", "yoyos", "yrapt", "yrent", "yrivd", + "yrneh", "ysame", "ytost", "yuans", "yucas", + "yucca", "yucch", "yucko", "yucks", "yucky", + "yufts", "yugas", "yuked", "yukes", "yukky", + "yukos", "yulan", "yules", "yummo", "yummy", + "yumps", "yupon", "yuppy", "yurta", "yurts", + "yuzus", "zabra", "zacks", "zaida", "zaide", + "zaidy", "zaire", "zakat", "zamac", "zamak", + "zaman", "zambo", "zamia", "zamis", "zanja", + "zante", "zanza", "zanze", "zappy", "zarda", + "zarfs", "zaris", "zatis", "zawns", "zaxes", + "zayde", "zayin", "zazen", "zeals", "zebec", + "zebub", "zebus", "zedas", "zeera", "zeins", + "zendo", "zerda", "zerks", "zeros", "zests", + "zetas", "zexes", "zezes", "zhomo", "zhush", + "zhuzh", "zibet", "ziffs", "zigan", "zikrs", + "zilas", "zilch", "zilla", "zills", "zimbi", + "zimbs", "zinco", "zincs", "zincy", "zineb", + "zines", "zings", "zingy", "zinke", "zinky", + "zinos", "zippo", "zippy", "ziram", "zitis", + "zitty", "zizel", "zizit", "zlote", "zloty", + "zoaea", "zobos", "zobus", "zocco", "zoeae", + "zoeal", "zoeas", "zoism", "zoist", "zokor", + "zolle", "zombi", "zonae", "zonda", "zoned", + "zoner", "zones", "zonks", "zooea", "zooey", + "zooid", "zooks", "zooms", "zoomy", "zoons", + "zooty", "zoppa", "zoppo", "zoril", "zoris", + "zorro", "zorse", "zouks", "zowee", "zowie", + "zulus", "zupan", "zupas", "zuppa", "zurfs", + "zuzim", "zygal", "zygon", "zymes", "zymic", +]