From 755c8510d7bfa4c628348ad2878accb2690912d1 Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Sat, 27 May 2023 20:41:08 -0400 Subject: [PATCH 01/79] First basic implementation of ChatGPT --- functions.js | 24 ++++++++++++++++++++++++ package.json | 7 ++++--- slash-commands/chat.js | 20 ++++++++++++++++++++ 3 files changed, 48 insertions(+), 3 deletions(-) create mode 100644 slash-commands/chat.js diff --git a/functions.js b/functions.js index 025c020..2d2650e 100644 --- a/functions.js +++ b/functions.js @@ -21,6 +21,14 @@ const Discord = require('discord.js'); // Fuzzy text matching for db lookups const FuzzySearch = require('fuzzy-search'); +// OpenAI +const { Configuration, OpenAIApi } = require("openai"); + +const configuration = new Configuration({ + apiKey: process.env.OPENAI_API_KEY, +}); +const openai = new OpenAIApi(configuration); + // Various imports from other files const config = require('./config.json'); const strings = require('./strings.json'); @@ -530,6 +538,22 @@ const functions = { } } }, + openAI: { + chatPrompt(userPrompt) { + return new Promise(async (resolve, reject) => { + const response = await openai.createCompletion({ + model: 'text-davinci-003', + prompt: userPrompt, + temperature: 0, + max_tokens: 250 + }).catch(e => { + reject(e); + return null; + }); + resolve(response); + }); + } + }, // Parent-Level functions (miscellaneuous) closeRequest(requestId, interaction) { if (interaction.user.id == ownerId) { diff --git a/package.json b/package.json index 7c84570..05f8e83 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "nodbot", - "version": "3.1.0", - "description": "Nods and Nod Accessories.", + "version": "3.2.0", + "description": "Nods and Nod Accessories, now with ChatGPT!", "main": "main.js", "dependencies": { "@discordjs/builders": "^0.16.0", @@ -12,10 +12,11 @@ "dotenv": "^10.0.0", "fuzzy-search": "^3.2.1", "mysql": "^2.18.1", + "openai": "^3.2.1", "tenorjs": "^1.0.10" }, "engines": { - "node": "16.x" + "node": "18.x" }, "devDependencies": { "eslint": "^7.32.0" diff --git a/slash-commands/chat.js b/slash-commands/chat.js new file mode 100644 index 0000000..848efe8 --- /dev/null +++ b/slash-commands/chat.js @@ -0,0 +1,20 @@ +const { SlashCommandBuilder } = require('@discordjs/builders'); +const fn = require('../functions.js'); + +module.exports = { + data: new SlashCommandBuilder() + .setName('chat') + .setDescription('Send a message to ChatGPT') + .addStringOption(o => + o.setName("prompt") + .setDescription("Prompt to send to ChatGPT") + .setRequired(true) + ), + async execute(interaction) { + await interaction.deferReply(); + const userPrompt = interaction.options.getString("prompt"); + const response = await fn.openAI.chatPrompt(userPrompt).catch(e => console.error(e)); + const responseText = response.data.choices[0].text; + await interaction.editReply(`${responseText}`); + }, +}; \ No newline at end of file From 53625be91f3f91483d4f4e1adb2236236372bbc8 Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Sun, 28 May 2023 10:08:51 -0400 Subject: [PATCH 02/79] Basic Dall-e implementation --- functions.js | 36 +++++++++++++++++++++++++++++++++++- slash-commands/dalle.js | 25 +++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 slash-commands/dalle.js diff --git a/functions.js b/functions.js index 2d2650e..3a0ebe2 100644 --- a/functions.js +++ b/functions.js @@ -28,6 +28,14 @@ const configuration = new Configuration({ apiKey: process.env.OPENAI_API_KEY, }); const openai = new OpenAIApi(configuration); +async function openAIStatus(o) { + const response = await o.listModels(); + const models = response.data.data; + models.forEach(e => { + console.log(`Model ID: ${e.id}`); + }); +}; +openAIStatus(openai); // Various imports from other files const config = require('./config.json'); @@ -544,7 +552,7 @@ const functions = { const response = await openai.createCompletion({ model: 'text-davinci-003', prompt: userPrompt, - temperature: 0, + temperature: 0.7, max_tokens: 250 }).catch(e => { reject(e); @@ -552,6 +560,20 @@ const functions = { }); resolve(response); }); + }, + imagePrompt(userPrompt, userId) { + return new Promise(async (resolve, reject) => { + try { + const response = await openai.createImage({ + prompt: userPrompt, + user: userId + }); + resolve(response.data.data[0].url); + } catch (e) { + reject(e); + return; + } + }); } }, // Parent-Level functions (miscellaneuous) @@ -595,6 +617,18 @@ const functions = { return newText + ' <:spongebob:1053398825965985822>'; }, + generateErrorId() { + const digitCount = 10; + const digits = []; + for (let i = 0; i < digitCount; i++) { + const randBase = Math.random(); + const randNumRaw = randBase * 10; + const randNumRound = Math.floor(randNumRaw); + digits.push(randNumRound); + } + const errorId = digits.join(""); + return errorId; + } }; module.exports = functions; \ No newline at end of file diff --git a/slash-commands/dalle.js b/slash-commands/dalle.js new file mode 100644 index 0000000..eb97f9d --- /dev/null +++ b/slash-commands/dalle.js @@ -0,0 +1,25 @@ +const { SlashCommandBuilder } = require('@discordjs/builders'); +const fn = require('../functions.js'); + +module.exports = { + data: new SlashCommandBuilder() + .setName('dalle') + .setDescription('Generate an image with DALL-e') + .addStringOption(o => + o.setName("prompt") + .setDescription("Prompt to send to DALL-e") + .setRequired(true) + ), + async execute(interaction) { + try { + await interaction.deferReply(); + const userPrompt = interaction.options.getString("prompt"); + const response = await fn.openAI.imagePrompt(userPrompt); + await interaction.editReply(`${response}`); + } catch (err) { + const errorId = fn.generateErrorId(); + console.error(`${errorId}: ${err}`); + await interaction.editReply(`An error has occured. Error ID: ${errorId}\n${err}`); + } + }, +}; \ No newline at end of file From 4e2e8bc70290b2571662d532678ac0634e537e06 Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Mon, 29 May 2023 08:47:07 -0400 Subject: [PATCH 03/79] Add size option and response embed for dall-e --- functions.js | 11 ++++++++++- slash-commands/dalle.js | 18 +++++++++++++++--- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/functions.js b/functions.js index 3a0ebe2..6296e14 100644 --- a/functions.js +++ b/functions.js @@ -377,6 +377,14 @@ const functions = { interaction.reply({ embeds: [ strainEmbed ]}); }, + dalle(prompt, imageUrl) { + const dalleEmbed = new Discord.MessageEmbed() + .setAuthor({ name: "NodDraw" }) + .setTimestamp() + .setImage(imageUrl) + .setFooter({ text: prompt }); + return { embeds: [dalleEmbed] }; + } }, collect: { gifName(interaction) { @@ -561,11 +569,12 @@ const functions = { resolve(response); }); }, - imagePrompt(userPrompt, userId) { + imagePrompt(userPrompt, size, userId) { return new Promise(async (resolve, reject) => { try { const response = await openai.createImage({ prompt: userPrompt, + size: size, user: userId }); resolve(response.data.data[0].url); diff --git a/slash-commands/dalle.js b/slash-commands/dalle.js index eb97f9d..ccb1ad6 100644 --- a/slash-commands/dalle.js +++ b/slash-commands/dalle.js @@ -9,13 +9,25 @@ module.exports = { o.setName("prompt") .setDescription("Prompt to send to DALL-e") .setRequired(true) - ), + ) + .addStringOption(o => + o.setName("size") + .setDescription("1024x1024, 512x512, 256x256") + .setRequired(false) + .addChoices( + { name: "1024x1024 (2¢)", value: "1024x1024" }, + { name: "512x512 (1.8¢)", value: "512x512" }, + { name: "256x256 (1.6¢)", value: "256x256" } + )), async execute(interaction) { try { await interaction.deferReply(); const userPrompt = interaction.options.getString("prompt"); - const response = await fn.openAI.imagePrompt(userPrompt); - await interaction.editReply(`${response}`); + const size = interaction.options.getString("size") ? interaction.options.getString("size") : "512x512"; + + const imageUrl = await fn.openAI.imagePrompt(userPrompt, size); + const dalleEmbed = fn.embeds.dalle(userPrompt, imageUrl); + await interaction.editReply(dalleEmbed); } catch (err) { const errorId = fn.generateErrorId(); console.error(`${errorId}: ${err}`); From 2c75ff09d95a054dad8af67767be2c04fc2ff9b9 Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Mon, 29 May 2023 09:22:11 -0400 Subject: [PATCH 04/79] Improved embed style. --- functions.js | 24 +++++++++++++++++++----- slash-commands/chat.js | 4 ++-- slash-commands/dalle.js | 2 +- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/functions.js b/functions.js index 6296e14..2547257 100644 --- a/functions.js +++ b/functions.js @@ -377,13 +377,27 @@ const functions = { interaction.reply({ embeds: [ strainEmbed ]}); }, - dalle(prompt, imageUrl) { + dalle(user, prompt, imageUrl) { const dalleEmbed = new Discord.MessageEmbed() - .setAuthor({ name: "NodDraw" }) - .setTimestamp() + .setAuthor({ name: "NodBot powered by DALL-E", iconURL: "https://assets.vfsh.dev/openai-logos/PNGs/openai-logomark.png" }) + .addFields( + { name: "Prompt", value: prompt } + ) .setImage(imageUrl) - .setFooter({ text: prompt }); + .setFooter({ text: user.username, iconURL: user.avatarURL() }) + .setTimestamp(); return { embeds: [dalleEmbed] }; + }, + gpt(user, prompt, response) { + const gptEmbed = new Discord.MessageEmbed() + .setAuthor({ name: "NodBot powered by GPT-3", iconURL: "https://assets.vfsh.dev/openai-logos/PNGs/openai-logomark.png" }) + .addFields( + { name: "Prompt", value: prompt }, + { name: "Response", value: response } + ) + .setFooter({ text: user.username, iconURL: user.avatarURL() }) + .setTimestamp(); + return { embeds: [gptEmbed] }; } }, collect: { @@ -566,7 +580,7 @@ const functions = { reject(e); return null; }); - resolve(response); + resolve(response.data.choices[0].text); }); }, imagePrompt(userPrompt, size, userId) { diff --git a/slash-commands/chat.js b/slash-commands/chat.js index 848efe8..e3aee29 100644 --- a/slash-commands/chat.js +++ b/slash-commands/chat.js @@ -14,7 +14,7 @@ module.exports = { await interaction.deferReply(); const userPrompt = interaction.options.getString("prompt"); const response = await fn.openAI.chatPrompt(userPrompt).catch(e => console.error(e)); - const responseText = response.data.choices[0].text; - await interaction.editReply(`${responseText}`); + const gptEmbed = fn.embeds.gpt(interaction.user, userPrompt, response); + await interaction.editReply(gptEmbed); }, }; \ No newline at end of file diff --git a/slash-commands/dalle.js b/slash-commands/dalle.js index ccb1ad6..ff105f6 100644 --- a/slash-commands/dalle.js +++ b/slash-commands/dalle.js @@ -26,7 +26,7 @@ module.exports = { const size = interaction.options.getString("size") ? interaction.options.getString("size") : "512x512"; const imageUrl = await fn.openAI.imagePrompt(userPrompt, size); - const dalleEmbed = fn.embeds.dalle(userPrompt, imageUrl); + const dalleEmbed = fn.embeds.dalle(interaction.user, userPrompt, imageUrl); await interaction.editReply(dalleEmbed); } catch (err) { const errorId = fn.generateErrorId(); From efdc605dc0373f71041091829bbaa36a854032df Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Wed, 31 May 2023 08:07:12 -0400 Subject: [PATCH 05/79] Adding costs to embeds --- functions.js | 17 ++++++----------- slash-commands/chat.js | 7 ++++++- slash-commands/dalle.js | 2 +- strings.json | 10 ++++++++++ 4 files changed, 23 insertions(+), 13 deletions(-) diff --git a/functions.js b/functions.js index 2547257..fd0e479 100644 --- a/functions.js +++ b/functions.js @@ -377,26 +377,21 @@ const functions = { interaction.reply({ embeds: [ strainEmbed ]}); }, - dalle(user, prompt, imageUrl) { + dalle(prompt, imageUrl, size) { const dalleEmbed = new Discord.MessageEmbed() .setAuthor({ name: "NodBot powered by DALL-E", iconURL: "https://assets.vfsh.dev/openai-logos/PNGs/openai-logomark.png" }) .addFields( { name: "Prompt", value: prompt } ) .setImage(imageUrl) - .setFooter({ text: user.username, iconURL: user.avatarURL() }) - .setTimestamp(); + .setFooter({ text: `This ${size} image cost ${strings.costs.dalle[size]}¢ to generate.` }) return { embeds: [dalleEmbed] }; }, - gpt(user, prompt, response) { + gpt(prompt, response, usage) { const gptEmbed = new Discord.MessageEmbed() .setAuthor({ name: "NodBot powered by GPT-3", iconURL: "https://assets.vfsh.dev/openai-logos/PNGs/openai-logomark.png" }) - .addFields( - { name: "Prompt", value: prompt }, - { name: "Response", value: response } - ) - .setFooter({ text: user.username, iconURL: user.avatarURL() }) - .setTimestamp(); + .setDescription(`**Prompt**\n${prompt}\n\n**Response**\n${response}`) + .setFooter({ text: `This prompt used ${usage.tokens} tokens for a cost of ${usage.usd}¢` }) return { embeds: [gptEmbed] }; } }, @@ -580,7 +575,7 @@ const functions = { reject(e); return null; }); - resolve(response.data.choices[0].text); + resolve(response.data); }); }, imagePrompt(userPrompt, size, userId) { diff --git a/slash-commands/chat.js b/slash-commands/chat.js index e3aee29..a538115 100644 --- a/slash-commands/chat.js +++ b/slash-commands/chat.js @@ -14,7 +14,12 @@ module.exports = { await interaction.deferReply(); const userPrompt = interaction.options.getString("prompt"); const response = await fn.openAI.chatPrompt(userPrompt).catch(e => console.error(e)); - const gptEmbed = fn.embeds.gpt(interaction.user, userPrompt, response); + const responseText = response.choices[0].text.slice(2); + const usage = { + tokens: response.usage.total_tokens, + usd: response.usage.total_tokens * ( 0.2 / 1000 ) // 0.2¢ per 1000 tokens or 0.0002¢ per token. + }; + const gptEmbed = fn.embeds.gpt(userPrompt, responseText, usage); await interaction.editReply(gptEmbed); }, }; \ No newline at end of file diff --git a/slash-commands/dalle.js b/slash-commands/dalle.js index ff105f6..a848e02 100644 --- a/slash-commands/dalle.js +++ b/slash-commands/dalle.js @@ -26,7 +26,7 @@ module.exports = { const size = interaction.options.getString("size") ? interaction.options.getString("size") : "512x512"; const imageUrl = await fn.openAI.imagePrompt(userPrompt, size); - const dalleEmbed = fn.embeds.dalle(interaction.user, userPrompt, imageUrl); + const dalleEmbed = fn.embeds.dalle(userPrompt, imageUrl, size); await interaction.editReply(dalleEmbed); } catch (err) { const errorId = fn.generateErrorId(); diff --git a/strings.json b/strings.json index bcf8a14..b82b6db 100644 --- a/strings.json +++ b/strings.json @@ -22,5 +22,15 @@ "bussin fr, no cap", "ongggg no :billed_cap: fr fr" ], + "costs": { + "gpt": { + "gpt-3.5-turbo": 0.2 + }, + "dalle": { + "256x256": 1.6, + "512x512": 1.8, + "1024x1024": 2.0 + } + }, "temp": {} } \ No newline at end of file From 200468ac1001cd291f3d2cd5481be812e5134f30 Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Wed, 31 May 2023 08:33:03 -0400 Subject: [PATCH 06/79] Implement logging to db --- functions.js | 8 +++++++- slash-commands/chat.js | 3 ++- slash-commands/dalle.js | 2 ++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/functions.js b/functions.js index fd0e479..54c1da4 100644 --- a/functions.js +++ b/functions.js @@ -391,7 +391,7 @@ const functions = { const gptEmbed = new Discord.MessageEmbed() .setAuthor({ name: "NodBot powered by GPT-3", iconURL: "https://assets.vfsh.dev/openai-logos/PNGs/openai-logomark.png" }) .setDescription(`**Prompt**\n${prompt}\n\n**Response**\n${response}`) - .setFooter({ text: `This prompt used ${usage.tokens} tokens for a cost of ${usage.usd}¢` }) + .setFooter({ text: `This prompt used ${usage.tokens} tokens for a cost of ${usage.usdc}¢` }) return { embeds: [gptEmbed] }; } }, @@ -488,6 +488,12 @@ const functions = { resolve(); }); }) + }, + openai(user, prompt, engine, tokens, usdc) { + const query = `INSERT INTO openai (user, prompt, engine, tokens, usdc) VALUES (${db.escape(user)}, ${db.escape(prompt)}, ${db.escape(engine)}, ${db.escape(tokens)}, ${db.escape(usdc)})`; + db.query(query, (err) => { + if (err) throw err; + }); } }, download: { diff --git a/slash-commands/chat.js b/slash-commands/chat.js index a538115..2418a7b 100644 --- a/slash-commands/chat.js +++ b/slash-commands/chat.js @@ -17,9 +17,10 @@ module.exports = { const responseText = response.choices[0].text.slice(2); const usage = { tokens: response.usage.total_tokens, - usd: response.usage.total_tokens * ( 0.2 / 1000 ) // 0.2¢ per 1000 tokens or 0.0002¢ per token. + usdc: response.usage.total_tokens * ( 0.2 / 1000 ) // 0.2¢ per 1000 tokens or 0.0002¢ per token. }; const gptEmbed = fn.embeds.gpt(userPrompt, responseText, usage); await interaction.editReply(gptEmbed); + fn.upload.openai(interaction.user.id, userPrompt, "gpt-3.5-turbo", usage.tokens, usage.usdc); }, }; \ No newline at end of file diff --git a/slash-commands/dalle.js b/slash-commands/dalle.js index a848e02..7636c1a 100644 --- a/slash-commands/dalle.js +++ b/slash-commands/dalle.js @@ -1,5 +1,6 @@ const { SlashCommandBuilder } = require('@discordjs/builders'); const fn = require('../functions.js'); +const strings = require("../strings.json"); module.exports = { data: new SlashCommandBuilder() @@ -28,6 +29,7 @@ module.exports = { const imageUrl = await fn.openAI.imagePrompt(userPrompt, size); const dalleEmbed = fn.embeds.dalle(userPrompt, imageUrl, size); await interaction.editReply(dalleEmbed); + fn.upload.openai(interaction.user.id, userPrompt, "dalle", 0, strings.costs.dalle[size]); } catch (err) { const errorId = fn.generateErrorId(); console.error(`${errorId}: ${err}`); From 08618e2be27fbc38f039dee25f5fcd573079ad9f Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Thu, 15 Jun 2023 19:07:16 -0400 Subject: [PATCH 07/79] Experimental generating content embed --- functions.js | 8 ++++++++ slash-commands/chat.js | 1 + slash-commands/dalle.js | 1 + 3 files changed, 10 insertions(+) diff --git a/functions.js b/functions.js index 54c1da4..df69ff9 100644 --- a/functions.js +++ b/functions.js @@ -393,6 +393,14 @@ const functions = { .setDescription(`**Prompt**\n${prompt}\n\n**Response**\n${response}`) .setFooter({ text: `This prompt used ${usage.tokens} tokens for a cost of ${usage.usdc}¢` }) return { embeds: [gptEmbed] }; + }, + generatingResponse() { + const embed = new Discord.MessageEmbed() + .setAuthor({ name: "NodBot powered by OpenAI", iconURL: "https://assets.vfsh.dev/openai-logos/PNGs/openai-logomark.png" }) + .setImage("https://tenor.com/view/sucks-gif-4499658") + .setDescription("Generating a response, please stand by.") + .setFooter({ text: "Ligma balls" }); + return { embeds: [embed] }; } }, collect: { diff --git a/slash-commands/chat.js b/slash-commands/chat.js index 2418a7b..ed21ea5 100644 --- a/slash-commands/chat.js +++ b/slash-commands/chat.js @@ -12,6 +12,7 @@ module.exports = { ), async execute(interaction) { await interaction.deferReply(); + await interaction.editReply(fn.embeds.generatingResponse()); const userPrompt = interaction.options.getString("prompt"); const response = await fn.openAI.chatPrompt(userPrompt).catch(e => console.error(e)); const responseText = response.choices[0].text.slice(2); diff --git a/slash-commands/dalle.js b/slash-commands/dalle.js index 7636c1a..029b066 100644 --- a/slash-commands/dalle.js +++ b/slash-commands/dalle.js @@ -23,6 +23,7 @@ module.exports = { async execute(interaction) { try { await interaction.deferReply(); + await interaction.editReply(fn.embeds.generatingResponse()); const userPrompt = interaction.options.getString("prompt"); const size = interaction.options.getString("size") ? interaction.options.getString("size") : "512x512"; From 7c09aaffaa7c94d775aa310ebbbce76e35450b75 Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Thu, 15 Jun 2023 19:16:50 -0400 Subject: [PATCH 08/79] Minor updates --- functions.js | 2 +- slash-commands/chat.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/functions.js b/functions.js index df69ff9..369af8b 100644 --- a/functions.js +++ b/functions.js @@ -397,7 +397,7 @@ const functions = { generatingResponse() { const embed = new Discord.MessageEmbed() .setAuthor({ name: "NodBot powered by OpenAI", iconURL: "https://assets.vfsh.dev/openai-logos/PNGs/openai-logomark.png" }) - .setImage("https://tenor.com/view/sucks-gif-4499658") + .setImage("https://media.tenor.com/aHMHzNGCb4kAAAAC/sucks.gif") .setDescription("Generating a response, please stand by.") .setFooter({ text: "Ligma balls" }); return { embeds: [embed] }; diff --git a/slash-commands/chat.js b/slash-commands/chat.js index ed21ea5..efeaad7 100644 --- a/slash-commands/chat.js +++ b/slash-commands/chat.js @@ -15,7 +15,7 @@ module.exports = { await interaction.editReply(fn.embeds.generatingResponse()); const userPrompt = interaction.options.getString("prompt"); const response = await fn.openAI.chatPrompt(userPrompt).catch(e => console.error(e)); - const responseText = response.choices[0].text.slice(2); + const responseText = response.choices[0].text; const usage = { tokens: response.usage.total_tokens, usdc: response.usage.total_tokens * ( 0.2 / 1000 ) // 0.2¢ per 1000 tokens or 0.0002¢ per token. From c8d059e36d794c0e10b59937d93075735817045f Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Sun, 6 Aug 2023 08:47:15 -0400 Subject: [PATCH 09/79] Ignore all .env --- .gitignore | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 06fecb3..138619b 100644 --- a/.gitignore +++ b/.gitignore @@ -2,8 +2,7 @@ .vscode package-lock.json .VSCodeCounter/ -env.dev -env.prod +.env* # Custom folders # gifs/* From e99e6b2e1ff33c5723f6883ad4335e39999457c4 Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Sun, 6 Aug 2023 08:51:12 -0400 Subject: [PATCH 10/79] Run CI on push to main --- .github/workflows/production-docker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/production-docker.yml b/.github/workflows/production-docker.yml index d4e5c6b..db69c5c 100644 --- a/.github/workflows/production-docker.yml +++ b/.github/workflows/production-docker.yml @@ -1,7 +1,7 @@ name: NodBot Production Dockerization on: - pull_request: + push: branches: - main From 38fdc07e4e4368fca36275084c2abd7424cc8e9f Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Sun, 6 Aug 2023 08:51:28 -0400 Subject: [PATCH 11/79] Revert .sb functionality --- functions.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/functions.js b/functions.js index 369af8b..65891b1 100644 --- a/functions.js +++ b/functions.js @@ -627,6 +627,7 @@ const functions = { }, spongebob(commandData) { let newText = ''; + let lastIsUpper = 0; for (const letter of commandData.args) { if (letter == ' ') { newText += letter; @@ -634,13 +635,15 @@ const functions = { } if (letter == 'i' || letter == 'I') { newText += 'i'; + lastIsUpper = 0; continue; } if (letter == 'l' || letter == 'L') { newText += 'L'; + lastIsUpper = 1; continue; } - if (Math.random() > 0.5) { + if (lastIsUpper === 0) { newText += letter.toUpperCase(); } else { newText += letter.toLowerCase(); From 10021d6926df8d389aa7d122d9e99772d74b400e Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Sun, 6 Aug 2023 08:58:35 -0400 Subject: [PATCH 12/79] changed HED_REF to main hardcoded --- .github/workflows/production-docker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/production-docker.yml b/.github/workflows/production-docker.yml index db69c5c..9785845 100644 --- a/.github/workflows/production-docker.yml +++ b/.github/workflows/production-docker.yml @@ -22,7 +22,7 @@ jobs: whoami cd /root/nodbot git pull - git checkout $GITHUB_HEAD_REF + git checkout main - name: Build the Docker image run: | cd /root/nodbot From 1bff94e71b37e1c6f86d4e5205528a0aa45d72b2 Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Sun, 6 Aug 2023 09:04:24 -0400 Subject: [PATCH 13/79] Forgot to toggle --- functions.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/functions.js b/functions.js index 65891b1..358d552 100644 --- a/functions.js +++ b/functions.js @@ -645,8 +645,10 @@ const functions = { } if (lastIsUpper === 0) { newText += letter.toUpperCase(); + lastIsUpper = 1; } else { newText += letter.toLowerCase(); + lastIsUpper = 0; } } From 18ef6e56c2eb6258b37d54cd68dd421804df733d Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Sun, 6 Aug 2023 09:14:44 -0400 Subject: [PATCH 14/79] Shouldn't be pushing to main --- .github/workflows/production-docker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/production-docker.yml b/.github/workflows/production-docker.yml index 9785845..6b94711 100644 --- a/.github/workflows/production-docker.yml +++ b/.github/workflows/production-docker.yml @@ -1,7 +1,7 @@ name: NodBot Production Dockerization on: - push: + pull_request: branches: - main From 17a9bd4ea2f6e758f17a2501570348b1c28e5d00 Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Sun, 6 Aug 2023 17:29:17 -0400 Subject: [PATCH 15/79] Restructure /save commands --- package.json | 2 +- slash-commands/save.js | 238 +++++++++++++++++++++++++++++++++++ slash-commands/savegif.js | 93 -------------- slash-commands/savejoint.js | 17 --- slash-commands/savemd.js | 17 --- slash-commands/savepasta.js | 24 ---- slash-commands/savestrain.js | 54 -------- 7 files changed, 239 insertions(+), 206 deletions(-) create mode 100644 slash-commands/save.js delete mode 100644 slash-commands/savegif.js delete mode 100644 slash-commands/savejoint.js delete mode 100644 slash-commands/savemd.js delete mode 100644 slash-commands/savepasta.js delete mode 100644 slash-commands/savestrain.js diff --git a/package.json b/package.json index 05f8e83..55b30c9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "nodbot", - "version": "3.2.0", + "version": "3.2.1", "description": "Nods and Nod Accessories, now with ChatGPT!", "main": "main.js", "dependencies": { diff --git a/slash-commands/save.js b/slash-commands/save.js new file mode 100644 index 0000000..13f5d38 --- /dev/null +++ b/slash-commands/save.js @@ -0,0 +1,238 @@ +const tenor = require('tenorjs').client({ + 'Key': process.env.tenorAPIKey, // https://tenor.com/developer/keyregistration + 'Filter': 'off', // "off", "low", "medium", "high", not case sensitive + 'Locale': 'en_US', + 'MediaFilter': 'minimal', + 'DateFormat': 'D/MM/YYYY - H:mm:ss A', +}); + +const { SlashCommandBuilder } = require('@discordjs/builders'); +const { MessageActionRow, MessageButton } = require('discord.js'); +const fn = require('../functions.js'); +const strings = require('../strings.json'); +const { emoji } = strings; + +module.exports = { + data: new SlashCommandBuilder() + .setName('save') + .setDescription('Save content to Nodbot\'s database.') +// GIF Search + .addSubcommand(subcommand => + subcommand + .setName('gifsearch') + .setDescription('Search Tenor for a GIF.') + .addStringOption(option => + option + .setName('query') + .setDescription('Search Query') + .setRequired(true)) + .addStringOption(option => + option + .setName('name') + .setDescription('What to save the gif as') + .setRequired(true)) + ) +// GIF URL + .addSubcommand(subcommand => + subcommand + .setName('gifurl') + .setDescription('Specify a URL to save.') + .addStringOption(option => + option + .setName('url') + .setDescription('URL Link to the GIF') + .setRequired(true)) + .addStringOption(option => + option + .setName('name') + .setDescription('What to save the gif as') + .setRequired(true)) + ) +// Joint + .addSubcommand(subcommand => + subcommand + .setName('joint') + .setDescription('Roll a joint and stash it in the database.') + .addStringOption(option => + option + .setName('joint-content') + .setDescription('Phrase to save') + .setRequired(true) + ) + ) +// MD + .addSubcommand(subcommand => + subcommand + .setName('md') + .setDescription('Add medical advice to the database.') + .addStringOption(option => + option + .setName('advice-content') + .setDescription('Advice to save') + .setRequired(true) + ) + ) +// Pasta + .addSubcommand(subcommand => + subcommand + .setName('pasta') + .setDescription('Save a copypasta to the database.') + .addStringOption(option => + option + .setName('pasta-name') + .setDescription('Title of the copypasta') + .setRequired(true) + ) + .addStringOption(option => + option + .setName('pasta-content') + .setDescription('Content of the copypasta') + .setRequired(true) + ) + ) +// Strain + .addSubcommand(subcommand => + subcommand + .setName('strain') + .setDescription('Store a new Strain in the database!') + .addStringOption(option => + option + .setName('name') + .setDescription('Name of the Strain') + .setRequired(true)) + .addStringOption(option => + option + .setName('type') + .setDescription('Indica/Sativa/Hybrid') + .setRequired(true) + .addChoices( + { name: "Indica", value: "Indica" }, + { name: "Hybrid", value: "Hybrid" }, + { name: "Sativa", value: "Sativa" } + ) + ) + .addStringOption(option => + option + .setName('effects') + .setDescription('The effects given by the strain') + .setRequired(false)) + .addStringOption(option => + option + .setName('flavor') + .setDescription('Flavor notes') + .setRequired(false)) + .addStringOption(option => + option + .setName('rating') + .setDescription('Number of stars') + .setRequired(false)) + .addStringOption(option => + option + .setName('description') + .setDescription('Description of the strain') + .setRequired(false)) + ), + async execute(interaction) { + await interaction.deferReply({ ephemeral: true }); + try { + // Code Here... + const subcommand = interaction.options.getSubcommand(); + switch (subcommand) { +// GIF Search + case "gifsearch": + // TODO Check on option names + // Previous GIF button + const prevButton = new MessageButton().setCustomId('prevGif').setLabel('Previous GIF').setStyle('SECONDARY').setDisabled(true); + // Confirm GIF Button + const confirmButton = new MessageButton().setCustomId('confirmGif').setLabel('Confirm').setStyle('PRIMARY'); + // Next GIF Button + const nextButton = new MessageButton().setCustomId('nextGif').setLabel('Next GIF').setStyle('SECONDARY'); + // Cancel Button + const cancelButton = new MessageButton().setCustomId('cancelGif').setLabel('Cancel').setStyle('DANGER'); + // Put all the above into an ActionRow to be sent as a component of the reply + const actionRow = new MessageActionRow().addComponents(prevButton, confirmButton, nextButton, cancelButton); + + // Get the query + const query = interaction.options.getString('query'); + strings.temp.gifName = interaction.options.getString('name').toLowerCase(); + + // Search Tenor for the GIF + tenor.Search.Query(query, '10').then(res => { + strings.temp.gifs = []; + strings.temp.gifIndex = 0; + strings.temp.gifLimit = res.length - 1; + strings.temp.gifUserId = interaction.user.id; + + if (res[0] == undefined) { + interaction.editReply('Sorry I was unable to find a GIF of ' + query); + return; + } + for (const row of res) { + strings.temp.gifs.push({ + embed_url: row.media_formats.gif.url, + }); + } + interaction.editReply({ content: strings.temp.gifs[0].embed_url, components: [actionRow], ephemeral: true }); + }); + break; +// GIF URL + case "gifurl": + //TODO Check on option names + const gifData = { + name: interaction.options.getString('name').toLowerCase(), + embed_url: interaction.options.getString('url'), + }; + fn.upload.gif(gifData, interaction.client); + interaction.editReply({ content: `I've saved the GIF as ${gifData.name}.gif`, ephemeral: true }); + fn.download.gifs(interaction.client); + break; +// Joint + case "joint": + //TODO + fn.upload.joint(interaction.options.getString('joint-content'), interaction.client); + interaction.editReply({ content: `The joint has been rolled${emoji.joint}`, ephemeral: true }); + break; +// MD + case "md": + //TODO + fn.upload.medicalAdvice(interaction.options.getString('advice-content'), interaction.client); + interaction.editReply({ content: `The advice has been saved!`, ephemeral: true }); + break; +// Pasta + case "pasta": + //TODO + const pastaData = { + name: interaction.options.getString('pasta-name').toLowerCase(), + content: interaction.options.getString('pasta-content'), + }; + fn.upload.pasta(pastaData, interaction.client); + interaction.editReply({content: `The copypasta has been saved as ${pastaData.name}.pasta`, ephemeral: true }); + break; +// Strain + case "strain": + //TODO + fn.upload.strain(interaction).then(res => { + interaction.editReply({ + content: `The strain information has been saved. (${interaction.options.getString('name')})`, + ephemeral: true + }); + }).catch(err => { + console.log(`E: ${err}`); + interaction.editReply({ + content: 'There was a problem saving the strain.', + ephemeral: true + }); + }); + break; +// Default + default: + + break; + } + } catch (err) { + const errorId = fn.generateErrorId(); + console.error(`${errorId}: err`); + await interaction.editReply(`Sorry, an error has occured. Error ID: ${errorId}`); + } + } +}; \ No newline at end of file diff --git a/slash-commands/savegif.js b/slash-commands/savegif.js deleted file mode 100644 index 27f4778..0000000 --- a/slash-commands/savegif.js +++ /dev/null @@ -1,93 +0,0 @@ -const tenor = require('tenorjs').client({ - 'Key': process.env.tenorAPIKey, // https://tenor.com/developer/keyregistration - 'Filter': 'off', // "off", "low", "medium", "high", not case sensitive - 'Locale': 'en_US', - 'MediaFilter': 'minimal', - 'DateFormat': 'D/MM/YYYY - H:mm:ss A', -}); - -const { SlashCommandBuilder } = require('@discordjs/builders'); -const { MessageActionRow, MessageButton } = require('discord.js'); -const fn = require('../functions.js'); -const strings = require('../strings.json'); - -module.exports = { - data: new SlashCommandBuilder() - .setName('savegif') - .setDescription('Save a GIF to Nodbot\'s database.') - .addSubcommand(subcommand => - subcommand - .setName('searchgif') - .setDescription('Search Tenor for a GIF.') - .addStringOption(option => - option.setName('query') - .setDescription('Search Query') - .setRequired(true)) - .addStringOption(option => - option.setName('name') - .setDescription('What to save the gif as') - .setRequired(true)) - ) - .addSubcommand(subcommand => - subcommand - .setName('enterurl') - .setDescription('Specify a URL to save.') - .addStringOption(option => - option - .setName('url') - .setDescription('URL Link to the GIF') - .setRequired(true)) - .addStringOption(option => - option.setName('name') - .setDescription('What to save the gif as') - .setRequired(true)) - ), - async execute(interaction) { - if (interaction.options.getSubcommand() == 'searchgif') { - // Previous GIF button - const prevButton = new MessageButton().setCustomId('prevGif').setLabel('Previous GIF').setStyle('SECONDARY').setDisabled(true); - // Confirm GIF Button - const confirmButton = new MessageButton().setCustomId('confirmGif').setLabel('Confirm').setStyle('PRIMARY'); - // Next GIF Button - const nextButton = new MessageButton().setCustomId('nextGif').setLabel('Next GIF').setStyle('SECONDARY'); - // Cancel Button - const cancelButton = new MessageButton().setCustomId('cancelGif').setLabel('Cancel').setStyle('DANGER'); - // Put all the above into an ActionRow to be sent as a component of the reply - const actionRow = new MessageActionRow().addComponents(prevButton, confirmButton, nextButton, cancelButton); - - // Get the query - const query = interaction.options.getString('query'); - strings.temp.gifName = interaction.options.getString('name').toLowerCase(); - - // Search Tenor for the GIF - tenor.Search.Query(query, '10').then(res => { - strings.temp.gifs = []; - strings.temp.gifIndex = 0; - strings.temp.gifLimit = res.length - 1; - strings.temp.gifUserId = interaction.user.id; - - if (res[0] == undefined) { - interaction.reply('Sorry I was unable to find a GIF of ' + query); - return; - } - for (const row of res) { - strings.temp.gifs.push({ - embed_url: row.media[0].gif.url, - }); - } - interaction.reply({ content: strings.temp.gifs[0].embed_url, components: [actionRow], ephemeral: true }); - }); - } - - if (interaction.options.getSubcommand() == 'enterurl') { - const gifData = { - name: interaction.options.getString('name'), - embed_url: interaction.options.getString('url'), - }; - fn.upload.gif(gifData, interaction.client); - interaction.reply({ content: `I've saved the GIF as ${gifData.name}.gif`, ephemeral: true }); - fn.download.gifs(interaction.client); - } - - }, -}; \ No newline at end of file diff --git a/slash-commands/savejoint.js b/slash-commands/savejoint.js deleted file mode 100644 index ba48eac..0000000 --- a/slash-commands/savejoint.js +++ /dev/null @@ -1,17 +0,0 @@ -const { SlashCommandBuilder } = require('@discordjs/builders'); -const fn = require('../functions.js'); -const { emoji } = require('../strings.json'); - -module.exports = { - data: new SlashCommandBuilder() - .setName('savejoint') - .setDescription('Save a phrase for /joint!') - .addStringOption(option => - option.setName('joint-content') - .setDescription('What is the phrase?') - .setRequired(true)), - async execute(interaction) { - fn.upload.joint(interaction.options.getString('joint-content'), interaction.client); - interaction.reply({ content: `The joint has been rolled${emoji.joint}`, ephemeral: true }); - }, -}; \ No newline at end of file diff --git a/slash-commands/savemd.js b/slash-commands/savemd.js deleted file mode 100644 index 8391da3..0000000 --- a/slash-commands/savemd.js +++ /dev/null @@ -1,17 +0,0 @@ -const { SlashCommandBuilder } = require('@discordjs/builders'); -const fn = require('../functions.js'); -// const { emoji } = require('../strings.json'); - -module.exports = { - data: new SlashCommandBuilder() - .setName('savemd') - .setDescription('Add medical advice to NodBot\'s Database!') - .addStringOption(option => - option.setName('advice-content') - .setDescription('What is the advice?') - .setRequired(true)), - async execute(interaction) { - fn.upload.medicalAdvice(interaction.options.getString('advice-content'), interaction.client); - interaction.reply({ content: `The advice has been saved!`, ephemeral: true }); - }, -}; \ No newline at end of file diff --git a/slash-commands/savepasta.js b/slash-commands/savepasta.js deleted file mode 100644 index a89da4a..0000000 --- a/slash-commands/savepasta.js +++ /dev/null @@ -1,24 +0,0 @@ -const { SlashCommandBuilder } = require('@discordjs/builders'); -const fn = require('../functions.js'); - -module.exports = { - data: new SlashCommandBuilder() - .setName('savepasta') - .setDescription('Save a copypasta!') - .addStringOption(option => - option.setName('pasta-name') - .setDescription('What should the name of the copypasta be?') - .setRequired(true)) - .addStringOption(option => - option.setName('pasta-content') - .setDescription('What is the content of the copypasta?') - .setRequired(true)), - async execute(interaction) { - const pastaData = { - name: interaction.options.getString('pasta-name'), - content: interaction.options.getString('pasta-content'), - }; - fn.upload.pasta(pastaData, interaction.client); - interaction.reply({content: `The copypasta has been saved as ${pastaData.name}.pasta`, ephemeral: true }); - }, -}; \ No newline at end of file diff --git a/slash-commands/savestrain.js b/slash-commands/savestrain.js deleted file mode 100644 index 3cc90f8..0000000 --- a/slash-commands/savestrain.js +++ /dev/null @@ -1,54 +0,0 @@ -const { SlashCommandBuilder } = require('@discordjs/builders'); -const fn = require('../functions.js'); -const { emoji } = require('../strings.json'); - -// Strain Name | Type | Effects | Flavor | Rating | Description - -module.exports = { - data: new SlashCommandBuilder() - .setName('savestrain') - .setDescription('Store a new Strain in the database!') - .addStringOption(option => - option.setName('name') - .setDescription('Name of the Strain') - .setRequired(true)) - .addStringOption(option => - option.setName('type') - .setDescription('Indica/Sativa/Hybrid') - .setRequired(true) - .addChoices( - { name: "Indica", value: "Indica" }, - { name: "Hybrid", value: "Hybrid" }, - { name: "Sativa", value: "Sativa" } - )) - .addStringOption(option => - option.setName('effects') - .setDescription('The effects given by the strain') - .setRequired(false)) - .addStringOption(option => - option.setName('flavor') - .setDescription('Flavor notes') - .setRequired(false)) - .addStringOption(option => - option.setName('rating') - .setDescription('Number of stars') - .setRequired(false)) - .addStringOption(option => - option.setName('description') - .setDescription('Description of the strain') - .setRequired(false)), - async execute(interaction) { - fn.upload.strain(interaction).then(res => { - interaction.reply({ - content: `The strain information has been saved. (${interaction.options.getString('name')})`, - ephemeral: true - }); - }).catch(err => { - console.log(`E: ${err}`); - interaction.reply({ - content: 'There was a problem saving the strain.', - ephemeral: true - }); - }); - }, -}; \ No newline at end of file From cb834cb7eecb4c2d7aa6b0a088bdf2b303e9fad4 Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Tue, 8 Aug 2023 13:25:07 -0400 Subject: [PATCH 16/79] Classes, Embed.SetAuthor, /gifs, /edit, PARTIAL --- CustomModules/NodBot.js | 15 ++++++ dot-commands/gif.js | 6 +-- functions.js | 65 ++++++++++++++------------ main.js | 51 +++++++++++++++----- slash-commands/edit.js | 101 ++++++++++++++++++++++++++++++++++++++++ slash-commands/gifs.js | 33 +++++++------ slash-commands/save.js | 10 ++-- 7 files changed, 217 insertions(+), 64 deletions(-) create mode 100644 CustomModules/NodBot.js create mode 100644 slash-commands/edit.js diff --git a/CustomModules/NodBot.js b/CustomModules/NodBot.js new file mode 100644 index 0000000..ecb8c53 --- /dev/null +++ b/CustomModules/NodBot.js @@ -0,0 +1,15 @@ +module.exports = { + GifData: class { + constructor() { + this.gifName = ""; + this.gifUrl = ""; + } + setInfo(name, url) { + if ((!name) || (!url)) throw `Expected a name and url, receieved {name: ${name}, url: ${url}}`; + this.name = name; + this.url = url; + + return this; + } + } +} \ No newline at end of file diff --git a/dot-commands/gif.js b/dot-commands/gif.js index c7dedd7..b9f746a 100644 --- a/dot-commands/gif.js +++ b/dot-commands/gif.js @@ -13,7 +13,7 @@ module.exports = { async execute(message, commandData) { // if (message.deletable) message.delete(); const client = message.client; - if (!client.gifs.has(commandData.args)) { + if (!client.gifs.has(commandData.args.toLowerCase())) { if (process.env.isDev) console.log('https://tenor.googleapis.com/v2/search?' + `&q=${commandData.args}` + `&key=${process.env.tenorAPIKey}` + '&limit=1&contentfilter=off'); const q = await axios.get( 'https://tenor.googleapis.com/v2/search?' + @@ -43,11 +43,11 @@ module.exports = { // }).catch(err => console.error(err)); } else { // message.reply(commandData.args + ' requested by ' + message.author.username + '\n' + client.gifs.get(commandData.args).embed_url); - commandData.embed_url = client.gifs.get(commandData.args).embed_url; + const gifData = client.gifs.get(commandData.args.toLowerCase()); // message.reply(fn.embeds.gif(commandData)); // message.channel.send(`> ${commandData.author} - ${commandData.args}.gif`); // message.channel.send(commandData.embed_url); - message.reply(commandData.embed_url); + message.reply(gifData.url); } } } \ No newline at end of file diff --git a/functions.js b/functions.js index 358d552..b02a9bc 100644 --- a/functions.js +++ b/functions.js @@ -45,6 +45,7 @@ const dotCommandFiles = fs.readdirSync('./dot-commands/').filter(file => file.en // MySQL database connection const mysql = require('mysql'); +const { GifData } = require('./CustomModules/NodBot'); const db = new mysql.createPool({ connectionLimit: 10, host: dbHost, @@ -102,12 +103,13 @@ const functions = { if (!client.gifs) client.gifs = new Discord.Collection(); client.gifs.clear(); for (const row of rows) { - const gif = { - id: row.id, - name: row.name, - embed_url: row.embed_url - }; - client.gifs.set(gif.name, gif); + // const gif = { + // id: row.id, + // name: row.name, + // embed_url: row.embed_url + // }; + const gifData = new GifData().setInfo(row.name, row.embed_url); + client.gifs.set(gifData.name, gifData); } if (isDev) console.log('GIFs Collection Built'); }, @@ -215,7 +217,7 @@ const functions = { // Construct the Help Embed const helpEmbed = new Discord.MessageEmbed() .setColor('BLUE') - .setAuthor('Help Page') + .setAuthor({name: 'Help Page'}) .setDescription(strings.help.description) .setThumbnail(strings.urls.avatar); @@ -268,14 +270,14 @@ const functions = { }, gif(commandData) { return { embeds: [new Discord.MessageEmbed() - .setAuthor(`${commandData.args}.${commandData.command}`) + .setAuthor({name: `${commandData.args}.${commandData.command}`}) .setImage(commandData.embed_url) .setTimestamp() .setFooter(commandData.author)]}; }, pasta(commandData) { return { embeds: [ new Discord.MessageEmbed() - .setAuthor(`${commandData.args}.${commandData.command}`) + .setAuthor({name: `${commandData.args}.${commandData.command}`}) .setDescription(commandData.content) .setThumbnail(commandData.iconUrl) .setTimestamp() @@ -284,7 +286,7 @@ const functions = { pastas(commandData) { const pastasArray = []; const pastasEmbed = new Discord.MessageEmbed() - .setAuthor(commandData.command) + .setAuthor({name: commandData.command}) .setTimestamp() .setFooter(commandData.author); @@ -297,32 +299,25 @@ const functions = { return { embeds: [pastasEmbed], ephemeral: true }; }, - gifs(commandData) { - const gifsArray = []; + gifs(commandData, gifList) { const gifsEmbed = new Discord.MessageEmbed() - .setAuthor(commandData.command) + .setAuthor({name: commandData.command}) .setTimestamp() - .setFooter(commandData.author); - - for (const row of commandData.gifs) { - gifsArray.push(`#${row.id} - ${row.name}.gif`); - } - - const gifsString = gifsArray.join('\n'); - gifsEmbed.setDescription(gifsString); + .setFooter(commandData.author) + .setDescription(gifList.join('\n')); return { embeds: [gifsEmbed] }; }, text(commandData) { return { embeds: [new Discord.MessageEmbed() - .setAuthor(commandData.command) + .setAuthor({name: commandData.command}) .setDescription(commandData.content) .setTimestamp() .setFooter(commandData.author)]}; }, requests(commandData) { const requestsEmbed = new Discord.MessageEmbed() - .setAuthor(commandData.command) + .setAuthor({name: commandData.command}) .setTimestamp() .setFooter(commandData.author); @@ -418,7 +413,7 @@ const functions = { }); }, pasta(pastaData, client) { - const query = `INSERT INTO pastas (name, content) VALUES (${db.escape(pastaData.name)},${db.escape(pastaData.content)})`; + const query = `INSERT INTO pastas (name, content) VALUES (${db.escape(pastaData.name)},${db.escape(pastaData.content)}) ON DUPLICATE KEY UPDATE content=${db.escape(pastaData.content)}`; db.query(query, (err, rows, fields) => { if (err) throw err; functions.download.pastas(client); @@ -431,9 +426,9 @@ const functions = { functions.download.joints(client); }); }, - gif(gifData, client) { - const query = `INSERT INTO gifs (name, embed_url) VALUES (${db.escape(gifData.name)}, ${db.escape(gifData.embed_url)})`; - db.query(query, (err, rows, fields) => { + async gif(gifData, client) { + const query = `INSERT INTO gifs (name, embed_url) VALUES (${db.escape(gifData.name)}, ${db.escape(gifData.url)}) ON DUPLICATE KEY UPDATE embed_url=${db.escape(gifData.embed_url)}`; + await db.query(query, (err, rows, fields) => { if (err) throw err; functions.download.gifs(client); }); @@ -487,7 +482,7 @@ const functions = { const description = db.escape(( interaction.options.getString('description') || 'Unknown' )); const flavor = db.escape(( interaction.options.getString('flavor') || 'Unknown' )); const rating = db.escape(( interaction.options.getString('rating') || '3' )); - const strainQuery = `INSERT INTO strains (strain, type, effects, description, flavor, rating) VALUES (${strain}, ${type}, ${effects}, ${description}, ${flavor}, ${rating})`; + const strainQuery = `INSERT INTO strains (strain, type, effects, description, flavor, rating) VALUES (${strain}, ${type}, ${effects}, ${description}, ${flavor}, ${rating}) ON DUPLICATE KEY UPDATE strain=${db.escape(strain)}, type=${db.escape(type)}, effects=${db.escape(effects)}, description=${db.escape(description)}, flavor=${db.escape(flavor)}, rating=${db.escape(rating)}`; console.log(strainQuery); return new Promise((resolve, reject) => { db.query(strainQuery, (err, rows, fields) => { @@ -519,9 +514,9 @@ const functions = { functions.collections.pastas(rows, client); }); }, - gifs(client) { + async gifs(client) { const query = 'SELECT * FROM gifs ORDER BY id ASC'; - db.query(query, (err, rows, fields) => { + await db.query(query, (err, rows, fields) => { if (err) throw err; functions.collections.gifs(rows, client); }); @@ -608,6 +603,16 @@ const functions = { }); } }, + search: { + gifs(query, client) { + const gifSearcher = new FuzzySearch(client.gifs.map(element => element.name)); + return gifSearcher.search(query).slice(0,25); + }, + pastas(query, client) { + const pastaSearcher = new FuzzySearch(client.pastas.map(element => element.name)); + return pastaSearcher.search(query).slice(0,25); + } + }, // Parent-Level functions (miscellaneuous) closeRequest(requestId, interaction) { if (interaction.user.id == ownerId) { diff --git a/main.js b/main.js index 0ee3d91..ed084ef 100644 --- a/main.js +++ b/main.js @@ -27,6 +27,7 @@ const { MessageActionRow, MessageButton } = require('discord.js'); const fn = require('./functions.js'); const config = require('./config.json'); const strings = require('./strings.json'); +const { GifData } = require('./CustomModules/NodBot.js'); const isDev = process.env.isDev; client.once('ready', () => { @@ -108,10 +109,11 @@ client.on('interactionCreate', async interaction => { interaction.update(strings.temp.gifs[newIndex].embed_url); break; case 'confirmGif': - const gifData = { - name: strings.temp.gifName, - embed_url: strings.temp.gifs[strings.temp.gifIndex].embed_url, - }; + // const gifData = { + // name: strings.temp.gifName, + // url: strings.temp.gifs[strings.temp.gifIndex].embed_url, + // }; + const gifData = new GifData().setInfo(strings.temp.gifName, strings.temp.gifs[strings.temp.gifIndex].embed_url); fn.upload.gif(gifData, client); interaction.update({ content: `I've saved the GIF as ${gifData.name}.gif`, components: [] }); fn.download.gifs(interaction.client); @@ -176,14 +178,39 @@ client.on('interactionCreate', async interaction => { // Handle autocomplete requests if (interaction.isAutocomplete()) { - if (interaction.commandName == 'strain') { - const searchString = interaction.options.getFocused(); - const choices = fn.weed.strain.lookup(searchString, interaction.client); - await interaction.respond( - choices.map(choice => ({ name: choice, value: choice })) - ) - } else { - return; + switch (interaction.commandName) { + case 'strain': + const searchString = interaction.options.getFocused(); + const choices = fn.weed.strain.lookup(searchString, interaction.client); + await interaction.respond( + choices.map(choice => ({ name: choice, value: choice })) + ); + break; + case "edit": + //TODO + switch (interaction.options.getSubcommand()) { + case 'gif': + const gifQuery = interaction.options.getFocused(); + const gifChoices = fn.search.gifs(gifQuery, interaction.client); + await interaction.respond( + gifChoices.map(choice => ({ name: choice, value: choice })) + ); + break; + case 'pasta': + const pastaQuery = interaction.options.getFocused(); + const pastaChoices = fn.search.pastas(pastaQuery, interaction.client); + await interaction.respond( + pastaChoices.map(choice => ({ name: choice, value: choice })) + ); + break; + + default: + break; + } + break; + + default: + break; } } }); diff --git a/slash-commands/edit.js b/slash-commands/edit.js new file mode 100644 index 0000000..2c9394c --- /dev/null +++ b/slash-commands/edit.js @@ -0,0 +1,101 @@ +const tenor = require('tenorjs').client({ + 'Key': process.env.tenorAPIKey, // https://tenor.com/developer/keyregistration + 'Filter': 'off', // "off", "low", "medium", "high", not case sensitive + 'Locale': 'en_US', + 'MediaFilter': 'minimal', + 'DateFormat': 'D/MM/YYYY - H:mm:ss A', +}); + +const { SlashCommandBuilder } = require('@discordjs/builders'); +const { MessageActionRow, MessageButton } = require('discord.js'); +const { GifData } = require('../CustomModules/NodBot'); +const fn = require('../functions.js'); +const strings = require('../strings.json'); +const { emoji } = strings; + +module.exports = { + data: new SlashCommandBuilder() + .setName('edit') + .setDescription('Edit content in Nodbot\'s database.') + .addSubcommand(subcommand => + subcommand + .setName('gif') + .setDescription('Edit a GIF URL') + .addStringOption(option => + option + .setName('name') + .setDescription('The name of the GIF to edit') + .setRequired(true) + .setAutocomplete(true) + ) + .addStringOption(option => + option + .setName('url') + .setDescription('The new URL') + .setRequired(true) + ) + ) + .addSubcommand(subcommand => + subcommand + .setName('pasta') + .setDescription('Edit a copypasta\'s content') + .addStringOption(option => + option + .setName('name') + .setDescription('The name of the copypasta') + .setRequired(true) + .setAutocomplete(true) + ) + .addStringOption(option => + option + .setName('content') + .setDescription('The new content of the copypasta') + .setRequired(true) + ) + ), + async execute(interaction) { + await interaction.deferReply({ ephemeral: true }); + try { + // Code Here... + const subcommand = interaction.options.getSubcommand(); + switch (subcommand) { +// GIF + case "gif": + //TODO + await this.editGif(interaction, interaction.options.getString('name'), interaction.options.getString('url')); + break; +// Joint + case "joint": + //TODO + break; +// MD + case "md": + //TODO + break; +// Pasta + case "pasta": + //TODO + break; +// Strain + case "strain": + //TODO + break; + break; +// Default + default: + + break; + } + } catch (err) { + const errorId = fn.generateErrorId(); + console.error(`${errorId}: err`); + await interaction.editReply(`Sorry, an error has occured. Error ID: ${errorId}`); + } + }, + async editGif(interaction, name, url) { + const gifData = new GifData().setInfo(name, url); + await fn.upload.gif(gifData, interaction.client); + await fn.download.gifs(interaction.client); + await interaction.editReply(`I've updated ${gifData.name}.gif`); + } +}; \ No newline at end of file diff --git a/slash-commands/gifs.js b/slash-commands/gifs.js index 934ff86..0409968 100644 --- a/slash-commands/gifs.js +++ b/slash-commands/gifs.js @@ -11,23 +11,26 @@ module.exports = { interaction.reply('For some reason I don\'t have access to the collection of gifs. Sorry about that!'); return; } - const gifsMap = interaction.client.gifs.map(e => { - return { - id: e.id, - name: e.name, - }; + // const gifsMap = interaction.client.gifs.map(e => {e.name, e.url}); + // const commandData = { + // gifs: [], + // command: 'gifs', + // author: interaction.user.tag, + // }; + // for (const row of gifsMap) { + // commandData.gifs.push({ + // id: row.id, + // name: row.name, + // }); + // } + let gifList = []; + interaction.client.gifs.forEach(element => { + gifList.push(`[${element.name}](${element.url})`); }); const commandData = { - gifs: [], - command: 'gifs', - author: interaction.user.tag, + command: "/gifs", + author: interaction.member.displayName }; - for (const row of gifsMap) { - commandData.gifs.push({ - id: row.id, - name: row.name, - }); - } - interaction.reply(fn.embeds.gifs(commandData)); + interaction.reply(fn.embeds.gifs(commandData, gifList)); }, }; \ No newline at end of file diff --git a/slash-commands/save.js b/slash-commands/save.js index 13f5d38..6390e8b 100644 --- a/slash-commands/save.js +++ b/slash-commands/save.js @@ -10,6 +10,7 @@ const { SlashCommandBuilder } = require('@discordjs/builders'); const { MessageActionRow, MessageButton } = require('discord.js'); const fn = require('../functions.js'); const strings = require('../strings.json'); +const { GifData } = require('../CustomModules/NodBot.js'); const { emoji } = strings; module.exports = { @@ -178,10 +179,11 @@ module.exports = { // GIF URL case "gifurl": //TODO Check on option names - const gifData = { - name: interaction.options.getString('name').toLowerCase(), - embed_url: interaction.options.getString('url'), - }; + // const gifData = { + // name: interaction.options.getString('name').toLowerCase(), + // url: interaction.options.getString('url'), + // }; + const gifData = new GifData().setInfo(interaction.options.getString('name').toLowerCase(), interaction.options.getString('url')); fn.upload.gif(gifData, interaction.client); interaction.editReply({ content: `I've saved the GIF as ${gifData.name}.gif`, ephemeral: true }); fn.download.gifs(interaction.client); From f3051ec944e7dbd505cccee4d299dffee44a2c42 Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Tue, 8 Aug 2023 14:34:46 -0400 Subject: [PATCH 17/79] /edit pasta, setFooter, PastaData Classification --- CustomModules/NodBot.js | 51 +++++++++++++++++++++++++++++++++++------ dot-commands/pasta.js | 8 +++---- functions.js | 33 +++++++++++--------------- slash-commands/edit.js | 11 ++++++++- 4 files changed, 71 insertions(+), 32 deletions(-) diff --git a/CustomModules/NodBot.js b/CustomModules/NodBot.js index ecb8c53..2d5ff83 100644 --- a/CustomModules/NodBot.js +++ b/CustomModules/NodBot.js @@ -1,15 +1,52 @@ module.exports = { GifData: class { constructor() { - this.gifName = ""; - this.gifUrl = ""; + this.id = 0; + this.name = ""; + this.url = ""; } - setInfo(name, url) { - if ((!name) || (!url)) throw `Expected a name and url, receieved {name: ${name}, url: ${url}}`; - this.name = name; - this.url = url; - return this; + // Initial GifData configuration + // Can also be used to update the data piecemeal + setInfo(name, url, id) { + // Check for existing or incoming name + if ((this.name === "") && (typeof name !== 'string')) throw `Error: This Gif doesn't have existing name, and no name is going to be set.`; + // Check for existing content or incoming content + if ((this.url === "") && (typeof url !== 'string')) throw `Error: This Gif doesn't have existing url, and no url is going to be set.`; + + // Property is set if the variable is the right type, + // otherwise it keeps the existing property + this.id = typeof id === 'number' ? id : this.id; + this.name = typeof name === 'string' ? name : this.name; + this.url = typeof url === 'string' ? url : this.url; + + return this; // For chaining + } + }, + PastaData: class { + constructor() { + this.id = 0; + this.name = ""; + this.content = ""; + this.iconUrl = ""; + } + + // Initial PastaData configuration + // Can also be used to update the data piecemeal + setInfo(name, content, iconUrl, id) { + // Check for existing or incoming name + if ((this.name === "") && (typeof name !== 'string')) throw `Error: This Pasta doesn't have existing name, and no name is going to be set.`; + // Check for existing content or incoming content + if ((this.content === "") && (typeof content !== 'string')) throw `Error: This Pasta doesn't have existing content, and no content is going to be set.`; + + // Property is set if the variable is the right type, + // otherwise it keeps the existing property + this.id = typeof id === 'number' ? id : this.id; + this.name = typeof name === 'string' ? name : this.name; + this.content = typeof content === 'string' ? content : this.content; + this.iconUrl = typeof iconUrl === 'string' ? iconUrl : this.iconUrl; + + return this; // For chaining } } } \ No newline at end of file diff --git a/dot-commands/pasta.js b/dot-commands/pasta.js index 247cf96..357f8ac 100644 --- a/dot-commands/pasta.js +++ b/dot-commands/pasta.js @@ -6,14 +6,12 @@ module.exports = { usage: '.pasta', execute(message, commandData) { const client = message.client; - let replyBody = ''; - let iconUrl; + let pastaData; if (!client.pastas.has(commandData.args)) { commandData.content = 'Sorry I couldn\'t find that pasta.'; } else { - commandData.content = client.pastas.get(commandData.args).content; - commandData.iconUrl = client.pastas.get(commandData.args).iconUrl; + pastaData = client.pastas.get(commandData.args); } - message.reply(fn.embeds.pasta(commandData)); + message.reply(fn.embeds.pasta(commandData, pastaData)); } } \ No newline at end of file diff --git a/functions.js b/functions.js index b02a9bc..b3a571e 100644 --- a/functions.js +++ b/functions.js @@ -45,7 +45,7 @@ const dotCommandFiles = fs.readdirSync('./dot-commands/').filter(file => file.en // MySQL database connection const mysql = require('mysql'); -const { GifData } = require('./CustomModules/NodBot'); +const { GifData, PastaData } = require('./CustomModules/NodBot'); const db = new mysql.createPool({ connectionLimit: 10, host: dbHost, @@ -129,13 +129,8 @@ const functions = { if (!client.pastas) client.pastas = new Discord.Collection(); client.pastas.clear(); for (const row of rows) { - const pasta = { - id: row.id, - name: row.name, - content: row.content, - iconUrl: row.iconurl, - }; - client.pastas.set(pasta.name, pasta); + const pastaData = new PastaData().setInfo(row.name, row.content, row.iconurl, row.id); + client.pastas.set(pastaData.name, pastaData); } if (isDev) console.log('Pastas Collection Built'); }, @@ -183,7 +178,7 @@ const functions = { const commandData = {}; // Split the message content at the final instance of a period const finalPeriod = message.content.lastIndexOf('.'); - if(isDev) console.log(message.content); + // if(isDev) console.log(message.content); // If the final period is the last character, or doesn't exist if (finalPeriod < 0) { if (isDev) console.log(finalPeriod); @@ -195,7 +190,7 @@ const functions = { commandData.args = message.content.slice(0,finalPeriod).toLowerCase(); // Get the last part of the message, everything after the final period commandData.command = message.content.slice(finalPeriod).replace('.','').toLowerCase(); - commandData.author = `${message.author.username}#${message.author.discriminator}`; + commandData.author = `${message.author.username}`; return this.checkCommand(commandData); }, checkCommand(commandData) { @@ -273,22 +268,22 @@ const functions = { .setAuthor({name: `${commandData.args}.${commandData.command}`}) .setImage(commandData.embed_url) .setTimestamp() - .setFooter(commandData.author)]}; + .setFooter({text: commandData.author})]}; }, - pasta(commandData) { + pasta(commandData, pastaData) { return { embeds: [ new Discord.MessageEmbed() .setAuthor({name: `${commandData.args}.${commandData.command}`}) - .setDescription(commandData.content) - .setThumbnail(commandData.iconUrl) + .setDescription(pastaData.content) + .setThumbnail(pastaData.iconUrl) .setTimestamp() - .setFooter(commandData.author)]}; + .setFooter({text: commandData.author})]}; }, pastas(commandData) { const pastasArray = []; const pastasEmbed = new Discord.MessageEmbed() .setAuthor({name: commandData.command}) .setTimestamp() - .setFooter(commandData.author); + .setFooter({text: commandData.author}); for (const row of commandData.pastas) { pastasArray.push(`#${row.id} - ${row.name}.pasta`); @@ -303,7 +298,7 @@ const functions = { const gifsEmbed = new Discord.MessageEmbed() .setAuthor({name: commandData.command}) .setTimestamp() - .setFooter(commandData.author) + .setFooter({text: commandData.author}) .setDescription(gifList.join('\n')); return { embeds: [gifsEmbed] }; @@ -313,13 +308,13 @@ const functions = { .setAuthor({name: commandData.command}) .setDescription(commandData.content) .setTimestamp() - .setFooter(commandData.author)]}; + .setFooter({text: commandData.author})]}; }, requests(commandData) { const requestsEmbed = new Discord.MessageEmbed() .setAuthor({name: commandData.command}) .setTimestamp() - .setFooter(commandData.author); + .setFooter({text: commandData.author}); const requestsArray = []; diff --git a/slash-commands/edit.js b/slash-commands/edit.js index 2c9394c..975e933 100644 --- a/slash-commands/edit.js +++ b/slash-commands/edit.js @@ -8,7 +8,7 @@ const tenor = require('tenorjs').client({ const { SlashCommandBuilder } = require('@discordjs/builders'); const { MessageActionRow, MessageButton } = require('discord.js'); -const { GifData } = require('../CustomModules/NodBot'); +const { GifData, PastaData } = require('../CustomModules/NodBot'); const fn = require('../functions.js'); const strings = require('../strings.json'); const { emoji } = strings; @@ -17,6 +17,7 @@ module.exports = { data: new SlashCommandBuilder() .setName('edit') .setDescription('Edit content in Nodbot\'s database.') +// GIF .addSubcommand(subcommand => subcommand .setName('gif') @@ -35,6 +36,7 @@ module.exports = { .setRequired(true) ) ) +// Pasta .addSubcommand(subcommand => subcommand .setName('pasta') @@ -75,6 +77,7 @@ module.exports = { // Pasta case "pasta": //TODO + await this.editPasta(interaction, interaction.options.getString('name'), interaction.options.getString('content')); break; // Strain case "strain": @@ -97,5 +100,11 @@ module.exports = { await fn.upload.gif(gifData, interaction.client); await fn.download.gifs(interaction.client); await interaction.editReply(`I've updated ${gifData.name}.gif`); + }, + async editPasta(interaction, name, content) { + const pastaData = new PastaData().setInfo(name, content); + await fn.upload.pasta(pastaData, interaction.client); + await fn.download.gifs(interaction.client); + await interaction.editReply(`I've updated ${name}.pasta`); } }; \ No newline at end of file From 6e062ffef2b5672ea5ef7ed1a4998e61b92ca426 Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Tue, 8 Aug 2023 14:39:32 -0400 Subject: [PATCH 18/79] Use Head Ref for main PRs --- .github/workflows/production-docker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/production-docker.yml b/.github/workflows/production-docker.yml index 6b94711..d4e5c6b 100644 --- a/.github/workflows/production-docker.yml +++ b/.github/workflows/production-docker.yml @@ -22,7 +22,7 @@ jobs: whoami cd /root/nodbot git pull - git checkout main + git checkout $GITHUB_HEAD_REF - name: Build the Docker image run: | cd /root/nodbot From b28e193b55777879a20030e4f0ce5c50c879ecf4 Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Tue, 8 Aug 2023 14:44:59 -0400 Subject: [PATCH 19/79] Update to use Node 18 LTS --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 7b75fef..e7e0027 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM node:16 +FROM node:18 RUN mkdir -p /usr/src/app WORKDIR /usr/src/app From c562c06925aafb980f692ea51908160b9db55c46 Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Tue, 8 Aug 2023 15:06:29 -0400 Subject: [PATCH 20/79] Fix incorrect insert statement --- functions.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/functions.js b/functions.js index b3a571e..6b53169 100644 --- a/functions.js +++ b/functions.js @@ -422,7 +422,7 @@ const functions = { }); }, async gif(gifData, client) { - const query = `INSERT INTO gifs (name, embed_url) VALUES (${db.escape(gifData.name)}, ${db.escape(gifData.url)}) ON DUPLICATE KEY UPDATE embed_url=${db.escape(gifData.embed_url)}`; + const query = `INSERT INTO gifs (name, embed_url) VALUES (${db.escape(gifData.name)}, ${db.escape(gifData.url)}) ON DUPLICATE KEY UPDATE embed_url=${db.escape(gifData.url)}`; await db.query(query, (err, rows, fields) => { if (err) throw err; functions.download.gifs(client); From f995d9a6432bef913cb408d7fb6ed8b1837141df Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Wed, 18 Oct 2023 17:33:03 -0400 Subject: [PATCH 21/79] Upgrade to gpt-3.5-turbo --- functions.js | 33 +++++++++++---------------------- package.json | 2 +- slash-commands/chat.js | 8 +++++--- strings.json | 7 +++++++ 4 files changed, 24 insertions(+), 26 deletions(-) diff --git a/functions.js b/functions.js index 6b53169..7cce43d 100644 --- a/functions.js +++ b/functions.js @@ -22,20 +22,8 @@ const Discord = require('discord.js'); const FuzzySearch = require('fuzzy-search'); // OpenAI -const { Configuration, OpenAIApi } = require("openai"); - -const configuration = new Configuration({ - apiKey: process.env.OPENAI_API_KEY, -}); -const openai = new OpenAIApi(configuration); -async function openAIStatus(o) { - const response = await o.listModels(); - const models = response.data.data; - models.forEach(e => { - console.log(`Model ID: ${e.id}`); - }); -}; -openAIStatus(openai); +const OpenAI = require("openai"); +const openai = new OpenAI(); // Various imports from other files const config = require('./config.json'); @@ -379,9 +367,9 @@ const functions = { }, gpt(prompt, response, usage) { const gptEmbed = new Discord.MessageEmbed() - .setAuthor({ name: "NodBot powered by GPT-3", iconURL: "https://assets.vfsh.dev/openai-logos/PNGs/openai-logomark.png" }) + .setAuthor({ name: "NodBot powered by GPT-3.5", iconURL: "https://assets.vfsh.dev/openai-logos/PNGs/openai-logomark.png" }) .setDescription(`**Prompt**\n${prompt}\n\n**Response**\n${response}`) - .setFooter({ text: `This prompt used ${usage.tokens} tokens for a cost of ${usage.usdc}¢` }) + .setFooter({ text: `This prompt used ${usage.tokens} tokens for a cost of ${usage.usdc}¢. Generated using ${strings.ai.chatModel}` }) return { embeds: [gptEmbed] }; }, generatingResponse() { @@ -570,16 +558,17 @@ const functions = { openAI: { chatPrompt(userPrompt) { return new Promise(async (resolve, reject) => { - const response = await openai.createCompletion({ - model: 'text-davinci-003', - prompt: userPrompt, - temperature: 0.7, - max_tokens: 250 + const response = await openai.chat.completions.create({ + messages: [{ + role: 'user', + content: userPrompt + }], + model: strings.ai.chatModel }).catch(e => { reject(e); return null; }); - resolve(response.data); + resolve(response); }); }, imagePrompt(userPrompt, size, userId) { diff --git a/package.json b/package.json index 55b30c9..3ec6382 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "dotenv": "^10.0.0", "fuzzy-search": "^3.2.1", "mysql": "^2.18.1", - "openai": "^3.2.1", + "openai": "^4.12.0", "tenorjs": "^1.0.10" }, "engines": { diff --git a/slash-commands/chat.js b/slash-commands/chat.js index efeaad7..2c9ba34 100644 --- a/slash-commands/chat.js +++ b/slash-commands/chat.js @@ -1,5 +1,6 @@ const { SlashCommandBuilder } = require('@discordjs/builders'); const fn = require('../functions.js'); +const strings = require('../strings.json'); module.exports = { data: new SlashCommandBuilder() @@ -15,13 +16,14 @@ module.exports = { await interaction.editReply(fn.embeds.generatingResponse()); const userPrompt = interaction.options.getString("prompt"); const response = await fn.openAI.chatPrompt(userPrompt).catch(e => console.error(e)); - const responseText = response.choices[0].text; + const responseText = response.choices[0].message.content; const usage = { tokens: response.usage.total_tokens, - usdc: response.usage.total_tokens * ( 0.2 / 1000 ) // 0.2¢ per 1000 tokens or 0.0002¢ per token. + usdc: (response.usage.prompt_tokens * (strings.ai.chatPromptCentsPer / strings.ai.chatPromptUnits)) + + (response.usage.completion_tokens * (strings.ai.chatResCentsPer / strings.ai.chatResUnits)) }; const gptEmbed = fn.embeds.gpt(userPrompt, responseText, usage); await interaction.editReply(gptEmbed); - fn.upload.openai(interaction.user.id, userPrompt, "gpt-3.5-turbo", usage.tokens, usage.usdc); + fn.upload.openai(interaction.user.id, userPrompt, strings.ai.chatModel, usage.tokens, usage.usdc); }, }; \ No newline at end of file diff --git a/strings.json b/strings.json index b82b6db..94ee7cf 100644 --- a/strings.json +++ b/strings.json @@ -32,5 +32,12 @@ "1024x1024": 2.0 } }, + "ai": { + "chatModel": "gpt-3.5-turbo", + "chatPromptCentsPer": 0.15, + "chatPromptUnits": 1000, + "chatResCentsPer": 0.2, + "chatResUnits": 1000 + }, "temp": {} } \ No newline at end of file From 82f65a800ca5da4c9da9a731d523595535520a47 Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Wed, 13 Dec 2023 16:49:48 -0500 Subject: [PATCH 22/79] bugfixes --- dot-commands/pasta.js | 4 +++- functions.js | 7 ++++--- slash-commands/save.js | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/dot-commands/pasta.js b/dot-commands/pasta.js index 357f8ac..da202ef 100644 --- a/dot-commands/pasta.js +++ b/dot-commands/pasta.js @@ -8,7 +8,9 @@ module.exports = { const client = message.client; let pastaData; if (!client.pastas.has(commandData.args)) { - commandData.content = 'Sorry I couldn\'t find that pasta.'; + pastaData = { + content: "Sorry, I couldn't find that pasta." + }; } else { pastaData = client.pastas.get(commandData.args); } diff --git a/functions.js b/functions.js index 7cce43d..101b86e 100644 --- a/functions.js +++ b/functions.js @@ -262,7 +262,7 @@ const functions = { return { embeds: [ new Discord.MessageEmbed() .setAuthor({name: `${commandData.args}.${commandData.command}`}) .setDescription(pastaData.content) - .setThumbnail(pastaData.iconUrl) + .setThumbnail("https://assets.vfsh.dev/shednod.png") .setTimestamp() .setFooter({text: commandData.author})]}; }, @@ -395,12 +395,13 @@ const functions = { functions.download.requests(client); }); }, - pasta(pastaData, client) { + async pasta(pastaData, client) { const query = `INSERT INTO pastas (name, content) VALUES (${db.escape(pastaData.name)},${db.escape(pastaData.content)}) ON DUPLICATE KEY UPDATE content=${db.escape(pastaData.content)}`; - db.query(query, (err, rows, fields) => { + await db.query(query, (err, rows, fields) => { if (err) throw err; functions.download.pastas(client); }); + return; }, joint(content, client) { const query = `INSERT INTO joints (content) VALUES (${db.escape(content)})`; diff --git a/slash-commands/save.js b/slash-commands/save.js index 6390e8b..b47b05d 100644 --- a/slash-commands/save.js +++ b/slash-commands/save.js @@ -207,7 +207,7 @@ module.exports = { name: interaction.options.getString('pasta-name').toLowerCase(), content: interaction.options.getString('pasta-content'), }; - fn.upload.pasta(pastaData, interaction.client); + await fn.upload.pasta(pastaData, interaction.client); interaction.editReply({content: `The copypasta has been saved as ${pastaData.name}.pasta`, ephemeral: true }); break; // Strain From 97b4136b6465d7e45f42896c27a50a7b9377ade3 Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Thu, 14 Dec 2023 10:43:40 -0500 Subject: [PATCH 23/79] Fix joint randomization and add more aliases --- config.json | 3 ++- dot-commands/joint.js | 20 ++++++++++++++++++-- functions.js | 7 ++++++- main.js | 4 ++++ 4 files changed, 30 insertions(+), 4 deletions(-) diff --git a/config.json b/config.json index b9087cf..467e255 100644 --- a/config.json +++ b/config.json @@ -1,4 +1,5 @@ { "guildId": "868542949737246730", - "validCommands": [] + "validCommands": [], + "roaches": [] } \ No newline at end of file diff --git a/dot-commands/joint.js b/dot-commands/joint.js index 2ce3202..939a5e1 100644 --- a/dot-commands/joint.js +++ b/dot-commands/joint.js @@ -5,13 +5,29 @@ module.exports = { name: 'joint', description: 'Send a random weed-themed phrase.', usage: '.joint', - alias: ['bong', 'blunt', 'bowl', 'pipe'], + alias: ['bong', 'blunt', 'bowl', 'pipe', 'dab', 'vape', 'dabs', 'shatter', 'edible', 'edibles', 'doobie', 'spliff', 'gummy', 'gummies', 'hash', 'toke', 'big doinks'], execute(message, commandData) { let joints = []; for (const entry of message.client.joints.map(joint => joint.content)) { joints.push(entry); } - const randIndex = Math.floor(Math.random() * joints.length); + let randIndex = Math.floor(Math.random() * joints.length); + let joint = joints[randIndex]; + + // Check if the joint has already been smoked + while (message.client.roaches.has(joint)) { + randIndex = Math.floor(Math.random() * joints.length); + joint = joints[randIndex]; + } + // Send the joint message.reply(`${joints[randIndex]} ${emoji.joint}`); + // Check how full the roach collection is + if (message.client.roaches.size / joints.length >= 0.85) { + // If the roach collection is 85% of the joints collection + // Empty it out + message.client.roaches.clear(); + } + // Add the joint to the roach collection + message.client.roaches.set(joint, "baked"); } } \ No newline at end of file diff --git a/functions.js b/functions.js index 101b86e..870c942 100644 --- a/functions.js +++ b/functions.js @@ -149,7 +149,7 @@ const functions = { if (isDev) console.log('Strains Collection Built'); }, medicalAdvice(rows, client) { - if (!client.medicalAdviceCol) client.medicalAdviceColl = new Discord.Collection(); + if (!client.medicalAdviceColl) client.medicalAdviceColl = new Discord.Collection(); client.medicalAdviceColl.clear(); for (const row of rows) { const medicalAdvice = { @@ -160,6 +160,11 @@ const functions = { } if (isDev) console.log('Medical Advice Collection Built'); }, + roaches(client) { + if (!client.roaches) client.roaches = new Discord.Collection(); + client.roaches.clear(); + if (isDev) console.log('Medical Advice Collection Built'); + } }, dot: { getCommandData(message) { diff --git a/main.js b/main.js index ed084ef..584a89c 100644 --- a/main.js +++ b/main.js @@ -34,6 +34,7 @@ client.once('ready', () => { fn.collections.slashCommands(client); fn.collections.dotCommands(client); fn.collections.setvalidCommands(client); + fn.collections.roaches(client); fn.download.gifs(client); fn.download.pastas(client); fn.download.joints(client); @@ -222,8 +223,11 @@ client.on('messageCreate', message => { // Wildcard Responses, will respond if any message contains the trigger word(s), excluding self-messages const lowerContent = message.content.toLowerCase(); + // big + doinks if (lowerContent.includes('big') && lowerContent.includes('doinks')) message.reply('gang.'); + // ligma if (lowerContent.includes('ligma')) message.reply('ligma balls, goteem'); + // frfr, fr fr , bussin, ong if (lowerContent.includes('frfr') || lowerContent.includes('fr fr') || lowerContent.includes('bussin') || lowerContent.includes(' ong') || lowerContent.startsWith('ong')) { const randIndex = Math.floor(Math.random() * strings.capbacks.length); message.reply(strings.capbacks[randIndex]); From 15d39e33816462ceb7e9b183a661b69b355afc1a Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Thu, 14 Dec 2023 10:54:05 -0500 Subject: [PATCH 24/79] commmenting --- dot-commands/joint.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dot-commands/joint.js b/dot-commands/joint.js index 939a5e1..9abc9d1 100644 --- a/dot-commands/joint.js +++ b/dot-commands/joint.js @@ -8,14 +8,18 @@ module.exports = { alias: ['bong', 'blunt', 'bowl', 'pipe', 'dab', 'vape', 'dabs', 'shatter', 'edible', 'edibles', 'doobie', 'spliff', 'gummy', 'gummies', 'hash', 'toke', 'big doinks'], execute(message, commandData) { let joints = []; + // Create a simple array of the joint texts for (const entry of message.client.joints.map(joint => joint.content)) { joints.push(entry); } + // Generate a random number between 0 and the length of the joints array let randIndex = Math.floor(Math.random() * joints.length); + // Grab the joint text from the array let joint = joints[randIndex]; // Check if the joint has already been smoked while (message.client.roaches.has(joint)) { + // Regenerate a random number and recheck randIndex = Math.floor(Math.random() * joints.length); joint = joints[randIndex]; } From d61ffbaaf750d98922a220a751c99a32cb02e694 Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Mon, 1 Jan 2024 15:42:17 -0500 Subject: [PATCH 25/79] Remove chat and dalle commands --- slash-commands/chat.js | 29 ----------------------------- slash-commands/dalle.js | 40 ---------------------------------------- 2 files changed, 69 deletions(-) delete mode 100644 slash-commands/chat.js delete mode 100644 slash-commands/dalle.js diff --git a/slash-commands/chat.js b/slash-commands/chat.js deleted file mode 100644 index 2c9ba34..0000000 --- a/slash-commands/chat.js +++ /dev/null @@ -1,29 +0,0 @@ -const { SlashCommandBuilder } = require('@discordjs/builders'); -const fn = require('../functions.js'); -const strings = require('../strings.json'); - -module.exports = { - data: new SlashCommandBuilder() - .setName('chat') - .setDescription('Send a message to ChatGPT') - .addStringOption(o => - o.setName("prompt") - .setDescription("Prompt to send to ChatGPT") - .setRequired(true) - ), - async execute(interaction) { - await interaction.deferReply(); - await interaction.editReply(fn.embeds.generatingResponse()); - const userPrompt = interaction.options.getString("prompt"); - const response = await fn.openAI.chatPrompt(userPrompt).catch(e => console.error(e)); - const responseText = response.choices[0].message.content; - const usage = { - tokens: response.usage.total_tokens, - usdc: (response.usage.prompt_tokens * (strings.ai.chatPromptCentsPer / strings.ai.chatPromptUnits)) + - (response.usage.completion_tokens * (strings.ai.chatResCentsPer / strings.ai.chatResUnits)) - }; - const gptEmbed = fn.embeds.gpt(userPrompt, responseText, usage); - await interaction.editReply(gptEmbed); - fn.upload.openai(interaction.user.id, userPrompt, strings.ai.chatModel, usage.tokens, usage.usdc); - }, -}; \ No newline at end of file diff --git a/slash-commands/dalle.js b/slash-commands/dalle.js deleted file mode 100644 index 029b066..0000000 --- a/slash-commands/dalle.js +++ /dev/null @@ -1,40 +0,0 @@ -const { SlashCommandBuilder } = require('@discordjs/builders'); -const fn = require('../functions.js'); -const strings = require("../strings.json"); - -module.exports = { - data: new SlashCommandBuilder() - .setName('dalle') - .setDescription('Generate an image with DALL-e') - .addStringOption(o => - o.setName("prompt") - .setDescription("Prompt to send to DALL-e") - .setRequired(true) - ) - .addStringOption(o => - o.setName("size") - .setDescription("1024x1024, 512x512, 256x256") - .setRequired(false) - .addChoices( - { name: "1024x1024 (2¢)", value: "1024x1024" }, - { name: "512x512 (1.8¢)", value: "512x512" }, - { name: "256x256 (1.6¢)", value: "256x256" } - )), - async execute(interaction) { - try { - await interaction.deferReply(); - await interaction.editReply(fn.embeds.generatingResponse()); - const userPrompt = interaction.options.getString("prompt"); - const size = interaction.options.getString("size") ? interaction.options.getString("size") : "512x512"; - - const imageUrl = await fn.openAI.imagePrompt(userPrompt, size); - const dalleEmbed = fn.embeds.dalle(userPrompt, imageUrl, size); - await interaction.editReply(dalleEmbed); - fn.upload.openai(interaction.user.id, userPrompt, "dalle", 0, strings.costs.dalle[size]); - } catch (err) { - const errorId = fn.generateErrorId(); - console.error(`${errorId}: ${err}`); - await interaction.editReply(`An error has occured. Error ID: ${errorId}\n${err}`); - } - }, -}; \ No newline at end of file From 545756b76217ef83ab30c4dc2ab8bfcf5ff5a7b3 Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Mon, 1 Jan 2024 15:44:55 -0500 Subject: [PATCH 26/79] Fix log overwriting error --- Dockerfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index e7e0027..51b2ca5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,4 +5,5 @@ WORKDIR /usr/src/app COPY package.json ./ RUN npm install COPY . . -CMD ["/bin/sh", "-c", "node main.js 2> /logs/nodbot.error 1> /logs/nodbot.log"] \ No newline at end of file +# CMD ["/bin/sh", "-c", "node main.js 2> /logs/nodbot.error 1> /logs/nodbot.log"] +CMD ["/bin/sh", "-c", "node src/main.js 2> /logs/$(date +%Y-%m-%d_%H-%M-%S)-error.txt 1> /logs/$(date +%Y-%m-%d_%H-%M-%S)-status.txt"] \ No newline at end of file From 3f5cc0a9ffa69eae1faf7ad3bc90f792e79d4171 Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Mon, 1 Jan 2024 15:47:14 -0500 Subject: [PATCH 27/79] Fix exec dir --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 51b2ca5..b10bc75 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,4 +6,4 @@ COPY package.json ./ RUN npm install COPY . . # CMD ["/bin/sh", "-c", "node main.js 2> /logs/nodbot.error 1> /logs/nodbot.log"] -CMD ["/bin/sh", "-c", "node src/main.js 2> /logs/$(date +%Y-%m-%d_%H-%M-%S)-error.txt 1> /logs/$(date +%Y-%m-%d_%H-%M-%S)-status.txt"] \ No newline at end of file +CMD ["/bin/sh", "-c", "node main.js 2> /logs/$(date +%Y-%m-%d_%H-%M-%S)-error.txt 1> /logs/$(date +%Y-%m-%d_%H-%M-%S)-status.txt"] \ No newline at end of file From 2ea94092db5b42cdbdfe0631586f93c444be68e0 Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Fri, 14 Jun 2024 14:43:06 -0400 Subject: [PATCH 28/79] Ignore Mac BS --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 138619b..fcfa662 100644 --- a/.gitignore +++ b/.gitignore @@ -114,3 +114,4 @@ dist # TernJS port file .tern-port +.DS_Store From ae9ce308b2a4ac7b750e42dbd8a328ceed661040 Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Fri, 14 Jun 2024 14:43:23 -0400 Subject: [PATCH 29/79] Ignore Mac BS --- .DS_Store | Bin 6148 -> 6148 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/.DS_Store b/.DS_Store index 5008ddfcf53c02e82d7eee2e57c38e5672ef89f6..f388235cbc75a06861b27741a6e6016b0f7ddc09 100644 GIT binary patch literal 6148 zcmeHKO;5r=5S`VkfFI#tqR0LLO-MYO3gzg*5bp{YG-)jfka+CLpCNz37!M}iyy(%t zW8$0Lg?6bFE~q3s$?jWbXLes-+8vgNM0L=v5S59jfX3*Q(EVUM&n;ss+OrE3yhhNe zG+I&E%|u#B>}314CO`BncYzMYu!?cDk9 zb?R(bM<&t6XkWUf0X2=?Y3(T+k>+rA_fXRuCe{g~gvs^6w)dB zHhu?mMLm;Sk@@FDr+FUVk9p>1B%J5VF!}TOOPh+f59v$f96#(eKEe&H?i-0aWfS$%!Av`dlQh_Q} z=qrX$>F~Qc&eIqxROuw-&R9q9Ec6XU$lc+0WjHP8$*j2B-YT$21y7A>G%Id zQm|`V1*`&ptblO*hF=8*j1|HI PvwsAn47Rfh{Hg-qJd?!^ delta 65 zcmZoMXfc=|#>AjHF;Q%yo+1YW5HK<@2y7PQ5M$X`FpGIJI|n}pP#!4ooq009h$187 SWK$94$^JYXn`1;)FarR`U=BS1 From 928f12fe019cfa41c283c6cadb5a797a464e8647 Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Fri, 14 Jun 2024 20:30:34 -0400 Subject: [PATCH 30/79] Versioning --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 55b30c9..3b73fb7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "nodbot", - "version": "3.2.1", + "version": "3.2.2", "description": "Nods and Nod Accessories, now with ChatGPT!", "main": "main.js", "dependencies": { From caefe0e228317fb87c1500a0056b3e6fedf4367f Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Fri, 14 Jun 2024 20:34:51 -0400 Subject: [PATCH 31/79] Fix silly replace method for getting command --- functions.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/functions.js b/functions.js index 6b53169..0d87691 100644 --- a/functions.js +++ b/functions.js @@ -189,7 +189,7 @@ const functions = { // Get the first part of the message, everything leading up to the final period commandData.args = message.content.slice(0,finalPeriod).toLowerCase(); // Get the last part of the message, everything after the final period - commandData.command = message.content.slice(finalPeriod).replace('.','').toLowerCase(); + commandData.command = message.content.slice(finalPeriod + 1).toLowerCase(); commandData.author = `${message.author.username}`; return this.checkCommand(commandData); }, From 0106983a5f122bd488cf68df270f16fdd2d5d143 Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Fri, 14 Jun 2024 21:38:36 -0400 Subject: [PATCH 32/79] Fixed how replies work with .sb --- dot-commands/spongebob.js | 37 +++++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/dot-commands/spongebob.js b/dot-commands/spongebob.js index f886a27..38f5bc0 100644 --- a/dot-commands/spongebob.js +++ b/dot-commands/spongebob.js @@ -10,20 +10,33 @@ module.exports = { // message.reply(fn.spongebob(commandData)).then(() => { // message.delete(); // }); - if (message.reference != undefined) { - const repliedMessageId = message.reference.messageId; - message.channel.messages.fetch(repliedMessageId) - .then(repliedMessage => { - repliedMessage.reply(fn.spongebob({ args: repliedMessage.content })).then(() => { - if (message.deletable) message.delete(); + if (message.reference != undefined) { // message.reference is undefined if the message isn't a reply to another message + if (commandData.args !== "") { // If the replying message isn't just .sb + const repliedMessageId = message.reference.messageId; // grab the message Id of the replied-to msg + message.channel.messages.fetch(repliedMessageId) // Fetch the message because with our luck it isn't in the cache + .then(repliedMessage => { + repliedMessage.reply(fn.spongebob({ args: commandData.args })).then(() => { // Use the pre-command text of the replying message to sb-ify + if (message.deletable) message.delete(); // If the initiating message is deletable, delete it. + }); + }) + .catch(err => { + console.error(err); }); - }) - .catch(err => { - console.error(err); - }); - } else { + } else { // We're working with a basic ".sb" and can proceed as we did before... + const repliedMessageId = message.reference.messageId; // grab the message Id of the replied-to msg + message.channel.messages.fetch(repliedMessageId) // Fetch the message because with our luck it isn't in the cache + .then(repliedMessage => { + repliedMessage.reply(fn.spongebob({ args: repliedMessage.content })).then(() => { + if (message.deletable) message.delete(); + }); + }) + .catch(err => { + console.error(err); + }); + } + } else { // The message isn't a reply, so just sb it like we did from the very beginning message.channel.send(fn.spongebob(commandData)).then(() => { - if (message.deletable) message.delete(); + if (message.deletable) message.delete(); // If the initiating message is deletable, delete it. }); } } From d1e2152de96dc870daeedd00403fd102d6f75a8e Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Fri, 14 Jun 2024 22:06:54 -0400 Subject: [PATCH 33/79] Disabled OpenAI init --- functions.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/functions.js b/functions.js index 98ad506..fdb1492 100644 --- a/functions.js +++ b/functions.js @@ -22,8 +22,8 @@ const Discord = require('discord.js'); const FuzzySearch = require('fuzzy-search'); // OpenAI -const OpenAI = require("openai"); -const openai = new OpenAI(); +// const OpenAI = require("openai"); +// const openai = new OpenAI(); // Various imports from other files const config = require('./config.json'); From 22f2ac58df2205e826ef45c8def32c5c1315ddaa Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Fri, 21 Jun 2024 15:01:56 -0400 Subject: [PATCH 34/79] I hate you --- .DS_Store | Bin 6148 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 .DS_Store diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index f388235cbc75a06861b27741a6e6016b0f7ddc09..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHKO;5r=5S`VkfFI#tqR0LLO-MYO3gzg*5bp{YG-)jfka+CLpCNz37!M}iyy(%t zW8$0Lg?6bFE~q3s$?jWbXLes-+8vgNM0L=v5S59jfX3*Q(EVUM&n;ss+OrE3yhhNe zG+I&E%|u#B>}314CO`BncYzMYu!?cDk9 zb?R(bM<&t6XkWUf0X2=?Y3(T+k>+rA_fXRuCe{g~gvs^6w)dB zHhu?mMLm;Sk@@FDr+FUVk9p>1B%J5VF!}TOOPh+f59v$f96#(eKEe&H?i-0aWfS$%!Av`dlQh_Q} z=qrX$>F~Qc&eIqxROuw-&R9q9Ec6XU$lc+0WjHP8$*j2B-YT$21y7A>G%Id zQm|`V1*`&ptblO*hF=8*j1|HI PvwsAn47Rfh{Hg-qJd?!^ From bfa6e1001100abfcd5e554195031073084e7b59b Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Fri, 21 Jun 2024 15:02:08 -0400 Subject: [PATCH 35/79] Versioning v3.2.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e3257c6..e419fc5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "nodbot", - "version": "3.2.2", + "version": "3.2.3", "description": "Nods and Nod Accessories, now with ChatGPT!", "main": "main.js", "dependencies": { From 7003351eccfab419a0b0fa7ec0b7d6cbd48b5097 Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Fri, 21 Jun 2024 15:02:22 -0400 Subject: [PATCH 36/79] Updating how autoresponses are handled to be cleaner --- functions.js | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ main.js | 15 +++++---------- strings.json | 44 ++++++++++++++++++++++++++++++++++++-------- 3 files changed, 90 insertions(+), 18 deletions(-) diff --git a/functions.js b/functions.js index fdb1492..c3b5486 100644 --- a/functions.js +++ b/functions.js @@ -649,6 +649,55 @@ const functions = { return newText + ' <:spongebob:1053398825965985822>'; }, + autoresponses: { // Specific responses for certain keywords in sent messages + checkForAll(messageContent) { + let responses = []; + if (this.bigDoinks(messageContent)) responses.push("bigDoinks"); + if (this.ligma(messageContent)) responses.push("ligma"); + if (this.ong(messageContent)) responses.push("ong"); + return responses; + }, + bigDoinks(messageContent) { + let count = 0; + const { keywords } = strings.autoresponses.bigDoinks; + keywords.forEach(e => { + if (messageContent.includes(e)) count++; + }); + if (count === keywords.length) { + return true; + } + }, + ligma(messageContent) { + let count = 0; + const { keywords } = strings.autoresponses.ligma; + keywords.forEach(e => { + if (messageContent.includes(e)) count++; + }); + if (count > 0) { + return true; + } + }, + ong(messageContent) { + let count = 0; + const { keywords } = strings.autoresponses.ong; + keywords.forEach(e => { + if (messageContent.includes(e)) count++; + }); + if (count > 0) { + return true; + } + }, + send(message, responseType) { + const { responses } = strings.autoresponses[responseType]; + const randomIndex = Math.floor(Math.random() * responses.length); + const response = responses[randomIndex]; + try { + message.reply(response); + } catch(e) { + console.log(new Error(e)); + } + } + }, generateErrorId() { const digitCount = 10; const digits = []; diff --git a/main.js b/main.js index 584a89c..4527304 100644 --- a/main.js +++ b/main.js @@ -221,17 +221,12 @@ client.on('messageCreate', message => { // Some basic checking to prevent running unnecessary code if (message.author.bot) return; - // Wildcard Responses, will respond if any message contains the trigger word(s), excluding self-messages + // Automatic Responses, will respond if any message contains the keyword(s), excluding self-messages const lowerContent = message.content.toLowerCase(); - // big + doinks - if (lowerContent.includes('big') && lowerContent.includes('doinks')) message.reply('gang.'); - // ligma - if (lowerContent.includes('ligma')) message.reply('ligma balls, goteem'); - // frfr, fr fr , bussin, ong - if (lowerContent.includes('frfr') || lowerContent.includes('fr fr') || lowerContent.includes('bussin') || lowerContent.includes(' ong') || lowerContent.startsWith('ong')) { - const randIndex = Math.floor(Math.random() * strings.capbacks.length); - message.reply(strings.capbacks[randIndex]); - } + const autoresponses = fn.autoresponses.checkForAll(lowerContent); + autoresponses.forEach(e => { + fn.autoresponses.send(message, e); + }); // Break the message down into its components and analyze it const commandData = fn.dot.getCommandData(message); diff --git a/strings.json b/strings.json index 94ee7cf..134d225 100644 --- a/strings.json +++ b/strings.json @@ -14,14 +14,6 @@ "urls": { "avatar": "https://cdn.discordapp.com/avatars/513184762073055252/12227aa23a06d5178853e59b72c7487b.webp?size=128" }, - "capbacks": [ - "on god?!", - "fr fr?!", - "no cap?!", - "no cap fr", - "bussin fr, no cap", - "ongggg no :billed_cap: fr fr" - ], "costs": { "gpt": { "gpt-3.5-turbo": 0.2 @@ -39,5 +31,41 @@ "chatResCentsPer": 0.2, "chatResUnits": 1000 }, + "autoresponses": { + "bigDoinks": { + "keywords": ["big", "doinks"], + "responses": [ + "<:bigdoinks:1053706618853924905> Gang.", + "<:bigdoinks:1053706618853924905> Out here in Amish", + "<:bigdoinks:1053706618853924905> Out here in Amish, smoking Big Doinks in Amish... Gang." + ] + }, + "ligma": { + "keywords": ["ligma"], + "responses": [ + "ligma balls lmao gottem", + "ligma balls ahaha", + "https://tenor.com/view/ligma-balls-gif-12236083", + "<:deadmonkey:1139186312444911707>" + ] + }, + "ong": { + "keywords": [ + "frfr", + "fr fr", + "bussin", + "no cap", + " ong " + ], + "responses": [ + "on god?!", + "fr fr?!", + "no cap?!", + "no cap fr", + "bussin fr, no cap", + "ongggg no :billed_cap: fr fr" + ] + } + }, "temp": {} } \ No newline at end of file From 99af5ca8b41aaeea936f4080938266b1635c22ee Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Fri, 21 Jun 2024 15:11:34 -0400 Subject: [PATCH 37/79] Add f u nodbot response --- functions.js | 11 +++++++++++ strings.json | 13 +++++++++++++ 2 files changed, 24 insertions(+) diff --git a/functions.js b/functions.js index c3b5486..c3aa962 100644 --- a/functions.js +++ b/functions.js @@ -655,6 +655,7 @@ const functions = { if (this.bigDoinks(messageContent)) responses.push("bigDoinks"); if (this.ligma(messageContent)) responses.push("ligma"); if (this.ong(messageContent)) responses.push("ong"); + if (this.fuckYou(messageContent)) responses.push("fuckYou"); return responses; }, bigDoinks(messageContent) { @@ -687,6 +688,16 @@ const functions = { return true; } }, + fuckYou(messageContent) { + let count = 0; + const { keywords } = strings.autoresponses.fuckYou; + keywords.forEach(e => { + if (messageContent.includes(e)) count++; + }); + if (count === keywords.length) { + return true; + } + }, send(message, responseType) { const { responses } = strings.autoresponses[responseType]; const randomIndex = Math.floor(Math.random() * responses.length); diff --git a/strings.json b/strings.json index 134d225..3cb89dc 100644 --- a/strings.json +++ b/strings.json @@ -65,6 +65,19 @@ "bussin fr, no cap", "ongggg no :billed_cap: fr fr" ] + }, + "fuckYou": { + "keywords": [ + "fuck", + "nodbot" + ], + "responses": [ + "no u", + "go fuck yourself", + "why does everyone hate me :sob:", + "<:kms:310190799784509441>", + "Eat a bag of dicks" + ] } }, "temp": {} From 2a3b53ea086fd39fec81eb0e1316e2d29b1d701d Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Fri, 21 Jun 2024 15:14:38 -0400 Subject: [PATCH 38/79] Fix kms emoji is --- strings.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/strings.json b/strings.json index 3cb89dc..e7991f8 100644 --- a/strings.json +++ b/strings.json @@ -75,7 +75,7 @@ "no u", "go fuck yourself", "why does everyone hate me :sob:", - "<:kms:310190799784509441>", + "<:kms:1253790048696926298>", "Eat a bag of dicks" ] } From 388bc4d021305acd0437b69a41fc5287b0842018 Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Fri, 21 Jun 2024 18:35:12 -0400 Subject: [PATCH 39/79] Add Metars with Decoding TODO: add TAFs --- config.json | 3 +- dot-commands/metar.js | 26 ++++++++++++ functions.js | 92 +++++++++++++++++++++++++++++++++++++------ main.js | 16 ++++---- package.json | 2 +- 5 files changed, 118 insertions(+), 21 deletions(-) create mode 100644 dot-commands/metar.js diff --git a/config.json b/config.json index 467e255..dbd4f48 100644 --- a/config.json +++ b/config.json @@ -1,5 +1,6 @@ { "guildId": "868542949737246730", "validCommands": [], - "roaches": [] + "roaches": [], + "icaoIds": ["OMAL","OMAA","OMAD","OMAM","OMBY","OMDL","OMFJ","OMSJ","OMDW","OMDB","OMDM","OMRK","OADZ","OAFZ","OARZ","OAHN","OASN","OAQN","OAMS","OABN","OAFR","OAMN","OAGN","OADS","OACC","OABT","OADY","OAZI","OAHR","OASD","OAZJ","OAGZ","OAKB","OAKN","OATN","OARG","OAKS","OASL","OAUZ","OASH","OAJL","OASA","OAOG","OAIX","OATQ","TAPH","TAPA","TQPF","UDYZ","UDSG","FNAM","FNBG","FNCT","FNLB","FNKU","FNCA","FNGI","FNXA","FNHU","FNUB","FNCV","FNME","FNWK","FNSU","FNPA","FNLU","FNCF","FNDU","FNLK","FNLZ","FNZG","FNCH","FNSA","FNCP","FNMA","FNCZ","FNUE","FNUA","FNMO","FNNG","FNUG","FNZE","FNBC","FNSO","SCRM","SABE","SAZB","SAZC","SADP","SAEZ","SAAJ","SADL","SAZM","SAZO","SAZF","SAZH","SAZP","SAZL","SAZT","SAZV","SANC","SARS","SARE","SAVR","SAVC","SAVD","SAVE","SAWS","SAVM","SAVY","SAVT","SAWM","SACO","SACC","SAOC","SAOD","SARL","SARC","SARM","SATM","SATG","SATU","SAAC","SAAG","SAAP","SATC","SARF","SATK","SASJ","SAZG","SAZR","SANL","SAMR","SAMM","SAME","SATD","SARI","SARP","SAHZ","SAZY","SAZW","SAHC","SAZN","SAHS","SAZS","SAVB","SAHR","SAVJ","SAVQ","SAVN","SAVS","SAVV","SASO","SASA","SAST","SANU","SAOU","SAOS","SAOR","SAWA","SAWR","SAVH","SAWP","SAWD","SAWG","SAWT","SAWU","SAWJ","SANW","SAFS","SAFR","SATR","SAAR","SAAV","SANR","SANE","SAWE","SAWH","SANT","NSAS","NSTU","LOWK","LOWW","LOWL","LOWS","LOWG","LOWI","LOIH","YSCB","YMAY","YARM","YLMQ","YBHI","YBTH","YBNA","YBKE","YBRW","YSBK","YBRN","YCBA","YCDO","YSCN","YCNK","YCFS","YCAH","YCTM","YCNM","YCBB","YCBR","YCAS","YCUA","YCWR","YCOR","YSDU","YMDG","YDLQ","YEVD","YFIL","YFST","YFBS","YGTH","YGFN","YGLI","YSMB","YGDH","YGLB","YHAY","YIVL","YKMP","YLHI","YLRD","YLIS","YMER","YMOR","YMND","YMRY","YNBR","YNHS","YYNG","YSNW","YNAR","YSCO","YWLM","YNYN","YORG","YCOM","YPKS","YPMQ","YSGT","YSSY","YTOC","YTEM","YSTW","YTRE","YTMU","YTIB","YQDI","YWWA","YSWG","YWLG","YWCA","YWCH","YWOL","YWWL","YSRI","YBAS","YAUV","YALX","YAYE","YBRL","YBTI","YCOO","YCFD","YCKI","YDVR","YDLV","YPDN","YELD","YFNE","YGBI","YPGV","YGPT","YGTE","YTGT","YHMB","YHOO","YHBY","YHBR","YINW","YJAB","YKCA","YKCS","YKKG","YPTN","YLEV","YLKN","YMHU","YMCR","YMGB","YMVG","YMGD","YMDS","YMQA","YMNS","YMSF","YMUP","YNUM","YKPT","YRNG","YRKD","YRRB","YNGU","YSMP","YSNB","YTBR","YTNK","YTMY","YVRD","YWAV","YWOR","YWTL","YYND","YARY","YABI","YAPH","YNPE","YAGD","YAUR","YAMC","YAYR","YLLE","YBAR","YBUD","YBAU","YBIE","YBAW","YBCK","YBLL","YBTR","YBPI","YBBN","YBOU","YBEO","YBKT","YBDV","YCCA","YCRY","YCMU","YCMW","YCMT","YCCT","YCCY","YBCS","YBCV","YCKN","YCDR","YCOE","YCHT","YUNY","YDAY","YDLT","YDRH","YDKI","YDMG","YDBR","YDOR","YDBI","YDRI","YDPD","YDIX","YDYS","YPMP","YEML","YESE","YGAY","YGAM","YGDS","YBOI","YGKL","YGLE","YGLO","YGLA","YGDI","YGON","YGTN","YGNV","YGYM","YHTL","YHUG","YHID","YHHY","YHDY","YBHM","YHBA","YIFY","YIFL","YIGM","YIKM","YINJ","YLHR","YBMA","YISF","YJLC","YJDA","YCSV","YKRY","YKLB","YKML","YKLA","YKPR","YKMB","YSPV","YKUB","YKOW","YLIN","YLFD","YLND","YCGO","YLOR","YLRE","YLHS","YLOV","YLRS","YLRA","YLAH","YLZI","YMYB","YBSU","YMOT","YBMK","YMEU","YMMU","YMTO","YMRB","YMBA","YMIT","YMGV","YMIR","YMWX","YMAE","YDNI","YNAP","YNSH","YNTN","YORC","YYKI","YBOK","YMTI","YMNK","YBCG","YMOO","YOEN","YOSB","YMNY","YTMO","YPAM","YBPN","YRMD","YROM","YROB","YBRK","YRSB","YRTP","YSII","YSPK","YSGE","YSPT","YSPE","YSTI","YSMR","YWBS","YTGA","YTDR","YTNG","YTEE","YBTL","YTWB","YTHY","YMAA","YUDA","YQLP","YMTB","YVRS","YWCK","YWND","YBWP","YWTN","YMLS","YWDH","YWDL","YWMP","YSHR","YBWW","YYMI","YTGM","YTAM","YTAA","YBWN","YSGW","YPAD","YAMK","YAMT","YCWL","YCDU","YCBP","YCEE","YCWI","YDLK","YERN","YEDA","YMGN","YHAW","YIDK","YINN","YKBY","YKSC","YYTA","YBLC","YLEC","YLOK","YMTG","YMPA","YMCT","YMUG","YOOM","YALA","YMUK","YMWT","YNRC","YNUB","YOOD","YCOD","YOLD","YYOR","YPDI","YPSH","YPLC","YPIR","YPAG","YPMH","YREN","YMRE","YMYT","YPWR","YWUD","YWHA","YMIN","YWYY","YDPO","YFLI","YGTO","YMHB","YSTH","YKII","YMLT","YSMI","YSRN","YQNS","YARA","YMAV","YBLA","YBNS","YBDG","YCRG","YECH","YGLG","YHML","YHSM","YHPN","YKER","YPOK","YMMB","YMEN","YMML","YHOT","YMIA","YOUY","YPOD","YROI","YORB","YSHT","YSWL","YSWH","YWSL","YLTV","YWGT","YWKB","YWBL","YOLA","YMCO","YABA","YBDF","YBRM","YBLN","YBGO","YBUN","YBYS","YBWX","YBEB","YBRY","YCAG","YCOI","YCWA","YCHK","YCWY","YCUE","YCAR","YCIN","YDGA","YDRA","YDBY","YDRD","YEEB","YESP","YECL","YEXM","YFTZ","YFRT","YFLO","YFRV","YGIB","YGIA","YGDN","YGEL","YGSC","YARG","YHLC","YHIL","YPJT","YJNB","YKBR","YKBL","YFDF","YPKG","YKNG","YPKU","YKAR","YPKA","YYLR","YPLM","YLST","YLEO","YLTN","YMBL","YMGR","YMHO","YMIP","YSHK","YMJM","YMEK","YMOG","YMDI","YMGT","YMUC","YMRW","YMWA","YMYR","YSAN","YCNF","YNUL","YNRG","YNSM","YBGD","YORV","YOLW","YPBO","YPPH","YPPD","YPDO","YROE","YRYH","YRTI","YNRV","YSHG","YSOL","YSCR","YTAB","YTHD","YTEF","YTKY","YTMP","YTST","YKAL","YUSL","YWIT","YWAL","YANG","YMNE","YWDG","YWWG","YMMI","YWLU","YWWI","YWYM","YYAL","YNWN","TNCA","UBBB","UBBG","UBBL","UBBN","UBBQ","UBEE","UBBY","LQMO","LQSA","LQTZ","LQBK","TBPB","VGBR","VGEG","VGCM","VGCB","VGHS","VGJR","VGIS","VGRJ","VGSD","VGSG","VGSH","VGSY","EBAW","EBZR","EBBR","EBCI","EBLG","EBKT","EBOS","DFOU","DFET","DFEZ","DFOB","DFEB","DFEF","DFOO","DFFD","DFEP","DFON","DFOD","DFCP","DFEA","DFEM","DFEG","DFOG","DFCA","DFEE","DFCL","DFOY","DFCJ","DFOT","DFER","DFED","DFEL","DFES","DFCC","LBBG","LBHS","LBPD","LBRS","LBSS","LBSF","LBSZ","LBTG","LBWN","LBGO","OBBI","HBBA","HBBE","HBBO","DBBK","DBBN","DBBP","DBBS","DBBD","DBBB","TFFJ","TXKF","WBSB","SLAG","SLSU","SLSB","SLCB","SLHI","SLHJ","SLBU","SLGY","SLMG","SLRQ","SLRY","SLRI","SLSA","SLJO","SLSM","SLSR","SLRA","SLTR","SLAP","SLLP","SLOR","SLCO","SLPR","SLPO","SLUY","SLAS","SLCA","SLCP","SLTI","SLPS","SLRB","SLJE","SLJV","SLSI","SLET","SLVG","SLVR","SLBJ","SLYA","SLTJ","SLVM","TNCB","TNCS","TNCE","SBCZ","SNOU","SBRB","SBTK","SWSN","SNAL","SBMO","SBMQ","SBOI","SWBC","SWNK","SWCA","SWKO","SWEI","SWOB","SWHT","SWII","SWTP","SBIC","SWLB","SBEG","SWMW","SBMY","SWNA","SDCG","SWPI","SBMN","SWBR","SBUA","SBTT","SBTF","SNBU","SBPS","SNBX","SNBR","SNBL","SNED","SBCV","SNJD","SNGI","SBIL","SNIU","SNIC","SNZW","SNHA","SNJB","SNJK","SBLP","SBLE","SNMU","SBUF","SNRD","SBSV","SNTF","SBTC","SNVB","SBQV","SBAC","SNWC","SBFZ","SBJU","SBJE","SBBR","SNKI","SNGA","SNMX","SBVT","SWNS","SWEC","SBCN","SBGO","SBIT","SWJW","SBMC","SWNQ","SWLC","SWUA","SWKT","SNAI","SNBC","SBRR","SNBS","SBCI","SNCP","SNGM","SBIZ","SNYE","SBSL","SBDB","SBCG","SBCR","SSCL","SSDO","SSPN","SBPP","SBTG","SBAT","SSOU","SWTU","SBBW","SWKC","SBCY","SWEK","SWDM","SWHP","SWJN","SWJU","SIZX","SILC","SWXM","SWVB","SWXV","SWSI","SWPG","SWPQ","SWRD","SWST","SWFX","SWTS","SWVC","SBAX","SNAR","SNDV","SNDT","SBGV","SBIP","SBZM","SBJF","SNJR","SNJN","SNDN","SBMK","SNNU","SNPX","SNPD","SBPC","SNZA","SNOS","SNLO","SNTO","SBUR","SBUL","SBVG","SBHT","SBBE","SNVS","SBAA","SBCJ","SNKE","SNYA","SBIH","SBEK","SBMA","SBMD","SNMA","SJNP","SNTI","SDOW","SNOX","SNMZ","SNDC","SNSW","SBSN","SNFX","SBTB","SBKG","SBJP","SSYA","SSAP","SSOG","SBBI","SBCA","SSKM","SSCP","SBCT","SSFB","SSCT","SSGY","SBGU","SBFI","SBLO","SBMG","SSZW","SSPG","SSPB","SSPI","SBTL","SBTD","SBTU","SSUM","SNRU","SBFN","SBPL","SBRF","SNQG","SNGD","SNPC","SBPB","SBTE","SBMS","SBNT","SSLT","SBBG","SSCN","SSSC","SSVP","SBCX","SSER","SBNM","SSHZ","SSIJ","SSIQ","SNLB","SBPK","SBPF","SBPA","SBSM","SBRG","SSRU","SSZR","SBTR","SBUG","SBBZ","SBCP","SBCB","SDUN","SBME","SDRS","SBVH","SWCQ","SBGM","SWJI","SSKW","SWPM","SBPV","SBBV","SSBL","SSCK","SBCM","SBCD","SBFL","SSJA","SBJA","SBJV","SBLJ","SSLN","SBNF","SSOE","SSUV","SSVI","SBCH","SBAS","SBAQ","SBAU","SBBT","SBBU","SBBP","SDAM","SIMK","SBGW","SDJL","SBAE","SBLN","SBML","SDOU","SBDN","SDSC","SBRP","SBSJ","SBSR","SDCO","SBST","SDUB","SBUP","SDVG","SBAR","SWRA","SWGN","SWDN","SWGI","SWIY","SBPJ","SBPN","MYAP","MYBG","MYBS","MYCB","MYAF","MYBC","MYAB","MYAN","MYCC","MYAW","MYGF","MYEF","MYEN","MYES","MYEH","MYAM","MYAT","MYIG","MYCI","MYRD","MYLD","MYCP","MYLS","MYMM","MYNN","MYRP","MYSM","MYAK","MYCA","MYEM","MYER","MYGW","VQBT","VQPR","VQGP","VQTY","FBOR","FBSP","FBSN","FBTL","FBKE","FBGZ","FBTS","FBFT","FBKR","FBMN","FBSV","FBSW","FBSK","FBLO","FBJW","UMBB","UMGG","UMMG","UMOO","UMMM","UMMS","UMII","MZBZ","MZPL","CYNR","CZPC","CYBA","CYBF","CYCT","CYEG","CYET","CYJA","CYLB","CYLL","CYMM","CYOD","CYOJ","CYOP","CYPE","CYPY","CYQF","CYQL","CYQU","CYRM","CYSD","CYVG","CYXH","CYYC","CYYM","CYZH","CYZU","CZHP","CYHC","CYBD","CYAL","CYAZ","CYBH","CYBL","CYCD","CYCG","CYCQ","CYCW","CYCZ","CYDL","CYDQ","CZBB","CYGB","CYHE","CYKA","CYLW","CYNJ","CYNH","CYPR","CYPW","CYPZ","CYQQ","CYQZ","CYRV","CYSE","CZAM","CYVK","CYVR","CYWH","CYWL","CYXC","CYXJ","CYXS","CYXT","CYXX","CYYD","CYYE","CYYF","CYYJ","CYZP","CYZT","CBBC","CZGF","CZML","CZMT","CZST","CZSW","CZBD","CZEE","CZMN","CZWH","CZFG","CZNG","CZSN","CYBQ","CYBR","CYBT","CYBV","CYCR","CYDN","CZTA","CYFO","CYGM","CYGO","CYGX","CYIV","CYLR","CYNE","CYOH","CYPG","CYQD","CYRS","CYST","CZLQ","CYTH","CYWG","CYYI","CYYL","CYYQ","CZAC","CZGI","CZGR","CZJG","CZJN","CZTM","CYCH","CYCL","CYFC","CYQM","CYSJ","CYSL","CZBF","CYAY","CYDF","CYDP","CYHO","CYJT","CYMH","CYFT","CYQX","CYCA","CYWK","CYYR","CYYT","CZUM","CYKD","CYVL","CYEV","CYWE","CYFR","CYFS","CYGH","CYHI","CYHY","CYJF","CYMD","CYOA","CYPC","CYRA","CYLK","CYSM","CYSY","CYUB","CYVQ","CYWJ","CYWY","CYZF","CZFM","CZFN","CYID","CYHZ","CYPD","CYQI","CYQY","CYZX","CYAB","CYBB","CYBK","CYCB","CYCO","CYCS","CYCY","CYEK","CYEU","CYFB","CYGT","CYGZ","CYHK","CYIO","CYLC","CYLT","CYRB","CYRT","CYSK","CYTE","CYUT","CYUX","CYVM","CYVN","CYXN","CYXP","CYYH","CYZS","CZMD","CYCK","CYAQ","CYAC","CYAG","CYAM","CYAT","CYCC","CYCE","CYSN","CYCN","CYEL","CYEM","CYER","CYFA","CYFH","CYGK","CYGQ","CYHD","CYHF","CYHM","CYHN","CYHP","CYIB","CYKM","CYKF","CYKX","CYLD","CYLH","CYLS","CYMG","CYMO","CYKP","CYOO","CYOS","CYOW","CYPL","CYPM","CYPO","CYPQ","CYQA","CYQG","CYQK","CYQN","CYQS","CYQT","CYRL","CYRO","CYSB","CYSH","CYSP","CYTA","CYTL","CYTR","CYTS","CYTZ","CYVV","CYVZ","CYWA","CYWP","CYXL","CYXR","CYXU","CYXZ","CYYB","CYYU","CYYW","CYYZ","CYZE","CYZR","CZKE","CZPB","CZRJ","CZSJ","CZUC","CYSU","CYYG","CYKO","CYLU","CYAH","CYAD","CYBC","CYBG","CYBX","CYDO","CYEY","CYFE","CYGL","CYGP","CYGR","CYGV","CYGW","CYHR","CYIF","CYIK","CYJN","CYAS","CYKL","CYKQ","CYLP","CYLQ","CYME","CYML","CYMT","CYMW","CYMX","CYNA","CYNC","CYND","CYNM","CYHH","CYPH","CYLA","CYPN","CYPX","CYQB","CYHA","CYRI","CYRJ","CYRQ","CYSC","CYTF","CYFJ","CYTQ","CYMU","CYUL","CYUY","CYVB","CYVO","CYVP","CYKG","CYXK","CYYY","CYZG","CYZV","CZBM","CZEM","CYBE","CYEN","CYHB","CYKC","CYKJ","CYKY","CYLJ","CYMJ","CYNL","CYPA","CYQR","CYQV","CYQW","CYSF","CYVC","CYVT","CYXE","CYYN","CZFD","CZPO","CZWL","CYDM","CYDA","CYDB","CYHT","CYMA","CYOC","CYQH","CYXQ","CYXY","CYZW","CZFA","YPCC","FZKJ","FZFD","FZEN","FZEA","FZQA","FZSK","FZQG","FZTK","FZQC","FZKA","FZWC","FZWT","FZVI","FZVA","FZWA","FZVR","FZUA","FZUG","FZVM","FZVS","FZUK","FZAA","FZAB","FZAJ","FZAL","FZAM","FZAG","FZAR","FZQM","FZBO","FZCB","FZBA","FZOK","FZCA","FZBT","FZCE","FZCV","FZBI","FZOC","FZOA","FZOP","FZFU","FZGA","FZNP","FZNA","FZJH","FZFP","FZGV","FZMA","FZFK","FZFA","FZRB","FZRF","FZRM","FZRQ","FZRA","FZIC","FZIR","FZGN","FEFN","FEFF","FEFZ","FEGE","FEFY","FEFR","FEFW","FEFT","FEFC","FEFG","FEGM","FEGR","FEFO","FEFM","FEGU","FEFS","FEGF","FEGZ","FEFI","FEGO","FCBM","FCBY","FCBZ","FCBB","FCOB","FCOO","FCOM","FCOE","FCOK","FCBS","FCOT","FCOI","FCPL","FCPA","FCMM","FCBD","FCOG","FCBL","FCPP","FCBK","FCOU","FCOS","LSZB","LSGG","LSZS","LSME","LSZC","LSZR","LSZA","LSGS","LSZH","DIAP","DIOF","DIGN","DISP","DITB","DISS","DIAO","DIAU","DIOD","DIDV","DIGA","DIDK","DIGL","DIMN","DIDL","DIBI","DIFK","DIKO","DIBK","DISG","DITM","DIYO","DIBU","DIBN","NCAI","NCAT","NCMG","NCMH","NCMR","NCMK","NCPY","NCPK","NCRG","SCBA","SCCC","SCCY","SCHR","SCAS","SCFA","SCCF","SCBE","SCTT","SCAR","SCRA","SCAT","SCES","SCLL","SCIE","SCGE","SCCH","SCQB","SCSE","SCOV","SCTC","SCQP","SCTO","SCPC","SCFT","SCFR","SCPQ","SCTE","SCPV","SCAP","SCST","SCTN","SCJO","SCAC","SCVD","SCNT","SCCI","SCSB","SCFM","SCGZ","SCTL","SCEL","SCKP","SCDA","SCIP","SCVM","SCAN","SCRD","FKKN","FKYS","FKKY","FKKO","FKKI","FKKJ","FKKH","FKKL","FKKD","FKAN","FKKR","FKKG","FKKV","FKKU","FKKS","FKKM","FKKW","FKKB","FKKF","FKKC","ZSAQ","ZSBB","ZSFY","ZSOF","ZSTX","ZSWA","ZBAA","ZUWL","ZUWS","ZUCK","ZUDZ","ZUQJ","ZULP","ZUWX","ZSFZ","ZSQZ","ZSLO","ZSSM","ZSWY","ZSAM","ZLDH","ZLXH","ZLQY","ZLJQ","ZLJC","ZLLL","ZLLN","ZLTS","ZLZY","ZGGG","ZGFS","ZGHZ","ZGMX","ZGOW","ZGSZ","ZGXN","ZGZJ","ZGSD","ZGBS","ZGBH","ZGHC","ZGKL","ZGZH","ZGNN","ZGWZ","ZUYI","ZUAS","ZUBJ","ZUNP","ZUGY","ZULB","ZUPS","ZUTR","ZUMT","ZUZY","ZJHK","ZJSY","ZBDH","ZBCD","ZBHD","ZBSJ","ZBTS","ZBXT","ZBZJ","ZYDQ","ZYFY","ZYHE","ZYHB","ZYJD","ZYJM","ZYJS","ZYJX","ZYLD","ZYMD","ZYQQ","ZYMH","ZYYL","ZHXY","ZHAY","ZHCC","ZHLY","ZHNY","ZHEC","ZHES","ZHSN","ZHGH","ZHSS","ZHSY","ZHHH","ZHXF","ZHYC","ZGCZ","ZGYY","ZGCD","ZGHA","ZGDY","ZGCJ","ZGHY","ZGLG","ZGSY","ZSCG","ZSSH","ZSLG","ZSNJ","ZSNT","ZSRG","ZSSZ","ZSWX","ZSXZ","ZSYN","ZSYA","ZSJD","ZSJA","ZSJJ","ZSCN","ZSGZ","ZSSR","ZSYC","ZYCC","ZYBA","ZYJL","ZYBS","ZYTN","ZYYJ","ZYSQ","ZYAS","ZYCY","ZYCH","ZYDD","ZYTL","ZYJZ","ZYTX","ZYXC","ZYYK","ZBOW","ZBCF","ZBDS","ZBER","ZBHH","ZBLA","ZBUL","ZBHZ","ZBMZ","ZBYZ","ZBTL","ZBUH","ZBXH","ZBES","ZLGY","ZLIC","ZLZW","ZLHB","ZLGL","ZLGM","ZLDL","ZLXN","ZLYS","ZLAK","ZBCZ","ZBDT","ZLYA","ZLHZ","ZBLL","ZLSN","ZBYN","ZLYL","ZBXZ","ZLXY","ZSHZ","ZSDY","ZLJN","ZSLY","ZSQD","ZSJN","ZSWF","ZSWH","ZSYT","ZSPD","ZSSS","ZBYC","ZUDA","ZUHY","ZUUU","ZUDX","ZUDC","ZUGH","ZUGU","ZUJZ","ZUKD","ZULZ","ZUMY","ZUNC","ZUZH","ZUTF","ZUXC","ZUYB","ZBTJ","ZWAT","ZWAK","ZWBL","ZWFY","ZWHM","ZWTN","ZWCM","ZWKC","ZWSH","ZWKN","ZWKL","ZWKM","ZWNL","ZWRQ","ZWHZ","ZWSS","ZWTC","ZWTL","ZWWW","ZWYN","ZUBD","ZULS","ZUNZ","ZUAL","ZURK","ZPBS","ZPCW","ZPDQ","ZPDL","ZPJH","ZPJM","ZPPP","ZPLJ","ZPLC","ZPMS","ZPSM","ZUTC","ZPWS","ZPYM","ZPZT","ZSHC","ZSZS","ZSLQ","ZSJU","ZSNB","ZSWZ","ZSYW","SKLT","SKLP","SCSF","SKRA","SKAN","SKAM","SKLC","SKCU","SKEB","SKMD","SKIG","SKRG","SKPN","SKNC","SKOT","SKPR","SKTU","SKUR","SKAT","SKUC","SKCN","SKSA","SKTM","SKBQ","SKCG","SKMG","SKMP","SKVL","SKPA","SKSO","SKTA","SKMZ","SKAC","SKYA","SKFL","SKSV","SKTQ","SKYP","SKHC","SKOE","SKPZ","SKTD","SKGP","SKPP","SKMB","SKAG","SKVP","SKAD","SKCP","SKBS","SKCD","SKCA","SKJU","SKNQ","SKUI","SKML","SKMR","SKPQ","SKBO","SKBM","SKPD","SKMF","SKSJ","SKNV","SKPI","SKLM","SKRH","SKBC","SKPL","SKSM","SKAP","SKCI","SVWX","SKNA","SKUB","SKVV","SKEH","SKIP","SKPS","SKCO","SKCC","SKOC","SKTB","SKLG","SKAS","SKVG","SKAR","SKPE","SKSP","SKPV","SKBG","SKCM","SKEJ","SKRU","SKCV","SKCZ","SKTL","SKHA","SKGI","SKIB","SKQU","SKBU","SKCL","SKGO","SKUL","SKCR","SKMU","SKGA","SKIM","SKPC","SKSL","MRAN","MRLC","MRRF","MROC","MRUP","MRMJ","MRLB","MRNC","MRNS","MRIA","MRCR","MRTM","MRBC","MRGP","MRLM","MRBT","MRBA","MRDK","MRGF","MRCH","MRCC","MRPJ","MRPM","MRTR","MRSV","MRQP","MRSI","MRPV","MUPB","MUCM","MUCA","MUCC","MUCF","MUBY","MUMZ","MUBA","MUGT","MUGM","MUHG","MUMO","MUCL","MUNG","MUSN","MUHA","MUVT","MUVR","MUKW","MULM","MUSJ","MUTD","MUSS","MUCU","MUBR","MUSC","GVBA","GVBR","GVMA","GVNP","GVAN","GVSN","GVAC","GVMT","GVSF","GVSV","TNCC","YPXM","LCGK","LCLK","LCEN","LCRA","LCPH","LKCS","LKTB","LKKV","LKMR","LKMT","LKZA","LKOL","LKPO","LKPD","LKPR","LKVO","LKHO","LKKU","EDNY","EDSB","ETIE","EDTL","EDFM","EDDS","EDMA","EDQD","ETSF","EDJA","EDQG","EDQM","ETSI","ETIK","ETIN","EDDM","EDDN","EDMO","EDMS","EDQE","EDDT","EDDB","EDCD","EDDW","EDWB","EDDH","EDHI","EDDF","ETHF","EDVK","ETOU","EDBH","EDBN","EDCG","EDAH","EDCP","EDAX","ETNL","EDOP","EDWG","EDWR","EDWZ","EDVE","EDWE","ETMN","EDDV","EDWJ","EDWL","EDWS","EDWY","EDWU","EDWI","EDWD","EDKA","EDLI","EDDK","EDLW","EDDL","EDLE","EDDG","ETNG","ETUO","EDLN","EDLV","EDLP","EDGS","EDRB","EDFH","ETAR","ETAD","EDRZ","EDDR","EDDC","EDAU","EDDP","EDBC","EDCK","EDAQ","EDHN","EDXF","EDXW","EDXB","EDXH","EDHK","EDHL","EDXY","EDXO","EDXJ","ETNS","EDAC","EDGE","EDDE","HDAS","HDAM","HDOB","HDMO","HDTJ","EKCH","EKRN","EKAH","EKKA","EKSV","EKVJ","EKYT","EKLS","EKSN","EKTS","EKMB","EKRK","EKBI","EKEB","EKOD","EKSB","EKSP","TDPD","TDCF","MDBH","MDJB","MDPC","MDCZ","MDSD","MDCR","MDPP","MDCY","MDAB","MDST","DAUA","DATM","DAUT","DAAG","DABB","DABT","DAOR","DAAE","DAUB","DAOI","DABC","DAAD","DAOY","DAUO","DAUE","DAUG","DAAJ","DAUZ","DAAP","DAAV","DAFH","DAUL","DAOV","DAAY","DAOO","DAOL","DAUH","DAUU","DAUK","DAAS","DAOS","DABP","DATG","DAUI","DAAT","DABS","DAOB","DAOF","DAON","SECU","SETU","SERO","SEMH","SETN","SEGS","SEII","SEST","SEGU","SETM","SEMA","SESV","SEJI","SEMT","SEPV","SESC","SETH","SEMC","SEJD","SECO","SETI","SESM","SEQM","SESA","SENL","SEPT","SETR","SEAM","EETN","EEKA","EEPU","EEKE","EETU","HEGN","HEMA","HEAX","HEBA","HE25","HECA","HELX","HEDK","HEOW","HEKG","HEBL","HESN","HEAT","HEPS","HETR","HESC","HESH","HETB","HEAL","HEMM","HEAR","HEMK","HHAS","HHSB","HHTS","HHMS","LEMG","LEGR","LEAM","LEBA","LEMO","LERT","LEZL","LEJR","LEHC","LETL","LEZG","LEAS","GCRR","GCFV","GCGM","GCLP","GCLA","GCHI","LEXJ","LERL","LELN","LEBG","LESA","LEVD","LEAB","LEBL","LEGE","LEDA","LESU","LERS","LEBZ","LECO","LEST","LEVX","LEIB","LEMH","LEPA","LELO","LEMD","LETO","GEML","LELC","LEMI","LEPP","LEBB","LESO","LEVT","LEAL","LECH","LEVC","HAAB","HASM","HABD","HADM","HADT","HADC","HAMM","HAGN","HALL","HAMA","HAPW","HASO","HADR","HAGM","HABE","HADD","HANG","HAFN","HAGH","HAGB","HAGR","HAJM","HAML","HAMN","HANJ","HANK","HASK","HABB","HAKD","HAGO","HASL","HAJJ","HAKL","HAWR","HAAX","HAHU","HAMK","HAAM","HALA","HABC","HABU","HAMT","HAMR","HASD","HATP","HAMJ","HAWC","EFLP","EFKA","EFKJ","EFSI","EFMI","EFSA","EFVR","EFKI","EFJY","EFHA","EFUT","EFET","EFIV","EFKE","EFKT","EFRO","EFSO","EFTP","EFKK","EFVA","EFJO","EFIT","EFKS","EFOU","EFYL","EFKU","EFPO","EFHK","EFHF","EFHV","EFMA","EFTU","NFNH","NFFN","NFND","NFNA","NFCI","NFNW","NFKD","NFNO","NFNB","NFNK","NFMO","NFNG","NFOL","NFVB","NFNU","NFNL","NFFR","NFNR","NFNS","NFNM","NFCS","NFMA","NFFO","NFNV","NFVL","NFSW","EKVG","EGYP","SFAL","PTKK","PTSA","PTPN","PTYA","LFHU","LFLW","LFLC","LFLB","LFLJ","LFMH","LFLS","LFHP","LFLY","LFLL","LFBK","LFKX","LFHM","LFLP","LFHO","LFLO","LFLU","LFLV","LFHS","LFHY","LFLA","LFSD","LFGJ","LFQG","LFLN","LFRB","LFRD","LFRO","LFRJ","LFRH","LFRU","LFRN","LFRT","LFRQ","LFRV","LFLD","LFLX","LFOZ","LFOT","LFKJ","LFKB","LFKC","LFKF","LFKO","LFKS","LFGA","LFSN","LFSG","LFJL","LFSF","LFSR","LFST","LFSZ","LFQV","LFAQ","LFAC","LFPC","LFQT","LFQQ","LFAT","LFPG","LFPO","LFPN","LFRC","LFRK","LFRG","LFAB","LFOE","LFRF","LFOH","LFOP","LFBA","LFBU","LFBZ","LFBD","LFSL","LFBG","LFBE","LFBL","LFBH","LFBN","LFBX","LFBI","LFBP","LFDN","LFCY","LFMU","LFMK","LFCK","LFTW","LFCI","LFBT","LFNB","LFMT","LFMP","LFCR","LFBO","LFCC","LFJR","LFOU","LFRI","LFEY","LFRE","LFRM","LFOO","LFOV","LFRS","LFRZ","LFMV","LFMR","LFMD","LFMQ","LFNA","LFTZ","LFML","LFMN","LFMI","LFMA","LFNC","LFTH","FOOL","FOGA","FOOD","FOON","FOGQ","FOGJ","FOGR","FOGF","FOGE","FOGG","FOGM","FOGI","FOOY","FOOT","FOGB","FOOE","FOOK","FOGK","FOOR","FOGW","FOOI","FOOH","FOOG","FOOB","FOGV","FOOM","FOGO","EGTB","EGHD","EGHJ","EGLK","EGXH","EGUB","EGBB","EGNH","EGHH","EGKB","EGGD","EGNL","EGVN","EGNC","EGSC","EGBE","EGCN","EGNX","EGTE","EGLF","EGVA","EGBP","EGBJ","EGXU","EGNJ","EGNS","EGHE","EGYM","EGKR","EGNM","EGLC","EGHC","EGKK","EG74","EGLL","EGUL","EGGP","EGGW","EGDL","EGMD","EGCC","EGUN","EGNV","EGNT","EGWU","EGBN","EGHQ","EGSH","EGVO","EGBK","EGTK","EGXC","EGSU","EGHL","EGHR","EGUY","EGTO","EGMC","EGHI","EGXP","EGSS","EGDJ","EGXW","EGDY","EGJB","EGJA","EGMH","EGNO","EGAA","EGAC","EGQB","EGAB","EGAE","EGXJ","EGPD","EGQL","EGPL","EGPR","EGEC","EGPN","EGPH","EGED","EGEF","EGQK","EGPF","EGPI","EGPE","EGPA","EGQS","EGPB","EGET","EGES","EGEN","EGEO","EGPK","EGEP","EGPT","EGEI","EGER","EGPO","EGPU","EGPW","EGEH","EGPC","EGEW","EGTG","EGNR","EGFF","EGFE","EGFH","EGOV","EGKA","TGPY","UGSS","UGSB","UGKO","UGTB","SOCA","SOGS","SOOM","SOOA","SOOG","SOOR","SOOS","DGSI","DGSN","DGAA","DGLE","DGTK","LXGB","BGJN","BGUQ","BGUK","BGQQ","BGTL","BGUM","BGBW","BGCH","BGAA","BGCO","BGGH","BGPT","BGKK","BGSS","BGMQ","BGSF","GBYD","GUOK","GUSB","GUCY","GUFH","GUFA","GUSI","GUXN","GUKU","GULB","GUMA","GUNZ","TFFB","TFFA","TFFM","TFFS","TFFR","TFFC","FGAB","FGSL","FGBT","FGMY","LGAL","LGKV","LGAV","LGKC","LGAG","LGRX","LGAD","LGKA","LGKZ","LGKR","LGKF","LGPZ","LGZA","LGIO","LGTS","LGSA","LGIR","LGST","LGKP","LGKY","LGMK","LGNX","LGSO","LGSR","LGPL","LGKO","LGKS","LGKJ","LGLE","LGML","LGPA","LGRP","LGHL","LGKL","LGSP","LGSY","LGSK","LGLR","LGBL","LGIK","LGHI","LGLM","LGMT","LGSM","MGCB","MGRB","MGSJ","MGGT","MGHT","MGRD","MGPB","MGCR","MGTK","MGPP","MGQZ","MGCT","MGQC","MGPG","MGRT","PGUM","PGUA","GGOV","GGBU","SYBR","SYMR","SYMB","SYBT","SYIB","SYKM","SYPR","SYCJ","SYGO","SYKZ","SYSC","SYMK","SYKA","SYKT","SYMD","SYMM","SYOR","SYAH","SYKS","SYKR","SYLT","SYLP","SYAN","VHHH","MHLC","MHTE","MHIR","MHTJ","MHSC","MHRU","MHSR","MHLM","MHTG","MHAH","MHPC","MHPL","MHLE","MHNJ","MHRO","MHUT","MHMA","MHGS","MHGE","MHJU","MHCS","MHEA","MHYR","MHUL","LDDU","LDZA","LDPL","LDOS","LDLO","LDRI","LDSB","LDSP","LDZD","MTJE","MTCH","MTPX","MTPP","MTCA","MTJA","LHPP","LHBP","LHMC","LHDC","LHSM","WITT","WITM","WITL","WITC","WITN","WADD","WIII","WIHP","WIIG","WIPL","WIPI","WIBJ","WARW","WAMG","WAMY","WIPA","WIPH","WIPU","WIBT","WICC","WICD","WICN","WICA","WICM","WARC","WAHL","WAHP","WARQ","WARS","WAHI","WADY","WARE","WARA","WARR","WART","WIOK","WIOO","WIOP","WIOS","WAOO","WAOC","WRBK","WAON","WIOG","WAOI","WAGG","WAOS","WAOW","WALS","WALK","WALL","WRLC","WALJ","WRLA","WRLH","WALT","WALV","WRLB","WRLP","WRLF","WAGD","WITA","WALR","WIOM","WIPK","WIKD","WIDD","WION","WIDN","WIAG","WILL","WAMA","WAPH","WAPE","WAMR","WAPN","WAPT","WAEE","WAPA","WAPP","WAPK","WAPD","WAMJ","WAMK","WAPF","WAPR","WAPC","WAPG","WAPI","WAPV","WADB","WADL","WADU","WADS","WATA","WATM","WRKB","WATE","WATT","WATO","WATL","WATW","WATC","WATG","WATR","WATS","WADT","WADW","WASG","WASO","WASF","WASI","WASU","WASE","WASK","WASR","WASB","WASM","WASN","WASC","WASS","WAST","WAJA","WABB","WAJB","WAKE","WAJG","WAJJ","WAJC","WAJN","WABT","WABL","WABE","WABK","WAKM","WAKP","WABN","WAJL","WAJM","WAKD","WAKK","WABI","WABR","WAJO","WAKO","WABD","WAJE","WAJS","WABP","WAKT","WAJU","WABV","WAJR","WABG","WAVV","WASW","WAKQ","WABO","WAJI","WIBD","WIBB","WIBS","WIDS","WIPB","WAFJ","WAWT","WAWM","WAWS","WAAA","WAMW","WAFF","WAMP","WAMI","WAWB","WAWW","WAWP","WAWR","WA44","WIME","WIMN","WIMS","WIMB","WIMM","WAMM","WIMK","WAMN","WAMH","WIMP","WIPT","WIDE","WIBR","WIPV","WIPQ","WIPP","WADA","WASA","WIIJ","EINN","EIBN","EICK","EIDL","EILT","EIDW","EICM","EIMN","EIIR","EIIM","EICA","EIKY","EIKK","EIBT","EIKN","EISG","EIWF","LLBS","LLEY","LLET","LLER","LLMR","LLMZ","LLOV","LLNV","LLYT","LLKS","LLIB","LLHA","LLSD","LLBG","OJJR","VOCX","VOPB","VIBY","VOCP","VOPN","VORY","VOTP","VOBZ","VEVZ","VEPG","VEAN","VETJ","VEZO","VEDZ","VEMN","VEGT","VELR","VEKW","VEKM","VEKU","VEJT","VERU","VETZ","VEDH","VEGY","VEMZ","VEPT","VICG","VEBU","VARP","VADN","VIDP","VOGO","VAAH","VABO","VABJ","VABV","VAKS","VAKE","VAJM","VAPR","VARK","VASU","VIHR","VIGG","VIBR","VISM","VIJU","VILH","VISR","VEDB","VERC","VEJS","VOBI","VOBL","VAHB","VOML","VABM","VOMY","VOJV","VOCL","VOKN","VOCI","VOTV","VOAT","VABP","VAGN","VIGR","VAKJ","VAID","VAJB","VIST","VAAK","VABB","VAOZ","VAAU","VAJL","VAKP","VALT","VANP","VAND","VAPO","VARG","VASL","VEIM","VEBI","VELP","VEMR","VEBS","VIJR","VEJP","VERK","VOPC","VIAX","VIAR","VIBT","VIPK","VILD","VIBK","VIJP","VIJO","VIKG","VIKO","VAUD","VOCB","VOMD","VOMM","VONV","VOSM","VOTK","VOTJ","VOTR","VOHY","VOHS","VORG","VOWA","VEAT","VEKR","VIAG","VEGK","VIAL","VIKA","VILK","VEBN","VIDN","VIPT","VECC","VECO","VEBD","VEMH","VEDG","VEBG","ORAA","ORAT","ORMM","ORNI","ORER","ORSU","ORBI","ORBB","ORKK","ORBM","OIIP","OITL","OITP","SVHG","OITU","OITK","OITR","LATI","OITM","OITT","OIBB","OIBH","OITH","OIBQ","OIBJ","OIBP","OIFS","OIFE","OIFM","OISF","OISJ","OISR","OISL","OISS","OIGG","OING","OINE","OIHH","OIHS","OIBA","OIBL","OIKB","OIKQ","OIKP","OIBK","OIBV","OIBS","OICI","OIKM","OIKJ","OIKK","OIKR","OIKY","OICC","OIMT","OIMB","OIMS","OIMC","OIMM","OIMN","OIAA","OIAG","OIAW","OIAD","OIAM","OIAJ","OIAH","OISY","OICS","OICK","OIHR","OINJ","OINN","OINR","OINZ","OIIK","OIMJ","OIIS","OIZB","FMNE","FMNH","FMNA","OIZI","FMNJ","FMNN","FMNS","FMNV","OIZH","OIZC","FMND","OIIE","OIFK","OIII","OIYY","OITZ","BIBF","BIDV","BIHN","BIRK","BIAR","BIBK","BIBV","BIEG","BIFF","BIGR","BIHU","BIRL","BINF","BIOF","BIKP","BIRG","BISI","BITN","BIVO","BIBD","BIBL","BIRF","BIPA","BIKR","BIFM","BIVM","BIKF","BIGJ","BIHK","BIIS","BIRE","BITE","BIGF","BIST","LIBP","LIAP","LIBC","LICR","LICA","LIRN","LIRI","LIPE","LIPK","LIDR","LIPR","LIPA","LIPQ","LIPD","LIRF","LIMG","LIMJ","LIML","LIMC","LIPO","LIPY","LIMZ","LIMF","LIBR","LIBD","LIBF","LIBN","LIBG","LIEA","LIEE","LIED","LIER","LIEO","LIET","LICB","LICC","LICD","LICZ","LICJ","LICG","LICT","LIRJ","LIRQ","LIRS","LIQL","LIRP","LIQS","LIPB","LIRZ","LIMW","LIDB","LIPH","LIPZ","LIPT","LIPX","EGJJ","MKTP","MKKJ","MKJP","MKJS","MKBS","MKNG","OJAQ","OJAM","OJMF","OJMN","OJAI","RJGG","RJNA","RJSK","RJSR","RJSA","RJSH","RJSM","RJOM","RJNF","RJFF","RJFR","RJSF","RJOA","RJBH","RJEC","RJCH","RJCK","RJEB","RJCM","RJCB","RJEO","RJCR","RJER","RJCN","RJCW","RJBT","RJAH","RJNK","RJNW","RJSI","RJOT","RJKA","RJKI","RJFK","RJFC","RJKB","RORY","RJKN","RJFG","RJTA","RJOK","RJDA","RJFT","RJSS","RJFM","RJAF","RJFE","RJDB","RJFU","RJDU","RJDT","RJSN","RJSD","RJFO","RJOB","RORA","RODN","RORH","RORE","ROIG","ROKR","RORK","ROMD","ROMY","ROYN","ROAH","RORS","RORT","ROKJ","RJBB","RJFS","RJOW","RJOC","RJNS","RJOS","RJTH","RJTT","RJAW","RJAM","RJTQ","RJAA","RJTO","RJNO","RJOR","RJOH","RJNT","RJBD","RJSC","RJSY","RJOI","RJDC","HKJK","HKGA","HKAM","HKKG","HKKR","HKML","HKKI","HKUK","HKNY","HKLU","HKMA","HKMY","HKMB","HKMK","HKMO","HKNW","HKNK","HKKE","HKNI","HKSB","HKKL","HKHO","HKES","HKFG","HKLK","HKLO","HKLY","HKEL","HKKT","HKWJ","UAFM","UAFO","VDBG","VDKH","VDKK","VDKT","VDSV","VDMK","VDPP","VDST","VDRK","VDSR","NGUK","NGAB","NGTB","NGTR","NGTU","NGBR","NGKT","NGMA","NGMN","NGMK","NGNU","NGTO","NGON","NGTE","NGTM","NGTA","NGTS","PCIS","PLCH","FMCV","FMCH","FMCN","FMCI","TKPK","TKPN","ZKHM","ZKSD","ZKWS","ZKUJ","ZKPY","ZKSE","RKPK","RKTU","RKTI","RKTP","RKNN","RKNW","RKNY","RKJU","RKJK","RKJJ","RKJB","RKJY","RKSI","RKSO","RKSW","RKPE","RKPS","RKTH","RKTN","RKTL","RKPU","RKTY","RKPC","RKPD","OKAJ","OKBK","MWCB","MWCR","MWCL","UAAL","UAAA","UAAR","UACK","UATT","UACC","UATG","UARR","UAOL","UATE","UAII","UASB","UASP","UAAH","UAKD","UAKK","UAUR","UAUU","UAOO","UASS","UASK","UACP","UADD","VLAP","VLHS","VLKG","VLPS","VLSN","VLTK","VLLN","VLLB","VLOS","VLSV","VLSK","VLVT","VLSB","VLXK","OLBA","OLKA","TFFG","TLPC","TLPL","VCCG","VCCB","VCCS","VCCT","VCCA","VCCH","VCCJ","VCRI","VCCK","VCCW","VCBI","VCCN","VCCC","GLBU","GLTN","GLST","GLVA","GLRB","GLCP","GLMR","GLNA","GLGE","FXLR","FXPG","FXSS","FXMF","FXMM","FXSM","FXNK","FXMK","FXTK","FXLK","FXSK","FXQN","FXQG","FXLS","FXMA","FXSH","FXTA","EYVI","EYKA","EYPA","EYPP","EYSA","ELLX","EVDA","EVRA","EVLA","EVVA","HLGN","HLLQ","HLZN","HLON","HLKF","HLMB","HLNR","HLLB","HLGT","HLMS","HLTD","HLLS","HLGD","HLLM","HLLT","HLZW","HLUB","GMMD","GMMC","GMMN","GMMB","GMFK","GMAZ","GMMZ","GMFF","GMFM","GMMF","GMAT","GMMW","GMFO","GMFB","GMML","GMMA","GMMH","GMMX","GMMS","GMMY","GMME","GMAD","GMMI","GMTA","GMTT","LUBL","LUKK","LYBR","LYPG","LYTV","FMME","FMFE","FMMI","FMSU","FMMX","FMSI","FMSM","FMSG","FMSF","FMSK","FMNQ","FMNO","FMNL","FMNM","FMMO","FMNT","FMMR","FMNW","FMMG","FMNF","FMNX","FMNP","FMNG","FMMU","FMMQ","FMMS","FMMT","FMMY","FMMH","FMMZ","FMNR","FMNC","FMSY","FMSV","FMML","FMSD","FMMK","FMSJ","FMMV","FMSR","FMSL","FMSN","FMST","FMSZ","FMSB","FMSC","FMMC","FMMN","PKMA","PKWA","PKMJ","MLIP","LWOH","LWSK","GABS","GAGO","GAYE","GAKA","GAKY","GANR","GANK","GAMB","GASK","GAKO","GAGM","GATB","VYPN","VBHD","VYAN","VYPY","VYBM","VYMK","VYPT","VYLK","VYPA","VYPP","VYGG","VYKU","VYMW","VYPK","VYPU","VYHN","VYMD","VYNT","VYBG","VYCZ","VYMM","VYYE","VYSW","VYGW","VYKP","VYMN","VYTD","VYHL","VYKI","VYKL","VYMY","VYHH","VYKG","VYLS","VYMT","VYMO","VYMS","VYNS","VYTL","VYKT","VYME","VYDW","VYBP","VYYY","ZMTG","ZMUL","ZMBH","ZMBN","ZMCD","ZMMG","ZMTL","ZMAT","ZMDN","ZMUH","ZMBS","ZMKD","ZMHG","ZMMN","ZMDZ","ZMAH","ZMHU","ZMHH","ZMBR","ZMBU","ZMCK","ZMUB","ZMUG","VMMC","PGRO","PGSN","PGWT","TFFF","GQPA","GQNF","GQNE","GQPP","GQNK","GQNS","GQNJ","GQNA","GQNU","GQNO","GQNT","GQNL","GQNC","GQND","GQNI","GQPF","GQPZ","GQNH","GQNB","TRPG","LMML","FIMP","FIMR","VRMD","VRMV","VRMT","VRMF","VRMH","VRMM","VRMO","VRMK","VREI","VRMG","VRNT","FWCL","FWCD","FWKA","FWKG","FWLK","FWKI","FWCM","FWMG","FWMY","FWUU","FWDW","FWSM","MMAS","MX86","MMGR","MMLP","MMLT","MMMG","MMPL","MMSD","MMES","MMML","MMSF","MMTJ","MMCE","MMCP","MMCO","MMPQ","MMTP","MMTG","MMCS","MMCU","MMCG","MMCC","MMMV","MMPG","MMIO","MMTC","MMIA","MMZO","MMDO","MMLO","MMCY","MMAA","MMZH","MMGL","MMPR","MMJC","MMMX","MMSM","MMTO","MMLC","MMMM","MMPN","MMZM","MMCB","MMEP","MMMY","MMAN","MMBT","MMIT","MMOX","MMPS","MMSZ","MMPB","MMHC","MMQT","MMCM","MMUN","MMCZ","MMIM","MMSP","MMTN","MMCL","MMLM","MMMZ","MMCN","MMCA","MMGM","MMHO","MMNG","MMPE","MMVA","MMCV","MMMA","MMDM","MMNL","MMRX","MMTM","MMJA","MMMT","MMPA","MMVR","MMCT","MMMD","MMZC","WMKJ","WMAU","WMKA","WMKL","WMKC","WMKM","WMKD","WMAN","WMBT","WMKI","WMPA","WMBA","WMBI","WMKB","WMKP","WBKK","WBKN","WBKG","WBKT","WBKL","WBKD","WBKP","WBKR","WBKS","WBKA","WBKO","WBKH","WBKE","WBKM","WBKW","WBGZ","WBGQ","WBGC","WBGN","WBGB","WBGG","WBGP","WBGF","WBGL","WBGJ","WBGD","WBGU","WBGW","WBGK","WBGM","WBGR","WBMU","WBGI","WBGS","WBGY","WBTM","WMKK","WMSA","WMKE","WMPR","WMKN","FQIB","FQLU","FQMD","FQMP","FQPB","FQXA","FQIN","FQVL","FQCH","FQIA","FQMA","FQPO","FQAG","FQNP","FQNC","FQCB","FQLC","FQBR","FQTT","FQQL","FYAR","FYME","FYSM","FYWB","FYSS","FYAA","FYKB","FYKT","FYLZ","FYOG","FYSA","FYRU","FYWE","FYMG","FYNG","FYWH","FYOP","FYTE","FYGB","FYOS","FYOA","FYHI","FYNA","FYOO","FYMO","FYTM","FYGF","FYOW","FYLS","FYKM","FYOE","NWWC","NWWD","NWWK","NWWQ","NWWP","NWWU","NWWM","NWWE","NWWW","NWWA","NWWL","NWWR","NWWV","DRZA","DRZL","DRRM","DRRN","DRRT","DRZR","YSNF","DNAA","DNJO","DNYO","DNAI","DNMK","DNMA","DNCA","DNAS","DNSU","DNBE","DNEN","DNGO","DNIM","DNKA","DNZA","DNKN","DNIL","DNMM","DNMN","DNAK","DNIB","DNPO","DNSO","MNBZ","MNPC","MNRT","MNSI","MNWP","MNBL","MNNG","MNCI","MNMG","MNSC","MNCE","EHGG","EHLE","EHLW","EHBK","EHEH","EHGR","EHVK","EHWO","EHAM","EHKD","EHTW","EHSB","EHRD","ENGM","ENKL","ENAT","ENBS","ENBV","ENHK","ENHF","ENHV","ENKR","ENNA","ENMH","ENSS","ENVD","ENHA","ENBR","ENSO","ENAL","ENOV","ENKB","ENML","ENVA","ENAN","ENBN","ENBO","ENEV","ENLK","ENMS","ENRA","ENNK","ENRS","ENSK","ENST","ENSH","ENFG","ENRY","ENHD","ENZV","ENBL","ENFL","ENSD","ENSG","ENOL","ENNM","ENRO","ENRM","ENNO","ENSN","ENDU","ENSR","ENTC","ENCN","ENTO","VNKT","VNLT","VNBR","VNNG","VNSK","VNBL","VNJS","VNMA","VNPK","VNJP","VNRC","VNDP","VNST","VNJL","VNBJ","VNVT","VNRB","VNTR","VNBW","VNDT","VNMN","VNCG","VNTJ","VNBP","VNGK","VNMG","VNSI","VNDG","VNRP","VNRK","VNJI","VNLD","VNLK","VNPL","VNRT","VNSB","VNBT","VNBG","VNDL","VNDH","VNSR","VNTP","ANYN","NIUE","NZAA","NZAR","NZCX","NZGB","NZKE","NZRO","NZTG","NZWK","NZAS","NZCH","NZGT","NZKI","NZTU","NZUK","NZCI","NZGS","NZNR","NZWO","NZOH","NZPM","NZWU","NZWB","NZPN","NZNS","NZDA","NZKT","NZKK","NZKO","NZWR","NZLX","NZDN","NZOU","NZWF","NZQN","NZNV","NZMF","NZMC","NZRC","NZMO","NZNP","NZTK","NZMK","NZHN","NZMA","NZRA","NZTO","NZTH","NZAP","NZWT","NZMS","NZPP","NZWN","NZGM","NZHK","NZWS","OOMS","OOGB","OOBR","OOFD","OOLK","OOSH","AYNO","OOKB","OORQ","OOMA","OOSR","FZSB","MDLR","OOMX","OOSA","OOTH","MPBO","MPCH","MPDA","MPSM","MPEJ","MPJE","MPLP","MPOA","MPCE","MPHO","MPWN","MPMG","MPTO","MPVR","MPSA","SPPY","SPLN","SPHZ","SPEO","SPHY","SPQU","SPHO","SPAY","SPJR","SPJE","SPNC","SPIL","SPIM","SPGM","SPZA","SPSO","SPJN","SPJJ","SPMF","SPRU","SPHI","SPMR","SPZO","SPQT","SPDR","SPMS","SPBR","SPTU","SPSY","SPLO","SPUR","SPYL","SPJL","SPBL","SPJI","SPBB","SPJA","SPOA","SPST","SPTN","SPME","SPAR","SPCL","NTAM","NTAR","NTAV","NTAT","NTMN","NTMD","NTMU","NTMP","NTTB","NTTH","NTTP","NTAA","NTTR","NTTE","NTGA","NTHE","NTGD","NTGU","NTKF","NTGF","NTGB","NTKH","NTGJ","NTGH","NTTO","NTKA","NTGK","NTKT","NTGM","NTGV","NTGN","NTKN","NTGW","NTGP","NTGQ","NTGE","NTTG","NTKK","NTKO","NTGC","NTKM","NTGT","NTGO","NTKR","NTTX","NTUV","NTGI","NTGY","NTTM","NTTU","AYBK","AYIA","AYIQ","AYEF","AYER","AYFA","AYGF","AYHH","AYKH","AYJO","AYKQ","AYRA","AYEA","AYOP","AYLS","AYMP","AYMA","AYQQ","AYRK","AYQO","AYTY","AYTI","AYWT","AYCH","AYRI","AYGL","AYMV","AYNI","AYTK","AYSH","AYZI","AYXO","AYVO","AYUI","AYWQ","AYWK","AYAN","AYAY","AYDI","AYGA","AYOK","AYLG","AYOL","AYMW","AYNY","AYTR","AYUC","AYWO","AYWD","AYAO","AYKM","AYKK","AYQA","AYSK","AYSS","AYBA","AYWB","AYJS","AYKR","AYMD","AYNA","AYSD","AYWH","AYMO","AYYM","AYAG","AYGN","AYKA","AYMS","AYAX","AYUM","AYBC","AYBG","AYBP","AYBR","AYBU","AYNS","AYDE","AYDN","AYEN","AYFI","AYGP","AYGI","AYGG","AYHE","AYHU","AYID","AYII","AYKB","AYNB","AYOE","AYKD","AYRO","AYNM","AYYR","AYYE","AYKT","AYLB","AYNZ","AYLT","AYLN","AYLP","AYLX","AYLO","AYSX","AYMJ","AYMI","AYMC","AYMB","AYOG","AYOM","AYPD","AYSP","AYXI","AYEW","AYSW","AYQS","AYTP","AYTZ","AYTS","AYTW","AYWS","AYWC","AYWU","AYXE","AYZA","AYAF","AYBD","AYDO","AYDR","AYEO","AYEB","AYGC","AYGX","AYNJ","AYNC","AYPQ","AYPY","AYYO","AYRE","AYSF","AYSG","AYCS","AYTF","AYUE","AYBZ","AYNX","AYEE","AYKV","AYKY","AYMZ","AYSE","AYWG","AYKO","AYGR","AYTU","AYPE","AYAT","AYBF","AYEV","AYHB","AYHO","AYHF","AYOQ","AYOW","AYNN","AYLI","AYOO","AYKG","AYDL","AYKU","AYKW","AYMN","AYPO","AYMQ","AYRM","AYMR","AYBM","AYPB","AYPJ","AYVM","AYTA","AYUR","AYWF","AYIW","AYBL","AYCG","AYGJ","AYGT","AYHK","AYKC","AYLL","AYSL","AYSV","AYTG","AYVL","AYUZ","AYWJ","AYIX","AYVN","AYND","AYBO","AYCB","AYNE","AYMH","AYKJ","AYAQ","AYDK","AYPG","AYSJ","AYTV","AYYL","AYAE","AYVW","AYYK","AYAK","AYGU","AYAA","AYAM","AYAI","AYAW","AYET","AYBQ","AYBH","AYBI","AYDU","AYDB","AYEL","AYFR","AYFE","AYFU","AYGS","AYUP","AYML","AYGV","AYIO","AYTO","AYIM","AYYP","AYUY","AYLU","AYEH","AYIY","ATNR","AYOB","AYOJ","AYOF","AYOV","AYZS","AYPC","AYRG","AYSO","AYSA","AYZN","AYSU","AYTB","AYTH","AYTE","AYTN","AYQL","AYTT","AYNU","AYKI","AYXW","AYXP","AYED","RPME","RPVK","RPVE","RPLP","RPVS","RPUR","RPLB","RPUO","RPUB","RPVT","RPLH","RPUT","RPUD","RPUN","RPMH","RPVR","RPUV","RPLS","RPVM","RPMQ","RPMD","RPLI","RPSG","RPVI","RPUY","RPUS","RPMI","RPVO","RPVA","RPMC","RPMM","RPUW","RPVJ","RPLU","RPUM","RPUH","RPMY","RPMO","RPLL","RPMA","RPVB","RPVD","RPVF","RPLO","RPEN","RPVP","RPSD","RPSV","RPVV","RPLC","RPLE","RPVU","RPVC","RPMR","RPMJ","RPNS","RPMS","RPMF","RPMW","RPMU","RPMN","RPMV","RPMG","PRNO","RPMP","RPMZ","OPMF","OPRT","OPMA","OPDB","OPGD","OPJI","OPKH","OPLL","OPOR","OPPG","OPPI","OPZB","OPSB","OPSU","OPTU","OPQT","OPCL","OPGT","OPSD","OPIS","OPBN","OPCH","OPDI","OPKT","OPPC","OPPS","OPSS","OPTA","OPWN","OPBW","OPDG","OPLA","OPFA","OPMT","OPMI","OPRK","OPSR","OPST","OPTH","OPDD","OPKD","OPJA","OPKC","OPMJ","OPMP","OPSW","OPSK","OPSN","OPNH","EPWR","EPBY","EPLL","EPBP","EPLB","EPZG","EPKK","EPRA","EPWA","EPMO","EPRZ","EPGD","EPRU","EPKT","EPSY","EPPO","EPKZ","EPSC","LFVP","LFVM","TJSJ","TJPS","TJIG","LVGZ","LPBJ","LPBR","LPBG","LPCO","LPFR","LPPM","LPCS","LPPT","LPSI","LPPR","LPMA","LPPS","LPCR","LPFL","LPGR","LPHR","LPPD","LPPI","LPSJ","LPAZ","LPLA","LPCH","LPVR","LPVZ","PTRO","SGOL","SGES","SGPJ","SGME","SGFI","SGAS","SGBN","SGCO","SGEN","SGAY","SGPI","OTBD","OTHH","OTBH","FMEE","FMEP","LRAR","LRBC","LROD","LRCS","LRCL","LRCK","LRCV","LRIA","LROP","LRBM","LRTM","LRSM","LRSB","LRSV","LRTR","LRTC","LYBE","LYBT","LYNI","LYUZ","UNBG","UNBB","UHBB","UHBI","UHBW","ULAA","ULAS","ULKK","ULAL","URWA","UWUB","UWUF","UWUK","UWUU","UUOB","UUBP","UECT","UIUU","URMG","USCC","USCM","UHMA","UHMK","UHMO","UHMD","UHMP","UWKS","URML","URMS","UIBB","UIKE","UIII","UUBI","UIKK","UIKB","UIBS","UITT","URMN","UMKK","URWI","UUBC","UHPP","ULPB","UNEE","UNWW","UHNB","UHKM","UHHH","UHKK","UHNN","UHOO","UNAA","USHQ","USHH","USHI","USRK","USHK","USRN","USNN","USHN","USHS","USNR","USRR","USHU","USKK","UUYI","UUYP","UUYY","UUYH","UUYS","UUYX","UUYW","UUBA","URKA","URSS","URKG","URKK","UNKS","UODD","UNII","UOHH","UOII","UNKL","UOOO","UNIP","UOTT","USUU","UUOK","ULSS","ULLI","UUOL","UHMM","UHMW","UWKJ","UWPS","UUBB","UUEE","UUMU","UUMO","UUBW","ULMK","ULMM","ULDD","ULAM","ULDW","ULNN","UWGG","UNNT","UNOO","UWOR","UWOO","UUOR","UWPP","USPP","UHTG","UHWP","UHWW","ULOO","ULOL","URRR","URRP","URRT","URRY","UUWR","UEEA","UESG","UESO","UESS","UEMM","UEST","UEMH","UERR","UEMA","UELL","UENN","UEMO","UERO","UERP","UESK","UEBS","UENS","UERS","UEBT","UERL","UEMU","UEMT","UENI","UENW","UEEE","UEVV","UESU","UHSB","UHSM","UHSK","UHSI","UHSN","UHSH","UHSS","UHSO","UWWW","UWSB","UWSS","URMO","UUBS","URMM","URMT","USSS","UUOT","UWKD","UWKE","UWKB","UNSS","UNTT","UUBT","UUEM","USTR","USTO","UNKY","USII","UWLL","UWLW","ULWC","ULWW","URWW","ULWU","UUOO","USDB","USDP","USRO","USMU","USMM","USDA","USDD","USDS","USDU","USDK","UUDL","UUBK","UIAA","HRYU","HRYG","HRZA","HRYI","HRYR","OEBA","OERR","OERF","OETR","OESK","OEGT","OEMA","OEAO","OEYN","OEGS","OEZL","OEPS","OEDW","OERK","OESL","OEWD","OEPA","OEDR","OEDF","OEAH","OEKK","OEAB","OEBH","OEKM","OEHL","OEGN","OEJN","OETF","OENG","OESH","OEWJ","OENN","OETB","AGTI","AGGY","AGGC","AGKG","AGGJ","AGGH","AGKW","AGGI","AGNA","AGGP","AGGF","AGJO","AGGV","AGGK","AGGT","AGAR","AGAF","AGGA","AGAT","AGGQ","AGGB","AGGR","AGGU","AGGL","AGGE","AGBT","AGGS","AGEV","AGOK","AGGN","AGKU","AGGO","AGGM","AGRM","AGRC","AGBA","FSSB","FSSD","FSDR","FSSF","FSPP","FSIA","HSFA","HSDZ","HSWD","HSKG","HSGF","HSKA","HSNW","HSSK","HSFS","HSDN","HSDB","HSMN","HSSW","HSPN","HSAT","HSGG","HSNN","HSOB","HSLI","HSNH","HSGN","HSZA","HSKI","ESDF","ESSD","ESUE","ESKM","ESSK","ESNH","ESNY","ESSV","ESMT","ESND","ESNZ","ESGJ","ESSF","ESMQ","ESMO","ESSW","ESMX","ESNX","ESNG","ESNQ","ESPA","ESUP","ESKK","ESOE","ESSL","ESSP","ESTA","ESMK","ESSU","ESSA","ESOH","ESOK","ESST","ESUT","ESNL","ESNS","ESUD","ESNU","ESNV","ESNK","ESNO","ESNN","ESGG","ESGP","ESGR","ESGL","ESGT","WSAP","WSSS","WSAT","WSSL","FHAW","FHSH","ENSB","LZLU","LZSL","LZIB","LJPZ","LZKZ","LJMB","LZPW","LZTT","LJLJ","LZPP","LZZI","GFKE","GFYE","GFKB","GFBN","GFGK","GFBO","GFLL","GFHA","GOOY","GOOK","GOTK","GODK","GOSM","GOSP","GOSR","GOSS","GOTB","GOTS","GOTT","GOBD","GOGS","GOGG","HCMM","HCMA","HCMF","HCMS","HCMC","HCMG","HCMB","HCMD","HCMJ","HCMK","HCMO","HCMR","HCME","HCMU","HCMV","HCMI","HCMH","SMCO","SMBN","SMMO","SMWA","SMNI","SMJP","SMZO","SMCA","SMDA","SMTP","SMDO","SMPA","SMST","SMWS","HJJJ","HSMK","HSSM","HSWW","FPPR","FPST","MSSS","MSLP","TNCM","OSKL","OSLK","OSDZ","OSDI","OSAP","OSPR","FDMS","FDSK","MBGT","MBMC","MBNC","MBPI","MBPV","MBSY","MBSC","FTTI","FTTY","FTTS","FTTM","FTTK","FTTJ","FTTU","FTTL","FTTD","FTTP","FTTB","FTTA","FTTC","FTTN","FTTH","DXNG","DXXX","VTUO","VTCC","VTCT","VTBF","VTSE","VTUK","VTSG","VTBS","VTBD","VTCL","VTUL","VTBL","VTCH","VTBK","VTUW","VTUQ","VTPI","VTSF","VTCN","VTSC","VTSK","VTPB","VTPP","VTCP","VTSP","VTPH","VTSR","VTBU","VTUV","VTUI","VTSS","VTSH","VTPO","VTSB","VTSM","VTUJ","VTPM","VTPT","VTST","VTBO","VTUU","VTUD","VTPU","UTDD","UTDT","UTDK","UTDL","WPAT","WPEC","WPDL","WPMN","WPOC","WPDB","WPVQ","UTAK","UTAA","UTAT","UTAV","UTAM","DTTG","DTTF","DTKA","DTTJ","DTMB","DTTX","DTNH","DTTR","DTTZ","DTTA","NFTL","NFTO","NFTP","NFTE","NFTF","NFTV","LTAF","LTAG","LTCP","LTAH","LTCO","LTAP","LTAD","LTAC","LTAI","LTFG","LTBD","LTBG","LTBF","LTFD","LTCJ","LTCU","LTBE","LTBR","LTBH","LTFK","LTAY","LTCC","LTCA","LTCD","LTCE","LTBY","LTBI","LTAJ","LTCW","LTDA","LTCT","LTFC","LTBA","LTFM","LTFJ","LTCN","LTCF","LTAL","LTAU","LTBQ","LTAN","LTBZ","LTAT","LTCR","LTFE","LTBV","LTBS","LTCK","LTAZ","LTCB","LTFO","LTFH","LTCS","LTCH","LTCL","LTCM","LTCV","LTAR","LTBU","LTAW","LTCG","LTBO","LTCI","LTAS","TTPP","TTCP","NGFU","RCKU","RCPO","RCYU","RCLM","RCKH","RCBS","RCFG","RCMT","RCCM","RCQC","RCWA","RCKW","RCDC","RCMQ","RCNN","RCSS","RCGI","RCLY","RCFN","RCTP","HTAR","HTLM","HTDA","HTDO","HTGE","HTIR","HTBU","HTKA","HTKJ","HTPE","HTKI","HTLI","HTNA","HTGR","HTMU","HTMB","HTZA","HTMT","HTMI","HTMW","HTNJ","HTMA","HTSU","HTSO","HTMD","HTSY","HTSN","HTTB","HTTG","UKFK","UKFF","UKKE","UKKL","UKLN","UKDD","UKDR","UKCC","UKCK","UKCM","UKLI","UKHH","UKOH","UKLH","UKKG","UKKK","UKBB","UKCW","UKLL","UKON","UKOO","UKHP","UKLR","UKFB","UKHS","UKLT","UKWW","UKLC","UKLU","UKDB","UKDE","UKKV","HUAR","HUGU","HUJI","HUKF","HUEN","HUKS","HUMI","HUMA","HUPA","HUSO","HUTO","PWAK","KAIV","KALX","KANB","KASN","KAUO","KBFM","KBHM","KDCU","KDHN","KEDN","KEUF","KGAD","KJKA","KHAB","KHSV","KHUA","KMGM","KMOB","KMSL","KMVC","KMXF","KNBJ","KOZR","KPLR","KSEM","KTCL","KTOI","PAFM","PADK","PADQ","KPHH","PFAL","PAGN","PAWI","PAAK","PFAK","PAKH","PAKN","PAKP","PANC","PANI","PANT","PANV","PARC","PATQ","PAAT","PABE","PAGQ","PABI","PABL","PABM","PABR","PABA","PABT","PABG","PACD","PACV","PACE","PACI","PFCL","PACX","PACK","PACY","PACZ","PADL","PADE","PADU","PAEG","PAED","PAEE","PAII","PAEH","PAEI","PFEL","PAEL","PAEM","PAEN","PANN","PAFA","PAFB","PANR","PAFR","PAFW","PFYU","PAGA","PAGM","PAGB","PAGK","PAGL","PAGZ","PAGS","PAHC","PAOH","PAHN","PAHO","PAHP","PAHL","PAHU","PAHY","PAIK","PAIG","PAKO","PAIL","PACR","PAJN","PAFE","PAKV","PAKD","PAKF","PAJZ","PAKK","PADY","PALG","PALB","PAKW","PAMB","PANW","PFKO","PAPC","PAKI","PAPE","PASM","PAKT","PFKT","PFKA","PAVC","PAVL","PAGG","PAQH","PFKW","PAKY","PFKU","PAKL","PAMH","PALN","PALU","PAMC","PAIN","PAMD","PADM","PAML","PAMO","PAMR","PAMM","PABK","PAMX","PAMY","PFCB","PAFS","PAOU","PAGT","PANO","PAQT","PANU","PAOB","PAOM","PAOO","KORI","PAOR","PFNO","PAOT","PAAQ","PAOC","PAPO","PAPN","PPIZ","PAPK","PAAL","PAPR","PAPG","PALJ","PAAP","PAPH","PAPM","PARY","PADG","PARS","PASC","PACM","PASD","PAGY","PAGH","PASH","PAHX","PASI","PFSH","PASW","PASL","PAMK","PASP","PASN","PASO","PAPB","PASA","PASV","PAWD","PASX","PASY","PATA","PATK","PFTO","PATE","PATL","PATC","PATG","PAST","PAUM","PAUN","PAIM","PAKU","PAVA","PAVD","PAVE","PAIW","PAWB","PALR","PASK","PAWM","PANA","PAUO","PAWG","PACS","PFWS","PAWN","PAWS","PAEW","PAYA","KAVQ","KIWA","KBXK","KCFT","KCGZ","KDGL","KDMA","KDUG","KDVT","KFHU","KFLG","KGCN","KGYR","KHII","KIFP","KIGM","KINW","KLGF","KLUF","KFFZ","KMZJ","KOLS","KPGA","KPHX","KPAN","KPRC","KSAD","KSDL","KSEZ","KSJN","KSOW","KTUS","KTYL","KNYL","KAGO","KARG","KAWM","KBVX","KBYH","KCDH","KCVK","KCRT","KELD","KFCY","KFLP","KFSM","KFYV","KHEE","KHKA","KHOT","KHRO","KJBR","KLIT","KLRF","KMPJ","KMXA","KPBF","KPGR","KROG","KSGT","KSLG","KASG","KSRC","KTXK","KBPK","KXNA","KACV","KAHC","KAPC","KAPV","KAUN","KAVX","KBAB","KBFL","KBIH","KBLH","KBLU","KBNG","KBUR","KBWC","KBYS","KCCB","KCCR","KCEC","KCIC","KCRQ","KCLR","KCNO","KCPM","KCRO","KCXL","KDAG","KEDW","KEED","KEKA","KEMT","KFAT","KFCH","KFUL","KHAF","KHHR","KCVH","KHMT","KHWD","KIPL","KIYK","KKIC","KLAX","KLGB","KLPC","KLSN","KLVK","KMAE","KMCC","KMCE","KMER","KMHR","KMHV","KMIT","KMMH","KMOD","KMRY","KMYF","KMYV","KNJK","KNKX","KNLC","KDVO","KNRC","KNRS","KNTD","KNUQ","KNZY","KOAK","KOAR","KOKB","KONT","KOVE","KOXR","KPAO","KPMD","KPOC","KPRB","KPSP","KPTV","KPVF","KRAL","KRBL","KRDD","KRHV","KRIR","KRIV","KMPI","KSAC","KSAN","KSAS","KSBA","KSBD","KSBP","KSCK","KSDM","KSEE","KSFO","KSIY","KSJC","KSMF","KSMO","KSMX","KSNA","KSNS","KSPA","KIZA","KSQL","KSTS","KSMS","KSUU","KSVE","KSZN","KSZP","KTRK","KTLR","KTNP","KTOA","KTRM","KTSP","KTVL","KUDD","KUKI","KVBG","KVCV","KVIS","KVNY","KWHP","KWJF","KWLW","KWVI","KAFF","KAKO","KALS","KAPA","KASE","KBKF","KBJC","KCEZ","KCAG","KCOS","KDEN","KDRO","KEGE","KFCS","KFNL","KGJT","KGUC","KGWS","KGXY","KHDN","KLAA","KLIC","KLXV","KMTJ","KPSO","KPUB","KRIL","KSBS","KANK","KSTK","KTAD","KTEX","KBDU","KBDL","KBDR","KDXR","KGON","KHFD","KHVN","KOXC","KDOV","KGED","KILG","KAAF","KAPF","KAVO","KBCT","KBOW","KCDK","KCEW","KCLW","KCOF","KCOI","KCRG","KCTY","KDAB","KDTS","KECP","KEGI","KEYW","KFLL","KFMY","KFPR","KFXE","KGIF","KGNV","KHST","KHWO","KIMM","KISM","KJAX","KLAL","KLCQ","KLEE","KLNA","KMCF","KMCO","KMIA","KMLB","KMKY","KMTH","KNEN","KNIP","KNPA","KNQX","KNRB","KNSE","KNUN","KOBE","KOCF","KOPF","KORL","KPAM","KPBI","KPGD","KPHK","KPIE","KPNS","KPMP","KRSW","KSEF","KSFB","KSPG","KSRQ","KSUA","KTIX","KTLH","KTMB","KTNT","KTPA","KTPF","KSGJ","KVNC","KVPS","KVQQ","KVRB","KZPH","KABY","KAGS","KAHN","KATL","KAYS","KBGE","KBQK","KCSG","KDBN","KDNL","KDNN","KFTY","KGVL","KLGC","KLHW","KLSF","KLZU","KMAC","KMCN","KMGE","KMGR","KMLJ","KMQW","KMUL","KPDK","KPIM","KRMG","KSAV","KSSI","KSVN","KSYV","KTBR","KTMA","KTOC","KTVI","KVAD","KVDI","KVLD","KWDR","KWRB","PHBK","PHSF","NSFQ","PHDH","PHHI","PHNL","PHHN","PHTO","PHJH","PHJR","PHKO","PHLI","PHNY","PHLU","PMDY","PHMK","PHMU","PHNG","PHOG","PHPA","PHUP","KBOI","KBYI","KLLJ","KCOE","KGNG","KIDA","KGIC","KLWS","KMLD","KMUO","KMYL","KPIH","KRXE","KSMN","KSUN","KTWF","KALN","KARR","KBLV","KBMI","KCIR","KCMI","KCPS","KDEC","KDNV","KDPA","KDVN","KENL","KEOK","KFEP","KGBG","KGRE","KHSB","KIJX","KIKK","KJOT","KLOT","KLWV","KMDH","KMDW","KMLI","KMQB","KMTO","KMVN","KMWA","KOLY","KORD","KPIA","KRFD","KSAR","KSLO","KSPI","KSQI","KUGN","KUIN","KVLA","KVYS","KAID","KANQ","KBFR","KBMG","KCEV","KBAK","KEKM","KEVV","KFRH","KFWA","VOGB","KGFD","KGSH","KGUS","KHLB","KHNB","KIND","KLAF","KPPO","KIMS","KMGC","KMIE","KMZZ","KOKK","KRCR","KRID","KRZL","KSBN","KSER","KSIV","KSMD","KVPZ","KAIO","KALO","KAMW","KAXA","KBNW","KBRL","KCBF","KCCY","KCID","KCIN","KCSQ","KCWI","KDBQ","KDEH","KDNS","KDSM","KEBS","KEFW","KEST","KFFL","KFSW","KFOD","KFXY","KHPT","KICL","KIDG","KIFA","KIOW","KLRJ","KMCW","KMIW","KMPZ","KMUT","KMXO","KOMA","KOOA","KOTM","KPOH","KPRO","KSLB","KSPW","KSUX","KTNU","KANY","KBEC","KCBK","KCEA","KCFV","KCNK","KCNU","KDDC","KEQA","KEMP","KEWK","KFLV","KFOE","KFRI","KFSK","KGBD","KGCK","KGLD","KHLC","KHUT","KHYS","KIAB","KICT","KIDP","KIXD","KLBL","KLWC","KLYO","KMHK","KMPR","KOJC","KPPF","KPTS","KPTT","KRSL","KSLN","KTOP","KWLD","KBRY","KBWG","KCEY","KCVG","KEKX","KFFT","KFTK","KGLW","KHOP","KLEX","KLOU","KLOZ","KOWB","KPAH","KPBX","KSDF","KSME","KAEX","KARA","KBAD","KBTR","KBXA","KCWF","KDRI","KDTN","KESF","KHUM","KLCH","KLFT","KMLU","KMSY","KNBG","KNEW","KOPL","KPOE","KPTN","KRSN","KSHV","KAUG","KBGR","KBHB","KCAR","KIZG","KHUL","KIWI","KLEW","KMLT","KBXM","KOLD","KOWK","KPNN","KPQI","KPWM","KRKD","KSFM","KFVE","KWVL","KADW","KANP","KAPG","KBWI","KCBE","KCGE","KCGS","KESN","KFDK","KFME","KGAI","KHGR","KMTN","KNHK","KOXB","KSBY","KACK","TJAB","KBAF","KBED","KBOS","TJBQ","KBVY","TJCP","KEWB","TJFA","KFMH","KGBR","KGDM","KHYA","KLWM","TJMZ","KMVY","TJRV","KORH","KOWD","KPSF","KPVC","KPYM","TJVQ","KACB","KADG","KAMN","KAPN","KARB","KAZO","KBEH","KBTL","KCAD","KCIU","KCMX","KDRM","KDTW","KESC","KFNT","KGDW","KGLR","KGRR","KHAI","KHLM","KHTL","KIMT","KIRS","KISQ","KIWD","KJXN","KLAN","KLDM","KMBL","KMBS","KMCD","KMKG","KMNM","KMOP","KSAW","KMTC","KOSC","KPHN","KPLN","KPTK","KRCT","KTVC","KCFS","KRQB","KAEL","KAUM","KAXN","KBBB","KBDE","KBJI","KBRD","KCKN","KDLH","KDTL","KEVM","KFBL","KFCM","KFFM","KFRM","KGPZ","KCKC","KHIB","KBDH","KINL","KELO","KMIC","KMJQ","KMKT","KMML","KMOX","KMSP","KMVE","KMWM","KDVP","KONA","KOTG","KOWA","KPKD","KROX","KRRT","KRST","KRWF","KSTC","KSTP","KSYN","KTVF","KULM","KBIX","KCBM","KCKM","KCRX","KMBO","KGLH","KGPT","KGTR","KGWO","KHBG","KHEZ","KHKS","KJAN","KLMS","KLUL","KMCB","KMEI","KMMS","KOLV","KOSX","KPQL","KPIB","KTUP","KUBS","KUOX","KUTA","KVKS","KAIZ","KBBG","KBUM","KCGI","KCOU","KDMO","KEOS","KFAM","KIRK","KJEF","KJLN","PFKK","KTKX","KMAW","KMBY","KMCI","KMHL","KMKC","KNVD","KPLK","KPOF","KSGF","KSIK","KSTJ","KSTL","KSUS","KSZL","KTBN","KTRX","KVIH","KBIL","KBTM","KBZN","KCTB","KDLN","KGPI","KGDV","KGGW","KGTF","KHLN","KHVR","KJDN","KLVM","KLWT","KMLS","KMSO","KOLF","KPWD","KRPX","KSBX","KSDY","KTHM","KWYS","KAIA","KANW","KBBW","KBFF","KBIE","KBUB","KCDR","KEAR","KFBY","KFET","KGRI","KGRN","KHDE","KHSI","KIML","KLBF","KLNK","KLXN","KMCK","KMHN","KMLE","KOFF","KOFK","KOGA","KOKS","KOLU","KONL","KSCB","KSNY","KVTN","KBAM","KBTY","KCXP","KDRA","KEKO","KELY","KFLX","KGAB","KHND","KHTH","KINS","KLAS","KLOL","KLSV","KLWL","KMEV","KNFL","KRNO","KTPH","KUCC","KVGT","KWMC","KTNX","KAFN","KASH","KBML","KCNH","KCON","KEEN","KERR","KHIE","KLCI","KLEB","KMHT","KPSM","KACY","KBLM","KCDW","KEWR","KLDJ","KVAY","KMIV","KMJX","KMMU","KNEL","KTEB","KTTN","KWRI","KWWD","KABQ","KALM","KATS","KAXX","KCAO","KCNM","KCVN","KCVS","KDMN","KFMN","KFSU","KGNT","KGUP","KHMN","KHOB","KLAM","KLRU","KLSB","KLVS","KONM","KROW","KRTN","KSRR","KSAF","KSVC","KTCC","KTCS","KSKX","KWSD","KALB","KART","KBGM","KBUF","KDKK","KDSV","KELM","KELZ","KFOK","KFRG","KGFL","KHPN","KHTO","KIAG","KISP","KITH","KJFK","KJHW","KLGA","KLKP","KMGJ","KMSS","KMSV","KMTP","KOGS","KOIC","KOLE","KPBG","KPOU","KRME","KROC","KSCH","KSLK","KSWF","KSYR","KHWV","KAVL","KCLT","KCTZ","KECG","KEDE","KEWN","KFAY","KFBG","KFFA","KGSB","KGSO","KHFF","KHKY","KHSE","KUKF","KILM","KINT","KISO","KLBT","KLHZ","KMQI","KMRN","KMEB","KOAJ","KOCW","KPGV","KPOB","KRDU","KRWI","KRZZ","KSOP","KRUQ","KSVH","KJQF","KASY","KBIS","KBPP","KDIK","KDVL","KFAR","KGFK","KISN","KJMS","KMIB","KMOT","KPMB","KRDR","KBWP","KXWA","KAKR","KAOH","KUNI","KAXV","KBJJ","KBKL","KCAK","KCGF","KCLE","KCMH","KDAY","KDFI","KFDY","KFFO","KGQQ","KHAO","KHTW","KILN","KHZY","KLCK","KLNN","KLUK","KMFD","KMGY","KMNN","KMWO","KOSU","KOXD","KPHD","KPMH","KSGH","KSKY","KTDZ","KTOL","KYNG","KZZV","KADM","KADH","KAXS","KBVO","KBKN","KCHK","KCKA","KCLK","KCSM","KCUH","KDUA","KDUC","KELK","KEND","KFDR","KFSI","KGAG","KGOK","KGUY","KHBR","KHHW","KLAW","KLTS","KMIO","KMKO","KMLC","KOKC","KOKM","KOUN","KPNC","KPWA","KRKR","KRVS","KSNL","KSUD","KSWO","KTIK","KTUL","KWDG","KWWR","KAST","KBKE","KBNO","KBOK","KCVO","KCZK","KDLS","KEUG","KHRI","KHIO","KGCD","KLGD","KLKV","KLMT","KMFR","KONO","KONP","KOTH","KTMK","KPDT","KPDX","KPFC","KRBG","KRDM","KREO","KSLE","KTTD","KABE","KAGC","KAOO","KAVP","KLOM","KBFD","KBVI","KBTP","KMQS","KDUJ","KDYL","KERI","KFKL","KCXY","KHZL","KIDI","KIPT","KJST","KLBE","KLHV","KLNS","KMDT","KGKJ","KMPO","KMUI","KPHL","KPIT","KPNE","KPSB","KPTW","KRDG","KRVL","KUNV","KSEG","KOYM","KTHV","KUKT","KWAY","KWBW","KAFJ","KBID","KOQU","KUUU","KPVD","KSFZ","KWST","KAIK","KAND","KARW","KBNL","KBBP","KCAE","KCDN","KCEU","KCHS","KCRE","KCUB","KDLC","KFLO","KGYH","KGGE","KGMU","KGRD","KGSP","KCQW","KHXD","KHVS","KMMT","KMYR","KOGB","KRBW","KUZA","KSSC","KABR","KATY","KBKX","KFSD","KHON","KLEM","KLQK","KMBG","KMHE","KPHP","KPIR","KRAP","KRCA","KSPF","KBTN","KMDS","KIEN","KYKN","KAPT","KBNA","KCHA","KCKV","KCSV","KFYM","KGCY","KGHM","KGKT","KMEM","KMKL","KMMI","KMOR","KMQY","KMRC","KNQA","KPHT","KRKW","KRNC","KSYI","KTHA","KTRI","KTYS","KUCY","KUOS","KABI","KACT","KADS","KAFW","KALI","KAMA","KASL","KAUS","KBYY","KBBD","KBGD","KBIF","KBKD","KBMT","KBPT","KBRO","KBWD","KCDS","KCFD","KCLL","KCNW","KCOM","KCOT","KCRP","KCRS","KCXO","KCZT","KDAL","KDFW","KDHT","KDLF","KDRT","KDWH","KDYS","KEFD","KELA","KELP","KERV","KETN","KFST","KFTW","KNFW","KGGG","KGLE","KGLS","KGRK","KGVT","KBPG","KHLR","KHOU","KHPY","KHRL","KUTS","KIAH","KILE","KINK","KIWS","KJAS","KJCT","KJSO","KCWC","KLBB","KLFK","KLBX","KLRD","KMAF","KMDD","KMFE","KOSA","KMRF","KMWL","KNGP","KNGW","KNQI","KOCH","KONY","KOZA","KPEQ","KGYI","KPPA","KPRX","KPSN","KPSX","KPVW","KRBD","KRCK","KRFG","KRKP","KRND","KSAT","KSEP","KSGR","KSJT","KSKF","KSLR","KSNK","KSPS","KSSF","KSWW","KTDW","KTPL","KTRL","KTYR","KUVA","KVCT","KVHN","KWEA","KARM","KBCE","KBDG","KBMC","KBTF","KCDC","KCNY","KDPG","KDTA","KENV","KFOM","KHIF","KHVE","KKNB","KLGU","KMLF","KOGD","KPUC","KPVU","KRIF","KSGU","KSLC","KVEL","KBTV","KEFK","KCDA","KMPV","KMVL","KRUT","KVSF","KAPH","KBCB","KBKT","KCHO","KDAA","KDAN","KDCA","KNDY","KFAF","KFKN","KFRR","KGVE","KHSP","KIAD","KLFI","KLNP","KLKU","KLVL","KLYH","KMFV","KHEF","KNGU","KNTU","KNYG","KORF","KPHF","KPSK","KPTB","KRIC","KROA","KSHD","KVJI","KWAL","KOKV","KALW","KBFI","KBLI","KCLM","KCLS","KEAT","KELN","KEPH","KORS","KESW","KFHR","KGEG","KGRF","KHQM","KKLS","KBVS","KMWH","KNUW","KOKH","KOLM","KOMK","KPAE","KPSC","KPUW","KPWT","KRLD","KRNT","KSEA","KSFF","KSHN","KSKA","KTCM","KTDO","KTIW","KUIL","KYKM","KBKW","KBLF","KCKB","KCRW","KEKN","KHLG","KHTS","KLWB","KMGW","KMRB","KPKB","KAHH","KARV","KASX","KATW","KAUW","KCLI","KCMY","KCWA","KEAU","KEGV","KENW","KETB","KFLD","KGRB","KGTG","KHYR","KISW","KJVL","KLNR","KLSE","KMDZ","KMFI","KMKE","KMSN","KMTW","KMWC","KOEO","KOSH","KPDC","KPKF","KRAC","KRHI","KRPD","KRNH","KRRL","KSBM","KSTE","KSUE","KSUW","KUES","KUNU","KVOK","KAFO","KBPI","KBYG","KCOD","KCPR","KCYS","KDGW","KEAN","KECS","KEMM","KEVW","KFBR","KGCC","KGEY","KJAC","KLAR","KLND","KLSK","KPOY","KPNA","KRIW","KRKS","KRWL","KSAA","KSHR","KTHP","KTOR","KWRL","SUAG","SUBU","SUMO","SUCA","SUDU","SULS","SUMU","SUPU","SURV","SUVO","SUSO","SUTB","SUTR","UTTT","UTKA","UTSN","UTSB","UTKF","UTFN","UTSA","UTSK","UTNN","UTSS","UTST","UTNU","TVSB","TVSC","TVSM","TVSU","TVSA","SVPA","SVAN","SVBC","SVST","SVEZ","SVGD","SVPT","SVSR","SVBI","SVSB","SVCN","SVCB","SVCD","SVED","SVIC","SVIE","SVKA","SVKM","SVPR","SVSE","SVTM","SVUM","SVBS","SVPC","SVVA","SVPE","SVTC","SVCR","SVJC","SVCL","SVVP","SVBM","SVCO","SVMD","SVVG","SVRS","SVMT","SVMG","SVAC","SVGU","SVCU","SVCP","SVGI","SVLF","SVPM","SVSO","SVSA","SVVL","SVMI","SVSP","SVON","SVCG","SVMC","SVSZ","TUPJ","TUPA","TUPW","TIST","TISX","VVCS","VVVT","VVPC","VVCM","VVCT","VVDN","VVBM","VVDB","VVPK","VVNB","VVCI","VVTS","VVCR","VVNT","VVPQ","VVRG","VVDL","VVVH","VVPR","VVTH","VVDH","VVCA","VVVD","VVNS","VVTX","VVPB","NVSF","NVSL","NVSP","NVSI","NVSX","NVSU","NVSO","NVSG","NVSN","NVSR","NVSH","NVSW","NVSZ","NVSS","NVSE","NVSM","NVST","NVVQ","NVVV","NVSV","NVVA","NVVB","NVVD","NVVF","NVVI","NVVW","NVSA","NVSC","NVSD","NVSQ","NLWF","NLWW","NSMA","NSAU","NSFA","NSFI","OYMS","ODAL","OYAA","OYBI","OYHD","OYKM","OYGD","OYQN","OYSY","OYRN","OYSQ","ODAS","OYMB","OYSH","OYSN","OYAT","OYBN","OYTZ","FMCZ","FAPA","FABE","FACD","FAEL","FAPJ","FAMW","FAPE","FAUT","FAQT","FABL","FAFB","FAHR","FATN","FAWM","FAGC","FALA","FAOR","FAWB","FAGM","FAWK","FADK","FALE","FAEM","FAHL","FALY","FAMG","FAMU","FANC","FAPM","FADQ","FARB","FAUL","FAVG","FAVY","FAAL","FAER","FAGI","FAHS","FALO","FALD","FATZ","FAMS","FAPH","FAPP","FATH","FAUS","FAMD","FAHW","FAKP","FAMN","FAKN","FANG","FANS","FASZ","FASC","FAKD","FAMM","FAPN","FAPS","FARI","FAVB","FAAG","FAAB","FAKM","FAKZ","FAKU","FALC","FAPK","FASB","FASS","FAUP","FACT","FAGG","FAMO","FAOH","FAOB","FAPG","FARS","FALW","FAVR","FLSO","FLND","FLCP","FLMF","FLMA","FLLS","FLZB","FLSW","FLKS","FLBA","FLKY","FLLI","FLNA","FLKL","FLKO","FLLK","FLMG","FLSS","FLSN","FVBU","FVHA","FVCH","FVMU","FVKB","FVCZ","FVMH","FVMV","FVWN","FVFA","FVWT","FVTL"] } \ No newline at end of file diff --git a/dot-commands/metar.js b/dot-commands/metar.js new file mode 100644 index 0000000..2da15b5 --- /dev/null +++ b/dot-commands/metar.js @@ -0,0 +1,26 @@ +const fn = require('../functions'); + +module.exports = { + name: 'metar', + description: 'Lookup METAR for an airport', + usage: 'ICAO.metar', + async execute(message, commandData) { + try { + // Parse the ICAOs into a CSV list by trimming whitespace and converting delimiters + // Also checks for validity of ICAOs + const icaoList = fn.avWx.parseICAOs(commandData); + const metarData = await fn.avWx.metar.getData(icaoList); + const messages = fn.avWx.metar.parseData(metarData); + messages.forEach(messagePayload => { + message.reply(messagePayload); + }); + } catch (e) { + try { + message.reply(`Something went wrong while retrieving the METAR: ${e.name}\n\n${e.message}`); + console.error(e); + } catch (e) { + console.error(e); + } + } + } +} \ No newline at end of file diff --git a/functions.js b/functions.js index c3aa962..90cbc4e 100644 --- a/functions.js +++ b/functions.js @@ -34,6 +34,7 @@ const dotCommandFiles = fs.readdirSync('./dot-commands/').filter(file => file.en // MySQL database connection const mysql = require('mysql'); const { GifData, PastaData } = require('./CustomModules/NodBot'); +const axios = require('axios'); const db = new mysql.createPool({ connectionLimit: 10, host: dbHost, @@ -384,6 +385,30 @@ const functions = { .setDescription("Generating a response, please stand by.") .setFooter({ text: "Ligma balls" }); return { embeds: [embed] }; + }, + avWx: { + metar(metarData) { + const wgst = metarData.wgst ? `G${metarData.wgst}` : ''; + const clouds = []; + const interAltim = Math.round((metarData.altim * 0.2952998057228486) * 10) + const altim = interAltim / 100; + metarData.clouds.forEach(cloudLayer => { + clouds.push(`${cloudLayer.cover} @ ${cloudLayer.base}`); + }); + const embed = new Discord.MessageEmbed() + .setAuthor({ name: `${metarData.icaoId} METAR`, iconURL: "https://aviationweather.gov/img/icons/awc-logo-180.png"}) + .setDescription(metarData.rawOb) + .setFooter({ text: "METAR by AviationWeather.gov" }) + .addFields( + { name: 'Observation Time', value: `${metarData.reportTime}Z` }, + { name: 'Temperature', value: `${metarData.temp}ºC/${metarData.dewp}ºC`}, + { name: 'Winds', value: `${metarData.wdir}@${metarData.wspd}${wgst} kts`}, + { name: 'Visibility', value: `${metarData.visib} SM` }, + { name: 'Clouds', value: clouds.join('\n') }, + { name: 'Altimeter', value: `${altim} inHg` } + ) + return { embeds: [embed] }; + } } }, collect: { @@ -489,16 +514,16 @@ const functions = { } }, download: { - requests(client) { + async requests(client) { const query = 'SELECT * FROM requests WHERE status = \'Active\' ORDER BY id DESC'; - db.query(query, (err, rows, fields) => { + await db.query(query, (err, rows, fields) => { if (err) throw err; functions.collections.requests(rows, client); }); }, - pastas(client) { + async pastas(client) { const query = 'SELECT * FROM pastas ORDER BY id ASC'; - db.query(query, (err, rows, fields) => { + await db.query(query, (err, rows, fields) => { if (err) throw err; functions.collections.pastas(rows, client); }); @@ -510,16 +535,16 @@ const functions = { functions.collections.gifs(rows, client); }); }, - joints(client) { + async joints(client) { const query = 'SELECT * FROM joints ORDER BY id ASC'; - db.query(query, (err, rows, fields) => { + await db.query(query, (err, rows, fields) => { if (err) throw err; functions.collections.joints(rows, client); }); }, - strain(strainName, interaction) { + async strain(strainName, interaction) { const query = `SELECT id, strain, type, effects, description, flavor, rating FROM strains WHERE strain = ${db.escape(strainName)}`; - db.query(query, (err, rows, fields) => { + await db.query(query, (err, rows, fields) => { if (rows != undefined) { const strainInfo = { id: `${rows[0].id}`, @@ -534,16 +559,16 @@ const functions = { } }); }, - strains(client) { + async strains(client) { const query = 'SELECT id, strain FROM strains'; - db.query(query, (err, rows, fields) => { + await db.query(query, (err, rows, fields) => { if (err) throw err; functions.collections.strains(rows, client); }); }, - medicalAdvice(client) { + async medicalAdvice(client) { const query = 'SELECT * FROM medical_advice ORDER BY id ASC'; - db.query(query, (err, rows, fields) => { + await db.query(query, (err, rows, fields) => { if (err) throw err; functions.collections.medicalAdvice(rows, client); }); @@ -709,6 +734,49 @@ const functions = { } } }, + avWx: { + parseICAOs(commandData) { + let input = commandData.args.toUpperCase(); + // Replace newlines and different delimiters with a comma + let standardizedInput = input.replace(/[\s,;]+/g, ','); + + // Split the string by commas + let icaoArray = standardizedInput.split(','); + + // Trim each element to remove extra whitespace + icaoArray = icaoArray.map(icao => icao.trim()).filter(icao => icao.length > 0); + + icaoArray.forEach(icao => { + if (!(config.icaoIds.includes(icao))) throw new Error(`Invalid ICAO ID Detected: ${icao}`); + }); + + // Join the array into a comma-separated string + return icaoArray.join(','); + }, + metar: { + async getAllICAOs() { + const reqUrl = `https://aviationweather.gov/api/data/metar?format=json` + const response = await axios.get(reqUrl); + let icaoArray = []; + response.data.forEach(e => { + icaoArray.push(e.icaoId) + }); + return icaoArray; + }, + async getData(icaoList) { + const reqUrl = `https://aviationweather.gov/api/data/metar?ids=${icaoList}&format=json`; + const response = await axios.get(reqUrl); + return response.data; + }, + parseData(metarData) { + let messages = []; + metarData.forEach(metar => { + messages.push(functions.embeds.avWx.metar(metar)); + }) + return messages; + } + } + }, generateErrorId() { const digitCount = 10; const digits = []; diff --git a/main.js b/main.js index 4527304..23c68b7 100644 --- a/main.js +++ b/main.js @@ -30,18 +30,20 @@ const strings = require('./strings.json'); const { GifData } = require('./CustomModules/NodBot.js'); const isDev = process.env.isDev; -client.once('ready', () => { +client.once('ready', async () => { fn.collections.slashCommands(client); fn.collections.dotCommands(client); fn.collections.setvalidCommands(client); fn.collections.roaches(client); - fn.download.gifs(client); - fn.download.pastas(client); - fn.download.joints(client); - fn.download.requests(client); - fn.download.strains(client); - fn.download.medicalAdvice(client); + await fn.download.gifs(client); + await fn.download.pastas(client); + await fn.download.joints(client); + await fn.download.requests(client); + await fn.download.strains(client); + await fn.download.medicalAdvice(client); console.log('Ready!'); + // const icaoArray = await fn.avWx.metar.getAllICAOs(); + // console.log(JSON.stringify(icaoArray)); client.channels.fetch(statusChannelId).then(channel => { channel.send(`${new Date().toISOString()} -- <@${process.env.ownerId}>\nStartup Sequence Complete`); }); diff --git a/package.json b/package.json index e419fc5..92c9503 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "nodbot", - "version": "3.2.3", + "version": "3.3.0", "description": "Nods and Nod Accessories, now with ChatGPT!", "main": "main.js", "dependencies": { From 13553d7e5a7aa1be587959b9203b5e31dc7f8819 Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Fri, 21 Jun 2024 19:15:22 -0400 Subject: [PATCH 40/79] Add KCQX --- config.json | 2 +- functions.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config.json b/config.json index dbd4f48..9c78d99 100644 --- a/config.json +++ b/config.json @@ -2,5 +2,5 @@ "guildId": "868542949737246730", "validCommands": [], "roaches": [], - "icaoIds": ["OMAL","OMAA","OMAD","OMAM","OMBY","OMDL","OMFJ","OMSJ","OMDW","OMDB","OMDM","OMRK","OADZ","OAFZ","OARZ","OAHN","OASN","OAQN","OAMS","OABN","OAFR","OAMN","OAGN","OADS","OACC","OABT","OADY","OAZI","OAHR","OASD","OAZJ","OAGZ","OAKB","OAKN","OATN","OARG","OAKS","OASL","OAUZ","OASH","OAJL","OASA","OAOG","OAIX","OATQ","TAPH","TAPA","TQPF","UDYZ","UDSG","FNAM","FNBG","FNCT","FNLB","FNKU","FNCA","FNGI","FNXA","FNHU","FNUB","FNCV","FNME","FNWK","FNSU","FNPA","FNLU","FNCF","FNDU","FNLK","FNLZ","FNZG","FNCH","FNSA","FNCP","FNMA","FNCZ","FNUE","FNUA","FNMO","FNNG","FNUG","FNZE","FNBC","FNSO","SCRM","SABE","SAZB","SAZC","SADP","SAEZ","SAAJ","SADL","SAZM","SAZO","SAZF","SAZH","SAZP","SAZL","SAZT","SAZV","SANC","SARS","SARE","SAVR","SAVC","SAVD","SAVE","SAWS","SAVM","SAVY","SAVT","SAWM","SACO","SACC","SAOC","SAOD","SARL","SARC","SARM","SATM","SATG","SATU","SAAC","SAAG","SAAP","SATC","SARF","SATK","SASJ","SAZG","SAZR","SANL","SAMR","SAMM","SAME","SATD","SARI","SARP","SAHZ","SAZY","SAZW","SAHC","SAZN","SAHS","SAZS","SAVB","SAHR","SAVJ","SAVQ","SAVN","SAVS","SAVV","SASO","SASA","SAST","SANU","SAOU","SAOS","SAOR","SAWA","SAWR","SAVH","SAWP","SAWD","SAWG","SAWT","SAWU","SAWJ","SANW","SAFS","SAFR","SATR","SAAR","SAAV","SANR","SANE","SAWE","SAWH","SANT","NSAS","NSTU","LOWK","LOWW","LOWL","LOWS","LOWG","LOWI","LOIH","YSCB","YMAY","YARM","YLMQ","YBHI","YBTH","YBNA","YBKE","YBRW","YSBK","YBRN","YCBA","YCDO","YSCN","YCNK","YCFS","YCAH","YCTM","YCNM","YCBB","YCBR","YCAS","YCUA","YCWR","YCOR","YSDU","YMDG","YDLQ","YEVD","YFIL","YFST","YFBS","YGTH","YGFN","YGLI","YSMB","YGDH","YGLB","YHAY","YIVL","YKMP","YLHI","YLRD","YLIS","YMER","YMOR","YMND","YMRY","YNBR","YNHS","YYNG","YSNW","YNAR","YSCO","YWLM","YNYN","YORG","YCOM","YPKS","YPMQ","YSGT","YSSY","YTOC","YTEM","YSTW","YTRE","YTMU","YTIB","YQDI","YWWA","YSWG","YWLG","YWCA","YWCH","YWOL","YWWL","YSRI","YBAS","YAUV","YALX","YAYE","YBRL","YBTI","YCOO","YCFD","YCKI","YDVR","YDLV","YPDN","YELD","YFNE","YGBI","YPGV","YGPT","YGTE","YTGT","YHMB","YHOO","YHBY","YHBR","YINW","YJAB","YKCA","YKCS","YKKG","YPTN","YLEV","YLKN","YMHU","YMCR","YMGB","YMVG","YMGD","YMDS","YMQA","YMNS","YMSF","YMUP","YNUM","YKPT","YRNG","YRKD","YRRB","YNGU","YSMP","YSNB","YTBR","YTNK","YTMY","YVRD","YWAV","YWOR","YWTL","YYND","YARY","YABI","YAPH","YNPE","YAGD","YAUR","YAMC","YAYR","YLLE","YBAR","YBUD","YBAU","YBIE","YBAW","YBCK","YBLL","YBTR","YBPI","YBBN","YBOU","YBEO","YBKT","YBDV","YCCA","YCRY","YCMU","YCMW","YCMT","YCCT","YCCY","YBCS","YBCV","YCKN","YCDR","YCOE","YCHT","YUNY","YDAY","YDLT","YDRH","YDKI","YDMG","YDBR","YDOR","YDBI","YDRI","YDPD","YDIX","YDYS","YPMP","YEML","YESE","YGAY","YGAM","YGDS","YBOI","YGKL","YGLE","YGLO","YGLA","YGDI","YGON","YGTN","YGNV","YGYM","YHTL","YHUG","YHID","YHHY","YHDY","YBHM","YHBA","YIFY","YIFL","YIGM","YIKM","YINJ","YLHR","YBMA","YISF","YJLC","YJDA","YCSV","YKRY","YKLB","YKML","YKLA","YKPR","YKMB","YSPV","YKUB","YKOW","YLIN","YLFD","YLND","YCGO","YLOR","YLRE","YLHS","YLOV","YLRS","YLRA","YLAH","YLZI","YMYB","YBSU","YMOT","YBMK","YMEU","YMMU","YMTO","YMRB","YMBA","YMIT","YMGV","YMIR","YMWX","YMAE","YDNI","YNAP","YNSH","YNTN","YORC","YYKI","YBOK","YMTI","YMNK","YBCG","YMOO","YOEN","YOSB","YMNY","YTMO","YPAM","YBPN","YRMD","YROM","YROB","YBRK","YRSB","YRTP","YSII","YSPK","YSGE","YSPT","YSPE","YSTI","YSMR","YWBS","YTGA","YTDR","YTNG","YTEE","YBTL","YTWB","YTHY","YMAA","YUDA","YQLP","YMTB","YVRS","YWCK","YWND","YBWP","YWTN","YMLS","YWDH","YWDL","YWMP","YSHR","YBWW","YYMI","YTGM","YTAM","YTAA","YBWN","YSGW","YPAD","YAMK","YAMT","YCWL","YCDU","YCBP","YCEE","YCWI","YDLK","YERN","YEDA","YMGN","YHAW","YIDK","YINN","YKBY","YKSC","YYTA","YBLC","YLEC","YLOK","YMTG","YMPA","YMCT","YMUG","YOOM","YALA","YMUK","YMWT","YNRC","YNUB","YOOD","YCOD","YOLD","YYOR","YPDI","YPSH","YPLC","YPIR","YPAG","YPMH","YREN","YMRE","YMYT","YPWR","YWUD","YWHA","YMIN","YWYY","YDPO","YFLI","YGTO","YMHB","YSTH","YKII","YMLT","YSMI","YSRN","YQNS","YARA","YMAV","YBLA","YBNS","YBDG","YCRG","YECH","YGLG","YHML","YHSM","YHPN","YKER","YPOK","YMMB","YMEN","YMML","YHOT","YMIA","YOUY","YPOD","YROI","YORB","YSHT","YSWL","YSWH","YWSL","YLTV","YWGT","YWKB","YWBL","YOLA","YMCO","YABA","YBDF","YBRM","YBLN","YBGO","YBUN","YBYS","YBWX","YBEB","YBRY","YCAG","YCOI","YCWA","YCHK","YCWY","YCUE","YCAR","YCIN","YDGA","YDRA","YDBY","YDRD","YEEB","YESP","YECL","YEXM","YFTZ","YFRT","YFLO","YFRV","YGIB","YGIA","YGDN","YGEL","YGSC","YARG","YHLC","YHIL","YPJT","YJNB","YKBR","YKBL","YFDF","YPKG","YKNG","YPKU","YKAR","YPKA","YYLR","YPLM","YLST","YLEO","YLTN","YMBL","YMGR","YMHO","YMIP","YSHK","YMJM","YMEK","YMOG","YMDI","YMGT","YMUC","YMRW","YMWA","YMYR","YSAN","YCNF","YNUL","YNRG","YNSM","YBGD","YORV","YOLW","YPBO","YPPH","YPPD","YPDO","YROE","YRYH","YRTI","YNRV","YSHG","YSOL","YSCR","YTAB","YTHD","YTEF","YTKY","YTMP","YTST","YKAL","YUSL","YWIT","YWAL","YANG","YMNE","YWDG","YWWG","YMMI","YWLU","YWWI","YWYM","YYAL","YNWN","TNCA","UBBB","UBBG","UBBL","UBBN","UBBQ","UBEE","UBBY","LQMO","LQSA","LQTZ","LQBK","TBPB","VGBR","VGEG","VGCM","VGCB","VGHS","VGJR","VGIS","VGRJ","VGSD","VGSG","VGSH","VGSY","EBAW","EBZR","EBBR","EBCI","EBLG","EBKT","EBOS","DFOU","DFET","DFEZ","DFOB","DFEB","DFEF","DFOO","DFFD","DFEP","DFON","DFOD","DFCP","DFEA","DFEM","DFEG","DFOG","DFCA","DFEE","DFCL","DFOY","DFCJ","DFOT","DFER","DFED","DFEL","DFES","DFCC","LBBG","LBHS","LBPD","LBRS","LBSS","LBSF","LBSZ","LBTG","LBWN","LBGO","OBBI","HBBA","HBBE","HBBO","DBBK","DBBN","DBBP","DBBS","DBBD","DBBB","TFFJ","TXKF","WBSB","SLAG","SLSU","SLSB","SLCB","SLHI","SLHJ","SLBU","SLGY","SLMG","SLRQ","SLRY","SLRI","SLSA","SLJO","SLSM","SLSR","SLRA","SLTR","SLAP","SLLP","SLOR","SLCO","SLPR","SLPO","SLUY","SLAS","SLCA","SLCP","SLTI","SLPS","SLRB","SLJE","SLJV","SLSI","SLET","SLVG","SLVR","SLBJ","SLYA","SLTJ","SLVM","TNCB","TNCS","TNCE","SBCZ","SNOU","SBRB","SBTK","SWSN","SNAL","SBMO","SBMQ","SBOI","SWBC","SWNK","SWCA","SWKO","SWEI","SWOB","SWHT","SWII","SWTP","SBIC","SWLB","SBEG","SWMW","SBMY","SWNA","SDCG","SWPI","SBMN","SWBR","SBUA","SBTT","SBTF","SNBU","SBPS","SNBX","SNBR","SNBL","SNED","SBCV","SNJD","SNGI","SBIL","SNIU","SNIC","SNZW","SNHA","SNJB","SNJK","SBLP","SBLE","SNMU","SBUF","SNRD","SBSV","SNTF","SBTC","SNVB","SBQV","SBAC","SNWC","SBFZ","SBJU","SBJE","SBBR","SNKI","SNGA","SNMX","SBVT","SWNS","SWEC","SBCN","SBGO","SBIT","SWJW","SBMC","SWNQ","SWLC","SWUA","SWKT","SNAI","SNBC","SBRR","SNBS","SBCI","SNCP","SNGM","SBIZ","SNYE","SBSL","SBDB","SBCG","SBCR","SSCL","SSDO","SSPN","SBPP","SBTG","SBAT","SSOU","SWTU","SBBW","SWKC","SBCY","SWEK","SWDM","SWHP","SWJN","SWJU","SIZX","SILC","SWXM","SWVB","SWXV","SWSI","SWPG","SWPQ","SWRD","SWST","SWFX","SWTS","SWVC","SBAX","SNAR","SNDV","SNDT","SBGV","SBIP","SBZM","SBJF","SNJR","SNJN","SNDN","SBMK","SNNU","SNPX","SNPD","SBPC","SNZA","SNOS","SNLO","SNTO","SBUR","SBUL","SBVG","SBHT","SBBE","SNVS","SBAA","SBCJ","SNKE","SNYA","SBIH","SBEK","SBMA","SBMD","SNMA","SJNP","SNTI","SDOW","SNOX","SNMZ","SNDC","SNSW","SBSN","SNFX","SBTB","SBKG","SBJP","SSYA","SSAP","SSOG","SBBI","SBCA","SSKM","SSCP","SBCT","SSFB","SSCT","SSGY","SBGU","SBFI","SBLO","SBMG","SSZW","SSPG","SSPB","SSPI","SBTL","SBTD","SBTU","SSUM","SNRU","SBFN","SBPL","SBRF","SNQG","SNGD","SNPC","SBPB","SBTE","SBMS","SBNT","SSLT","SBBG","SSCN","SSSC","SSVP","SBCX","SSER","SBNM","SSHZ","SSIJ","SSIQ","SNLB","SBPK","SBPF","SBPA","SBSM","SBRG","SSRU","SSZR","SBTR","SBUG","SBBZ","SBCP","SBCB","SDUN","SBME","SDRS","SBVH","SWCQ","SBGM","SWJI","SSKW","SWPM","SBPV","SBBV","SSBL","SSCK","SBCM","SBCD","SBFL","SSJA","SBJA","SBJV","SBLJ","SSLN","SBNF","SSOE","SSUV","SSVI","SBCH","SBAS","SBAQ","SBAU","SBBT","SBBU","SBBP","SDAM","SIMK","SBGW","SDJL","SBAE","SBLN","SBML","SDOU","SBDN","SDSC","SBRP","SBSJ","SBSR","SDCO","SBST","SDUB","SBUP","SDVG","SBAR","SWRA","SWGN","SWDN","SWGI","SWIY","SBPJ","SBPN","MYAP","MYBG","MYBS","MYCB","MYAF","MYBC","MYAB","MYAN","MYCC","MYAW","MYGF","MYEF","MYEN","MYES","MYEH","MYAM","MYAT","MYIG","MYCI","MYRD","MYLD","MYCP","MYLS","MYMM","MYNN","MYRP","MYSM","MYAK","MYCA","MYEM","MYER","MYGW","VQBT","VQPR","VQGP","VQTY","FBOR","FBSP","FBSN","FBTL","FBKE","FBGZ","FBTS","FBFT","FBKR","FBMN","FBSV","FBSW","FBSK","FBLO","FBJW","UMBB","UMGG","UMMG","UMOO","UMMM","UMMS","UMII","MZBZ","MZPL","CYNR","CZPC","CYBA","CYBF","CYCT","CYEG","CYET","CYJA","CYLB","CYLL","CYMM","CYOD","CYOJ","CYOP","CYPE","CYPY","CYQF","CYQL","CYQU","CYRM","CYSD","CYVG","CYXH","CYYC","CYYM","CYZH","CYZU","CZHP","CYHC","CYBD","CYAL","CYAZ","CYBH","CYBL","CYCD","CYCG","CYCQ","CYCW","CYCZ","CYDL","CYDQ","CZBB","CYGB","CYHE","CYKA","CYLW","CYNJ","CYNH","CYPR","CYPW","CYPZ","CYQQ","CYQZ","CYRV","CYSE","CZAM","CYVK","CYVR","CYWH","CYWL","CYXC","CYXJ","CYXS","CYXT","CYXX","CYYD","CYYE","CYYF","CYYJ","CYZP","CYZT","CBBC","CZGF","CZML","CZMT","CZST","CZSW","CZBD","CZEE","CZMN","CZWH","CZFG","CZNG","CZSN","CYBQ","CYBR","CYBT","CYBV","CYCR","CYDN","CZTA","CYFO","CYGM","CYGO","CYGX","CYIV","CYLR","CYNE","CYOH","CYPG","CYQD","CYRS","CYST","CZLQ","CYTH","CYWG","CYYI","CYYL","CYYQ","CZAC","CZGI","CZGR","CZJG","CZJN","CZTM","CYCH","CYCL","CYFC","CYQM","CYSJ","CYSL","CZBF","CYAY","CYDF","CYDP","CYHO","CYJT","CYMH","CYFT","CYQX","CYCA","CYWK","CYYR","CYYT","CZUM","CYKD","CYVL","CYEV","CYWE","CYFR","CYFS","CYGH","CYHI","CYHY","CYJF","CYMD","CYOA","CYPC","CYRA","CYLK","CYSM","CYSY","CYUB","CYVQ","CYWJ","CYWY","CYZF","CZFM","CZFN","CYID","CYHZ","CYPD","CYQI","CYQY","CYZX","CYAB","CYBB","CYBK","CYCB","CYCO","CYCS","CYCY","CYEK","CYEU","CYFB","CYGT","CYGZ","CYHK","CYIO","CYLC","CYLT","CYRB","CYRT","CYSK","CYTE","CYUT","CYUX","CYVM","CYVN","CYXN","CYXP","CYYH","CYZS","CZMD","CYCK","CYAQ","CYAC","CYAG","CYAM","CYAT","CYCC","CYCE","CYSN","CYCN","CYEL","CYEM","CYER","CYFA","CYFH","CYGK","CYGQ","CYHD","CYHF","CYHM","CYHN","CYHP","CYIB","CYKM","CYKF","CYKX","CYLD","CYLH","CYLS","CYMG","CYMO","CYKP","CYOO","CYOS","CYOW","CYPL","CYPM","CYPO","CYPQ","CYQA","CYQG","CYQK","CYQN","CYQS","CYQT","CYRL","CYRO","CYSB","CYSH","CYSP","CYTA","CYTL","CYTR","CYTS","CYTZ","CYVV","CYVZ","CYWA","CYWP","CYXL","CYXR","CYXU","CYXZ","CYYB","CYYU","CYYW","CYYZ","CYZE","CYZR","CZKE","CZPB","CZRJ","CZSJ","CZUC","CYSU","CYYG","CYKO","CYLU","CYAH","CYAD","CYBC","CYBG","CYBX","CYDO","CYEY","CYFE","CYGL","CYGP","CYGR","CYGV","CYGW","CYHR","CYIF","CYIK","CYJN","CYAS","CYKL","CYKQ","CYLP","CYLQ","CYME","CYML","CYMT","CYMW","CYMX","CYNA","CYNC","CYND","CYNM","CYHH","CYPH","CYLA","CYPN","CYPX","CYQB","CYHA","CYRI","CYRJ","CYRQ","CYSC","CYTF","CYFJ","CYTQ","CYMU","CYUL","CYUY","CYVB","CYVO","CYVP","CYKG","CYXK","CYYY","CYZG","CYZV","CZBM","CZEM","CYBE","CYEN","CYHB","CYKC","CYKJ","CYKY","CYLJ","CYMJ","CYNL","CYPA","CYQR","CYQV","CYQW","CYSF","CYVC","CYVT","CYXE","CYYN","CZFD","CZPO","CZWL","CYDM","CYDA","CYDB","CYHT","CYMA","CYOC","CYQH","CYXQ","CYXY","CYZW","CZFA","YPCC","FZKJ","FZFD","FZEN","FZEA","FZQA","FZSK","FZQG","FZTK","FZQC","FZKA","FZWC","FZWT","FZVI","FZVA","FZWA","FZVR","FZUA","FZUG","FZVM","FZVS","FZUK","FZAA","FZAB","FZAJ","FZAL","FZAM","FZAG","FZAR","FZQM","FZBO","FZCB","FZBA","FZOK","FZCA","FZBT","FZCE","FZCV","FZBI","FZOC","FZOA","FZOP","FZFU","FZGA","FZNP","FZNA","FZJH","FZFP","FZGV","FZMA","FZFK","FZFA","FZRB","FZRF","FZRM","FZRQ","FZRA","FZIC","FZIR","FZGN","FEFN","FEFF","FEFZ","FEGE","FEFY","FEFR","FEFW","FEFT","FEFC","FEFG","FEGM","FEGR","FEFO","FEFM","FEGU","FEFS","FEGF","FEGZ","FEFI","FEGO","FCBM","FCBY","FCBZ","FCBB","FCOB","FCOO","FCOM","FCOE","FCOK","FCBS","FCOT","FCOI","FCPL","FCPA","FCMM","FCBD","FCOG","FCBL","FCPP","FCBK","FCOU","FCOS","LSZB","LSGG","LSZS","LSME","LSZC","LSZR","LSZA","LSGS","LSZH","DIAP","DIOF","DIGN","DISP","DITB","DISS","DIAO","DIAU","DIOD","DIDV","DIGA","DIDK","DIGL","DIMN","DIDL","DIBI","DIFK","DIKO","DIBK","DISG","DITM","DIYO","DIBU","DIBN","NCAI","NCAT","NCMG","NCMH","NCMR","NCMK","NCPY","NCPK","NCRG","SCBA","SCCC","SCCY","SCHR","SCAS","SCFA","SCCF","SCBE","SCTT","SCAR","SCRA","SCAT","SCES","SCLL","SCIE","SCGE","SCCH","SCQB","SCSE","SCOV","SCTC","SCQP","SCTO","SCPC","SCFT","SCFR","SCPQ","SCTE","SCPV","SCAP","SCST","SCTN","SCJO","SCAC","SCVD","SCNT","SCCI","SCSB","SCFM","SCGZ","SCTL","SCEL","SCKP","SCDA","SCIP","SCVM","SCAN","SCRD","FKKN","FKYS","FKKY","FKKO","FKKI","FKKJ","FKKH","FKKL","FKKD","FKAN","FKKR","FKKG","FKKV","FKKU","FKKS","FKKM","FKKW","FKKB","FKKF","FKKC","ZSAQ","ZSBB","ZSFY","ZSOF","ZSTX","ZSWA","ZBAA","ZUWL","ZUWS","ZUCK","ZUDZ","ZUQJ","ZULP","ZUWX","ZSFZ","ZSQZ","ZSLO","ZSSM","ZSWY","ZSAM","ZLDH","ZLXH","ZLQY","ZLJQ","ZLJC","ZLLL","ZLLN","ZLTS","ZLZY","ZGGG","ZGFS","ZGHZ","ZGMX","ZGOW","ZGSZ","ZGXN","ZGZJ","ZGSD","ZGBS","ZGBH","ZGHC","ZGKL","ZGZH","ZGNN","ZGWZ","ZUYI","ZUAS","ZUBJ","ZUNP","ZUGY","ZULB","ZUPS","ZUTR","ZUMT","ZUZY","ZJHK","ZJSY","ZBDH","ZBCD","ZBHD","ZBSJ","ZBTS","ZBXT","ZBZJ","ZYDQ","ZYFY","ZYHE","ZYHB","ZYJD","ZYJM","ZYJS","ZYJX","ZYLD","ZYMD","ZYQQ","ZYMH","ZYYL","ZHXY","ZHAY","ZHCC","ZHLY","ZHNY","ZHEC","ZHES","ZHSN","ZHGH","ZHSS","ZHSY","ZHHH","ZHXF","ZHYC","ZGCZ","ZGYY","ZGCD","ZGHA","ZGDY","ZGCJ","ZGHY","ZGLG","ZGSY","ZSCG","ZSSH","ZSLG","ZSNJ","ZSNT","ZSRG","ZSSZ","ZSWX","ZSXZ","ZSYN","ZSYA","ZSJD","ZSJA","ZSJJ","ZSCN","ZSGZ","ZSSR","ZSYC","ZYCC","ZYBA","ZYJL","ZYBS","ZYTN","ZYYJ","ZYSQ","ZYAS","ZYCY","ZYCH","ZYDD","ZYTL","ZYJZ","ZYTX","ZYXC","ZYYK","ZBOW","ZBCF","ZBDS","ZBER","ZBHH","ZBLA","ZBUL","ZBHZ","ZBMZ","ZBYZ","ZBTL","ZBUH","ZBXH","ZBES","ZLGY","ZLIC","ZLZW","ZLHB","ZLGL","ZLGM","ZLDL","ZLXN","ZLYS","ZLAK","ZBCZ","ZBDT","ZLYA","ZLHZ","ZBLL","ZLSN","ZBYN","ZLYL","ZBXZ","ZLXY","ZSHZ","ZSDY","ZLJN","ZSLY","ZSQD","ZSJN","ZSWF","ZSWH","ZSYT","ZSPD","ZSSS","ZBYC","ZUDA","ZUHY","ZUUU","ZUDX","ZUDC","ZUGH","ZUGU","ZUJZ","ZUKD","ZULZ","ZUMY","ZUNC","ZUZH","ZUTF","ZUXC","ZUYB","ZBTJ","ZWAT","ZWAK","ZWBL","ZWFY","ZWHM","ZWTN","ZWCM","ZWKC","ZWSH","ZWKN","ZWKL","ZWKM","ZWNL","ZWRQ","ZWHZ","ZWSS","ZWTC","ZWTL","ZWWW","ZWYN","ZUBD","ZULS","ZUNZ","ZUAL","ZURK","ZPBS","ZPCW","ZPDQ","ZPDL","ZPJH","ZPJM","ZPPP","ZPLJ","ZPLC","ZPMS","ZPSM","ZUTC","ZPWS","ZPYM","ZPZT","ZSHC","ZSZS","ZSLQ","ZSJU","ZSNB","ZSWZ","ZSYW","SKLT","SKLP","SCSF","SKRA","SKAN","SKAM","SKLC","SKCU","SKEB","SKMD","SKIG","SKRG","SKPN","SKNC","SKOT","SKPR","SKTU","SKUR","SKAT","SKUC","SKCN","SKSA","SKTM","SKBQ","SKCG","SKMG","SKMP","SKVL","SKPA","SKSO","SKTA","SKMZ","SKAC","SKYA","SKFL","SKSV","SKTQ","SKYP","SKHC","SKOE","SKPZ","SKTD","SKGP","SKPP","SKMB","SKAG","SKVP","SKAD","SKCP","SKBS","SKCD","SKCA","SKJU","SKNQ","SKUI","SKML","SKMR","SKPQ","SKBO","SKBM","SKPD","SKMF","SKSJ","SKNV","SKPI","SKLM","SKRH","SKBC","SKPL","SKSM","SKAP","SKCI","SVWX","SKNA","SKUB","SKVV","SKEH","SKIP","SKPS","SKCO","SKCC","SKOC","SKTB","SKLG","SKAS","SKVG","SKAR","SKPE","SKSP","SKPV","SKBG","SKCM","SKEJ","SKRU","SKCV","SKCZ","SKTL","SKHA","SKGI","SKIB","SKQU","SKBU","SKCL","SKGO","SKUL","SKCR","SKMU","SKGA","SKIM","SKPC","SKSL","MRAN","MRLC","MRRF","MROC","MRUP","MRMJ","MRLB","MRNC","MRNS","MRIA","MRCR","MRTM","MRBC","MRGP","MRLM","MRBT","MRBA","MRDK","MRGF","MRCH","MRCC","MRPJ","MRPM","MRTR","MRSV","MRQP","MRSI","MRPV","MUPB","MUCM","MUCA","MUCC","MUCF","MUBY","MUMZ","MUBA","MUGT","MUGM","MUHG","MUMO","MUCL","MUNG","MUSN","MUHA","MUVT","MUVR","MUKW","MULM","MUSJ","MUTD","MUSS","MUCU","MUBR","MUSC","GVBA","GVBR","GVMA","GVNP","GVAN","GVSN","GVAC","GVMT","GVSF","GVSV","TNCC","YPXM","LCGK","LCLK","LCEN","LCRA","LCPH","LKCS","LKTB","LKKV","LKMR","LKMT","LKZA","LKOL","LKPO","LKPD","LKPR","LKVO","LKHO","LKKU","EDNY","EDSB","ETIE","EDTL","EDFM","EDDS","EDMA","EDQD","ETSF","EDJA","EDQG","EDQM","ETSI","ETIK","ETIN","EDDM","EDDN","EDMO","EDMS","EDQE","EDDT","EDDB","EDCD","EDDW","EDWB","EDDH","EDHI","EDDF","ETHF","EDVK","ETOU","EDBH","EDBN","EDCG","EDAH","EDCP","EDAX","ETNL","EDOP","EDWG","EDWR","EDWZ","EDVE","EDWE","ETMN","EDDV","EDWJ","EDWL","EDWS","EDWY","EDWU","EDWI","EDWD","EDKA","EDLI","EDDK","EDLW","EDDL","EDLE","EDDG","ETNG","ETUO","EDLN","EDLV","EDLP","EDGS","EDRB","EDFH","ETAR","ETAD","EDRZ","EDDR","EDDC","EDAU","EDDP","EDBC","EDCK","EDAQ","EDHN","EDXF","EDXW","EDXB","EDXH","EDHK","EDHL","EDXY","EDXO","EDXJ","ETNS","EDAC","EDGE","EDDE","HDAS","HDAM","HDOB","HDMO","HDTJ","EKCH","EKRN","EKAH","EKKA","EKSV","EKVJ","EKYT","EKLS","EKSN","EKTS","EKMB","EKRK","EKBI","EKEB","EKOD","EKSB","EKSP","TDPD","TDCF","MDBH","MDJB","MDPC","MDCZ","MDSD","MDCR","MDPP","MDCY","MDAB","MDST","DAUA","DATM","DAUT","DAAG","DABB","DABT","DAOR","DAAE","DAUB","DAOI","DABC","DAAD","DAOY","DAUO","DAUE","DAUG","DAAJ","DAUZ","DAAP","DAAV","DAFH","DAUL","DAOV","DAAY","DAOO","DAOL","DAUH","DAUU","DAUK","DAAS","DAOS","DABP","DATG","DAUI","DAAT","DABS","DAOB","DAOF","DAON","SECU","SETU","SERO","SEMH","SETN","SEGS","SEII","SEST","SEGU","SETM","SEMA","SESV","SEJI","SEMT","SEPV","SESC","SETH","SEMC","SEJD","SECO","SETI","SESM","SEQM","SESA","SENL","SEPT","SETR","SEAM","EETN","EEKA","EEPU","EEKE","EETU","HEGN","HEMA","HEAX","HEBA","HE25","HECA","HELX","HEDK","HEOW","HEKG","HEBL","HESN","HEAT","HEPS","HETR","HESC","HESH","HETB","HEAL","HEMM","HEAR","HEMK","HHAS","HHSB","HHTS","HHMS","LEMG","LEGR","LEAM","LEBA","LEMO","LERT","LEZL","LEJR","LEHC","LETL","LEZG","LEAS","GCRR","GCFV","GCGM","GCLP","GCLA","GCHI","LEXJ","LERL","LELN","LEBG","LESA","LEVD","LEAB","LEBL","LEGE","LEDA","LESU","LERS","LEBZ","LECO","LEST","LEVX","LEIB","LEMH","LEPA","LELO","LEMD","LETO","GEML","LELC","LEMI","LEPP","LEBB","LESO","LEVT","LEAL","LECH","LEVC","HAAB","HASM","HABD","HADM","HADT","HADC","HAMM","HAGN","HALL","HAMA","HAPW","HASO","HADR","HAGM","HABE","HADD","HANG","HAFN","HAGH","HAGB","HAGR","HAJM","HAML","HAMN","HANJ","HANK","HASK","HABB","HAKD","HAGO","HASL","HAJJ","HAKL","HAWR","HAAX","HAHU","HAMK","HAAM","HALA","HABC","HABU","HAMT","HAMR","HASD","HATP","HAMJ","HAWC","EFLP","EFKA","EFKJ","EFSI","EFMI","EFSA","EFVR","EFKI","EFJY","EFHA","EFUT","EFET","EFIV","EFKE","EFKT","EFRO","EFSO","EFTP","EFKK","EFVA","EFJO","EFIT","EFKS","EFOU","EFYL","EFKU","EFPO","EFHK","EFHF","EFHV","EFMA","EFTU","NFNH","NFFN","NFND","NFNA","NFCI","NFNW","NFKD","NFNO","NFNB","NFNK","NFMO","NFNG","NFOL","NFVB","NFNU","NFNL","NFFR","NFNR","NFNS","NFNM","NFCS","NFMA","NFFO","NFNV","NFVL","NFSW","EKVG","EGYP","SFAL","PTKK","PTSA","PTPN","PTYA","LFHU","LFLW","LFLC","LFLB","LFLJ","LFMH","LFLS","LFHP","LFLY","LFLL","LFBK","LFKX","LFHM","LFLP","LFHO","LFLO","LFLU","LFLV","LFHS","LFHY","LFLA","LFSD","LFGJ","LFQG","LFLN","LFRB","LFRD","LFRO","LFRJ","LFRH","LFRU","LFRN","LFRT","LFRQ","LFRV","LFLD","LFLX","LFOZ","LFOT","LFKJ","LFKB","LFKC","LFKF","LFKO","LFKS","LFGA","LFSN","LFSG","LFJL","LFSF","LFSR","LFST","LFSZ","LFQV","LFAQ","LFAC","LFPC","LFQT","LFQQ","LFAT","LFPG","LFPO","LFPN","LFRC","LFRK","LFRG","LFAB","LFOE","LFRF","LFOH","LFOP","LFBA","LFBU","LFBZ","LFBD","LFSL","LFBG","LFBE","LFBL","LFBH","LFBN","LFBX","LFBI","LFBP","LFDN","LFCY","LFMU","LFMK","LFCK","LFTW","LFCI","LFBT","LFNB","LFMT","LFMP","LFCR","LFBO","LFCC","LFJR","LFOU","LFRI","LFEY","LFRE","LFRM","LFOO","LFOV","LFRS","LFRZ","LFMV","LFMR","LFMD","LFMQ","LFNA","LFTZ","LFML","LFMN","LFMI","LFMA","LFNC","LFTH","FOOL","FOGA","FOOD","FOON","FOGQ","FOGJ","FOGR","FOGF","FOGE","FOGG","FOGM","FOGI","FOOY","FOOT","FOGB","FOOE","FOOK","FOGK","FOOR","FOGW","FOOI","FOOH","FOOG","FOOB","FOGV","FOOM","FOGO","EGTB","EGHD","EGHJ","EGLK","EGXH","EGUB","EGBB","EGNH","EGHH","EGKB","EGGD","EGNL","EGVN","EGNC","EGSC","EGBE","EGCN","EGNX","EGTE","EGLF","EGVA","EGBP","EGBJ","EGXU","EGNJ","EGNS","EGHE","EGYM","EGKR","EGNM","EGLC","EGHC","EGKK","EG74","EGLL","EGUL","EGGP","EGGW","EGDL","EGMD","EGCC","EGUN","EGNV","EGNT","EGWU","EGBN","EGHQ","EGSH","EGVO","EGBK","EGTK","EGXC","EGSU","EGHL","EGHR","EGUY","EGTO","EGMC","EGHI","EGXP","EGSS","EGDJ","EGXW","EGDY","EGJB","EGJA","EGMH","EGNO","EGAA","EGAC","EGQB","EGAB","EGAE","EGXJ","EGPD","EGQL","EGPL","EGPR","EGEC","EGPN","EGPH","EGED","EGEF","EGQK","EGPF","EGPI","EGPE","EGPA","EGQS","EGPB","EGET","EGES","EGEN","EGEO","EGPK","EGEP","EGPT","EGEI","EGER","EGPO","EGPU","EGPW","EGEH","EGPC","EGEW","EGTG","EGNR","EGFF","EGFE","EGFH","EGOV","EGKA","TGPY","UGSS","UGSB","UGKO","UGTB","SOCA","SOGS","SOOM","SOOA","SOOG","SOOR","SOOS","DGSI","DGSN","DGAA","DGLE","DGTK","LXGB","BGJN","BGUQ","BGUK","BGQQ","BGTL","BGUM","BGBW","BGCH","BGAA","BGCO","BGGH","BGPT","BGKK","BGSS","BGMQ","BGSF","GBYD","GUOK","GUSB","GUCY","GUFH","GUFA","GUSI","GUXN","GUKU","GULB","GUMA","GUNZ","TFFB","TFFA","TFFM","TFFS","TFFR","TFFC","FGAB","FGSL","FGBT","FGMY","LGAL","LGKV","LGAV","LGKC","LGAG","LGRX","LGAD","LGKA","LGKZ","LGKR","LGKF","LGPZ","LGZA","LGIO","LGTS","LGSA","LGIR","LGST","LGKP","LGKY","LGMK","LGNX","LGSO","LGSR","LGPL","LGKO","LGKS","LGKJ","LGLE","LGML","LGPA","LGRP","LGHL","LGKL","LGSP","LGSY","LGSK","LGLR","LGBL","LGIK","LGHI","LGLM","LGMT","LGSM","MGCB","MGRB","MGSJ","MGGT","MGHT","MGRD","MGPB","MGCR","MGTK","MGPP","MGQZ","MGCT","MGQC","MGPG","MGRT","PGUM","PGUA","GGOV","GGBU","SYBR","SYMR","SYMB","SYBT","SYIB","SYKM","SYPR","SYCJ","SYGO","SYKZ","SYSC","SYMK","SYKA","SYKT","SYMD","SYMM","SYOR","SYAH","SYKS","SYKR","SYLT","SYLP","SYAN","VHHH","MHLC","MHTE","MHIR","MHTJ","MHSC","MHRU","MHSR","MHLM","MHTG","MHAH","MHPC","MHPL","MHLE","MHNJ","MHRO","MHUT","MHMA","MHGS","MHGE","MHJU","MHCS","MHEA","MHYR","MHUL","LDDU","LDZA","LDPL","LDOS","LDLO","LDRI","LDSB","LDSP","LDZD","MTJE","MTCH","MTPX","MTPP","MTCA","MTJA","LHPP","LHBP","LHMC","LHDC","LHSM","WITT","WITM","WITL","WITC","WITN","WADD","WIII","WIHP","WIIG","WIPL","WIPI","WIBJ","WARW","WAMG","WAMY","WIPA","WIPH","WIPU","WIBT","WICC","WICD","WICN","WICA","WICM","WARC","WAHL","WAHP","WARQ","WARS","WAHI","WADY","WARE","WARA","WARR","WART","WIOK","WIOO","WIOP","WIOS","WAOO","WAOC","WRBK","WAON","WIOG","WAOI","WAGG","WAOS","WAOW","WALS","WALK","WALL","WRLC","WALJ","WRLA","WRLH","WALT","WALV","WRLB","WRLP","WRLF","WAGD","WITA","WALR","WIOM","WIPK","WIKD","WIDD","WION","WIDN","WIAG","WILL","WAMA","WAPH","WAPE","WAMR","WAPN","WAPT","WAEE","WAPA","WAPP","WAPK","WAPD","WAMJ","WAMK","WAPF","WAPR","WAPC","WAPG","WAPI","WAPV","WADB","WADL","WADU","WADS","WATA","WATM","WRKB","WATE","WATT","WATO","WATL","WATW","WATC","WATG","WATR","WATS","WADT","WADW","WASG","WASO","WASF","WASI","WASU","WASE","WASK","WASR","WASB","WASM","WASN","WASC","WASS","WAST","WAJA","WABB","WAJB","WAKE","WAJG","WAJJ","WAJC","WAJN","WABT","WABL","WABE","WABK","WAKM","WAKP","WABN","WAJL","WAJM","WAKD","WAKK","WABI","WABR","WAJO","WAKO","WABD","WAJE","WAJS","WABP","WAKT","WAJU","WABV","WAJR","WABG","WAVV","WASW","WAKQ","WABO","WAJI","WIBD","WIBB","WIBS","WIDS","WIPB","WAFJ","WAWT","WAWM","WAWS","WAAA","WAMW","WAFF","WAMP","WAMI","WAWB","WAWW","WAWP","WAWR","WA44","WIME","WIMN","WIMS","WIMB","WIMM","WAMM","WIMK","WAMN","WAMH","WIMP","WIPT","WIDE","WIBR","WIPV","WIPQ","WIPP","WADA","WASA","WIIJ","EINN","EIBN","EICK","EIDL","EILT","EIDW","EICM","EIMN","EIIR","EIIM","EICA","EIKY","EIKK","EIBT","EIKN","EISG","EIWF","LLBS","LLEY","LLET","LLER","LLMR","LLMZ","LLOV","LLNV","LLYT","LLKS","LLIB","LLHA","LLSD","LLBG","OJJR","VOCX","VOPB","VIBY","VOCP","VOPN","VORY","VOTP","VOBZ","VEVZ","VEPG","VEAN","VETJ","VEZO","VEDZ","VEMN","VEGT","VELR","VEKW","VEKM","VEKU","VEJT","VERU","VETZ","VEDH","VEGY","VEMZ","VEPT","VICG","VEBU","VARP","VADN","VIDP","VOGO","VAAH","VABO","VABJ","VABV","VAKS","VAKE","VAJM","VAPR","VARK","VASU","VIHR","VIGG","VIBR","VISM","VIJU","VILH","VISR","VEDB","VERC","VEJS","VOBI","VOBL","VAHB","VOML","VABM","VOMY","VOJV","VOCL","VOKN","VOCI","VOTV","VOAT","VABP","VAGN","VIGR","VAKJ","VAID","VAJB","VIST","VAAK","VABB","VAOZ","VAAU","VAJL","VAKP","VALT","VANP","VAND","VAPO","VARG","VASL","VEIM","VEBI","VELP","VEMR","VEBS","VIJR","VEJP","VERK","VOPC","VIAX","VIAR","VIBT","VIPK","VILD","VIBK","VIJP","VIJO","VIKG","VIKO","VAUD","VOCB","VOMD","VOMM","VONV","VOSM","VOTK","VOTJ","VOTR","VOHY","VOHS","VORG","VOWA","VEAT","VEKR","VIAG","VEGK","VIAL","VIKA","VILK","VEBN","VIDN","VIPT","VECC","VECO","VEBD","VEMH","VEDG","VEBG","ORAA","ORAT","ORMM","ORNI","ORER","ORSU","ORBI","ORBB","ORKK","ORBM","OIIP","OITL","OITP","SVHG","OITU","OITK","OITR","LATI","OITM","OITT","OIBB","OIBH","OITH","OIBQ","OIBJ","OIBP","OIFS","OIFE","OIFM","OISF","OISJ","OISR","OISL","OISS","OIGG","OING","OINE","OIHH","OIHS","OIBA","OIBL","OIKB","OIKQ","OIKP","OIBK","OIBV","OIBS","OICI","OIKM","OIKJ","OIKK","OIKR","OIKY","OICC","OIMT","OIMB","OIMS","OIMC","OIMM","OIMN","OIAA","OIAG","OIAW","OIAD","OIAM","OIAJ","OIAH","OISY","OICS","OICK","OIHR","OINJ","OINN","OINR","OINZ","OIIK","OIMJ","OIIS","OIZB","FMNE","FMNH","FMNA","OIZI","FMNJ","FMNN","FMNS","FMNV","OIZH","OIZC","FMND","OIIE","OIFK","OIII","OIYY","OITZ","BIBF","BIDV","BIHN","BIRK","BIAR","BIBK","BIBV","BIEG","BIFF","BIGR","BIHU","BIRL","BINF","BIOF","BIKP","BIRG","BISI","BITN","BIVO","BIBD","BIBL","BIRF","BIPA","BIKR","BIFM","BIVM","BIKF","BIGJ","BIHK","BIIS","BIRE","BITE","BIGF","BIST","LIBP","LIAP","LIBC","LICR","LICA","LIRN","LIRI","LIPE","LIPK","LIDR","LIPR","LIPA","LIPQ","LIPD","LIRF","LIMG","LIMJ","LIML","LIMC","LIPO","LIPY","LIMZ","LIMF","LIBR","LIBD","LIBF","LIBN","LIBG","LIEA","LIEE","LIED","LIER","LIEO","LIET","LICB","LICC","LICD","LICZ","LICJ","LICG","LICT","LIRJ","LIRQ","LIRS","LIQL","LIRP","LIQS","LIPB","LIRZ","LIMW","LIDB","LIPH","LIPZ","LIPT","LIPX","EGJJ","MKTP","MKKJ","MKJP","MKJS","MKBS","MKNG","OJAQ","OJAM","OJMF","OJMN","OJAI","RJGG","RJNA","RJSK","RJSR","RJSA","RJSH","RJSM","RJOM","RJNF","RJFF","RJFR","RJSF","RJOA","RJBH","RJEC","RJCH","RJCK","RJEB","RJCM","RJCB","RJEO","RJCR","RJER","RJCN","RJCW","RJBT","RJAH","RJNK","RJNW","RJSI","RJOT","RJKA","RJKI","RJFK","RJFC","RJKB","RORY","RJKN","RJFG","RJTA","RJOK","RJDA","RJFT","RJSS","RJFM","RJAF","RJFE","RJDB","RJFU","RJDU","RJDT","RJSN","RJSD","RJFO","RJOB","RORA","RODN","RORH","RORE","ROIG","ROKR","RORK","ROMD","ROMY","ROYN","ROAH","RORS","RORT","ROKJ","RJBB","RJFS","RJOW","RJOC","RJNS","RJOS","RJTH","RJTT","RJAW","RJAM","RJTQ","RJAA","RJTO","RJNO","RJOR","RJOH","RJNT","RJBD","RJSC","RJSY","RJOI","RJDC","HKJK","HKGA","HKAM","HKKG","HKKR","HKML","HKKI","HKUK","HKNY","HKLU","HKMA","HKMY","HKMB","HKMK","HKMO","HKNW","HKNK","HKKE","HKNI","HKSB","HKKL","HKHO","HKES","HKFG","HKLK","HKLO","HKLY","HKEL","HKKT","HKWJ","UAFM","UAFO","VDBG","VDKH","VDKK","VDKT","VDSV","VDMK","VDPP","VDST","VDRK","VDSR","NGUK","NGAB","NGTB","NGTR","NGTU","NGBR","NGKT","NGMA","NGMN","NGMK","NGNU","NGTO","NGON","NGTE","NGTM","NGTA","NGTS","PCIS","PLCH","FMCV","FMCH","FMCN","FMCI","TKPK","TKPN","ZKHM","ZKSD","ZKWS","ZKUJ","ZKPY","ZKSE","RKPK","RKTU","RKTI","RKTP","RKNN","RKNW","RKNY","RKJU","RKJK","RKJJ","RKJB","RKJY","RKSI","RKSO","RKSW","RKPE","RKPS","RKTH","RKTN","RKTL","RKPU","RKTY","RKPC","RKPD","OKAJ","OKBK","MWCB","MWCR","MWCL","UAAL","UAAA","UAAR","UACK","UATT","UACC","UATG","UARR","UAOL","UATE","UAII","UASB","UASP","UAAH","UAKD","UAKK","UAUR","UAUU","UAOO","UASS","UASK","UACP","UADD","VLAP","VLHS","VLKG","VLPS","VLSN","VLTK","VLLN","VLLB","VLOS","VLSV","VLSK","VLVT","VLSB","VLXK","OLBA","OLKA","TFFG","TLPC","TLPL","VCCG","VCCB","VCCS","VCCT","VCCA","VCCH","VCCJ","VCRI","VCCK","VCCW","VCBI","VCCN","VCCC","GLBU","GLTN","GLST","GLVA","GLRB","GLCP","GLMR","GLNA","GLGE","FXLR","FXPG","FXSS","FXMF","FXMM","FXSM","FXNK","FXMK","FXTK","FXLK","FXSK","FXQN","FXQG","FXLS","FXMA","FXSH","FXTA","EYVI","EYKA","EYPA","EYPP","EYSA","ELLX","EVDA","EVRA","EVLA","EVVA","HLGN","HLLQ","HLZN","HLON","HLKF","HLMB","HLNR","HLLB","HLGT","HLMS","HLTD","HLLS","HLGD","HLLM","HLLT","HLZW","HLUB","GMMD","GMMC","GMMN","GMMB","GMFK","GMAZ","GMMZ","GMFF","GMFM","GMMF","GMAT","GMMW","GMFO","GMFB","GMML","GMMA","GMMH","GMMX","GMMS","GMMY","GMME","GMAD","GMMI","GMTA","GMTT","LUBL","LUKK","LYBR","LYPG","LYTV","FMME","FMFE","FMMI","FMSU","FMMX","FMSI","FMSM","FMSG","FMSF","FMSK","FMNQ","FMNO","FMNL","FMNM","FMMO","FMNT","FMMR","FMNW","FMMG","FMNF","FMNX","FMNP","FMNG","FMMU","FMMQ","FMMS","FMMT","FMMY","FMMH","FMMZ","FMNR","FMNC","FMSY","FMSV","FMML","FMSD","FMMK","FMSJ","FMMV","FMSR","FMSL","FMSN","FMST","FMSZ","FMSB","FMSC","FMMC","FMMN","PKMA","PKWA","PKMJ","MLIP","LWOH","LWSK","GABS","GAGO","GAYE","GAKA","GAKY","GANR","GANK","GAMB","GASK","GAKO","GAGM","GATB","VYPN","VBHD","VYAN","VYPY","VYBM","VYMK","VYPT","VYLK","VYPA","VYPP","VYGG","VYKU","VYMW","VYPK","VYPU","VYHN","VYMD","VYNT","VYBG","VYCZ","VYMM","VYYE","VYSW","VYGW","VYKP","VYMN","VYTD","VYHL","VYKI","VYKL","VYMY","VYHH","VYKG","VYLS","VYMT","VYMO","VYMS","VYNS","VYTL","VYKT","VYME","VYDW","VYBP","VYYY","ZMTG","ZMUL","ZMBH","ZMBN","ZMCD","ZMMG","ZMTL","ZMAT","ZMDN","ZMUH","ZMBS","ZMKD","ZMHG","ZMMN","ZMDZ","ZMAH","ZMHU","ZMHH","ZMBR","ZMBU","ZMCK","ZMUB","ZMUG","VMMC","PGRO","PGSN","PGWT","TFFF","GQPA","GQNF","GQNE","GQPP","GQNK","GQNS","GQNJ","GQNA","GQNU","GQNO","GQNT","GQNL","GQNC","GQND","GQNI","GQPF","GQPZ","GQNH","GQNB","TRPG","LMML","FIMP","FIMR","VRMD","VRMV","VRMT","VRMF","VRMH","VRMM","VRMO","VRMK","VREI","VRMG","VRNT","FWCL","FWCD","FWKA","FWKG","FWLK","FWKI","FWCM","FWMG","FWMY","FWUU","FWDW","FWSM","MMAS","MX86","MMGR","MMLP","MMLT","MMMG","MMPL","MMSD","MMES","MMML","MMSF","MMTJ","MMCE","MMCP","MMCO","MMPQ","MMTP","MMTG","MMCS","MMCU","MMCG","MMCC","MMMV","MMPG","MMIO","MMTC","MMIA","MMZO","MMDO","MMLO","MMCY","MMAA","MMZH","MMGL","MMPR","MMJC","MMMX","MMSM","MMTO","MMLC","MMMM","MMPN","MMZM","MMCB","MMEP","MMMY","MMAN","MMBT","MMIT","MMOX","MMPS","MMSZ","MMPB","MMHC","MMQT","MMCM","MMUN","MMCZ","MMIM","MMSP","MMTN","MMCL","MMLM","MMMZ","MMCN","MMCA","MMGM","MMHO","MMNG","MMPE","MMVA","MMCV","MMMA","MMDM","MMNL","MMRX","MMTM","MMJA","MMMT","MMPA","MMVR","MMCT","MMMD","MMZC","WMKJ","WMAU","WMKA","WMKL","WMKC","WMKM","WMKD","WMAN","WMBT","WMKI","WMPA","WMBA","WMBI","WMKB","WMKP","WBKK","WBKN","WBKG","WBKT","WBKL","WBKD","WBKP","WBKR","WBKS","WBKA","WBKO","WBKH","WBKE","WBKM","WBKW","WBGZ","WBGQ","WBGC","WBGN","WBGB","WBGG","WBGP","WBGF","WBGL","WBGJ","WBGD","WBGU","WBGW","WBGK","WBGM","WBGR","WBMU","WBGI","WBGS","WBGY","WBTM","WMKK","WMSA","WMKE","WMPR","WMKN","FQIB","FQLU","FQMD","FQMP","FQPB","FQXA","FQIN","FQVL","FQCH","FQIA","FQMA","FQPO","FQAG","FQNP","FQNC","FQCB","FQLC","FQBR","FQTT","FQQL","FYAR","FYME","FYSM","FYWB","FYSS","FYAA","FYKB","FYKT","FYLZ","FYOG","FYSA","FYRU","FYWE","FYMG","FYNG","FYWH","FYOP","FYTE","FYGB","FYOS","FYOA","FYHI","FYNA","FYOO","FYMO","FYTM","FYGF","FYOW","FYLS","FYKM","FYOE","NWWC","NWWD","NWWK","NWWQ","NWWP","NWWU","NWWM","NWWE","NWWW","NWWA","NWWL","NWWR","NWWV","DRZA","DRZL","DRRM","DRRN","DRRT","DRZR","YSNF","DNAA","DNJO","DNYO","DNAI","DNMK","DNMA","DNCA","DNAS","DNSU","DNBE","DNEN","DNGO","DNIM","DNKA","DNZA","DNKN","DNIL","DNMM","DNMN","DNAK","DNIB","DNPO","DNSO","MNBZ","MNPC","MNRT","MNSI","MNWP","MNBL","MNNG","MNCI","MNMG","MNSC","MNCE","EHGG","EHLE","EHLW","EHBK","EHEH","EHGR","EHVK","EHWO","EHAM","EHKD","EHTW","EHSB","EHRD","ENGM","ENKL","ENAT","ENBS","ENBV","ENHK","ENHF","ENHV","ENKR","ENNA","ENMH","ENSS","ENVD","ENHA","ENBR","ENSO","ENAL","ENOV","ENKB","ENML","ENVA","ENAN","ENBN","ENBO","ENEV","ENLK","ENMS","ENRA","ENNK","ENRS","ENSK","ENST","ENSH","ENFG","ENRY","ENHD","ENZV","ENBL","ENFL","ENSD","ENSG","ENOL","ENNM","ENRO","ENRM","ENNO","ENSN","ENDU","ENSR","ENTC","ENCN","ENTO","VNKT","VNLT","VNBR","VNNG","VNSK","VNBL","VNJS","VNMA","VNPK","VNJP","VNRC","VNDP","VNST","VNJL","VNBJ","VNVT","VNRB","VNTR","VNBW","VNDT","VNMN","VNCG","VNTJ","VNBP","VNGK","VNMG","VNSI","VNDG","VNRP","VNRK","VNJI","VNLD","VNLK","VNPL","VNRT","VNSB","VNBT","VNBG","VNDL","VNDH","VNSR","VNTP","ANYN","NIUE","NZAA","NZAR","NZCX","NZGB","NZKE","NZRO","NZTG","NZWK","NZAS","NZCH","NZGT","NZKI","NZTU","NZUK","NZCI","NZGS","NZNR","NZWO","NZOH","NZPM","NZWU","NZWB","NZPN","NZNS","NZDA","NZKT","NZKK","NZKO","NZWR","NZLX","NZDN","NZOU","NZWF","NZQN","NZNV","NZMF","NZMC","NZRC","NZMO","NZNP","NZTK","NZMK","NZHN","NZMA","NZRA","NZTO","NZTH","NZAP","NZWT","NZMS","NZPP","NZWN","NZGM","NZHK","NZWS","OOMS","OOGB","OOBR","OOFD","OOLK","OOSH","AYNO","OOKB","OORQ","OOMA","OOSR","FZSB","MDLR","OOMX","OOSA","OOTH","MPBO","MPCH","MPDA","MPSM","MPEJ","MPJE","MPLP","MPOA","MPCE","MPHO","MPWN","MPMG","MPTO","MPVR","MPSA","SPPY","SPLN","SPHZ","SPEO","SPHY","SPQU","SPHO","SPAY","SPJR","SPJE","SPNC","SPIL","SPIM","SPGM","SPZA","SPSO","SPJN","SPJJ","SPMF","SPRU","SPHI","SPMR","SPZO","SPQT","SPDR","SPMS","SPBR","SPTU","SPSY","SPLO","SPUR","SPYL","SPJL","SPBL","SPJI","SPBB","SPJA","SPOA","SPST","SPTN","SPME","SPAR","SPCL","NTAM","NTAR","NTAV","NTAT","NTMN","NTMD","NTMU","NTMP","NTTB","NTTH","NTTP","NTAA","NTTR","NTTE","NTGA","NTHE","NTGD","NTGU","NTKF","NTGF","NTGB","NTKH","NTGJ","NTGH","NTTO","NTKA","NTGK","NTKT","NTGM","NTGV","NTGN","NTKN","NTGW","NTGP","NTGQ","NTGE","NTTG","NTKK","NTKO","NTGC","NTKM","NTGT","NTGO","NTKR","NTTX","NTUV","NTGI","NTGY","NTTM","NTTU","AYBK","AYIA","AYIQ","AYEF","AYER","AYFA","AYGF","AYHH","AYKH","AYJO","AYKQ","AYRA","AYEA","AYOP","AYLS","AYMP","AYMA","AYQQ","AYRK","AYQO","AYTY","AYTI","AYWT","AYCH","AYRI","AYGL","AYMV","AYNI","AYTK","AYSH","AYZI","AYXO","AYVO","AYUI","AYWQ","AYWK","AYAN","AYAY","AYDI","AYGA","AYOK","AYLG","AYOL","AYMW","AYNY","AYTR","AYUC","AYWO","AYWD","AYAO","AYKM","AYKK","AYQA","AYSK","AYSS","AYBA","AYWB","AYJS","AYKR","AYMD","AYNA","AYSD","AYWH","AYMO","AYYM","AYAG","AYGN","AYKA","AYMS","AYAX","AYUM","AYBC","AYBG","AYBP","AYBR","AYBU","AYNS","AYDE","AYDN","AYEN","AYFI","AYGP","AYGI","AYGG","AYHE","AYHU","AYID","AYII","AYKB","AYNB","AYOE","AYKD","AYRO","AYNM","AYYR","AYYE","AYKT","AYLB","AYNZ","AYLT","AYLN","AYLP","AYLX","AYLO","AYSX","AYMJ","AYMI","AYMC","AYMB","AYOG","AYOM","AYPD","AYSP","AYXI","AYEW","AYSW","AYQS","AYTP","AYTZ","AYTS","AYTW","AYWS","AYWC","AYWU","AYXE","AYZA","AYAF","AYBD","AYDO","AYDR","AYEO","AYEB","AYGC","AYGX","AYNJ","AYNC","AYPQ","AYPY","AYYO","AYRE","AYSF","AYSG","AYCS","AYTF","AYUE","AYBZ","AYNX","AYEE","AYKV","AYKY","AYMZ","AYSE","AYWG","AYKO","AYGR","AYTU","AYPE","AYAT","AYBF","AYEV","AYHB","AYHO","AYHF","AYOQ","AYOW","AYNN","AYLI","AYOO","AYKG","AYDL","AYKU","AYKW","AYMN","AYPO","AYMQ","AYRM","AYMR","AYBM","AYPB","AYPJ","AYVM","AYTA","AYUR","AYWF","AYIW","AYBL","AYCG","AYGJ","AYGT","AYHK","AYKC","AYLL","AYSL","AYSV","AYTG","AYVL","AYUZ","AYWJ","AYIX","AYVN","AYND","AYBO","AYCB","AYNE","AYMH","AYKJ","AYAQ","AYDK","AYPG","AYSJ","AYTV","AYYL","AYAE","AYVW","AYYK","AYAK","AYGU","AYAA","AYAM","AYAI","AYAW","AYET","AYBQ","AYBH","AYBI","AYDU","AYDB","AYEL","AYFR","AYFE","AYFU","AYGS","AYUP","AYML","AYGV","AYIO","AYTO","AYIM","AYYP","AYUY","AYLU","AYEH","AYIY","ATNR","AYOB","AYOJ","AYOF","AYOV","AYZS","AYPC","AYRG","AYSO","AYSA","AYZN","AYSU","AYTB","AYTH","AYTE","AYTN","AYQL","AYTT","AYNU","AYKI","AYXW","AYXP","AYED","RPME","RPVK","RPVE","RPLP","RPVS","RPUR","RPLB","RPUO","RPUB","RPVT","RPLH","RPUT","RPUD","RPUN","RPMH","RPVR","RPUV","RPLS","RPVM","RPMQ","RPMD","RPLI","RPSG","RPVI","RPUY","RPUS","RPMI","RPVO","RPVA","RPMC","RPMM","RPUW","RPVJ","RPLU","RPUM","RPUH","RPMY","RPMO","RPLL","RPMA","RPVB","RPVD","RPVF","RPLO","RPEN","RPVP","RPSD","RPSV","RPVV","RPLC","RPLE","RPVU","RPVC","RPMR","RPMJ","RPNS","RPMS","RPMF","RPMW","RPMU","RPMN","RPMV","RPMG","PRNO","RPMP","RPMZ","OPMF","OPRT","OPMA","OPDB","OPGD","OPJI","OPKH","OPLL","OPOR","OPPG","OPPI","OPZB","OPSB","OPSU","OPTU","OPQT","OPCL","OPGT","OPSD","OPIS","OPBN","OPCH","OPDI","OPKT","OPPC","OPPS","OPSS","OPTA","OPWN","OPBW","OPDG","OPLA","OPFA","OPMT","OPMI","OPRK","OPSR","OPST","OPTH","OPDD","OPKD","OPJA","OPKC","OPMJ","OPMP","OPSW","OPSK","OPSN","OPNH","EPWR","EPBY","EPLL","EPBP","EPLB","EPZG","EPKK","EPRA","EPWA","EPMO","EPRZ","EPGD","EPRU","EPKT","EPSY","EPPO","EPKZ","EPSC","LFVP","LFVM","TJSJ","TJPS","TJIG","LVGZ","LPBJ","LPBR","LPBG","LPCO","LPFR","LPPM","LPCS","LPPT","LPSI","LPPR","LPMA","LPPS","LPCR","LPFL","LPGR","LPHR","LPPD","LPPI","LPSJ","LPAZ","LPLA","LPCH","LPVR","LPVZ","PTRO","SGOL","SGES","SGPJ","SGME","SGFI","SGAS","SGBN","SGCO","SGEN","SGAY","SGPI","OTBD","OTHH","OTBH","FMEE","FMEP","LRAR","LRBC","LROD","LRCS","LRCL","LRCK","LRCV","LRIA","LROP","LRBM","LRTM","LRSM","LRSB","LRSV","LRTR","LRTC","LYBE","LYBT","LYNI","LYUZ","UNBG","UNBB","UHBB","UHBI","UHBW","ULAA","ULAS","ULKK","ULAL","URWA","UWUB","UWUF","UWUK","UWUU","UUOB","UUBP","UECT","UIUU","URMG","USCC","USCM","UHMA","UHMK","UHMO","UHMD","UHMP","UWKS","URML","URMS","UIBB","UIKE","UIII","UUBI","UIKK","UIKB","UIBS","UITT","URMN","UMKK","URWI","UUBC","UHPP","ULPB","UNEE","UNWW","UHNB","UHKM","UHHH","UHKK","UHNN","UHOO","UNAA","USHQ","USHH","USHI","USRK","USHK","USRN","USNN","USHN","USHS","USNR","USRR","USHU","USKK","UUYI","UUYP","UUYY","UUYH","UUYS","UUYX","UUYW","UUBA","URKA","URSS","URKG","URKK","UNKS","UODD","UNII","UOHH","UOII","UNKL","UOOO","UNIP","UOTT","USUU","UUOK","ULSS","ULLI","UUOL","UHMM","UHMW","UWKJ","UWPS","UUBB","UUEE","UUMU","UUMO","UUBW","ULMK","ULMM","ULDD","ULAM","ULDW","ULNN","UWGG","UNNT","UNOO","UWOR","UWOO","UUOR","UWPP","USPP","UHTG","UHWP","UHWW","ULOO","ULOL","URRR","URRP","URRT","URRY","UUWR","UEEA","UESG","UESO","UESS","UEMM","UEST","UEMH","UERR","UEMA","UELL","UENN","UEMO","UERO","UERP","UESK","UEBS","UENS","UERS","UEBT","UERL","UEMU","UEMT","UENI","UENW","UEEE","UEVV","UESU","UHSB","UHSM","UHSK","UHSI","UHSN","UHSH","UHSS","UHSO","UWWW","UWSB","UWSS","URMO","UUBS","URMM","URMT","USSS","UUOT","UWKD","UWKE","UWKB","UNSS","UNTT","UUBT","UUEM","USTR","USTO","UNKY","USII","UWLL","UWLW","ULWC","ULWW","URWW","ULWU","UUOO","USDB","USDP","USRO","USMU","USMM","USDA","USDD","USDS","USDU","USDK","UUDL","UUBK","UIAA","HRYU","HRYG","HRZA","HRYI","HRYR","OEBA","OERR","OERF","OETR","OESK","OEGT","OEMA","OEAO","OEYN","OEGS","OEZL","OEPS","OEDW","OERK","OESL","OEWD","OEPA","OEDR","OEDF","OEAH","OEKK","OEAB","OEBH","OEKM","OEHL","OEGN","OEJN","OETF","OENG","OESH","OEWJ","OENN","OETB","AGTI","AGGY","AGGC","AGKG","AGGJ","AGGH","AGKW","AGGI","AGNA","AGGP","AGGF","AGJO","AGGV","AGGK","AGGT","AGAR","AGAF","AGGA","AGAT","AGGQ","AGGB","AGGR","AGGU","AGGL","AGGE","AGBT","AGGS","AGEV","AGOK","AGGN","AGKU","AGGO","AGGM","AGRM","AGRC","AGBA","FSSB","FSSD","FSDR","FSSF","FSPP","FSIA","HSFA","HSDZ","HSWD","HSKG","HSGF","HSKA","HSNW","HSSK","HSFS","HSDN","HSDB","HSMN","HSSW","HSPN","HSAT","HSGG","HSNN","HSOB","HSLI","HSNH","HSGN","HSZA","HSKI","ESDF","ESSD","ESUE","ESKM","ESSK","ESNH","ESNY","ESSV","ESMT","ESND","ESNZ","ESGJ","ESSF","ESMQ","ESMO","ESSW","ESMX","ESNX","ESNG","ESNQ","ESPA","ESUP","ESKK","ESOE","ESSL","ESSP","ESTA","ESMK","ESSU","ESSA","ESOH","ESOK","ESST","ESUT","ESNL","ESNS","ESUD","ESNU","ESNV","ESNK","ESNO","ESNN","ESGG","ESGP","ESGR","ESGL","ESGT","WSAP","WSSS","WSAT","WSSL","FHAW","FHSH","ENSB","LZLU","LZSL","LZIB","LJPZ","LZKZ","LJMB","LZPW","LZTT","LJLJ","LZPP","LZZI","GFKE","GFYE","GFKB","GFBN","GFGK","GFBO","GFLL","GFHA","GOOY","GOOK","GOTK","GODK","GOSM","GOSP","GOSR","GOSS","GOTB","GOTS","GOTT","GOBD","GOGS","GOGG","HCMM","HCMA","HCMF","HCMS","HCMC","HCMG","HCMB","HCMD","HCMJ","HCMK","HCMO","HCMR","HCME","HCMU","HCMV","HCMI","HCMH","SMCO","SMBN","SMMO","SMWA","SMNI","SMJP","SMZO","SMCA","SMDA","SMTP","SMDO","SMPA","SMST","SMWS","HJJJ","HSMK","HSSM","HSWW","FPPR","FPST","MSSS","MSLP","TNCM","OSKL","OSLK","OSDZ","OSDI","OSAP","OSPR","FDMS","FDSK","MBGT","MBMC","MBNC","MBPI","MBPV","MBSY","MBSC","FTTI","FTTY","FTTS","FTTM","FTTK","FTTJ","FTTU","FTTL","FTTD","FTTP","FTTB","FTTA","FTTC","FTTN","FTTH","DXNG","DXXX","VTUO","VTCC","VTCT","VTBF","VTSE","VTUK","VTSG","VTBS","VTBD","VTCL","VTUL","VTBL","VTCH","VTBK","VTUW","VTUQ","VTPI","VTSF","VTCN","VTSC","VTSK","VTPB","VTPP","VTCP","VTSP","VTPH","VTSR","VTBU","VTUV","VTUI","VTSS","VTSH","VTPO","VTSB","VTSM","VTUJ","VTPM","VTPT","VTST","VTBO","VTUU","VTUD","VTPU","UTDD","UTDT","UTDK","UTDL","WPAT","WPEC","WPDL","WPMN","WPOC","WPDB","WPVQ","UTAK","UTAA","UTAT","UTAV","UTAM","DTTG","DTTF","DTKA","DTTJ","DTMB","DTTX","DTNH","DTTR","DTTZ","DTTA","NFTL","NFTO","NFTP","NFTE","NFTF","NFTV","LTAF","LTAG","LTCP","LTAH","LTCO","LTAP","LTAD","LTAC","LTAI","LTFG","LTBD","LTBG","LTBF","LTFD","LTCJ","LTCU","LTBE","LTBR","LTBH","LTFK","LTAY","LTCC","LTCA","LTCD","LTCE","LTBY","LTBI","LTAJ","LTCW","LTDA","LTCT","LTFC","LTBA","LTFM","LTFJ","LTCN","LTCF","LTAL","LTAU","LTBQ","LTAN","LTBZ","LTAT","LTCR","LTFE","LTBV","LTBS","LTCK","LTAZ","LTCB","LTFO","LTFH","LTCS","LTCH","LTCL","LTCM","LTCV","LTAR","LTBU","LTAW","LTCG","LTBO","LTCI","LTAS","TTPP","TTCP","NGFU","RCKU","RCPO","RCYU","RCLM","RCKH","RCBS","RCFG","RCMT","RCCM","RCQC","RCWA","RCKW","RCDC","RCMQ","RCNN","RCSS","RCGI","RCLY","RCFN","RCTP","HTAR","HTLM","HTDA","HTDO","HTGE","HTIR","HTBU","HTKA","HTKJ","HTPE","HTKI","HTLI","HTNA","HTGR","HTMU","HTMB","HTZA","HTMT","HTMI","HTMW","HTNJ","HTMA","HTSU","HTSO","HTMD","HTSY","HTSN","HTTB","HTTG","UKFK","UKFF","UKKE","UKKL","UKLN","UKDD","UKDR","UKCC","UKCK","UKCM","UKLI","UKHH","UKOH","UKLH","UKKG","UKKK","UKBB","UKCW","UKLL","UKON","UKOO","UKHP","UKLR","UKFB","UKHS","UKLT","UKWW","UKLC","UKLU","UKDB","UKDE","UKKV","HUAR","HUGU","HUJI","HUKF","HUEN","HUKS","HUMI","HUMA","HUPA","HUSO","HUTO","PWAK","KAIV","KALX","KANB","KASN","KAUO","KBFM","KBHM","KDCU","KDHN","KEDN","KEUF","KGAD","KJKA","KHAB","KHSV","KHUA","KMGM","KMOB","KMSL","KMVC","KMXF","KNBJ","KOZR","KPLR","KSEM","KTCL","KTOI","PAFM","PADK","PADQ","KPHH","PFAL","PAGN","PAWI","PAAK","PFAK","PAKH","PAKN","PAKP","PANC","PANI","PANT","PANV","PARC","PATQ","PAAT","PABE","PAGQ","PABI","PABL","PABM","PABR","PABA","PABT","PABG","PACD","PACV","PACE","PACI","PFCL","PACX","PACK","PACY","PACZ","PADL","PADE","PADU","PAEG","PAED","PAEE","PAII","PAEH","PAEI","PFEL","PAEL","PAEM","PAEN","PANN","PAFA","PAFB","PANR","PAFR","PAFW","PFYU","PAGA","PAGM","PAGB","PAGK","PAGL","PAGZ","PAGS","PAHC","PAOH","PAHN","PAHO","PAHP","PAHL","PAHU","PAHY","PAIK","PAIG","PAKO","PAIL","PACR","PAJN","PAFE","PAKV","PAKD","PAKF","PAJZ","PAKK","PADY","PALG","PALB","PAKW","PAMB","PANW","PFKO","PAPC","PAKI","PAPE","PASM","PAKT","PFKT","PFKA","PAVC","PAVL","PAGG","PAQH","PFKW","PAKY","PFKU","PAKL","PAMH","PALN","PALU","PAMC","PAIN","PAMD","PADM","PAML","PAMO","PAMR","PAMM","PABK","PAMX","PAMY","PFCB","PAFS","PAOU","PAGT","PANO","PAQT","PANU","PAOB","PAOM","PAOO","KORI","PAOR","PFNO","PAOT","PAAQ","PAOC","PAPO","PAPN","PPIZ","PAPK","PAAL","PAPR","PAPG","PALJ","PAAP","PAPH","PAPM","PARY","PADG","PARS","PASC","PACM","PASD","PAGY","PAGH","PASH","PAHX","PASI","PFSH","PASW","PASL","PAMK","PASP","PASN","PASO","PAPB","PASA","PASV","PAWD","PASX","PASY","PATA","PATK","PFTO","PATE","PATL","PATC","PATG","PAST","PAUM","PAUN","PAIM","PAKU","PAVA","PAVD","PAVE","PAIW","PAWB","PALR","PASK","PAWM","PANA","PAUO","PAWG","PACS","PFWS","PAWN","PAWS","PAEW","PAYA","KAVQ","KIWA","KBXK","KCFT","KCGZ","KDGL","KDMA","KDUG","KDVT","KFHU","KFLG","KGCN","KGYR","KHII","KIFP","KIGM","KINW","KLGF","KLUF","KFFZ","KMZJ","KOLS","KPGA","KPHX","KPAN","KPRC","KSAD","KSDL","KSEZ","KSJN","KSOW","KTUS","KTYL","KNYL","KAGO","KARG","KAWM","KBVX","KBYH","KCDH","KCVK","KCRT","KELD","KFCY","KFLP","KFSM","KFYV","KHEE","KHKA","KHOT","KHRO","KJBR","KLIT","KLRF","KMPJ","KMXA","KPBF","KPGR","KROG","KSGT","KSLG","KASG","KSRC","KTXK","KBPK","KXNA","KACV","KAHC","KAPC","KAPV","KAUN","KAVX","KBAB","KBFL","KBIH","KBLH","KBLU","KBNG","KBUR","KBWC","KBYS","KCCB","KCCR","KCEC","KCIC","KCRQ","KCLR","KCNO","KCPM","KCRO","KCXL","KDAG","KEDW","KEED","KEKA","KEMT","KFAT","KFCH","KFUL","KHAF","KHHR","KCVH","KHMT","KHWD","KIPL","KIYK","KKIC","KLAX","KLGB","KLPC","KLSN","KLVK","KMAE","KMCC","KMCE","KMER","KMHR","KMHV","KMIT","KMMH","KMOD","KMRY","KMYF","KMYV","KNJK","KNKX","KNLC","KDVO","KNRC","KNRS","KNTD","KNUQ","KNZY","KOAK","KOAR","KOKB","KONT","KOVE","KOXR","KPAO","KPMD","KPOC","KPRB","KPSP","KPTV","KPVF","KRAL","KRBL","KRDD","KRHV","KRIR","KRIV","KMPI","KSAC","KSAN","KSAS","KSBA","KSBD","KSBP","KSCK","KSDM","KSEE","KSFO","KSIY","KSJC","KSMF","KSMO","KSMX","KSNA","KSNS","KSPA","KIZA","KSQL","KSTS","KSMS","KSUU","KSVE","KSZN","KSZP","KTRK","KTLR","KTNP","KTOA","KTRM","KTSP","KTVL","KUDD","KUKI","KVBG","KVCV","KVIS","KVNY","KWHP","KWJF","KWLW","KWVI","KAFF","KAKO","KALS","KAPA","KASE","KBKF","KBJC","KCEZ","KCAG","KCOS","KDEN","KDRO","KEGE","KFCS","KFNL","KGJT","KGUC","KGWS","KGXY","KHDN","KLAA","KLIC","KLXV","KMTJ","KPSO","KPUB","KRIL","KSBS","KANK","KSTK","KTAD","KTEX","KBDU","KBDL","KBDR","KDXR","KGON","KHFD","KHVN","KOXC","KDOV","KGED","KILG","KAAF","KAPF","KAVO","KBCT","KBOW","KCDK","KCEW","KCLW","KCOF","KCOI","KCRG","KCTY","KDAB","KDTS","KECP","KEGI","KEYW","KFLL","KFMY","KFPR","KFXE","KGIF","KGNV","KHST","KHWO","KIMM","KISM","KJAX","KLAL","KLCQ","KLEE","KLNA","KMCF","KMCO","KMIA","KMLB","KMKY","KMTH","KNEN","KNIP","KNPA","KNQX","KNRB","KNSE","KNUN","KOBE","KOCF","KOPF","KORL","KPAM","KPBI","KPGD","KPHK","KPIE","KPNS","KPMP","KRSW","KSEF","KSFB","KSPG","KSRQ","KSUA","KTIX","KTLH","KTMB","KTNT","KTPA","KTPF","KSGJ","KVNC","KVPS","KVQQ","KVRB","KZPH","KABY","KAGS","KAHN","KATL","KAYS","KBGE","KBQK","KCSG","KDBN","KDNL","KDNN","KFTY","KGVL","KLGC","KLHW","KLSF","KLZU","KMAC","KMCN","KMGE","KMGR","KMLJ","KMQW","KMUL","KPDK","KPIM","KRMG","KSAV","KSSI","KSVN","KSYV","KTBR","KTMA","KTOC","KTVI","KVAD","KVDI","KVLD","KWDR","KWRB","PHBK","PHSF","NSFQ","PHDH","PHHI","PHNL","PHHN","PHTO","PHJH","PHJR","PHKO","PHLI","PHNY","PHLU","PMDY","PHMK","PHMU","PHNG","PHOG","PHPA","PHUP","KBOI","KBYI","KLLJ","KCOE","KGNG","KIDA","KGIC","KLWS","KMLD","KMUO","KMYL","KPIH","KRXE","KSMN","KSUN","KTWF","KALN","KARR","KBLV","KBMI","KCIR","KCMI","KCPS","KDEC","KDNV","KDPA","KDVN","KENL","KEOK","KFEP","KGBG","KGRE","KHSB","KIJX","KIKK","KJOT","KLOT","KLWV","KMDH","KMDW","KMLI","KMQB","KMTO","KMVN","KMWA","KOLY","KORD","KPIA","KRFD","KSAR","KSLO","KSPI","KSQI","KUGN","KUIN","KVLA","KVYS","KAID","KANQ","KBFR","KBMG","KCEV","KBAK","KEKM","KEVV","KFRH","KFWA","VOGB","KGFD","KGSH","KGUS","KHLB","KHNB","KIND","KLAF","KPPO","KIMS","KMGC","KMIE","KMZZ","KOKK","KRCR","KRID","KRZL","KSBN","KSER","KSIV","KSMD","KVPZ","KAIO","KALO","KAMW","KAXA","KBNW","KBRL","KCBF","KCCY","KCID","KCIN","KCSQ","KCWI","KDBQ","KDEH","KDNS","KDSM","KEBS","KEFW","KEST","KFFL","KFSW","KFOD","KFXY","KHPT","KICL","KIDG","KIFA","KIOW","KLRJ","KMCW","KMIW","KMPZ","KMUT","KMXO","KOMA","KOOA","KOTM","KPOH","KPRO","KSLB","KSPW","KSUX","KTNU","KANY","KBEC","KCBK","KCEA","KCFV","KCNK","KCNU","KDDC","KEQA","KEMP","KEWK","KFLV","KFOE","KFRI","KFSK","KGBD","KGCK","KGLD","KHLC","KHUT","KHYS","KIAB","KICT","KIDP","KIXD","KLBL","KLWC","KLYO","KMHK","KMPR","KOJC","KPPF","KPTS","KPTT","KRSL","KSLN","KTOP","KWLD","KBRY","KBWG","KCEY","KCVG","KEKX","KFFT","KFTK","KGLW","KHOP","KLEX","KLOU","KLOZ","KOWB","KPAH","KPBX","KSDF","KSME","KAEX","KARA","KBAD","KBTR","KBXA","KCWF","KDRI","KDTN","KESF","KHUM","KLCH","KLFT","KMLU","KMSY","KNBG","KNEW","KOPL","KPOE","KPTN","KRSN","KSHV","KAUG","KBGR","KBHB","KCAR","KIZG","KHUL","KIWI","KLEW","KMLT","KBXM","KOLD","KOWK","KPNN","KPQI","KPWM","KRKD","KSFM","KFVE","KWVL","KADW","KANP","KAPG","KBWI","KCBE","KCGE","KCGS","KESN","KFDK","KFME","KGAI","KHGR","KMTN","KNHK","KOXB","KSBY","KACK","TJAB","KBAF","KBED","KBOS","TJBQ","KBVY","TJCP","KEWB","TJFA","KFMH","KGBR","KGDM","KHYA","KLWM","TJMZ","KMVY","TJRV","KORH","KOWD","KPSF","KPVC","KPYM","TJVQ","KACB","KADG","KAMN","KAPN","KARB","KAZO","KBEH","KBTL","KCAD","KCIU","KCMX","KDRM","KDTW","KESC","KFNT","KGDW","KGLR","KGRR","KHAI","KHLM","KHTL","KIMT","KIRS","KISQ","KIWD","KJXN","KLAN","KLDM","KMBL","KMBS","KMCD","KMKG","KMNM","KMOP","KSAW","KMTC","KOSC","KPHN","KPLN","KPTK","KRCT","KTVC","KCFS","KRQB","KAEL","KAUM","KAXN","KBBB","KBDE","KBJI","KBRD","KCKN","KDLH","KDTL","KEVM","KFBL","KFCM","KFFM","KFRM","KGPZ","KCKC","KHIB","KBDH","KINL","KELO","KMIC","KMJQ","KMKT","KMML","KMOX","KMSP","KMVE","KMWM","KDVP","KONA","KOTG","KOWA","KPKD","KROX","KRRT","KRST","KRWF","KSTC","KSTP","KSYN","KTVF","KULM","KBIX","KCBM","KCKM","KCRX","KMBO","KGLH","KGPT","KGTR","KGWO","KHBG","KHEZ","KHKS","KJAN","KLMS","KLUL","KMCB","KMEI","KMMS","KOLV","KOSX","KPQL","KPIB","KTUP","KUBS","KUOX","KUTA","KVKS","KAIZ","KBBG","KBUM","KCGI","KCOU","KDMO","KEOS","KFAM","KIRK","KJEF","KJLN","PFKK","KTKX","KMAW","KMBY","KMCI","KMHL","KMKC","KNVD","KPLK","KPOF","KSGF","KSIK","KSTJ","KSTL","KSUS","KSZL","KTBN","KTRX","KVIH","KBIL","KBTM","KBZN","KCTB","KDLN","KGPI","KGDV","KGGW","KGTF","KHLN","KHVR","KJDN","KLVM","KLWT","KMLS","KMSO","KOLF","KPWD","KRPX","KSBX","KSDY","KTHM","KWYS","KAIA","KANW","KBBW","KBFF","KBIE","KBUB","KCDR","KEAR","KFBY","KFET","KGRI","KGRN","KHDE","KHSI","KIML","KLBF","KLNK","KLXN","KMCK","KMHN","KMLE","KOFF","KOFK","KOGA","KOKS","KOLU","KONL","KSCB","KSNY","KVTN","KBAM","KBTY","KCXP","KDRA","KEKO","KELY","KFLX","KGAB","KHND","KHTH","KINS","KLAS","KLOL","KLSV","KLWL","KMEV","KNFL","KRNO","KTPH","KUCC","KVGT","KWMC","KTNX","KAFN","KASH","KBML","KCNH","KCON","KEEN","KERR","KHIE","KLCI","KLEB","KMHT","KPSM","KACY","KBLM","KCDW","KEWR","KLDJ","KVAY","KMIV","KMJX","KMMU","KNEL","KTEB","KTTN","KWRI","KWWD","KABQ","KALM","KATS","KAXX","KCAO","KCNM","KCVN","KCVS","KDMN","KFMN","KFSU","KGNT","KGUP","KHMN","KHOB","KLAM","KLRU","KLSB","KLVS","KONM","KROW","KRTN","KSRR","KSAF","KSVC","KTCC","KTCS","KSKX","KWSD","KALB","KART","KBGM","KBUF","KDKK","KDSV","KELM","KELZ","KFOK","KFRG","KGFL","KHPN","KHTO","KIAG","KISP","KITH","KJFK","KJHW","KLGA","KLKP","KMGJ","KMSS","KMSV","KMTP","KOGS","KOIC","KOLE","KPBG","KPOU","KRME","KROC","KSCH","KSLK","KSWF","KSYR","KHWV","KAVL","KCLT","KCTZ","KECG","KEDE","KEWN","KFAY","KFBG","KFFA","KGSB","KGSO","KHFF","KHKY","KHSE","KUKF","KILM","KINT","KISO","KLBT","KLHZ","KMQI","KMRN","KMEB","KOAJ","KOCW","KPGV","KPOB","KRDU","KRWI","KRZZ","KSOP","KRUQ","KSVH","KJQF","KASY","KBIS","KBPP","KDIK","KDVL","KFAR","KGFK","KISN","KJMS","KMIB","KMOT","KPMB","KRDR","KBWP","KXWA","KAKR","KAOH","KUNI","KAXV","KBJJ","KBKL","KCAK","KCGF","KCLE","KCMH","KDAY","KDFI","KFDY","KFFO","KGQQ","KHAO","KHTW","KILN","KHZY","KLCK","KLNN","KLUK","KMFD","KMGY","KMNN","KMWO","KOSU","KOXD","KPHD","KPMH","KSGH","KSKY","KTDZ","KTOL","KYNG","KZZV","KADM","KADH","KAXS","KBVO","KBKN","KCHK","KCKA","KCLK","KCSM","KCUH","KDUA","KDUC","KELK","KEND","KFDR","KFSI","KGAG","KGOK","KGUY","KHBR","KHHW","KLAW","KLTS","KMIO","KMKO","KMLC","KOKC","KOKM","KOUN","KPNC","KPWA","KRKR","KRVS","KSNL","KSUD","KSWO","KTIK","KTUL","KWDG","KWWR","KAST","KBKE","KBNO","KBOK","KCVO","KCZK","KDLS","KEUG","KHRI","KHIO","KGCD","KLGD","KLKV","KLMT","KMFR","KONO","KONP","KOTH","KTMK","KPDT","KPDX","KPFC","KRBG","KRDM","KREO","KSLE","KTTD","KABE","KAGC","KAOO","KAVP","KLOM","KBFD","KBVI","KBTP","KMQS","KDUJ","KDYL","KERI","KFKL","KCXY","KHZL","KIDI","KIPT","KJST","KLBE","KLHV","KLNS","KMDT","KGKJ","KMPO","KMUI","KPHL","KPIT","KPNE","KPSB","KPTW","KRDG","KRVL","KUNV","KSEG","KOYM","KTHV","KUKT","KWAY","KWBW","KAFJ","KBID","KOQU","KUUU","KPVD","KSFZ","KWST","KAIK","KAND","KARW","KBNL","KBBP","KCAE","KCDN","KCEU","KCHS","KCRE","KCUB","KDLC","KFLO","KGYH","KGGE","KGMU","KGRD","KGSP","KCQW","KHXD","KHVS","KMMT","KMYR","KOGB","KRBW","KUZA","KSSC","KABR","KATY","KBKX","KFSD","KHON","KLEM","KLQK","KMBG","KMHE","KPHP","KPIR","KRAP","KRCA","KSPF","KBTN","KMDS","KIEN","KYKN","KAPT","KBNA","KCHA","KCKV","KCSV","KFYM","KGCY","KGHM","KGKT","KMEM","KMKL","KMMI","KMOR","KMQY","KMRC","KNQA","KPHT","KRKW","KRNC","KSYI","KTHA","KTRI","KTYS","KUCY","KUOS","KABI","KACT","KADS","KAFW","KALI","KAMA","KASL","KAUS","KBYY","KBBD","KBGD","KBIF","KBKD","KBMT","KBPT","KBRO","KBWD","KCDS","KCFD","KCLL","KCNW","KCOM","KCOT","KCRP","KCRS","KCXO","KCZT","KDAL","KDFW","KDHT","KDLF","KDRT","KDWH","KDYS","KEFD","KELA","KELP","KERV","KETN","KFST","KFTW","KNFW","KGGG","KGLE","KGLS","KGRK","KGVT","KBPG","KHLR","KHOU","KHPY","KHRL","KUTS","KIAH","KILE","KINK","KIWS","KJAS","KJCT","KJSO","KCWC","KLBB","KLFK","KLBX","KLRD","KMAF","KMDD","KMFE","KOSA","KMRF","KMWL","KNGP","KNGW","KNQI","KOCH","KONY","KOZA","KPEQ","KGYI","KPPA","KPRX","KPSN","KPSX","KPVW","KRBD","KRCK","KRFG","KRKP","KRND","KSAT","KSEP","KSGR","KSJT","KSKF","KSLR","KSNK","KSPS","KSSF","KSWW","KTDW","KTPL","KTRL","KTYR","KUVA","KVCT","KVHN","KWEA","KARM","KBCE","KBDG","KBMC","KBTF","KCDC","KCNY","KDPG","KDTA","KENV","KFOM","KHIF","KHVE","KKNB","KLGU","KMLF","KOGD","KPUC","KPVU","KRIF","KSGU","KSLC","KVEL","KBTV","KEFK","KCDA","KMPV","KMVL","KRUT","KVSF","KAPH","KBCB","KBKT","KCHO","KDAA","KDAN","KDCA","KNDY","KFAF","KFKN","KFRR","KGVE","KHSP","KIAD","KLFI","KLNP","KLKU","KLVL","KLYH","KMFV","KHEF","KNGU","KNTU","KNYG","KORF","KPHF","KPSK","KPTB","KRIC","KROA","KSHD","KVJI","KWAL","KOKV","KALW","KBFI","KBLI","KCLM","KCLS","KEAT","KELN","KEPH","KORS","KESW","KFHR","KGEG","KGRF","KHQM","KKLS","KBVS","KMWH","KNUW","KOKH","KOLM","KOMK","KPAE","KPSC","KPUW","KPWT","KRLD","KRNT","KSEA","KSFF","KSHN","KSKA","KTCM","KTDO","KTIW","KUIL","KYKM","KBKW","KBLF","KCKB","KCRW","KEKN","KHLG","KHTS","KLWB","KMGW","KMRB","KPKB","KAHH","KARV","KASX","KATW","KAUW","KCLI","KCMY","KCWA","KEAU","KEGV","KENW","KETB","KFLD","KGRB","KGTG","KHYR","KISW","KJVL","KLNR","KLSE","KMDZ","KMFI","KMKE","KMSN","KMTW","KMWC","KOEO","KOSH","KPDC","KPKF","KRAC","KRHI","KRPD","KRNH","KRRL","KSBM","KSTE","KSUE","KSUW","KUES","KUNU","KVOK","KAFO","KBPI","KBYG","KCOD","KCPR","KCYS","KDGW","KEAN","KECS","KEMM","KEVW","KFBR","KGCC","KGEY","KJAC","KLAR","KLND","KLSK","KPOY","KPNA","KRIW","KRKS","KRWL","KSAA","KSHR","KTHP","KTOR","KWRL","SUAG","SUBU","SUMO","SUCA","SUDU","SULS","SUMU","SUPU","SURV","SUVO","SUSO","SUTB","SUTR","UTTT","UTKA","UTSN","UTSB","UTKF","UTFN","UTSA","UTSK","UTNN","UTSS","UTST","UTNU","TVSB","TVSC","TVSM","TVSU","TVSA","SVPA","SVAN","SVBC","SVST","SVEZ","SVGD","SVPT","SVSR","SVBI","SVSB","SVCN","SVCB","SVCD","SVED","SVIC","SVIE","SVKA","SVKM","SVPR","SVSE","SVTM","SVUM","SVBS","SVPC","SVVA","SVPE","SVTC","SVCR","SVJC","SVCL","SVVP","SVBM","SVCO","SVMD","SVVG","SVRS","SVMT","SVMG","SVAC","SVGU","SVCU","SVCP","SVGI","SVLF","SVPM","SVSO","SVSA","SVVL","SVMI","SVSP","SVON","SVCG","SVMC","SVSZ","TUPJ","TUPA","TUPW","TIST","TISX","VVCS","VVVT","VVPC","VVCM","VVCT","VVDN","VVBM","VVDB","VVPK","VVNB","VVCI","VVTS","VVCR","VVNT","VVPQ","VVRG","VVDL","VVVH","VVPR","VVTH","VVDH","VVCA","VVVD","VVNS","VVTX","VVPB","NVSF","NVSL","NVSP","NVSI","NVSX","NVSU","NVSO","NVSG","NVSN","NVSR","NVSH","NVSW","NVSZ","NVSS","NVSE","NVSM","NVST","NVVQ","NVVV","NVSV","NVVA","NVVB","NVVD","NVVF","NVVI","NVVW","NVSA","NVSC","NVSD","NVSQ","NLWF","NLWW","NSMA","NSAU","NSFA","NSFI","OYMS","ODAL","OYAA","OYBI","OYHD","OYKM","OYGD","OYQN","OYSY","OYRN","OYSQ","ODAS","OYMB","OYSH","OYSN","OYAT","OYBN","OYTZ","FMCZ","FAPA","FABE","FACD","FAEL","FAPJ","FAMW","FAPE","FAUT","FAQT","FABL","FAFB","FAHR","FATN","FAWM","FAGC","FALA","FAOR","FAWB","FAGM","FAWK","FADK","FALE","FAEM","FAHL","FALY","FAMG","FAMU","FANC","FAPM","FADQ","FARB","FAUL","FAVG","FAVY","FAAL","FAER","FAGI","FAHS","FALO","FALD","FATZ","FAMS","FAPH","FAPP","FATH","FAUS","FAMD","FAHW","FAKP","FAMN","FAKN","FANG","FANS","FASZ","FASC","FAKD","FAMM","FAPN","FAPS","FARI","FAVB","FAAG","FAAB","FAKM","FAKZ","FAKU","FALC","FAPK","FASB","FASS","FAUP","FACT","FAGG","FAMO","FAOH","FAOB","FAPG","FARS","FALW","FAVR","FLSO","FLND","FLCP","FLMF","FLMA","FLLS","FLZB","FLSW","FLKS","FLBA","FLKY","FLLI","FLNA","FLKL","FLKO","FLLK","FLMG","FLSS","FLSN","FVBU","FVHA","FVCH","FVMU","FVKB","FVCZ","FVMH","FVMV","FVWN","FVFA","FVWT","FVTL"] + "icaoIds": ["OMAL","OMAA","OMAD","OMAM","OMBY","OMDL","OMFJ","OMSJ","OMDW","OMDB","OMDM","OMRK","OADZ","OAFZ","OARZ","OAHN","OASN","OAQN","OAMS","OABN","OAFR","OAMN","OAGN","OADS","OACC","OABT","OADY","OAZI","OAHR","OASD","OAZJ","OAGZ","OAKB","OAKN","OATN","OARG","OAKS","OASL","OAUZ","OASH","OAJL","OASA","OAOG","OAIX","OATQ","TAPH","TAPA","TQPF","UDYZ","UDSG","FNAM","FNBG","FNCT","FNLB","FNKU","FNCA","FNGI","FNXA","FNHU","FNUB","FNCV","FNME","FNWK","FNSU","FNPA","FNLU","FNCF","FNDU","FNLK","FNLZ","FNZG","FNCH","FNSA","FNCP","FNMA","FNCZ","FNUE","FNUA","FNMO","FNNG","FNUG","FNZE","FNBC","FNSO","SCRM","SABE","SAZB","SAZC","SADP","SAEZ","SAAJ","SADL","SAZM","SAZO","SAZF","SAZH","SAZP","SAZL","SAZT","SAZV","SANC","SARS","SARE","SAVR","SAVC","SAVD","SAVE","SAWS","SAVM","SAVY","SAVT","SAWM","SACO","SACC","SAOC","SAOD","SARL","SARC","SARM","SATM","SATG","SATU","SAAC","SAAG","SAAP","SATC","SARF","SATK","SASJ","SAZG","SAZR","SANL","SAMR","SAMM","SAME","SATD","SARI","SARP","SAHZ","SAZY","SAZW","SAHC","SAZN","SAHS","SAZS","SAVB","SAHR","SAVJ","SAVQ","SAVN","SAVS","SAVV","SASO","SASA","SAST","SANU","SAOU","SAOS","SAOR","SAWA","SAWR","SAVH","SAWP","SAWD","SAWG","SAWT","SAWU","SAWJ","SANW","SAFS","SAFR","SATR","SAAR","SAAV","SANR","SANE","SAWE","SAWH","SANT","NSAS","NSTU","LOWK","LOWW","LOWL","LOWS","LOWG","LOWI","LOIH","YSCB","YMAY","YARM","YLMQ","YBHI","YBTH","YBNA","YBKE","YBRW","YSBK","YBRN","YCBA","YCDO","YSCN","YCNK","YCFS","YCAH","YCTM","YCNM","YCBB","YCBR","YCAS","YCUA","YCWR","YCOR","YSDU","YMDG","YDLQ","YEVD","YFIL","YFST","YFBS","YGTH","YGFN","YGLI","YSMB","YGDH","YGLB","YHAY","YIVL","YKMP","YLHI","YLRD","YLIS","YMER","YMOR","YMND","YMRY","YNBR","YNHS","YYNG","YSNW","YNAR","YSCO","YWLM","YNYN","YORG","YCOM","YPKS","YPMQ","YSGT","YSSY","YTOC","YTEM","YSTW","YTRE","YTMU","YTIB","YQDI","YWWA","YSWG","YWLG","YWCA","YWCH","YWOL","YWWL","YSRI","YBAS","YAUV","YALX","YAYE","YBRL","YBTI","YCOO","YCFD","YCKI","YDVR","YDLV","YPDN","YELD","YFNE","YGBI","YPGV","YGPT","YGTE","YTGT","YHMB","YHOO","YHBY","YHBR","YINW","YJAB","YKCA","YKCS","YKKG","YPTN","YLEV","YLKN","YMHU","YMCR","YMGB","YMVG","YMGD","YMDS","YMQA","YMNS","YMSF","YMUP","YNUM","YKPT","YRNG","YRKD","YRRB","YNGU","YSMP","YSNB","YTBR","YTNK","YTMY","YVRD","YWAV","YWOR","YWTL","YYND","YARY","YABI","YAPH","YNPE","YAGD","YAUR","YAMC","YAYR","YLLE","YBAR","YBUD","YBAU","YBIE","YBAW","YBCK","YBLL","YBTR","YBPI","YBBN","YBOU","YBEO","YBKT","YBDV","YCCA","YCRY","YCMU","YCMW","YCMT","YCCT","YCCY","YBCS","YBCV","YCKN","YCDR","YCOE","YCHT","YUNY","YDAY","YDLT","YDRH","YDKI","YDMG","YDBR","YDOR","YDBI","YDRI","YDPD","YDIX","YDYS","YPMP","YEML","YESE","YGAY","YGAM","YGDS","YBOI","YGKL","YGLE","YGLO","YGLA","YGDI","YGON","YGTN","YGNV","YGYM","YHTL","YHUG","YHID","YHHY","YHDY","YBHM","YHBA","YIFY","YIFL","YIGM","YIKM","YINJ","YLHR","YBMA","YISF","YJLC","YJDA","YCSV","YKRY","YKLB","YKML","YKLA","YKPR","YKMB","YSPV","YKUB","YKOW","YLIN","YLFD","YLND","YCGO","YLOR","YLRE","YLHS","YLOV","YLRS","YLRA","YLAH","YLZI","YMYB","YBSU","YMOT","YBMK","YMEU","YMMU","YMTO","YMRB","YMBA","YMIT","YMGV","YMIR","YMWX","YMAE","YDNI","YNAP","YNSH","YNTN","YORC","YYKI","YBOK","YMTI","YMNK","YBCG","YMOO","YOEN","YOSB","YMNY","YTMO","YPAM","YBPN","YRMD","YROM","YROB","YBRK","YRSB","YRTP","YSII","YSPK","YSGE","YSPT","YSPE","YSTI","YSMR","YWBS","YTGA","YTDR","YTNG","YTEE","YBTL","YTWB","YTHY","YMAA","YUDA","YQLP","YMTB","YVRS","YWCK","YWND","YBWP","YWTN","YMLS","YWDH","YWDL","YWMP","YSHR","YBWW","YYMI","YTGM","YTAM","YTAA","YBWN","YSGW","YPAD","YAMK","YAMT","YCWL","YCDU","YCBP","YCEE","YCWI","YDLK","YERN","YEDA","YMGN","YHAW","YIDK","YINN","YKBY","YKSC","YYTA","YBLC","YLEC","YLOK","YMTG","YMPA","YMCT","YMUG","YOOM","YALA","YMUK","YMWT","YNRC","YNUB","YOOD","YCOD","YOLD","YYOR","YPDI","YPSH","YPLC","YPIR","YPAG","YPMH","YREN","YMRE","YMYT","YPWR","YWUD","YWHA","YMIN","YWYY","YDPO","YFLI","YGTO","YMHB","YSTH","YKII","YMLT","YSMI","YSRN","YQNS","YARA","YMAV","YBLA","YBNS","YBDG","YCRG","YECH","YGLG","YHML","YHSM","YHPN","YKER","YPOK","YMMB","YMEN","YMML","YHOT","YMIA","YOUY","YPOD","YROI","YORB","YSHT","YSWL","YSWH","YWSL","YLTV","YWGT","YWKB","YWBL","YOLA","YMCO","YABA","YBDF","YBRM","YBLN","YBGO","YBUN","YBYS","YBWX","YBEB","YBRY","YCAG","YCOI","YCWA","YCHK","YCWY","YCUE","YCAR","YCIN","YDGA","YDRA","YDBY","YDRD","YEEB","YESP","YECL","YEXM","YFTZ","YFRT","YFLO","YFRV","YGIB","YGIA","YGDN","YGEL","YGSC","YARG","YHLC","YHIL","YPJT","YJNB","YKBR","YKBL","YFDF","YPKG","YKNG","YPKU","YKAR","YPKA","YYLR","YPLM","YLST","YLEO","YLTN","YMBL","YMGR","YMHO","YMIP","YSHK","YMJM","YMEK","YMOG","YMDI","YMGT","YMUC","YMRW","YMWA","YMYR","YSAN","YCNF","YNUL","YNRG","YNSM","YBGD","YORV","YOLW","YPBO","YPPH","YPPD","YPDO","YROE","YRYH","YRTI","YNRV","YSHG","YSOL","YSCR","YTAB","YTHD","YTEF","YTKY","YTMP","YTST","YKAL","YUSL","YWIT","YWAL","YANG","YMNE","YWDG","YWWG","YMMI","YWLU","YWWI","YWYM","YYAL","YNWN","TNCA","UBBB","UBBG","UBBL","UBBN","UBBQ","UBEE","UBBY","LQMO","LQSA","LQTZ","LQBK","TBPB","VGBR","VGEG","VGCM","VGCB","VGHS","VGJR","VGIS","VGRJ","VGSD","VGSG","VGSH","VGSY","EBAW","EBZR","EBBR","EBCI","EBLG","EBKT","EBOS","DFOU","DFET","DFEZ","DFOB","DFEB","DFEF","DFOO","DFFD","DFEP","DFON","DFOD","DFCP","DFEA","DFEM","DFEG","DFOG","DFCA","DFEE","DFCL","DFOY","DFCJ","DFOT","DFER","DFED","DFEL","DFES","DFCC","LBBG","LBHS","LBPD","LBRS","LBSS","LBSF","LBSZ","LBTG","LBWN","LBGO","OBBI","HBBA","HBBE","HBBO","DBBK","DBBN","DBBP","DBBS","DBBD","DBBB","TFFJ","TXKF","WBSB","SLAG","SLSU","SLSB","SLCB","SLHI","SLHJ","SLBU","SLGY","SLMG","SLRQ","SLRY","SLRI","SLSA","SLJO","SLSM","SLSR","SLRA","SLTR","SLAP","SLLP","SLOR","SLCO","SLPR","SLPO","SLUY","SLAS","SLCA","SLCP","SLTI","SLPS","SLRB","SLJE","SLJV","SLSI","SLET","SLVG","SLVR","SLBJ","SLYA","SLTJ","SLVM","TNCB","TNCS","TNCE","SBCZ","SNOU","SBRB","SBTK","SWSN","SNAL","SBMO","SBMQ","SBOI","SWBC","SWNK","SWCA","SWKO","SWEI","SWOB","SWHT","SWII","SWTP","SBIC","SWLB","SBEG","SWMW","SBMY","SWNA","SDCG","SWPI","SBMN","SWBR","SBUA","SBTT","SBTF","SNBU","SBPS","SNBX","SNBR","SNBL","SNED","SBCV","SNJD","SNGI","SBIL","SNIU","SNIC","SNZW","SNHA","SNJB","SNJK","SBLP","SBLE","SNMU","SBUF","SNRD","SBSV","SNTF","SBTC","SNVB","SBQV","SBAC","SNWC","SBFZ","SBJU","SBJE","SBBR","SNKI","SNGA","SNMX","SBVT","SWNS","SWEC","SBCN","SBGO","SBIT","SWJW","SBMC","SWNQ","SWLC","SWUA","SWKT","SNAI","SNBC","SBRR","SNBS","SBCI","SNCP","SNGM","SBIZ","SNYE","SBSL","SBDB","SBCG","SBCR","SSCL","SSDO","SSPN","SBPP","SBTG","SBAT","SSOU","SWTU","SBBW","SWKC","SBCY","SWEK","SWDM","SWHP","SWJN","SWJU","SIZX","SILC","SWXM","SWVB","SWXV","SWSI","SWPG","SWPQ","SWRD","SWST","SWFX","SWTS","SWVC","SBAX","SNAR","SNDV","SNDT","SBGV","SBIP","SBZM","SBJF","SNJR","SNJN","SNDN","SBMK","SNNU","SNPX","SNPD","SBPC","SNZA","SNOS","SNLO","SNTO","SBUR","SBUL","SBVG","SBHT","SBBE","SNVS","SBAA","SBCJ","SNKE","SNYA","SBIH","SBEK","SBMA","SBMD","SNMA","SJNP","SNTI","SDOW","SNOX","SNMZ","SNDC","SNSW","SBSN","SNFX","SBTB","SBKG","SBJP","SSYA","SSAP","SSOG","SBBI","SBCA","SSKM","SSCP","SBCT","SSFB","SSCT","SSGY","SBGU","SBFI","SBLO","SBMG","SSZW","SSPG","SSPB","SSPI","SBTL","SBTD","SBTU","SSUM","SNRU","SBFN","SBPL","SBRF","SNQG","SNGD","SNPC","SBPB","SBTE","SBMS","SBNT","SSLT","SBBG","SSCN","SSSC","SSVP","SBCX","SSER","SBNM","SSHZ","SSIJ","SSIQ","SNLB","SBPK","SBPF","SBPA","SBSM","SBRG","SSRU","SSZR","SBTR","SBUG","SBBZ","SBCP","SBCB","SDUN","SBME","SDRS","SBVH","SWCQ","SBGM","SWJI","SSKW","SWPM","SBPV","SBBV","SSBL","SSCK","SBCM","SBCD","SBFL","SSJA","SBJA","SBJV","SBLJ","SSLN","SBNF","SSOE","SSUV","SSVI","SBCH","SBAS","SBAQ","SBAU","SBBT","SBBU","SBBP","SDAM","SIMK","SBGW","SDJL","SBAE","SBLN","SBML","SDOU","SBDN","SDSC","SBRP","SBSJ","SBSR","SDCO","SBST","SDUB","SBUP","SDVG","SBAR","SWRA","SWGN","SWDN","SWGI","SWIY","SBPJ","SBPN","MYAP","MYBG","MYBS","MYCB","MYAF","MYBC","MYAB","MYAN","MYCC","MYAW","MYGF","MYEF","MYEN","MYES","MYEH","MYAM","MYAT","MYIG","MYCI","MYRD","MYLD","MYCP","MYLS","MYMM","MYNN","MYRP","MYSM","MYAK","MYCA","MYEM","MYER","MYGW","VQBT","VQPR","VQGP","VQTY","FBOR","FBSP","FBSN","FBTL","FBKE","FBGZ","FBTS","FBFT","FBKR","FBMN","FBSV","FBSW","FBSK","FBLO","FBJW","UMBB","UMGG","UMMG","UMOO","UMMM","UMMS","UMII","MZBZ","MZPL","CYNR","CZPC","CYBA","CYBF","CYCT","CYEG","CYET","CYJA","CYLB","CYLL","CYMM","CYOD","CYOJ","CYOP","CYPE","CYPY","CYQF","CYQL","CYQU","CYRM","CYSD","CYVG","CYXH","CYYC","CYYM","CYZH","CYZU","CZHP","CYHC","CYBD","CYAL","CYAZ","CYBH","CYBL","CYCD","CYCG","CYCQ","CYCW","CYCZ","CYDL","CYDQ","CZBB","CYGB","CYHE","CYKA","CYLW","CYNJ","CYNH","CYPR","CYPW","CYPZ","CYQQ","CYQZ","CYRV","CYSE","CZAM","CYVK","CYVR","CYWH","CYWL","CYXC","CYXJ","CYXS","CYXT","CYXX","CYYD","CYYE","CYYF","CYYJ","CYZP","CYZT","CBBC","CZGF","CZML","CZMT","CZST","CZSW","CZBD","CZEE","CZMN","CZWH","CZFG","CZNG","CZSN","CYBQ","CYBR","CYBT","CYBV","CYCR","CYDN","CZTA","CYFO","CYGM","CYGO","CYGX","CYIV","CYLR","CYNE","CYOH","CYPG","CYQD","CYRS","CYST","CZLQ","CYTH","CYWG","CYYI","CYYL","CYYQ","CZAC","CZGI","CZGR","CZJG","CZJN","CZTM","CYCH","CYCL","CYFC","CYQM","CYSJ","CYSL","CZBF","CYAY","CYDF","CYDP","CYHO","CYJT","CYMH","CYFT","CYQX","CYCA","CYWK","CYYR","CYYT","CZUM","CYKD","CYVL","CYEV","CYWE","CYFR","CYFS","CYGH","CYHI","CYHY","CYJF","CYMD","CYOA","CYPC","CYRA","CYLK","CYSM","CYSY","CYUB","CYVQ","CYWJ","CYWY","CYZF","CZFM","CZFN","CYID","CYHZ","CYPD","CYQI","CYQY","CYZX","CYAB","CYBB","CYBK","CYCB","CYCO","CYCS","CYCY","CYEK","CYEU","CYFB","CYGT","CYGZ","CYHK","CYIO","CYLC","CYLT","CYRB","CYRT","CYSK","CYTE","CYUT","CYUX","CYVM","CYVN","CYXN","CYXP","CYYH","CYZS","CZMD","CYCK","CYAQ","CYAC","CYAG","CYAM","CYAT","CYCC","CYCE","CYSN","CYCN","CYEL","CYEM","CYER","CYFA","CYFH","CYGK","CYGQ","CYHD","CYHF","CYHM","CYHN","CYHP","CYIB","CYKM","CYKF","CYKX","CYLD","CYLH","CYLS","CYMG","CYMO","CYKP","CYOO","CYOS","CYOW","CYPL","CYPM","CYPO","CYPQ","CYQA","CYQG","CYQK","CYQN","CYQS","CYQT","CYRL","CYRO","CYSB","CYSH","CYSP","CYTA","CYTL","CYTR","CYTS","CYTZ","CYVV","CYVZ","CYWA","CYWP","CYXL","CYXR","CYXU","CYXZ","CYYB","CYYU","CYYW","CYYZ","CYZE","CYZR","CZKE","CZPB","CZRJ","CZSJ","CZUC","CYSU","CYYG","CYKO","CYLU","CYAH","CYAD","CYBC","CYBG","CYBX","CYDO","CYEY","CYFE","CYGL","CYGP","CYGR","CYGV","CYGW","CYHR","CYIF","CYIK","CYJN","CYAS","CYKL","CYKQ","CYLP","CYLQ","CYME","CYML","CYMT","CYMW","CYMX","CYNA","CYNC","CYND","CYNM","CYHH","CYPH","CYLA","CYPN","CYPX","CYQB","CYHA","CYRI","CYRJ","CYRQ","CYSC","CYTF","CYFJ","CYTQ","CYMU","CYUL","CYUY","CYVB","CYVO","CYVP","CYKG","CYXK","CYYY","CYZG","CYZV","CZBM","CZEM","CYBE","CYEN","CYHB","CYKC","CYKJ","CYKY","CYLJ","CYMJ","CYNL","CYPA","CYQR","CYQV","CYQW","CYSF","CYVC","CYVT","CYXE","CYYN","CZFD","CZPO","CZWL","CYDM","CYDA","CYDB","CYHT","CYMA","CYOC","CYQH","CYXQ","CYXY","CYZW","CZFA","YPCC","FZKJ","FZFD","FZEN","FZEA","FZQA","FZSK","FZQG","FZTK","FZQC","FZKA","FZWC","FZWT","FZVI","FZVA","FZWA","FZVR","FZUA","FZUG","FZVM","FZVS","FZUK","FZAA","FZAB","FZAJ","FZAL","FZAM","FZAG","FZAR","FZQM","FZBO","FZCB","FZBA","FZOK","FZCA","FZBT","FZCE","FZCV","FZBI","FZOC","FZOA","FZOP","FZFU","FZGA","FZNP","FZNA","FZJH","FZFP","FZGV","FZMA","FZFK","FZFA","FZRB","FZRF","FZRM","FZRQ","FZRA","FZIC","FZIR","FZGN","FEFN","FEFF","FEFZ","FEGE","FEFY","FEFR","FEFW","FEFT","FEFC","FEFG","FEGM","FEGR","FEFO","FEFM","FEGU","FEFS","FEGF","FEGZ","FEFI","FEGO","FCBM","FCBY","FCBZ","FCBB","FCOB","FCOO","FCOM","FCOE","FCOK","FCBS","FCOT","FCOI","FCPL","FCPA","FCMM","FCBD","FCOG","FCBL","FCPP","FCBK","FCOU","FCOS","LSZB","LSGG","LSZS","LSME","LSZC","LSZR","LSZA","LSGS","LSZH","DIAP","DIOF","DIGN","DISP","DITB","DISS","DIAO","DIAU","DIOD","DIDV","DIGA","DIDK","DIGL","DIMN","DIDL","DIBI","DIFK","DIKO","DIBK","DISG","DITM","DIYO","DIBU","DIBN","NCAI","NCAT","NCMG","NCMH","NCMR","NCMK","NCPY","NCPK","NCRG","SCBA","SCCC","SCCY","SCHR","SCAS","SCFA","SCCF","SCBE","SCTT","SCAR","SCRA","SCAT","SCES","SCLL","SCIE","SCGE","SCCH","SCQB","SCSE","SCOV","SCTC","SCQP","SCTO","SCPC","SCFT","SCFR","SCPQ","SCTE","SCPV","SCAP","SCST","SCTN","SCJO","SCAC","SCVD","SCNT","SCCI","SCSB","SCFM","SCGZ","SCTL","SCEL","SCKP","SCDA","SCIP","SCVM","SCAN","SCRD","FKKN","FKYS","FKKY","FKKO","FKKI","FKKJ","FKKH","FKKL","FKKD","FKAN","FKKR","FKKG","FKKV","FKKU","FKKS","FKKM","FKKW","FKKB","FKKF","FKKC","ZSAQ","ZSBB","ZSFY","ZSOF","ZSTX","ZSWA","ZBAA","ZUWL","ZUWS","ZUCK","ZUDZ","ZUQJ","ZULP","ZUWX","ZSFZ","ZSQZ","ZSLO","ZSSM","ZSWY","ZSAM","ZLDH","ZLXH","ZLQY","ZLJQ","ZLJC","ZLLL","ZLLN","ZLTS","ZLZY","ZGGG","ZGFS","ZGHZ","ZGMX","ZGOW","ZGSZ","ZGXN","ZGZJ","ZGSD","ZGBS","ZGBH","ZGHC","ZGKL","ZGZH","ZGNN","ZGWZ","ZUYI","ZUAS","ZUBJ","ZUNP","ZUGY","ZULB","ZUPS","ZUTR","ZUMT","ZUZY","ZJHK","ZJSY","ZBDH","ZBCD","ZBHD","ZBSJ","ZBTS","ZBXT","ZBZJ","ZYDQ","ZYFY","ZYHE","ZYHB","ZYJD","ZYJM","ZYJS","ZYJX","ZYLD","ZYMD","ZYQQ","ZYMH","ZYYL","ZHXY","ZHAY","ZHCC","ZHLY","ZHNY","ZHEC","ZHES","ZHSN","ZHGH","ZHSS","ZHSY","ZHHH","ZHXF","ZHYC","ZGCZ","ZGYY","ZGCD","ZGHA","ZGDY","ZGCJ","ZGHY","ZGLG","ZGSY","ZSCG","ZSSH","ZSLG","ZSNJ","ZSNT","ZSRG","ZSSZ","ZSWX","ZSXZ","ZSYN","ZSYA","ZSJD","ZSJA","ZSJJ","ZSCN","ZSGZ","ZSSR","ZSYC","ZYCC","ZYBA","ZYJL","ZYBS","ZYTN","ZYYJ","ZYSQ","ZYAS","ZYCY","ZYCH","ZYDD","ZYTL","ZYJZ","ZYTX","ZYXC","ZYYK","ZBOW","ZBCF","ZBDS","ZBER","ZBHH","ZBLA","ZBUL","ZBHZ","ZBMZ","ZBYZ","ZBTL","ZBUH","ZBXH","ZBES","ZLGY","ZLIC","ZLZW","ZLHB","ZLGL","ZLGM","ZLDL","ZLXN","ZLYS","ZLAK","ZBCZ","ZBDT","ZLYA","ZLHZ","ZBLL","ZLSN","ZBYN","ZLYL","ZBXZ","ZLXY","ZSHZ","ZSDY","ZLJN","ZSLY","ZSQD","ZSJN","ZSWF","ZSWH","ZSYT","ZSPD","ZSSS","ZBYC","ZUDA","ZUHY","ZUUU","ZUDX","ZUDC","ZUGH","ZUGU","ZUJZ","ZUKD","ZULZ","ZUMY","ZUNC","ZUZH","ZUTF","ZUXC","ZUYB","ZBTJ","ZWAT","ZWAK","ZWBL","ZWFY","ZWHM","ZWTN","ZWCM","ZWKC","ZWSH","ZWKN","ZWKL","ZWKM","ZWNL","ZWRQ","ZWHZ","ZWSS","ZWTC","ZWTL","ZWWW","ZWYN","ZUBD","ZULS","ZUNZ","ZUAL","ZURK","ZPBS","ZPCW","ZPDQ","ZPDL","ZPJH","ZPJM","ZPPP","ZPLJ","ZPLC","ZPMS","ZPSM","ZUTC","ZPWS","ZPYM","ZPZT","ZSHC","ZSZS","ZSLQ","ZSJU","ZSNB","ZSWZ","ZSYW","SKLT","SKLP","SCSF","SKRA","SKAN","SKAM","SKLC","SKCU","SKEB","SKMD","SKIG","SKRG","SKPN","SKNC","SKOT","SKPR","SKTU","SKUR","SKAT","SKUC","SKCN","SKSA","SKTM","SKBQ","SKCG","SKMG","SKMP","SKVL","SKPA","SKSO","SKTA","SKMZ","SKAC","SKYA","SKFL","SKSV","SKTQ","SKYP","SKHC","SKOE","SKPZ","SKTD","SKGP","SKPP","SKMB","SKAG","SKVP","SKAD","SKCP","SKBS","SKCD","SKCA","SKJU","SKNQ","SKUI","SKML","SKMR","SKPQ","SKBO","SKBM","SKPD","SKMF","SKSJ","SKNV","SKPI","SKLM","SKRH","SKBC","SKPL","SKSM","SKAP","SKCI","SVWX","SKNA","SKUB","SKVV","SKEH","SKIP","SKPS","SKCO","SKCC","SKOC","SKTB","SKLG","SKAS","SKVG","SKAR","SKPE","SKSP","SKPV","SKBG","SKCM","SKEJ","SKRU","SKCV","SKCZ","SKTL","SKHA","SKGI","SKIB","SKQU","SKBU","SKCL","SKGO","SKUL","SKCR","SKMU","SKGA","SKIM","SKPC","SKSL","MRAN","MRLC","MRRF","MROC","MRUP","MRMJ","MRLB","MRNC","MRNS","MRIA","MRCR","MRTM","MRBC","MRGP","MRLM","MRBT","MRBA","MRDK","MRGF","MRCH","MRCC","MRPJ","MRPM","MRTR","MRSV","MRQP","MRSI","MRPV","MUPB","MUCM","MUCA","MUCC","MUCF","MUBY","MUMZ","MUBA","MUGT","MUGM","MUHG","MUMO","MUCL","MUNG","MUSN","MUHA","MUVT","MUVR","MUKW","MULM","MUSJ","MUTD","MUSS","MUCU","MUBR","MUSC","GVBA","GVBR","GVMA","GVNP","GVAN","GVSN","GVAC","GVMT","GVSF","GVSV","TNCC","YPXM","LCGK","LCLK","LCEN","LCRA","LCPH","LKCS","LKTB","LKKV","LKMR","LKMT","LKZA","LKOL","LKPO","LKPD","LKPR","LKVO","LKHO","LKKU","EDNY","EDSB","ETIE","EDTL","EDFM","EDDS","EDMA","EDQD","ETSF","EDJA","EDQG","EDQM","ETSI","ETIK","ETIN","EDDM","EDDN","EDMO","EDMS","EDQE","EDDT","EDDB","EDCD","EDDW","EDWB","EDDH","EDHI","EDDF","ETHF","EDVK","ETOU","EDBH","EDBN","EDCG","EDAH","EDCP","EDAX","ETNL","EDOP","EDWG","EDWR","EDWZ","EDVE","EDWE","ETMN","EDDV","EDWJ","EDWL","EDWS","EDWY","EDWU","EDWI","EDWD","EDKA","EDLI","EDDK","EDLW","EDDL","EDLE","EDDG","ETNG","ETUO","EDLN","EDLV","EDLP","EDGS","EDRB","EDFH","ETAR","ETAD","EDRZ","EDDR","EDDC","EDAU","EDDP","EDBC","EDCK","EDAQ","EDHN","EDXF","EDXW","EDXB","EDXH","EDHK","EDHL","EDXY","EDXO","EDXJ","ETNS","EDAC","EDGE","EDDE","HDAS","HDAM","HDOB","HDMO","HDTJ","EKCH","EKRN","EKAH","EKKA","EKSV","EKVJ","EKYT","EKLS","EKSN","EKTS","EKMB","EKRK","EKBI","EKEB","EKOD","EKSB","EKSP","TDPD","TDCF","MDBH","MDJB","MDPC","MDCZ","MDSD","MDCR","MDPP","MDCY","MDAB","MDST","DAUA","DATM","DAUT","DAAG","DABB","DABT","DAOR","DAAE","DAUB","DAOI","DABC","DAAD","DAOY","DAUO","DAUE","DAUG","DAAJ","DAUZ","DAAP","DAAV","DAFH","DAUL","DAOV","DAAY","DAOO","DAOL","DAUH","DAUU","DAUK","DAAS","DAOS","DABP","DATG","DAUI","DAAT","DABS","DAOB","DAOF","DAON","SECU","SETU","SERO","SEMH","SETN","SEGS","SEII","SEST","SEGU","SETM","SEMA","SESV","SEJI","SEMT","SEPV","SESC","SETH","SEMC","SEJD","SECO","SETI","SESM","SEQM","SESA","SENL","SEPT","SETR","SEAM","EETN","EEKA","EEPU","EEKE","EETU","HEGN","HEMA","HEAX","HEBA","HE25","HECA","HELX","HEDK","HEOW","HEKG","HEBL","HESN","HEAT","HEPS","HETR","HESC","HESH","HETB","HEAL","HEMM","HEAR","HEMK","HHAS","HHSB","HHTS","HHMS","LEMG","LEGR","LEAM","LEBA","LEMO","LERT","LEZL","LEJR","LEHC","LETL","LEZG","LEAS","GCRR","GCFV","GCGM","GCLP","GCLA","GCHI","LEXJ","LERL","LELN","LEBG","LESA","LEVD","LEAB","LEBL","LEGE","LEDA","LESU","LERS","LEBZ","LECO","LEST","LEVX","LEIB","LEMH","LEPA","LELO","LEMD","LETO","GEML","LELC","LEMI","LEPP","LEBB","LESO","LEVT","LEAL","LECH","LEVC","HAAB","HASM","HABD","HADM","HADT","HADC","HAMM","HAGN","HALL","HAMA","HAPW","HASO","HADR","HAGM","HABE","HADD","HANG","HAFN","HAGH","HAGB","HAGR","HAJM","HAML","HAMN","HANJ","HANK","HASK","HABB","HAKD","HAGO","HASL","HAJJ","HAKL","HAWR","HAAX","HAHU","HAMK","HAAM","HALA","HABC","HABU","HAMT","HAMR","HASD","HATP","HAMJ","HAWC","EFLP","EFKA","EFKJ","EFSI","EFMI","EFSA","EFVR","EFKI","EFJY","EFHA","EFUT","EFET","EFIV","EFKE","EFKT","EFRO","EFSO","EFTP","EFKK","EFVA","EFJO","EFIT","EFKS","EFOU","EFYL","EFKU","EFPO","EFHK","EFHF","EFHV","EFMA","EFTU","NFNH","NFFN","NFND","NFNA","NFCI","NFNW","NFKD","NFNO","NFNB","NFNK","NFMO","NFNG","NFOL","NFVB","NFNU","NFNL","NFFR","NFNR","NFNS","NFNM","NFCS","NFMA","NFFO","NFNV","NFVL","NFSW","EKVG","EGYP","SFAL","PTKK","PTSA","PTPN","PTYA","LFHU","LFLW","LFLC","LFLB","LFLJ","LFMH","LFLS","LFHP","LFLY","LFLL","LFBK","LFKX","LFHM","LFLP","LFHO","LFLO","LFLU","LFLV","LFHS","LFHY","LFLA","LFSD","LFGJ","LFQG","LFLN","LFRB","LFRD","LFRO","LFRJ","LFRH","LFRU","LFRN","LFRT","LFRQ","LFRV","LFLD","LFLX","LFOZ","LFOT","LFKJ","LFKB","LFKC","LFKF","LFKO","LFKS","LFGA","LFSN","LFSG","LFJL","LFSF","LFSR","LFST","LFSZ","LFQV","LFAQ","LFAC","LFPC","LFQT","LFQQ","LFAT","LFPG","LFPO","LFPN","LFRC","LFRK","LFRG","LFAB","LFOE","LFRF","LFOH","LFOP","LFBA","LFBU","LFBZ","LFBD","LFSL","LFBG","LFBE","LFBL","LFBH","LFBN","LFBX","LFBI","LFBP","LFDN","LFCY","LFMU","LFMK","LFCK","LFTW","LFCI","LFBT","LFNB","LFMT","LFMP","LFCR","LFBO","LFCC","LFJR","LFOU","LFRI","LFEY","LFRE","LFRM","LFOO","LFOV","LFRS","LFRZ","LFMV","LFMR","LFMD","LFMQ","LFNA","LFTZ","LFML","LFMN","LFMI","LFMA","LFNC","LFTH","FOOL","FOGA","FOOD","FOON","FOGQ","FOGJ","FOGR","FOGF","FOGE","FOGG","FOGM","FOGI","FOOY","FOOT","FOGB","FOOE","FOOK","FOGK","FOOR","FOGW","FOOI","FOOH","FOOG","FOOB","FOGV","FOOM","FOGO","EGTB","EGHD","EGHJ","EGLK","EGXH","EGUB","EGBB","EGNH","EGHH","EGKB","EGGD","EGNL","EGVN","EGNC","EGSC","EGBE","EGCN","EGNX","EGTE","EGLF","EGVA","EGBP","EGBJ","EGXU","EGNJ","EGNS","EGHE","EGYM","EGKR","EGNM","EGLC","EGHC","EGKK","EG74","EGLL","EGUL","EGGP","EGGW","EGDL","EGMD","EGCC","EGUN","EGNV","EGNT","EGWU","EGBN","EGHQ","EGSH","EGVO","EGBK","EGTK","EGXC","EGSU","EGHL","EGHR","EGUY","EGTO","EGMC","EGHI","EGXP","EGSS","EGDJ","EGXW","EGDY","EGJB","EGJA","EGMH","EGNO","EGAA","EGAC","EGQB","EGAB","EGAE","EGXJ","EGPD","EGQL","EGPL","EGPR","EGEC","EGPN","EGPH","EGED","EGEF","EGQK","EGPF","EGPI","EGPE","EGPA","EGQS","EGPB","EGET","EGES","EGEN","EGEO","EGPK","EGEP","EGPT","EGEI","EGER","EGPO","EGPU","EGPW","EGEH","EGPC","EGEW","EGTG","EGNR","EGFF","EGFE","EGFH","EGOV","EGKA","TGPY","UGSS","UGSB","UGKO","UGTB","SOCA","SOGS","SOOM","SOOA","SOOG","SOOR","SOOS","DGSI","DGSN","DGAA","DGLE","DGTK","LXGB","BGJN","BGUQ","BGUK","BGQQ","BGTL","BGUM","BGBW","BGCH","BGAA","BGCO","BGGH","BGPT","BGKK","BGSS","BGMQ","BGSF","GBYD","GUOK","GUSB","GUCY","GUFH","GUFA","GUSI","GUXN","GUKU","GULB","GUMA","GUNZ","TFFB","TFFA","TFFM","TFFS","TFFR","TFFC","FGAB","FGSL","FGBT","FGMY","LGAL","LGKV","LGAV","LGKC","LGAG","LGRX","LGAD","LGKA","LGKZ","LGKR","LGKF","LGPZ","LGZA","LGIO","LGTS","LGSA","LGIR","LGST","LGKP","LGKY","LGMK","LGNX","LGSO","LGSR","LGPL","LGKO","LGKS","LGKJ","LGLE","LGML","LGPA","LGRP","LGHL","LGKL","LGSP","LGSY","LGSK","LGLR","LGBL","LGIK","LGHI","LGLM","LGMT","LGSM","MGCB","MGRB","MGSJ","MGGT","MGHT","MGRD","MGPB","MGCR","MGTK","MGPP","MGQZ","MGCT","MGQC","MGPG","MGRT","PGUM","PGUA","GGOV","GGBU","SYBR","SYMR","SYMB","SYBT","SYIB","SYKM","SYPR","SYCJ","SYGO","SYKZ","SYSC","SYMK","SYKA","SYKT","SYMD","SYMM","SYOR","SYAH","SYKS","SYKR","SYLT","SYLP","SYAN","VHHH","MHLC","MHTE","MHIR","MHTJ","MHSC","MHRU","MHSR","MHLM","MHTG","MHAH","MHPC","MHPL","MHLE","MHNJ","MHRO","MHUT","MHMA","MHGS","MHGE","MHJU","MHCS","MHEA","MHYR","MHUL","LDDU","LDZA","LDPL","LDOS","LDLO","LDRI","LDSB","LDSP","LDZD","MTJE","MTCH","MTPX","MTPP","MTCA","MTJA","LHPP","LHBP","LHMC","LHDC","LHSM","WITT","WITM","WITL","WITC","WITN","WADD","WIII","WIHP","WIIG","WIPL","WIPI","WIBJ","WARW","WAMG","WAMY","WIPA","WIPH","WIPU","WIBT","WICC","WICD","WICN","WICA","WICM","WARC","WAHL","WAHP","WARQ","WARS","WAHI","WADY","WARE","WARA","WARR","WART","WIOK","WIOO","WIOP","WIOS","WAOO","WAOC","WRBK","WAON","WIOG","WAOI","WAGG","WAOS","WAOW","WALS","WALK","WALL","WRLC","WALJ","WRLA","WRLH","WALT","WALV","WRLB","WRLP","WRLF","WAGD","WITA","WALR","WIOM","WIPK","WIKD","WIDD","WION","WIDN","WIAG","WILL","WAMA","WAPH","WAPE","WAMR","WAPN","WAPT","WAEE","WAPA","WAPP","WAPK","WAPD","WAMJ","WAMK","WAPF","WAPR","WAPC","WAPG","WAPI","WAPV","WADB","WADL","WADU","WADS","WATA","WATM","WRKB","WATE","WATT","WATO","WATL","WATW","WATC","WATG","WATR","WATS","WADT","WADW","WASG","WASO","WASF","WASI","WASU","WASE","WASK","WASR","WASB","WASM","WASN","WASC","WASS","WAST","WAJA","WABB","WAJB","WAKE","WAJG","WAJJ","WAJC","WAJN","WABT","WABL","WABE","WABK","WAKM","WAKP","WABN","WAJL","WAJM","WAKD","WAKK","WABI","WABR","WAJO","WAKO","WABD","WAJE","WAJS","WABP","WAKT","WAJU","WABV","WAJR","WABG","WAVV","WASW","WAKQ","WABO","WAJI","WIBD","WIBB","WIBS","WIDS","WIPB","WAFJ","WAWT","WAWM","WAWS","WAAA","WAMW","WAFF","WAMP","WAMI","WAWB","WAWW","WAWP","WAWR","WA44","WIME","WIMN","WIMS","WIMB","WIMM","WAMM","WIMK","WAMN","WAMH","WIMP","WIPT","WIDE","WIBR","WIPV","WIPQ","WIPP","WADA","WASA","WIIJ","EINN","EIBN","EICK","EIDL","EILT","EIDW","EICM","EIMN","EIIR","EIIM","EICA","EIKY","EIKK","EIBT","EIKN","EISG","EIWF","LLBS","LLEY","LLET","LLER","LLMR","LLMZ","LLOV","LLNV","LLYT","LLKS","LLIB","LLHA","LLSD","LLBG","OJJR","VOCX","VOPB","VIBY","VOCP","VOPN","VORY","VOTP","VOBZ","VEVZ","VEPG","VEAN","VETJ","VEZO","VEDZ","VEMN","VEGT","VELR","VEKW","VEKM","VEKU","VEJT","VERU","VETZ","VEDH","VEGY","VEMZ","VEPT","VICG","VEBU","VARP","VADN","VIDP","VOGO","VAAH","VABO","VABJ","VABV","VAKS","VAKE","VAJM","VAPR","VARK","VASU","VIHR","VIGG","VIBR","VISM","VIJU","VILH","VISR","VEDB","VERC","VEJS","VOBI","VOBL","VAHB","VOML","VABM","VOMY","VOJV","VOCL","VOKN","VOCI","VOTV","VOAT","VABP","VAGN","VIGR","VAKJ","VAID","VAJB","VIST","VAAK","VABB","VAOZ","VAAU","VAJL","VAKP","VALT","VANP","VAND","VAPO","VARG","VASL","VEIM","VEBI","VELP","VEMR","VEBS","VIJR","VEJP","VERK","VOPC","VIAX","VIAR","VIBT","VIPK","VILD","VIBK","VIJP","VIJO","VIKG","VIKO","VAUD","VOCB","VOMD","VOMM","VONV","VOSM","VOTK","VOTJ","VOTR","VOHY","VOHS","VORG","VOWA","VEAT","VEKR","VIAG","VEGK","VIAL","VIKA","VILK","VEBN","VIDN","VIPT","VECC","VECO","VEBD","VEMH","VEDG","VEBG","ORAA","ORAT","ORMM","ORNI","ORER","ORSU","ORBI","ORBB","ORKK","ORBM","OIIP","OITL","OITP","SVHG","OITU","OITK","OITR","LATI","OITM","OITT","OIBB","OIBH","OITH","OIBQ","OIBJ","OIBP","OIFS","OIFE","OIFM","OISF","OISJ","OISR","OISL","OISS","OIGG","OING","OINE","OIHH","OIHS","OIBA","OIBL","OIKB","OIKQ","OIKP","OIBK","OIBV","OIBS","OICI","OIKM","OIKJ","OIKK","OIKR","OIKY","OICC","OIMT","OIMB","OIMS","OIMC","OIMM","OIMN","OIAA","OIAG","OIAW","OIAD","OIAM","OIAJ","OIAH","OISY","OICS","OICK","OIHR","OINJ","OINN","OINR","OINZ","OIIK","OIMJ","OIIS","OIZB","FMNE","FMNH","FMNA","OIZI","FMNJ","FMNN","FMNS","FMNV","OIZH","OIZC","FMND","OIIE","OIFK","OIII","OIYY","OITZ","BIBF","BIDV","BIHN","BIRK","BIAR","BIBK","BIBV","BIEG","BIFF","BIGR","BIHU","BIRL","BINF","BIOF","BIKP","BIRG","BISI","BITN","BIVO","BIBD","BIBL","BIRF","BIPA","BIKR","BIFM","BIVM","BIKF","BIGJ","BIHK","BIIS","BIRE","BITE","BIGF","BIST","LIBP","LIAP","LIBC","LICR","LICA","LIRN","LIRI","LIPE","LIPK","LIDR","LIPR","LIPA","LIPQ","LIPD","LIRF","LIMG","LIMJ","LIML","LIMC","LIPO","LIPY","LIMZ","LIMF","LIBR","LIBD","LIBF","LIBN","LIBG","LIEA","LIEE","LIED","LIER","LIEO","LIET","LICB","LICC","LICD","LICZ","LICJ","LICG","LICT","LIRJ","LIRQ","LIRS","LIQL","LIRP","LIQS","LIPB","LIRZ","LIMW","LIDB","LIPH","LIPZ","LIPT","LIPX","EGJJ","MKTP","MKKJ","MKJP","MKJS","MKBS","MKNG","OJAQ","OJAM","OJMF","OJMN","OJAI","RJGG","RJNA","RJSK","RJSR","RJSA","RJSH","RJSM","RJOM","RJNF","RJFF","RJFR","RJSF","RJOA","RJBH","RJEC","RJCH","RJCK","RJEB","RJCM","RJCB","RJEO","RJCR","RJER","RJCN","RJCW","RJBT","RJAH","RJNK","RJNW","RJSI","RJOT","RJKA","RJKI","RJFK","RJFC","RJKB","RORY","RJKN","RJFG","RJTA","RJOK","RJDA","RJFT","RJSS","RJFM","RJAF","RJFE","RJDB","RJFU","RJDU","RJDT","RJSN","RJSD","RJFO","RJOB","RORA","RODN","RORH","RORE","ROIG","ROKR","RORK","ROMD","ROMY","ROYN","ROAH","RORS","RORT","ROKJ","RJBB","RJFS","RJOW","RJOC","RJNS","RJOS","RJTH","RJTT","RJAW","RJAM","RJTQ","RJAA","RJTO","RJNO","RJOR","RJOH","RJNT","RJBD","RJSC","RJSY","RJOI","RJDC","HKJK","HKGA","HKAM","HKKG","HKKR","HKML","HKKI","HKUK","HKNY","HKLU","HKMA","HKMY","HKMB","HKMK","HKMO","HKNW","HKNK","HKKE","HKNI","HKSB","HKKL","HKHO","HKES","HKFG","HKLK","HKLO","HKLY","HKEL","HKKT","HKWJ","UAFM","UAFO","VDBG","VDKH","VDKK","VDKT","VDSV","VDMK","VDPP","VDST","VDRK","VDSR","NGUK","NGAB","NGTB","NGTR","NGTU","NGBR","NGKT","NGMA","NGMN","NGMK","NGNU","NGTO","NGON","NGTE","NGTM","NGTA","NGTS","PCIS","PLCH","FMCV","FMCH","FMCN","FMCI","TKPK","TKPN","ZKHM","ZKSD","ZKWS","ZKUJ","ZKPY","ZKSE","RKPK","RKTU","RKTI","RKTP","RKNN","RKNW","RKNY","RKJU","RKJK","RKJJ","RKJB","RKJY","RKSI","RKSO","RKSW","RKPE","RKPS","RKTH","RKTN","RKTL","RKPU","RKTY","RKPC","RKPD","OKAJ","OKBK","MWCB","MWCR","MWCL","UAAL","UAAA","UAAR","UACK","UATT","UACC","UATG","UARR","UAOL","UATE","UAII","UASB","UASP","UAAH","UAKD","UAKK","UAUR","UAUU","UAOO","UASS","UASK","UACP","UADD","VLAP","VLHS","VLKG","VLPS","VLSN","VLTK","VLLN","VLLB","VLOS","VLSV","VLSK","VLVT","VLSB","VLXK","OLBA","OLKA","TFFG","TLPC","TLPL","VCCG","VCCB","VCCS","VCCT","VCCA","VCCH","VCCJ","VCRI","VCCK","VCCW","VCBI","VCCN","VCCC","GLBU","GLTN","GLST","GLVA","GLRB","GLCP","GLMR","GLNA","GLGE","FXLR","FXPG","FXSS","FXMF","FXMM","FXSM","FXNK","FXMK","FXTK","FXLK","FXSK","FXQN","FXQG","FXLS","FXMA","FXSH","FXTA","EYVI","EYKA","EYPA","EYPP","EYSA","ELLX","EVDA","EVRA","EVLA","EVVA","HLGN","HLLQ","HLZN","HLON","HLKF","HLMB","HLNR","HLLB","HLGT","HLMS","HLTD","HLLS","HLGD","HLLM","HLLT","HLZW","HLUB","GMMD","GMMC","GMMN","GMMB","GMFK","GMAZ","GMMZ","GMFF","GMFM","GMMF","GMAT","GMMW","GMFO","GMFB","GMML","GMMA","GMMH","GMMX","GMMS","GMMY","GMME","GMAD","GMMI","GMTA","GMTT","LUBL","LUKK","LYBR","LYPG","LYTV","FMME","FMFE","FMMI","FMSU","FMMX","FMSI","FMSM","FMSG","FMSF","FMSK","FMNQ","FMNO","FMNL","FMNM","FMMO","FMNT","FMMR","FMNW","FMMG","FMNF","FMNX","FMNP","FMNG","FMMU","FMMQ","FMMS","FMMT","FMMY","FMMH","FMMZ","FMNR","FMNC","FMSY","FMSV","FMML","FMSD","FMMK","FMSJ","FMMV","FMSR","FMSL","FMSN","FMST","FMSZ","FMSB","FMSC","FMMC","FMMN","PKMA","PKWA","PKMJ","MLIP","LWOH","LWSK","GABS","GAGO","GAYE","GAKA","GAKY","GANR","GANK","GAMB","GASK","GAKO","GAGM","GATB","VYPN","VBHD","VYAN","VYPY","VYBM","VYMK","VYPT","VYLK","VYPA","VYPP","VYGG","VYKU","VYMW","VYPK","VYPU","VYHN","VYMD","VYNT","VYBG","VYCZ","VYMM","VYYE","VYSW","VYGW","VYKP","VYMN","VYTD","VYHL","VYKI","VYKL","VYMY","VYHH","VYKG","VYLS","VYMT","VYMO","VYMS","VYNS","VYTL","VYKT","VYME","VYDW","VYBP","VYYY","ZMTG","ZMUL","ZMBH","ZMBN","ZMCD","ZMMG","ZMTL","ZMAT","ZMDN","ZMUH","ZMBS","ZMKD","ZMHG","ZMMN","ZMDZ","ZMAH","ZMHU","ZMHH","ZMBR","ZMBU","ZMCK","ZMUB","ZMUG","VMMC","PGRO","PGSN","PGWT","TFFF","GQPA","GQNF","GQNE","GQPP","GQNK","GQNS","GQNJ","GQNA","GQNU","GQNO","GQNT","GQNL","GQNC","GQND","GQNI","GQPF","GQPZ","GQNH","GQNB","TRPG","LMML","FIMP","FIMR","VRMD","VRMV","VRMT","VRMF","VRMH","VRMM","VRMO","VRMK","VREI","VRMG","VRNT","FWCL","FWCD","FWKA","FWKG","FWLK","FWKI","FWCM","FWMG","FWMY","FWUU","FWDW","FWSM","MMAS","MX86","MMGR","MMLP","MMLT","MMMG","MMPL","MMSD","MMES","MMML","MMSF","MMTJ","MMCE","MMCP","MMCO","MMPQ","MMTP","MMTG","MMCS","MMCU","MMCG","MMCC","MMMV","MMPG","MMIO","MMTC","MMIA","MMZO","MMDO","MMLO","MMCY","MMAA","MMZH","MMGL","MMPR","MMJC","MMMX","MMSM","MMTO","MMLC","MMMM","MMPN","MMZM","MMCB","MMEP","MMMY","MMAN","MMBT","MMIT","MMOX","MMPS","MMSZ","MMPB","MMHC","MMQT","MMCM","MMUN","MMCZ","MMIM","MMSP","MMTN","MMCL","MMLM","MMMZ","MMCN","MMCA","MMGM","MMHO","MMNG","MMPE","MMVA","MMCV","MMMA","MMDM","MMNL","MMRX","MMTM","MMJA","MMMT","MMPA","MMVR","MMCT","MMMD","MMZC","WMKJ","WMAU","WMKA","WMKL","WMKC","WMKM","WMKD","WMAN","WMBT","WMKI","WMPA","WMBA","WMBI","WMKB","WMKP","WBKK","WBKN","WBKG","WBKT","WBKL","WBKD","WBKP","WBKR","WBKS","WBKA","WBKO","WBKH","WBKE","WBKM","WBKW","WBGZ","WBGQ","WBGC","WBGN","WBGB","WBGG","WBGP","WBGF","WBGL","WBGJ","WBGD","WBGU","WBGW","WBGK","WBGM","WBGR","WBMU","WBGI","WBGS","WBGY","WBTM","WMKK","WMSA","WMKE","WMPR","WMKN","FQIB","FQLU","FQMD","FQMP","FQPB","FQXA","FQIN","FQVL","FQCH","FQIA","FQMA","FQPO","FQAG","FQNP","FQNC","FQCB","FQLC","FQBR","FQTT","FQQL","FYAR","FYME","FYSM","FYWB","FYSS","FYAA","FYKB","FYKT","FYLZ","FYOG","FYSA","FYRU","FYWE","FYMG","FYNG","FYWH","FYOP","FYTE","FYGB","FYOS","FYOA","FYHI","FYNA","FYOO","FYMO","FYTM","FYGF","FYOW","FYLS","FYKM","FYOE","NWWC","NWWD","NWWK","NWWQ","NWWP","NWWU","NWWM","NWWE","NWWW","NWWA","NWWL","NWWR","NWWV","DRZA","DRZL","DRRM","DRRN","DRRT","DRZR","YSNF","DNAA","DNJO","DNYO","DNAI","DNMK","DNMA","DNCA","DNAS","DNSU","DNBE","DNEN","DNGO","DNIM","DNKA","DNZA","DNKN","DNIL","DNMM","DNMN","DNAK","DNIB","DNPO","DNSO","MNBZ","MNPC","MNRT","MNSI","MNWP","MNBL","MNNG","MNCI","MNMG","MNSC","MNCE","EHGG","EHLE","EHLW","EHBK","EHEH","EHGR","EHVK","EHWO","EHAM","EHKD","EHTW","EHSB","EHRD","ENGM","ENKL","ENAT","ENBS","ENBV","ENHK","ENHF","ENHV","ENKR","ENNA","ENMH","ENSS","ENVD","ENHA","ENBR","ENSO","ENAL","ENOV","ENKB","ENML","ENVA","ENAN","ENBN","ENBO","ENEV","ENLK","ENMS","ENRA","ENNK","ENRS","ENSK","ENST","ENSH","ENFG","ENRY","ENHD","ENZV","ENBL","ENFL","ENSD","ENSG","ENOL","ENNM","ENRO","ENRM","ENNO","ENSN","ENDU","ENSR","ENTC","ENCN","ENTO","VNKT","VNLT","VNBR","VNNG","VNSK","VNBL","VNJS","VNMA","VNPK","VNJP","VNRC","VNDP","VNST","VNJL","VNBJ","VNVT","VNRB","VNTR","VNBW","VNDT","VNMN","VNCG","VNTJ","VNBP","VNGK","VNMG","VNSI","VNDG","VNRP","VNRK","VNJI","VNLD","VNLK","VNPL","VNRT","VNSB","VNBT","VNBG","VNDL","VNDH","VNSR","VNTP","ANYN","NIUE","NZAA","NZAR","NZCX","NZGB","NZKE","NZRO","NZTG","NZWK","NZAS","NZCH","NZGT","NZKI","NZTU","NZUK","NZCI","NZGS","NZNR","NZWO","NZOH","NZPM","NZWU","NZWB","NZPN","NZNS","NZDA","NZKT","NZKK","NZKO","NZWR","NZLX","NZDN","NZOU","NZWF","NZQN","NZNV","NZMF","NZMC","NZRC","NZMO","NZNP","NZTK","NZMK","NZHN","NZMA","NZRA","NZTO","NZTH","NZAP","NZWT","NZMS","NZPP","NZWN","NZGM","NZHK","NZWS","OOMS","OOGB","OOBR","OOFD","OOLK","OOSH","AYNO","OOKB","OORQ","OOMA","OOSR","FZSB","MDLR","OOMX","OOSA","OOTH","MPBO","MPCH","MPDA","MPSM","MPEJ","MPJE","MPLP","MPOA","MPCE","MPHO","MPWN","MPMG","MPTO","MPVR","MPSA","SPPY","SPLN","SPHZ","SPEO","SPHY","SPQU","SPHO","SPAY","SPJR","SPJE","SPNC","SPIL","SPIM","SPGM","SPZA","SPSO","SPJN","SPJJ","SPMF","SPRU","SPHI","SPMR","SPZO","SPQT","SPDR","SPMS","SPBR","SPTU","SPSY","SPLO","SPUR","SPYL","SPJL","SPBL","SPJI","SPBB","SPJA","SPOA","SPST","SPTN","SPME","SPAR","SPCL","NTAM","NTAR","NTAV","NTAT","NTMN","NTMD","NTMU","NTMP","NTTB","NTTH","NTTP","NTAA","NTTR","NTTE","NTGA","NTHE","NTGD","NTGU","NTKF","NTGF","NTGB","NTKH","NTGJ","NTGH","NTTO","NTKA","NTGK","NTKT","NTGM","NTGV","NTGN","NTKN","NTGW","NTGP","NTGQ","NTGE","NTTG","NTKK","NTKO","NTGC","NTKM","NTGT","NTGO","NTKR","NTTX","NTUV","NTGI","NTGY","NTTM","NTTU","AYBK","AYIA","AYIQ","AYEF","AYER","AYFA","AYGF","AYHH","AYKH","AYJO","AYKQ","AYRA","AYEA","AYOP","AYLS","AYMP","AYMA","AYQQ","AYRK","AYQO","AYTY","AYTI","AYWT","AYCH","AYRI","AYGL","AYMV","AYNI","AYTK","AYSH","AYZI","AYXO","AYVO","AYUI","AYWQ","AYWK","AYAN","AYAY","AYDI","AYGA","AYOK","AYLG","AYOL","AYMW","AYNY","AYTR","AYUC","AYWO","AYWD","AYAO","AYKM","AYKK","AYQA","AYSK","AYSS","AYBA","AYWB","AYJS","AYKR","AYMD","AYNA","AYSD","AYWH","AYMO","AYYM","AYAG","AYGN","AYKA","AYMS","AYAX","AYUM","AYBC","AYBG","AYBP","AYBR","AYBU","AYNS","AYDE","AYDN","AYEN","AYFI","AYGP","AYGI","AYGG","AYHE","AYHU","AYID","AYII","AYKB","AYNB","AYOE","AYKD","AYRO","AYNM","AYYR","AYYE","AYKT","AYLB","AYNZ","AYLT","AYLN","AYLP","AYLX","AYLO","AYSX","AYMJ","AYMI","AYMC","AYMB","AYOG","AYOM","AYPD","AYSP","AYXI","AYEW","AYSW","AYQS","AYTP","AYTZ","AYTS","AYTW","AYWS","AYWC","AYWU","AYXE","AYZA","AYAF","AYBD","AYDO","AYDR","AYEO","AYEB","AYGC","AYGX","AYNJ","AYNC","AYPQ","AYPY","AYYO","AYRE","AYSF","AYSG","AYCS","AYTF","AYUE","AYBZ","AYNX","AYEE","AYKV","AYKY","AYMZ","AYSE","AYWG","AYKO","AYGR","AYTU","AYPE","AYAT","AYBF","AYEV","AYHB","AYHO","AYHF","AYOQ","AYOW","AYNN","AYLI","AYOO","AYKG","AYDL","AYKU","AYKW","AYMN","AYPO","AYMQ","AYRM","AYMR","AYBM","AYPB","AYPJ","AYVM","AYTA","AYUR","AYWF","AYIW","AYBL","AYCG","AYGJ","AYGT","AYHK","AYKC","AYLL","AYSL","AYSV","AYTG","AYVL","AYUZ","AYWJ","AYIX","AYVN","AYND","AYBO","AYCB","AYNE","AYMH","AYKJ","AYAQ","AYDK","AYPG","AYSJ","AYTV","AYYL","AYAE","AYVW","AYYK","AYAK","AYGU","AYAA","AYAM","AYAI","AYAW","AYET","AYBQ","AYBH","AYBI","AYDU","AYDB","AYEL","AYFR","AYFE","AYFU","AYGS","AYUP","AYML","AYGV","AYIO","AYTO","AYIM","AYYP","AYUY","AYLU","AYEH","AYIY","ATNR","AYOB","AYOJ","AYOF","AYOV","AYZS","AYPC","AYRG","AYSO","AYSA","AYZN","AYSU","AYTB","AYTH","AYTE","AYTN","AYQL","AYTT","AYNU","AYKI","AYXW","AYXP","AYED","RPME","RPVK","RPVE","RPLP","RPVS","RPUR","RPLB","RPUO","RPUB","RPVT","RPLH","RPUT","RPUD","RPUN","RPMH","RPVR","RPUV","RPLS","RPVM","RPMQ","RPMD","RPLI","RPSG","RPVI","RPUY","RPUS","RPMI","RPVO","RPVA","RPMC","RPMM","RPUW","RPVJ","RPLU","RPUM","RPUH","RPMY","RPMO","RPLL","RPMA","RPVB","RPVD","RPVF","RPLO","RPEN","RPVP","RPSD","RPSV","RPVV","RPLC","RPLE","RPVU","RPVC","RPMR","RPMJ","RPNS","RPMS","RPMF","RPMW","RPMU","RPMN","RPMV","RPMG","PRNO","RPMP","RPMZ","OPMF","OPRT","OPMA","OPDB","OPGD","OPJI","OPKH","OPLL","OPOR","OPPG","OPPI","OPZB","OPSB","OPSU","OPTU","OPQT","OPCL","OPGT","OPSD","OPIS","OPBN","OPCH","OPDI","OPKT","OPPC","OPPS","OPSS","OPTA","OPWN","OPBW","OPDG","OPLA","OPFA","OPMT","OPMI","OPRK","OPSR","OPST","OPTH","OPDD","OPKD","OPJA","OPKC","OPMJ","OPMP","OPSW","OPSK","OPSN","OPNH","EPWR","EPBY","EPLL","EPBP","EPLB","EPZG","EPKK","EPRA","EPWA","EPMO","EPRZ","EPGD","EPRU","EPKT","EPSY","EPPO","EPKZ","EPSC","LFVP","LFVM","TJSJ","TJPS","TJIG","LVGZ","LPBJ","LPBR","LPBG","LPCO","LPFR","LPPM","LPCS","LPPT","LPSI","LPPR","LPMA","LPPS","LPCR","LPFL","LPGR","LPHR","LPPD","LPPI","LPSJ","LPAZ","LPLA","LPCH","LPVR","LPVZ","PTRO","SGOL","SGES","SGPJ","SGME","SGFI","SGAS","SGBN","SGCO","SGEN","SGAY","SGPI","OTBD","OTHH","OTBH","FMEE","FMEP","LRAR","LRBC","LROD","LRCS","LRCL","LRCK","LRCV","LRIA","LROP","LRBM","LRTM","LRSM","LRSB","LRSV","LRTR","LRTC","LYBE","LYBT","LYNI","LYUZ","UNBG","UNBB","UHBB","UHBI","UHBW","ULAA","ULAS","ULKK","ULAL","URWA","UWUB","UWUF","UWUK","UWUU","UUOB","UUBP","UECT","UIUU","URMG","USCC","USCM","UHMA","UHMK","UHMO","UHMD","UHMP","UWKS","URML","URMS","UIBB","UIKE","UIII","UUBI","UIKK","UIKB","UIBS","UITT","URMN","UMKK","URWI","UUBC","UHPP","ULPB","UNEE","UNWW","UHNB","UHKM","UHHH","UHKK","UHNN","UHOO","UNAA","USHQ","USHH","USHI","USRK","USHK","USRN","USNN","USHN","USHS","USNR","USRR","USHU","USKK","UUYI","UUYP","UUYY","UUYH","UUYS","UUYX","UUYW","UUBA","URKA","URSS","URKG","URKK","UNKS","UODD","UNII","UOHH","UOII","UNKL","UOOO","UNIP","UOTT","USUU","UUOK","ULSS","ULLI","UUOL","UHMM","UHMW","UWKJ","UWPS","UUBB","UUEE","UUMU","UUMO","UUBW","ULMK","ULMM","ULDD","ULAM","ULDW","ULNN","UWGG","UNNT","UNOO","UWOR","UWOO","UUOR","UWPP","USPP","UHTG","UHWP","UHWW","ULOO","ULOL","URRR","URRP","URRT","URRY","UUWR","UEEA","UESG","UESO","UESS","UEMM","UEST","UEMH","UERR","UEMA","UELL","UENN","UEMO","UERO","UERP","UESK","UEBS","UENS","UERS","UEBT","UERL","UEMU","UEMT","UENI","UENW","UEEE","UEVV","UESU","UHSB","UHSM","UHSK","UHSI","UHSN","UHSH","UHSS","UHSO","UWWW","UWSB","UWSS","URMO","UUBS","URMM","URMT","USSS","UUOT","UWKD","UWKE","UWKB","UNSS","UNTT","UUBT","UUEM","USTR","USTO","UNKY","USII","UWLL","UWLW","ULWC","ULWW","URWW","ULWU","UUOO","USDB","USDP","USRO","USMU","USMM","USDA","USDD","USDS","USDU","USDK","UUDL","UUBK","UIAA","HRYU","HRYG","HRZA","HRYI","HRYR","OEBA","OERR","OERF","OETR","OESK","OEGT","OEMA","OEAO","OEYN","OEGS","OEZL","OEPS","OEDW","OERK","OESL","OEWD","OEPA","OEDR","OEDF","OEAH","OEKK","OEAB","OEBH","OEKM","OEHL","OEGN","OEJN","OETF","OENG","OESH","OEWJ","OENN","OETB","AGTI","AGGY","AGGC","AGKG","AGGJ","AGGH","AGKW","AGGI","AGNA","AGGP","AGGF","AGJO","AGGV","AGGK","AGGT","AGAR","AGAF","AGGA","AGAT","AGGQ","AGGB","AGGR","AGGU","AGGL","AGGE","AGBT","AGGS","AGEV","AGOK","AGGN","AGKU","AGGO","AGGM","AGRM","AGRC","AGBA","FSSB","FSSD","FSDR","FSSF","FSPP","FSIA","HSFA","HSDZ","HSWD","HSKG","HSGF","HSKA","HSNW","HSSK","HSFS","HSDN","HSDB","HSMN","HSSW","HSPN","HSAT","HSGG","HSNN","HSOB","HSLI","HSNH","HSGN","HSZA","HSKI","ESDF","ESSD","ESUE","ESKM","ESSK","ESNH","ESNY","ESSV","ESMT","ESND","ESNZ","ESGJ","ESSF","ESMQ","ESMO","ESSW","ESMX","ESNX","ESNG","ESNQ","ESPA","ESUP","ESKK","ESOE","ESSL","ESSP","ESTA","ESMK","ESSU","ESSA","ESOH","ESOK","ESST","ESUT","ESNL","ESNS","ESUD","ESNU","ESNV","ESNK","ESNO","ESNN","ESGG","ESGP","ESGR","ESGL","ESGT","WSAP","WSSS","WSAT","WSSL","FHAW","FHSH","ENSB","LZLU","LZSL","LZIB","LJPZ","LZKZ","LJMB","LZPW","LZTT","LJLJ","LZPP","LZZI","GFKE","GFYE","GFKB","GFBN","GFGK","GFBO","GFLL","GFHA","GOOY","GOOK","GOTK","GODK","GOSM","GOSP","GOSR","GOSS","GOTB","GOTS","GOTT","GOBD","GOGS","GOGG","HCMM","HCMA","HCMF","HCMS","HCMC","HCMG","HCMB","HCMD","HCMJ","HCMK","HCMO","HCMR","HCME","HCMU","HCMV","HCMI","HCMH","SMCO","SMBN","SMMO","SMWA","SMNI","SMJP","SMZO","SMCA","SMDA","SMTP","SMDO","SMPA","SMST","SMWS","HJJJ","HSMK","HSSM","HSWW","FPPR","FPST","MSSS","MSLP","TNCM","OSKL","OSLK","OSDZ","OSDI","OSAP","OSPR","FDMS","FDSK","MBGT","MBMC","MBNC","MBPI","MBPV","MBSY","MBSC","FTTI","FTTY","FTTS","FTTM","FTTK","FTTJ","FTTU","FTTL","FTTD","FTTP","FTTB","FTTA","FTTC","FTTN","FTTH","DXNG","DXXX","VTUO","VTCC","VTCT","VTBF","VTSE","VTUK","VTSG","VTBS","VTBD","VTCL","VTUL","VTBL","VTCH","VTBK","VTUW","VTUQ","VTPI","VTSF","VTCN","VTSC","VTSK","VTPB","VTPP","VTCP","VTSP","VTPH","VTSR","VTBU","VTUV","VTUI","VTSS","VTSH","VTPO","VTSB","VTSM","VTUJ","VTPM","VTPT","VTST","VTBO","VTUU","VTUD","VTPU","UTDD","UTDT","UTDK","UTDL","WPAT","WPEC","WPDL","WPMN","WPOC","WPDB","WPVQ","UTAK","UTAA","UTAT","UTAV","UTAM","DTTG","DTTF","DTKA","DTTJ","DTMB","DTTX","DTNH","DTTR","DTTZ","DTTA","NFTL","NFTO","NFTP","NFTE","NFTF","NFTV","LTAF","LTAG","LTCP","LTAH","LTCO","LTAP","LTAD","LTAC","LTAI","LTFG","LTBD","LTBG","LTBF","LTFD","LTCJ","LTCU","LTBE","LTBR","LTBH","LTFK","LTAY","LTCC","LTCA","LTCD","LTCE","LTBY","LTBI","LTAJ","LTCW","LTDA","LTCT","LTFC","LTBA","LTFM","LTFJ","LTCN","LTCF","LTAL","LTAU","LTBQ","LTAN","LTBZ","LTAT","LTCR","LTFE","LTBV","LTBS","LTCK","LTAZ","LTCB","LTFO","LTFH","LTCS","LTCH","LTCL","LTCM","LTCV","LTAR","LTBU","LTAW","LTCG","LTBO","LTCI","LTAS","TTPP","TTCP","NGFU","RCKU","RCPO","RCYU","RCLM","RCKH","RCBS","RCFG","RCMT","RCCM","RCQC","RCWA","RCKW","RCDC","RCMQ","RCNN","RCSS","RCGI","RCLY","RCFN","RCTP","HTAR","HTLM","HTDA","HTDO","HTGE","HTIR","HTBU","HTKA","HTKJ","HTPE","HTKI","HTLI","HTNA","HTGR","HTMU","HTMB","HTZA","HTMT","HTMI","HTMW","HTNJ","HTMA","HTSU","HTSO","HTMD","HTSY","HTSN","HTTB","HTTG","UKFK","UKFF","UKKE","UKKL","UKLN","UKDD","UKDR","UKCC","UKCK","UKCM","UKLI","UKHH","UKOH","UKLH","UKKG","UKKK","UKBB","UKCW","UKLL","UKON","UKOO","UKHP","UKLR","UKFB","UKHS","UKLT","UKWW","UKLC","UKLU","UKDB","UKDE","UKKV","HUAR","HUGU","HUJI","HUKF","HUEN","HUKS","HUMI","HUMA","HUPA","HUSO","HUTO","PWAK","KAIV","KALX","KANB","KASN","KAUO","KBFM","KBHM","KDCU","KDHN","KEDN","KEUF","KGAD","KJKA","KHAB","KHSV","KHUA","KMGM","KMOB","KMSL","KMVC","KMXF","KNBJ","KOZR","KPLR","KSEM","KTCL","KTOI","PAFM","PADK","PADQ","KPHH","PFAL","PAGN","PAWI","PAAK","PFAK","PAKH","PAKN","PAKP","PANC","PANI","PANT","PANV","PARC","PATQ","PAAT","PABE","PAGQ","PABI","PABL","PABM","PABR","PABA","PABT","PABG","PACD","PACV","PACE","PACI","PFCL","PACX","PACK","PACY","PACZ","PADL","PADE","PADU","PAEG","PAED","PAEE","PAII","PAEH","PAEI","PFEL","PAEL","PAEM","PAEN","PANN","PAFA","PAFB","PANR","PAFR","PAFW","PFYU","PAGA","PAGM","PAGB","PAGK","PAGL","PAGZ","PAGS","PAHC","PAOH","PAHN","PAHO","PAHP","PAHL","PAHU","PAHY","PAIK","PAIG","PAKO","PAIL","PACR","PAJN","PAFE","PAKV","PAKD","PAKF","PAJZ","PAKK","PADY","PALG","PALB","PAKW","PAMB","PANW","PFKO","PAPC","PAKI","PAPE","PASM","PAKT","PFKT","PFKA","PAVC","PAVL","PAGG","PAQH","PFKW","PAKY","PFKU","PAKL","PAMH","PALN","PALU","PAMC","PAIN","PAMD","PADM","PAML","PAMO","PAMR","PAMM","PABK","PAMX","PAMY","PFCB","PAFS","PAOU","PAGT","PANO","PAQT","PANU","PAOB","PAOM","PAOO","KORI","PAOR","PFNO","PAOT","PAAQ","PAOC","PAPO","PAPN","PPIZ","PAPK","PAAL","PAPR","PAPG","PALJ","PAAP","PAPH","PAPM","PARY","PADG","PARS","PASC","PACM","PASD","PAGY","PAGH","PASH","PAHX","PASI","PFSH","PASW","PASL","PAMK","PASP","PASN","PASO","PAPB","PASA","PASV","PAWD","PASX","PASY","PATA","PATK","PFTO","PATE","PATL","PATC","PATG","PAST","PAUM","PAUN","PAIM","PAKU","PAVA","PAVD","PAVE","PAIW","PAWB","PALR","PASK","PAWM","PANA","PAUO","PAWG","PACS","PFWS","PAWN","PAWS","PAEW","PAYA","KAVQ","KIWA","KBXK","KCFT","KCGZ","KDGL","KDMA","KDUG","KDVT","KFHU","KFLG","KGCN","KGYR","KHII","KIFP","KIGM","KINW","KLGF","KLUF","KFFZ","KMZJ","KOLS","KPGA","KPHX","KPAN","KPRC","KSAD","KSDL","KSEZ","KSJN","KSOW","KTUS","KTYL","KNYL","KAGO","KARG","KAWM","KBVX","KBYH","KCDH","KCVK","KCRT","KELD","KFCY","KFLP","KFSM","KFYV","KHEE","KHKA","KHOT","KHRO","KJBR","KLIT","KLRF","KMPJ","KMXA","KPBF","KPGR","KROG","KSGT","KSLG","KASG","KSRC","KTXK","KBPK","KXNA","KACV","KAHC","KAPC","KAPV","KAUN","KAVX","KBAB","KBFL","KBIH","KBLH","KBLU","KBNG","KBUR","KBWC","KBYS","KCCB","KCCR","KCEC","KCIC","KCRQ","KCLR","KCNO","KCPM","KCRO","KCXL","KDAG","KEDW","KEED","KEKA","KEMT","KFAT","KFCH","KFUL","KHAF","KHHR","KCVH","KHMT","KHWD","KIPL","KIYK","KKIC","KLAX","KLGB","KLPC","KLSN","KLVK","KMAE","KMCC","KMCE","KMER","KMHR","KMHV","KMIT","KMMH","KMOD","KMRY","KMYF","KMYV","KNJK","KNKX","KNLC","KDVO","KNRC","KNRS","KNTD","KNUQ","KNZY","KOAK","KOAR","KOKB","KONT","KOVE","KOXR","KPAO","KPMD","KPOC","KPRB","KPSP","KPTV","KPVF","KRAL","KRBL","KRDD","KRHV","KRIR","KRIV","KMPI","KSAC","KSAN","KSAS","KSBA","KSBD","KSBP","KSCK","KSDM","KSEE","KSFO","KSIY","KSJC","KSMF","KSMO","KSMX","KSNA","KSNS","KSPA","KIZA","KSQL","KSTS","KSMS","KSUU","KSVE","KSZN","KSZP","KTRK","KTLR","KTNP","KTOA","KTRM","KTSP","KTVL","KUDD","KUKI","KVBG","KVCV","KVIS","KVNY","KWHP","KWJF","KWLW","KWVI","KAFF","KAKO","KALS","KAPA","KASE","KBKF","KBJC","KCEZ","KCAG","KCOS","KDEN","KDRO","KEGE","KFCS","KFNL","KGJT","KGUC","KGWS","KGXY","KHDN","KLAA","KLIC","KLXV","KMTJ","KPSO","KPUB","KRIL","KSBS","KANK","KSTK","KTAD","KTEX","KBDU","KBDL","KBDR","KDXR","KGON","KHFD","KHVN","KOXC","KDOV","KGED","KILG","KAAF","KAPF","KAVO","KBCT","KBOW","KCDK","KCEW","KCLW","KCOF","KCOI","KCRG","KCTY","KDAB","KDTS","KECP","KEGI","KEYW","KFLL","KFMY","KFPR","KFXE","KGIF","KGNV","KHST","KHWO","KIMM","KISM","KJAX","KLAL","KLCQ","KLEE","KLNA","KMCF","KMCO","KMIA","KMLB","KMKY","KMTH","KNEN","KNIP","KNPA","KNQX","KNRB","KNSE","KNUN","KOBE","KOCF","KOPF","KORL","KPAM","KPBI","KPGD","KPHK","KPIE","KPNS","KPMP","KRSW","KSEF","KSFB","KSPG","KSRQ","KSUA","KTIX","KTLH","KTMB","KTNT","KTPA","KTPF","KSGJ","KVNC","KVPS","KVQQ","KVRB","KZPH","KABY","KAGS","KAHN","KATL","KAYS","KBGE","KBQK","KCSG","KDBN","KDNL","KDNN","KFTY","KGVL","KLGC","KLHW","KLSF","KLZU","KMAC","KMCN","KMGE","KMGR","KMLJ","KMQW","KMUL","KPDK","KPIM","KRMG","KSAV","KSSI","KSVN","KSYV","KTBR","KTMA","KTOC","KTVI","KVAD","KVDI","KVLD","KWDR","KWRB","PHBK","PHSF","NSFQ","PHDH","PHHI","PHNL","PHHN","PHTO","PHJH","PHJR","PHKO","PHLI","PHNY","PHLU","PMDY","PHMK","PHMU","PHNG","PHOG","PHPA","PHUP","KBOI","KBYI","KLLJ","KCOE","KGNG","KIDA","KGIC","KLWS","KMLD","KMUO","KMYL","KPIH","KRXE","KSMN","KSUN","KTWF","KALN","KARR","KBLV","KBMI","KCIR","KCMI","KCPS","KDEC","KDNV","KDPA","KDVN","KENL","KEOK","KFEP","KGBG","KGRE","KHSB","KIJX","KIKK","KJOT","KLOT","KLWV","KMDH","KMDW","KMLI","KMQB","KMTO","KMVN","KMWA","KOLY","KORD","KPIA","KRFD","KSAR","KSLO","KSPI","KSQI","KUGN","KUIN","KVLA","KVYS","KAID","KANQ","KBFR","KBMG","KCEV","KBAK","KEKM","KEVV","KFRH","KFWA","VOGB","KGFD","KGSH","KGUS","KHLB","KHNB","KIND","KLAF","KPPO","KIMS","KMGC","KMIE","KMZZ","KOKK","KRCR","KRID","KRZL","KSBN","KSER","KSIV","KSMD","KVPZ","KAIO","KALO","KAMW","KAXA","KBNW","KBRL","KCBF","KCCY","KCID","KCIN","KCSQ","KCWI","KDBQ","KDEH","KDNS","KDSM","KEBS","KEFW","KEST","KFFL","KFSW","KFOD","KFXY","KHPT","KICL","KIDG","KIFA","KIOW","KLRJ","KMCW","KMIW","KMPZ","KMUT","KMXO","KOMA","KOOA","KOTM","KPOH","KPRO","KSLB","KSPW","KSUX","KTNU","KANY","KBEC","KCBK","KCEA","KCFV","KCNK","KCNU","KDDC","KEQA","KEMP","KEWK","KFLV","KFOE","KFRI","KFSK","KGBD","KGCK","KGLD","KHLC","KHUT","KHYS","KIAB","KICT","KIDP","KIXD","KLBL","KLWC","KLYO","KMHK","KMPR","KOJC","KPPF","KPTS","KPTT","KRSL","KSLN","KTOP","KWLD","KBRY","KBWG","KCEY","KCVG","KEKX","KFFT","KFTK","KGLW","KHOP","KLEX","KLOU","KLOZ","KOWB","KPAH","KPBX","KSDF","KSME","KAEX","KARA","KBAD","KBTR","KBXA","KCWF","KDRI","KDTN","KESF","KHUM","KLCH","KLFT","KMLU","KMSY","KNBG","KNEW","KOPL","KPOE","KPTN","KRSN","KSHV","KAUG","KBGR","KBHB","KCAR","KIZG","KHUL","KIWI","KLEW","KMLT","KBXM","KOLD","KOWK","KPNN","KPQI","KPWM","KRKD","KSFM","KFVE","KWVL","KADW","KANP","KAPG","KBWI","KCBE","KCGE","KCGS","KESN","KFDK","KFME","KGAI","KHGR","KMTN","KNHK","KOXB","KSBY","KACK","TJAB","KBAF","KBED","KBOS","TJBQ","KBVY","TJCP","KEWB","TJFA","KFMH","KGBR","KGDM","KHYA","KLWM","TJMZ","KMVY","TJRV","KORH","KOWD","KPSF","KPVC","KPYM","TJVQ","KACB","KADG","KAMN","KAPN","KARB","KAZO","KBEH","KBTL","KCAD","KCIU","KCMX","KDRM","KDTW","KESC","KFNT","KGDW","KGLR","KGRR","KHAI","KHLM","KHTL","KIMT","KIRS","KISQ","KIWD","KJXN","KLAN","KLDM","KMBL","KMBS","KMCD","KMKG","KMNM","KMOP","KSAW","KMTC","KOSC","KPHN","KPLN","KPTK","KRCT","KTVC","KCFS","KRQB","KAEL","KAUM","KAXN","KBBB","KBDE","KBJI","KBRD","KCKN","KDLH","KDTL","KEVM","KFBL","KFCM","KFFM","KFRM","KGPZ","KCKC","KHIB","KBDH","KINL","KELO","KMIC","KMJQ","KMKT","KMML","KMOX","KMSP","KMVE","KMWM","KDVP","KONA","KOTG","KOWA","KPKD","KROX","KRRT","KRST","KRWF","KSTC","KSTP","KSYN","KTVF","KULM","KBIX","KCBM","KCKM","KCRX","KMBO","KGLH","KGPT","KGTR","KGWO","KHBG","KHEZ","KHKS","KJAN","KLMS","KLUL","KMCB","KMEI","KMMS","KOLV","KOSX","KPQL","KPIB","KTUP","KUBS","KUOX","KUTA","KVKS","KAIZ","KBBG","KBUM","KCGI","KCOU","KDMO","KEOS","KFAM","KIRK","KJEF","KJLN","PFKK","KTKX","KMAW","KMBY","KMCI","KMHL","KMKC","KNVD","KPLK","KPOF","KSGF","KSIK","KSTJ","KSTL","KSUS","KSZL","KTBN","KTRX","KVIH","KBIL","KBTM","KBZN","KCTB","KDLN","KGPI","KGDV","KGGW","KGTF","KHLN","KHVR","KJDN","KLVM","KLWT","KMLS","KMSO","KOLF","KPWD","KRPX","KSBX","KSDY","KTHM","KWYS","KAIA","KANW","KBBW","KBFF","KBIE","KBUB","KCDR","KEAR","KFBY","KFET","KGRI","KGRN","KHDE","KHSI","KIML","KLBF","KLNK","KLXN","KMCK","KMHN","KMLE","KOFF","KOFK","KOGA","KOKS","KOLU","KONL","KSCB","KSNY","KVTN","KBAM","KBTY","KCXP","KDRA","KEKO","KELY","KFLX","KGAB","KHND","KHTH","KINS","KLAS","KLOL","KLSV","KLWL","KMEV","KNFL","KRNO","KTPH","KUCC","KVGT","KWMC","KTNX","KAFN","KASH","KBML","KCNH","KCON","KEEN","KERR","KHIE","KLCI","KLEB","KMHT","KPSM","KACY","KBLM","KCDW","KEWR","KLDJ","KVAY","KMIV","KMJX","KMMU","KNEL","KTEB","KTTN","KWRI","KWWD","KABQ","KALM","KATS","KAXX","KCAO","KCNM","KCVN","KCVS","KDMN","KFMN","KFSU","KGNT","KGUP","KHMN","KHOB","KLAM","KLRU","KLSB","KLVS","KONM","KROW","KRTN","KSRR","KSAF","KSVC","KTCC","KTCS","KSKX","KWSD","KALB","KART","KBGM","KBUF","KDKK","KDSV","KELM","KELZ","KFOK","KFRG","KGFL","KHPN","KHTO","KIAG","KISP","KITH","KJFK","KJHW","KLGA","KLKP","KMGJ","KMSS","KMSV","KMTP","KOGS","KOIC","KOLE","KPBG","KPOU","KRME","KROC","KSCH","KSLK","KSWF","KSYR","KHWV","KAVL","KCLT","KCTZ","KECG","KEDE","KEWN","KFAY","KFBG","KFFA","KGSB","KGSO","KHFF","KHKY","KHSE","KUKF","KILM","KINT","KISO","KLBT","KLHZ","KMQI","KMRN","KMEB","KOAJ","KOCW","KPGV","KPOB","KRDU","KRWI","KRZZ","KSOP","KRUQ","KSVH","KJQF","KASY","KBIS","KBPP","KDIK","KDVL","KFAR","KGFK","KISN","KJMS","KMIB","KMOT","KPMB","KRDR","KBWP","KXWA","KAKR","KAOH","KUNI","KAXV","KBJJ","KBKL","KCAK","KCGF","KCLE","KCMH","KDAY","KDFI","KFDY","KFFO","KGQQ","KHAO","KHTW","KILN","KHZY","KLCK","KLNN","KLUK","KMFD","KMGY","KMNN","KMWO","KOSU","KOXD","KPHD","KPMH","KSGH","KSKY","KTDZ","KTOL","KYNG","KZZV","KADM","KADH","KAXS","KBVO","KBKN","KCHK","KCKA","KCLK","KCSM","KCUH","KDUA","KDUC","KELK","KEND","KFDR","KFSI","KGAG","KGOK","KGUY","KHBR","KHHW","KLAW","KLTS","KMIO","KMKO","KMLC","KOKC","KOKM","KOUN","KPNC","KPWA","KRKR","KRVS","KSNL","KSUD","KSWO","KTIK","KTUL","KWDG","KWWR","KAST","KBKE","KBNO","KBOK","KCVO","KCZK","KDLS","KEUG","KHRI","KHIO","KGCD","KLGD","KLKV","KLMT","KMFR","KONO","KONP","KOTH","KTMK","KPDT","KPDX","KPFC","KRBG","KRDM","KREO","KSLE","KTTD","KABE","KAGC","KAOO","KAVP","KLOM","KBFD","KBVI","KBTP","KMQS","KDUJ","KDYL","KERI","KFKL","KCXY","KHZL","KIDI","KIPT","KJST","KLBE","KLHV","KLNS","KMDT","KGKJ","KMPO","KMUI","KPHL","KPIT","KPNE","KPSB","KPTW","KRDG","KRVL","KUNV","KSEG","KOYM","KTHV","KUKT","KWAY","KWBW","KAFJ","KBID","KOQU","KUUU","KPVD","KSFZ","KWST","KAIK","KAND","KARW","KBNL","KBBP","KCAE","KCDN","KCEU","KCHS","KCRE","KCUB","KDLC","KFLO","KGYH","KGGE","KGMU","KGRD","KGSP","KCQW","KCQX","KHXD","KHVS","KMMT","KMYR","KOGB","KRBW","KUZA","KSSC","KABR","KATY","KBKX","KFSD","KHON","KLEM","KLQK","KMBG","KMHE","KPHP","KPIR","KRAP","KRCA","KSPF","KBTN","KMDS","KIEN","KYKN","KAPT","KBNA","KCHA","KCKV","KCSV","KFYM","KGCY","KGHM","KGKT","KMEM","KMKL","KMMI","KMOR","KMQY","KMRC","KNQA","KPHT","KRKW","KRNC","KSYI","KTHA","KTRI","KTYS","KUCY","KUOS","KABI","KACT","KADS","KAFW","KALI","KAMA","KASL","KAUS","KBYY","KBBD","KBGD","KBIF","KBKD","KBMT","KBPT","KBRO","KBWD","KCDS","KCFD","KCLL","KCNW","KCOM","KCOT","KCRP","KCRS","KCXO","KCZT","KDAL","KDFW","KDHT","KDLF","KDRT","KDWH","KDYS","KEFD","KELA","KELP","KERV","KETN","KFST","KFTW","KNFW","KGGG","KGLE","KGLS","KGRK","KGVT","KBPG","KHLR","KHOU","KHPY","KHRL","KUTS","KIAH","KILE","KINK","KIWS","KJAS","KJCT","KJSO","KCWC","KLBB","KLFK","KLBX","KLRD","KMAF","KMDD","KMFE","KOSA","KMRF","KMWL","KNGP","KNGW","KNQI","KOCH","KONY","KOZA","KPEQ","KGYI","KPPA","KPRX","KPSN","KPSX","KPVW","KRBD","KRCK","KRFG","KRKP","KRND","KSAT","KSEP","KSGR","KSJT","KSKF","KSLR","KSNK","KSPS","KSSF","KSWW","KTDW","KTPL","KTRL","KTYR","KUVA","KVCT","KVHN","KWEA","KARM","KBCE","KBDG","KBMC","KBTF","KCDC","KCNY","KDPG","KDTA","KENV","KFOM","KHIF","KHVE","KKNB","KLGU","KMLF","KOGD","KPUC","KPVU","KRIF","KSGU","KSLC","KVEL","KBTV","KEFK","KCDA","KMPV","KMVL","KRUT","KVSF","KAPH","KBCB","KBKT","KCHO","KDAA","KDAN","KDCA","KNDY","KFAF","KFKN","KFRR","KGVE","KHSP","KIAD","KLFI","KLNP","KLKU","KLVL","KLYH","KMFV","KHEF","KNGU","KNTU","KNYG","KORF","KPHF","KPSK","KPTB","KRIC","KROA","KSHD","KVJI","KWAL","KOKV","KALW","KBFI","KBLI","KCLM","KCLS","KEAT","KELN","KEPH","KORS","KESW","KFHR","KGEG","KGRF","KHQM","KKLS","KBVS","KMWH","KNUW","KOKH","KOLM","KOMK","KPAE","KPSC","KPUW","KPWT","KRLD","KRNT","KSEA","KSFF","KSHN","KSKA","KTCM","KTDO","KTIW","KUIL","KYKM","KBKW","KBLF","KCKB","KCRW","KEKN","KHLG","KHTS","KLWB","KMGW","KMRB","KPKB","KAHH","KARV","KASX","KATW","KAUW","KCLI","KCMY","KCWA","KEAU","KEGV","KENW","KETB","KFLD","KGRB","KGTG","KHYR","KISW","KJVL","KLNR","KLSE","KMDZ","KMFI","KMKE","KMSN","KMTW","KMWC","KOEO","KOSH","KPDC","KPKF","KRAC","KRHI","KRPD","KRNH","KRRL","KSBM","KSTE","KSUE","KSUW","KUES","KUNU","KVOK","KAFO","KBPI","KBYG","KCOD","KCPR","KCYS","KDGW","KEAN","KECS","KEMM","KEVW","KFBR","KGCC","KGEY","KJAC","KLAR","KLND","KLSK","KPOY","KPNA","KRIW","KRKS","KRWL","KSAA","KSHR","KTHP","KTOR","KWRL","SUAG","SUBU","SUMO","SUCA","SUDU","SULS","SUMU","SUPU","SURV","SUVO","SUSO","SUTB","SUTR","UTTT","UTKA","UTSN","UTSB","UTKF","UTFN","UTSA","UTSK","UTNN","UTSS","UTST","UTNU","TVSB","TVSC","TVSM","TVSU","TVSA","SVPA","SVAN","SVBC","SVST","SVEZ","SVGD","SVPT","SVSR","SVBI","SVSB","SVCN","SVCB","SVCD","SVED","SVIC","SVIE","SVKA","SVKM","SVPR","SVSE","SVTM","SVUM","SVBS","SVPC","SVVA","SVPE","SVTC","SVCR","SVJC","SVCL","SVVP","SVBM","SVCO","SVMD","SVVG","SVRS","SVMT","SVMG","SVAC","SVGU","SVCU","SVCP","SVGI","SVLF","SVPM","SVSO","SVSA","SVVL","SVMI","SVSP","SVON","SVCG","SVMC","SVSZ","TUPJ","TUPA","TUPW","TIST","TISX","VVCS","VVVT","VVPC","VVCM","VVCT","VVDN","VVBM","VVDB","VVPK","VVNB","VVCI","VVTS","VVCR","VVNT","VVPQ","VVRG","VVDL","VVVH","VVPR","VVTH","VVDH","VVCA","VVVD","VVNS","VVTX","VVPB","NVSF","NVSL","NVSP","NVSI","NVSX","NVSU","NVSO","NVSG","NVSN","NVSR","NVSH","NVSW","NVSZ","NVSS","NVSE","NVSM","NVST","NVVQ","NVVV","NVSV","NVVA","NVVB","NVVD","NVVF","NVVI","NVVW","NVSA","NVSC","NVSD","NVSQ","NLWF","NLWW","NSMA","NSAU","NSFA","NSFI","OYMS","ODAL","OYAA","OYBI","OYHD","OYKM","OYGD","OYQN","OYSY","OYRN","OYSQ","ODAS","OYMB","OYSH","OYSN","OYAT","OYBN","OYTZ","FMCZ","FAPA","FABE","FACD","FAEL","FAPJ","FAMW","FAPE","FAUT","FAQT","FABL","FAFB","FAHR","FATN","FAWM","FAGC","FALA","FAOR","FAWB","FAGM","FAWK","FADK","FALE","FAEM","FAHL","FALY","FAMG","FAMU","FANC","FAPM","FADQ","FARB","FAUL","FAVG","FAVY","FAAL","FAER","FAGI","FAHS","FALO","FALD","FATZ","FAMS","FAPH","FAPP","FATH","FAUS","FAMD","FAHW","FAKP","FAMN","FAKN","FANG","FANS","FASZ","FASC","FAKD","FAMM","FAPN","FAPS","FARI","FAVB","FAAG","FAAB","FAKM","FAKZ","FAKU","FALC","FAPK","FASB","FASS","FAUP","FACT","FAGG","FAMO","FAOH","FAOB","FAPG","FARS","FALW","FAVR","FLSO","FLND","FLCP","FLMF","FLMA","FLLS","FLZB","FLSW","FLKS","FLBA","FLKY","FLLI","FLNA","FLKL","FLKO","FLLK","FLMG","FLSS","FLSN","FVBU","FVHA","FVCH","FVMU","FVKB","FVCZ","FVMH","FVMV","FVWN","FVFA","FVWT","FVTL"] } \ No newline at end of file diff --git a/functions.js b/functions.js index 90cbc4e..9c23508 100644 --- a/functions.js +++ b/functions.js @@ -396,7 +396,7 @@ const functions = { clouds.push(`${cloudLayer.cover} @ ${cloudLayer.base}`); }); const embed = new Discord.MessageEmbed() - .setAuthor({ name: `${metarData.icaoId} METAR`, iconURL: "https://aviationweather.gov/img/icons/awc-logo-180.png"}) + .setAuthor({ name: `${metarData.name} [${metarData.icaoId}] METAR`, iconURL: "https://aviationweather.gov/img/icons/awc-logo-180.png"}) .setDescription(metarData.rawOb) .setFooter({ text: "METAR by AviationWeather.gov" }) .addFields( From 5a9b91ade155c9a3f73d8c18bf1b0fe8d1c99885 Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Fri, 21 Jun 2024 19:19:37 -0400 Subject: [PATCH 41/79] Fix cloud layer CLR --- functions.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/functions.js b/functions.js index 9c23508..95ed41d 100644 --- a/functions.js +++ b/functions.js @@ -393,7 +393,11 @@ const functions = { const interAltim = Math.round((metarData.altim * 0.2952998057228486) * 10) const altim = interAltim / 100; metarData.clouds.forEach(cloudLayer => { - clouds.push(`${cloudLayer.cover} @ ${cloudLayer.base}`); + if (cloudLayer.base !== null) { + clouds.push(`${cloudLayer.cover} @ ${cloudLayer.base}`); + } else { + clouds.push(`${cloudLayer.cover}`); + } }); const embed = new Discord.MessageEmbed() .setAuthor({ name: `${metarData.name} [${metarData.icaoId}] METAR`, iconURL: "https://aviationweather.gov/img/icons/awc-logo-180.png"}) From 66dbdceb2a2a5425c67e0d887b1337f04b883c34 Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Fri, 21 Jun 2024 20:19:05 -0400 Subject: [PATCH 42/79] Minor tweaks --- functions.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/functions.js b/functions.js index 95ed41d..a4e673f 100644 --- a/functions.js +++ b/functions.js @@ -394,19 +394,20 @@ const functions = { const altim = interAltim / 100; metarData.clouds.forEach(cloudLayer => { if (cloudLayer.base !== null) { - clouds.push(`${cloudLayer.cover} @ ${cloudLayer.base}`); + clouds.push(`${cloudLayer.cover} @ ${cloudLayer.base}'`); } else { clouds.push(`${cloudLayer.cover}`); } }); const embed = new Discord.MessageEmbed() .setAuthor({ name: `${metarData.name} [${metarData.icaoId}] METAR`, iconURL: "https://aviationweather.gov/img/icons/awc-logo-180.png"}) - .setDescription(metarData.rawOb) - .setFooter({ text: "METAR by AviationWeather.gov" }) + .setImage("https://media.discordapp.net/stickers/1175134632845516821.webp") + .setDescription(`**Not for real world use!**\n\n${metarData.rawOb}`) + .setFooter({ text: "METAR by AviationWeather.gov for CumbHub LLC" }) .addFields( { name: 'Observation Time', value: `${metarData.reportTime}Z` }, { name: 'Temperature', value: `${metarData.temp}ºC/${metarData.dewp}ºC`}, - { name: 'Winds', value: `${metarData.wdir}@${metarData.wspd}${wgst} kts`}, + { name: 'Winds', value: `${metarData.wdir}º@${metarData.wspd}${wgst} kts`}, { name: 'Visibility', value: `${metarData.visib} SM` }, { name: 'Clouds', value: clouds.join('\n') }, { name: 'Altimeter', value: `${altim} inHg` } From 6700e36907941d418b40e87311830ab38a91cafc Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Fri, 21 Jun 2024 20:20:07 -0400 Subject: [PATCH 43/79] Make update script --- update.sh | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 update.sh diff --git a/update.sh b/update.sh new file mode 100644 index 0000000..6380ff3 --- /dev/null +++ b/update.sh @@ -0,0 +1,4 @@ +#!/bin/bash +git pull +docker build . -t v0idf1sh/nodbot +docker push v0idf1sh/nodbot \ No newline at end of file From 444bad79358c96f207c62d3b064384482cce5120 Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Sat, 22 Jun 2024 09:17:24 -0400 Subject: [PATCH 44/79] Add D-ATIS from clowd.io --- config.json | 3 +- dot-commands/datis.js | 24 ++++++++++++ functions.js | 87 ++++++++++++++++++++++++++++++++++++++----- main.js | 2 +- 4 files changed, 104 insertions(+), 12 deletions(-) create mode 100644 dot-commands/datis.js diff --git a/config.json b/config.json index 9c78d99..488a934 100644 --- a/config.json +++ b/config.json @@ -2,5 +2,6 @@ "guildId": "868542949737246730", "validCommands": [], "roaches": [], - "icaoIds": ["OMAL","OMAA","OMAD","OMAM","OMBY","OMDL","OMFJ","OMSJ","OMDW","OMDB","OMDM","OMRK","OADZ","OAFZ","OARZ","OAHN","OASN","OAQN","OAMS","OABN","OAFR","OAMN","OAGN","OADS","OACC","OABT","OADY","OAZI","OAHR","OASD","OAZJ","OAGZ","OAKB","OAKN","OATN","OARG","OAKS","OASL","OAUZ","OASH","OAJL","OASA","OAOG","OAIX","OATQ","TAPH","TAPA","TQPF","UDYZ","UDSG","FNAM","FNBG","FNCT","FNLB","FNKU","FNCA","FNGI","FNXA","FNHU","FNUB","FNCV","FNME","FNWK","FNSU","FNPA","FNLU","FNCF","FNDU","FNLK","FNLZ","FNZG","FNCH","FNSA","FNCP","FNMA","FNCZ","FNUE","FNUA","FNMO","FNNG","FNUG","FNZE","FNBC","FNSO","SCRM","SABE","SAZB","SAZC","SADP","SAEZ","SAAJ","SADL","SAZM","SAZO","SAZF","SAZH","SAZP","SAZL","SAZT","SAZV","SANC","SARS","SARE","SAVR","SAVC","SAVD","SAVE","SAWS","SAVM","SAVY","SAVT","SAWM","SACO","SACC","SAOC","SAOD","SARL","SARC","SARM","SATM","SATG","SATU","SAAC","SAAG","SAAP","SATC","SARF","SATK","SASJ","SAZG","SAZR","SANL","SAMR","SAMM","SAME","SATD","SARI","SARP","SAHZ","SAZY","SAZW","SAHC","SAZN","SAHS","SAZS","SAVB","SAHR","SAVJ","SAVQ","SAVN","SAVS","SAVV","SASO","SASA","SAST","SANU","SAOU","SAOS","SAOR","SAWA","SAWR","SAVH","SAWP","SAWD","SAWG","SAWT","SAWU","SAWJ","SANW","SAFS","SAFR","SATR","SAAR","SAAV","SANR","SANE","SAWE","SAWH","SANT","NSAS","NSTU","LOWK","LOWW","LOWL","LOWS","LOWG","LOWI","LOIH","YSCB","YMAY","YARM","YLMQ","YBHI","YBTH","YBNA","YBKE","YBRW","YSBK","YBRN","YCBA","YCDO","YSCN","YCNK","YCFS","YCAH","YCTM","YCNM","YCBB","YCBR","YCAS","YCUA","YCWR","YCOR","YSDU","YMDG","YDLQ","YEVD","YFIL","YFST","YFBS","YGTH","YGFN","YGLI","YSMB","YGDH","YGLB","YHAY","YIVL","YKMP","YLHI","YLRD","YLIS","YMER","YMOR","YMND","YMRY","YNBR","YNHS","YYNG","YSNW","YNAR","YSCO","YWLM","YNYN","YORG","YCOM","YPKS","YPMQ","YSGT","YSSY","YTOC","YTEM","YSTW","YTRE","YTMU","YTIB","YQDI","YWWA","YSWG","YWLG","YWCA","YWCH","YWOL","YWWL","YSRI","YBAS","YAUV","YALX","YAYE","YBRL","YBTI","YCOO","YCFD","YCKI","YDVR","YDLV","YPDN","YELD","YFNE","YGBI","YPGV","YGPT","YGTE","YTGT","YHMB","YHOO","YHBY","YHBR","YINW","YJAB","YKCA","YKCS","YKKG","YPTN","YLEV","YLKN","YMHU","YMCR","YMGB","YMVG","YMGD","YMDS","YMQA","YMNS","YMSF","YMUP","YNUM","YKPT","YRNG","YRKD","YRRB","YNGU","YSMP","YSNB","YTBR","YTNK","YTMY","YVRD","YWAV","YWOR","YWTL","YYND","YARY","YABI","YAPH","YNPE","YAGD","YAUR","YAMC","YAYR","YLLE","YBAR","YBUD","YBAU","YBIE","YBAW","YBCK","YBLL","YBTR","YBPI","YBBN","YBOU","YBEO","YBKT","YBDV","YCCA","YCRY","YCMU","YCMW","YCMT","YCCT","YCCY","YBCS","YBCV","YCKN","YCDR","YCOE","YCHT","YUNY","YDAY","YDLT","YDRH","YDKI","YDMG","YDBR","YDOR","YDBI","YDRI","YDPD","YDIX","YDYS","YPMP","YEML","YESE","YGAY","YGAM","YGDS","YBOI","YGKL","YGLE","YGLO","YGLA","YGDI","YGON","YGTN","YGNV","YGYM","YHTL","YHUG","YHID","YHHY","YHDY","YBHM","YHBA","YIFY","YIFL","YIGM","YIKM","YINJ","YLHR","YBMA","YISF","YJLC","YJDA","YCSV","YKRY","YKLB","YKML","YKLA","YKPR","YKMB","YSPV","YKUB","YKOW","YLIN","YLFD","YLND","YCGO","YLOR","YLRE","YLHS","YLOV","YLRS","YLRA","YLAH","YLZI","YMYB","YBSU","YMOT","YBMK","YMEU","YMMU","YMTO","YMRB","YMBA","YMIT","YMGV","YMIR","YMWX","YMAE","YDNI","YNAP","YNSH","YNTN","YORC","YYKI","YBOK","YMTI","YMNK","YBCG","YMOO","YOEN","YOSB","YMNY","YTMO","YPAM","YBPN","YRMD","YROM","YROB","YBRK","YRSB","YRTP","YSII","YSPK","YSGE","YSPT","YSPE","YSTI","YSMR","YWBS","YTGA","YTDR","YTNG","YTEE","YBTL","YTWB","YTHY","YMAA","YUDA","YQLP","YMTB","YVRS","YWCK","YWND","YBWP","YWTN","YMLS","YWDH","YWDL","YWMP","YSHR","YBWW","YYMI","YTGM","YTAM","YTAA","YBWN","YSGW","YPAD","YAMK","YAMT","YCWL","YCDU","YCBP","YCEE","YCWI","YDLK","YERN","YEDA","YMGN","YHAW","YIDK","YINN","YKBY","YKSC","YYTA","YBLC","YLEC","YLOK","YMTG","YMPA","YMCT","YMUG","YOOM","YALA","YMUK","YMWT","YNRC","YNUB","YOOD","YCOD","YOLD","YYOR","YPDI","YPSH","YPLC","YPIR","YPAG","YPMH","YREN","YMRE","YMYT","YPWR","YWUD","YWHA","YMIN","YWYY","YDPO","YFLI","YGTO","YMHB","YSTH","YKII","YMLT","YSMI","YSRN","YQNS","YARA","YMAV","YBLA","YBNS","YBDG","YCRG","YECH","YGLG","YHML","YHSM","YHPN","YKER","YPOK","YMMB","YMEN","YMML","YHOT","YMIA","YOUY","YPOD","YROI","YORB","YSHT","YSWL","YSWH","YWSL","YLTV","YWGT","YWKB","YWBL","YOLA","YMCO","YABA","YBDF","YBRM","YBLN","YBGO","YBUN","YBYS","YBWX","YBEB","YBRY","YCAG","YCOI","YCWA","YCHK","YCWY","YCUE","YCAR","YCIN","YDGA","YDRA","YDBY","YDRD","YEEB","YESP","YECL","YEXM","YFTZ","YFRT","YFLO","YFRV","YGIB","YGIA","YGDN","YGEL","YGSC","YARG","YHLC","YHIL","YPJT","YJNB","YKBR","YKBL","YFDF","YPKG","YKNG","YPKU","YKAR","YPKA","YYLR","YPLM","YLST","YLEO","YLTN","YMBL","YMGR","YMHO","YMIP","YSHK","YMJM","YMEK","YMOG","YMDI","YMGT","YMUC","YMRW","YMWA","YMYR","YSAN","YCNF","YNUL","YNRG","YNSM","YBGD","YORV","YOLW","YPBO","YPPH","YPPD","YPDO","YROE","YRYH","YRTI","YNRV","YSHG","YSOL","YSCR","YTAB","YTHD","YTEF","YTKY","YTMP","YTST","YKAL","YUSL","YWIT","YWAL","YANG","YMNE","YWDG","YWWG","YMMI","YWLU","YWWI","YWYM","YYAL","YNWN","TNCA","UBBB","UBBG","UBBL","UBBN","UBBQ","UBEE","UBBY","LQMO","LQSA","LQTZ","LQBK","TBPB","VGBR","VGEG","VGCM","VGCB","VGHS","VGJR","VGIS","VGRJ","VGSD","VGSG","VGSH","VGSY","EBAW","EBZR","EBBR","EBCI","EBLG","EBKT","EBOS","DFOU","DFET","DFEZ","DFOB","DFEB","DFEF","DFOO","DFFD","DFEP","DFON","DFOD","DFCP","DFEA","DFEM","DFEG","DFOG","DFCA","DFEE","DFCL","DFOY","DFCJ","DFOT","DFER","DFED","DFEL","DFES","DFCC","LBBG","LBHS","LBPD","LBRS","LBSS","LBSF","LBSZ","LBTG","LBWN","LBGO","OBBI","HBBA","HBBE","HBBO","DBBK","DBBN","DBBP","DBBS","DBBD","DBBB","TFFJ","TXKF","WBSB","SLAG","SLSU","SLSB","SLCB","SLHI","SLHJ","SLBU","SLGY","SLMG","SLRQ","SLRY","SLRI","SLSA","SLJO","SLSM","SLSR","SLRA","SLTR","SLAP","SLLP","SLOR","SLCO","SLPR","SLPO","SLUY","SLAS","SLCA","SLCP","SLTI","SLPS","SLRB","SLJE","SLJV","SLSI","SLET","SLVG","SLVR","SLBJ","SLYA","SLTJ","SLVM","TNCB","TNCS","TNCE","SBCZ","SNOU","SBRB","SBTK","SWSN","SNAL","SBMO","SBMQ","SBOI","SWBC","SWNK","SWCA","SWKO","SWEI","SWOB","SWHT","SWII","SWTP","SBIC","SWLB","SBEG","SWMW","SBMY","SWNA","SDCG","SWPI","SBMN","SWBR","SBUA","SBTT","SBTF","SNBU","SBPS","SNBX","SNBR","SNBL","SNED","SBCV","SNJD","SNGI","SBIL","SNIU","SNIC","SNZW","SNHA","SNJB","SNJK","SBLP","SBLE","SNMU","SBUF","SNRD","SBSV","SNTF","SBTC","SNVB","SBQV","SBAC","SNWC","SBFZ","SBJU","SBJE","SBBR","SNKI","SNGA","SNMX","SBVT","SWNS","SWEC","SBCN","SBGO","SBIT","SWJW","SBMC","SWNQ","SWLC","SWUA","SWKT","SNAI","SNBC","SBRR","SNBS","SBCI","SNCP","SNGM","SBIZ","SNYE","SBSL","SBDB","SBCG","SBCR","SSCL","SSDO","SSPN","SBPP","SBTG","SBAT","SSOU","SWTU","SBBW","SWKC","SBCY","SWEK","SWDM","SWHP","SWJN","SWJU","SIZX","SILC","SWXM","SWVB","SWXV","SWSI","SWPG","SWPQ","SWRD","SWST","SWFX","SWTS","SWVC","SBAX","SNAR","SNDV","SNDT","SBGV","SBIP","SBZM","SBJF","SNJR","SNJN","SNDN","SBMK","SNNU","SNPX","SNPD","SBPC","SNZA","SNOS","SNLO","SNTO","SBUR","SBUL","SBVG","SBHT","SBBE","SNVS","SBAA","SBCJ","SNKE","SNYA","SBIH","SBEK","SBMA","SBMD","SNMA","SJNP","SNTI","SDOW","SNOX","SNMZ","SNDC","SNSW","SBSN","SNFX","SBTB","SBKG","SBJP","SSYA","SSAP","SSOG","SBBI","SBCA","SSKM","SSCP","SBCT","SSFB","SSCT","SSGY","SBGU","SBFI","SBLO","SBMG","SSZW","SSPG","SSPB","SSPI","SBTL","SBTD","SBTU","SSUM","SNRU","SBFN","SBPL","SBRF","SNQG","SNGD","SNPC","SBPB","SBTE","SBMS","SBNT","SSLT","SBBG","SSCN","SSSC","SSVP","SBCX","SSER","SBNM","SSHZ","SSIJ","SSIQ","SNLB","SBPK","SBPF","SBPA","SBSM","SBRG","SSRU","SSZR","SBTR","SBUG","SBBZ","SBCP","SBCB","SDUN","SBME","SDRS","SBVH","SWCQ","SBGM","SWJI","SSKW","SWPM","SBPV","SBBV","SSBL","SSCK","SBCM","SBCD","SBFL","SSJA","SBJA","SBJV","SBLJ","SSLN","SBNF","SSOE","SSUV","SSVI","SBCH","SBAS","SBAQ","SBAU","SBBT","SBBU","SBBP","SDAM","SIMK","SBGW","SDJL","SBAE","SBLN","SBML","SDOU","SBDN","SDSC","SBRP","SBSJ","SBSR","SDCO","SBST","SDUB","SBUP","SDVG","SBAR","SWRA","SWGN","SWDN","SWGI","SWIY","SBPJ","SBPN","MYAP","MYBG","MYBS","MYCB","MYAF","MYBC","MYAB","MYAN","MYCC","MYAW","MYGF","MYEF","MYEN","MYES","MYEH","MYAM","MYAT","MYIG","MYCI","MYRD","MYLD","MYCP","MYLS","MYMM","MYNN","MYRP","MYSM","MYAK","MYCA","MYEM","MYER","MYGW","VQBT","VQPR","VQGP","VQTY","FBOR","FBSP","FBSN","FBTL","FBKE","FBGZ","FBTS","FBFT","FBKR","FBMN","FBSV","FBSW","FBSK","FBLO","FBJW","UMBB","UMGG","UMMG","UMOO","UMMM","UMMS","UMII","MZBZ","MZPL","CYNR","CZPC","CYBA","CYBF","CYCT","CYEG","CYET","CYJA","CYLB","CYLL","CYMM","CYOD","CYOJ","CYOP","CYPE","CYPY","CYQF","CYQL","CYQU","CYRM","CYSD","CYVG","CYXH","CYYC","CYYM","CYZH","CYZU","CZHP","CYHC","CYBD","CYAL","CYAZ","CYBH","CYBL","CYCD","CYCG","CYCQ","CYCW","CYCZ","CYDL","CYDQ","CZBB","CYGB","CYHE","CYKA","CYLW","CYNJ","CYNH","CYPR","CYPW","CYPZ","CYQQ","CYQZ","CYRV","CYSE","CZAM","CYVK","CYVR","CYWH","CYWL","CYXC","CYXJ","CYXS","CYXT","CYXX","CYYD","CYYE","CYYF","CYYJ","CYZP","CYZT","CBBC","CZGF","CZML","CZMT","CZST","CZSW","CZBD","CZEE","CZMN","CZWH","CZFG","CZNG","CZSN","CYBQ","CYBR","CYBT","CYBV","CYCR","CYDN","CZTA","CYFO","CYGM","CYGO","CYGX","CYIV","CYLR","CYNE","CYOH","CYPG","CYQD","CYRS","CYST","CZLQ","CYTH","CYWG","CYYI","CYYL","CYYQ","CZAC","CZGI","CZGR","CZJG","CZJN","CZTM","CYCH","CYCL","CYFC","CYQM","CYSJ","CYSL","CZBF","CYAY","CYDF","CYDP","CYHO","CYJT","CYMH","CYFT","CYQX","CYCA","CYWK","CYYR","CYYT","CZUM","CYKD","CYVL","CYEV","CYWE","CYFR","CYFS","CYGH","CYHI","CYHY","CYJF","CYMD","CYOA","CYPC","CYRA","CYLK","CYSM","CYSY","CYUB","CYVQ","CYWJ","CYWY","CYZF","CZFM","CZFN","CYID","CYHZ","CYPD","CYQI","CYQY","CYZX","CYAB","CYBB","CYBK","CYCB","CYCO","CYCS","CYCY","CYEK","CYEU","CYFB","CYGT","CYGZ","CYHK","CYIO","CYLC","CYLT","CYRB","CYRT","CYSK","CYTE","CYUT","CYUX","CYVM","CYVN","CYXN","CYXP","CYYH","CYZS","CZMD","CYCK","CYAQ","CYAC","CYAG","CYAM","CYAT","CYCC","CYCE","CYSN","CYCN","CYEL","CYEM","CYER","CYFA","CYFH","CYGK","CYGQ","CYHD","CYHF","CYHM","CYHN","CYHP","CYIB","CYKM","CYKF","CYKX","CYLD","CYLH","CYLS","CYMG","CYMO","CYKP","CYOO","CYOS","CYOW","CYPL","CYPM","CYPO","CYPQ","CYQA","CYQG","CYQK","CYQN","CYQS","CYQT","CYRL","CYRO","CYSB","CYSH","CYSP","CYTA","CYTL","CYTR","CYTS","CYTZ","CYVV","CYVZ","CYWA","CYWP","CYXL","CYXR","CYXU","CYXZ","CYYB","CYYU","CYYW","CYYZ","CYZE","CYZR","CZKE","CZPB","CZRJ","CZSJ","CZUC","CYSU","CYYG","CYKO","CYLU","CYAH","CYAD","CYBC","CYBG","CYBX","CYDO","CYEY","CYFE","CYGL","CYGP","CYGR","CYGV","CYGW","CYHR","CYIF","CYIK","CYJN","CYAS","CYKL","CYKQ","CYLP","CYLQ","CYME","CYML","CYMT","CYMW","CYMX","CYNA","CYNC","CYND","CYNM","CYHH","CYPH","CYLA","CYPN","CYPX","CYQB","CYHA","CYRI","CYRJ","CYRQ","CYSC","CYTF","CYFJ","CYTQ","CYMU","CYUL","CYUY","CYVB","CYVO","CYVP","CYKG","CYXK","CYYY","CYZG","CYZV","CZBM","CZEM","CYBE","CYEN","CYHB","CYKC","CYKJ","CYKY","CYLJ","CYMJ","CYNL","CYPA","CYQR","CYQV","CYQW","CYSF","CYVC","CYVT","CYXE","CYYN","CZFD","CZPO","CZWL","CYDM","CYDA","CYDB","CYHT","CYMA","CYOC","CYQH","CYXQ","CYXY","CYZW","CZFA","YPCC","FZKJ","FZFD","FZEN","FZEA","FZQA","FZSK","FZQG","FZTK","FZQC","FZKA","FZWC","FZWT","FZVI","FZVA","FZWA","FZVR","FZUA","FZUG","FZVM","FZVS","FZUK","FZAA","FZAB","FZAJ","FZAL","FZAM","FZAG","FZAR","FZQM","FZBO","FZCB","FZBA","FZOK","FZCA","FZBT","FZCE","FZCV","FZBI","FZOC","FZOA","FZOP","FZFU","FZGA","FZNP","FZNA","FZJH","FZFP","FZGV","FZMA","FZFK","FZFA","FZRB","FZRF","FZRM","FZRQ","FZRA","FZIC","FZIR","FZGN","FEFN","FEFF","FEFZ","FEGE","FEFY","FEFR","FEFW","FEFT","FEFC","FEFG","FEGM","FEGR","FEFO","FEFM","FEGU","FEFS","FEGF","FEGZ","FEFI","FEGO","FCBM","FCBY","FCBZ","FCBB","FCOB","FCOO","FCOM","FCOE","FCOK","FCBS","FCOT","FCOI","FCPL","FCPA","FCMM","FCBD","FCOG","FCBL","FCPP","FCBK","FCOU","FCOS","LSZB","LSGG","LSZS","LSME","LSZC","LSZR","LSZA","LSGS","LSZH","DIAP","DIOF","DIGN","DISP","DITB","DISS","DIAO","DIAU","DIOD","DIDV","DIGA","DIDK","DIGL","DIMN","DIDL","DIBI","DIFK","DIKO","DIBK","DISG","DITM","DIYO","DIBU","DIBN","NCAI","NCAT","NCMG","NCMH","NCMR","NCMK","NCPY","NCPK","NCRG","SCBA","SCCC","SCCY","SCHR","SCAS","SCFA","SCCF","SCBE","SCTT","SCAR","SCRA","SCAT","SCES","SCLL","SCIE","SCGE","SCCH","SCQB","SCSE","SCOV","SCTC","SCQP","SCTO","SCPC","SCFT","SCFR","SCPQ","SCTE","SCPV","SCAP","SCST","SCTN","SCJO","SCAC","SCVD","SCNT","SCCI","SCSB","SCFM","SCGZ","SCTL","SCEL","SCKP","SCDA","SCIP","SCVM","SCAN","SCRD","FKKN","FKYS","FKKY","FKKO","FKKI","FKKJ","FKKH","FKKL","FKKD","FKAN","FKKR","FKKG","FKKV","FKKU","FKKS","FKKM","FKKW","FKKB","FKKF","FKKC","ZSAQ","ZSBB","ZSFY","ZSOF","ZSTX","ZSWA","ZBAA","ZUWL","ZUWS","ZUCK","ZUDZ","ZUQJ","ZULP","ZUWX","ZSFZ","ZSQZ","ZSLO","ZSSM","ZSWY","ZSAM","ZLDH","ZLXH","ZLQY","ZLJQ","ZLJC","ZLLL","ZLLN","ZLTS","ZLZY","ZGGG","ZGFS","ZGHZ","ZGMX","ZGOW","ZGSZ","ZGXN","ZGZJ","ZGSD","ZGBS","ZGBH","ZGHC","ZGKL","ZGZH","ZGNN","ZGWZ","ZUYI","ZUAS","ZUBJ","ZUNP","ZUGY","ZULB","ZUPS","ZUTR","ZUMT","ZUZY","ZJHK","ZJSY","ZBDH","ZBCD","ZBHD","ZBSJ","ZBTS","ZBXT","ZBZJ","ZYDQ","ZYFY","ZYHE","ZYHB","ZYJD","ZYJM","ZYJS","ZYJX","ZYLD","ZYMD","ZYQQ","ZYMH","ZYYL","ZHXY","ZHAY","ZHCC","ZHLY","ZHNY","ZHEC","ZHES","ZHSN","ZHGH","ZHSS","ZHSY","ZHHH","ZHXF","ZHYC","ZGCZ","ZGYY","ZGCD","ZGHA","ZGDY","ZGCJ","ZGHY","ZGLG","ZGSY","ZSCG","ZSSH","ZSLG","ZSNJ","ZSNT","ZSRG","ZSSZ","ZSWX","ZSXZ","ZSYN","ZSYA","ZSJD","ZSJA","ZSJJ","ZSCN","ZSGZ","ZSSR","ZSYC","ZYCC","ZYBA","ZYJL","ZYBS","ZYTN","ZYYJ","ZYSQ","ZYAS","ZYCY","ZYCH","ZYDD","ZYTL","ZYJZ","ZYTX","ZYXC","ZYYK","ZBOW","ZBCF","ZBDS","ZBER","ZBHH","ZBLA","ZBUL","ZBHZ","ZBMZ","ZBYZ","ZBTL","ZBUH","ZBXH","ZBES","ZLGY","ZLIC","ZLZW","ZLHB","ZLGL","ZLGM","ZLDL","ZLXN","ZLYS","ZLAK","ZBCZ","ZBDT","ZLYA","ZLHZ","ZBLL","ZLSN","ZBYN","ZLYL","ZBXZ","ZLXY","ZSHZ","ZSDY","ZLJN","ZSLY","ZSQD","ZSJN","ZSWF","ZSWH","ZSYT","ZSPD","ZSSS","ZBYC","ZUDA","ZUHY","ZUUU","ZUDX","ZUDC","ZUGH","ZUGU","ZUJZ","ZUKD","ZULZ","ZUMY","ZUNC","ZUZH","ZUTF","ZUXC","ZUYB","ZBTJ","ZWAT","ZWAK","ZWBL","ZWFY","ZWHM","ZWTN","ZWCM","ZWKC","ZWSH","ZWKN","ZWKL","ZWKM","ZWNL","ZWRQ","ZWHZ","ZWSS","ZWTC","ZWTL","ZWWW","ZWYN","ZUBD","ZULS","ZUNZ","ZUAL","ZURK","ZPBS","ZPCW","ZPDQ","ZPDL","ZPJH","ZPJM","ZPPP","ZPLJ","ZPLC","ZPMS","ZPSM","ZUTC","ZPWS","ZPYM","ZPZT","ZSHC","ZSZS","ZSLQ","ZSJU","ZSNB","ZSWZ","ZSYW","SKLT","SKLP","SCSF","SKRA","SKAN","SKAM","SKLC","SKCU","SKEB","SKMD","SKIG","SKRG","SKPN","SKNC","SKOT","SKPR","SKTU","SKUR","SKAT","SKUC","SKCN","SKSA","SKTM","SKBQ","SKCG","SKMG","SKMP","SKVL","SKPA","SKSO","SKTA","SKMZ","SKAC","SKYA","SKFL","SKSV","SKTQ","SKYP","SKHC","SKOE","SKPZ","SKTD","SKGP","SKPP","SKMB","SKAG","SKVP","SKAD","SKCP","SKBS","SKCD","SKCA","SKJU","SKNQ","SKUI","SKML","SKMR","SKPQ","SKBO","SKBM","SKPD","SKMF","SKSJ","SKNV","SKPI","SKLM","SKRH","SKBC","SKPL","SKSM","SKAP","SKCI","SVWX","SKNA","SKUB","SKVV","SKEH","SKIP","SKPS","SKCO","SKCC","SKOC","SKTB","SKLG","SKAS","SKVG","SKAR","SKPE","SKSP","SKPV","SKBG","SKCM","SKEJ","SKRU","SKCV","SKCZ","SKTL","SKHA","SKGI","SKIB","SKQU","SKBU","SKCL","SKGO","SKUL","SKCR","SKMU","SKGA","SKIM","SKPC","SKSL","MRAN","MRLC","MRRF","MROC","MRUP","MRMJ","MRLB","MRNC","MRNS","MRIA","MRCR","MRTM","MRBC","MRGP","MRLM","MRBT","MRBA","MRDK","MRGF","MRCH","MRCC","MRPJ","MRPM","MRTR","MRSV","MRQP","MRSI","MRPV","MUPB","MUCM","MUCA","MUCC","MUCF","MUBY","MUMZ","MUBA","MUGT","MUGM","MUHG","MUMO","MUCL","MUNG","MUSN","MUHA","MUVT","MUVR","MUKW","MULM","MUSJ","MUTD","MUSS","MUCU","MUBR","MUSC","GVBA","GVBR","GVMA","GVNP","GVAN","GVSN","GVAC","GVMT","GVSF","GVSV","TNCC","YPXM","LCGK","LCLK","LCEN","LCRA","LCPH","LKCS","LKTB","LKKV","LKMR","LKMT","LKZA","LKOL","LKPO","LKPD","LKPR","LKVO","LKHO","LKKU","EDNY","EDSB","ETIE","EDTL","EDFM","EDDS","EDMA","EDQD","ETSF","EDJA","EDQG","EDQM","ETSI","ETIK","ETIN","EDDM","EDDN","EDMO","EDMS","EDQE","EDDT","EDDB","EDCD","EDDW","EDWB","EDDH","EDHI","EDDF","ETHF","EDVK","ETOU","EDBH","EDBN","EDCG","EDAH","EDCP","EDAX","ETNL","EDOP","EDWG","EDWR","EDWZ","EDVE","EDWE","ETMN","EDDV","EDWJ","EDWL","EDWS","EDWY","EDWU","EDWI","EDWD","EDKA","EDLI","EDDK","EDLW","EDDL","EDLE","EDDG","ETNG","ETUO","EDLN","EDLV","EDLP","EDGS","EDRB","EDFH","ETAR","ETAD","EDRZ","EDDR","EDDC","EDAU","EDDP","EDBC","EDCK","EDAQ","EDHN","EDXF","EDXW","EDXB","EDXH","EDHK","EDHL","EDXY","EDXO","EDXJ","ETNS","EDAC","EDGE","EDDE","HDAS","HDAM","HDOB","HDMO","HDTJ","EKCH","EKRN","EKAH","EKKA","EKSV","EKVJ","EKYT","EKLS","EKSN","EKTS","EKMB","EKRK","EKBI","EKEB","EKOD","EKSB","EKSP","TDPD","TDCF","MDBH","MDJB","MDPC","MDCZ","MDSD","MDCR","MDPP","MDCY","MDAB","MDST","DAUA","DATM","DAUT","DAAG","DABB","DABT","DAOR","DAAE","DAUB","DAOI","DABC","DAAD","DAOY","DAUO","DAUE","DAUG","DAAJ","DAUZ","DAAP","DAAV","DAFH","DAUL","DAOV","DAAY","DAOO","DAOL","DAUH","DAUU","DAUK","DAAS","DAOS","DABP","DATG","DAUI","DAAT","DABS","DAOB","DAOF","DAON","SECU","SETU","SERO","SEMH","SETN","SEGS","SEII","SEST","SEGU","SETM","SEMA","SESV","SEJI","SEMT","SEPV","SESC","SETH","SEMC","SEJD","SECO","SETI","SESM","SEQM","SESA","SENL","SEPT","SETR","SEAM","EETN","EEKA","EEPU","EEKE","EETU","HEGN","HEMA","HEAX","HEBA","HE25","HECA","HELX","HEDK","HEOW","HEKG","HEBL","HESN","HEAT","HEPS","HETR","HESC","HESH","HETB","HEAL","HEMM","HEAR","HEMK","HHAS","HHSB","HHTS","HHMS","LEMG","LEGR","LEAM","LEBA","LEMO","LERT","LEZL","LEJR","LEHC","LETL","LEZG","LEAS","GCRR","GCFV","GCGM","GCLP","GCLA","GCHI","LEXJ","LERL","LELN","LEBG","LESA","LEVD","LEAB","LEBL","LEGE","LEDA","LESU","LERS","LEBZ","LECO","LEST","LEVX","LEIB","LEMH","LEPA","LELO","LEMD","LETO","GEML","LELC","LEMI","LEPP","LEBB","LESO","LEVT","LEAL","LECH","LEVC","HAAB","HASM","HABD","HADM","HADT","HADC","HAMM","HAGN","HALL","HAMA","HAPW","HASO","HADR","HAGM","HABE","HADD","HANG","HAFN","HAGH","HAGB","HAGR","HAJM","HAML","HAMN","HANJ","HANK","HASK","HABB","HAKD","HAGO","HASL","HAJJ","HAKL","HAWR","HAAX","HAHU","HAMK","HAAM","HALA","HABC","HABU","HAMT","HAMR","HASD","HATP","HAMJ","HAWC","EFLP","EFKA","EFKJ","EFSI","EFMI","EFSA","EFVR","EFKI","EFJY","EFHA","EFUT","EFET","EFIV","EFKE","EFKT","EFRO","EFSO","EFTP","EFKK","EFVA","EFJO","EFIT","EFKS","EFOU","EFYL","EFKU","EFPO","EFHK","EFHF","EFHV","EFMA","EFTU","NFNH","NFFN","NFND","NFNA","NFCI","NFNW","NFKD","NFNO","NFNB","NFNK","NFMO","NFNG","NFOL","NFVB","NFNU","NFNL","NFFR","NFNR","NFNS","NFNM","NFCS","NFMA","NFFO","NFNV","NFVL","NFSW","EKVG","EGYP","SFAL","PTKK","PTSA","PTPN","PTYA","LFHU","LFLW","LFLC","LFLB","LFLJ","LFMH","LFLS","LFHP","LFLY","LFLL","LFBK","LFKX","LFHM","LFLP","LFHO","LFLO","LFLU","LFLV","LFHS","LFHY","LFLA","LFSD","LFGJ","LFQG","LFLN","LFRB","LFRD","LFRO","LFRJ","LFRH","LFRU","LFRN","LFRT","LFRQ","LFRV","LFLD","LFLX","LFOZ","LFOT","LFKJ","LFKB","LFKC","LFKF","LFKO","LFKS","LFGA","LFSN","LFSG","LFJL","LFSF","LFSR","LFST","LFSZ","LFQV","LFAQ","LFAC","LFPC","LFQT","LFQQ","LFAT","LFPG","LFPO","LFPN","LFRC","LFRK","LFRG","LFAB","LFOE","LFRF","LFOH","LFOP","LFBA","LFBU","LFBZ","LFBD","LFSL","LFBG","LFBE","LFBL","LFBH","LFBN","LFBX","LFBI","LFBP","LFDN","LFCY","LFMU","LFMK","LFCK","LFTW","LFCI","LFBT","LFNB","LFMT","LFMP","LFCR","LFBO","LFCC","LFJR","LFOU","LFRI","LFEY","LFRE","LFRM","LFOO","LFOV","LFRS","LFRZ","LFMV","LFMR","LFMD","LFMQ","LFNA","LFTZ","LFML","LFMN","LFMI","LFMA","LFNC","LFTH","FOOL","FOGA","FOOD","FOON","FOGQ","FOGJ","FOGR","FOGF","FOGE","FOGG","FOGM","FOGI","FOOY","FOOT","FOGB","FOOE","FOOK","FOGK","FOOR","FOGW","FOOI","FOOH","FOOG","FOOB","FOGV","FOOM","FOGO","EGTB","EGHD","EGHJ","EGLK","EGXH","EGUB","EGBB","EGNH","EGHH","EGKB","EGGD","EGNL","EGVN","EGNC","EGSC","EGBE","EGCN","EGNX","EGTE","EGLF","EGVA","EGBP","EGBJ","EGXU","EGNJ","EGNS","EGHE","EGYM","EGKR","EGNM","EGLC","EGHC","EGKK","EG74","EGLL","EGUL","EGGP","EGGW","EGDL","EGMD","EGCC","EGUN","EGNV","EGNT","EGWU","EGBN","EGHQ","EGSH","EGVO","EGBK","EGTK","EGXC","EGSU","EGHL","EGHR","EGUY","EGTO","EGMC","EGHI","EGXP","EGSS","EGDJ","EGXW","EGDY","EGJB","EGJA","EGMH","EGNO","EGAA","EGAC","EGQB","EGAB","EGAE","EGXJ","EGPD","EGQL","EGPL","EGPR","EGEC","EGPN","EGPH","EGED","EGEF","EGQK","EGPF","EGPI","EGPE","EGPA","EGQS","EGPB","EGET","EGES","EGEN","EGEO","EGPK","EGEP","EGPT","EGEI","EGER","EGPO","EGPU","EGPW","EGEH","EGPC","EGEW","EGTG","EGNR","EGFF","EGFE","EGFH","EGOV","EGKA","TGPY","UGSS","UGSB","UGKO","UGTB","SOCA","SOGS","SOOM","SOOA","SOOG","SOOR","SOOS","DGSI","DGSN","DGAA","DGLE","DGTK","LXGB","BGJN","BGUQ","BGUK","BGQQ","BGTL","BGUM","BGBW","BGCH","BGAA","BGCO","BGGH","BGPT","BGKK","BGSS","BGMQ","BGSF","GBYD","GUOK","GUSB","GUCY","GUFH","GUFA","GUSI","GUXN","GUKU","GULB","GUMA","GUNZ","TFFB","TFFA","TFFM","TFFS","TFFR","TFFC","FGAB","FGSL","FGBT","FGMY","LGAL","LGKV","LGAV","LGKC","LGAG","LGRX","LGAD","LGKA","LGKZ","LGKR","LGKF","LGPZ","LGZA","LGIO","LGTS","LGSA","LGIR","LGST","LGKP","LGKY","LGMK","LGNX","LGSO","LGSR","LGPL","LGKO","LGKS","LGKJ","LGLE","LGML","LGPA","LGRP","LGHL","LGKL","LGSP","LGSY","LGSK","LGLR","LGBL","LGIK","LGHI","LGLM","LGMT","LGSM","MGCB","MGRB","MGSJ","MGGT","MGHT","MGRD","MGPB","MGCR","MGTK","MGPP","MGQZ","MGCT","MGQC","MGPG","MGRT","PGUM","PGUA","GGOV","GGBU","SYBR","SYMR","SYMB","SYBT","SYIB","SYKM","SYPR","SYCJ","SYGO","SYKZ","SYSC","SYMK","SYKA","SYKT","SYMD","SYMM","SYOR","SYAH","SYKS","SYKR","SYLT","SYLP","SYAN","VHHH","MHLC","MHTE","MHIR","MHTJ","MHSC","MHRU","MHSR","MHLM","MHTG","MHAH","MHPC","MHPL","MHLE","MHNJ","MHRO","MHUT","MHMA","MHGS","MHGE","MHJU","MHCS","MHEA","MHYR","MHUL","LDDU","LDZA","LDPL","LDOS","LDLO","LDRI","LDSB","LDSP","LDZD","MTJE","MTCH","MTPX","MTPP","MTCA","MTJA","LHPP","LHBP","LHMC","LHDC","LHSM","WITT","WITM","WITL","WITC","WITN","WADD","WIII","WIHP","WIIG","WIPL","WIPI","WIBJ","WARW","WAMG","WAMY","WIPA","WIPH","WIPU","WIBT","WICC","WICD","WICN","WICA","WICM","WARC","WAHL","WAHP","WARQ","WARS","WAHI","WADY","WARE","WARA","WARR","WART","WIOK","WIOO","WIOP","WIOS","WAOO","WAOC","WRBK","WAON","WIOG","WAOI","WAGG","WAOS","WAOW","WALS","WALK","WALL","WRLC","WALJ","WRLA","WRLH","WALT","WALV","WRLB","WRLP","WRLF","WAGD","WITA","WALR","WIOM","WIPK","WIKD","WIDD","WION","WIDN","WIAG","WILL","WAMA","WAPH","WAPE","WAMR","WAPN","WAPT","WAEE","WAPA","WAPP","WAPK","WAPD","WAMJ","WAMK","WAPF","WAPR","WAPC","WAPG","WAPI","WAPV","WADB","WADL","WADU","WADS","WATA","WATM","WRKB","WATE","WATT","WATO","WATL","WATW","WATC","WATG","WATR","WATS","WADT","WADW","WASG","WASO","WASF","WASI","WASU","WASE","WASK","WASR","WASB","WASM","WASN","WASC","WASS","WAST","WAJA","WABB","WAJB","WAKE","WAJG","WAJJ","WAJC","WAJN","WABT","WABL","WABE","WABK","WAKM","WAKP","WABN","WAJL","WAJM","WAKD","WAKK","WABI","WABR","WAJO","WAKO","WABD","WAJE","WAJS","WABP","WAKT","WAJU","WABV","WAJR","WABG","WAVV","WASW","WAKQ","WABO","WAJI","WIBD","WIBB","WIBS","WIDS","WIPB","WAFJ","WAWT","WAWM","WAWS","WAAA","WAMW","WAFF","WAMP","WAMI","WAWB","WAWW","WAWP","WAWR","WA44","WIME","WIMN","WIMS","WIMB","WIMM","WAMM","WIMK","WAMN","WAMH","WIMP","WIPT","WIDE","WIBR","WIPV","WIPQ","WIPP","WADA","WASA","WIIJ","EINN","EIBN","EICK","EIDL","EILT","EIDW","EICM","EIMN","EIIR","EIIM","EICA","EIKY","EIKK","EIBT","EIKN","EISG","EIWF","LLBS","LLEY","LLET","LLER","LLMR","LLMZ","LLOV","LLNV","LLYT","LLKS","LLIB","LLHA","LLSD","LLBG","OJJR","VOCX","VOPB","VIBY","VOCP","VOPN","VORY","VOTP","VOBZ","VEVZ","VEPG","VEAN","VETJ","VEZO","VEDZ","VEMN","VEGT","VELR","VEKW","VEKM","VEKU","VEJT","VERU","VETZ","VEDH","VEGY","VEMZ","VEPT","VICG","VEBU","VARP","VADN","VIDP","VOGO","VAAH","VABO","VABJ","VABV","VAKS","VAKE","VAJM","VAPR","VARK","VASU","VIHR","VIGG","VIBR","VISM","VIJU","VILH","VISR","VEDB","VERC","VEJS","VOBI","VOBL","VAHB","VOML","VABM","VOMY","VOJV","VOCL","VOKN","VOCI","VOTV","VOAT","VABP","VAGN","VIGR","VAKJ","VAID","VAJB","VIST","VAAK","VABB","VAOZ","VAAU","VAJL","VAKP","VALT","VANP","VAND","VAPO","VARG","VASL","VEIM","VEBI","VELP","VEMR","VEBS","VIJR","VEJP","VERK","VOPC","VIAX","VIAR","VIBT","VIPK","VILD","VIBK","VIJP","VIJO","VIKG","VIKO","VAUD","VOCB","VOMD","VOMM","VONV","VOSM","VOTK","VOTJ","VOTR","VOHY","VOHS","VORG","VOWA","VEAT","VEKR","VIAG","VEGK","VIAL","VIKA","VILK","VEBN","VIDN","VIPT","VECC","VECO","VEBD","VEMH","VEDG","VEBG","ORAA","ORAT","ORMM","ORNI","ORER","ORSU","ORBI","ORBB","ORKK","ORBM","OIIP","OITL","OITP","SVHG","OITU","OITK","OITR","LATI","OITM","OITT","OIBB","OIBH","OITH","OIBQ","OIBJ","OIBP","OIFS","OIFE","OIFM","OISF","OISJ","OISR","OISL","OISS","OIGG","OING","OINE","OIHH","OIHS","OIBA","OIBL","OIKB","OIKQ","OIKP","OIBK","OIBV","OIBS","OICI","OIKM","OIKJ","OIKK","OIKR","OIKY","OICC","OIMT","OIMB","OIMS","OIMC","OIMM","OIMN","OIAA","OIAG","OIAW","OIAD","OIAM","OIAJ","OIAH","OISY","OICS","OICK","OIHR","OINJ","OINN","OINR","OINZ","OIIK","OIMJ","OIIS","OIZB","FMNE","FMNH","FMNA","OIZI","FMNJ","FMNN","FMNS","FMNV","OIZH","OIZC","FMND","OIIE","OIFK","OIII","OIYY","OITZ","BIBF","BIDV","BIHN","BIRK","BIAR","BIBK","BIBV","BIEG","BIFF","BIGR","BIHU","BIRL","BINF","BIOF","BIKP","BIRG","BISI","BITN","BIVO","BIBD","BIBL","BIRF","BIPA","BIKR","BIFM","BIVM","BIKF","BIGJ","BIHK","BIIS","BIRE","BITE","BIGF","BIST","LIBP","LIAP","LIBC","LICR","LICA","LIRN","LIRI","LIPE","LIPK","LIDR","LIPR","LIPA","LIPQ","LIPD","LIRF","LIMG","LIMJ","LIML","LIMC","LIPO","LIPY","LIMZ","LIMF","LIBR","LIBD","LIBF","LIBN","LIBG","LIEA","LIEE","LIED","LIER","LIEO","LIET","LICB","LICC","LICD","LICZ","LICJ","LICG","LICT","LIRJ","LIRQ","LIRS","LIQL","LIRP","LIQS","LIPB","LIRZ","LIMW","LIDB","LIPH","LIPZ","LIPT","LIPX","EGJJ","MKTP","MKKJ","MKJP","MKJS","MKBS","MKNG","OJAQ","OJAM","OJMF","OJMN","OJAI","RJGG","RJNA","RJSK","RJSR","RJSA","RJSH","RJSM","RJOM","RJNF","RJFF","RJFR","RJSF","RJOA","RJBH","RJEC","RJCH","RJCK","RJEB","RJCM","RJCB","RJEO","RJCR","RJER","RJCN","RJCW","RJBT","RJAH","RJNK","RJNW","RJSI","RJOT","RJKA","RJKI","RJFK","RJFC","RJKB","RORY","RJKN","RJFG","RJTA","RJOK","RJDA","RJFT","RJSS","RJFM","RJAF","RJFE","RJDB","RJFU","RJDU","RJDT","RJSN","RJSD","RJFO","RJOB","RORA","RODN","RORH","RORE","ROIG","ROKR","RORK","ROMD","ROMY","ROYN","ROAH","RORS","RORT","ROKJ","RJBB","RJFS","RJOW","RJOC","RJNS","RJOS","RJTH","RJTT","RJAW","RJAM","RJTQ","RJAA","RJTO","RJNO","RJOR","RJOH","RJNT","RJBD","RJSC","RJSY","RJOI","RJDC","HKJK","HKGA","HKAM","HKKG","HKKR","HKML","HKKI","HKUK","HKNY","HKLU","HKMA","HKMY","HKMB","HKMK","HKMO","HKNW","HKNK","HKKE","HKNI","HKSB","HKKL","HKHO","HKES","HKFG","HKLK","HKLO","HKLY","HKEL","HKKT","HKWJ","UAFM","UAFO","VDBG","VDKH","VDKK","VDKT","VDSV","VDMK","VDPP","VDST","VDRK","VDSR","NGUK","NGAB","NGTB","NGTR","NGTU","NGBR","NGKT","NGMA","NGMN","NGMK","NGNU","NGTO","NGON","NGTE","NGTM","NGTA","NGTS","PCIS","PLCH","FMCV","FMCH","FMCN","FMCI","TKPK","TKPN","ZKHM","ZKSD","ZKWS","ZKUJ","ZKPY","ZKSE","RKPK","RKTU","RKTI","RKTP","RKNN","RKNW","RKNY","RKJU","RKJK","RKJJ","RKJB","RKJY","RKSI","RKSO","RKSW","RKPE","RKPS","RKTH","RKTN","RKTL","RKPU","RKTY","RKPC","RKPD","OKAJ","OKBK","MWCB","MWCR","MWCL","UAAL","UAAA","UAAR","UACK","UATT","UACC","UATG","UARR","UAOL","UATE","UAII","UASB","UASP","UAAH","UAKD","UAKK","UAUR","UAUU","UAOO","UASS","UASK","UACP","UADD","VLAP","VLHS","VLKG","VLPS","VLSN","VLTK","VLLN","VLLB","VLOS","VLSV","VLSK","VLVT","VLSB","VLXK","OLBA","OLKA","TFFG","TLPC","TLPL","VCCG","VCCB","VCCS","VCCT","VCCA","VCCH","VCCJ","VCRI","VCCK","VCCW","VCBI","VCCN","VCCC","GLBU","GLTN","GLST","GLVA","GLRB","GLCP","GLMR","GLNA","GLGE","FXLR","FXPG","FXSS","FXMF","FXMM","FXSM","FXNK","FXMK","FXTK","FXLK","FXSK","FXQN","FXQG","FXLS","FXMA","FXSH","FXTA","EYVI","EYKA","EYPA","EYPP","EYSA","ELLX","EVDA","EVRA","EVLA","EVVA","HLGN","HLLQ","HLZN","HLON","HLKF","HLMB","HLNR","HLLB","HLGT","HLMS","HLTD","HLLS","HLGD","HLLM","HLLT","HLZW","HLUB","GMMD","GMMC","GMMN","GMMB","GMFK","GMAZ","GMMZ","GMFF","GMFM","GMMF","GMAT","GMMW","GMFO","GMFB","GMML","GMMA","GMMH","GMMX","GMMS","GMMY","GMME","GMAD","GMMI","GMTA","GMTT","LUBL","LUKK","LYBR","LYPG","LYTV","FMME","FMFE","FMMI","FMSU","FMMX","FMSI","FMSM","FMSG","FMSF","FMSK","FMNQ","FMNO","FMNL","FMNM","FMMO","FMNT","FMMR","FMNW","FMMG","FMNF","FMNX","FMNP","FMNG","FMMU","FMMQ","FMMS","FMMT","FMMY","FMMH","FMMZ","FMNR","FMNC","FMSY","FMSV","FMML","FMSD","FMMK","FMSJ","FMMV","FMSR","FMSL","FMSN","FMST","FMSZ","FMSB","FMSC","FMMC","FMMN","PKMA","PKWA","PKMJ","MLIP","LWOH","LWSK","GABS","GAGO","GAYE","GAKA","GAKY","GANR","GANK","GAMB","GASK","GAKO","GAGM","GATB","VYPN","VBHD","VYAN","VYPY","VYBM","VYMK","VYPT","VYLK","VYPA","VYPP","VYGG","VYKU","VYMW","VYPK","VYPU","VYHN","VYMD","VYNT","VYBG","VYCZ","VYMM","VYYE","VYSW","VYGW","VYKP","VYMN","VYTD","VYHL","VYKI","VYKL","VYMY","VYHH","VYKG","VYLS","VYMT","VYMO","VYMS","VYNS","VYTL","VYKT","VYME","VYDW","VYBP","VYYY","ZMTG","ZMUL","ZMBH","ZMBN","ZMCD","ZMMG","ZMTL","ZMAT","ZMDN","ZMUH","ZMBS","ZMKD","ZMHG","ZMMN","ZMDZ","ZMAH","ZMHU","ZMHH","ZMBR","ZMBU","ZMCK","ZMUB","ZMUG","VMMC","PGRO","PGSN","PGWT","TFFF","GQPA","GQNF","GQNE","GQPP","GQNK","GQNS","GQNJ","GQNA","GQNU","GQNO","GQNT","GQNL","GQNC","GQND","GQNI","GQPF","GQPZ","GQNH","GQNB","TRPG","LMML","FIMP","FIMR","VRMD","VRMV","VRMT","VRMF","VRMH","VRMM","VRMO","VRMK","VREI","VRMG","VRNT","FWCL","FWCD","FWKA","FWKG","FWLK","FWKI","FWCM","FWMG","FWMY","FWUU","FWDW","FWSM","MMAS","MX86","MMGR","MMLP","MMLT","MMMG","MMPL","MMSD","MMES","MMML","MMSF","MMTJ","MMCE","MMCP","MMCO","MMPQ","MMTP","MMTG","MMCS","MMCU","MMCG","MMCC","MMMV","MMPG","MMIO","MMTC","MMIA","MMZO","MMDO","MMLO","MMCY","MMAA","MMZH","MMGL","MMPR","MMJC","MMMX","MMSM","MMTO","MMLC","MMMM","MMPN","MMZM","MMCB","MMEP","MMMY","MMAN","MMBT","MMIT","MMOX","MMPS","MMSZ","MMPB","MMHC","MMQT","MMCM","MMUN","MMCZ","MMIM","MMSP","MMTN","MMCL","MMLM","MMMZ","MMCN","MMCA","MMGM","MMHO","MMNG","MMPE","MMVA","MMCV","MMMA","MMDM","MMNL","MMRX","MMTM","MMJA","MMMT","MMPA","MMVR","MMCT","MMMD","MMZC","WMKJ","WMAU","WMKA","WMKL","WMKC","WMKM","WMKD","WMAN","WMBT","WMKI","WMPA","WMBA","WMBI","WMKB","WMKP","WBKK","WBKN","WBKG","WBKT","WBKL","WBKD","WBKP","WBKR","WBKS","WBKA","WBKO","WBKH","WBKE","WBKM","WBKW","WBGZ","WBGQ","WBGC","WBGN","WBGB","WBGG","WBGP","WBGF","WBGL","WBGJ","WBGD","WBGU","WBGW","WBGK","WBGM","WBGR","WBMU","WBGI","WBGS","WBGY","WBTM","WMKK","WMSA","WMKE","WMPR","WMKN","FQIB","FQLU","FQMD","FQMP","FQPB","FQXA","FQIN","FQVL","FQCH","FQIA","FQMA","FQPO","FQAG","FQNP","FQNC","FQCB","FQLC","FQBR","FQTT","FQQL","FYAR","FYME","FYSM","FYWB","FYSS","FYAA","FYKB","FYKT","FYLZ","FYOG","FYSA","FYRU","FYWE","FYMG","FYNG","FYWH","FYOP","FYTE","FYGB","FYOS","FYOA","FYHI","FYNA","FYOO","FYMO","FYTM","FYGF","FYOW","FYLS","FYKM","FYOE","NWWC","NWWD","NWWK","NWWQ","NWWP","NWWU","NWWM","NWWE","NWWW","NWWA","NWWL","NWWR","NWWV","DRZA","DRZL","DRRM","DRRN","DRRT","DRZR","YSNF","DNAA","DNJO","DNYO","DNAI","DNMK","DNMA","DNCA","DNAS","DNSU","DNBE","DNEN","DNGO","DNIM","DNKA","DNZA","DNKN","DNIL","DNMM","DNMN","DNAK","DNIB","DNPO","DNSO","MNBZ","MNPC","MNRT","MNSI","MNWP","MNBL","MNNG","MNCI","MNMG","MNSC","MNCE","EHGG","EHLE","EHLW","EHBK","EHEH","EHGR","EHVK","EHWO","EHAM","EHKD","EHTW","EHSB","EHRD","ENGM","ENKL","ENAT","ENBS","ENBV","ENHK","ENHF","ENHV","ENKR","ENNA","ENMH","ENSS","ENVD","ENHA","ENBR","ENSO","ENAL","ENOV","ENKB","ENML","ENVA","ENAN","ENBN","ENBO","ENEV","ENLK","ENMS","ENRA","ENNK","ENRS","ENSK","ENST","ENSH","ENFG","ENRY","ENHD","ENZV","ENBL","ENFL","ENSD","ENSG","ENOL","ENNM","ENRO","ENRM","ENNO","ENSN","ENDU","ENSR","ENTC","ENCN","ENTO","VNKT","VNLT","VNBR","VNNG","VNSK","VNBL","VNJS","VNMA","VNPK","VNJP","VNRC","VNDP","VNST","VNJL","VNBJ","VNVT","VNRB","VNTR","VNBW","VNDT","VNMN","VNCG","VNTJ","VNBP","VNGK","VNMG","VNSI","VNDG","VNRP","VNRK","VNJI","VNLD","VNLK","VNPL","VNRT","VNSB","VNBT","VNBG","VNDL","VNDH","VNSR","VNTP","ANYN","NIUE","NZAA","NZAR","NZCX","NZGB","NZKE","NZRO","NZTG","NZWK","NZAS","NZCH","NZGT","NZKI","NZTU","NZUK","NZCI","NZGS","NZNR","NZWO","NZOH","NZPM","NZWU","NZWB","NZPN","NZNS","NZDA","NZKT","NZKK","NZKO","NZWR","NZLX","NZDN","NZOU","NZWF","NZQN","NZNV","NZMF","NZMC","NZRC","NZMO","NZNP","NZTK","NZMK","NZHN","NZMA","NZRA","NZTO","NZTH","NZAP","NZWT","NZMS","NZPP","NZWN","NZGM","NZHK","NZWS","OOMS","OOGB","OOBR","OOFD","OOLK","OOSH","AYNO","OOKB","OORQ","OOMA","OOSR","FZSB","MDLR","OOMX","OOSA","OOTH","MPBO","MPCH","MPDA","MPSM","MPEJ","MPJE","MPLP","MPOA","MPCE","MPHO","MPWN","MPMG","MPTO","MPVR","MPSA","SPPY","SPLN","SPHZ","SPEO","SPHY","SPQU","SPHO","SPAY","SPJR","SPJE","SPNC","SPIL","SPIM","SPGM","SPZA","SPSO","SPJN","SPJJ","SPMF","SPRU","SPHI","SPMR","SPZO","SPQT","SPDR","SPMS","SPBR","SPTU","SPSY","SPLO","SPUR","SPYL","SPJL","SPBL","SPJI","SPBB","SPJA","SPOA","SPST","SPTN","SPME","SPAR","SPCL","NTAM","NTAR","NTAV","NTAT","NTMN","NTMD","NTMU","NTMP","NTTB","NTTH","NTTP","NTAA","NTTR","NTTE","NTGA","NTHE","NTGD","NTGU","NTKF","NTGF","NTGB","NTKH","NTGJ","NTGH","NTTO","NTKA","NTGK","NTKT","NTGM","NTGV","NTGN","NTKN","NTGW","NTGP","NTGQ","NTGE","NTTG","NTKK","NTKO","NTGC","NTKM","NTGT","NTGO","NTKR","NTTX","NTUV","NTGI","NTGY","NTTM","NTTU","AYBK","AYIA","AYIQ","AYEF","AYER","AYFA","AYGF","AYHH","AYKH","AYJO","AYKQ","AYRA","AYEA","AYOP","AYLS","AYMP","AYMA","AYQQ","AYRK","AYQO","AYTY","AYTI","AYWT","AYCH","AYRI","AYGL","AYMV","AYNI","AYTK","AYSH","AYZI","AYXO","AYVO","AYUI","AYWQ","AYWK","AYAN","AYAY","AYDI","AYGA","AYOK","AYLG","AYOL","AYMW","AYNY","AYTR","AYUC","AYWO","AYWD","AYAO","AYKM","AYKK","AYQA","AYSK","AYSS","AYBA","AYWB","AYJS","AYKR","AYMD","AYNA","AYSD","AYWH","AYMO","AYYM","AYAG","AYGN","AYKA","AYMS","AYAX","AYUM","AYBC","AYBG","AYBP","AYBR","AYBU","AYNS","AYDE","AYDN","AYEN","AYFI","AYGP","AYGI","AYGG","AYHE","AYHU","AYID","AYII","AYKB","AYNB","AYOE","AYKD","AYRO","AYNM","AYYR","AYYE","AYKT","AYLB","AYNZ","AYLT","AYLN","AYLP","AYLX","AYLO","AYSX","AYMJ","AYMI","AYMC","AYMB","AYOG","AYOM","AYPD","AYSP","AYXI","AYEW","AYSW","AYQS","AYTP","AYTZ","AYTS","AYTW","AYWS","AYWC","AYWU","AYXE","AYZA","AYAF","AYBD","AYDO","AYDR","AYEO","AYEB","AYGC","AYGX","AYNJ","AYNC","AYPQ","AYPY","AYYO","AYRE","AYSF","AYSG","AYCS","AYTF","AYUE","AYBZ","AYNX","AYEE","AYKV","AYKY","AYMZ","AYSE","AYWG","AYKO","AYGR","AYTU","AYPE","AYAT","AYBF","AYEV","AYHB","AYHO","AYHF","AYOQ","AYOW","AYNN","AYLI","AYOO","AYKG","AYDL","AYKU","AYKW","AYMN","AYPO","AYMQ","AYRM","AYMR","AYBM","AYPB","AYPJ","AYVM","AYTA","AYUR","AYWF","AYIW","AYBL","AYCG","AYGJ","AYGT","AYHK","AYKC","AYLL","AYSL","AYSV","AYTG","AYVL","AYUZ","AYWJ","AYIX","AYVN","AYND","AYBO","AYCB","AYNE","AYMH","AYKJ","AYAQ","AYDK","AYPG","AYSJ","AYTV","AYYL","AYAE","AYVW","AYYK","AYAK","AYGU","AYAA","AYAM","AYAI","AYAW","AYET","AYBQ","AYBH","AYBI","AYDU","AYDB","AYEL","AYFR","AYFE","AYFU","AYGS","AYUP","AYML","AYGV","AYIO","AYTO","AYIM","AYYP","AYUY","AYLU","AYEH","AYIY","ATNR","AYOB","AYOJ","AYOF","AYOV","AYZS","AYPC","AYRG","AYSO","AYSA","AYZN","AYSU","AYTB","AYTH","AYTE","AYTN","AYQL","AYTT","AYNU","AYKI","AYXW","AYXP","AYED","RPME","RPVK","RPVE","RPLP","RPVS","RPUR","RPLB","RPUO","RPUB","RPVT","RPLH","RPUT","RPUD","RPUN","RPMH","RPVR","RPUV","RPLS","RPVM","RPMQ","RPMD","RPLI","RPSG","RPVI","RPUY","RPUS","RPMI","RPVO","RPVA","RPMC","RPMM","RPUW","RPVJ","RPLU","RPUM","RPUH","RPMY","RPMO","RPLL","RPMA","RPVB","RPVD","RPVF","RPLO","RPEN","RPVP","RPSD","RPSV","RPVV","RPLC","RPLE","RPVU","RPVC","RPMR","RPMJ","RPNS","RPMS","RPMF","RPMW","RPMU","RPMN","RPMV","RPMG","PRNO","RPMP","RPMZ","OPMF","OPRT","OPMA","OPDB","OPGD","OPJI","OPKH","OPLL","OPOR","OPPG","OPPI","OPZB","OPSB","OPSU","OPTU","OPQT","OPCL","OPGT","OPSD","OPIS","OPBN","OPCH","OPDI","OPKT","OPPC","OPPS","OPSS","OPTA","OPWN","OPBW","OPDG","OPLA","OPFA","OPMT","OPMI","OPRK","OPSR","OPST","OPTH","OPDD","OPKD","OPJA","OPKC","OPMJ","OPMP","OPSW","OPSK","OPSN","OPNH","EPWR","EPBY","EPLL","EPBP","EPLB","EPZG","EPKK","EPRA","EPWA","EPMO","EPRZ","EPGD","EPRU","EPKT","EPSY","EPPO","EPKZ","EPSC","LFVP","LFVM","TJSJ","TJPS","TJIG","LVGZ","LPBJ","LPBR","LPBG","LPCO","LPFR","LPPM","LPCS","LPPT","LPSI","LPPR","LPMA","LPPS","LPCR","LPFL","LPGR","LPHR","LPPD","LPPI","LPSJ","LPAZ","LPLA","LPCH","LPVR","LPVZ","PTRO","SGOL","SGES","SGPJ","SGME","SGFI","SGAS","SGBN","SGCO","SGEN","SGAY","SGPI","OTBD","OTHH","OTBH","FMEE","FMEP","LRAR","LRBC","LROD","LRCS","LRCL","LRCK","LRCV","LRIA","LROP","LRBM","LRTM","LRSM","LRSB","LRSV","LRTR","LRTC","LYBE","LYBT","LYNI","LYUZ","UNBG","UNBB","UHBB","UHBI","UHBW","ULAA","ULAS","ULKK","ULAL","URWA","UWUB","UWUF","UWUK","UWUU","UUOB","UUBP","UECT","UIUU","URMG","USCC","USCM","UHMA","UHMK","UHMO","UHMD","UHMP","UWKS","URML","URMS","UIBB","UIKE","UIII","UUBI","UIKK","UIKB","UIBS","UITT","URMN","UMKK","URWI","UUBC","UHPP","ULPB","UNEE","UNWW","UHNB","UHKM","UHHH","UHKK","UHNN","UHOO","UNAA","USHQ","USHH","USHI","USRK","USHK","USRN","USNN","USHN","USHS","USNR","USRR","USHU","USKK","UUYI","UUYP","UUYY","UUYH","UUYS","UUYX","UUYW","UUBA","URKA","URSS","URKG","URKK","UNKS","UODD","UNII","UOHH","UOII","UNKL","UOOO","UNIP","UOTT","USUU","UUOK","ULSS","ULLI","UUOL","UHMM","UHMW","UWKJ","UWPS","UUBB","UUEE","UUMU","UUMO","UUBW","ULMK","ULMM","ULDD","ULAM","ULDW","ULNN","UWGG","UNNT","UNOO","UWOR","UWOO","UUOR","UWPP","USPP","UHTG","UHWP","UHWW","ULOO","ULOL","URRR","URRP","URRT","URRY","UUWR","UEEA","UESG","UESO","UESS","UEMM","UEST","UEMH","UERR","UEMA","UELL","UENN","UEMO","UERO","UERP","UESK","UEBS","UENS","UERS","UEBT","UERL","UEMU","UEMT","UENI","UENW","UEEE","UEVV","UESU","UHSB","UHSM","UHSK","UHSI","UHSN","UHSH","UHSS","UHSO","UWWW","UWSB","UWSS","URMO","UUBS","URMM","URMT","USSS","UUOT","UWKD","UWKE","UWKB","UNSS","UNTT","UUBT","UUEM","USTR","USTO","UNKY","USII","UWLL","UWLW","ULWC","ULWW","URWW","ULWU","UUOO","USDB","USDP","USRO","USMU","USMM","USDA","USDD","USDS","USDU","USDK","UUDL","UUBK","UIAA","HRYU","HRYG","HRZA","HRYI","HRYR","OEBA","OERR","OERF","OETR","OESK","OEGT","OEMA","OEAO","OEYN","OEGS","OEZL","OEPS","OEDW","OERK","OESL","OEWD","OEPA","OEDR","OEDF","OEAH","OEKK","OEAB","OEBH","OEKM","OEHL","OEGN","OEJN","OETF","OENG","OESH","OEWJ","OENN","OETB","AGTI","AGGY","AGGC","AGKG","AGGJ","AGGH","AGKW","AGGI","AGNA","AGGP","AGGF","AGJO","AGGV","AGGK","AGGT","AGAR","AGAF","AGGA","AGAT","AGGQ","AGGB","AGGR","AGGU","AGGL","AGGE","AGBT","AGGS","AGEV","AGOK","AGGN","AGKU","AGGO","AGGM","AGRM","AGRC","AGBA","FSSB","FSSD","FSDR","FSSF","FSPP","FSIA","HSFA","HSDZ","HSWD","HSKG","HSGF","HSKA","HSNW","HSSK","HSFS","HSDN","HSDB","HSMN","HSSW","HSPN","HSAT","HSGG","HSNN","HSOB","HSLI","HSNH","HSGN","HSZA","HSKI","ESDF","ESSD","ESUE","ESKM","ESSK","ESNH","ESNY","ESSV","ESMT","ESND","ESNZ","ESGJ","ESSF","ESMQ","ESMO","ESSW","ESMX","ESNX","ESNG","ESNQ","ESPA","ESUP","ESKK","ESOE","ESSL","ESSP","ESTA","ESMK","ESSU","ESSA","ESOH","ESOK","ESST","ESUT","ESNL","ESNS","ESUD","ESNU","ESNV","ESNK","ESNO","ESNN","ESGG","ESGP","ESGR","ESGL","ESGT","WSAP","WSSS","WSAT","WSSL","FHAW","FHSH","ENSB","LZLU","LZSL","LZIB","LJPZ","LZKZ","LJMB","LZPW","LZTT","LJLJ","LZPP","LZZI","GFKE","GFYE","GFKB","GFBN","GFGK","GFBO","GFLL","GFHA","GOOY","GOOK","GOTK","GODK","GOSM","GOSP","GOSR","GOSS","GOTB","GOTS","GOTT","GOBD","GOGS","GOGG","HCMM","HCMA","HCMF","HCMS","HCMC","HCMG","HCMB","HCMD","HCMJ","HCMK","HCMO","HCMR","HCME","HCMU","HCMV","HCMI","HCMH","SMCO","SMBN","SMMO","SMWA","SMNI","SMJP","SMZO","SMCA","SMDA","SMTP","SMDO","SMPA","SMST","SMWS","HJJJ","HSMK","HSSM","HSWW","FPPR","FPST","MSSS","MSLP","TNCM","OSKL","OSLK","OSDZ","OSDI","OSAP","OSPR","FDMS","FDSK","MBGT","MBMC","MBNC","MBPI","MBPV","MBSY","MBSC","FTTI","FTTY","FTTS","FTTM","FTTK","FTTJ","FTTU","FTTL","FTTD","FTTP","FTTB","FTTA","FTTC","FTTN","FTTH","DXNG","DXXX","VTUO","VTCC","VTCT","VTBF","VTSE","VTUK","VTSG","VTBS","VTBD","VTCL","VTUL","VTBL","VTCH","VTBK","VTUW","VTUQ","VTPI","VTSF","VTCN","VTSC","VTSK","VTPB","VTPP","VTCP","VTSP","VTPH","VTSR","VTBU","VTUV","VTUI","VTSS","VTSH","VTPO","VTSB","VTSM","VTUJ","VTPM","VTPT","VTST","VTBO","VTUU","VTUD","VTPU","UTDD","UTDT","UTDK","UTDL","WPAT","WPEC","WPDL","WPMN","WPOC","WPDB","WPVQ","UTAK","UTAA","UTAT","UTAV","UTAM","DTTG","DTTF","DTKA","DTTJ","DTMB","DTTX","DTNH","DTTR","DTTZ","DTTA","NFTL","NFTO","NFTP","NFTE","NFTF","NFTV","LTAF","LTAG","LTCP","LTAH","LTCO","LTAP","LTAD","LTAC","LTAI","LTFG","LTBD","LTBG","LTBF","LTFD","LTCJ","LTCU","LTBE","LTBR","LTBH","LTFK","LTAY","LTCC","LTCA","LTCD","LTCE","LTBY","LTBI","LTAJ","LTCW","LTDA","LTCT","LTFC","LTBA","LTFM","LTFJ","LTCN","LTCF","LTAL","LTAU","LTBQ","LTAN","LTBZ","LTAT","LTCR","LTFE","LTBV","LTBS","LTCK","LTAZ","LTCB","LTFO","LTFH","LTCS","LTCH","LTCL","LTCM","LTCV","LTAR","LTBU","LTAW","LTCG","LTBO","LTCI","LTAS","TTPP","TTCP","NGFU","RCKU","RCPO","RCYU","RCLM","RCKH","RCBS","RCFG","RCMT","RCCM","RCQC","RCWA","RCKW","RCDC","RCMQ","RCNN","RCSS","RCGI","RCLY","RCFN","RCTP","HTAR","HTLM","HTDA","HTDO","HTGE","HTIR","HTBU","HTKA","HTKJ","HTPE","HTKI","HTLI","HTNA","HTGR","HTMU","HTMB","HTZA","HTMT","HTMI","HTMW","HTNJ","HTMA","HTSU","HTSO","HTMD","HTSY","HTSN","HTTB","HTTG","UKFK","UKFF","UKKE","UKKL","UKLN","UKDD","UKDR","UKCC","UKCK","UKCM","UKLI","UKHH","UKOH","UKLH","UKKG","UKKK","UKBB","UKCW","UKLL","UKON","UKOO","UKHP","UKLR","UKFB","UKHS","UKLT","UKWW","UKLC","UKLU","UKDB","UKDE","UKKV","HUAR","HUGU","HUJI","HUKF","HUEN","HUKS","HUMI","HUMA","HUPA","HUSO","HUTO","PWAK","KAIV","KALX","KANB","KASN","KAUO","KBFM","KBHM","KDCU","KDHN","KEDN","KEUF","KGAD","KJKA","KHAB","KHSV","KHUA","KMGM","KMOB","KMSL","KMVC","KMXF","KNBJ","KOZR","KPLR","KSEM","KTCL","KTOI","PAFM","PADK","PADQ","KPHH","PFAL","PAGN","PAWI","PAAK","PFAK","PAKH","PAKN","PAKP","PANC","PANI","PANT","PANV","PARC","PATQ","PAAT","PABE","PAGQ","PABI","PABL","PABM","PABR","PABA","PABT","PABG","PACD","PACV","PACE","PACI","PFCL","PACX","PACK","PACY","PACZ","PADL","PADE","PADU","PAEG","PAED","PAEE","PAII","PAEH","PAEI","PFEL","PAEL","PAEM","PAEN","PANN","PAFA","PAFB","PANR","PAFR","PAFW","PFYU","PAGA","PAGM","PAGB","PAGK","PAGL","PAGZ","PAGS","PAHC","PAOH","PAHN","PAHO","PAHP","PAHL","PAHU","PAHY","PAIK","PAIG","PAKO","PAIL","PACR","PAJN","PAFE","PAKV","PAKD","PAKF","PAJZ","PAKK","PADY","PALG","PALB","PAKW","PAMB","PANW","PFKO","PAPC","PAKI","PAPE","PASM","PAKT","PFKT","PFKA","PAVC","PAVL","PAGG","PAQH","PFKW","PAKY","PFKU","PAKL","PAMH","PALN","PALU","PAMC","PAIN","PAMD","PADM","PAML","PAMO","PAMR","PAMM","PABK","PAMX","PAMY","PFCB","PAFS","PAOU","PAGT","PANO","PAQT","PANU","PAOB","PAOM","PAOO","KORI","PAOR","PFNO","PAOT","PAAQ","PAOC","PAPO","PAPN","PPIZ","PAPK","PAAL","PAPR","PAPG","PALJ","PAAP","PAPH","PAPM","PARY","PADG","PARS","PASC","PACM","PASD","PAGY","PAGH","PASH","PAHX","PASI","PFSH","PASW","PASL","PAMK","PASP","PASN","PASO","PAPB","PASA","PASV","PAWD","PASX","PASY","PATA","PATK","PFTO","PATE","PATL","PATC","PATG","PAST","PAUM","PAUN","PAIM","PAKU","PAVA","PAVD","PAVE","PAIW","PAWB","PALR","PASK","PAWM","PANA","PAUO","PAWG","PACS","PFWS","PAWN","PAWS","PAEW","PAYA","KAVQ","KIWA","KBXK","KCFT","KCGZ","KDGL","KDMA","KDUG","KDVT","KFHU","KFLG","KGCN","KGYR","KHII","KIFP","KIGM","KINW","KLGF","KLUF","KFFZ","KMZJ","KOLS","KPGA","KPHX","KPAN","KPRC","KSAD","KSDL","KSEZ","KSJN","KSOW","KTUS","KTYL","KNYL","KAGO","KARG","KAWM","KBVX","KBYH","KCDH","KCVK","KCRT","KELD","KFCY","KFLP","KFSM","KFYV","KHEE","KHKA","KHOT","KHRO","KJBR","KLIT","KLRF","KMPJ","KMXA","KPBF","KPGR","KROG","KSGT","KSLG","KASG","KSRC","KTXK","KBPK","KXNA","KACV","KAHC","KAPC","KAPV","KAUN","KAVX","KBAB","KBFL","KBIH","KBLH","KBLU","KBNG","KBUR","KBWC","KBYS","KCCB","KCCR","KCEC","KCIC","KCRQ","KCLR","KCNO","KCPM","KCRO","KCXL","KDAG","KEDW","KEED","KEKA","KEMT","KFAT","KFCH","KFUL","KHAF","KHHR","KCVH","KHMT","KHWD","KIPL","KIYK","KKIC","KLAX","KLGB","KLPC","KLSN","KLVK","KMAE","KMCC","KMCE","KMER","KMHR","KMHV","KMIT","KMMH","KMOD","KMRY","KMYF","KMYV","KNJK","KNKX","KNLC","KDVO","KNRC","KNRS","KNTD","KNUQ","KNZY","KOAK","KOAR","KOKB","KONT","KOVE","KOXR","KPAO","KPMD","KPOC","KPRB","KPSP","KPTV","KPVF","KRAL","KRBL","KRDD","KRHV","KRIR","KRIV","KMPI","KSAC","KSAN","KSAS","KSBA","KSBD","KSBP","KSCK","KSDM","KSEE","KSFO","KSIY","KSJC","KSMF","KSMO","KSMX","KSNA","KSNS","KSPA","KIZA","KSQL","KSTS","KSMS","KSUU","KSVE","KSZN","KSZP","KTRK","KTLR","KTNP","KTOA","KTRM","KTSP","KTVL","KUDD","KUKI","KVBG","KVCV","KVIS","KVNY","KWHP","KWJF","KWLW","KWVI","KAFF","KAKO","KALS","KAPA","KASE","KBKF","KBJC","KCEZ","KCAG","KCOS","KDEN","KDRO","KEGE","KFCS","KFNL","KGJT","KGUC","KGWS","KGXY","KHDN","KLAA","KLIC","KLXV","KMTJ","KPSO","KPUB","KRIL","KSBS","KANK","KSTK","KTAD","KTEX","KBDU","KBDL","KBDR","KDXR","KGON","KHFD","KHVN","KOXC","KDOV","KGED","KILG","KAAF","KAPF","KAVO","KBCT","KBOW","KCDK","KCEW","KCLW","KCOF","KCOI","KCRG","KCTY","KDAB","KDTS","KECP","KEGI","KEYW","KFLL","KFMY","KFPR","KFXE","KGIF","KGNV","KHST","KHWO","KIMM","KISM","KJAX","KLAL","KLCQ","KLEE","KLNA","KMCF","KMCO","KMIA","KMLB","KMKY","KMTH","KNEN","KNIP","KNPA","KNQX","KNRB","KNSE","KNUN","KOBE","KOCF","KOPF","KORL","KPAM","KPBI","KPGD","KPHK","KPIE","KPNS","KPMP","KRSW","KSEF","KSFB","KSPG","KSRQ","KSUA","KTIX","KTLH","KTMB","KTNT","KTPA","KTPF","KSGJ","KVNC","KVPS","KVQQ","KVRB","KZPH","KABY","KAGS","KAHN","KATL","KAYS","KBGE","KBQK","KCSG","KDBN","KDNL","KDNN","KFTY","KGVL","KLGC","KLHW","KLSF","KLZU","KMAC","KMCN","KMGE","KMGR","KMLJ","KMQW","KMUL","KPDK","KPIM","KRMG","KSAV","KSSI","KSVN","KSYV","KTBR","KTMA","KTOC","KTVI","KVAD","KVDI","KVLD","KWDR","KWRB","PHBK","PHSF","NSFQ","PHDH","PHHI","PHNL","PHHN","PHTO","PHJH","PHJR","PHKO","PHLI","PHNY","PHLU","PMDY","PHMK","PHMU","PHNG","PHOG","PHPA","PHUP","KBOI","KBYI","KLLJ","KCOE","KGNG","KIDA","KGIC","KLWS","KMLD","KMUO","KMYL","KPIH","KRXE","KSMN","KSUN","KTWF","KALN","KARR","KBLV","KBMI","KCIR","KCMI","KCPS","KDEC","KDNV","KDPA","KDVN","KENL","KEOK","KFEP","KGBG","KGRE","KHSB","KIJX","KIKK","KJOT","KLOT","KLWV","KMDH","KMDW","KMLI","KMQB","KMTO","KMVN","KMWA","KOLY","KORD","KPIA","KRFD","KSAR","KSLO","KSPI","KSQI","KUGN","KUIN","KVLA","KVYS","KAID","KANQ","KBFR","KBMG","KCEV","KBAK","KEKM","KEVV","KFRH","KFWA","VOGB","KGFD","KGSH","KGUS","KHLB","KHNB","KIND","KLAF","KPPO","KIMS","KMGC","KMIE","KMZZ","KOKK","KRCR","KRID","KRZL","KSBN","KSER","KSIV","KSMD","KVPZ","KAIO","KALO","KAMW","KAXA","KBNW","KBRL","KCBF","KCCY","KCID","KCIN","KCSQ","KCWI","KDBQ","KDEH","KDNS","KDSM","KEBS","KEFW","KEST","KFFL","KFSW","KFOD","KFXY","KHPT","KICL","KIDG","KIFA","KIOW","KLRJ","KMCW","KMIW","KMPZ","KMUT","KMXO","KOMA","KOOA","KOTM","KPOH","KPRO","KSLB","KSPW","KSUX","KTNU","KANY","KBEC","KCBK","KCEA","KCFV","KCNK","KCNU","KDDC","KEQA","KEMP","KEWK","KFLV","KFOE","KFRI","KFSK","KGBD","KGCK","KGLD","KHLC","KHUT","KHYS","KIAB","KICT","KIDP","KIXD","KLBL","KLWC","KLYO","KMHK","KMPR","KOJC","KPPF","KPTS","KPTT","KRSL","KSLN","KTOP","KWLD","KBRY","KBWG","KCEY","KCVG","KEKX","KFFT","KFTK","KGLW","KHOP","KLEX","KLOU","KLOZ","KOWB","KPAH","KPBX","KSDF","KSME","KAEX","KARA","KBAD","KBTR","KBXA","KCWF","KDRI","KDTN","KESF","KHUM","KLCH","KLFT","KMLU","KMSY","KNBG","KNEW","KOPL","KPOE","KPTN","KRSN","KSHV","KAUG","KBGR","KBHB","KCAR","KIZG","KHUL","KIWI","KLEW","KMLT","KBXM","KOLD","KOWK","KPNN","KPQI","KPWM","KRKD","KSFM","KFVE","KWVL","KADW","KANP","KAPG","KBWI","KCBE","KCGE","KCGS","KESN","KFDK","KFME","KGAI","KHGR","KMTN","KNHK","KOXB","KSBY","KACK","TJAB","KBAF","KBED","KBOS","TJBQ","KBVY","TJCP","KEWB","TJFA","KFMH","KGBR","KGDM","KHYA","KLWM","TJMZ","KMVY","TJRV","KORH","KOWD","KPSF","KPVC","KPYM","TJVQ","KACB","KADG","KAMN","KAPN","KARB","KAZO","KBEH","KBTL","KCAD","KCIU","KCMX","KDRM","KDTW","KESC","KFNT","KGDW","KGLR","KGRR","KHAI","KHLM","KHTL","KIMT","KIRS","KISQ","KIWD","KJXN","KLAN","KLDM","KMBL","KMBS","KMCD","KMKG","KMNM","KMOP","KSAW","KMTC","KOSC","KPHN","KPLN","KPTK","KRCT","KTVC","KCFS","KRQB","KAEL","KAUM","KAXN","KBBB","KBDE","KBJI","KBRD","KCKN","KDLH","KDTL","KEVM","KFBL","KFCM","KFFM","KFRM","KGPZ","KCKC","KHIB","KBDH","KINL","KELO","KMIC","KMJQ","KMKT","KMML","KMOX","KMSP","KMVE","KMWM","KDVP","KONA","KOTG","KOWA","KPKD","KROX","KRRT","KRST","KRWF","KSTC","KSTP","KSYN","KTVF","KULM","KBIX","KCBM","KCKM","KCRX","KMBO","KGLH","KGPT","KGTR","KGWO","KHBG","KHEZ","KHKS","KJAN","KLMS","KLUL","KMCB","KMEI","KMMS","KOLV","KOSX","KPQL","KPIB","KTUP","KUBS","KUOX","KUTA","KVKS","KAIZ","KBBG","KBUM","KCGI","KCOU","KDMO","KEOS","KFAM","KIRK","KJEF","KJLN","PFKK","KTKX","KMAW","KMBY","KMCI","KMHL","KMKC","KNVD","KPLK","KPOF","KSGF","KSIK","KSTJ","KSTL","KSUS","KSZL","KTBN","KTRX","KVIH","KBIL","KBTM","KBZN","KCTB","KDLN","KGPI","KGDV","KGGW","KGTF","KHLN","KHVR","KJDN","KLVM","KLWT","KMLS","KMSO","KOLF","KPWD","KRPX","KSBX","KSDY","KTHM","KWYS","KAIA","KANW","KBBW","KBFF","KBIE","KBUB","KCDR","KEAR","KFBY","KFET","KGRI","KGRN","KHDE","KHSI","KIML","KLBF","KLNK","KLXN","KMCK","KMHN","KMLE","KOFF","KOFK","KOGA","KOKS","KOLU","KONL","KSCB","KSNY","KVTN","KBAM","KBTY","KCXP","KDRA","KEKO","KELY","KFLX","KGAB","KHND","KHTH","KINS","KLAS","KLOL","KLSV","KLWL","KMEV","KNFL","KRNO","KTPH","KUCC","KVGT","KWMC","KTNX","KAFN","KASH","KBML","KCNH","KCON","KEEN","KERR","KHIE","KLCI","KLEB","KMHT","KPSM","KACY","KBLM","KCDW","KEWR","KLDJ","KVAY","KMIV","KMJX","KMMU","KNEL","KTEB","KTTN","KWRI","KWWD","KABQ","KALM","KATS","KAXX","KCAO","KCNM","KCVN","KCVS","KDMN","KFMN","KFSU","KGNT","KGUP","KHMN","KHOB","KLAM","KLRU","KLSB","KLVS","KONM","KROW","KRTN","KSRR","KSAF","KSVC","KTCC","KTCS","KSKX","KWSD","KALB","KART","KBGM","KBUF","KDKK","KDSV","KELM","KELZ","KFOK","KFRG","KGFL","KHPN","KHTO","KIAG","KISP","KITH","KJFK","KJHW","KLGA","KLKP","KMGJ","KMSS","KMSV","KMTP","KOGS","KOIC","KOLE","KPBG","KPOU","KRME","KROC","KSCH","KSLK","KSWF","KSYR","KHWV","KAVL","KCLT","KCTZ","KECG","KEDE","KEWN","KFAY","KFBG","KFFA","KGSB","KGSO","KHFF","KHKY","KHSE","KUKF","KILM","KINT","KISO","KLBT","KLHZ","KMQI","KMRN","KMEB","KOAJ","KOCW","KPGV","KPOB","KRDU","KRWI","KRZZ","KSOP","KRUQ","KSVH","KJQF","KASY","KBIS","KBPP","KDIK","KDVL","KFAR","KGFK","KISN","KJMS","KMIB","KMOT","KPMB","KRDR","KBWP","KXWA","KAKR","KAOH","KUNI","KAXV","KBJJ","KBKL","KCAK","KCGF","KCLE","KCMH","KDAY","KDFI","KFDY","KFFO","KGQQ","KHAO","KHTW","KILN","KHZY","KLCK","KLNN","KLUK","KMFD","KMGY","KMNN","KMWO","KOSU","KOXD","KPHD","KPMH","KSGH","KSKY","KTDZ","KTOL","KYNG","KZZV","KADM","KADH","KAXS","KBVO","KBKN","KCHK","KCKA","KCLK","KCSM","KCUH","KDUA","KDUC","KELK","KEND","KFDR","KFSI","KGAG","KGOK","KGUY","KHBR","KHHW","KLAW","KLTS","KMIO","KMKO","KMLC","KOKC","KOKM","KOUN","KPNC","KPWA","KRKR","KRVS","KSNL","KSUD","KSWO","KTIK","KTUL","KWDG","KWWR","KAST","KBKE","KBNO","KBOK","KCVO","KCZK","KDLS","KEUG","KHRI","KHIO","KGCD","KLGD","KLKV","KLMT","KMFR","KONO","KONP","KOTH","KTMK","KPDT","KPDX","KPFC","KRBG","KRDM","KREO","KSLE","KTTD","KABE","KAGC","KAOO","KAVP","KLOM","KBFD","KBVI","KBTP","KMQS","KDUJ","KDYL","KERI","KFKL","KCXY","KHZL","KIDI","KIPT","KJST","KLBE","KLHV","KLNS","KMDT","KGKJ","KMPO","KMUI","KPHL","KPIT","KPNE","KPSB","KPTW","KRDG","KRVL","KUNV","KSEG","KOYM","KTHV","KUKT","KWAY","KWBW","KAFJ","KBID","KOQU","KUUU","KPVD","KSFZ","KWST","KAIK","KAND","KARW","KBNL","KBBP","KCAE","KCDN","KCEU","KCHS","KCRE","KCUB","KDLC","KFLO","KGYH","KGGE","KGMU","KGRD","KGSP","KCQW","KCQX","KHXD","KHVS","KMMT","KMYR","KOGB","KRBW","KUZA","KSSC","KABR","KATY","KBKX","KFSD","KHON","KLEM","KLQK","KMBG","KMHE","KPHP","KPIR","KRAP","KRCA","KSPF","KBTN","KMDS","KIEN","KYKN","KAPT","KBNA","KCHA","KCKV","KCSV","KFYM","KGCY","KGHM","KGKT","KMEM","KMKL","KMMI","KMOR","KMQY","KMRC","KNQA","KPHT","KRKW","KRNC","KSYI","KTHA","KTRI","KTYS","KUCY","KUOS","KABI","KACT","KADS","KAFW","KALI","KAMA","KASL","KAUS","KBYY","KBBD","KBGD","KBIF","KBKD","KBMT","KBPT","KBRO","KBWD","KCDS","KCFD","KCLL","KCNW","KCOM","KCOT","KCRP","KCRS","KCXO","KCZT","KDAL","KDFW","KDHT","KDLF","KDRT","KDWH","KDYS","KEFD","KELA","KELP","KERV","KETN","KFST","KFTW","KNFW","KGGG","KGLE","KGLS","KGRK","KGVT","KBPG","KHLR","KHOU","KHPY","KHRL","KUTS","KIAH","KILE","KINK","KIWS","KJAS","KJCT","KJSO","KCWC","KLBB","KLFK","KLBX","KLRD","KMAF","KMDD","KMFE","KOSA","KMRF","KMWL","KNGP","KNGW","KNQI","KOCH","KONY","KOZA","KPEQ","KGYI","KPPA","KPRX","KPSN","KPSX","KPVW","KRBD","KRCK","KRFG","KRKP","KRND","KSAT","KSEP","KSGR","KSJT","KSKF","KSLR","KSNK","KSPS","KSSF","KSWW","KTDW","KTPL","KTRL","KTYR","KUVA","KVCT","KVHN","KWEA","KARM","KBCE","KBDG","KBMC","KBTF","KCDC","KCNY","KDPG","KDTA","KENV","KFOM","KHIF","KHVE","KKNB","KLGU","KMLF","KOGD","KPUC","KPVU","KRIF","KSGU","KSLC","KVEL","KBTV","KEFK","KCDA","KMPV","KMVL","KRUT","KVSF","KAPH","KBCB","KBKT","KCHO","KDAA","KDAN","KDCA","KNDY","KFAF","KFKN","KFRR","KGVE","KHSP","KIAD","KLFI","KLNP","KLKU","KLVL","KLYH","KMFV","KHEF","KNGU","KNTU","KNYG","KORF","KPHF","KPSK","KPTB","KRIC","KROA","KSHD","KVJI","KWAL","KOKV","KALW","KBFI","KBLI","KCLM","KCLS","KEAT","KELN","KEPH","KORS","KESW","KFHR","KGEG","KGRF","KHQM","KKLS","KBVS","KMWH","KNUW","KOKH","KOLM","KOMK","KPAE","KPSC","KPUW","KPWT","KRLD","KRNT","KSEA","KSFF","KSHN","KSKA","KTCM","KTDO","KTIW","KUIL","KYKM","KBKW","KBLF","KCKB","KCRW","KEKN","KHLG","KHTS","KLWB","KMGW","KMRB","KPKB","KAHH","KARV","KASX","KATW","KAUW","KCLI","KCMY","KCWA","KEAU","KEGV","KENW","KETB","KFLD","KGRB","KGTG","KHYR","KISW","KJVL","KLNR","KLSE","KMDZ","KMFI","KMKE","KMSN","KMTW","KMWC","KOEO","KOSH","KPDC","KPKF","KRAC","KRHI","KRPD","KRNH","KRRL","KSBM","KSTE","KSUE","KSUW","KUES","KUNU","KVOK","KAFO","KBPI","KBYG","KCOD","KCPR","KCYS","KDGW","KEAN","KECS","KEMM","KEVW","KFBR","KGCC","KGEY","KJAC","KLAR","KLND","KLSK","KPOY","KPNA","KRIW","KRKS","KRWL","KSAA","KSHR","KTHP","KTOR","KWRL","SUAG","SUBU","SUMO","SUCA","SUDU","SULS","SUMU","SUPU","SURV","SUVO","SUSO","SUTB","SUTR","UTTT","UTKA","UTSN","UTSB","UTKF","UTFN","UTSA","UTSK","UTNN","UTSS","UTST","UTNU","TVSB","TVSC","TVSM","TVSU","TVSA","SVPA","SVAN","SVBC","SVST","SVEZ","SVGD","SVPT","SVSR","SVBI","SVSB","SVCN","SVCB","SVCD","SVED","SVIC","SVIE","SVKA","SVKM","SVPR","SVSE","SVTM","SVUM","SVBS","SVPC","SVVA","SVPE","SVTC","SVCR","SVJC","SVCL","SVVP","SVBM","SVCO","SVMD","SVVG","SVRS","SVMT","SVMG","SVAC","SVGU","SVCU","SVCP","SVGI","SVLF","SVPM","SVSO","SVSA","SVVL","SVMI","SVSP","SVON","SVCG","SVMC","SVSZ","TUPJ","TUPA","TUPW","TIST","TISX","VVCS","VVVT","VVPC","VVCM","VVCT","VVDN","VVBM","VVDB","VVPK","VVNB","VVCI","VVTS","VVCR","VVNT","VVPQ","VVRG","VVDL","VVVH","VVPR","VVTH","VVDH","VVCA","VVVD","VVNS","VVTX","VVPB","NVSF","NVSL","NVSP","NVSI","NVSX","NVSU","NVSO","NVSG","NVSN","NVSR","NVSH","NVSW","NVSZ","NVSS","NVSE","NVSM","NVST","NVVQ","NVVV","NVSV","NVVA","NVVB","NVVD","NVVF","NVVI","NVVW","NVSA","NVSC","NVSD","NVSQ","NLWF","NLWW","NSMA","NSAU","NSFA","NSFI","OYMS","ODAL","OYAA","OYBI","OYHD","OYKM","OYGD","OYQN","OYSY","OYRN","OYSQ","ODAS","OYMB","OYSH","OYSN","OYAT","OYBN","OYTZ","FMCZ","FAPA","FABE","FACD","FAEL","FAPJ","FAMW","FAPE","FAUT","FAQT","FABL","FAFB","FAHR","FATN","FAWM","FAGC","FALA","FAOR","FAWB","FAGM","FAWK","FADK","FALE","FAEM","FAHL","FALY","FAMG","FAMU","FANC","FAPM","FADQ","FARB","FAUL","FAVG","FAVY","FAAL","FAER","FAGI","FAHS","FALO","FALD","FATZ","FAMS","FAPH","FAPP","FATH","FAUS","FAMD","FAHW","FAKP","FAMN","FAKN","FANG","FANS","FASZ","FASC","FAKD","FAMM","FAPN","FAPS","FARI","FAVB","FAAG","FAAB","FAKM","FAKZ","FAKU","FALC","FAPK","FASB","FASS","FAUP","FACT","FAGG","FAMO","FAOH","FAOB","FAPG","FARS","FALW","FAVR","FLSO","FLND","FLCP","FLMF","FLMA","FLLS","FLZB","FLSW","FLKS","FLBA","FLKY","FLLI","FLNA","FLKL","FLKO","FLLK","FLMG","FLSS","FLSN","FVBU","FVHA","FVCH","FVMU","FVKB","FVCZ","FVMH","FVMV","FVWN","FVFA","FVWT","FVTL"] + "icaoIds": [], + "datisICAOs": [] } \ No newline at end of file diff --git a/dot-commands/datis.js b/dot-commands/datis.js new file mode 100644 index 0000000..c494761 --- /dev/null +++ b/dot-commands/datis.js @@ -0,0 +1,24 @@ +const fn = require('../functions'); + +module.exports = { + name: 'datis', + description: 'Lookup dATIS for an airport', + usage: 'ICAO.datis', + alias: [ 'atis' ], + async execute(message, commandData) { + try { + const icaoId = commandData.args; + if (icaoId.length !== 4) throw new Error('Not enough or too many ICAO IDs!') + const datisData = await fn.avWx.datis.getData(icaoId); + const messagePayload = fn.avWx.datis.parseData(datisData[0]); + message.reply(messagePayload); + } catch (e) { + try { + message.reply(`Something went wrong while retrieving the METAR: ${e.name}\n\n${e.message}`); + console.error(e); + } catch (e) { + console.error(e); + } + } + } +} \ No newline at end of file diff --git a/functions.js b/functions.js index a4e673f..8e2666a 100644 --- a/functions.js +++ b/functions.js @@ -14,6 +14,7 @@ const ownerId = process.env.ownerId; // filesystem const fs = require('fs'); +const zlib = require('zlib'); // Discord.js const Discord = require('discord.js'); @@ -25,6 +26,9 @@ const FuzzySearch = require('fuzzy-search'); // const OpenAI = require("openai"); // const openai = new OpenAI(); +// Axios for APIs +const axios = require('axios'); + // Various imports from other files const config = require('./config.json'); const strings = require('./strings.json'); @@ -34,7 +38,6 @@ const dotCommandFiles = fs.readdirSync('./dot-commands/').filter(file => file.en // MySQL database connection const mysql = require('mysql'); const { GifData, PastaData } = require('./CustomModules/NodBot'); -const axios = require('axios'); const db = new mysql.createPool({ connectionLimit: 10, host: dbHost, @@ -401,18 +404,32 @@ const functions = { }); const embed = new Discord.MessageEmbed() .setAuthor({ name: `${metarData.name} [${metarData.icaoId}] METAR`, iconURL: "https://aviationweather.gov/img/icons/awc-logo-180.png"}) - .setImage("https://media.discordapp.net/stickers/1175134632845516821.webp") + // .setImage("https://media.discordapp.net/stickers/1175134632845516821.webp") .setDescription(`**Not for real world use!**\n\n${metarData.rawOb}`) .setFooter({ text: "METAR by AviationWeather.gov for CumbHub LLC" }) .addFields( { name: 'Observation Time', value: `${metarData.reportTime}Z` }, { name: 'Temperature', value: `${metarData.temp}ºC/${metarData.dewp}ºC`}, - { name: 'Winds', value: `${metarData.wdir}º@${metarData.wspd}${wgst} kts`}, + { name: 'Winds', value: `${metarData.wdir.toString().padStart(3, '0')}º@${metarData.wspd}${wgst} kts`}, { name: 'Visibility', value: `${metarData.visib} SM` }, { name: 'Clouds', value: clouds.join('\n') }, { name: 'Altimeter', value: `${altim} inHg` } ) return { embeds: [embed] }; + }, + datis(datisData) { + const messageEmbed = new Discord.MessageEmbed() + .setAuthor({ name: `${datisData.airport} Digital ATIS` }) + // .setImage('https://media.discordapp.net/stickers/1175134632845516821.webp') + .setDescription(`**Do not use for real world flight planning or navigation.**\n\n${datisData.datis}`) + .addFields( + { name: 'Information', value: `${datisData.code}` }, + { name: 'Retreival Time', value: `${new Date().toISOString()}` } + ) + .setFooter({ text: 'D-ATIS by Clowd.io for CumbHub LLC' }) + + const messagePayload = { embeds: [ messageEmbed ] }; + return messagePayload; } } }, @@ -760,13 +777,42 @@ const functions = { }, metar: { async getAllICAOs() { - const reqUrl = `https://aviationweather.gov/api/data/metar?format=json` - const response = await axios.get(reqUrl); - let icaoArray = []; - response.data.forEach(e => { - icaoArray.push(e.icaoId) - }); - return icaoArray; + const reqUrl = `https://aviationweather.gov/data/cache/stations.cache.json.gz` + try { + // Step 1: Download the GZipped file + const response = await axios({ + url: reqUrl, + method: 'GET', + responseType: 'arraybuffer', // Ensure we get the raw binary data + headers: { + 'Accept-Encoding': 'gzip' // Ensure the server sends gzipped content + } + }); + + // Step 2: Decompress the GZipped content + const buffer = Buffer.from(response.data); + zlib.gunzip(buffer, (err, decompressedBuffer) => { + if (err) { + console.error('An error occurred during decompression:', err); + return; + } + + // Step 3: Parse the decompressed JSON + const jsonString = decompressedBuffer.toString('utf-8'); + try { + const jsonData = JSON.parse(jsonString); + // console.log('Parsed JSON data:', jsonData); + jsonData.forEach(airport => { + config.icaoIds.push(airport.icaoId); + }); + // console.log(`ICAO IDs: ${config.icaoIds.length}\n\n${config.icaoIds}`) + } catch (jsonError) { + console.error('An error occurred while parsing JSON:', jsonError); + } + }); + } catch (error) { + console.error('An error occurred during the HTTP request:', error); + } }, async getData(icaoList) { const reqUrl = `https://aviationweather.gov/api/data/metar?ids=${icaoList}&format=json`; @@ -780,6 +826,27 @@ const functions = { }) return messages; } + }, + datis: { + async getAllICAOs() { + const reqUrl = 'https://datis.clowd.io/api/stations'; + const response = await axios.get(reqUrl); + response.forEach(icaoId => { + config.datisICAOs.push(icaoId); + }); + }, + validate(icaoId) { + return config.datisICAOs.includes(icaoId); + }, + async getData(icaoId) { + const reqUrl = `https://datis.clowd.io/api/${icaoId}`; + const response = await axios.get(reqUrl); + if (response.error !== undefined) throw new Error('The D-ATIS API returned an error:\n' + response.error); + return response.data; + }, + parseData(datisData) { + return functions.embeds.avWx.datis(datisData); + } } }, generateErrorId() { diff --git a/main.js b/main.js index 23c68b7..7902b9e 100644 --- a/main.js +++ b/main.js @@ -42,7 +42,7 @@ client.once('ready', async () => { await fn.download.strains(client); await fn.download.medicalAdvice(client); console.log('Ready!'); - // const icaoArray = await fn.avWx.metar.getAllICAOs(); + await fn.avWx.metar.getAllICAOs(); // console.log(JSON.stringify(icaoArray)); client.channels.fetch(statusChannelId).then(channel => { channel.send(`${new Date().toISOString()} -- <@${process.env.ownerId}>\nStartup Sequence Complete`); From b11d14b72d6085ef7daddb58dfa5c401185aa612 Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Sat, 22 Jun 2024 09:42:02 -0400 Subject: [PATCH 45/79] Add and tweak D-ATIS --- dot-commands/datis.js | 16 ++++++++++------ dot-commands/metar.js | 2 +- functions.js | 2 +- main.js | 1 + package.json | 2 +- 5 files changed, 14 insertions(+), 9 deletions(-) diff --git a/dot-commands/datis.js b/dot-commands/datis.js index c494761..478f44c 100644 --- a/dot-commands/datis.js +++ b/dot-commands/datis.js @@ -7,14 +7,18 @@ module.exports = { alias: [ 'atis' ], async execute(message, commandData) { try { - const icaoId = commandData.args; - if (icaoId.length !== 4) throw new Error('Not enough or too many ICAO IDs!') - const datisData = await fn.avWx.datis.getData(icaoId); - const messagePayload = fn.avWx.datis.parseData(datisData[0]); - message.reply(messagePayload); + const icaoId = commandData.args.toUpperCase(); + if (icaoId.length !== 4) throw new Error('Invalid ICAO ID. Provide only one ICAO code at a time like KBOS'); + if (fn.avWx.datis.validate(icaoId)) { + const datisData = await fn.avWx.datis.getData(icaoId); + const messagePayload = fn.avWx.datis.parseData(datisData[0]); + message.reply(messagePayload); + } else { + message.reply("No D-ATIS available for the specified ICAO ID."); + } } catch (e) { try { - message.reply(`Something went wrong while retrieving the METAR: ${e.name}\n\n${e.message}`); + message.reply(`D-ATIS Error: ${e.message}`); console.error(e); } catch (e) { console.error(e); diff --git a/dot-commands/metar.js b/dot-commands/metar.js index 2da15b5..33207e9 100644 --- a/dot-commands/metar.js +++ b/dot-commands/metar.js @@ -16,7 +16,7 @@ module.exports = { }); } catch (e) { try { - message.reply(`Something went wrong while retrieving the METAR: ${e.name}\n\n${e.message}`); + message.reply(`METAR Error: ${e.message}`); console.error(e); } catch (e) { console.error(e); diff --git a/functions.js b/functions.js index 8e2666a..47f69dc 100644 --- a/functions.js +++ b/functions.js @@ -831,7 +831,7 @@ const functions = { async getAllICAOs() { const reqUrl = 'https://datis.clowd.io/api/stations'; const response = await axios.get(reqUrl); - response.forEach(icaoId => { + response.data.forEach(icaoId => { config.datisICAOs.push(icaoId); }); }, diff --git a/main.js b/main.js index 7902b9e..55a347c 100644 --- a/main.js +++ b/main.js @@ -43,6 +43,7 @@ client.once('ready', async () => { await fn.download.medicalAdvice(client); console.log('Ready!'); await fn.avWx.metar.getAllICAOs(); + await fn.avWx.datis.getAllICAOs(); // console.log(JSON.stringify(icaoArray)); client.channels.fetch(statusChannelId).then(channel => { channel.send(`${new Date().toISOString()} -- <@${process.env.ownerId}>\nStartup Sequence Complete`); diff --git a/package.json b/package.json index 92c9503..566a3e0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "nodbot", - "version": "3.3.0", + "version": "3.3.1", "description": "Nods and Nod Accessories, now with ChatGPT!", "main": "main.js", "dependencies": { From 550eb79374e7af0833d065d668f4122203f324bd Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Sat, 22 Jun 2024 10:08:28 -0400 Subject: [PATCH 46/79] Fix split ATISes --- dot-commands/datis.js | 2 +- functions.js | 26 ++++++++++++++++++++------ 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/dot-commands/datis.js b/dot-commands/datis.js index 478f44c..e6948f7 100644 --- a/dot-commands/datis.js +++ b/dot-commands/datis.js @@ -11,7 +11,7 @@ module.exports = { if (icaoId.length !== 4) throw new Error('Invalid ICAO ID. Provide only one ICAO code at a time like KBOS'); if (fn.avWx.datis.validate(icaoId)) { const datisData = await fn.avWx.datis.getData(icaoId); - const messagePayload = fn.avWx.datis.parseData(datisData[0]); + const messagePayload = fn.avWx.datis.parseData(datisData); message.reply(messagePayload); } else { message.reply("No D-ATIS available for the specified ICAO ID."); diff --git a/functions.js b/functions.js index 47f69dc..ff26fb9 100644 --- a/functions.js +++ b/functions.js @@ -419,15 +419,29 @@ const functions = { }, datis(datisData) { const messageEmbed = new Discord.MessageEmbed() - .setAuthor({ name: `${datisData.airport} Digital ATIS` }) + .setAuthor({ name: `${datisData[0].airport} Digital ATIS` }) // .setImage('https://media.discordapp.net/stickers/1175134632845516821.webp') - .setDescription(`**Do not use for real world flight planning or navigation.**\n\n${datisData.datis}`) - .addFields( - { name: 'Information', value: `${datisData.code}` }, - { name: 'Retreival Time', value: `${new Date().toISOString()}` } - ) + .setDescription(`**Do not use for real world flight planning or navigation.**`) .setFooter({ text: 'D-ATIS by Clowd.io for CumbHub LLC' }) + + if (datisData.length > 1) { + datisData.forEach(data => { + if (data.type === 'dep') messageEmbed.addFields({ name: 'Departure Digital ATIS', value: data.datis, inline: false }); + if (data.type === 'arr') messageEmbed.addFields({ name: 'Arrival Digital ATIS', value: data.datis, inline: false }); + messageEmbed.addFields({ name: 'Information', value: data.code, inline: true }); + }) + messageEmbed.addFields( + { name: 'Retreival Time', value: `${new Date().toISOString()}` } + ); + } else { + messageEmbed.addFields( + { name: 'Digital ATIS', value: datisData[0].datis, inline: false }, + { name: 'Information', value: `${datisData[0].code}`, inline: true }, + { name: 'Retreival Time', value: `${new Date().toISOString()}`, inline: true } + ) + } + const messagePayload = { embeds: [ messageEmbed ] }; return messagePayload; } From 4c20d084719f3b48fc33e34a11c39bb233939026 Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Sat, 22 Jun 2024 10:10:05 -0400 Subject: [PATCH 47/79] Adjust embed appearance --- functions.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/functions.js b/functions.js index ff26fb9..db01aa6 100644 --- a/functions.js +++ b/functions.js @@ -431,7 +431,7 @@ const functions = { messageEmbed.addFields({ name: 'Information', value: data.code, inline: true }); }) messageEmbed.addFields( - { name: 'Retreival Time', value: `${new Date().toISOString()}` } + { name: 'Retreival Time', value: `${new Date().toISOString()}`, inline: true } ); } else { messageEmbed.addFields( From 798aaef4ea6f130848b6a2c973983f5af3e3cea1 Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Sat, 22 Jun 2024 10:16:21 -0400 Subject: [PATCH 48/79] Adjust embed appearance --- functions.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/functions.js b/functions.js index db01aa6..1439d78 100644 --- a/functions.js +++ b/functions.js @@ -408,12 +408,12 @@ const functions = { .setDescription(`**Not for real world use!**\n\n${metarData.rawOb}`) .setFooter({ text: "METAR by AviationWeather.gov for CumbHub LLC" }) .addFields( - { name: 'Observation Time', value: `${metarData.reportTime}Z` }, - { name: 'Temperature', value: `${metarData.temp}ºC/${metarData.dewp}ºC`}, - { name: 'Winds', value: `${metarData.wdir.toString().padStart(3, '0')}º@${metarData.wspd}${wgst} kts`}, - { name: 'Visibility', value: `${metarData.visib} SM` }, - { name: 'Clouds', value: clouds.join('\n') }, - { name: 'Altimeter', value: `${altim} inHg` } + { name: 'Observation Time', value: `${metarData.reportTime}Z`, inline: true }, + { name: 'Temperature', value: `${metarData.temp}ºC/${metarData.dewp}ºC`, inline: true }, + { name: 'Winds', value: `${metarData.wdir.toString().padStart(3, '0')}º@${metarData.wspd}${wgst} kts`, inline: true }, + { name: 'Visibility', value: `${metarData.visib} SM`, inline: true }, + { name: 'Clouds', value: clouds.join('\n'), inline: true }, + { name: 'Altimeter', value: `${altim} inHg`, inline: true } ) return { embeds: [embed] }; }, From 806d70b2928e9443ab2bf8445c3de57b961b52f9 Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Sat, 22 Jun 2024 10:19:29 -0400 Subject: [PATCH 49/79] Move METAR raw to message body --- functions.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/functions.js b/functions.js index 1439d78..addd6fa 100644 --- a/functions.js +++ b/functions.js @@ -405,7 +405,7 @@ const functions = { const embed = new Discord.MessageEmbed() .setAuthor({ name: `${metarData.name} [${metarData.icaoId}] METAR`, iconURL: "https://aviationweather.gov/img/icons/awc-logo-180.png"}) // .setImage("https://media.discordapp.net/stickers/1175134632845516821.webp") - .setDescription(`**Not for real world use!**\n\n${metarData.rawOb}`) + .setDescription(`**Do not use for real world flight planning or navigation.**`) .setFooter({ text: "METAR by AviationWeather.gov for CumbHub LLC" }) .addFields( { name: 'Observation Time', value: `${metarData.reportTime}Z`, inline: true }, @@ -415,7 +415,7 @@ const functions = { { name: 'Clouds', value: clouds.join('\n'), inline: true }, { name: 'Altimeter', value: `${altim} inHg`, inline: true } ) - return { embeds: [embed] }; + return { body: metarData.rawOb, embeds: [embed] }; }, datis(datisData) { const messageEmbed = new Discord.MessageEmbed() From ecb50148b956a2f23b9800f8a0a7974bdba2531d Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Sat, 22 Jun 2024 10:26:01 -0400 Subject: [PATCH 50/79] Fix body/content --- functions.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/functions.js b/functions.js index addd6fa..50fc8c5 100644 --- a/functions.js +++ b/functions.js @@ -415,7 +415,7 @@ const functions = { { name: 'Clouds', value: clouds.join('\n'), inline: true }, { name: 'Altimeter', value: `${altim} inHg`, inline: true } ) - return { body: metarData.rawOb, embeds: [embed] }; + return { content: metarData.rawOb, embeds: [embed] }; }, datis(datisData) { const messageEmbed = new Discord.MessageEmbed() From 2f9d29d891f2e5e3a1d45ef449e6d3efe00bb95f Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Sat, 22 Jun 2024 10:42:26 -0400 Subject: [PATCH 51/79] Updating docs --- README.md | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7d31f60..7b473ee 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,9 @@ # About Nodbot Nodbot is a content saving and serving Discord bot. Nodbot is able to search Tenor for GIFs, save custom copypastas, and look up marijuana strain information. Nodbot is in semi-active development by voidf1sh. It's buggy as hell and very shoddily built. Don't use it. +# Status +This should be ready to merge into `main`, let it run a couple days with testing before creating a PR. METAR and D-ATIS are implemented. TAFs will come later as they're more complicated. + # Nodbot Help Use the `/help` command to see the bot's help message. @@ -13,12 +16,13 @@ Use the `/help` command to see the bot's help message. # Immediate To-Do -1. ~~Sanitize inputs for SQL queries.~~ Done. +1. ~~Sanitize inputs for SQL queries.~~ 2. ~~Move environment variables so they don't get included in the image.~~ 3. Implement error handling on all actions. -4. Ephemeral responses to some/most slash commands. +4. ~~Ephemeral responses to some/most slash commands.~~ 5. Comment the code! Document! 6. Check for and create database tables if necessary. Handle errors. +7. Readjust keyword autoresponses to be more generic instead of hard coded # Deploy NodBot Yourself @@ -31,6 +35,13 @@ Use the `/help` command to see the bot's help message. 6. Configure your environment variables as outlined below. 7. Fire it up with `node main.js` +# Recent Changes + +* Added METAR via AviationWeather.gov API +* Added D-ATIS via datis.clowd.io API +* Updated how keyword autoresponses are handled +* Changed `.joint` to reduce duplication and repetition by implementing an Ashtray and Roaches + ## Table Structure ``` From 8f7ed605a4ab14f1da5020d1e73ce6be479d179e Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Sun, 22 Sep 2024 22:26:09 +0000 Subject: [PATCH 52/79] Update .github/workflows/pe-docker.yml Match from pe branch --- .github/workflows/pe-docker.yml | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/.github/workflows/pe-docker.yml b/.github/workflows/pe-docker.yml index 003f963..d52bcfe 100644 --- a/.github/workflows/pe-docker.yml +++ b/.github/workflows/pe-docker.yml @@ -1,9 +1,9 @@ -name: NodBot Production Dockerization +name: NodBot PE Dockerization on: - commit: + push: branches: - - pe + - main env: DHUB_UNAME: ${{ secrets.DHUB_UNAME }} @@ -13,23 +13,35 @@ jobs: build: - runs-on: self-hosted + runs-on: ubuntu-latest steps: - name: Pull latest from Git run: | pwd whoami - cd /root/nodbot - git pull - git checkout pe + mkdir -p /var/lib/act_runner/ + cd /var/lib/act_runner/ + if [ ! -d "nodbot" ]; then + git clone https://git.vfsh.dev/voidf1sh/nodbot + cd nodbot + else + cd nodbot + git pull + fi + git checkout ${{ gitea.ref}} - name: Build the Docker image run: | - cd /root/nodbot + cd /var/lib/act_runner/nodbot docker build . --file Dockerfile --tag v0idf1sh/nodbot-pe - name: Log into Docker Hub run: docker login -u $DHUB_UNAME -p $DHUB_PWORD - name: Push image to Docker Hub run: | - cd /root/nodbot - docker push v0idf1sh/nodbot-pe \ No newline at end of file + cd /var/lib/act_runner/nodbot + docker push v0idf1sh/nodbot-pe + - name: Restart the container + run: | + cd /srv/docker/nodbot-pe + docker-compose down + docker-compose up -d \ No newline at end of file From 38d90d7f6bb842f109a7ac609075eadd1be9ec4f Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Sun, 22 Sep 2024 18:49:27 -0400 Subject: [PATCH 53/79] Update CI/CD --- {.github => .gitea}/workflows/pe-docker.yml | 4 ++-- {.github => .gitea}/workflows/production-docker.yml | 0 2 files changed, 2 insertions(+), 2 deletions(-) rename {.github => .gitea}/workflows/pe-docker.yml (96%) rename {.github => .gitea}/workflows/production-docker.yml (100%) diff --git a/.github/workflows/pe-docker.yml b/.gitea/workflows/pe-docker.yml similarity index 96% rename from .github/workflows/pe-docker.yml rename to .gitea/workflows/pe-docker.yml index d52bcfe..179d2e7 100644 --- a/.github/workflows/pe-docker.yml +++ b/.gitea/workflows/pe-docker.yml @@ -3,7 +3,7 @@ name: NodBot PE Dockerization on: push: branches: - - main + - pe env: DHUB_UNAME: ${{ secrets.DHUB_UNAME }} @@ -13,7 +13,7 @@ jobs: build: - runs-on: ubuntu-latest + runs-on: self-hosted steps: - name: Pull latest from Git diff --git a/.github/workflows/production-docker.yml b/.gitea/workflows/production-docker.yml similarity index 100% rename from .github/workflows/production-docker.yml rename to .gitea/workflows/production-docker.yml From 70fc12d45873c62cd661d56946470a27e7705c1a Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Mon, 23 Sep 2024 18:51:34 -0400 Subject: [PATCH 54/79] Fix branch references --- .gitea/workflows/pe-docker.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.gitea/workflows/pe-docker.yml b/.gitea/workflows/pe-docker.yml index 179d2e7..9e13c26 100644 --- a/.gitea/workflows/pe-docker.yml +++ b/.gitea/workflows/pe-docker.yml @@ -10,14 +10,12 @@ env: DHUB_PWORD: ${{ secrets.DHUB_PWORD }} jobs: - build: - runs-on: self-hosted - steps: - name: Pull latest from Git run: | + echo "Branch: ${{ gitea.head_ref }}" pwd whoami mkdir -p /var/lib/act_runner/ @@ -29,7 +27,7 @@ jobs: cd nodbot git pull fi - git checkout ${{ gitea.ref}} + git checkout ${{ gitea.head_ref }} - name: Build the Docker image run: | cd /var/lib/act_runner/nodbot From 9d9a1447f3fad3d39bac5f971ee7576b1f458d5b Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Mon, 23 Sep 2024 18:51:43 -0400 Subject: [PATCH 55/79] Fixed Prod Deployment --- .gitea/workflows/production-docker.yml | 30 +++++++++++++++++--------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/.gitea/workflows/production-docker.yml b/.gitea/workflows/production-docker.yml index d4e5c6b..c524d9b 100644 --- a/.gitea/workflows/production-docker.yml +++ b/.gitea/workflows/production-docker.yml @@ -3,33 +3,43 @@ name: NodBot Production Dockerization on: pull_request: branches: - - main + - main env: DHUB_UNAME: ${{ secrets.DHUB_UNAME }} DHUB_PWORD: ${{ secrets.DHUB_PWORD }} jobs: - build: - runs-on: self-hosted - steps: - name: Pull latest from Git run: | + echo "Branch: ${{ gitea.head_ref }}" pwd whoami - cd /root/nodbot - git pull - git checkout $GITHUB_HEAD_REF + mkdir -p /var/lib/act_runner/ + cd /var/lib/act_runner/ + if [ ! -d "nodbot" ]; then + git clone https://git.vfsh.dev/voidf1sh/nodbot + cd nodbot + else + cd nodbot + git pull + fi + git checkout ${{ gitea.head_ref }} - name: Build the Docker image run: | - cd /root/nodbot + cd /var/lib/act_runner/nodbot docker build . --file Dockerfile --tag v0idf1sh/nodbot - name: Log into Docker Hub run: docker login -u $DHUB_UNAME -p $DHUB_PWORD - name: Push image to Docker Hub run: | - cd /root/nodbot - docker push v0idf1sh/nodbot \ No newline at end of file + cd /var/lib/act_runner/nodbot + docker push v0idf1sh/nodbot + - name: Restart the container + run: | + cd /srv/docker/nodbot + docker-compose down + docker-compose up -d \ No newline at end of file From 7b967cca8c5d38d830835840e7affe56f080e093 Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Mon, 23 Sep 2024 21:06:35 -0400 Subject: [PATCH 56/79] Versioning -- v3.3.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 566a3e0..513ea8b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "nodbot", - "version": "3.3.1", + "version": "3.3.2", "description": "Nods and Nod Accessories, now with ChatGPT!", "main": "main.js", "dependencies": { From 0c2eae76aa183c89a4e98109a9cac73458b81d4f Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Mon, 23 Sep 2024 21:10:08 -0400 Subject: [PATCH 57/79] Remove vestigial code --- slash-commands/help.js | 25 ++----------------------- 1 file changed, 2 insertions(+), 23 deletions(-) diff --git a/slash-commands/help.js b/slash-commands/help.js index d18d9fe..084f2d1 100644 --- a/slash-commands/help.js +++ b/slash-commands/help.js @@ -4,29 +4,8 @@ const fn = require('../functions.js'); module.exports = { data: new SlashCommandBuilder() .setName('help') - .setDescription('Send the help page.') - // .addStringOption(option => - // option.setName('location') - // .setDescription('Send help in this channel or in DMs?') - // .setRequired(true) - // .addChoice('Here', 'channel') - // .addChoice('DMs', 'dm')) - , + .setDescription('Send the help page.'), async execute(interaction) { - // switch (interaction.options.getString('location')) { - // case 'channel': - // await interaction.reply(fn.embeds.help(interaction)); - // break; - // case 'dm': - // await interaction.user.createDM().then(channel => { - // channel.send(fn.embeds.help(interaction)); - // interaction.reply({content: 'I\'ve sent you a copy of my help page.', ephemeral: true}); - // }); - // break; - // default: - // interaction.reply('There was an error, please try again.'); - // break; - // } await interaction.reply(fn.embeds.help(interaction)); - }, + } }; \ No newline at end of file From f231df89d8393823f87ff64f1cd3018d29175874 Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Mon, 23 Sep 2024 21:21:38 -0400 Subject: [PATCH 58/79] Move help from fields to the description. --- functions.js | 32 +++++++++++++------------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/functions.js b/functions.js index 50fc8c5..cee266c 100644 --- a/functions.js +++ b/functions.js @@ -210,31 +210,23 @@ const functions = { const helpEmbed = new Discord.MessageEmbed() .setColor('BLUE') .setAuthor({name: 'Help Page'}) - .setDescription(strings.help.description) .setThumbnail(strings.urls.avatar); // Construct the Slash Commands help let slashCommandsFields = []; - const slashCommandsMap = interaction.client.slashCommands.map(e => { return { name: e.data.name, description: e.data.description }; }) - for (const e of slashCommandsMap) { - slashCommandsFields.push({ - name: `- /${e.name}`, - value: e.description, - inline: false, - }); + slashCommandsFields.push(`- /${e.name} - ${e.description}`); } // Construct the Dot Commands Help let dotCommandsFields = []; - const dotCommandsMap = interaction.client.dotCommands.map(e => { return { name: e.name, @@ -242,19 +234,21 @@ const functions = { usage: e.usage }; }); - for (const e of dotCommandsMap) { - dotCommandsFields.push({ - name: `- .${e.name}`, - value: `${e.description}\nUsage: ${e.usage}`, - inline: false, - }); + dotCommandsFields.push(`- .${e.name} - ${e.description}\nUsage: ${e.usage}`); } - helpEmbed.addField('Slash Commands', strings.help.slash); - helpEmbed.addFields(slashCommandsFields); - helpEmbed.addField('Dot Commands', strings.help.dot); - helpEmbed.addFields(dotCommandsFields); + // Construct the Description Fields + const descriptionFields = [ + `${strings.help.description}\n`, + `**Slash Commands**\n${strings.help.slash}\n`, + `${slashCommandsFields.join('\n')}\n`, + `**Dot Commands**\n${strings.help.dot}\n`, + `${dotCommandsFields.join('\n')}` + ]; + + // Set the description + helpEmbed.setDescription(descriptionFields.join('\n')); return { embeds: [ helpEmbed From 28443611e49287adabef4722de672cfdda883aeb Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Mon, 23 Sep 2024 22:01:19 -0400 Subject: [PATCH 59/79] Vastly improved the /help command --- functions.js | 42 +++++++++++++++++++++++++++++------------- strings.json | 6 +++--- 2 files changed, 32 insertions(+), 16 deletions(-) diff --git a/functions.js b/functions.js index cee266c..d6b12dd 100644 --- a/functions.js +++ b/functions.js @@ -215,28 +215,44 @@ const functions = { // Construct the Slash Commands help let slashCommandsFields = []; + let slashSeenNames = new Array(); const slashCommandsMap = interaction.client.slashCommands.map(e => { - return { - name: e.data.name, - description: e.data.description - }; - }) + if (!slashSeenNames.includes(e.data.name)) { + slashSeenNames.push(e.data.name); + return { + name: e.data.name, + description: e.data.description + }; + } else { + return null; + } + }); for (const e of slashCommandsMap) { - slashCommandsFields.push(`- /${e.name} - ${e.description}`); + slashCommandsFields.push(`- \`/${e.name}\` - ${e.description}`); } + console.log(slashCommandsFields); // Construct the Dot Commands Help - let dotCommandsFields = []; + let dotCommandsFields = new Array(); + let dotSeenNames = new Array(); const dotCommandsMap = interaction.client.dotCommands.map(e => { - return { - name: e.name, - description: e.description, - usage: e.usage - }; + if (!dotSeenNames.includes(e.name)) { + dotSeenNames.push(e.name); + return { + name: e.name, + description: e.description, + usage: e.usage + }; + } else { + return null; + } }); for (const e of dotCommandsMap) { - dotCommandsFields.push(`- .${e.name} - ${e.description}\nUsage: ${e.usage}`); + if (e != null) { + dotCommandsFields.push(`- \`.${e.name}\` - ${e.description} - ${e.usage}`); + } } + console.log(dotCommandsFields); // Construct the Description Fields const descriptionFields = [ diff --git a/strings.json b/strings.json index e7991f8..8883464 100644 --- a/strings.json +++ b/strings.json @@ -1,8 +1,8 @@ { "help": { - "description": "Hi there! Thanks for checking out NodBot. NodBot is used in two distinct ways: with 'Slash Commands' (/help), and with 'Dot Commands' (nod.gif). The two types will be outlined below, along with usage examples.", - "slash": "Slash Commands always begin with a / and a menu will pop up to help complete the commands.", - "dot": "Dot Commands have the command at the end of the message, for example to search for a gif of 'nod', type 'nod.gif'" + "description": "Hi there! Thanks for checking out NodBot. NodBot is used in two distinct ways: with 'Slash Commands' (`/help`), and with 'Dot Commands' (`nod.gif`). The two types will be outlined below, along with usage examples.", + "slash": "Slash Commands always begin with a `/` and a menu will pop up to help complete the commands.", + "dot": "Dot Commands have the command at the end of the message, for example to search for a gif of `nod`, type `nod.gif`" }, "emoji": { "joint": "<:joint:862082955902976000>", From fdcb56998c8dd32cee2e5bdbf96ce659301be097 Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Mon, 23 Sep 2024 22:02:01 -0400 Subject: [PATCH 60/79] Ignore new env format --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index fcfa662..10223d5 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ package-lock.json .VSCodeCounter/ .env* +*.env # Custom folders # gifs/* From 1a0817a89c92dcadda01d4afcae87a4d9a9764e7 Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Wed, 25 Sep 2024 11:54:04 -0400 Subject: [PATCH 61/79] Versioning -- v3.3.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 513ea8b..8fcfff9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "nodbot", - "version": "3.3.2", + "version": "3.3.3", "description": "Nods and Nod Accessories, now with ChatGPT!", "main": "main.js", "dependencies": { From 23f081c6c1d82e597786047d8759391e4dd89e39 Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Wed, 25 Sep 2024 11:54:33 -0400 Subject: [PATCH 62/79] Move CommandData and checkCommand to NodBot Classes --- CustomModules/NodBot.js | 18 ++++++++++++++++++ functions.js | 33 +++------------------------------ 2 files changed, 21 insertions(+), 30 deletions(-) diff --git a/CustomModules/NodBot.js b/CustomModules/NodBot.js index 2d5ff83..24efec3 100644 --- a/CustomModules/NodBot.js +++ b/CustomModules/NodBot.js @@ -1,4 +1,22 @@ module.exports = { + CommandData: class { + constructor(message) { + // Get the location of the final period in the message + this.finalPeriod = message.content.lastIndexOf('.'); + this.isCommand = finalPeriod >= 0 ? true : false; // Check if there is a period somewhere in the message to flag as a possible command + this.args = message.content.slice(0,finalPeriod).toLowerCase(); // Grab everything leading up to the final period + this.command = message.content.slice(finalPeriod + 1).toLowerCase(); // Grab everything after the final period + this.author = message.author.username; + + return this; + } + + isValid(validCommands) { + if (this.args.startsWith('http')) return false; + if (this.args.startsWith('www')) return false; + return validCommands.includes(this.command); + } + }, GifData: class { constructor() { this.id = 0; diff --git a/functions.js b/functions.js index d6b12dd..7a27238 100644 --- a/functions.js +++ b/functions.js @@ -34,6 +34,7 @@ const config = require('./config.json'); const strings = require('./strings.json'); const slashCommandFiles = fs.readdirSync('./slash-commands/').filter(file => file.endsWith('.js')); const dotCommandFiles = fs.readdirSync('./dot-commands/').filter(file => file.endsWith('.js')); +const { CommandData } = require('./CustomModules/NodBot.js'); // MySQL database connection const mysql = require('mysql'); @@ -172,36 +173,8 @@ const functions = { }, dot: { getCommandData(message) { - const commandData = {}; - // Split the message content at the final instance of a period - const finalPeriod = message.content.lastIndexOf('.'); - // if(isDev) console.log(message.content); - // If the final period is the last character, or doesn't exist - if (finalPeriod < 0) { - if (isDev) console.log(finalPeriod); - commandData.isCommand = false; - return commandData; - } - commandData.isCommand = true; - // Get the first part of the message, everything leading up to the final period - commandData.args = message.content.slice(0,finalPeriod).toLowerCase(); - // Get the last part of the message, everything after the final period - commandData.command = message.content.slice(finalPeriod + 1).toLowerCase(); - commandData.author = `${message.author.username}`; - return this.checkCommand(commandData); - }, - checkCommand(commandData) { - if (commandData.isCommand) { - const validCommands = require('./config.json').validCommands; - commandData.isValid = validCommands.includes(commandData.command); - // Add exceptions for messages that contain only a link - if (commandData.args.startsWith('http')) commandData.isValid = false; - } - else { - commandData.isValid = false; - console.error('Somehow a non-command made it to checkCommands()'); - } - return commandData; + const commandData = new CommandData(message); + return commandData.isValid(require('./config.json').validCommands); } }, embeds: { From 00df6074d6eb4c8ec477764ca1230873e01b19d5 Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Wed, 25 Sep 2024 15:30:51 -0400 Subject: [PATCH 63/79] Fixed duplication of valid commands --- CustomModules/NodBot.js | 24 +++++++++++++++++++----- functions.js | 18 ++++++++++-------- 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/CustomModules/NodBot.js b/CustomModules/NodBot.js index 24efec3..ac29c41 100644 --- a/CustomModules/NodBot.js +++ b/CustomModules/NodBot.js @@ -3,18 +3,32 @@ module.exports = { constructor(message) { // Get the location of the final period in the message this.finalPeriod = message.content.lastIndexOf('.'); - this.isCommand = finalPeriod >= 0 ? true : false; // Check if there is a period somewhere in the message to flag as a possible command - this.args = message.content.slice(0,finalPeriod).toLowerCase(); // Grab everything leading up to the final period - this.command = message.content.slice(finalPeriod + 1).toLowerCase(); // Grab everything after the final period + this.isCommand = this.finalPeriod >= 0 ? true : false; // Check if there is a period somewhere in the message to flag as a possible command + this.isValid = false; + this.args = message.content.slice(0,this.finalPeriod).toLowerCase(); // Grab everything leading up to the final period + this.command = message.content.slice(this.finalPeriod + 1).toLowerCase(); // Grab everything after the final period this.author = message.author.username; return this; } - isValid(validCommands) { + validate(dotCommands) { if (this.args.startsWith('http')) return false; if (this.args.startsWith('www')) return false; - return validCommands.includes(this.command); + + for (const [key, value] of dotCommands) { + if (key === this.command) { + this.isValid = true; + return this.isValid; + } else if (value.alias && value.alias.includes(this.command)) { + this.command = key; + this.isValid = true; + return this.isValid; + } + } + + this.isValid = validCommands.includes(this.command); + return this.isValid; } }, GifData: class { diff --git a/functions.js b/functions.js index 7a27238..eeaeb3f 100644 --- a/functions.js +++ b/functions.js @@ -82,13 +82,13 @@ const functions = { for (const file of dotCommandFiles) { const dotCommand = require(`./dot-commands/${file}`); client.dotCommands.set(dotCommand.name, dotCommand); - if (Array.isArray(dotCommand.alias)) { - dotCommand.alias.forEach(element => { - client.dotCommands.set(element, dotCommand); - }); - } else if (dotCommand.alias != undefined) { - client.dotCommands.set(dotCommand.alias, dotCommand); - } + // if (Array.isArray(dotCommand.alias)) { + // dotCommand.alias.forEach(element => { + // client.dotCommands.set(element, dotCommand); + // }); + // } else if (dotCommand.alias != undefined) { + // client.dotCommands.set(dotCommand.alias, dotCommand); + // } } if (isDev) console.log('Dot Commands Collection Built'); }, @@ -174,7 +174,9 @@ const functions = { dot: { getCommandData(message) { const commandData = new CommandData(message); - return commandData.isValid(require('./config.json').validCommands); + const { validCommands } = require('./config.json'); + commandData.validate(message.client.dotCommands); + return commandData; } }, embeds: { From ecbfc2bc2aad2d01eef0b3cb68b39938c6fcb890 Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Wed, 25 Sep 2024 15:35:01 -0400 Subject: [PATCH 64/79] Remove unnecessary function calls now that classes exist --- CustomModules/NodBot.js | 6 +++--- functions.js | 8 -------- main.js | 4 ++-- 3 files changed, 5 insertions(+), 13 deletions(-) diff --git a/CustomModules/NodBot.js b/CustomModules/NodBot.js index ac29c41..2d2ed16 100644 --- a/CustomModules/NodBot.js +++ b/CustomModules/NodBot.js @@ -19,16 +19,16 @@ module.exports = { for (const [key, value] of dotCommands) { if (key === this.command) { this.isValid = true; - return this.isValid; + return this; } else if (value.alias && value.alias.includes(this.command)) { this.command = key; this.isValid = true; - return this.isValid; + return this; } } this.isValid = validCommands.includes(this.command); - return this.isValid; + return this; } }, GifData: class { diff --git a/functions.js b/functions.js index eeaeb3f..608848d 100644 --- a/functions.js +++ b/functions.js @@ -171,14 +171,6 @@ const functions = { if (isDev) console.log('Medical Advice Collection Built'); } }, - dot: { - getCommandData(message) { - const commandData = new CommandData(message); - const { validCommands } = require('./config.json'); - commandData.validate(message.client.dotCommands); - return commandData; - } - }, embeds: { help(interaction) { // Construct the Help Embed diff --git a/main.js b/main.js index 55a347c..2493676 100644 --- a/main.js +++ b/main.js @@ -27,7 +27,7 @@ const { MessageActionRow, MessageButton } = require('discord.js'); const fn = require('./functions.js'); const config = require('./config.json'); const strings = require('./strings.json'); -const { GifData } = require('./CustomModules/NodBot.js'); +const { GifData, CommandData } = require('./CustomModules/NodBot.js'); const isDev = process.env.isDev; client.once('ready', async () => { @@ -232,7 +232,7 @@ client.on('messageCreate', message => { }); // Break the message down into its components and analyze it - const commandData = fn.dot.getCommandData(message); + const commandData = new CommandData(message).validate(message.client.dotCommands); console.log(commandData); if (commandData.isValid && commandData.isCommand) { From be83b9ea749e6d788cf118478766754335ce2d92 Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Wed, 25 Sep 2024 18:56:33 -0400 Subject: [PATCH 65/79] WIP --- CustomModules/Embeds.js | 28 ++++++++++++++++++++++++++++ slash-commands/save.js | 12 ++---------- 2 files changed, 30 insertions(+), 10 deletions(-) create mode 100644 CustomModules/Embeds.js diff --git a/CustomModules/Embeds.js b/CustomModules/Embeds.js new file mode 100644 index 0000000..6335690 --- /dev/null +++ b/CustomModules/Embeds.js @@ -0,0 +1,28 @@ +module.exports = { + gifSearchAR() { + // Setup the buttons + const previousButton = new MessageButton() + .setCustomId('prevGif') + .setLabel('⬅️') + .setStyle('SECONDARY'); + + const confirmButton = new MessageButton() + .setCustomId('confirmGif') + .setLabel('✅') + .setStyle('PRIMARY'); + + const nextButton = new MessageButton() + .setCustomId('nextGif') + .setLabel('➡️') + .setStyle('SECONDARY'); + + const cancelButton = new MessageButton() + .setCustomId('cancelGif') + .setLabel('❌') + .setStyle('DANGER'); + + // Put the buttons into an ActionRow + return new MessageActionRow() + .addComponents(previousButton, confirmButton, nextButton, cancelButton); + } +} \ No newline at end of file diff --git a/slash-commands/save.js b/slash-commands/save.js index b47b05d..28f7533 100644 --- a/slash-commands/save.js +++ b/slash-commands/save.js @@ -11,6 +11,7 @@ const { MessageActionRow, MessageButton } = require('discord.js'); const fn = require('../functions.js'); const strings = require('../strings.json'); const { GifData } = require('../CustomModules/NodBot.js'); +const customEmbeds = require('../CustomModules/Embeds.js'); const { emoji } = strings; module.exports = { @@ -142,16 +143,7 @@ module.exports = { // GIF Search case "gifsearch": // TODO Check on option names - // Previous GIF button - const prevButton = new MessageButton().setCustomId('prevGif').setLabel('Previous GIF').setStyle('SECONDARY').setDisabled(true); - // Confirm GIF Button - const confirmButton = new MessageButton().setCustomId('confirmGif').setLabel('Confirm').setStyle('PRIMARY'); - // Next GIF Button - const nextButton = new MessageButton().setCustomId('nextGif').setLabel('Next GIF').setStyle('SECONDARY'); - // Cancel Button - const cancelButton = new MessageButton().setCustomId('cancelGif').setLabel('Cancel').setStyle('DANGER'); - // Put all the above into an ActionRow to be sent as a component of the reply - const actionRow = new MessageActionRow().addComponents(prevButton, confirmButton, nextButton, cancelButton); + const actionRow = customEmbeds.gifSearchAR(); // Get the query const query = interaction.options.getString('query'); From 8e5931e0d49d419b8c78889753ce67b75d3fc257 Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Wed, 25 Sep 2024 23:22:22 -0400 Subject: [PATCH 66/79] Working on storing interaction data in the client --- CustomModules/ButtonHandlers.js | 22 ++++++++ CustomModules/Embeds.js | 81 ++++++++++++++++++++++++++++- CustomModules/Indexer.js | 31 +++++++++++ CustomModules/InteractionStorage.js | 15 ++++++ CustomModules/NodBot.js | 2 - functions.js | 22 ++++---- main.js | 12 ++++- slash-commands/gifs.js | 43 +++++++-------- 8 files changed, 188 insertions(+), 40 deletions(-) create mode 100644 CustomModules/ButtonHandlers.js create mode 100644 CustomModules/Indexer.js create mode 100644 CustomModules/InteractionStorage.js diff --git a/CustomModules/ButtonHandlers.js b/CustomModules/ButtonHandlers.js new file mode 100644 index 0000000..a9cfa6c --- /dev/null +++ b/CustomModules/ButtonHandlers.js @@ -0,0 +1,22 @@ +const customEmbeds = require('../CustomModules/Embeds.js'); + +module.exports = { + baseEvent(interaction) { + console.log(interaction.component.customId); + switch (interaction.component.customId) { + // Any of the gifsPage Buttons + case 'prevGifsPage' || 'nextGifsPage' : + break; + default: + return; + } + }, + gifsPage(interaction, gifs, page) { + switch (buttonId) { + case 'prevGifsPage': + return 'previous'; + case 'nextGifsPage': + return 'next'; + } + } +} \ No newline at end of file diff --git a/CustomModules/Embeds.js b/CustomModules/Embeds.js index 6335690..cc057da 100644 --- a/CustomModules/Embeds.js +++ b/CustomModules/Embeds.js @@ -1,5 +1,7 @@ +const { MessageActionRow, MessageButton } = require('discord.js'); + module.exports = { - gifSearchAR() { + gifSearchAR(state) { // Setup the buttons const previousButton = new MessageButton() .setCustomId('prevGif') @@ -21,6 +23,83 @@ module.exports = { .setLabel('❌') .setStyle('DANGER'); + switch (state) { + case 'first': + previousButton.setDisabled(true); + break; + case 'last': + nextButton.setDisabled(true); + break; + } + + // Put the buttons into an ActionRow + return new MessageActionRow() + .addComponents(previousButton, confirmButton, nextButton, cancelButton); + }, + gifsPageAR() { + // Setup the buttons + const previousButton = new MessageButton() + .setCustomId('prevGifsPage') + .setLabel('⬅️') + .setStyle('SECONDARY'); + + const nextButton = new MessageButton() + .setCustomId('nextGifsPage') + .setLabel('➡️') + .setStyle('SECONDARY'); + + // Put the buttons into an ActionRow + return new MessageActionRow() + .addComponents(previousButton, nextButton); + }, + requestsPageAR() { + // Setup the buttons + const previousButton = new MessageButton() + .setCustomId('prevRequestsPage') + .setLabel('⬅️') + .setStyle('SECONDARY'); + + const confirmButton = new MessageButton() + .setCustomId('confirmRequestsPage') + .setLabel('✅') + .setStyle('PRIMARY'); + + const nextButton = new MessageButton() + .setCustomId('nextRequestsPage') + .setLabel('➡️') + .setStyle('SECONDARY'); + + const cancelButton = new MessageButton() + .setCustomId('cancelRequestsPage') + .setLabel('❌') + .setStyle('DANGER'); + + // Put the buttons into an ActionRow + return new MessageActionRow() + .addComponents(previousButton, confirmButton, nextButton, cancelButton); + }, + pastasPageAR() { + // Setup the buttons + const previousButton = new MessageButton() + .setCustomId('prevPastasPage') + .setLabel('⬅️') + .setStyle('SECONDARY'); + + const confirmButton = new MessageButton() + .setCustomId('confirmPastasPage') + .setLabel('✅') + .setStyle('PRIMARY'); + + const nextButton = new MessageButton() + .setCustomId('nextPastasPage') + .setLabel('➡️') + .setStyle('SECONDARY'); + + const cancelButton = new MessageButton() + .setCustomId('cancelPastasPage') + .setLabel('❌') + .setStyle('DANGER'); + // Put the buttons into an ActionRow return new MessageActionRow() .addComponents(previousButton, confirmButton, nextButton, cancelButton); diff --git a/CustomModules/Indexer.js b/CustomModules/Indexer.js new file mode 100644 index 0000000..8a3960f --- /dev/null +++ b/CustomModules/Indexer.js @@ -0,0 +1,31 @@ +module.exports = (collection, page) => { + const itemsPerPage = 10; + const index = page * itemsPerPage; + const totalPages = Math.ceil(collection.size / itemsPerPage); + let state = page === 0 ? 'first' : 'middle'; + + const thisPage = new Array(); + + // Map the Djs Collection to an Array + const collectionArray = collection.map((command) => command); + + for (let i = index; i < index + itemsPerPage; i++) { + if (collectionArray[i]) { + thisPage.push(collectionArray[i]); + } else { + state = 'last'; + break; + } + + if (i === collectionArray.size - 1) { + state = 'last'; + break; + } + } + + return { + state: state, + thisPage: thisPage, + pages: `Page ${page + 1}/${totalPages}` + }; +} \ No newline at end of file diff --git a/CustomModules/InteractionStorage.js b/CustomModules/InteractionStorage.js new file mode 100644 index 0000000..d5cf06a --- /dev/null +++ b/CustomModules/InteractionStorage.js @@ -0,0 +1,15 @@ +module.exports = class InteractionStorage { + constructor(idString, interaction) { + this.idString = idString; + + // Store in the client + interaction.client.iStorage.set(idString, this); + + // Delete this from the interactionStorage after 5 minutes + setTimeout(() => { + interaction.client.iStorage.delete(idString); + }, 300000); + + return this; + } +} \ No newline at end of file diff --git a/CustomModules/NodBot.js b/CustomModules/NodBot.js index 2d2ed16..d18c21b 100644 --- a/CustomModules/NodBot.js +++ b/CustomModules/NodBot.js @@ -26,8 +26,6 @@ module.exports = { return this; } } - - this.isValid = validCommands.includes(this.command); return this; } }, diff --git a/functions.js b/functions.js index 608848d..15a5e5a 100644 --- a/functions.js +++ b/functions.js @@ -1,7 +1,6 @@ /* eslint-disable comma-dangle */ // dotenv for handling environment variables -const dotenv = require('dotenv'); -dotenv.config(); +const dotenv = require('dotenv').config(); // Assignment of environment variables for database access const dbHost = process.env.dbHost; const dbUser = process.env.dbUser; @@ -9,7 +8,6 @@ const dbName = process.env.dbName; const dbPass = process.env.dbPass; const dbPort = process.env.dbPort; const isDev = process.env.isDev; - const ownerId = process.env.ownerId; // filesystem @@ -22,10 +20,6 @@ const Discord = require('discord.js'); // Fuzzy text matching for db lookups const FuzzySearch = require('fuzzy-search'); -// OpenAI -// const OpenAI = require("openai"); -// const openai = new OpenAI(); - // Axios for APIs const axios = require('axios'); @@ -34,7 +28,7 @@ const config = require('./config.json'); const strings = require('./strings.json'); const slashCommandFiles = fs.readdirSync('./slash-commands/').filter(file => file.endsWith('.js')); const dotCommandFiles = fs.readdirSync('./dot-commands/').filter(file => file.endsWith('.js')); -const { CommandData } = require('./CustomModules/NodBot.js'); +const customEmbeds = require('./CustomModules/Embeds.js'); // MySQL database connection const mysql = require('mysql'); @@ -51,6 +45,11 @@ const db = new mysql.createPool({ const functions = { // Functions for managing and creating Collections collections: { + interactionStorage(client) { + if (!client.iStorage) client.iStorage = new Discord.Collection(); + client.iStorage.clear(); + if (isDev) console.log('Interaction Storage Collection Built'); + } // Create the collection of slash commands slashCommands(client) { if (!client.slashCommands) client.slashCommands = new Discord.Collection(); @@ -268,14 +267,15 @@ const functions = { return { embeds: [pastasEmbed], ephemeral: true }; }, - gifs(commandData, gifList) { + gifs(commandData, gifsString, state) { const gifsEmbed = new Discord.MessageEmbed() .setAuthor({name: commandData.command}) .setTimestamp() .setFooter({text: commandData.author}) - .setDescription(gifList.join('\n')); + .setDescription(gifsString); - return { embeds: [gifsEmbed] }; + const gifsPageAR = customEmbeds.gifsPageAR(state); + return { embeds: [gifsEmbed], components: [gifsPageAR], ephemeral: true }; }, text(commandData) { return { embeds: [new Discord.MessageEmbed() diff --git a/main.js b/main.js index 2493676..304c7be 100644 --- a/main.js +++ b/main.js @@ -28,9 +28,12 @@ const fn = require('./functions.js'); const config = require('./config.json'); const strings = require('./strings.json'); const { GifData, CommandData } = require('./CustomModules/NodBot.js'); +const ButtonHandlers = require('./CustomModules/ButtonHandlers.js'); +const InteractionStorage = require('./CustomModules/InteractionStorage.js'); const isDev = process.env.isDev; client.once('ready', async () => { + fn.collections.interactionStorage(client); fn.collections.slashCommands(client); fn.collections.dotCommands(client); fn.collections.setvalidCommands(client); @@ -58,6 +61,12 @@ client.on('interactionCreate', async interaction => { } const { commandName } = interaction; + const idString = `${interaction.channelId}${interaction.member.id}`; + + if (!client.interactionStorage.has(idString)) { + new InteractionStorage(idString, interaction); + } + if (client.slashCommands.has(commandName)) { client.slashCommands.get(commandName).execute(interaction); } else { @@ -67,7 +76,7 @@ client.on('interactionCreate', async interaction => { } if (interaction.isButton()) { - if (interaction.user.id != strings.temp.gifUserId) return; + if (isDev) console.log(interaction.id); // Get some meta info from strings const index = strings.temp.gifIndex; const limit = strings.temp.gifLimit; @@ -176,6 +185,7 @@ client.on('interactionCreate', async interaction => { interaction.update({ content: 'Canceled.', components: [row] }); break; default: + ButtonHandlers.baseEvent(interaction); break; } } diff --git a/slash-commands/gifs.js b/slash-commands/gifs.js index 0409968..00a30f0 100644 --- a/slash-commands/gifs.js +++ b/slash-commands/gifs.js @@ -1,36 +1,29 @@ const { SlashCommandBuilder } = require('@discordjs/builders'); const { config } = require('dotenv'); const fn = require('../functions.js'); +const indexer = require('../CustomModules/Indexer.js'); module.exports = { data: new SlashCommandBuilder() .setName('gifs') .setDescription('Get a list of currently saved GIFs.'), - async execute(interaction) { - if (!interaction.client.gifs) { - interaction.reply('For some reason I don\'t have access to the collection of gifs. Sorry about that!'); - return; - } - // const gifsMap = interaction.client.gifs.map(e => {e.name, e.url}); - // const commandData = { - // gifs: [], - // command: 'gifs', - // author: interaction.user.tag, - // }; - // for (const row of gifsMap) { - // commandData.gifs.push({ - // id: row.id, - // name: row.name, - // }); - // } - let gifList = []; - interaction.client.gifs.forEach(element => { - gifList.push(`[${element.name}](${element.url})`); + execute(interaction) { + return new Promise((resolve, reject) => { + if (!interaction.client.gifs) { + interaction.reply('For some reason I don\'t have access to the collection of gifs. Sorry about that!'); + resolve(); + } + let gifList = indexer(interaction.client.gifs, 0); + let gifsString = new String(); + + for (const gif of gifList.thisPage) { + gifsString += `[${gif.name}.gif](${gif.url})\n`; + } + const commandData = { + command: "/gifs", + author: interaction.member.displayName + }; + interaction.reply(fn.embeds.gifs(commandData, gifsString, gifList.state)); }); - const commandData = { - command: "/gifs", - author: interaction.member.displayName - }; - interaction.reply(fn.embeds.gifs(commandData, gifList)); }, }; \ No newline at end of file From 7aa3d5d0a1e44e3f3f8cf83b96e582b9b7b70d7e Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Thu, 26 Sep 2024 08:09:09 -0400 Subject: [PATCH 67/79] MVP for Paged /gifs Browser --- CustomModules/ButtonHandlers.js | 49 ++++++++++++++++++++++++----- CustomModules/Embeds.js | 11 ++++++- CustomModules/Indexer.js | 3 +- CustomModules/InteractionStorage.js | 1 + functions.js | 42 +++---------------------- main.js | 11 +++---- slash-commands/gifs.js | 13 +++++--- 7 files changed, 72 insertions(+), 58 deletions(-) diff --git a/CustomModules/ButtonHandlers.js b/CustomModules/ButtonHandlers.js index a9cfa6c..4e9011f 100644 --- a/CustomModules/ButtonHandlers.js +++ b/CustomModules/ButtonHandlers.js @@ -1,22 +1,55 @@ const customEmbeds = require('../CustomModules/Embeds.js'); +const InteractionStorage = require('../CustomModules/InteractionStorage.js'); +const indexer = require('../CustomModules/Indexer.js'); +const fn = require('../functions.js'); module.exports = { baseEvent(interaction) { - console.log(interaction.component.customId); switch (interaction.component.customId) { // Any of the gifsPage Buttons - case 'prevGifsPage' || 'nextGifsPage' : + case 'prevGifsPage': + module.exports.gifsPage(interaction); + break; + case 'nextGifsPage': + module.exports.gifsPage(interaction); break; default: return; } }, - gifsPage(interaction, gifs, page) { - switch (buttonId) { - case 'prevGifsPage': - return 'previous'; - case 'nextGifsPage': - return 'next'; + gifsPage(interaction) { + let iStorage; + if (interaction.client.iStorage.has(interaction.message.interaction.id)) { + iStorage = interaction.client.iStorage.get(interaction.message.interaction.id) + } else { + iStorage = new InteractionStorage(interaction.message.interaction.id, interaction); + iStorage.page = 0; } + console.log('Beginning Page: ' + iStorage.page); + + switch (interaction.component.customId) { + case 'prevGifsPage': + if (iStorage.page > 0) { + iStorage.page = iStorage.page - 1; + } + break; + case 'nextGifsPage': + if (iStorage.page < interaction.client.gifs.size / 10) { + iStorage.page = iStorage.page + 1; + } + break; + default: + break; + } + const indexedGifs = indexer(interaction.client.gifs, iStorage.page); + indexedGifs.gifsString = new String(); + + for (const gif of indexedGifs.thisPage) { + indexedGifs.gifsString += `[${gif.name}.gif](${gif.url})\n`; + } + + console.log('Ending Page: ' + iStorage.page); + + interaction.update(fn.embeds.gifs({command: "/gifs", author: interaction.member.displayName}, indexedGifs)); } } \ No newline at end of file diff --git a/CustomModules/Embeds.js b/CustomModules/Embeds.js index cc057da..bbb9bb3 100644 --- a/CustomModules/Embeds.js +++ b/CustomModules/Embeds.js @@ -36,7 +36,7 @@ module.exports = { return new MessageActionRow() .addComponents(previousButton, confirmButton, nextButton, cancelButton); }, - gifsPageAR() { + gifsPageAR(state) { // Setup the buttons const previousButton = new MessageButton() .setCustomId('prevGifsPage') @@ -48,6 +48,15 @@ module.exports = { .setLabel('➡️') .setStyle('SECONDARY'); + switch (state) { + case 'first': + previousButton.setDisabled(true); + break; + case 'last': + nextButton.setDisabled(true); + break; + } + // Put the buttons into an ActionRow return new MessageActionRow() .addComponents(previousButton, nextButton); diff --git a/CustomModules/Indexer.js b/CustomModules/Indexer.js index 8a3960f..dacb3bb 100644 --- a/CustomModules/Indexer.js +++ b/CustomModules/Indexer.js @@ -26,6 +26,7 @@ module.exports = (collection, page) => { return { state: state, thisPage: thisPage, - pages: `Page ${page + 1}/${totalPages}` + totalPages: totalPages, + pagesString: `${page + 1}/${totalPages}` }; } \ No newline at end of file diff --git a/CustomModules/InteractionStorage.js b/CustomModules/InteractionStorage.js index d5cf06a..e1ace19 100644 --- a/CustomModules/InteractionStorage.js +++ b/CustomModules/InteractionStorage.js @@ -7,6 +7,7 @@ module.exports = class InteractionStorage { // Delete this from the interactionStorage after 5 minutes setTimeout(() => { + console.log(`Deleting interactionStorage with id: ${idString}`); interaction.client.iStorage.delete(idString); }, 300000); diff --git a/functions.js b/functions.js index 15a5e5a..f2e2507 100644 --- a/functions.js +++ b/functions.js @@ -49,7 +49,7 @@ const functions = { if (!client.iStorage) client.iStorage = new Discord.Collection(); client.iStorage.clear(); if (isDev) console.log('Interaction Storage Collection Built'); - } + }, // Create the collection of slash commands slashCommands(client) { if (!client.slashCommands) client.slashCommands = new Discord.Collection(); @@ -267,14 +267,14 @@ const functions = { return { embeds: [pastasEmbed], ephemeral: true }; }, - gifs(commandData, gifsString, state) { + gifs(commandData, indexedGifs) { const gifsEmbed = new Discord.MessageEmbed() .setAuthor({name: commandData.command}) .setTimestamp() - .setFooter({text: commandData.author}) - .setDescription(gifsString); + .setFooter({text: `Page: ${indexedGifs.pagesString}`}) + .setDescription(indexedGifs.gifsString); - const gifsPageAR = customEmbeds.gifsPageAR(state); + const gifsPageAR = customEmbeds.gifsPageAR(indexedGifs.state); return { embeds: [gifsEmbed], components: [gifsPageAR], ephemeral: true }; }, text(commandData) { @@ -599,38 +599,6 @@ const functions = { } } }, - openAI: { - chatPrompt(userPrompt) { - return new Promise(async (resolve, reject) => { - const response = await openai.chat.completions.create({ - messages: [{ - role: 'user', - content: userPrompt - }], - model: strings.ai.chatModel - }).catch(e => { - reject(e); - return null; - }); - resolve(response); - }); - }, - imagePrompt(userPrompt, size, userId) { - return new Promise(async (resolve, reject) => { - try { - const response = await openai.createImage({ - prompt: userPrompt, - size: size, - user: userId - }); - resolve(response.data.data[0].url); - } catch (e) { - reject(e); - return; - } - }); - } - }, search: { gifs(query, client) { const gifSearcher = new FuzzySearch(client.gifs.map(element => element.name)); diff --git a/main.js b/main.js index 304c7be..147f500 100644 --- a/main.js +++ b/main.js @@ -57,14 +57,12 @@ client.once('ready', async () => { client.on('interactionCreate', async interaction => { if (interaction.isCommand()) { if (isDev) { - console.log(interaction); + console.log('Interaction ID: ' + interaction.id); } const { commandName } = interaction; - const idString = `${interaction.channelId}${interaction.member.id}`; - - if (!client.interactionStorage.has(idString)) { - new InteractionStorage(idString, interaction); + if (!client.iStorage.has(interaction.id)) { + new InteractionStorage(interaction.id, interaction); } if (client.slashCommands.has(commandName)) { @@ -76,7 +74,8 @@ client.on('interactionCreate', async interaction => { } if (interaction.isButton()) { - if (isDev) console.log(interaction.id); + if (isDev) console.log('Origin Interaction ID: ' + interaction.message.interaction.id); + if (isDev) console.log('Button ID: ' + interaction.component.customId); // Get some meta info from strings const index = strings.temp.gifIndex; const limit = strings.temp.gifLimit; diff --git a/slash-commands/gifs.js b/slash-commands/gifs.js index 00a30f0..51d1d9d 100644 --- a/slash-commands/gifs.js +++ b/slash-commands/gifs.js @@ -13,17 +13,20 @@ module.exports = { interaction.reply('For some reason I don\'t have access to the collection of gifs. Sorry about that!'); resolve(); } - let gifList = indexer(interaction.client.gifs, 0); - let gifsString = new String(); + let iStorage = interaction.client.iStorage.get(interaction.id); + let indexedGifs = indexer(interaction.client.gifs, 0); + indexedGifs.gifsString = new String(); - for (const gif of gifList.thisPage) { - gifsString += `[${gif.name}.gif](${gif.url})\n`; + iStorage.page = 0; + + for (const gif of indexedGifs.thisPage) { + indexedGifs.gifsString += `[${gif.name}.gif](${gif.url})\n`; } const commandData = { command: "/gifs", author: interaction.member.displayName }; - interaction.reply(fn.embeds.gifs(commandData, gifsString, gifList.state)); + interaction.reply(fn.embeds.gifs(commandData, indexedGifs)); }); }, }; \ No newline at end of file From 709c8cfab7037ee494e9296a2438b0aaac338563 Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Thu, 26 Sep 2024 08:27:11 -0400 Subject: [PATCH 68/79] MVP for paged /pastas --- CustomModules/ButtonHandlers.js | 51 +++++++++++++++++++++++------ CustomModules/Embeds.js | 21 ++++++------ CustomModules/InteractionStorage.js | 1 + functions.js | 16 +++------ slash-commands/gifs.js | 36 ++++++++++---------- slash-commands/pastas.js | 31 ++++++++---------- 6 files changed, 88 insertions(+), 68 deletions(-) diff --git a/CustomModules/ButtonHandlers.js b/CustomModules/ButtonHandlers.js index 4e9011f..d0682b8 100644 --- a/CustomModules/ButtonHandlers.js +++ b/CustomModules/ButtonHandlers.js @@ -5,6 +5,14 @@ const fn = require('../functions.js'); module.exports = { baseEvent(interaction) { + let iStorage; + if (interaction.client.iStorage.has(interaction.message.interaction.id)) { + iStorage = interaction.client.iStorage.get(interaction.message.interaction.id) + } else { + iStorage = new InteractionStorage(interaction.message.interaction.id, interaction); + iStorage.page = 0; + } + if (interaction.user.id !== iStorage.userId) return; switch (interaction.component.customId) { // Any of the gifsPage Buttons case 'prevGifsPage': @@ -13,19 +21,18 @@ module.exports = { case 'nextGifsPage': module.exports.gifsPage(interaction); break; + case 'prevPastasPage': + module.exports.pastasPage(interaction); + break; + case 'nextPastasPage': + module.exports.pastasPage(interaction); + break; default: return; } }, gifsPage(interaction) { - let iStorage; - if (interaction.client.iStorage.has(interaction.message.interaction.id)) { - iStorage = interaction.client.iStorage.get(interaction.message.interaction.id) - } else { - iStorage = new InteractionStorage(interaction.message.interaction.id, interaction); - iStorage.page = 0; - } - console.log('Beginning Page: ' + iStorage.page); + const iStorage = interaction.client.iStorage.get(interaction.message.interaction.id); switch (interaction.component.customId) { case 'prevGifsPage': @@ -48,8 +55,32 @@ module.exports = { indexedGifs.gifsString += `[${gif.name}.gif](${gif.url})\n`; } - console.log('Ending Page: ' + iStorage.page); - interaction.update(fn.embeds.gifs({command: "/gifs", author: interaction.member.displayName}, indexedGifs)); + }, + pastasPage(interaction) { + const iStorage = interaction.client.iStorage.get(interaction.message.interaction.id); + + switch (interaction.component.customId) { + case 'prevPastasPage': + if (iStorage.page > 0) { + iStorage.page = iStorage.page - 1; + } + break; + case 'nextPastasPage': + if (iStorage.page < interaction.client.pastas.size / 10) { + iStorage.page = iStorage.page + 1; + } + break; + default: + break; + } + const indexedPastas = indexer(interaction.client.pastas, iStorage.page); + indexedPastas.pastasString = new String(); + + for (const pasta of indexedPastas.thisPage) { + indexedPastas.pastasString += `${pasta.name}.pasta\n`; + } + + interaction.update(fn.embeds.pastas({command: "/pastas", author: interaction.member.displayName}, indexedPastas)); } } \ No newline at end of file diff --git a/CustomModules/Embeds.js b/CustomModules/Embeds.js index bbb9bb3..036eb9b 100644 --- a/CustomModules/Embeds.js +++ b/CustomModules/Embeds.js @@ -87,30 +87,29 @@ module.exports = { return new MessageActionRow() .addComponents(previousButton, confirmButton, nextButton, cancelButton); }, - pastasPageAR() { + pastasPageAR(state) { // Setup the buttons const previousButton = new MessageButton() .setCustomId('prevPastasPage') .setLabel('⬅️') .setStyle('SECONDARY'); - const confirmButton = new MessageButton() - .setCustomId('confirmPastasPage') - .setLabel('✅') - .setStyle('PRIMARY'); - const nextButton = new MessageButton() .setCustomId('nextPastasPage') .setLabel('➡️') .setStyle('SECONDARY'); - const cancelButton = new MessageButton() - .setCustomId('cancelPastasPage') - .setLabel('❌') - .setStyle('DANGER'); + switch (state) { + case 'first': + previousButton.setDisabled(true); + break; + case 'last': + nextButton.setDisabled(true); + break; + } // Put the buttons into an ActionRow return new MessageActionRow() - .addComponents(previousButton, confirmButton, nextButton, cancelButton); + .addComponents(previousButton, nextButton); } } \ No newline at end of file diff --git a/CustomModules/InteractionStorage.js b/CustomModules/InteractionStorage.js index e1ace19..6103ecd 100644 --- a/CustomModules/InteractionStorage.js +++ b/CustomModules/InteractionStorage.js @@ -1,6 +1,7 @@ module.exports = class InteractionStorage { constructor(idString, interaction) { this.idString = idString; + this.userId = interaction.user.id; // Store in the client interaction.client.iStorage.set(idString, this); diff --git a/functions.js b/functions.js index f2e2507..7099c30 100644 --- a/functions.js +++ b/functions.js @@ -251,21 +251,15 @@ const functions = { .setTimestamp() .setFooter({text: commandData.author})]}; }, - pastas(commandData) { - const pastasArray = []; + pastas(commandData, indexedPastas) { const pastasEmbed = new Discord.MessageEmbed() .setAuthor({name: commandData.command}) .setTimestamp() - .setFooter({text: commandData.author}); + .setFooter({text: `Page: ${indexedPastas.pagesString}`}) + .setDescription(indexedPastas.pastasString); - for (const row of commandData.pastas) { - pastasArray.push(`#${row.id} - ${row.name}.pasta`); - } - - const pastasString = pastasArray.join('\n'); - pastasEmbed.setDescription(pastasString); - - return { embeds: [pastasEmbed], ephemeral: true }; + const pastasPageAR = customEmbeds.pastasPageAR(indexedPastas.state); + return { embeds: [pastasEmbed], components: [pastasPageAR], ephemeral: true }; }, gifs(commandData, indexedGifs) { const gifsEmbed = new Discord.MessageEmbed() diff --git a/slash-commands/gifs.js b/slash-commands/gifs.js index 51d1d9d..c372cc0 100644 --- a/slash-commands/gifs.js +++ b/slash-commands/gifs.js @@ -8,25 +8,23 @@ module.exports = { .setName('gifs') .setDescription('Get a list of currently saved GIFs.'), execute(interaction) { - return new Promise((resolve, reject) => { - if (!interaction.client.gifs) { - interaction.reply('For some reason I don\'t have access to the collection of gifs. Sorry about that!'); - resolve(); - } - let iStorage = interaction.client.iStorage.get(interaction.id); - let indexedGifs = indexer(interaction.client.gifs, 0); - indexedGifs.gifsString = new String(); + if (!interaction.client.gifs) { + interaction.reply('For some reason I don\'t have access to the collection of gifs. Sorry about that!'); + return; + } + let iStorage = interaction.client.iStorage.get(interaction.id); + let indexedGifs = indexer(interaction.client.gifs, 0); + indexedGifs.gifsString = new String(); - iStorage.page = 0; + iStorage.page = 0; - for (const gif of indexedGifs.thisPage) { - indexedGifs.gifsString += `[${gif.name}.gif](${gif.url})\n`; - } - const commandData = { - command: "/gifs", - author: interaction.member.displayName - }; - interaction.reply(fn.embeds.gifs(commandData, indexedGifs)); - }); - }, + for (const gif of indexedGifs.thisPage) { + indexedGifs.gifsString += `[${gif.name}.gif](${gif.url})\n`; + } + const commandData = { + command: "/gifs", + author: interaction.member.displayName + }; + interaction.reply(fn.embeds.gifs(commandData, indexedGifs)); + } }; \ No newline at end of file diff --git a/slash-commands/pastas.js b/slash-commands/pastas.js index baeb52d..8d43578 100644 --- a/slash-commands/pastas.js +++ b/slash-commands/pastas.js @@ -1,6 +1,7 @@ const { SlashCommandBuilder } = require('@discordjs/builders'); const { config } = require('dotenv'); const fn = require('../functions.js'); +const indexer = require('../CustomModules/Indexer.js'); module.exports = { data: new SlashCommandBuilder() @@ -11,23 +12,19 @@ module.exports = { interaction.reply({ content: 'For some reason I don\'t have access to the collection of copypastas. Sorry about that!', ephemeral: true }); return; } - const commandData = { - author: interaction.user.tag, - command: interaction.commandName, - pastas: [], - }; - const pastasMap = interaction.client.pastas.map(e => { - return { - id: e.id, - name: e.name, - }; - }); - for (const row of pastasMap) { - commandData.pastas.push({ - id: row.id, - name: row.name, - }); + let iStorage = interaction.client.iStorage.get(interaction.id); + let indexedPastas = indexer(interaction.client.pastas, 0); + indexedPastas.pastasString = new String(); + + iStorage.page = 0; + + for (const pasta of indexedPastas.thisPage) { + indexedPastas.pastasString += `${pasta.name}.pasta\n`; } - interaction.reply(fn.embeds.pastas(commandData)); + const commandData = { + command: "/pastas", + author: interaction.member.displayName + }; + interaction.reply(fn.embeds.pastas(commandData, indexedPastas)); }, }; \ No newline at end of file From c3fa30ea649440b20585ea74cb7e2614d0c1bf13 Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Thu, 26 Sep 2024 08:37:16 -0400 Subject: [PATCH 69/79] MVP for paged /requests --- CustomModules/ButtonHandlers.js | 33 +++++++++++++++++++++++ CustomModules/Embeds.js | 21 +++++++-------- functions.js | 19 ++++--------- slash-commands/requests.js | 48 ++++++++++++++------------------- 4 files changed, 68 insertions(+), 53 deletions(-) diff --git a/CustomModules/ButtonHandlers.js b/CustomModules/ButtonHandlers.js index d0682b8..f28b878 100644 --- a/CustomModules/ButtonHandlers.js +++ b/CustomModules/ButtonHandlers.js @@ -2,6 +2,7 @@ const customEmbeds = require('../CustomModules/Embeds.js'); const InteractionStorage = require('../CustomModules/InteractionStorage.js'); const indexer = require('../CustomModules/Indexer.js'); const fn = require('../functions.js'); +const requests = require('../slash-commands/requests.js'); module.exports = { baseEvent(interaction) { @@ -27,6 +28,12 @@ module.exports = { case 'nextPastasPage': module.exports.pastasPage(interaction); break; + case 'prevRequestsPage': + module.exports.requestsPage(interaction); + break; + case 'nextRequestsPage': + module.exports.requestsPage(interaction); + break; default: return; } @@ -82,5 +89,31 @@ module.exports = { } interaction.update(fn.embeds.pastas({command: "/pastas", author: interaction.member.displayName}, indexedPastas)); + }, + requestsPage(interaction) { + const iStorage = interaction.client.iStorage.get(interaction.message.interaction.id); + + switch (interaction.component.customId) { + case 'prevRequestsPage': + if (iStorage.page > 0) { + iStorage.page = iStorage.page - 1; + } + break; + case 'nextRequestsPage': + if (iStorage.page < interaction.client.requests.size / 10) { + iStorage.page = iStorage.page + 1; + } + break; + default: + break; + } + const indexedRequests = indexer(interaction.client.requests, iStorage.page); + indexedRequests.requestsString = new String(); + + for (const request of indexedRequests.thisPage) { + indexedRequests.requestsString += `[${request.id}]: ${request.request} (submitted by ${request.author})\n`; + } + + interaction.update(fn.embeds.requests({command: "/requests", author: interaction.member.displayName}, indexedRequests)); } } \ No newline at end of file diff --git a/CustomModules/Embeds.js b/CustomModules/Embeds.js index 036eb9b..3264174 100644 --- a/CustomModules/Embeds.js +++ b/CustomModules/Embeds.js @@ -61,31 +61,30 @@ module.exports = { return new MessageActionRow() .addComponents(previousButton, nextButton); }, - requestsPageAR() { + requestsPageAR(state) { // Setup the buttons const previousButton = new MessageButton() .setCustomId('prevRequestsPage') .setLabel('⬅️') .setStyle('SECONDARY'); - const confirmButton = new MessageButton() - .setCustomId('confirmRequestsPage') - .setLabel('✅') - .setStyle('PRIMARY'); - const nextButton = new MessageButton() .setCustomId('nextRequestsPage') .setLabel('➡️') .setStyle('SECONDARY'); - const cancelButton = new MessageButton() - .setCustomId('cancelRequestsPage') - .setLabel('❌') - .setStyle('DANGER'); + switch (state) { + case 'first': + previousButton.setDisabled(true); + break; + case 'last': + nextButton.setDisabled(true); + break; + } // Put the buttons into an ActionRow return new MessageActionRow() - .addComponents(previousButton, confirmButton, nextButton, cancelButton); + .addComponents(previousButton, nextButton); }, pastasPageAR(state) { // Setup the buttons diff --git a/functions.js b/functions.js index 7099c30..15b8caa 100644 --- a/functions.js +++ b/functions.js @@ -278,24 +278,15 @@ const functions = { .setTimestamp() .setFooter({text: commandData.author})]}; }, - requests(commandData) { + requests(commandData, indexedRequests) { const requestsEmbed = new Discord.MessageEmbed() .setAuthor({name: commandData.command}) .setTimestamp() - .setFooter({text: commandData.author}); + .setFooter({text: `Page: ${indexedRequests.pagesString}`}) + .setDescription(indexedRequests.requestsString); - const requestsArray = []; - - for (const row of commandData.requests) { - requestsArray.push( - `**#${row.id} - ${row.author}**`, - `Request: ${row.request}` - ); - } - - requestsEmbed.setDescription(requestsArray.join('\n')); - - return { embeds: [requestsEmbed], ephemeral: true }; + const requestsPageAR = customEmbeds.requestsPageAR(indexedRequests.state); + return { embeds: [requestsEmbed], components: [requestsPageAR], ephemeral: true }; }, strain(strainInfo, interaction) { const strainEmbed = new Discord.MessageEmbed() diff --git a/slash-commands/requests.js b/slash-commands/requests.js index 039504e..fbc8b3b 100644 --- a/slash-commands/requests.js +++ b/slash-commands/requests.js @@ -1,39 +1,31 @@ const { SlashCommandBuilder } = require('@discordjs/builders'); const { config } = require('dotenv'); const fn = require('../functions.js'); +const indexer = require('../CustomModules/Indexer.js'); module.exports = { data: new SlashCommandBuilder() .setName('requests') - .setDescription('Get a list of Active requests from the database') - .addStringOption(option => - option - .setName('page') - .setDescription('Page Number') - .setRequired(true)), + .setDescription('Get a list of Active requests from the database'), async execute(interaction) { - const pageNum = interaction.options.getString('page'); - const commandData = { - author: interaction.user.tag, - command: interaction.commandName, - requests: [], - }; - const requestsMap = interaction.client.requests.map(e => { - return { - id: e.id, - author: e.author, - request: e.request, - }; - }); - for (let i = ( 10 * ( pageNum - 1 ) ); i < ( 10 * pageNum ); i++) { - if (requestsMap[i] != undefined) { - commandData.requests.push({ - id: requestsMap[i].id, - author: requestsMap[i].author, - request: requestsMap[i].request, - }); - } + if (!interaction.client.requests) { + interaction.reply('For some reason I don\'t have access to the collection of requests. Sorry about that!'); + return; } - interaction.reply(fn.embeds.requests(commandData)); + let iStorage = interaction.client.iStorage.get(interaction.id); + let indexedRequests = indexer(interaction.client.requests, 0); + indexedRequests.requestsString = new String(); + + iStorage.page = 0; + + for (const request of indexedRequests.thisPage) { + indexedRequests.requestsString += `[${request.id}]: ${request.request} (submitted by ${request.author})\n`; + } + + const commandData = { + command: "/requests", + author: interaction.member.displayName + }; + interaction.reply(fn.embeds.requests(commandData, indexedRequests)); }, }; \ No newline at end of file From d0528c36377073dbb37d1e2fa0754568bc298f2b Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Thu, 26 Sep 2024 08:47:42 -0400 Subject: [PATCH 70/79] MVP for paged /joints --- CustomModules/ButtonHandlers.js | 32 ++++++++++++++++++++++++++++++++ CustomModules/Embeds.js | 25 +++++++++++++++++++++++++ functions.js | 10 ++++++++++ slash-commands/joints.js | 24 +++++++++++++++++++----- 4 files changed, 86 insertions(+), 5 deletions(-) diff --git a/CustomModules/ButtonHandlers.js b/CustomModules/ButtonHandlers.js index f28b878..cf3d6d9 100644 --- a/CustomModules/ButtonHandlers.js +++ b/CustomModules/ButtonHandlers.js @@ -34,6 +34,12 @@ module.exports = { case 'nextRequestsPage': module.exports.requestsPage(interaction); break; + case 'prevJointsPage': + module.exports.jointsPage(interaction); + break; + case 'nextJointsPage': + module.exports.jointsPage(interaction); + break; default: return; } @@ -115,5 +121,31 @@ module.exports = { } interaction.update(fn.embeds.requests({command: "/requests", author: interaction.member.displayName}, indexedRequests)); + }, + jointsPage(interaction) { + const iStorage = interaction.client.iStorage.get(interaction.message.interaction.id); + + switch (interaction.component.customId) { + case 'prevJointsPage': + if (iStorage.page > 0) { + iStorage.page = iStorage.page - 1; + } + break; + case 'nextJointsPage': + if (iStorage.page < interaction.client.joints.size / 10) { + iStorage.page = iStorage.page + 1; + } + break; + default: + break; + } + const indexedJoints = indexer(interaction.client.joints, iStorage.page); + indexedJoints.jointsString = new String(); + + for (const joint of indexedJoints.thisPage) { + indexedJoints.jointsString += `${joint.content}\n`; + } + + interaction.update(fn.embeds.joints({command: "/joints", author: interaction.member.displayName}, indexedJoints)); } } \ No newline at end of file diff --git a/CustomModules/Embeds.js b/CustomModules/Embeds.js index 3264174..115e66a 100644 --- a/CustomModules/Embeds.js +++ b/CustomModules/Embeds.js @@ -107,6 +107,31 @@ module.exports = { break; } + // Put the buttons into an ActionRow + return new MessageActionRow() + .addComponents(previousButton, nextButton); + }, + jointsPageAR(state) { + // Setup the buttons + const previousButton = new MessageButton() + .setCustomId('prevJointsPage') + .setLabel('⬅️') + .setStyle('SECONDARY'); + + const nextButton = new MessageButton() + .setCustomId('nextJointsPage') + .setLabel('➡️') + .setStyle('SECONDARY'); + + switch (state) { + case 'first': + previousButton.setDisabled(true); + break; + case 'last': + nextButton.setDisabled(true); + break; + } + // Put the buttons into an ActionRow return new MessageActionRow() .addComponents(previousButton, nextButton); diff --git a/functions.js b/functions.js index 15b8caa..f606849 100644 --- a/functions.js +++ b/functions.js @@ -271,6 +271,16 @@ const functions = { const gifsPageAR = customEmbeds.gifsPageAR(indexedGifs.state); return { embeds: [gifsEmbed], components: [gifsPageAR], ephemeral: true }; }, + joints(commandData, indexedJoints) { + const jointsEmbed = new Discord.MessageEmbed() + .setAuthor({name: commandData.command}) + .setTimestamp() + .setFooter({text: `Page: ${indexedJoints.pagesString}`}) + .setDescription(indexedJoints.jointsString); + + const jointsPageAR = customEmbeds.jointsPageAR(indexedJoints.state); + return { embeds: [jointsEmbed], components: [jointsPageAR], ephemeral: true }; + }, text(commandData) { return { embeds: [new Discord.MessageEmbed() .setAuthor({name: commandData.command}) diff --git a/slash-commands/joints.js b/slash-commands/joints.js index 2ca5b6c..bca4490 100644 --- a/slash-commands/joints.js +++ b/slash-commands/joints.js @@ -1,15 +1,29 @@ const { SlashCommandBuilder } = require('@discordjs/builders'); const fn = require('../functions.js'); +const indexer = require('../CustomModules/Indexer.js'); module.exports = { data: new SlashCommandBuilder() .setName('joints') .setDescription('Send a list of all the /joint phrases.'), async execute(interaction) { - let joints = []; - interaction.client.joints.map(e => { - joints.push(e.content); - }); - interaction.reply({ content: 'Here are all the `.joint` phrases I have saved:\n\n' + joints.join('\n'), ephemeral: true }); + if (!interaction.client.joints) { + interaction.reply('For some reason I don\'t have access to the collection of joints. Sorry about that!'); + return; + } + let iStorage = interaction.client.iStorage.get(interaction.id); + let indexedJoints = indexer(interaction.client.joints, 0); + indexedJoints.jointsString = new String(); + + iStorage.page = 0; + + for (const joint of indexedJoints.thisPage) { + indexedJoints.jointsString += `${joint.content}\n`; + } + const commandData = { + command: "/joints", + author: interaction.member.displayName + }; + interaction.reply(fn.embeds.joints(commandData, indexedJoints)); }, }; \ No newline at end of file From 4b75dfa88558d759d61b4a1d16d8a43921f901b0 Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Thu, 26 Sep 2024 09:07:20 -0400 Subject: [PATCH 71/79] v3.3.3 Documentation --- CHANGELOG.md | 23 +++++++++++++++++++++++ README.md | 33 +-------------------------------- Roadmap.md | 14 -------------- 3 files changed, 24 insertions(+), 46 deletions(-) create mode 100644 CHANGELOG.md delete mode 100644 Roadmap.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..a666790 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,23 @@ +## v3.3.x +#### v3.3.3 (#20) +* Fixed content-list slash commands `/gifs`, `/pastas`, `/joints`, `/requests` (#19) +* Fixed the creation of duplicate commands properly (#18) +* Added a ton of aliases for `.gif` (`.wav`, `.mp3`, `.mp4`, `.wmv`, etc.) + +#### v3.3.2 (#17) +* Fixed the `/help` command to not crash the bot (#15) +* Filtered out duplicate commands from the `/help` list, temporary fix (#18) +* Removed instances of `MessageEmbed.addField` due to deprecation (#16) + +v3.3.1 - Polishing and bugfixing for new AvWx commands +v3.3.0 - Added `.metar`, `.atis`, and `.datis` AvWx commands + +## v3.0.x +v3.0.1 - Migrate TenorJS API Endpoint +v3.0.2 - Add medical advice commands +v3.0.3 - Fix broken `/requests` command +v3.0.4 - Add ability to use multiple aliases +v3.0.5 - Add ability to save strains +v3.0.6 - Move `.strain` to `/strain` and add Autocomplete +v3.0.7 - Add `.spongebob` replies +v3.0.8 - Add ability to open requests by pages \ No newline at end of file diff --git a/README.md b/README.md index 7b473ee..799bc87 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,6 @@ # About Nodbot Nodbot is a content saving and serving Discord bot. Nodbot is able to search Tenor for GIFs, save custom copypastas, and look up marijuana strain information. Nodbot is in semi-active development by voidf1sh. It's buggy as hell and very shoddily built. Don't use it. -# Status -This should be ready to merge into `main`, let it run a couple days with testing before creating a PR. METAR and D-ATIS are implemented. TAFs will come later as they're more complicated. - # Nodbot Help Use the `/help` command to see the bot's help message. @@ -14,16 +11,6 @@ Use the `/help` command to see the bot's help message. ## Push Docker Image `docker push name/nodbot` -# Immediate To-Do - -1. ~~Sanitize inputs for SQL queries.~~ -2. ~~Move environment variables so they don't get included in the image.~~ -3. Implement error handling on all actions. -4. ~~Ephemeral responses to some/most slash commands.~~ -5. Comment the code! Document! -6. Check for and create database tables if necessary. Handle errors. -7. Readjust keyword autoresponses to be more generic instead of hard coded - # Deploy NodBot Yourself 1. Create an application at the [Discord Developer Portal](https://discord.com/developers/applications) @@ -35,13 +22,6 @@ Use the `/help` command to see the bot's help message. 6. Configure your environment variables as outlined below. 7. Fire it up with `node main.js` -# Recent Changes - -* Added METAR via AviationWeather.gov API -* Added D-ATIS via datis.clowd.io API -* Updated how keyword autoresponses are handled -* Changed `.joint` to reduce duplication and repetition by implementing an Ashtray and Roaches - ## Table Structure ``` @@ -108,15 +88,4 @@ tenorAPIKey= ownerId= statusChannelId= clientId= -``` - -## Changes - -v3.0.1 - Migrate TenorJS API Endpoint -v3.0.2 - Add medical advice commands -v3.0.3 - Fix broken `/requests` command -v3.0.4 - Add ability to use multiple aliases -v3.0.5 - Add ability to save strains -v3.0.6 - Move `.strain` to `/strain` and add Autocomplete -v3.0.7 - Add `.spongebob` replies -v3.0.8 - Add ability to open requests by pages \ No newline at end of file +``` \ No newline at end of file diff --git a/Roadmap.md b/Roadmap.md deleted file mode 100644 index 80bce7b..0000000 --- a/Roadmap.md +++ /dev/null @@ -1,14 +0,0 @@ -# v3.1.0 - -* Name checking for saving content -* .jpg, .wav -* Audio/Video attachments for saved content. -* Pass The Joint -* Voting system for Super Adventure Club - -# v4.0.0 -* Scalability: modify the code to allow the bot to be used in multiple servers - * including saved content, saved commands, preferences, etc. - -# v3.?.? -= Joke generator for Hallihan \ No newline at end of file From 09901b5e58ba146e47868ca040b5c56f0692645e Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Thu, 26 Sep 2024 09:07:26 -0400 Subject: [PATCH 72/79] Add aliases --- dot-commands/gif.js | 1 + 1 file changed, 1 insertion(+) diff --git a/dot-commands/gif.js b/dot-commands/gif.js index b9f746a..dc2ff98 100644 --- a/dot-commands/gif.js +++ b/dot-commands/gif.js @@ -9,6 +9,7 @@ const dotenv = require('dotenv').config(); module.exports = { name: 'gif', description: 'Send a GIF', + alias: ['jpg', 'png', 'gifv', 'webm', 'mp4', 'wav', 'wmv', 'webp', 'mp3', 'flac', 'ogg', 'avi', 'mov', 'mpg', 'mpeg', 'mkv', 'flv', 'bmp', 'tiff', 'tif', 'svg', 'ico'], usage: '.gif', async execute(message, commandData) { // if (message.deletable) message.delete(); From 8148890574a17a3c0e24da855e6d650b3f6cd04c Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Thu, 26 Sep 2024 09:22:16 -0400 Subject: [PATCH 73/79] Add listing of aliases to /help --- functions.js | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/functions.js b/functions.js index f606849..7d8a1b2 100644 --- a/functions.js +++ b/functions.js @@ -185,10 +185,11 @@ const functions = { const slashCommandsMap = interaction.client.slashCommands.map(e => { if (!slashSeenNames.includes(e.data.name)) { slashSeenNames.push(e.data.name); - return { + const command = { name: e.data.name, description: e.data.description }; + return command; } else { return null; } @@ -204,18 +205,29 @@ const functions = { const dotCommandsMap = interaction.client.dotCommands.map(e => { if (!dotSeenNames.includes(e.name)) { dotSeenNames.push(e.name); - return { + let command = { name: e.name, description: e.description, usage: e.usage }; + command.aliasString = new String(); + if (e.alias != undefined && typeof e.alias === 'object') { + for (const a of e.alias) { + command.aliasString += `\`.${a}\`, `; + } + } else if (e.alias != undefined && typeof e.alias === 'string') { + command.aliasString += `\`.${e.alias}\``; + } else { + command.aliasString = 'None'; + } + return command; } else { return null; } }); for (const e of dotCommandsMap) { if (e != null) { - dotCommandsFields.push(`- \`.${e.name}\` - ${e.description} - ${e.usage}`); + dotCommandsFields.push(`- \`.${e.name}\` - ${e.description}\n\tUsage: ${e.usage}\n\tAliases: ${e.aliasString}`); } } console.log(dotCommandsFields); From 3a35b829adac6f7d22c7a6cb24abc70a3cb81d3f Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Thu, 26 Sep 2024 09:23:25 -0400 Subject: [PATCH 74/79] Documentation update, final for v.3.3.3 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a666790..4b83906 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ * Fixed content-list slash commands `/gifs`, `/pastas`, `/joints`, `/requests` (#19) * Fixed the creation of duplicate commands properly (#18) * Added a ton of aliases for `.gif` (`.wav`, `.mp3`, `.mp4`, `.wmv`, etc.) +* Added alias lists in `/help` #### v3.3.2 (#17) * Fixed the `/help` command to not crash the bot (#15) From ed315d0cb12436f341021ebd47392e3b387724ae Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Thu, 26 Sep 2024 09:43:05 -0400 Subject: [PATCH 75/79] Versioning -- v3.4.0 --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 8fcfff9..ed51b46 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "nodbot", - "version": "3.3.3", - "description": "Nods and Nod Accessories, now with ChatGPT!", + "version": "3.4.0", + "description": "Nods and Nod Accessories", "main": "main.js", "dependencies": { "@discordjs/builders": "^0.16.0", From 2cbfc7f35463f9db85c1d977d513bcc9e511c705 Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Thu, 26 Sep 2024 09:55:49 -0400 Subject: [PATCH 76/79] WIP DNU --- CustomModules/NodBot.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/CustomModules/NodBot.js b/CustomModules/NodBot.js index d18c21b..f1d3a4a 100644 --- a/CustomModules/NodBot.js +++ b/CustomModules/NodBot.js @@ -16,6 +16,17 @@ module.exports = { if (this.args.startsWith('http')) return false; if (this.args.startsWith('www')) return false; + // Check for and extract the part of the message that's + // wrapped in any type of brackets or quotes eg. ([{``''""}]) + const bracketStart = this.args.match(/[\[\(\{\`\'\"\`]/g); + const bracketEnd = this.args.match(/[\]\)\}\`\'\"\`]/g); + let bracketedText = new String(); + if ((bracketStart && bracketEnd) && (bracketStart.length !== bracketEnd.length)) { + bracketedText = this.args.slice(this.args.indexOf(bracketStart[0]), this.args.lastIndexOf(bracketEnd[0]) + 1); + this.args = this.args.replace(bracketedText, ''); + } + console.log(bracketedText); + for (const [key, value] of dotCommands) { if (key === this.command) { this.isValid = true; From e4fbcca6c43acdbc735fd5a7dc00b78168945b8c Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Thu, 26 Sep 2024 14:20:56 -0400 Subject: [PATCH 77/79] MVP for nested commands --- CustomModules/NodBot.js | 108 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 97 insertions(+), 11 deletions(-) diff --git a/CustomModules/NodBot.js b/CustomModules/NodBot.js index f1d3a4a..9b993c3 100644 --- a/CustomModules/NodBot.js +++ b/CustomModules/NodBot.js @@ -8,6 +8,7 @@ module.exports = { this.args = message.content.slice(0,this.finalPeriod).toLowerCase(); // Grab everything leading up to the final period this.command = message.content.slice(this.finalPeriod + 1).toLowerCase(); // Grab everything after the final period this.author = message.author.username; + this.message = message; return this; } @@ -16,25 +17,110 @@ module.exports = { if (this.args.startsWith('http')) return false; if (this.args.startsWith('www')) return false; + const indices = { + curlyBrace: { + start: -1, + end: -1 + }, + bracket: { + start: -1, + end: -1 + }, + parenthesis: { + start: -1, + end: -1 + } + } + // Check for and extract the part of the message that's // wrapped in any type of brackets or quotes eg. ([{``''""}]) - const bracketStart = this.args.match(/[\[\(\{\`\'\"\`]/g); - const bracketEnd = this.args.match(/[\]\)\}\`\'\"\`]/g); - let bracketedText = new String(); - if ((bracketStart && bracketEnd) && (bracketStart.length !== bracketEnd.length)) { - bracketedText = this.args.slice(this.args.indexOf(bracketStart[0]), this.args.lastIndexOf(bracketEnd[0]) + 1); - this.args = this.args.replace(bracketedText, ''); + const curlyBraceStart = this.message.content.match(/[\{]/g); + const curlyBraceEnd = this.message.content.match(/[\}]/g); + if (curlyBraceStart && curlyBraceEnd) { + indices.curlyBrace.start = this.message.content.indexOf(curlyBraceStart[0]) + 1; + indices.curlyBrace.end = this.message.content.lastIndexOf(curlyBraceEnd[0]); + } + + const bracketStart = this.message.content.match(/[\[]/g); + const bracketEnd = this.message.content.match(/[\]]/g); + if (bracketStart && bracketEnd) { + indices.bracket.start = this.message.content.indexOf(bracketStart[0]) + 1; + indices.bracket.end = this.message.content.lastIndexOf(bracketEnd[0]); + } + + const parenthesisStart = this.message.content.match(/[\(]/g); + const parenthesisEnd = this.message.content.match(/[\)]/g); + if (parenthesisStart && parenthesisEnd) { + indices.parenthesis.start = this.message.content.indexOf(parenthesisStart[0]) + 1; + indices.parenthesis.end = this.message.content.lastIndexOf(parenthesisEnd[0]); + } + + let nestedText = new String(); + + if (indices.curlyBrace.start >= 0 && indices.curlyBrace.end > 0) { + nestedText = this.message.content.slice(indices.curlyBrace.start, indices.curlyBrace.end); + } + + if (indices.bracket.start >= 0 && indices.bracket.end > 0) { + nestedText = this.message.content.slice(indices.bracket.start, indices.bracket.end); + } + + if (indices.parenthesis.start >= 0 && indices.parenthesis.end > 0) { + nestedText = this.message.content.slice(indices.parenthesis.start, indices.parenthesis.end); + } + + console.log(nestedText); + + if (nestedText !== "") { + this.nestedCommand = { + finalPeriod: nestedText.lastIndexOf('.'), + isCommand: nestedText.lastIndexOf('.') >= 0 ? true : false, + args: nestedText.slice(0, nestedText.lastIndexOf('.')).toLowerCase(), + command: nestedText.slice(nestedText.lastIndexOf('.') + 1).toLowerCase() + } + + for (const [key, value] of dotCommands) { + if (key === this.nestedCommand.command) { + this.isValid = true; + this.args = this.nestedCommand.args; + this.command = key; + this.isCommand = this.nestedCommand.isCommand; + this.finalPeriod = this.nestedCommand.finalPeriod; + return this; + } else if (value.alias) { + if (typeof value.alias === 'string' && value.alias === this.nestedCommand.command) { + this.command = key + this.args = this.nestedCommand.args; + this.isValid = true; + this.isCommand = this.nestedCommand.isCommand; + this.finalPeriod = this.nestedCommand.finalPeriod; + return this; + } else if (typeof value.alias === 'object' && value.alias.includes(this.nestedCommand.command)) { + this.command = key + this.args = this.nestedCommand.args; + this.isValid = true; + this.isCommand = this.nestedCommand.isCommand; + this.finalPeriod = this.nestedCommand.finalPeriod; + return this; + } + } + } } - console.log(bracketedText); for (const [key, value] of dotCommands) { if (key === this.command) { this.isValid = true; return this; - } else if (value.alias && value.alias.includes(this.command)) { - this.command = key; - this.isValid = true; - return this; + } else if (value.alias) { + if (typeof value.alias === 'string' && value.alias === this.command) { + this.command = key; + this.isValid = true; + return this; + } else if (typeof value.alias === 'object' && value.alias.includes(this.command)) { + this.command = key; + this.isValid = true; + return this; + } } } return this; From 8d5f75e471bc3621298178956404d021cc4579a4 Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Thu, 26 Sep 2024 14:25:22 -0400 Subject: [PATCH 78/79] Add nested commands --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b83906..fa31e1f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## v3.4.x +#### v3.4.0 +* Added nested commands, enclose a command in brackets, braces, or parenthesis inside a longer message: `You really don't get it do you? [that's the joke.gif] You're so dense` would return the results for just `that's the joke.gif` + ## v3.3.x #### v3.3.3 (#20) * Fixed content-list slash commands `/gifs`, `/pastas`, `/joints`, `/requests` (#19) From 6175a30974400e65f57ffc13ec4486fec1bcb625 Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Thu, 26 Sep 2024 14:28:11 -0400 Subject: [PATCH 79/79] Add PR tag # --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fa31e1f..5b969d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,5 @@ ## v3.4.x -#### v3.4.0 +#### v3.4.0 (#25) * Added nested commands, enclose a command in brackets, braces, or parenthesis inside a longer message: `You really don't get it do you? [that's the joke.gif] You're so dense` would return the results for just `that's the joke.gif` ## v3.3.x