From f902ca0d640e3d9d8c60a44bad26044eda3aab64 Mon Sep 17 00:00:00 2001 From: osmarks Date: Sun, 11 Oct 2020 14:40:39 +0100 Subject: [PATCH] modularize it, add mostly working phone function --- src/db.py | 30 +- src/debug.py | 49 + src/main.py | 202 +- src/reminders.py | 100 + src/telephone.py | 197 ++ src/util.py | 46 +- wordlist-8192.txt | 8192 +++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 8635 insertions(+), 181 deletions(-) create mode 100644 src/debug.py create mode 100644 src/reminders.py create mode 100644 src/telephone.py create mode 100644 wordlist-8192.txt diff --git a/src/db.py b/src/db.py index 4544d19..2950a47 100644 --- a/src/db.py +++ b/src/db.py @@ -21,16 +21,44 @@ CREATE TABLE reminders ( expired INTEGER NOT NULL, extra TEXT NOT NULL ); +""", +""" +CREATE TABLE telephone_config ( + id TEXT PRIMARY KEY, + guild_id INTEGER NOT NULL, + channel_id INTEGER NOT NULL UNIQUE, + webhook TEXT +); +""", +""" +CREATE TABLE calls ( + from_id TEXT NOT NULL REFERENCES telephone_config(id) UNIQUE, + to_id TEXT NOT NULL REFERENCES telephone_config(id), + start_time INTEGER NOT NULL +); """ ] +async def execute_fetchone(self, sql, params=None): + if params == None: params = () + return await self._execute(self._fetchone, sql, params) + +def _fetchone(self, sql, params): + cursor = self._conn.execute(sql, params) + return cursor.fetchone() + async def init(db_path): db = await aiosqlite.connect(db_path) + await db.execute("PRAGMA foreign_keys = ON") + + db.row_factory = aiosqlite.Row + aiosqlite.Connection._fetchone = _fetchone + aiosqlite.Connection.execute_fetchone = execute_fetchone version = (await (await db.execute("PRAGMA user_version")).fetchone())[0] for i in range(version, len(migrations)): await db.executescript(migrations[i]) - # Normally this would be a terrible idea because of SQL injection. + # Normally interpolating like this would be a terrible idea because of SQL injection. # However, in this case there is not an obvious alternative (the parameter-based way apparently doesn't work) # and i + 1 will always be an integer anyway await db.execute(f"PRAGMA user_version = {i + 1}") diff --git a/src/debug.py b/src/debug.py new file mode 100644 index 0000000..7b03d87 --- /dev/null +++ b/src/debug.py @@ -0,0 +1,49 @@ +import util +import asyncio +import traceback +from discord.ext import commands + +def setup(bot): + async def admin_check(ctx): + return await bot.is_owner(ctx.author) + + @bot.group() + @commands.check(admin_check) + async def magic(ctx): + if ctx.invoked_subcommand == None: + return await ctx.send("Invalid magic command.") + + @magic.command(rest_is_raw=True) + async def py(ctx, *, code): + code = util.extract_codeblock(code) + try: + loc = { + **locals(), + "bot": bot, + "ctx": ctx, + "db": bot.database + } + result = await asyncio.wait_for(util.async_exec(code, loc, globals()), timeout=5.0) + if result != None: + if isinstance(result, str): + await ctx.send(result[:1999]) + else: + await ctx.send(util.gen_codeblock(repr(result))) + except TimeoutError: + await ctx.send(embed=util.error_embed("Timed out.")) + except BaseException as e: + await ctx.send(embed=util.error_embed(util.gen_codeblock(traceback.format_exc()))) + + @magic.command(rest_is_raw=True) + async def sql(ctx, *, code): + code = util.extract_codeblock(code) + try: + csr = bot.database.execute(code) + out = "" + async with csr as cursor: + async for row in cursor: + out += " ".join(map(repr, row)) + "\n" + await ctx.send(util.gen_codeblock(out)) + await bot.database.commit() + except Exception as e: + await ctx.send(embed=util.error_embed(util.gen_codeblock(traceback.format_exc()))) \ No newline at end of file diff --git a/src/main.py b/src/main.py index aa40006..b3bee87 100644 --- a/src/main.py +++ b/src/main.py @@ -11,37 +11,18 @@ import argparse import traceback import random import rolldice -from datetime import timezone, datetime import tio import db import util -def timestamp(): return int(datetime.now(tz=timezone.utc).timestamp()) - -# TODO refactor this -database = None - -config = toml.load(open("config.toml", "r")) +config = util.config logging.basicConfig(level=logging.INFO, format="%(levelname)s %(asctime)s %(message)s", datefmt="%H:%M:%S %d/%m/%Y") bot = commands.Bot(command_prefix=config["prefix"], description="AutoBotRobot, the most useless bot in the known universe.", case_insensitive=True) bot._skip_check = lambda x, y: False -def make_embed(*, fields=[], footer_text=None, **kwargs): - embed = discord.Embed(**kwargs) - for field in fields: - if len(field) > 2: - embed.add_field(name=field[0], value=field[1], inline=field[2]) - else: - embed.add_field(name=field[0], value=field[1], inline=False) - if footer_text: - embed.set_footer(text=footer_text) - return embed - -def error_embed(msg, title="Error"): - return make_embed(color=config["colors"]["error"], description=msg, title=title) cleaner = discord.ext.commands.clean_content() def clean(ctx, text): @@ -53,19 +34,20 @@ async def on_message(message): if len(words) == 10 and message.author.id == 435756251205468160: await message.channel.send(util.unlyric(message.content)) else: - if message.author.id == bot.user.id: return + if message.author == bot.user or message.author.discriminator == "0000": return ctx = await bot.get_context(message) if not ctx.valid: return await bot.invoke(ctx) @bot.event async def on_command_error(ctx, err): - print(ctx, err) - if isinstance(err, commands.CommandNotFound, commands.CheckFailure): return + #print(ctx, err) + if isinstance(err, (commands.CommandNotFound, commands.CheckFailure)): return try: trace = re.sub("\n\n+", "\n", "\n".join(traceback.format_exception(err, err, err.__traceback__))) - print(trace) - await ctx.send(embed=error_embed(gen_codeblock(trace), title="Internal error")) + #print(trace) + logging.error("command error occured (in %s)", ctx.invoked_with, exc_info=err) + await ctx.send(embed=util.error_embed(util.gen_codeblock(trace), title="Internal error")) except Exception as e: print("meta-error:", e) @bot.command(help="Gives you a random fortune as generated by `fortune`.") @@ -84,13 +66,13 @@ async def ping(ctx): async def delete(ctx, *, raw_target): target = await clean(ctx, raw_target.strip().replace("\n", " ")) if len(target) > 256: - await ctx.send(embed=error_embed("Deletion target must be max 256 chars")) + await ctx.send(embed=util.error_embed("Deletion target must be max 256 chars")) return async with ctx.typing(): await ctx.send(f"Deleting {target}...") await asyncio.sleep(1) - await database.execute("INSERT INTO deleted_items (timestamp, item) VALUES (?, ?)", (timestamp(), target)) - await database.commit() + await bot.database.execute("INSERT INTO deleted_items (timestamp, item) VALUES (?, ?)", (util.timestamp(), target)) + await bot.database.commit() await ctx.send(f"Deleted {target} successfully.") @bot.command(help="View recently deleted things, optionally matching a filter.") @@ -99,9 +81,9 @@ async def list_deleted(ctx, search=None): if search: acc = f"Recently deleted (matching {search}):\n" csr = None if search: - csr = database.execute("SELECT * FROM deleted_items WHERE item LIKE ? ORDER BY timestamp DESC LIMIT 100", (f"%{search}%",)) + csr = bot.database.execute("SELECT * FROM deleted_items WHERE item LIKE ? ORDER BY timestamp DESC LIMIT 100", (f"%{search}%",)) else: - csr = database.execute("SELECT * FROM deleted_items ORDER BY timestamp DESC LIMIT 100") + csr = bot.database.execute("SELECT * FROM deleted_items ORDER BY timestamp DESC LIMIT 100") async with csr as cursor: async for row in cursor: to_add = "- " + row[2].replace("```", "[REDACTED]") + "\n" @@ -124,20 +106,17 @@ exec_flag_parser = NonExitingArgumentParser(add_help=False) exec_flag_parser.add_argument("--verbose", "-v", action="store_true") exec_flag_parser.add_argument("--language", "-L") -def gen_codeblock(content): - return "```\n" + content.replace("```", "\\`\\`\\`")[:1900] + "\n```" - @bot.command(rest_is_raw=True, help="Execute provided code (in a codeblock) using TIO.run.") async def exec(ctx, *, arg): match = re.match(EXEC_REGEX, arg, flags=re.DOTALL) if match == None: - await ctx.send(embed=error_embed("Invalid format. Expected a codeblock.")) + await ctx.send(embed=util.error_embed("Invalid format. Expected a codeblock.")) return flags_raw = match.group(1) flags = exec_flag_parser.parse_args(flags_raw.split()) lang = flags.language or match.group(2) if not lang: - await ctx.send(embed=error_embed("No language specified. Use the -L flag or add a language to your codeblock.")) + await ctx.send(embed=util.error_embed("No language specified. Use the -L flag or add a language to your codeblock.")) return lang = lang.strip() code = match.group(3) @@ -145,11 +124,11 @@ async def exec(ctx, *, arg): async with ctx.typing(): ok, real_lang, result, debug = await tio.run(lang, code) if not ok: - await ctx.send(embed=error_embed(gen_codeblock(result), "Execution failed")) + await ctx.send(embed=util.error_embed(util.gen_codeblock(result), "Execution failed")) else: out = result if flags.verbose: - debug_block = "\n" + gen_codeblock(f"""{debug}\nLanguage: {real_lang}""") + debug_block = "\n" + util.gen_codeblock(f"""{debug}\nLanguage: {real_lang}""") out = out[:2000 - len(debug_block)] + debug_block else: out = out[:2000] @@ -167,93 +146,6 @@ async def supported_langs(ctx, search=None): if acc == "": acc = "No results." await ctx.send(acc) -@bot.command(brief="Set a reminder to be reminded about later.", rest_is_raw=True, help="""Sets a reminder which you will (probably) be reminded about at/after the specified time. -All times are UTC. -Reminders are checked every minute, so while precise times are not guaranteed, reminders should under normal conditions be received within 2 minutes of what you specify.""") -async def remind(ctx, time, *, reminder): - reminder = reminder.strip() - if len(reminder) > 512: - await ctx.send(embed=error_embed("Maximum reminder length is 512 characters", "Foolish user error")) - return - extra_data = { - "author_id": ctx.author.id, - "channel_id": ctx.message.channel.id, - "message_id": ctx.message.id, - "guild_id": ctx.message.guild and ctx.message.guild.id, - "original_time_spec": time - } - try: - time = util.parse_time(time) - except: - await ctx.send(embed=error_embed("Invalid time")) - return - await database.execute("INSERT INTO reminders (remind_timestamp, created_timestamp, reminder, expired, extra) VALUES (?, ?, ?, ?, ?)", - (time.timestamp(), timestamp(), reminder, 0, json.dumps(extra_data, separators=(',', ':')))) - await database.commit() - await ctx.send(f"Reminder scheduled for {util.format_time(time)}.") - -async def send_to_channel(info, text): - channel = bot.get_channel(info["channel_id"]) - if not channel: raise Exception(f"channel {info['channel_id']} unavailable/nonexistent") - await channel.send(text) - -async def send_by_dm(info, text): - user = bot.get_user(info["author_id"]) - if not user: raise Exception(f"user {info['author_id']} unavailable/nonexistent") - if not user.dm_channel: await user.create_dm() - await user.dm_channel.send(text) - -async def send_to_guild(info, text): - guild = bot.get_guild(info["guild_id"]) - member = guild.get_member(info["author_id"]) - self = guild.get_member(bot.user.id) - # if member is here, find a channel they can read and the bot can send in - if member: - for chan in guild.text_channels: - if chan.permissions_for(member).read_messages and chan.permissions_for(self).send_messages: - await chan.send(text) - return - # if member not here or no channel they can read messages in, send to any available channel - for chan in guild.text_channels: - if chan.permissions_for(self).send_messages: - await chan.send(text) - return - raise Exception(f"guild {info['author_id']} has no (valid) channels") - -remind_send_methods = [ - ("original channel", send_to_channel), - ("direct message", send_by_dm), - ("originating guild", send_to_guild) -] - -@tasks.loop(seconds=60) -async def remind_worker(): - csr = database.execute("SELECT * FROM reminders WHERE expired = 0 AND remind_timestamp < ?", (timestamp(),)) - to_expire = [] - async with csr as cursor: - async for row in cursor: - rid, remind_timestamp, created_timestamp, reminder_text, _, extra = row - try: - remind_timestamp = datetime.utcfromtimestamp(remind_timestamp) - created_timestamp = datetime.utcfromtimestamp(created_timestamp) - extra = json.loads(extra) - uid = extra["author_id"] - text = f"<@{uid}> Reminder queued at {util.format_time(created_timestamp)}: {reminder_text}" - - for method_name, func in remind_send_methods: - print("trying", method_name, rid) - try: - await func(extra, text) - to_expire.append(rid) - break - except Exception as e: logging.warning("failed to send %d to %s", rid, method_name, exc_info=e) - except Exception as e: - logging.warning("Could not send reminder %d", rid, exc_info=e) - for expiry_id in to_expire: - logging.info("Expiring reminder %d", expiry_id) - await database.execute("UPDATE reminders SET expired = 1 WHERE id = ?", (expiry_id,)) - await database.commit() - @bot.command(help="Get some information about the bot.") async def about(ctx): await ctx.send("""**AutoBotRobot: The least useful Discord bot ever designed.** @@ -304,68 +196,23 @@ async def random_choice(ctx, *choices): for choice in choices: counts[choice] = counts.get(choice, 0) + 1 await ctx.send("\n".join(map(lambda x: f"{x[0]} x{x[1]}", counts.items()))) - -async def admin_check(ctx): - if not await bot.is_owner(ctx.author): - # apparently this has to be a pure function because ++help calls it for some reason because of course - #await ctx.send(embed=error_embed(f"{ctx.author.name} is not in the sudoers file. This incident has been reported.")) - return False - return True - @bot.check async def andrew_bad(ctx): return ctx.message.author.id != 543131534685765673 -@bot.group() -@commands.check(admin_check) -async def magic(ctx): - if ctx.invoked_subcommand == None: - return await ctx.send("Invalid magic command.") - -@magic.command(rest_is_raw=True) -async def py(ctx, *, code): - code = util.extract_codeblock(code) - try: - loc = { - **locals(), - "bot": bot, - "ctx": ctx, - "db": database - } - result = await asyncio.wait_for(util.async_exec(code, loc, globals()), timeout=5.0) - if result != None: - if isinstance(result, str): - await ctx.send(result[:1999]) - else: - await ctx.send(gen_codeblock(repr(result))) - except TimeoutError: - await ctx.send(embed=error_embed("Timed out.")) - except BaseException as e: - await ctx.send(embed=error_embed(gen_codeblock(traceback.format_exc()))) - -@magic.command(rest_is_raw=True) -async def sql(ctx, *, code): - code = util.extract_codeblock(code) - try: - csr = database.execute(code) - out = "" - async with csr as cursor: - async for row in cursor: - out += " ".join(map(repr, row)) + "\n" - await ctx.send(gen_codeblock(out)) - await database.commit() - except Exception as e: - await ctx.send(embed=error_embed(gen_codeblock(traceback.format_exc()))) - @bot.event async def on_ready(): logging.info("Connected as " + bot.user.name) - await bot.change_presence(status=discord.Status.online, activity=discord.Activity(type=discord.ActivityType.listening, name=f"commands beginning with {config['prefix']}")) - remind_worker.start() + await bot.change_presence(status=discord.Status.online, activity=discord.Activity(type=discord.ActivityType.listening, name=f"commands beginning with {bot.command_prefix}")) async def run_bot(): - global database - database = await db.init(config["database"]) + bot.database = await db.init(config["database"]) + for ext in ( + "reminders", + "debug", + "telephone" + ): + bot.load_extension(ext) await bot.start(config["token"]) if __name__ == '__main__': @@ -373,7 +220,6 @@ if __name__ == '__main__': try: loop.run_until_complete(run_bot()) except KeyboardInterrupt: - remind_worker.cancel() loop.run_until_complete(bot.logout()) finally: loop.close() diff --git a/src/reminders.py b/src/reminders.py new file mode 100644 index 0000000..2f5b839 --- /dev/null +++ b/src/reminders.py @@ -0,0 +1,100 @@ +import json +import logging +from datetime import datetime +import discord.ext.tasks as tasks + +import util + +def setup(bot): + @bot.command(brief="Set a reminder to be reminded about later.", rest_is_raw=True, help="""Sets a reminder which you will (probably) be reminded about at/after the specified time. + All times are UTC. + Reminders are checked every minute, so while precise times are not guaranteed, reminders should under normal conditions be received within 2 minutes of what you specify.""") + async def remind(ctx, time, *, reminder): + reminder = reminder.strip() + if len(reminder) > 512: + await ctx.send(embed=util.error_embed("Maximum reminder length is 512 characters", "Foolish user error")) + return + extra_data = { + "author_id": ctx.author.id, + "channel_id": ctx.message.channel.id, + "message_id": ctx.message.id, + "guild_id": ctx.message.guild and ctx.message.guild.id, + "original_time_spec": time + } + try: + time = util.parse_time(time) + except: + await ctx.send(embed=util.error_embed("Invalid time")) + return + await bot.database.execute("INSERT INTO reminders (remind_timestamp, created_timestamp, reminder, expired, extra) VALUES (?, ?, ?, ?, ?)", + (time.timestamp(), util.timestamp(), reminder, 0, util.json_encode(extra_data))) + await bot.database.commit() + await ctx.send(f"Reminder scheduled for {util.format_time(time)}.") + + async def send_to_channel(info, text): + channel = bot.get_channel(info["channel_id"]) + if not channel: raise Exception(f"channel {info['channel_id']} unavailable/nonexistent") + await channel.send(text) + + async def send_by_dm(info, text): + user = bot.get_user(info["author_id"]) + if not user: raise Exception(f"user {info['author_id']} unavailable/nonexistent") + if not user.dm_channel: await user.create_dm() + await user.dm_channel.send(text) + + async def send_to_guild(info, text): + guild = bot.get_guild(info["guild_id"]) + member = guild.get_member(info["author_id"]) + self = guild.get_member(bot.user.id) + # if member is here, find a channel they can read and the bot can send in + if member: + for chan in guild.text_channels: + if chan.permissions_for(member).read_messages and chan.permissions_for(self).send_messages: + await chan.send(text) + return + # if member not here or no channel they can read messages in, send to any available channel + for chan in guild.text_channels: + if chan.permissions_for(self).send_messages: + await chan.send(text) + return + raise Exception(f"guild {info['author_id']} has no (valid) channels") + + remind_send_methods = [ + ("original channel", send_to_channel), + ("direct message", send_by_dm), + ("originating guild", send_to_guild) + ] + + @tasks.loop(seconds=60) + async def remind_worker(): + csr = bot.database.execute("SELECT * FROM reminders WHERE expired = 0 AND remind_timestamp < ?", (util.timestamp(),)) + to_expire = [] + async with csr as cursor: + async for row in cursor: + rid, remind_timestamp, created_timestamp, reminder_text, _, extra = row + try: + remind_timestamp = datetime.utcfromtimestamp(remind_timestamp) + created_timestamp = datetime.utcfromtimestamp(created_timestamp) + extra = json.loads(extra) + uid = extra["author_id"] + text = f"<@{uid}> Reminder queued at {util.format_time(created_timestamp)}: {reminder_text}" + + for method_name, func in remind_send_methods: + print("trying", method_name, rid) + try: + await func(extra, text) + to_expire.append(rid) + break + except Exception as e: logging.warning("failed to send %d to %s", rid, method_name, exc_info=e) + except Exception as e: + logging.warning("Could not send reminder %d", rid, exc_info=e) + for expiry_id in to_expire: + logging.info("Expiring reminder %d", expiry_id) + await bot.database.execute("UPDATE reminders SET expired = 1 WHERE id = ?", (expiry_id,)) + await bot.database.commit() + + remind_worker.start() + bot.remind_worker = remind_worker + +def teardown(bot): + bot.remind_worker.cancel() \ No newline at end of file diff --git a/src/telephone.py b/src/telephone.py new file mode 100644 index 0000000..6dcad88 --- /dev/null +++ b/src/telephone.py @@ -0,0 +1,197 @@ +from discord.ext import commands +import discord +import logging +import asyncio +import hashlib +from datetime import datetime + +import util + +# Generate a "phone" address +# Not actually for phones +def generate_address(ctx): + h = hashlib.blake2b(str(ctx.guild.id).encode("utf-8")).digest() + words = open("wordlist-8192.txt").readlines() + out = "" + for i in range(3): + out += words[int.from_bytes(h[i * 2:i * 2 + 3], "little") % 8192].strip().title() + return out + +channel_calls_cache = {} + +def setup(bot): + async def server_mod_check(ctx): + return ctx.author.permissions_in(ctx.channel).manage_channels or bot.is_owner(ctx.author) + + @bot.group(name="apiotelephone", aliases=["tel", "tele", "telephone", "apiotel"], brief="ApioTelephone lets you 'call' other servers.", help=f""" + Call other (participating) servers with ApioTelephone! To start, do {bot.command_prefix} tel setup (requires Manage Channels). + It's recommended that you give the bot Manage Webhooks permissions in this channel so that it can use webhook calls mode. + + """) + async def telephone(ctx): pass + + async def get_channel_config(channel): + return await bot.database.execute_fetchone("SELECT * FROM telephone_config WHERE channel_id = ?", (channel,)) + + async def get_addr_config(addr): + return await bot.database.execute_fetchone("SELECT * FROM telephone_config WHERE id = ?", (addr,)) + + def cache_call(chan, other, other_wh): + x = channel_calls_cache.get(chan) + if not x: + x = [] + channel_calls_cache[chan] = x + # append other end and associated webhook + x.append((other, other_wh)) + + def uncache_call(chan, other): + # remove other end + l = channel_calls_cache[chan] + for i, (c, _) in enumerate(l): + if c == other: l.pop(i) + + async def populate_cache(db): + for row in await db.execute_fetchall("""SELECT tcf.channel_id AS from_channel, tct.channel_id AS to_channel, tcf.webhook AS from_webhook, tct.webhook AS to_webhook FROM calls + JOIN telephone_config AS tcf ON tcf.id = calls.from_id JOIN telephone_config AS tct ON tct.id = calls.to_id"""): + cache_call(row["from_channel"], row["to_channel"], row["to_webhook"]) + cache_call(row["to_channel"], row["from_channel"], row["from_webhook"]) + + bot.loop.create_task(populate_cache(bot.database)) + + @bot.listen("on_message") + async def forward_call_messages(message): + calls = channel_calls_cache.get(message.channel.id, None) + if not calls: return + if (message.author.discriminator == "0000" and message.author.bot) or message.author == bot.user or message.content == "": # check if webhook, from itself, or only has embeds + return + async def send_to(call): + other_channel, other_webhook = call + if other_webhook: + await discord.Webhook.from_url(other_webhook, adapter=discord.AsyncWebhookAdapter(bot.http._HTTPClient__session)).send( + content=message.content, username=message.author.name, avatar_url=message.author.avatar_url, + allowed_mentions=discord.AllowedMentions(everyone=False)) + else: + m = f"**{message.author.name}**: " + m += message.content[:2000 - len(m)] + await bot.get_channel(other_channel).send(m) + await asyncio.gather(*map(send_to, calls)) + + @telephone.command() + @commands.check(server_mod_check) + async def setup(ctx): + await ctx.send("Configuring...") + num = generate_address(ctx) + await ctx.send(f"Your address is {num}.") + info = await get_addr_config(num) + webhook = None + if info: webhook = info["webhook"] + if not info or not webhook: + try: + webhook = (await ctx.channel.create_webhook(name="incoming message display", reason="configure for apiotelephone")).url + await ctx.send("Created webhook.") + except discord.Forbidden as f: + logging.warn("could not create webhook in #%s %s", ctx.channel.name, ctx.guild.name, exc_info=f) + await ctx.send("Webhook creation failed - please ensure permissions are available. This is not necessary but is recommended.") + await bot.database.execute("INSERT OR REPLACE INTO telephone_config VALUES (?, ?, ?, ?)", (num, ctx.guild.id, ctx.channel.id, webhook)) + await bot.database.commit() + await ctx.send("Configured.") + + @telephone.command(aliases=["call"]) + async def dial(ctx, address): + # basic checks - ensure this is a phone channel and has no other open calls + channel_info = await get_channel_config(ctx.channel.id) + if not channel_info: return await ctx.send(embed=util.error_embed("Not in a phone channel.")) + originating_address = channel_info["id"] + if address == originating_address: return await ctx.send(embed=util.error_embed("A channel cannot dial itself. That means *you*, Gibson.")) + recv_info = await get_addr_config(address) + if not recv_info: return await ctx.send(embed=util.error_embed("Destination address not found. Please check for typos and/or antimemes.")) + + current_call = await bot.database.execute_fetchone("SELECT * FROM calls WHERE from_id = ?", (originating_address,)) + if current_call: return await ctx.send(embed=util.error_embed(f"A call is already open (to {current_call['to_id']}) from this channel. Currently, only one outgoing call is permitted at a time.")) + + # post embed in the receiving channel prompting people to accept/decline call + recv_channel = bot.get_channel(recv_info["channel_id"]) + _, call_message = await asyncio.gather( + ctx.send(embed=util.info_embed("Outgoing call", f"Dialing {address}...")), + recv_channel.send(embed=util.info_embed("Incoming call", + f"Call from {originating_address}. Click :white_check_mark: to accept or :negative_squared_cross_mark: to decline.")) + ) + # add clickable reactions to it + await asyncio.gather( + call_message.add_reaction("✅"), + call_message.add_reaction("❎") + ) + + def check(re, u): return (str(re.emoji) == "✅" or str(re.emoji) == "❎") and u != bot.user + + # wait until someone clicks the reactions, or time out and say so + try: + reaction, user = await bot.wait_for("reaction_add", timeout=util.config["call_timeout"], check=check) + except asyncio.TimeoutError: + await asyncio.gather( + ctx.send(embed=util.error_embed("Timed out", "Outgoing call timed out - the other end did not pick up.")), + recv_channel.send(embed=util.error_embed("Timed out", "Call timed out - no response in time")) + ) + + await asyncio.gather(call_message.remove_reaction("✅", bot.user), call_message.remove_reaction("❎", bot.user)) + em = str(reaction.emoji) + if em == "✅": # accept call + await bot.database.execute("INSERT INTO calls VALUES (?, ?, ?)", (originating_address, address, util.timestamp())) + await bot.database.commit() + await asyncio.gather( + ctx.send(embed=util.info_embed("Outgoing call", "Call accepted and connected.")), + recv_channel.send(embed=util.info_embed("Incoming call", "Call accepted and connected.")) + ) + cache_call(ctx.channel.id, recv_channel.id, recv_info["webhook"]) + cache_call(recv_channel.id, ctx.channel.id, channel_info["webhook"]) + elif em == "❎": # drop call + await ctx.send(embed=util.error_embed("Your call was declined.", "Call declined")) + + async def get_calls(addr): + pass + + @telephone.command(aliases=["disconnect", "quit"]) + async def hangup(ctx): + channel_info = await get_channel_config(ctx.channel.id) + addr = channel_info["id"] + if not channel_info: return await ctx.send(embed=util.error_embed("Not in a phone channel.")) + from_here = await bot.database.execute_fetchone("SELECT * FROM calls WHERE from_id = ?", (addr,)) + to_here = await bot.database.execute_fetchone("SELECT * FROM calls WHERE to_id = ?", (addr,)) + if (not to_here) and (not from_here): return await ctx.send(embed=util.error_embed("No calls are active.")) + + other = None + if from_here: + other = from_here["to_id"] + await bot.database.execute("DELETE FROM calls WHERE from_id = ? AND to_id = ?", (addr, other)) + elif to_here: + other = to_here["from_id"] + await bot.database.execute("DELETE FROM calls WHERE to_id = ? AND from_id = ?", (addr, other)) + await bot.database.commit() + other_channel = (await get_addr_config(other))["channel_id"] + + uncache_call(ctx.channel.id, other_channel) + uncache_call(other_channel, ctx.channel.id) + + await asyncio.gather( + ctx.send(embed=util.info_embed("Hung up", f"Call to {other} disconnected.")), + bot.get_channel(other_channel).send(embed=util.info_embed("Hung up", f"Call to {addr} disconnected.")) + ) + + @telephone.command(aliases=["status"]) + async def info(ctx): + channel_info = await get_channel_config(ctx.channel.id) + if not channel_info: return await ctx.send(embed=util.info_embed("Phone status", "Not a phone channel")) + addr = channel_info['id'] + title = f"{addr} status" + + fields = [] + + now = datetime.utcnow() + def delta(ts): + return util.format_timedelta(datetime.utcfromtimestamp(ts), now) + + incoming = await bot.database.execute_fetchall("SELECT * FROM calls WHERE to_id = ?", (addr,)) + fields.extend(map(lambda x: ["Incoming call", f"From {x['from_id']} - for {delta(x['start_time'])}"], incoming)) + outgoing = await bot.database.execute_fetchall("SELECT * FROM calls WHERE from_id = ?", (addr,)) + fields.extend(map(lambda x: ["Outgoing call", f"To {x['from_id']} - for {delta(x['start_time'])}"], outgoing)) + await ctx.send(embed=util.info_embed(title, f"Connected: {len(incoming) + len(outgoing)}", fields)) \ No newline at end of file diff --git a/src/util.py b/src/util.py index d212a61..298c6b5 100644 --- a/src/util.py +++ b/src/util.py @@ -5,6 +5,13 @@ import ast import copy import random from dateutil.relativedelta import relativedelta +import json +import discord +import toml + +config = toml.load(open("config.toml", "r")) + +def timestamp(): return int(datetime.datetime.now(tz=datetime.timezone.utc).timestamp()) # from here: https://github.com/Rapptz/RoboDanny/blob/18b92ae2f53927aedebc25fb5eca02c8f6d7a874/cogs/utils/time.py short_timedelta_regex = re.compile(""" @@ -20,11 +27,11 @@ def parse_short_timedelta(text): match = short_timedelta_regex.fullmatch(text) if match is None or not match.group(0): raise ValueError("parse failed") data = { k: int(v) for k, v in match.groupdict(default=0).items() } - return datetime.datetime.utcnow() + relativedelta(**data) + return datetime.datetime.now(tz=datetime.timezone.utc) + relativedelta(**data) cal = parsedatetime.Calendar() def parse_humantime(text): - time_struct, parse_status = cal.parse(text) + time_struct, parse_status = cal.nlp(text) if parse_status == 1: return datetime.datetime(*time_struct[:6]) else: raise ValueError("parse failed") @@ -40,6 +47,22 @@ def parse_time(text): def format_time(dt): return dt.strftime("%H:%M:%S %d/%m/%Y") +timeparts = ( + ("y", "years"), + ("mo", "months"), + ("d", "days"), + ("m", "minutes"), + ("s", "seconds") +) + +def format_timedelta(from_, to): + d = relativedelta(to, from_) + out = "0s" if d.seconds == 0 else "" + for short, attr in timeparts: + x = getattr(d, attr) + if x != 0: out += str(x) + short + return out + CODEBLOCK_REGEX = "^[^`]*```[a-zA-Z0-9_\-+]*\n(.+)```$" CODELINE_REGEX = "^[^`]*`(.*)`$" def extract_codeblock(s): @@ -72,6 +95,20 @@ async def async_exec(code, loc, glob): exec(compile(wrapper, "", "exec"), loc, glob) return await (loc.get("repl_coroutine") or glob.get("repl_coroutine"))() +def make_embed(*, fields=(), footer_text=None, **kwargs): + embed = discord.Embed(**kwargs) + for field in fields: + if len(field) > 2: + embed.add_field(name=field[0], value=field[1], inline=field[2]) + else: + embed.add_field(name=field[0], value=field[1], inline=False) + if footer_text: + embed.set_footer(text=footer_text) + return embed + +def error_embed(msg, title="Error"): return make_embed(color=config["colors"]["error"], description=msg, title=title) +def info_embed(title, msg, fields=()): return make_embed(color=config["colors"]["info"], description=msg, title=title, fields=fields) + # https://github.com/LyricLy/Esobot/blob/bcc9e548c84ea9b23fc832d0b0aaa8288de64886/cogs/general.py lyrictable_raw = { "a": "а", @@ -134,3 +171,8 @@ def apioform(): def unlyric(text): return text.translate(lyrictable).replace("\u200b", "") + +def gen_codeblock(content): + return "```\n" + content.replace("```", "\\`\\`\\`")[:1900] + "\n```" + +def json_encode(x): return json.dumps(x, separators=(',', ':')) \ No newline at end of file diff --git a/wordlist-8192.txt b/wordlist-8192.txt new file mode 100644 index 0000000..8353a7e --- /dev/null +++ b/wordlist-8192.txt @@ -0,0 +1,8192 @@ +aaron +aback +abacus +abalone +abandon +abase +abash +abate +abbey +abbott +abby +abduct +abducts +abdul +abed +abel +abhor +abhors +abide +abides +abject +ablaze +able +abner +aboard +abode +abodes +abort +aborted +aborts +about +above +abraham +absent +absentee +absorb +absorbed +absorbing +absorbs +absurd +abuse +abyss +academies +academy +acadia +accent +accents +accept +accepts +accra +accrue +accuse +ace +aces +acetic +ache +ached +aches +achy +acid +acidic +acids +acing +acme +acne +acorn +acorns +acquit +acre +acres +acrid +acrobat +act +acted +acting +action +actions +active +actor +actors +actress +actresses +acts +acuity +acute +adage +adages +adagio +adam +adams +adapt +add +added +adder +addict +adding +addle +address +addresses +adds +adele +adept +adieu +adios +adjust +adjusted +adjusting +adjusts +adler +adlib +admin +admiral +admirals +admit +admits +admitted +admitting +adobe +adolf +adonis +adopt +adopted +adopting +adopts +adore +adorn +adrian +ads +adult +adultery +adults +advent +adverb +advert +advise +advised +advises +advising +aegis +aerial +aerosol +aesop +afar +affair +affairs +affine +affix +afghan +afire +afoot +afraid +africa +afro +aft +after +again +agatha +agave +age +aged +agenda +agent +ages +agile +aging +aglow +agnes +agnew +ago +agony +agree +ahead +ahoy +aid +aide +aided +aides +aiken +ail +aim +aimed +aiming +aims +air +airline +airlines +airport +airports +airway +aisle +aisles +ajar +ajax +akin +alabama +aladdin +alamo +alan +alarm +alarms +alas +alaska +albert +albino +album +albums +alchemy +alcohol +alcoholic +alden +alder +ale +alec +aleck +aleph +alert +ales +alex +alexa +alfonso +alfred +alfredo +algae +algebra +alia +alias +alibi +alice +alicia +alien +alight +align +alike +alimony +alive +alkali +all +allan +allay +allen +alley +allied +allow +alloy +allure +ally +allyn +alma +almanac +almond +almost +alms +aloe +aloft +aloha +alone +along +alonzo +aloof +aloud +alpha +alpine +alps +also +altar +alter +alto +alum +alumni +alvarez +alvin +always +amadeus +amanda +amass +amaze +amazon +amber +ambient +amble +ambush +ambushed +ambushing +amen +amend +amended +amends +america +american +americans +amid +amigo +amigos +amino +amish +amiss +amity +ammo +ammonia +amnesia +amok +among +amour +amp +ample +amply +amps +amulet +amulets +amuse +amy +anagram +analog +analogy +analyze +analyzed +analyzes +anatomy +anchor +and +andes +andre +andrea +andrew +android +andy +anew +angel +angela +angelo +anger +angie +angle +angles +anglo +angola +angry +angst +angus +animal +anise +anita +ankle +ankles +ann +anna +anne +annex +annie +annoy +annual +annul +anomaly +answer +ant +antares +ante +antenna +anti +antic +anton +antonio +ants +anvil +any +anyhow +anyway +aorta +apache +apart +apathy +ape +apes +apex +aphid +aplomb +apnea +apollo +appeal +appear +appeared +appearing +appears +append +apple +apply +apricot +april +apron +apropos +apt +aqua +arab +arabs +arbor +arc +arcade +arch +archer +archers +arches +archive +archived +archives +arcs +arctic +ardent +are +area +areas +arena +ares +argo +argon +argue +argus +aria +arid +ariel +arise +arizona +ark +arkansas +arlene +arm +armada +armed +armor +armored +armors +arms +army +arnold +aroma +aromas +arose +array +arrays +arrear +arrive +arrived +arrives +arriving +arrow +arsenal +arsenals +arson +art +artery +arthur +artie +artisan +artisans +artist +artists +arts +aruba +ascend +ash +ashen +ashes +ashley +ashy +asia +asian +aside +ask +asked +askew +asks +asleep +aspect +aspen +aspire +aspired +aspires +aspirin +aspiring +asset +assets +assist +assisted +assists +assure +aster +asthma +astral +asylum +ate +athena +athens +athlete +athletes +atla +atlanta +atlas +atoll +atom +atomic +atoms +atone +atop +attic +attire +aubrey +audio +audit +audited +auditing +audits +audrey +auger +august +aunt +aunts +aura +aural +auras +aurora +austin +austria +auto +autumn +avail +avalon +avatar +avenue +average +avert +avery +avian +aviate +avid +avoid +avon +avow +await +awaited +awaiting +awaits +awake +award +aware +awash +away +awe +awful +awl +awoke +awry +axe +axels +axes +axial +axiom +axis +axle +axles +axon +ayers +aztec +azure +babe +babel +babes +babies +baboon +baboons +baby +bach +back +backup +bacon +bad +bade +badge +badger +badgers +badly +baffle +bag +bagel +baggage +bagged +baggy +bags +bahama +bail +bails +bait +bake +baker +bakers +bakes +balance +balanced +balances +bald +baldy +bale +bali +balk +balkan +balky +ball +ballad +balled +ballet +balloon +balloons +ballot +ballots +balls +balm +balms +balmy +balsa +bambi +bambino +bamboo +ban +banal +banana +bananas +band +bandit +bandits +bands +bandy +bane +bang +bangs +banish +banjo +banjos +bank +banks +bar +barb +barbara +barber +barbs +barcode +bard +bare +barf +barfly +bargain +barge +bark +barks +barley +barn +barns +baron +barony +barrel +barry +bars +bart +barter +base +basel +bases +bash +basic +basil +basin +basins +basis +bask +basket +bass +basso +baste +bat +batch +bate +bater +bates +bath +bathe +baths +baton +bats +batteries +battery +bauble +baud +bauer +bavaria +bawd +bawdy +bawl +baxter +bay +bayed +bayonet +bayou +bays +bazaar +bazooka +beach +beaches +beacon +bead +beads +beady +beak +beam +beams +bean +beans +bear +beard +bears +beast +beat +beatles +beats +beauty +beaver +bebop +becalm +beck +becker +becky +bed +beds +bee +beech +beef +beefy +been +beep +beeps +beer +beers +bees +beet +beets +befall +befit +before +beg +began +beget +beggar +beggars +begged +begging +begin +begs +begun +behave +behaved +behaves +behaving +behind +beige +being +beirut +belch +belfry +belgium +belie +belief +beliefs +bell +bella +belle +bellow +bells +belly +belong +below +belt +belts +bemoan +bemoans +ben +bench +benches +bend +bender +bends +benefit +benign +benny +bent +bereft +beret +berg +berlin +bermuda +bern +bernard +berra +berry +bert +berth +bess +best +bet +beta +beth +bethel +betray +bets +betsy +betty +between +bevel +beware +beyond +bezel +bianca +bias +bib +bible +bicep +biceps +bicycle +bid +bide +bids +big +bike +biker +bikini +bikinis +bile +bilge +bilk +bill +billow +bills +billy +bimbo +bin +binary +bind +binds +bing +binge +binged +binges +bingo +bins +biology +biota +biped +birch +bird +birdie +birds +birth +biscuit +bishop +bismark +bison +bisque +bit +bite +bites +bits +bitten +black +blade +blair +blake +blame +blamed +blames +blaming +bland +blank +blare +blast +blaze +bleak +bleat +bled +bleed +bleeding +bleeds +blend +bless +blesses +blew +blimp +blimps +blind +blinded +blinds +blink +blinking +blinks +blip +blips +bliss +blithe +blitz +bloat +bloated +bloating +bloats +blob +blobs +block +blocked +blocking +blocks +bloke +blond +blonde +blood +bloom +blot +blotch +blotches +blots +blow +blown +blows +blue +blues +bluff +blunt +blur +blurs +blurt +blush +blythe +boa +boar +board +boards +boars +boast +boasted +boasting +boasts +boat +boats +bob +bobby +bobcat +bobs +bock +bode +body +bog +bogart +bogey +bogs +bogus +bohemia +boil +boiled +boiling +boils +boise +bold +bolo +bolt +bolts +bomb +bombay +bombs +bon +bonanza +bond +bonds +bone +bones +bongo +bongos +bonjour +bonobo +bonus +bonuses +bony +boo +booby +boogie +book +books +boom +booms +boon +boost +boot +booth +booths +boots +booty +booze +bop +borax +border +borders +bore +bored +bores +boric +boris +born +borne +boron +bosch +bosom +boson +boss +bosses +bossy +boston +botanic +botch +both +bottle +bottles +bough +boulder +boulders +bouncy +bound +bounded +bounds +bourn +bout +bouts +bovine +bow +bowed +bowel +bowie +bowl +bowls +bows +box +boxed +boxer +boxes +boxing +boxy +boy +boyish +boyle +boys +bozo +bra +brace +brad +brady +brag +bragging +brags +braid +brain +brains +brainy +brake +brakes +bran +brand +brands +brandt +brandy +brant +brash +brass +brassy +brat +brats +braun +brave +bravery +bravo +brawl +brawls +brawn +brazil +bread +breads +break +breaking +breaks +breath +bred +breed +breeds +breeze +bremen +brenda +breve +brews +brian +briar +bribe +bribed +bribes +bribing +brice +brick +bricks +bride +brides +bridge +bridges +brief +brig +brigade +brim +brine +bring +brink +briny +brisk +british +broad +brock +broil +broke +broken +bronco +bronx +bronze +brood +broods +brook +broom +broth +brother +brothers +brow +brown +brows +browse +bruce +bruin +brunch +bruno +brunt +brush +brutal +brute +bryan +bryant +bryce +buck +bucket +bucks +bud +buddha +buddy +budge +budget +buds +buenos +buff +buffalo +bug +buggy +bugle +bugs +build +built +bulb +bulbs +bulge +bulk +bulky +bull +bulls +bully +bum +bump +bumps +bumpy +bums +bun +bunch +bunches +bunco +bundle +bunk +bunker +bunkers +bunny +buns +bunt +bunts +bunyan +buoy +bureau +burger +burgers +buried +burly +burma +burn +burned +burns +burnt +burp +burps +burro +burst +burton +bury +bus +bush +bushel +bushy +bust +busy +but +butane +butch +butte +butter +button +buttons +butyl +buxom +buy +buyer +buyers +buys +buzz +buzzer +buzzy +bye +bylaw +byline +bypass +byron +byte +bytes +cab +cabal +cabana +cabaret +cabin +cabinet +cabins +cable +cables +cacao +cache +cackle +cacti +cactus +caddy +cadet +cadets +cadre +caesar +cafe +cafes +cage +caged +cages +cagey +cairn +cairo +cajun +cake +cakes +caleb +calf +calibre +calico +california +call +calls +callus +calm +calms +calorie +calve +calvin +calypso +cam +camber +came +camel +camelot +camels +cameo +camera +camilla +camp +camps +campus +can +canada +canal +canals +canary +cancer +candid +candle +candy +cane +caned +canes +cannon +cannons +cannot +canny +canoe +canon +canopy +cans +cantina +cantor +canvas +canvases +canyon +cap +cape +caped +caper +capital +capri +capsule +captain +car +caramel +carat +caravan +carbon +card +cardinal +care +career +cares +caress +caret +cargo +carl +carla +carlo +carlos +carmen +carmine +carol +carolina +carp +carpet +carrie +carrot +carrots +carry +cars +carson +cart +cartel +cartels +carter +cartoon +carts +carve +carved +carves +case +cases +casey +cash +cashew +casino +casinos +casio +cask +casket +caskets +casks +cast +caste +casting +castle +castles +castro +casts +cat +catalog +catalogs +catch +cathy +catnip +cats +catty +caulk +cause +cave +cavern +caves +caviar +cavort +caw +cease +cecil +cecilia +cedar +cede +celery +cell +cello +celtic +cement +census +cent +centaur +center +central +cents +centuries +century +ceramic +ceres +cern +ceylon +chad +chafe +chaff +chai +chain +chains +chair +chairs +chalk +chamber +chambers +champ +chance +change +changed +changes +channel +chant +chanted +chanting +chants +chaos +chap +chapel +chapels +chapter +chapters +char +chard +chariot +charles +charlie +charm +charms +chart +charter +charters +charts +chase +chases +chasm +chaste +chat +chats +cheap +cheapen +cheat +cheats +check +cheek +cheeky +cheer +cheers +cheese +chef +chefs +chemist +chemists +cherry +cherub +chess +chest +chew +chews +chewy +chic +chicago +chick +chicken +chickens +chicks +chide +chief +chiefs +child +chile +chili +chill +chilly +chime +chimes +chimp +chin +china +chink +chip +chips +chirp +chisel +chit +chive +chloe +chock +choice +choir +choke +choked +chokes +chomp +choose +chop +chopin +chops +choral +chord +chore +chose +chosen +chow +chris +chrome +chuck +chug +chum +chump +chunk +churn +chute +ciao +cicada +cicadas +cider +cigar +cigars +cilia +cinch +cindy +cinema +cipher +ciphers +circa +circle +circuit +circuits +circus +cite +cities +citizen +citizens +citrus +city +civic +civil +clad +claim +claimed +claims +clam +clammy +clamp +clan +clang +clank +clans +clap +claps +clara +clarinet +clarion +clark +clash +clashes +clasp +class +classic +classics +claudia +claus +clause +claw +claws +clay +clean +cleans +clear +cleat +clef +cleft +clerk +clerks +clever +cliche +click +clicks +client +cliff +climax +climb +cling +clinic +clink +clip +clive +cloak +cloaks +clock +clocks +clod +clog +clomp +clone +close +closet +clot +cloth +cloud +clout +clover +clovers +clown +cloy +club +clubs +cluck +clue +clues +clump +clumsy +clung +coach +coal +coast +coat +coats +coax +cob +cobalt +cobble +cobra +cockle +cockpit +cocky +coco +cocoa +coconut +cod +coda +coddle +code +coded +codes +cody +coed +cog +cogent +cogs +coif +coil +coils +coin +coins +coke +cola +colby +cold +cole +collect +colon +colonel +colonies +colony +color +colorado +colors +colt +columbia +columbus +coma +comb +combat +combine +combo +come +comedy +comet +comets +comfy +comic +comma +command +commands +common +commons +compact +companies +company +complex +comply +comrade +con +conan +concert +conch +concord +condo +condor +conduct +cone +coney +confide +congo +conic +connect +connected +connects +conner +conrad +consul +contact +context +contour +contours +control +controls +convert +convex +convey +convoy +conway +cony +cook +cooks +cooky +cool +cooley +coon +coop +cooper +coors +coos +cop +cope +copes +copper +cops +copy +coral +cord +cordon +cordova +cords +core +cores +cork +corks +corn +corner +cornet +corny +corona +correct +correctly +cortex +corvus +cosmic +cosmos +cost +costs +costume +costumes +cosy +cot +cotton +couch +couches +cough +could +count +counted +coup +coupe +couple +couples +coupon +courage +course +court +courts +cousin +cove +cover +covers +covet +cow +cowboy +cowl +cows +cox +coy +coyote +coyotes +cozy +crab +crack +craft +crafts +crag +craig +cram +cramp +crane +cranes +crank +cranks +crap +craps +crash +crass +crate +crater +craw +crawl +crayon +craze +crazy +creak +cream +credit +credo +creed +creek +creep +creole +crepe +crept +cress +crest +crete +crew +crib +cricket +cried +crime +crimp +crimson +crisis +crisp +critic +croak +crock +crocus +croft +crone +crook +croon +crop +crops +cross +crouch +crow +crowd +crown +crows +crud +crude +cruel +crumb +crump +crunch +crush +crushed +crushes +crust +crux +cruz +cry +crypt +crypts +crystal +crystals +cub +cuba +cuban +cube +cubes +cubic +cubist +cubs +cuddle +cue +cues +cuff +cull +cult +cults +culture +cultures +cumin +cup +cupful +cupid +cups +cur +curb +curd +cure +cured +cures +curfew +curie +curl +curled +curls +current +curries +curry +curse +curt +curtain +curve +curves +cusp +cuss +cut +cute +cutlet +cuts +cyan +cycle +cyclone +cyclops +cymbal +cynic +cyril +cyrus +cyst +czar +czech +dab +dad +dada +daddy +daffy +daft +dagger +dahlia +daily +dairy +dais +daisy +dakar +dakota +dale +dallas +dally +dam +damage +damages +dame +damon +damp +dams +damsel +dan +dance +danced +dances +dandy +dane +dang +danger +daniel +dank +danny +dante +danube +dare +dared +dares +dark +darken +darn +darry +dart +darts +darwin +dash +data +date +dates +datum +daub +daunt +dave +david +davis +dawn +dawson +day +days +daze +dazed +dazes +deacon +dead +deadly +deaf +deal +deals +dealt +dean +dear +death +debase +debbie +debby +debit +debra +debri +debris +debt +debts +debug +debut +decade +decades +decaing +decal +decay +december +decibel +decide +decimal +deck +declare +declared +decor +decoy +decree +decry +deed +deeds +deem +deep +deer +defect +defend +defer +define +deform +deft +defy +degree +deify +deign +deity +delaware +delay +delete +deleted +delhi +deli +delia +deliver +dell +delphi +delta +delve +demand +demark +demo +demon +demur +den +denial +denim +denmark +denny +dense +density +dent +denton +dents +denver +deny +depend +depends +deposit +deposits +depot +depth +depute +deputy +derby +desert +deserts +design +desire +desist +desk +desks +detach +detached +detail +detect +detected +detects +deter +detox +detroit +deuce +deus +develop +devil +devoid +devon +dew +dewey +dexter +diablo +diagram +dial +dialog +dials +diamond +diana +diane +diaper +diary +dibble +dibs +dice +did +die +died +diego +diem +dies +diesel +diet +diets +diety +dig +digit +digital +digits +digs +dike +dilate +dilemma +dill +dim +dime +dimes +dimly +dims +din +dine +diner +diners +ding +dingo +dingy +dinner +dinners +diode +dip +diploma +dips +dirac +dire +direct +directed +directs +dirge +dirk +dirt +dirty +disc +disco +dish +dishes +disk +disney +dispute +disputed +distant +disuse +ditch +ditches +ditto +ditty +diva +divan +dive +dives +divide +divided +dixie +dixon +dizzy +doc +dock +docket +doctor +doctors +dodge +doe +does +dog +dogma +dogs +doily +doing +dolby +dolce +dole +doll +dollar +dollars +dolly +dolphin +dolphins +dolt +domain +dome +domed +domino +don +donald +done +donna +donor +donut +doom +door +dope +dopey +dora +doric +doris +dorm +dormant +dose +dot +dote +dots +double +doubt +doug +dough +dour +douse +dove +dover +doves +dow +dowel +down +downs +dowry +doyle +doze +dozen +drab +draco +draft +drag +dragon +dragons +drain +drained +drains +drake +drama +drank +drape +drastic +draw +drawl +drawn +dread +dreaded +dreads +dream +dreamy +dreg +dregs +dress +dressy +drew +dried +drier +dries +drift +drifting +drill +drink +drinks +drip +drips +drive +driver +droid +droids +droll +drone +drool +droop +drop +drops +drove +drown +drug +drugs +druid +drum +drums +drunk +dry +dryad +dual +dub +dublin +duck +ducks +duct +dud +dude +due +duel +dueler +dues +duet +duff +duffy +dug +duke +dull +duly +dumb +dumbo +dummy +dump +dumps +dumpy +dunce +dune +dung +dunham +dunk +dunlop +duo +duos +dupe +during +dusk +dusky +dust +dusty +dutch +duty +dwarf +dwell +dwelt +dwight +dwyer +dye +dyed +dying +dylan +dynamic +dynamo +dynamos +dynasty +dyne +each +eager +eagle +ear +earl +early +earn +earns +ears +earth +ease +easel +easing +east +eastern +easy +eat +eaten +eater +eats +eave +eaves +ebb +ebony +echo +echoes +eclipse +ecology +economy +eddie +eddy +eden +edgar +edge +edges +edgy +edible +edict +edify +edison +edit +edith +edition +editions +editor +editors +edits +educate +educated +edward +edwin +eel +eels +eerie +efface +effect +effects +egan +egg +eggroll +eggs +ego +egress +egret +egypt +eight +eighteen +eighth +eighty +eject +elastic +elate +elbow +elder +eldon +elect +electra +elegant +elegy +element +elena +eleven +eleventh +elf +elfin +elide +elite +eliza +elk +elks +ella +ellen +ellipse +ellis +elm +elmer +elms +elope +elroy +else +elsie +elton +elude +elves +elvis +email +embalm +embargo +embark +embed +ember +emerald +emery +emil +emily +emit +emits +emma +emmy +emory +emote +emotion +empire +employ +empty +emu +enact +enamel +end +ended +ending +endive +ends +enema +enemy +energy +engine +england +english +engulf +enid +enigma +enjoy +enmity +ennui +enrico +ensue +enter +entrap +entry +envoy +envy +eon +eons +epic +epics +episode +epoch +epoxy +epsom +equal +equals +equator +equip +era +erase +erato +ere +erect +erg +ergo +eric +erica +erie +erin +ernest +ernie +ernst +erode +eros +erosion +err +errand +error +erupt +erwin +escape +escort +eskimo +essay +essex +ester +etch +eternal +ethan +ethel +ether +ethic +ethics +ethnic +ethos +ethyl +eucre +euler +eureka +euro +europe +eva +evade +evan +evans +eve +even +evening +event +ever +everest +every +evict +evident +evil +evoke +evolve +ewe +exact +exalt +exam +example +exams +excel +except +excess +exert +exhibit +exile +exist +exit +exits +exodus +exotic +expand +expel +explain +explore +expo +export +express +extant +extend +extent +extol +extra +extreme +exude +exult +eye +eyed +eyes +ezra +fable +fabric +face +faces +facet +facile +fact +factor +factory +facts +fad +fade +fads +fail +faint +fair +fairs +fairy +faith +fake +faker +falcon +fall +false +fame +family +famous +fan +fancy +fang +fangs +fanout +fans +fantasy +far +farce +fare +fargo +farm +farmer +farms +fashion +fast +fat +fatal +fate +father +fats +fatty +fault +faun +fauna +faust +faux +fawn +fax +faze +fear +fears +feast +feat +feather +february +fed +fee +feeble +feed +feeds +feel +feels +fees +feet +feign +feint +felice +felix +fell +felt +femur +fence +fend +fermi +fern +ferrari +ferric +ferry +fertile +fest +fetal +fetch +fetid +fetus +feud +feudal +fever +few +fez +fiasco +fiat +fib +fiber +fickle +fiction +fidel +fief +field +fiend +fiery +fiesta +fifteen +fifth +fifty +fig +fight +figs +figure +fiji +filch +file +filed +files +filet +fill +filler +filly +film +films +filmy +filter +filth +fin +final +finale +finance +finch +find +finder +fine +fined +finer +finger +finish +finite +fink +finland +fiona +fir +fire +firm +first +fish +fished +fisher +fishy +fist +fit +fits +five +fix +fixed +fizz +fjord +flab +flack +flag +flail +flair +flak +flake +flaky +flame +flank +flap +flare +flash +flask +flat +flavor +flaw +flax +flay +flea +fleck +fled +flee +fleet +fleming +flesh +flew +flex +flick +flier +flies +flight +flinch +fling +flint +flip +flipper +flirt +flit +float +flock +flog +flood +floor +flop +floppy +flora +floral +florida +flour +flout +flow +flower +flown +floyd +flu +flub +fluff +fluid +fluke +flung +flush +flute +flux +fly +flyer +flynn +foal +foam +foamy +fob +focal +foci +focus +fodder +foe +foes +fog +foggy +foil +fold +folio +folk +folly +fond +font +food +fool +foot +fop +for +foray +forbid +force +ford +forest +forever +forge +forget +forgot +fork +form +formal +format +forms +formula +fort +forte +forth +fortune +forty +forum +forward +fossil +foul +found +four +fourteen +fourth +fovea +fowl +fox +foxes +foxtrot +foxy +foyer +fractal +fragile +frail +frame +fran +franc +franca +france +francis +frank +fraud +fray +freak +fred +freddie +free +freed +freedom +freer +freeze +freezer +french +frenzy +freon +fresh +fret +freud +friar +friday +fried +friend +fries +fright +frill +frilly +frisbee +frisky +fritz +frock +frog +frogs +from +frond +front +frost +froth +frown +froze +frozen +fruit +fry +fuchsia +fudge +fuel +fugue +fuji +full +fully +fumble +fume +fumes +fun +fund +funds +fungal +fungi +fungus +funk +funky +funny +fur +furry +furs +fury +fuse +fuss +fussy +future +fuzz +fuzzy +gab +gable +gabriel +gadget +gaffe +gag +gage +gags +gain +gait +gal +gala +galaxy +gale +galileo +gall +gallery +gallop +game +games +gamma +gamut +gander +gang +gangs +gap +gape +gapes +gaps +garage +garb +garbage +garbo +garcia +garden +gargle +garish +garlic +garner +garth +gary +gas +gash +gasp +gasps +gassy +gate +gates +gator +gauche +gaudy +gauge +gaul +gaunt +gauss +gauze +gave +gavel +gavin +gawk +gawky +gaze +gazed +gazes +gear +gears +gecko +geese +gel +gelatin +geld +gem +gemini +gems +gene +general +genes +genesis +genetic +geneva +genie +genius +genoa +genre +gent +gentle +gentry +genuine +genus +geo +george +georgia +gerbil +germ +german +germany +germs +get +gets +getty +ghana +ghent +ghetto +ghost +ghoul +ghouls +giant +gibson +giddy +gift +gifts +gig +gila +gilbert +gild +giles +gill +gills +gilt +gimbal +gimpy +gin +gina +ginger +giraffe +gird +girl +girls +girth +gist +give +given +gives +gizmo +glacier +glad +gladdy +glade +glamor +glance +gland +glare +glass +glaze +gleam +glean +glee +glen +glib +glide +glint +gloat +glob +global +globe +glom +gloom +gloria +glory +gloss +glove +glow +glows +glucose +glue +glued +gluey +gluing +glum +glut +glyph +gnarl +gnarly +gnash +gnat +gnaw +gnaws +gnome +gnu +goa +goad +goal +goals +goat +goats +goblet +goblin +god +godly +gods +goes +goggle +gogo +going +gold +golem +golf +goliath +golly +gomez +gondola +gone +gong +goo +good +goods +gooey +goof +goofy +goon +goose +gopher +gordon +gore +gorge +gorilla +gory +gosh +gospel +gossip +got +gouda +gouge +gourd +gout +gown +gowns +grab +grabs +grace +grad +grade +grady +graft +grail +grain +gram +grams +grand +granite +grant +grape +graph +graphs +grasp +grass +grate +grave +gravel +gravity +gravy +gray +graze +great +greece +greed +greedy +greek +green +greet +greg +gregory +gremlin +greta +grew +grey +grid +grief +grieve +griffin +grill +grim +grime +grimy +grin +grind +grins +grip +gripe +gripes +grips +grit +groan +groat +grog +groin +groom +groove +grope +gross +ground +group +grout +grove +grovel +grow +growl +grown +grows +grub +grubs +gruff +grunt +guam +guano +guard +guava +guess +guest +guide +guild +guile +guilt +guinea +guise +guitar +gulag +gulf +gull +gulls +gully +gulp +gum +gumbo +gummy +gun +gunk +gunky +guns +guppy +gurgle +guru +gus +gush +gust +gustav +gusts +gusty +gut +guts +gutsy +guy +guyana +guys +gwen +gym +gypsum +gypsy +gyro +habit +habitat +hack +had +hades +hadron +hag +hague +haiku +hail +hair +hairs +hairy +haiti +hal +hale +haley +half +hall +halls +halo +halt +halts +halve +ham +hamlet +hammer +hams +hand +handle +hands +handy +hang +hanger +hank +hanna +hannah +hanoi +hans +hansel +hap +happy +harbor +hard +hardly +hardy +hare +harem +hark +harlem +harley +harm +harmony +harms +harold +harp +harps +harpy +harris +harry +harsh +harvard +harvest +harvey +has +hash +haste +hasty +hat +hatch +hate +hater +hates +hatred +hats +haul +hauls +haunt +haunts +havana +have +haven +havoc +haw +hawaii +hawk +hawks +hay +hayes +hazard +haze +hazel +hazy +head +heads +heady +heal +heals +healy +heap +heaps +hear +heard +hears +heart +heat +heath +heats +heave +heaven +heavy +hebrew +heck +heckle +hectic +hedge +heed +heel +heels +heft +hefty +height +heir +heirs +held +helen +helena +helga +helium +helix +hell +hello +helm +help +hem +hemp +hems +hen +hence +henry +hens +her +hera +herb +herbal +herbert +herbs +herd +here +herman +hero +heroic +heron +herons +hers +hertz +hew +hewn +hex +hexagon +hexed +hey +hid +hide +hides +high +higher +hijack +hike +hikes +hill +hills +hilly +hilt +him +hind +hindi +hindu +hinge +hint +hints +hip +hippie +hippo +hippy +hips +hire +hired +hires +his +hiss +history +hit +hitch +hits +hive +hives +hoard +hoax +hob +hobbit +hobby +hobo +hoc +hock +hockey +hodge +hodges +hoe +hog +hogan +hogs +hoist +hold +holds +holdup +hole +holes +holiday +hollow +holly +holt +holy +home +hone +honest +honesty +honey +hong +honk +honor +hood +hoof +hook +hooks +hookup +hoop +hoot +hop +hope +hopes +hops +horde +horizon +horn +horse +horus +hose +host +hostel +hot +hotbox +hotel +hotrod +hound +hour +house +houston +hovel +hover +how +howdy +howl +howls +hoyle +hub +hubbub +hubby +huber +hubs +huck +hue +hued +hues +huey +huff +hug +huge +hugo +hugs +hula +hulk +hull +hum +human +humid +humor +hump +humps +hums +humus +hun +hunch +hundred +hung +hunk +hunt +hunter +hunts +hurl +huron +hurrah +hurry +hurt +husband +hush +husk +husky +hut +hutch +hyde +hydra +hydro +hyena +hymn +hymnal +hype +hyper +hypo +iambic +ian +ibex +ibis +ibiza +ice +iceberg +iced +icicle +icing +icky +icon +icons +icy +ida +idaho +idea +ideal +ideals +ideas +idiom +idle +idly +idol +idols +idyll +iffy +igloo +ignite +igor +iliad +ill +image +imagine +imbibe +imbue +imitate +immune +immure +imp +impact +impel +imply +import +impress +imps +inane +inapt +inca +incest +inch +include +incur +index +india +indiana +indies +indigo +inept +inert +infamy +infant +infect +infer +infix +info +infra +ingot +ingrid +inhale +initial +ink +inky +inlay +inlet +inn +inner +inns +input +insect +inset +inside +instant +instead +insult +intel +intend +inter +into +intro +invent +invest +invite +invoke +ion +ionic +ions +iota +iowa +iran +iraq +iraqi +irate +ire +irene +iris +irish +irk +irked +iron +ironic +irons +irony +isaac +isabel +isis +islam +island +isle +isotope +israel +issue +italian +italy +itch +itchy +item +items +ivan +ivory +ivy +jab +jack +jackal +jacket +jackson +jacob +jade +jaded +jaguar +jail +jaime +jake +jam +jamaica +jamb +james +jan +jane +january +janus +japan +jar +jargon +jars +jasmine +jason +jaunt +java +jaw +jaws +jay +jazz +jazzy +jean +jeans +jedi +jeep +jeer +jeers +jeff +jello +jelly +jenny +jerk +jerks +jerky +jerome +jerry +jersey +jess +jesse +jessica +jest +jester +jesus +jet +jets +jew +jewel +jewish +jibe +jiffy +jig +jiggle +jigs +jill +jilt +jim +jimmy +jinx +jive +joan +job +jobs +jock +jockey +jody +joe +joel +joey +jog +jogs +john +join +joins +joint +joke +joker +jokes +jolly +jolt +jon +jonas +jones +jordan +jorge +jose +josef +joseph +josh +joshua +jostle +jot +jots +joule +journal +joust +jove +jowl +jowls +jowly +joy +joyce +juan +judas +jude +judge +judo +judy +jug +juggle +jugs +juice +juicy +juju +juke +jukes +julep +jules +julia +julie +juliet +julio +julius +july +jumbo +jump +jumps +jumpy +june +jungle +junior +junk +junky +juno +junta +jupiter +juror +jury +just +justice +jut +jute +kabul +kafka +kale +kane +kansas +kant +kappa +kaput +karate +karen +karl +karma +karol +karp +kate +kathy +katie +katz +kava +kayak +kazoo +keats +keel +keen +keep +keeps +keg +kegs +keith +keller +kelly +kelp +kemp +ken +kennel +kentucky +kenya +kepler +kept +kermit +kerry +kettle +kevin +key +keyed +keys +khaki +khan +khmer +kick +kicks +kid +kidney +kids +kiev +kill +kills +kiln +kilo +kilt +kilts +kim +kimono +kin +kind +kinds +kinetic +king +kingdom +kings +kink +kinky +kiosk +kirby +kirk +kiss +kit +kitchen +kite +kites +kitty +kiva +kiwi +klaus +klaxon +klutz +knack +knave +knead +knee +kneel +knees +knelt +knew +knick +knife +knight +knit +knits +knob +knobs +knock +knoll +knot +knots +know +known +knows +knox +koala +kodak +kong +kook +kooks +kooky +korea +kraft +kraut +krebs +kudos +kurd +kurt +kyle +kyoto +lab +label +labor +labs +lace +laces +lack +lacks +lactic +lacuna +lacy +lad +ladder +laden +ladle +lads +lady +lag +lager +lagoon +lagos +lags +laid +lain +lair +laity +lake +lakes +lam +lamar +lamb +lambs +lame +lamp +lamps +lance +land +lands +lane +lang +lanky +laos +lap +lapel +laps +lapse +laptop +lard +large +lark +larks +larry +lars +larsen +larva +larynx +laser +lash +lass +lasso +last +latch +late +later +latest +latex +lathe +latin +laud +laugh +launch +laura +lava +law +lawn +lawns +laws +lax +lay +layer +lays +layup +lazarus +laze +lazy +lea +leach +lead +leads +leaf +leafy +leak +leaks +leaky +lean +leap +leaps +leapt +lear +learn +leary +lease +leash +least +leave +lecture +led +ledge +lee +leech +leeds +leek +leer +leers +leery +leeway +left +lefty +leg +legacy +legal +legend +legion +legs +leland +lemma +lemon +lend +lends +length +lenin +lenny +lenore +lens +lent +leo +leon +leona +leonid +leopard +leper +leroy +less +lesson +lest +let +lets +letter +lev +levee +level +lever +levi +levis +levy +lewd +lewis +lexical +lexicon +liar +liars +libel +liberal +libido +libra +library +libya +lice +license +lick +licks +lid +lids +lie +lied +lien +lies +lieu +life +lift +lifts +light +like +liked +liken +likes +lilac +lilly +lilt +lily +lima +limb +limbo +limbs +lime +limit +limp +limps +lin +lincoln +lind +linda +linden +line +linear +linen +lines +lingo +link +lint +linus +lion +lip +lipid +lips +liquid +lira +lisa +lisbon +lisp +list +listen +lists +lit +liter +lithe +lithium +little +live +liven +liver +livid +living +liz +lizzie +llama +lloyd +load +loaf +loan +loaner +lob +lobby +lobe +lobs +lobster +local +locate +loch +lock +locks +locus +lode +lodge +loft +lofty +log +logan +loge +logic +logical +logo +logs +loin +loins +loire +lois +loiter +loki +lola +lomb +lome +london +lone +lonely +loner +long +longer +longs +look +looks +loom +loon +loony +loop +loose +loot +lope +lopez +lops +lord +lore +lorenzo +lose +loser +loses +loss +lossy +lost +lot +lots +lotto +lotus +lou +loud +louis +louise +louisiana +louse +lousy +lout +love +loved +lover +low +lower +lowry +loyal +lucas +luce +lucia +lucid +luck +lucky +lucy +ludwig +lug +luge +luger +lugs +luis +luke +lull +lumbar +lumen +lump +lumps +lumpy +luna +lunar +lunch +lung +lunge +lungs +lurch +lure +lurid +luring +lurk +lurks +lush +lust +lusty +lute +luxury +lydia +lye +lying +lymph +lynch +lynx +lyon +lyre +lyric +macaw +mace +mach +machine +macho +mack +macro +mad +madam +made +madly +madman +madonna +madrid +mae +maestro +mafia +magenta +magi +magic +magma +magnet +magnum +magoo +magpie +maid +maids +mail +mailbox +maim +maims +main +maine +maize +major +make +malady +male +mali +malice +malign +mall +malls +malt +malta +mama +mambo +mammal +mammoth +man +mana +manager +mandolin +mane +mange +mango +mania +manic +manila +manly +manna +manor +manse +mantle +manual +many +maori +map +maple +maps +mar +maraud +marble +march +marco +marcy +mares +marge +margin +margo +maria +marie +marimba +marin +marina +marine +mariner +mario +marion +mark +market +marks +marlin +marlon +marrow +marry +mars +marsh +mart +martin +martyr +marvin +marx +mary +maryland +mash +mask +masks +mason +mass +mast +master +masts +mat +match +mate +mated +mateo +mates +math +matrix +mats +matt +matte +mature +matzo +maul +mauls +mauve +mavis +maw +max +maxim +maxima +maximum +maxwell +may +maya +maybe +mayday +mayer +mayhem +mayo +mayor +maze +mazes +mead +meadow +meal +meals +mealy +mean +meaning +means +meant +meat +meaty +mecca +medal +media +medic +medical +medics +medium +medley +medusa +meek +meet +meets +meg +mega +mel +meld +melee +mellow +melody +melon +melt +melts +member +memo +memoir +memory +memos +memphis +men +mend +mendez +mendoza +mends +menlo +mental +mentor +menu +meow +merck +mercury +mercy +mere +merge +merit +merits +merlin +merry +mesa +mescal +mesh +meson +mess +message +messy +met +metal +meteor +meter +method +metro +mew +mexico +meyer +meyers +mezzo +miami +mice +michael +mickey +micro +mid +midas +middle +midge +midst +miff +might +miguel +mike +milan +mild +mildew +mile +miles +milk +milky +mill +miller +millet +million +mills +milo +milt +mime +mimes +mimi +mimic +mimosa +mince +mind +minds +mine +mined +miner +mineral +minerva +mines +mini +minimal +minimum +mink +minnesota +minnow +minor +minsk +mint +mints +minty +minus +minute +mira +miracle +mirage +miranda +mire +mired +mirror +mirth +miser +misery +miss +mission +missy +mist +mistake +mister +mists +misty +mit +mite +mites +mitts +mix +mixed +mixer +mixes +mixture +mixup +moan +moans +moat +moats +mob +mobil +mobile +mobs +moby +mock +mocks +modal +mode +model +modem +modern +modest +modish +modular +moe +mogul +moist +mojo +molar +mold +molds +mole +moles +molly +molt +molten +mom +moment +mommy +mona +monaco +monad +monarch +monday +mondo +money +monic +monica +monitor +monk +monkey +mono +monster +montana +month +monty +moo +mooch +mood +moods +moody +moon +moons +moose +moot +mop +mope +mopes +mops +moral +morale +morbid +more +morgan +morn +morning +moron +morph +morris +morse +morsel +mort +mortal +mosaic +moser +moses +moss +mossy +most +mot +mote +motel +moth +mother +moths +motif +motor +motto +mould +mound +mount +mourn +mouse +mousy +mouth +move +moved +moves +movie +mow +mowed +mower +mows +moxie +mozart +much +muck +mucus +mud +muddy +muff +muffin +mug +muggy +mugs +muir +mulch +mule +mules +mull +multi +mumble +mumps +munch +mung +munich +munson +muon +mural +muriel +murk +murky +muse +muses +museum +mush +mushy +music +musical +musk +musky +muslim +muss +mussel +must +mustang +musty +mute +muted +mutt +myers +mylar +myopia +myra +myron +myrrh +myself +mystery +mystic +myth +myths +nab +nabs +nadia +nadir +nag +nagoya +nags +nail +nails +naked +name +named +names +nancy +naomi +nap +nape +napkin +naps +nary +nasal +nash +nasty +natal +natasha +nate +native +natty +natural +nature +nausea +naval +nave +navel +navy +nay +neal +near +nearby +neat +nebraska +nebula +neck +necks +nectar +ned +need +needle +needs +needy +negate +neigh +neil +nell +nelsen +nelson +neon +nepal +neptune +nerd +nero +nerve +ness +nest +nests +net +nets +network +neuron +neutral +neutron +nevada +never +new +newly +news +newt +newton +next +nexus +nib +nibs +nice +nicer +nicety +niche +nick +nickel +niece +nifty +niger +nigh +night +nil +nile +nimbus +nina +nine +nineteen +ninety +ninja +ninth +nip +nirvana +nit +nitric +nitro +nitty +nix +nixon +noah +nob +nobel +noble +nobody +nod +nodal +node +nods +noel +noise +noisy +nolan +nomad +nominal +nonce +none +nook +noon +noose +nope +nor +nora +norm +norma +normal +north +norway +nose +noses +nosy +not +notch +note +noted +notes +nothing +notre +noun +nouns +nova +novak +novel +november +now +nowhere +nuance +nubia +nuclear +nuclei +nucleus +nude +nudge +nuke +null +numb +number +numeric +nun +nuns +nurse +nut +nutmeg +nuts +nutty +nylon +nymph +oaf +oak +oaken +oakley +oar +oars +oases +oasis +oat +oath +oats +oberon +obese +obey +obeys +obit +object +objet +oboe +obscure +observe +ocarina +occur +ocean +ochre +oct +octal +octave +octavia +octet +october +octopus +odd +oddity +odds +ode +odin +odium +odor +odors +off +offal +offend +offer +office +oft +often +ogden +ogle +ogled +ogles +ogre +ohio +ohm +oil +oiled +oils +oily +oink +okay +okays +okinawa +oklahoma +okra +olaf +olav +old +olden +older +oldy +olga +olive +oliver +olivia +olympic +omaha +oman +omega +omen +omens +omicron +omit +omits +once +one +onion +only +onset +onto +onus +onward +onyx +ooze +oozed +opal +opals +open +openly +opens +opera +opinion +opium +optic +optimal +optimum +option +opus +oral +orange +orate +orb +orbit +orbital +orbs +orca +orchid +ordain +order +ore +oregano +oregon +organ +organic +orient +origami +origin +orion +orlando +ornery +orphan +osaka +oscar +osier +oslo +othello +other +otis +otter +otto +ouch +ought +ounce +our +ours +oust +out +outdo +outer +outlaw +outside +ouzo +ova +oval +ovals +ovary +ovate +oven +ovens +over +overt +ovid +owe +owed +owen +owens +owes +owing +owl +owls +own +owned +owner +owners +owns +oxen +oxeye +oxford +oxide +oxnard +oxygen +ozark +ozone +pablo +pabst +pace +paces +pacific +pack +package +packet +packs +pact +pad +paddy +padre +pads +pagan +page +pages +pagoda +paid +pail +pain +pains +paint +pair +pal +palace +paladin +pale +pall +palm +palma +palms +pals +palsy +pam +pamela +pan +panama +pancake +panda +pandora +pane +panel +pang +panic +pans +pansy +pant +panther +pants +panty +papa +papal +paper +pappy +paprika +papua +par +paradox +parch +pardon +parent +pareto +pariah +paris +park +parker +parking +parks +parlor +parody +parole +parrot +parry +parse +parsley +part +partner +parts +party +pascal +pass +passage +passive +past +pasta +paste +pastel +pasty +pat +patch +patent +path +paths +patient +patio +patriot +patrol +pats +patsy +pattern +patton +patty +paul +paula +pauli +paulo +pause +pave +paved +paves +paw +pawed +pawn +pawns +paws +pax +pay +payday +paz +pea +peace +peach +peak +peaks +peaky +peal +pear +pearl +pears +peas +peat +pebble +pecan +peck +pecks +pedal +pedro +peek +peel +peep +peer +peeve +peg +pegasus +peggy +pegs +pelican +pelt +pen +penal +pence +pencil +pend +penguin +penny +pens +pent +peony +people +pep +pepper +peppy +percent +perch +percy +perez +perfect +perform +perfume +peril +period +perk +perks +perky +perm +permit +perry +persia +person +perth +peru +peruse +pest +pests +pet +petal +pete +peter +petit +petri +pets +petty +pew +phage +phantom +phase +phenol +phi +phil +phoenix +phone +phony +photo +phrase +phyla +physic +piano +pica +picasso +piccolo +pick +picks +pickup +picky +picnic +picture +pie +piece +pier +pierce +pierre +piers +pies +piety +pig +pigeon +pigment +pigs +pigsty +pike +pile +piles +pilgrim +pill +pills +pilot +pimple +pin +pinball +pinch +pine +pines +ping +pinion +pink +pins +pint +pinto +pinup +pioneer +pious +pip +pipe +piper +pique +pirate +piston +pit +pita +pitch +pith +pithy +pitney +pits +pity +pius +pivot +pixel +pixie +pizza +place +plague +plaid +plain +plan +plane +planet +plank +plant +plasm +plasma +plastic +plat +plate +plato +play +playa +plays +plaza +plea +plead +pleas +pleat +pledge +pliny +plod +plods +plop +plot +plots +plow +plows +ploy +ploys +pluck +plug +plugs +plum +plumb +plume +plump +plums +plunk +plus +plush +plushy +pluto +ply +poach +pocket +pod +podge +podium +pods +poe +poem +poems +poet +poetic +poetry +pogo +poi +point +poise +poison +poke +poked +poker +pokes +polar +polaris +pole +poles +police +polio +politic +politics +polk +polka +poll +polls +polo +polygon +pomona +pomp +poncho +pond +ponds +pong +pony +pooch +pooh +pool +pools +poor +pop +popcorn +pope +poppy +pops +popular +porch +pore +pores +pork +porous +port +portal +portia +porto +ports +portugal +pose +posed +poses +posey +posh +posit +posse +post +postage +poster +posts +pot +potato +pots +potter +pouch +pound +pour +pours +pout +pouts +pow +powder +power +pox +prague +pram +prank +prawn +pray +prays +precise +preen +prefer +prefix +prelude +premium +prep +prepare +present +press +presto +pretend +pretty +prey +price +prick +pride +prig +prim +prime +primp +prince +print +printer +prior +prism +prissy +private +privy +prize +pro +probe +problem +process +prod +prodigy +prods +product +profile +program +project +prom +promise +promo +prone +prong +proof +prop +propel +proper +props +propyl +prose +prosper +protect +protest +proton +proud +prove +provide +prow +prowl +proxy +prude +prune +prunes +pry +psalm +psych +pub +public +pubs +puce +puck +pucker +puddle +puddly +pudgy +puerto +puff +puffin +puffs +puffy +pug +puke +pull +pulls +pulp +pulsar +pulse +puma +pump +pumps +pun +punch +punic +punish +punk +punks +punky +puns +punt +punts +puny +pup +pupil +puppy +pure +purge +purify +purple +purse +pus +push +pushy +put +puts +putty +puzzle +pygmy +pyramid +pyre +pyrex +pyrite +python +qatar +quack +quad +quaff +quail +quake +quality +qualm +quark +quarry +quart +quarter +quash +quasi +quay +queasy +quebec +queen +quell +query +quest +queue +quick +quid +quiet +quill +quilt +quilts +quint +quip +quips +quirk +quit +quite +quits +quiver +quiz +quota +quote +rabbi +rabbit +rabid +race +raced +races +rachel +rack +racy +radar +radial +radical +radii +radio +radish +radium +radius +radon +rafael +raft +rafts +rag +rage +raged +rags +raid +raids +rail +rails +rain +rainbow +rains +rainy +raise +raisin +raj +raja +rake +raked +rakes +rally +ralph +ram +raman +rambo +ramirez +ramp +rams +ramsey +ran +ranch +random +rang +range +ranger +rangy +rank +ranks +rant +rants +rap +rapid +raps +rapt +rare +rascal +rash +rasp +rat +rate +rated +rates +rating +ratio +rats +rattle +rave +raved +raven +ravioli +raw +ray +raymond +rays +raze +razor +reach +read +reads +ready +reagan +real +realm +ream +reap +rear +reave +rebel +rebut +recap +recipe +recital +reck +record +recur +recycle +red +redeem +redo +reduce +reed +reeds +reef +reek +reeks +reel +reels +reese +reeve +refer +reflex +reform +regal +regard +regina +region +regis +regular +rehab +reich +reid +reign +rein +reins +reject +relax +relay +relic +rely +reman +remark +remedy +remit +remix +remora +remote +remus +rend +renew +reno +renown +rent +rents +rep +repair +repay +repeat +repel +repent +reply +report +reps +reptile +request +rerun +reset +resin +resort +respect +respond +rest +rests +result +resume +retch +return +reuse +reveal +revel +reverse +revet +review +revved +reward +rewove +rex +rheum +rhine +rhino +rho +rhode +rhyme +rib +ribbon +ribs +ricardo +rice +rich +richard +richmond +rick +rico +rid +ride +rider +ridge +rifle +rift +rig +riga +rigel +right +rigid +rigs +riley +rill +rim +rims +rind +ring +ringo +rings +rink +rinse +rio +riot +riots +rip +ripe +ripen +ripley +rips +rise +risen +risk +risky +rite +ritual +ritz +rival +river +rivet +riviera +roach +road +roads +roam +roar +roast +rob +robe +robert +robin +robot +robs +rock +rocket +rocks +rocky +rod +rode +rodent +rodeo +rods +roe +roger +rogue +roil +role +roll +rolls +roman +rome +romeo +romp +ron +ronald +rondo +rood +roof +rook +rookie +room +rooms +roomy +roost +root +roots +rope +rosa +rose +rosen +rosetta +ross +rosy +rot +rote +roth +rotor +rots +rouge +rough +round +rouse +rout +route +rove +rover +row +rowdy +rows +roy +royal +royce +rub +rubber +rube +ruben +rubric +rubs +ruby +ruddy +rude +rudolf +rudy +rue +rufus +rug +rugged +rugs +ruin +ruins +rule +ruler +rules +rum +rumen +rummy +rumor +rump +rumpus +run +rune +runes +rung +runs +runt +runty +runway +rupee +rural +ruse +rush +russ +russia +russian +russo +rust +rusts +rusty +rut +ruth +ruts +rutty +ryan +rye +saber +sabine +sable +sabrina +sack +sacks +sacred +sad +sadden +saddle +sadly +safari +safe +safer +safes +sag +saga +sagas +sage +sags +sahara +said +sail +sailor +sails +saint +sake +salad +salami +salary +sale +salem +sales +saline +salk +sally +salmon +salon +salsa +salt +salts +salty +salute +salve +salvo +sam +samba +same +sammy +samoa +sample +samuel +sanchez +sand +sandal +sandra +sands +sandy +sane +sang +sanity +sank +santa +santana +sap +sappy +saps +sarah +sardine +sari +sase +sash +sat +satan +satin +saturday +saturn +satyr +sauce +saucy +saudi +saul +sauna +savage +save +saved +saves +savory +savoy +savvy +saw +saws +sawyer +sax +saxon +say +says +scab +scala +scald +scale +scalp +scam +scamp +scan +scans +scar +scare +scarf +scarlet +scars +scary +scene +scent +scholar +school +scion +scoff +scold +scoop +scoot +scope +scorch +score +scorn +scorpio +scott +scour +scout +scow +scowl +scram +scrap +scrape +scratch +screen +screw +scrip +script +scrod +scroll +scrub +scuba +scud +scuff +scull +scum +scurry +sea +seal +seals +seam +seams +sean +sear +seas +season +seat +seats +seattle +second +secret +sect +section +sector +sects +secure +sedan +seduce +see +seed +seeds +seedy +seek +seeks +seem +seems +seen +seep +seer +seers +sees +seethe +segment +seize +select +self +selfish +sell +sells +semi +seminar +senator +send +sends +seneca +senior +sense +sensor +sent +sentry +seoul +sepia +september +sequel +sequin +serf +serial +serif +serpent +serum +serve +service +servo +sesame +set +seth +sets +setup +seven +seventeen +seventh +seventy +sever +severe +sew +sewed +sewer +sewn +sews +shack +shade +shadow +shady +shaft +shag +shaggy +shah +shake +shaken +shaky +shale +shall +shallow +sham +shame +shampoo +shank +shannon +shape +shard +shards +share +shark +sharon +sharp +shave +shaw +shawl +she +shear +sheath +shed +sheds +sheen +sheep +sheer +sheet +sheik +shelf +shell +shelter +sheriff +sherman +shift +shifty +shill +shim +shin +shine +shins +shiny +ship +ships +shire +shirk +shirt +shiv +shoal +shock +shoe +shoes +shone +shook +shoot +shoots +shop +shops +shore +short +shot +shots +shout +shove +show +shown +shows +showy +shrank +shred +shrew +shriek +shrike +shrink +shrub +shrug +shuck +shun +shunt +shut +shuts +shy +shyly +siam +sick +side +siege +siena +sienna +sierra +siesta +sieve +sift +sifts +sigh +sight +sigma +sign +signal +signs +silence +silicon +silk +silks +silky +sill +silly +silo +silt +silty +silver +similar +simon +simons +simple +sin +sinai +sinatra +since +sincere +sine +sinew +sing +singe +single +sings +sink +sinks +sins +sinus +sioux +sip +sips +sir +sire +siren +sis +sister +sit +site +sites +sits +six +sixteen +sixth +sixty +size +sizes +ska +skate +skew +ski +skid +skids +skied +skiers +skies +skiff +skiffs +skiing +skill +skim +skimp +skimpy +skims +skin +skip +skips +skirt +skis +skit +skits +skulk +skull +skunk +sky +slab +slabs +slack +slag +slain +slalom +slam +slams +slang +slant +slap +slaps +slash +slat +slate +slater +slave +slaw +slay +sled +sleds +sleek +sleep +sleet +slept +slew +slice +slick +slid +slide +slim +slime +slimy +sling +slip +slips +slit +sliver +sloan +slob +slog +slogan +sloop +slop +slope +sloppy +slops +slosh +slot +sloth +slots +slow +slows +slug +slugs +sluice +slum +slump +slums +slung +slur +slurp +slurs +sly +slyly +smack +small +smart +smash +smear +smell +smelt +smile +smirk +smith +smithy +smock +smog +smoggy +smoke +smoky +smooth +smudgy +smug +smut +snack +snafu +snag +snail +snails +snake +snap +snaps +snare +snark +snarl +snatch +sneak +sneer +sniff +snip +snipe +snob +snobs +snook +snoop +snore +snort +snot +snout +snow +snows +snowy +snub +snubs +snuff +snug +soak +soaks +soap +soapy +soar +soars +sob +sober +sobs +social +society +sock +socks +sod +soda +sofa +sofia +soft +soften +soggy +soil +soils +sol +solar +sold +sole +solemn +solid +solo +solomon +solve +soma +somber +some +son +sonar +sonata +song +songs +sonic +sonny +sonora +sons +sony +soon +soot +sooth +sop +soprano +sore +sorry +sort +sorts +sot +sough +soul +sound +soup +soupy +sour +source +sousa +south +soviet +sow +sown +sows +soy +soyuz +spa +space +spade +spain +spam +span +spank +spans +spar +spare +spark +sparks +sparta +spas +spasm +spat +spawn +spay +speak +spear +special +speck +sped +speech +speed +spell +spend +spent +sperm +spew +sphere +sphinx +spice +spicy +spider +spies +spike +spill +spilt +spin +spine +spins +spiral +spire +spires +spirit +spit +spite +spits +spitz +splat +splay +spline +split +spock +spoil +spoke +sponge +sponsor +spoof +spook +spooky +spool +spoon +spore +sport +spot +spots +spout +sprain +sprang +spray +sprays +spree +sprig +spring +spruce +spry +spud +spun +spunk +spur +spurn +spurs +spurt +spy +squad +square +squat +squaw +squid +squint +squirm +stab +stabs +stack +stacy +stadium +staff +stag +stage +staid +stain +stains +stair +stake +stale +stalk +stall +stamp +stan +stance +stand +stank +stanza +staph +star +stare +stark +stars +start +stash +stat +state +static +stats +statue +status +stave +stay +stays +stead +steady +steak +steal +steam +steed +steel +steep +steer +stein +stella +stem +stems +step +steps +stereo +sterile +stern +steve +stew +stick +sticky +stiff +stigma +stile +still +sting +stingy +stink +stint +stir +stirs +stock +stoic +stoke +stole +stomp +stone +stony +stood +stool +stoop +stop +stops +store +stork +storm +stormy +story +stout +stove +stow +strafe +strange +strap +straw +stray +street +stretch +strewn +strike +strip +stroll +strong +strum +strut +stuart +stub +stuck +stud +student +studio +study +stuff +stuffy +stump +stun +stung +stunk +stuns +stunt +style +styx +suave +sub +subject +subs +subtle +subtly +subway +such +suck +sucks +sudan +suds +sue +sued +suede +sues +suez +sugar +suit +suite +suits +sulfur +sulk +sulks +sulky +sully +sultan +sultry +sum +sumac +summer +summon +sumo +sums +sun +sunday +sung +sunk +sunny +suns +sunset +sunup +sup +super +supper +support +supra +supreme +sure +surf +surge +survive +susan +sushi +susie +suss +suzy +swag +swam +swami +swamp +swampy +swan +swanky +swans +swap +swarm +swart +swat +swath +sway +sways +swear +sweat +sweaty +swede +sweden +sweep +sweet +swell +swept +swift +swig +swim +swims +swine +swing +swipe +swirl +swish +swiss +switch +swoop +sword +swore +sworn +swum +swung +sybil +sykes +sylvan +symbol +syria +syrup +system +tab +table +tablet +taboo +tabs +tacit +tack +tacky +taco +tacoma +tact +tactic +tad +taffy +taft +tag +tags +tahiti +tahoe +taiga +tail +tailor +tails +taint +take +taken +takes +talc +tale +talent +tales +talk +talks +tall +tallow +tally +talon +tam +tame +tamer +tampa +tamper +tan +tang +tango +tangy +tank +tanks +tans +tanya +tao +tap +tape +taped +taper +tapes +tapir +taps +tar +tara +tardy +target +tariff +tarp +tarry +tart +tarts +tarzan +task +taste +tasty +tattle +tattoo +tau +taunt +taurus +taut +tavern +tawny +tax +taxi +tea +teach +teacher +teacup +teak +teal +team +teams +tear +tease +tech +ted +teddy +tee +teem +teen +teens +teensy +tees +teeth +teflon +telecom +telex +tell +tells +temper +temple +tempo +tempt +ten +tend +tends +tenet +tennis +tenor +tens +tense +tensor +tent +tenth +tents +tepee +tepid +term +terms +tern +terry +terse +test +tests +testy +texan +texas +text +textile +thai +than +thank +that +thatch +thaw +thaws +the +theft +their +them +theme +then +theory +there +thermos +these +theta +they +thick +thief +thigh +thin +thing +think +thins +third +thirsty +thirteen +thirty +this +thomas +thong +thor +thorn +thorny +thousand +threat +three +threw +throb +throes +throw +throws +thrum +thud +thug +thumb +thump +thursday +thwart +thyme +tiara +tiber +tibet +tibia +tic +tick +ticket +ticks +tics +tidal +tidbit +tide +tidy +tie +tied +tier +ties +tiger +tight +tilde +tile +tiled +tiles +till +tilt +tilth +tim +time +times +timid +tin +tina +tine +tinge +tinny +tint +tiny +tip +tipoff +tips +tipsy +tire +tired +tires +titan +titanic +tithe +title +titus +toad +toads +toast +tobacco +toby +today +toe +toes +tofu +tog +toga +togo +togs +toil +toilet +toils +token +tokyo +told +toll +tolls +tom +tomato +tomb +tombs +tome +tommy +ton +tonal +tone +tong +tonga +tonic +tonight +tonk +tons +tonsil +tony +too +took +tool +tools +toot +tooth +top +topaz +topic +topple +tops +topsy +torah +torch +torn +tornado +toronto +torpedo +torso +tort +torus +toss +tot +total +tote +totem +tots +touch +tough +tour +tourist +tours +tout +tow +towel +tower +town +tows +toxic +toxin +toy +toys +trace +track +tract +tractor +tracy +trade +traffic +tragedy +trail +train +trait +tram +tramp +trance +transit +trap +trapeze +traps +trash +travel +trawl +tray +trays +tread +treat +treble +tree +trees +trek +trench +trend +tress +triad +trial +triangle +tribal +tribe +tribune +trick +tricky +trident +tried +tries +trill +trilogy +trim +trims +trinity +trio +trip +tripe +tripod +trips +trite +triton +trivial +trod +troll +trombone +troop +tropic +trot +trots +trout +troy +truce +truck +trudge +trudy +true +truly +trumpet +trunk +truss +trust +truth +try +tub +tuba +tube +tubes +tubs +tuck +tudor +tues +tuesday +tuft +tufts +tug +tugs +tulane +tulip +tulsa +tumble +tuna +tunas +tune +tuned +tunic +tunis +tunnel +tuple +turbine +turbo +turf +turin +turk +turkey +turn +turquoise +turtle +turvy +tush +tusk +tusks +tussle +tutor +tutu +tux +twain +tweak +tweed +twelfth +twelve +twenty +twice +twig +twigs +twill +twin +twine +twins +twirl +twist +twisty +twit +two +twos +tyburn +tycoon +tying +tyke +tyler +type +typed +types +typic +typo +tyson +uganda +ugly +ulcer +ultra +umber +umbra +umpire +unary +uncle +uncut +under +undo +undue +unfit +unhand +unhook +unicorn +uniform +unify +union +unique +unit +unite +united +units +unity +unix +unsafe +untie +until +unto +unwed +update +upend +uphill +uphold +upon +upper +uproar +upset +uptake +upton +uranium +urban +urea +urge +urged +urgent +urges +urine +urn +ursula +usage +use +used +useful +user +uses +usher +usual +usurp +utah +utile +utmost +utopia +utter +uvula +vacuum +vague +vail +vain +vale +valet +valeur +valid +valor +value +valve +vampire +van +vane +vanilla +vans +vapor +variant +vase +vases +vast +vat +vatican +vats +vault +veal +vector +veer +veers +vega +veggie +veil +vein +veins +velcro +veldt +vellum +velvet +venal +vendor +vends +venial +venice +venom +vent +vents +ventura +venus +vera +verb +verbs +verge +verify +verity +vermont +vern +verne +verona +verse +version +vertigo +verve +very +vessel +vest +vests +vet +veteran +veto +vets +vex +vexed +vexes +via +vial +vials +vibes +vibrate +vicar +vice +vices +vichy +vicky +victor +victory +video +vie +vienna +view +vigil +vigor +viking +vile +villa +village +vincent +vine +vines +vinyl +viola +violet +violin +viper +virgil +virginia +virgo +virtual +virus +visa +visible +vision +visit +visitor +visor +vista +visual +vital +vitamin +viva +vivian +vivid +vixen +vocal +vodka +vogue +voice +void +volcano +volga +volt +voltage +volts +volume +vomit +voodoo +vortex +vote +vouch +vow +vowel +vows +voyage +voyager +vulcan +vulture +vying +wack +wacky +wad +wade +wades +wafer +waffle +wag +wage +wager +wages +waggle +wagon +wags +waif +wail +wails +waist +wait +waiter +waive +wake +waken +waldo +wale +walk +wall +walls +wally +walrus +walsh +walt +walter +walton +waltz +wan +wand +wane +wang +want +wants +war +warble +ward +warden +ware +warm +warmth +warn +warning +warns +warp +warren +wars +wart +warts +warty +wary +was +wash +washington +washy +wasp +wasps +wast +waste +watch +water +watt +watts +wave +waved +waver +waves +wavy +wax +waxen +waxy +way +wayne +ways +weak +weal +wealth +wean +wear +wears +weary +weather +weave +web +weber +webs +webster +wed +wedding +wedge +wednesday +weds +weed +weedy +week +weekend +weeks +weep +weeps +weigh +weir +weird +welch +welcome +weld +well +wells +welsh +welt +wendy +went +wept +were +west +western +wet +wets +whack +whale +wham +wharf +what +wheat +wheel +wheels +whelp +when +where +which +whig +while +whim +whine +whinny +whip +whips +whir +whirl +whisk +whiskey +whit +white +whiz +who +whole +whom +whoop +whoosh +whose +why +wick +wide +widen +wider +widow +width +wield +wife +wig +wigs +wild +wile +wiley +will +william +wills +willy +wilma +wilt +wily +wimp +wimpy +win +wince +winch +wind +window +windup +windy +wine +wines +wing +wings +wink +winks +winner +wins +winter +wipe +wire +wires +wiry +wisconsin +wisdom +wise +wiser +wish +wisp +wispy +wit +witch +with +wits +witty +wive +wizard +woe +woes +wok +woke +wolf +woman +womb +women +won +wonder +wong +wood +woods +woody +woof +wool +woozy +word +words +wordy +wore +work +world +worm +worms +wormy +worn +worry +worse +worst +worth +would +wound +wove +woven +wow +wrack +wraith +wrap +wrath +wreak +wreck +wren +wring +wrist +writ +write +writhe +wrong +wrote +wry +wyatt +wyoming +xenon +xerox +xylem +yacht +yak +yale +yalta +yam +yams +yang +yank +yankee +yanks +yard +yards +yarn +yaw +yawn +yawns +yeah +year +yearn +yeast +yeasty +yell +yellow +yemen +yen +yep +yes +yet +yew +yews +yield +yin +yip +yips +yodel +yoga +yogi +yogurt +yoke +yokel +yolk +yore +york +you +young +your +yours +youth +yowl +yowls +yoyo +yucca +yuck +yukon +yule +zaire +zap +zaps +zeal +zealot +zebra +zen +zenith +zero +zeroes +zest +zesty +zeta +zeus +ziggy +zigzag +zilch +zinc +zing +zinger +zion +zip +zipper +zippers +zips +ziti +zodiac +zoe +zone +zoned +zoning +zoo +zoom +zooms +zoos +zulu +zurich