Переделал фильтр чата: слова теперь в JSON, добавлен поиск по фрагментам, улучшена защита от обхода фильтра
This commit is contained in:
parent
2292137986
commit
cb60c29e91
4 changed files with 796 additions and 27 deletions
|
|
@ -3,7 +3,7 @@ plugins {
|
||||||
}
|
}
|
||||||
|
|
||||||
group = 'com.loki'
|
group = 'com.loki'
|
||||||
version = '1.5.3'
|
version = '1.5.4'
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
|
@ -17,6 +17,7 @@ dependencies {
|
||||||
compileOnly 'me.clip:placeholderapi:2.11.6'
|
compileOnly 'me.clip:placeholderapi:2.11.6'
|
||||||
compileOnly 'org.black_ixx:playerpoints:3.2.7'
|
compileOnly 'org.black_ixx:playerpoints:3.2.7'
|
||||||
compileOnly 'net.luckperms:api:5.4'
|
compileOnly 'net.luckperms:api:5.4'
|
||||||
|
implementation 'com.google.code.gson:gson:2.10.1'
|
||||||
|
|
||||||
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.10.0'
|
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.10.0'
|
||||||
testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.10.0'
|
testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.10.0'
|
||||||
|
|
@ -42,7 +43,7 @@ test {
|
||||||
}
|
}
|
||||||
|
|
||||||
jar {
|
jar {
|
||||||
archiveFileName = 'LoChat-1.5.3.jar'
|
archiveFileName = 'LoChat-1.5.4.jar'
|
||||||
from {
|
from {
|
||||||
configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
|
configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -126,6 +126,9 @@ public final class LoChat extends JavaPlugin {
|
||||||
if (customCommandManager != null) {
|
if (customCommandManager != null) {
|
||||||
customCommandManager.reload();
|
customCommandManager.reload();
|
||||||
}
|
}
|
||||||
|
if (filterManager != null) {
|
||||||
|
filterManager.reload();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LoChat getInstance() {
|
public static LoChat getInstance() {
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,111 @@
|
||||||
package com.loki.lochat.managers;
|
package com.loki.lochat.managers;
|
||||||
|
|
||||||
|
import com.google.gson.JsonArray;
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonParser;
|
||||||
import com.loki.lochat.LoChat;
|
import com.loki.lochat.LoChat;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileReader;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
public class FilterManager {
|
public class FilterManager {
|
||||||
|
|
||||||
private final LoChat plugin;
|
private final LoChat plugin;
|
||||||
|
private List<String> badWords = new ArrayList<>();
|
||||||
|
private List<String> fragments = new ArrayList<>();
|
||||||
|
|
||||||
public FilterManager(LoChat plugin) {
|
public FilterManager(LoChat plugin) {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
|
loadFilterWords();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Загружает плохие слова из JSON файла
|
||||||
|
*/
|
||||||
|
private void loadFilterWords() {
|
||||||
|
badWords.clear();
|
||||||
|
fragments.clear();
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Сначала пытаемся загрузить из data folder (если есть кастомный)
|
||||||
|
File customFile = new File(plugin.getDataFolder(), "filter-words.json");
|
||||||
|
if (customFile.exists()) {
|
||||||
|
try (FileReader reader = new FileReader(customFile, StandardCharsets.UTF_8)) {
|
||||||
|
JsonObject json = JsonParser.parseReader(reader).getAsJsonObject();
|
||||||
|
loadFromJsonObject(json);
|
||||||
|
plugin.getLogger().info("Загружены плохие слова из filter-words.json (data folder): " + badWords.size() + " слов, " + fragments.size() + " фрагментов");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Если кастомного нет, копируем из ресурсов
|
||||||
|
plugin.saveResource("filter-words.json", false);
|
||||||
|
|
||||||
|
// Теперь загружаем из data folder
|
||||||
|
if (customFile.exists()) {
|
||||||
|
try (FileReader reader = new FileReader(customFile, StandardCharsets.UTF_8)) {
|
||||||
|
JsonObject json = JsonParser.parseReader(reader).getAsJsonObject();
|
||||||
|
loadFromJsonObject(json);
|
||||||
|
plugin.getLogger().info("Загружено " + badWords.size() + " плохих слов и " + fragments.size() + " фрагментов из filter-words.json");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback на старый способ из config.yml
|
||||||
|
List<String> configWords = plugin.getConfigManager().getFilterWords();
|
||||||
|
if (configWords != null && !configWords.isEmpty()) {
|
||||||
|
badWords.addAll(configWords);
|
||||||
|
plugin.getLogger().warning("Используются слова из config.yml (filter-words.json не найден)");
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
plugin.getLogger().severe("Ошибка загрузки filter-words.json: " + e.getMessage());
|
||||||
|
e.printStackTrace();
|
||||||
|
// Fallback на старый способ
|
||||||
|
List<String> configWords = plugin.getConfigManager().getFilterWords();
|
||||||
|
if (configWords != null && !configWords.isEmpty()) {
|
||||||
|
badWords.addAll(configWords);
|
||||||
|
plugin.getLogger().info("Используются слова из config.yml (fallback)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Загружает данные из JSON объекта
|
||||||
|
*/
|
||||||
|
private void loadFromJsonObject(JsonObject json) {
|
||||||
|
if (json.has("words")) {
|
||||||
|
JsonArray wordsArray = json.getAsJsonArray("words");
|
||||||
|
for (JsonElement element : wordsArray) {
|
||||||
|
String word = element.getAsString();
|
||||||
|
if (word != null && !word.trim().isEmpty()) {
|
||||||
|
badWords.add(word.trim().toLowerCase());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json.has("fragments")) {
|
||||||
|
JsonArray fragmentsArray = json.getAsJsonArray("fragments");
|
||||||
|
for (JsonElement element : fragmentsArray) {
|
||||||
|
String fragment = element.getAsString();
|
||||||
|
if (fragment != null && !fragment.trim().isEmpty()) {
|
||||||
|
fragments.add(fragment.trim().toLowerCase());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Перезагружает список плохих слов
|
||||||
|
*/
|
||||||
|
public void reload() {
|
||||||
|
loadFilterWords();
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum FilterResult {
|
public enum FilterResult {
|
||||||
|
|
@ -32,15 +127,16 @@ public class FilterManager {
|
||||||
return FilterResult.ALLOWED;
|
return FilterResult.ALLOWED;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<String> badWords = plugin.getConfigManager().getFilterWords();
|
if (badWords.isEmpty() && fragments.isEmpty()) {
|
||||||
if (badWords == null || badWords.isEmpty()) {
|
|
||||||
return FilterResult.ALLOWED;
|
return FilterResult.ALLOWED;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Нормализуем сообщение (убираем обход фильтра)
|
// Нормализуем сообщение (убираем обход фильтра)
|
||||||
String normalizedMessage = normalizeMessage(message);
|
String normalizedMessage = normalizeMessage(message);
|
||||||
String lowerMessage = normalizedMessage.toLowerCase();
|
String lowerMessage = normalizedMessage.toLowerCase();
|
||||||
|
String originalLower = message.toLowerCase();
|
||||||
|
|
||||||
|
// Проверяем полные слова
|
||||||
for (String word : badWords) {
|
for (String word : badWords) {
|
||||||
if (word == null || word.trim().isEmpty()) {
|
if (word == null || word.trim().isEmpty()) {
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -50,29 +146,45 @@ public class FilterManager {
|
||||||
|
|
||||||
// Проверяем точное совпадение слова (с границами слов)
|
// Проверяем точное совпадение слова (с границами слов)
|
||||||
Pattern wordPattern = Pattern.compile("\\b" + Pattern.quote(lowerWord) + "\\b", Pattern.CASE_INSENSITIVE);
|
Pattern wordPattern = Pattern.compile("\\b" + Pattern.quote(lowerWord) + "\\b", Pattern.CASE_INSENSITIVE);
|
||||||
if (wordPattern.matcher(normalizedMessage).find()) {
|
if (wordPattern.matcher(normalizedMessage).find() || wordPattern.matcher(originalLower).find()) {
|
||||||
String action = plugin.getConfigManager().getFilterAction();
|
return getFilterResult();
|
||||||
return switch (action.toLowerCase()) {
|
|
||||||
case "block" -> FilterResult.BLOCKED;
|
|
||||||
case "warn" -> FilterResult.WARNED;
|
|
||||||
default -> FilterResult.CENSORED;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Также проверяем как подстроку (для частичных совпадений типа "пизд")
|
// Также проверяем как подстроку
|
||||||
if (lowerMessage.contains(lowerWord)) {
|
if (lowerMessage.contains(lowerWord) || originalLower.contains(lowerWord)) {
|
||||||
String action = plugin.getConfigManager().getFilterAction();
|
return getFilterResult();
|
||||||
return switch (action.toLowerCase()) {
|
}
|
||||||
case "block" -> FilterResult.BLOCKED;
|
}
|
||||||
case "warn" -> FilterResult.WARNED;
|
|
||||||
default -> FilterResult.CENSORED;
|
// Проверяем фрагменты (поиск по фрагментам типа "пизд" найдет "пизда", "пиздец" и т.д.)
|
||||||
};
|
for (String fragment : fragments) {
|
||||||
|
if (fragment == null || fragment.trim().isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
String lowerFragment = fragment.toLowerCase().trim();
|
||||||
|
|
||||||
|
// Ищем фрагмент в нормализованном сообщении
|
||||||
|
if (lowerMessage.contains(lowerFragment) || originalLower.contains(lowerFragment)) {
|
||||||
|
return getFilterResult();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return FilterResult.ALLOWED;
|
return FilterResult.ALLOWED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Возвращает результат фильтрации на основе настроек
|
||||||
|
*/
|
||||||
|
private FilterResult getFilterResult() {
|
||||||
|
String action = plugin.getConfigManager().getFilterAction();
|
||||||
|
return switch (action.toLowerCase()) {
|
||||||
|
case "block" -> FilterResult.BLOCKED;
|
||||||
|
case "warn" -> FilterResult.WARNED;
|
||||||
|
default -> FilterResult.CENSORED;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Цензурирует сообщение, заменяя запрещенные слова
|
* Цензурирует сообщение, заменяя запрещенные слова
|
||||||
*/
|
*/
|
||||||
|
|
@ -85,8 +197,7 @@ public class FilterManager {
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<String> badWords = plugin.getConfigManager().getFilterWords();
|
if (badWords.isEmpty() && fragments.isEmpty()) {
|
||||||
if (badWords == null || badWords.isEmpty()) {
|
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -98,38 +209,53 @@ public class FilterManager {
|
||||||
String result = message;
|
String result = message;
|
||||||
String normalizedMessage = normalizeMessage(message);
|
String normalizedMessage = normalizeMessage(message);
|
||||||
|
|
||||||
|
// Заменяем полные слова
|
||||||
for (String word : badWords) {
|
for (String word : badWords) {
|
||||||
if (word == null || word.trim().isEmpty()) {
|
if (word == null || word.trim().isEmpty()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
String lowerWord = word.toLowerCase().trim();
|
|
||||||
|
|
||||||
// Заменяем точные совпадения слов
|
// Заменяем точные совпадения слов
|
||||||
Pattern wordPattern = Pattern.compile("\\b" + Pattern.quote(word) + "\\b", Pattern.CASE_INSENSITIVE);
|
Pattern wordPattern = Pattern.compile("\\b" + Pattern.quote(word) + "\\b", Pattern.CASE_INSENSITIVE);
|
||||||
result = wordPattern.matcher(result).replaceAll(replacement);
|
result = wordPattern.matcher(result).replaceAll(replacement);
|
||||||
|
|
||||||
// Также заменяем как подстроку (для частичных совпадений)
|
// Также заменяем как подстроку
|
||||||
Pattern substringPattern = Pattern.compile("(?i)" + Pattern.quote(word));
|
Pattern substringPattern = Pattern.compile("(?i)" + Pattern.quote(word));
|
||||||
result = substringPattern.matcher(result).replaceAll(replacement);
|
result = substringPattern.matcher(result).replaceAll(replacement);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Заменяем фрагменты (находим слова содержащие фрагмент и заменяем их)
|
||||||
|
for (String fragment : fragments) {
|
||||||
|
if (fragment == null || fragment.trim().isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ищем слова содержащие фрагмент и заменяем весь фрагмент
|
||||||
|
Pattern fragmentPattern = Pattern.compile("(?i)" + Pattern.quote(fragment));
|
||||||
|
result = fragmentPattern.matcher(result).replaceAll(replacement);
|
||||||
|
|
||||||
|
// Также заменяем слова начинающиеся с фрагмента
|
||||||
|
Pattern wordStartPattern = Pattern.compile("\\b" + Pattern.quote(fragment) + "\\w*", Pattern.CASE_INSENSITIVE);
|
||||||
|
result = wordStartPattern.matcher(result).replaceAll(replacement);
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Нормализует сообщение, убирая попытки обхода фильтра
|
* Нормализует сообщение, убирая попытки обхода фильтра
|
||||||
* Заменяет специальные символы на обычные буквы
|
* Заменяет специальные символы на обычные буквы
|
||||||
|
* Например: "пизд@" -> "пизда", "х*й" -> "хай" (но "хуй" найдет)
|
||||||
*/
|
*/
|
||||||
private String normalizeMessage(String message) {
|
private String normalizeMessage(String message) {
|
||||||
if (message == null) {
|
if (message == null) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Заменяем символы обхода на буквы (для обнаружения х*й, х_уй и т.д.)
|
// Заменяем символы обхода на буквы (для обнаружения х*й, х_уй, пизд@ и т.д.)
|
||||||
String normalized = message;
|
String normalized = message;
|
||||||
|
|
||||||
// Заменяем символы обхода на буквы
|
// Заменяем символы обхода на похожие буквы
|
||||||
normalized = normalized.replace('*', 'а');
|
normalized = normalized.replace('*', 'а');
|
||||||
normalized = normalized.replace('_', 'а');
|
normalized = normalized.replace('_', 'а');
|
||||||
normalized = normalized.replace('-', 'а');
|
normalized = normalized.replace('-', 'а');
|
||||||
|
|
@ -146,12 +272,27 @@ public class FilterManager {
|
||||||
normalized = normalized.replace('7', 'т');
|
normalized = normalized.replace('7', 'т');
|
||||||
normalized = normalized.replace('8', 'в');
|
normalized = normalized.replace('8', 'в');
|
||||||
normalized = normalized.replace('9', 'д');
|
normalized = normalized.replace('9', 'д');
|
||||||
normalized = normalized.replace('@', 'а');
|
normalized = normalized.replace('@', 'а'); // пизд@ -> пизда
|
||||||
normalized = normalized.replace('#', 'х');
|
normalized = normalized.replace('#', 'х');
|
||||||
normalized = normalized.replace('$', 'с');
|
normalized = normalized.replace('$', 'с');
|
||||||
normalized = normalized.replace('%', 'о');
|
normalized = normalized.replace('%', 'о');
|
||||||
normalized = normalized.replace('^', 'х');
|
normalized = normalized.replace('^', 'х');
|
||||||
normalized = normalized.replace('&', 'а');
|
normalized = normalized.replace('&', 'а');
|
||||||
|
normalized = normalized.replace('~', 'а');
|
||||||
|
normalized = normalized.replace('`', 'а');
|
||||||
|
normalized = normalized.replace('=', 'а');
|
||||||
|
normalized = normalized.replace('+', 'а');
|
||||||
|
normalized = normalized.replace('[', 'а');
|
||||||
|
normalized = normalized.replace(']', 'а');
|
||||||
|
normalized = normalized.replace('{', 'а');
|
||||||
|
normalized = normalized.replace('}', 'а');
|
||||||
|
normalized = normalized.replace('(', 'а');
|
||||||
|
normalized = normalized.replace(')', 'а');
|
||||||
|
normalized = normalized.replace('/', 'а');
|
||||||
|
normalized = normalized.replace('\\', 'а');
|
||||||
|
normalized = normalized.replace('?', 'а');
|
||||||
|
normalized = normalized.replace('<', 'а');
|
||||||
|
normalized = normalized.replace('>', 'а');
|
||||||
|
|
||||||
// Убираем множественные пробелы
|
// Убираем множественные пробелы
|
||||||
normalized = normalized.replaceAll("\\s+", " ");
|
normalized = normalized.replaceAll("\\s+", " ");
|
||||||
|
|
|
||||||
624
src/main/resources/filter-words.json
Normal file
624
src/main/resources/filter-words.json
Normal file
|
|
@ -0,0 +1,624 @@
|
||||||
|
{
|
||||||
|
"words": [
|
||||||
|
"хуй",
|
||||||
|
"хуя",
|
||||||
|
"хуе",
|
||||||
|
"хуи",
|
||||||
|
"хую",
|
||||||
|
"хуё",
|
||||||
|
"пизд",
|
||||||
|
"пизда",
|
||||||
|
"пиздец",
|
||||||
|
"пизду",
|
||||||
|
"пизды",
|
||||||
|
"пиздо",
|
||||||
|
"блять",
|
||||||
|
"блядь",
|
||||||
|
"бля",
|
||||||
|
"бляд",
|
||||||
|
"ебать",
|
||||||
|
"ебал",
|
||||||
|
"ебало",
|
||||||
|
"ебать",
|
||||||
|
"ебет",
|
||||||
|
"ебут",
|
||||||
|
"ебу",
|
||||||
|
"ебё",
|
||||||
|
"ебан",
|
||||||
|
"сука",
|
||||||
|
"суки",
|
||||||
|
"суке",
|
||||||
|
"суку",
|
||||||
|
"сукой",
|
||||||
|
"суко",
|
||||||
|
"ебан",
|
||||||
|
"ебана",
|
||||||
|
"ебану",
|
||||||
|
"ебань",
|
||||||
|
"ебля",
|
||||||
|
"ебли",
|
||||||
|
"ебло",
|
||||||
|
"ебля",
|
||||||
|
"ебут",
|
||||||
|
"ебуть",
|
||||||
|
"ебёшь",
|
||||||
|
"ебёт",
|
||||||
|
"ебём",
|
||||||
|
"ебёте",
|
||||||
|
"ебут",
|
||||||
|
"ебаный",
|
||||||
|
"ебаная",
|
||||||
|
"ебаное",
|
||||||
|
"ебаные",
|
||||||
|
"ебаного",
|
||||||
|
"ебаной",
|
||||||
|
"ебаному",
|
||||||
|
"ебаным",
|
||||||
|
"ебаных",
|
||||||
|
"ебаным",
|
||||||
|
"ебаные",
|
||||||
|
"ебаными",
|
||||||
|
"ебаных",
|
||||||
|
"ебанный",
|
||||||
|
"ебанная",
|
||||||
|
"ебанное",
|
||||||
|
"ебанные",
|
||||||
|
"ебанного",
|
||||||
|
"ебанной",
|
||||||
|
"ебанному",
|
||||||
|
"ебанным",
|
||||||
|
"ебанных",
|
||||||
|
"ебанным",
|
||||||
|
"ебанные",
|
||||||
|
"ебанными",
|
||||||
|
"ебанных",
|
||||||
|
"заеб",
|
||||||
|
"заеба",
|
||||||
|
"заебе",
|
||||||
|
"заеби",
|
||||||
|
"заебу",
|
||||||
|
"заебё",
|
||||||
|
"уеб",
|
||||||
|
"уеба",
|
||||||
|
"уебе",
|
||||||
|
"уеби",
|
||||||
|
"уебу",
|
||||||
|
"уебё",
|
||||||
|
"выеб",
|
||||||
|
"выеба",
|
||||||
|
"выебе",
|
||||||
|
"выеби",
|
||||||
|
"выебу",
|
||||||
|
"выебё",
|
||||||
|
"проеб",
|
||||||
|
"проеба",
|
||||||
|
"проебе",
|
||||||
|
"проеби",
|
||||||
|
"проебу",
|
||||||
|
"проебё",
|
||||||
|
"долбоеб",
|
||||||
|
"долбоеба",
|
||||||
|
"долбоебе",
|
||||||
|
"долбоеби",
|
||||||
|
"долбоебу",
|
||||||
|
"долбоебё",
|
||||||
|
"мудак",
|
||||||
|
"мудака",
|
||||||
|
"мудаке",
|
||||||
|
"мудаки",
|
||||||
|
"мудаку",
|
||||||
|
"мудаком",
|
||||||
|
"мудаки",
|
||||||
|
"мудаков",
|
||||||
|
"мудакам",
|
||||||
|
"мудаками",
|
||||||
|
"мудаках",
|
||||||
|
"мудила",
|
||||||
|
"мудилы",
|
||||||
|
"мудиле",
|
||||||
|
"мудилу",
|
||||||
|
"мудилой",
|
||||||
|
"мудило",
|
||||||
|
"гандон",
|
||||||
|
"гондон",
|
||||||
|
"гандона",
|
||||||
|
"гондона",
|
||||||
|
"гандону",
|
||||||
|
"гондону",
|
||||||
|
"гандоном",
|
||||||
|
"гондоном",
|
||||||
|
"гандоне",
|
||||||
|
"гондоне",
|
||||||
|
"гандонов",
|
||||||
|
"гондонов",
|
||||||
|
"гандонам",
|
||||||
|
"гондонам",
|
||||||
|
"гандонами",
|
||||||
|
"гондонами",
|
||||||
|
"гандонах",
|
||||||
|
"гондонах",
|
||||||
|
"пидор",
|
||||||
|
"пидора",
|
||||||
|
"пидору",
|
||||||
|
"пидором",
|
||||||
|
"пидоре",
|
||||||
|
"пидоры",
|
||||||
|
"пидоров",
|
||||||
|
"пидорам",
|
||||||
|
"пидорами",
|
||||||
|
"пидорах",
|
||||||
|
"пидарас",
|
||||||
|
"пидараса",
|
||||||
|
"пидарасу",
|
||||||
|
"пидарасом",
|
||||||
|
"пидарасе",
|
||||||
|
"пидарасы",
|
||||||
|
"пидарасов",
|
||||||
|
"пидарасам",
|
||||||
|
"пидарасами",
|
||||||
|
"пидарасах",
|
||||||
|
"педик",
|
||||||
|
"педика",
|
||||||
|
"педику",
|
||||||
|
"педиком",
|
||||||
|
"педике",
|
||||||
|
"педики",
|
||||||
|
"педиков",
|
||||||
|
"педикам",
|
||||||
|
"педиками",
|
||||||
|
"педиках",
|
||||||
|
"гомик",
|
||||||
|
"гомика",
|
||||||
|
"гомику",
|
||||||
|
"гомиком",
|
||||||
|
"гомике",
|
||||||
|
"гомики",
|
||||||
|
"гомиков",
|
||||||
|
"гомикам",
|
||||||
|
"гомиками",
|
||||||
|
"гомиках",
|
||||||
|
"шлюха",
|
||||||
|
"шлюхи",
|
||||||
|
"шлюхе",
|
||||||
|
"шлюху",
|
||||||
|
"шлюхой",
|
||||||
|
"шлюхо",
|
||||||
|
"шлюх",
|
||||||
|
"блядина",
|
||||||
|
"блядины",
|
||||||
|
"блядине",
|
||||||
|
"блядину",
|
||||||
|
"блядиной",
|
||||||
|
"блядино",
|
||||||
|
"блядин",
|
||||||
|
"шлюшка",
|
||||||
|
"шлюшки",
|
||||||
|
"шлюшке",
|
||||||
|
"шлюшку",
|
||||||
|
"шлюшкой",
|
||||||
|
"шлюшко",
|
||||||
|
"шлюшек",
|
||||||
|
"проститутка",
|
||||||
|
"проститутки",
|
||||||
|
"проститутке",
|
||||||
|
"проститутку",
|
||||||
|
"проституткой",
|
||||||
|
"проститутко",
|
||||||
|
"проституток",
|
||||||
|
"проституткам",
|
||||||
|
"проститутками",
|
||||||
|
"проститутках",
|
||||||
|
"еблан",
|
||||||
|
"еблана",
|
||||||
|
"еблану",
|
||||||
|
"ебланом",
|
||||||
|
"еблане",
|
||||||
|
"ебланы",
|
||||||
|
"ебланов",
|
||||||
|
"ебланам",
|
||||||
|
"ебланами",
|
||||||
|
"ебланах",
|
||||||
|
"ебанутый",
|
||||||
|
"ебанутого",
|
||||||
|
"ебанутому",
|
||||||
|
"ебанутым",
|
||||||
|
"ебанутом",
|
||||||
|
"ебанутая",
|
||||||
|
"ебанутой",
|
||||||
|
"ебанутую",
|
||||||
|
"ебанутое",
|
||||||
|
"ебанутые",
|
||||||
|
"ебанутых",
|
||||||
|
"ебанутым",
|
||||||
|
"ебанутыми",
|
||||||
|
"ебанутых",
|
||||||
|
"ебанутый",
|
||||||
|
"ебанутого",
|
||||||
|
"ебанутому",
|
||||||
|
"ебанутым",
|
||||||
|
"ебанутом",
|
||||||
|
"ебанутая",
|
||||||
|
"ебанутой",
|
||||||
|
"ебанутую",
|
||||||
|
"ебанутое",
|
||||||
|
"ебанутые",
|
||||||
|
"ебанутых",
|
||||||
|
"ебанутым",
|
||||||
|
"ебанутыми",
|
||||||
|
"ебанутых",
|
||||||
|
"уебан",
|
||||||
|
"уебана",
|
||||||
|
"уебану",
|
||||||
|
"уебаном",
|
||||||
|
"уебане",
|
||||||
|
"уебаны",
|
||||||
|
"уебанов",
|
||||||
|
"уебанам",
|
||||||
|
"уебанами",
|
||||||
|
"уебанах",
|
||||||
|
"долбоёб",
|
||||||
|
"долбоёба",
|
||||||
|
"долбоёбу",
|
||||||
|
"долбоёбом",
|
||||||
|
"долбоёбе",
|
||||||
|
"долбоёбы",
|
||||||
|
"долбоёбов",
|
||||||
|
"долбоёбам",
|
||||||
|
"долбоёбами",
|
||||||
|
"долбоёбах",
|
||||||
|
"долбоеб",
|
||||||
|
"долбоеба",
|
||||||
|
"долбоебу",
|
||||||
|
"долбоебом",
|
||||||
|
"долбоебе",
|
||||||
|
"долбоебы",
|
||||||
|
"долбоебов",
|
||||||
|
"долбоебам",
|
||||||
|
"долбоебами",
|
||||||
|
"долбоебах",
|
||||||
|
"еблан",
|
||||||
|
"еблана",
|
||||||
|
"еблану",
|
||||||
|
"ебланом",
|
||||||
|
"еблане",
|
||||||
|
"ебланы",
|
||||||
|
"ебланов",
|
||||||
|
"ебланам",
|
||||||
|
"ебланами",
|
||||||
|
"ебланах",
|
||||||
|
"залупа",
|
||||||
|
"залупы",
|
||||||
|
"залупе",
|
||||||
|
"залупу",
|
||||||
|
"залупой",
|
||||||
|
"залупо",
|
||||||
|
"залуп",
|
||||||
|
"залупка",
|
||||||
|
"залупки",
|
||||||
|
"залупке",
|
||||||
|
"залупку",
|
||||||
|
"залупкой",
|
||||||
|
"залупко",
|
||||||
|
"залупок",
|
||||||
|
"залупкам",
|
||||||
|
"залупками",
|
||||||
|
"залупках",
|
||||||
|
"мразь",
|
||||||
|
"мрази",
|
||||||
|
"мрази",
|
||||||
|
"мразью",
|
||||||
|
"мразь",
|
||||||
|
"мразей",
|
||||||
|
"мразям",
|
||||||
|
"мразями",
|
||||||
|
"мразях",
|
||||||
|
"мразота",
|
||||||
|
"мразоты",
|
||||||
|
"мразоте",
|
||||||
|
"мразоту",
|
||||||
|
"мразотой",
|
||||||
|
"мразото",
|
||||||
|
"мразот",
|
||||||
|
"мразотой",
|
||||||
|
"мразотам",
|
||||||
|
"мразотами",
|
||||||
|
"мразотах",
|
||||||
|
"ублюдок",
|
||||||
|
"ублюдка",
|
||||||
|
"ублюдку",
|
||||||
|
"ублюдком",
|
||||||
|
"ублюдке",
|
||||||
|
"ублюдки",
|
||||||
|
"ублюдков",
|
||||||
|
"ублюдкам",
|
||||||
|
"ублюдками",
|
||||||
|
"ублюдках",
|
||||||
|
"выблядок",
|
||||||
|
"выблядка",
|
||||||
|
"выблядку",
|
||||||
|
"выблядком",
|
||||||
|
"выблядке",
|
||||||
|
"выблядки",
|
||||||
|
"выблядков",
|
||||||
|
"выблядкам",
|
||||||
|
"выблядками",
|
||||||
|
"выблядках",
|
||||||
|
"падла",
|
||||||
|
"падлы",
|
||||||
|
"падле",
|
||||||
|
"падлу",
|
||||||
|
"падлой",
|
||||||
|
"падло",
|
||||||
|
"падл",
|
||||||
|
"падлюга",
|
||||||
|
"падлюги",
|
||||||
|
"падлюге",
|
||||||
|
"падлюгу",
|
||||||
|
"падлюгой",
|
||||||
|
"падлюго",
|
||||||
|
"падлюг",
|
||||||
|
"падлюгам",
|
||||||
|
"падлюгами",
|
||||||
|
"падлюгах",
|
||||||
|
"гад",
|
||||||
|
"гада",
|
||||||
|
"гаду",
|
||||||
|
"гадом",
|
||||||
|
"гаде",
|
||||||
|
"гады",
|
||||||
|
"гадов",
|
||||||
|
"гадам",
|
||||||
|
"гадами",
|
||||||
|
"гадах",
|
||||||
|
"гадина",
|
||||||
|
"гадины",
|
||||||
|
"гадине",
|
||||||
|
"гадину",
|
||||||
|
"гадиной",
|
||||||
|
"гадино",
|
||||||
|
"гадин",
|
||||||
|
"гадинам",
|
||||||
|
"гадинами",
|
||||||
|
"гадинах",
|
||||||
|
"тварь",
|
||||||
|
"твари",
|
||||||
|
"твари",
|
||||||
|
"тварью",
|
||||||
|
"тварь",
|
||||||
|
"тварей",
|
||||||
|
"тварям",
|
||||||
|
"тварями",
|
||||||
|
"тварях",
|
||||||
|
"тварина",
|
||||||
|
"тварины",
|
||||||
|
"тварине",
|
||||||
|
"тварину",
|
||||||
|
"твариной",
|
||||||
|
"тварино",
|
||||||
|
"тварин",
|
||||||
|
"тваринам",
|
||||||
|
"тваринами",
|
||||||
|
"тваринах",
|
||||||
|
"сволочь",
|
||||||
|
"сволочи",
|
||||||
|
"сволочи",
|
||||||
|
"сволочью",
|
||||||
|
"сволочь",
|
||||||
|
"сволочей",
|
||||||
|
"сволочам",
|
||||||
|
"сволочами",
|
||||||
|
"сволочах",
|
||||||
|
"сволочка",
|
||||||
|
"сволочки",
|
||||||
|
"сволочке",
|
||||||
|
"сволочку",
|
||||||
|
"сволочкой",
|
||||||
|
"сволочко",
|
||||||
|
"сволочек",
|
||||||
|
"сволочкам",
|
||||||
|
"сволочками",
|
||||||
|
"сволочках",
|
||||||
|
"скотина",
|
||||||
|
"скотины",
|
||||||
|
"скотине",
|
||||||
|
"скотину",
|
||||||
|
"скотиной",
|
||||||
|
"скотино",
|
||||||
|
"скотин",
|
||||||
|
"скотинам",
|
||||||
|
"скотинами",
|
||||||
|
"скотинах",
|
||||||
|
"скотиняка",
|
||||||
|
"скотиняки",
|
||||||
|
"скотиняке",
|
||||||
|
"скотиняку",
|
||||||
|
"скотинякой",
|
||||||
|
"скотиняко",
|
||||||
|
"скотиняк",
|
||||||
|
"скотинякам",
|
||||||
|
"скотиняками",
|
||||||
|
"скотиняках",
|
||||||
|
"козел",
|
||||||
|
"козла",
|
||||||
|
"козлу",
|
||||||
|
"козлом",
|
||||||
|
"козле",
|
||||||
|
"козлы",
|
||||||
|
"козлов",
|
||||||
|
"козлам",
|
||||||
|
"козлами",
|
||||||
|
"козлах",
|
||||||
|
"козлина",
|
||||||
|
"козлины",
|
||||||
|
"козлине",
|
||||||
|
"козлину",
|
||||||
|
"козлиной",
|
||||||
|
"козлино",
|
||||||
|
"козлин",
|
||||||
|
"козлинам",
|
||||||
|
"козлинами",
|
||||||
|
"козлинах",
|
||||||
|
"козлище",
|
||||||
|
"козлища",
|
||||||
|
"козлищу",
|
||||||
|
"козлищем",
|
||||||
|
"козлище",
|
||||||
|
"козлищ",
|
||||||
|
"козлищам",
|
||||||
|
"козлищами",
|
||||||
|
"козлищах",
|
||||||
|
"козёл",
|
||||||
|
"козла",
|
||||||
|
"козлу",
|
||||||
|
"козлом",
|
||||||
|
"козле",
|
||||||
|
"козлы",
|
||||||
|
"козлов",
|
||||||
|
"козлам",
|
||||||
|
"козлами",
|
||||||
|
"козлах",
|
||||||
|
"козлина",
|
||||||
|
"козлины",
|
||||||
|
"козлине",
|
||||||
|
"козлину",
|
||||||
|
"козлиной",
|
||||||
|
"козлино",
|
||||||
|
"козлин",
|
||||||
|
"козлинам",
|
||||||
|
"козлинами",
|
||||||
|
"козлинах",
|
||||||
|
"козлище",
|
||||||
|
"козлища",
|
||||||
|
"козлищу",
|
||||||
|
"козлищем",
|
||||||
|
"козлище",
|
||||||
|
"козлищ",
|
||||||
|
"козлищам",
|
||||||
|
"козлищами",
|
||||||
|
"козлищах",
|
||||||
|
"козёл",
|
||||||
|
"козла",
|
||||||
|
"козлу",
|
||||||
|
"козлом",
|
||||||
|
"козле",
|
||||||
|
"козлы",
|
||||||
|
"козлов",
|
||||||
|
"козлам",
|
||||||
|
"козлами",
|
||||||
|
"козлах",
|
||||||
|
"козлина",
|
||||||
|
"козлины",
|
||||||
|
"козлине",
|
||||||
|
"козлину",
|
||||||
|
"козлиной",
|
||||||
|
"козлино",
|
||||||
|
"козлин",
|
||||||
|
"козлинам",
|
||||||
|
"козлинами",
|
||||||
|
"козлинах",
|
||||||
|
"козлище",
|
||||||
|
"козлища",
|
||||||
|
"козлищу",
|
||||||
|
"козлищем",
|
||||||
|
"козлище",
|
||||||
|
"козлищ",
|
||||||
|
"козлищам",
|
||||||
|
"козлищами",
|
||||||
|
"козлищах"
|
||||||
|
],
|
||||||
|
"fragments": [
|
||||||
|
"хуй",
|
||||||
|
"хуя",
|
||||||
|
"хуе",
|
||||||
|
"хуи",
|
||||||
|
"хую",
|
||||||
|
"хуё",
|
||||||
|
"пизд",
|
||||||
|
"бля",
|
||||||
|
"бляд",
|
||||||
|
"еб",
|
||||||
|
"еба",
|
||||||
|
"ебе",
|
||||||
|
"еби",
|
||||||
|
"ебу",
|
||||||
|
"ебё",
|
||||||
|
"ебан",
|
||||||
|
"ебал",
|
||||||
|
"ебан",
|
||||||
|
"ебля",
|
||||||
|
"ебли",
|
||||||
|
"ебло",
|
||||||
|
"ебут",
|
||||||
|
"ебуть",
|
||||||
|
"ебёшь",
|
||||||
|
"ебёт",
|
||||||
|
"ебём",
|
||||||
|
"ебёте",
|
||||||
|
"ебут",
|
||||||
|
"ебаный",
|
||||||
|
"ебаная",
|
||||||
|
"ебаное",
|
||||||
|
"ебаные",
|
||||||
|
"ебаного",
|
||||||
|
"ебаной",
|
||||||
|
"ебаному",
|
||||||
|
"ебаным",
|
||||||
|
"ебаных",
|
||||||
|
"ебаным",
|
||||||
|
"ебаные",
|
||||||
|
"ебаными",
|
||||||
|
"ебаных",
|
||||||
|
"ебанный",
|
||||||
|
"ебанная",
|
||||||
|
"ебанное",
|
||||||
|
"ебанные",
|
||||||
|
"ебанного",
|
||||||
|
"ебанной",
|
||||||
|
"ебанному",
|
||||||
|
"ебанным",
|
||||||
|
"ебанных",
|
||||||
|
"ебанным",
|
||||||
|
"ебанные",
|
||||||
|
"ебанными",
|
||||||
|
"ебанных",
|
||||||
|
"заеб",
|
||||||
|
"уеб",
|
||||||
|
"выеб",
|
||||||
|
"проеб",
|
||||||
|
"долбоеб",
|
||||||
|
"мудак",
|
||||||
|
"мудил",
|
||||||
|
"гандон",
|
||||||
|
"гондон",
|
||||||
|
"пидор",
|
||||||
|
"пидарас",
|
||||||
|
"педик",
|
||||||
|
"гомик",
|
||||||
|
"шлюх",
|
||||||
|
"блядин",
|
||||||
|
"проститутк",
|
||||||
|
"еблан",
|
||||||
|
"ебанут",
|
||||||
|
"уебан",
|
||||||
|
"долбоёб",
|
||||||
|
"долбоеб",
|
||||||
|
"залуп",
|
||||||
|
"мраз",
|
||||||
|
"мразот",
|
||||||
|
"ублюдок",
|
||||||
|
"выблядок",
|
||||||
|
"падл",
|
||||||
|
"падлюг",
|
||||||
|
"гад",
|
||||||
|
"гадин",
|
||||||
|
"твар",
|
||||||
|
"тварин",
|
||||||
|
"сволоч",
|
||||||
|
"скотин",
|
||||||
|
"козел",
|
||||||
|
"козл",
|
||||||
|
"козёл",
|
||||||
|
"козлищ"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue