refactor: вынести namegen в internal-пакет, расширить пулы имён

- Перенос client/namegen.go в client/internal/namegen с экспортируемым
  Generate()
- Вынос данных имён в data/*.txt, загрузка через //go:embed
- Расширение пулов: мужские 729→760, женские 31→99, фамилии 60→286
  (вкл. мем-имена)
- Переписан feminizeSurname через []rune (убрана хрупкая байтовая
  арифметика на len-4)
- Переход с math/rand на math/rand/v2
- Юнит-тесты: parseLines, feminizeSurname, целостность пулов, форма и
  покрытие по полу у Generate
This commit is contained in:
samosvalishe
2026-05-18 17:51:27 +03:00
parent ead97d0089
commit b3f81add0e
7 changed files with 1389 additions and 884 deletions
@@ -0,0 +1,99 @@
Александра
Алина
Алла
Алёна
Анастасия
Ангелина
Анна
Антонина
Валентина
Валерия
Варвара
Василиса
Вера
Вероника
Виктория
Галина
Дарина
Дарья
Диана
Ева
Евгения
Екатерина
Елена
Елизавета
Зинаида
Зоя
Инна
Ирина
Карина
Кира
Кристина
Ксения
Лариса
Лидия
Любовь
Людмила
Майя
Маргарита
Марина
Мария
Милана
Надежда
Наталья
Нина
Олеся
Ольга
Полина
Раиса
Регина
Римма
Светлана
София
Тамара
Татьяна
Ульяна
Эльвира
Юлия
Яна
Ярослава
Аврора
Алиса
Арья
Барби
Беллатриса
Белль
Ванда
Венди
Гамора
Гермиона
Гоар
Дейенерис
Дороти
Жасмин
Зена
Круэлла
Лара
Лея
Луна
Малефисента
Маша
Матильда
Мерида
Минни
Молли
Мона
Мулан
Наташа
Пиппи
Рапунцель
Санса
Серсея
Тиана
Тинкер
Тринити
Урсула
Фиона
Харли
Эдна
Эльза
@@ -0,0 +1,760 @@
Аарон
Аба
Аббас
Абд аль-Узза
Абдуллах
Абид
Аботур
Аввакум
Август
Авдей
Авель
Аверкий
Авигдор
Авирмэд
Авксентий
Авл
Авнер
Аврелий
Автандил
Автоном
Агапит
Агафангел
Агафодор
Агафон
Аги
Агриппа
Адам
Адар
Адиль
Адольф
Адонирам
Адриан
Азамат
Азарий
Азат
Азиз
Азим
Айварс
Айдар
Айрат
Акакий
Аквилий
Акиф
Акоп
Аксель
Алан
Аланус
Алек
Александр
Алексей
Алемдар
Алик
Алим
Алипий
Алишер
Алмат
Алоиз
Алон
Альберик
Альберт
Альбин
Альваро
Альвиан
Альвизе
Альфонс
Альфред
Амадис
Амвросий
Амедей
Амин
Амир
Амр
Амфилохий
Анания
Анас
Анастасий
Анатолий
Ангеляр
Андокид
Андрей
Андроник
Аннерс
Анри
Ансельм
Антипа
Антон
Антоний
Антонин
Антуан
Арам
Арефа
Арзуман
Аристарх
Аристон
Ариф
Аркадий
Арсений
Артём
Артур
Арфаксад
Асаф
Атанасий
Атом
Аттик
Афанасий
Афинагор
Афиней
Афиф
Африкан
Ахилл
Ахмад
Ахтям
Ашот
Бадар
Бартоломео
Басир
Бахтияр
Баян
Безсон
Бен
Беньямин
Берт
Бехруз
Билял
Богдан
Болеслав
Бонавентура
Борис
Борислав
Боян
Бронислав
Брячислав
Бурхан
Бутрос
Бямбасурэн
Вадим
Валентин
Валентино
Валерий
Валерьян
Вальдемар
Вангьял
Варлам
Варнава
Варфоломей
Василий
Вахтанг
Велвел
Венансио
Венедикт
Вениамин
Венцеслав
Вигго
Викентий
Виктор
Викторин
Вильгельм
Винцас
Виссарион
Виталий
Витаутас
Вито
Владимир
Владислав
Владлен
Влас
Воислав
Володарь
Вольфганг
Вописк
Всеволод
Всеслав
Вук
Вукол
Вышеслав
Вячеслав
Габриеле
Гавриил
Гай
Галактион
Галымжан
Гамлет
Гаспар
Гафур
Гвидо
Гейдар
Геласий
Гелий
Гельмут
Геннадий
Генри
Генрих
Георге
Георгий
Гераклид
Герасим
Герберт
Герман
Германн
Геронтий
Герхард
Гийом
Гильем
Гинкмар
Глеб
Гней
Горацио
Гордей
Градислав
Григорий
Гримоальд
Гуго
Гурий
Густав
Гьялцен
Давид
Дамдинсурэн
Дамир
Даниил
Дарий
Демид
Демьян
Денеш
Денис
Децим
Джаббар
Джамиль
Джан
Джанер
Джанфранко
Джафар
Джейкоб
Джихангир
Джованни
Джон
Джохар
Джулиано
Джулиус
Дино
Диодор
Дитер
Дитмар
Дитрих
Дмитрий
Доминик
Дональд
Донат
Дорофей
Досифей
Евгений
Евграф
Евдоким
Еврит
Евсей
Евстафий
Евтихан
Евтихий
Егор
Елеазар
Елисей
Емельян
Епифаний
Ербол
Ерванд
Еремей
Ермак
Ермолай
Ерофей
Ефим
Ефрем
Жан
Ждан
Жером
Жоан
Захар
Захария
Збигнев
Зденек
Зейналабдин
Зенон
Зеэв
Зигмунд
Зинон
Зия
Золтан
Зосима
Иакинф
Иан
Ибрагим
Ибрахим
Иван
Игнатий
Игорь
Иероним
Иерофей
Израиль
Икрима
Иларий
Илия
Илларион
Илмари
Ильфат
Илья
Имран
Иннокентий
Иоаким
Иоанн
Иоанникий
Иоахим
Иов
Иоганн
Иоганнес
Ионафан
Иосафат
Ираклий
Иржи
Иринарх
Ириней
Иродион
Иса
Исаак
Исаакий
Исаия
Исидор
Ислам
Исмаил
Истислав
Истома
Истукарий
Иштван
Йюрген
Кадваллон
Кадир
Казимир
Каликст
Калин
Каллистрат
Кальман
Канат
Карен
Карлос
Карп
Картерий
Кассиан
Кассий
Касторий
Касьян
Катберт
Квинт
Кехлер
Киллиан
Ким
Кир
Кириак
Кирилл
Клаас
Клавдиан
Клеоник
Климент
Кондрат
Конон
Конрад
Константин
Корнелиус
Корнилий
Коррадо
Косьма
Кратет
Кратипп
Крис
Криспин
Кристиан
Кронид
Кузьма
Куприян
Курбан
Курт
Кутлуг-Буга
Кэлин
Лаврентий
Лавс
Ладислав
Лазарь
Лайл
Лампрехт
Ландульф
Лев
Леви
Ленни
Леонид
Леонтий
Леонхард
Лиам
Линкей
Логгин
Лоренц
Лоренцо
Луи
Луитпольд
Лука
Лукас
Лукий
Лукьян
Луций
Людовик
Макар
Максим
Максимиан
Максимилиан
Малик
Малх
Мамбет
Маний
Мануил
Мануэль
Мариан
Мариус
Марк
Маркел
Мартын
Марчелло
Матвей
Матео
Матиас
Матфей
Матфий
Махмуд
Меир
Мелентий
Мелитон
Менахем-Мендель
Месроп
Мефодий
Мечислав
Мика
Микеланджело
Микулаш
Милорад
Мина
Мирко
Мирон
Мирослав
Митрофан
Михаил
Михей
Младан
Модест
Моисей
Мордехай
Мстислав
Мурад
Мухаммед
Мэдисон
Мэлор
Мэлс
Назар
Наиль
Насиф
Натан
Натаниэль
Наум
Нафанаил
Нацагдорж
Нестор
Никандр
Никанор
Никита
Никифор
Никодим
Николай
Нил
Нильс
Ноа
Ной
Норд
Нуржан
Нурлан
Овадья
Оге
Одинец
Октав
Октавиан
Октавий
Октавио
Олаф
Оле
Олег
Оливер
Ольгерд
Онисим
Орест
Осип
Оскар
Осман
Отто
Оттон
Очирбат
Пабло
Павел
Павлин
Павсикакий
Паисий
Палладий
Панкратий
Пантелеймон
Паруйр
Парфений
Патрик
Пафнутий
Пахомий
Педро
Пётр
Пимен
Пинхас
Пипин
Питирим
Пол
Полидор
Полиевкт
Поликарп
Поликрат
Порфирий
Потап
Предраг
Премысл
Приск
Прокл
Прокопий
Прокул
Протасий
Прохор
Публий
Рагнар
Рагуил
Радмир
Радослав
Разумник
Раймонд
Рамадан
Рамазан
Рахман
Рашад
Рейнхард
Ренат
Реститут
Ричард
Роберт
Родерик
Родион
Рожер
Розарио
Роман
Ромен
Рон
Ронан
Ростислав
Рудольф
Руслан
Руф
Руфин
Рушан
Сабит
Савва
Савватий
Савелий
Савин
Саддам
Садик
Саид
Салават
Салих
Саллюстий
Салман
Самуил
Сармат
Святослав
Севастьян
Северин
Секст
Секунд
Семён
Септимий
Серапион
Сергей
Серж
Сигеберт
Сильвестр
Симеон
Симон
Созон
Соломон
Сонам
Софрон
Спиридон
Срджан
Станислав
Степан
Стефано
Стивен
Таврион
Тавус
Тадеуш
Тарас
Тарасий
Тейс
Тендзин
Теофил
Терентий
Терри
Тиберий
Тигран
Тимофей
Тимур
Тихомир
Тихон
Томас
Томоми
Торос
Тофик
Трифон
Трофим
Тудхалия
Тутмос
Тьерри
Тьяго
Уве
Уильям
Улдис
Ульрих
Ульф
Умар
Урызмаг
Усама
Усман
Фавст
Фаддей
Файзулла
Фарид
Фахраддин
Федериго
Фёдор
Федосей
Федот
Фейсал
Феликс
Феоктист
Феофан
Феофил
Феофилакт
Фердинанд
Ференц
Фидель
Филарет
Филат
Филип
Филипп
Философ
Филострат
Фирс
Фока
Фома
Фотий
Франц
Франческо
Фредерик
Фридрих
Фрол
Фульк
Хайме
Ханс
Харальд
Харитон
Харри
Харрисон
Хасан
Хетаг
Хильдерик
Хирам
Хлодвиг
Хокон
Хорив
Хоселито
Хосрой
Хрисанф
Христофор
Хуан
Цэрэндорж
Чеслав
Шалом
Шамиль
Шамсуддин
Шапур
Шарль
Шейх-Хайдар
Шон
Эберхард
Эдмунд
Эдуард
Элбэгдорж
Элджернон
Элиас
Эллиот
Эмиль
Энрик
Энрико
Энтони
Эразм
Эраст
Эрик
Эрнст
Эсекьель
Эстебан
Этьен
Ювеналий
Юлиан
Юлий
Юлиус
Юрий
Юстас
Юстин
Яков
Якуб
Якун
Ян
Яни
Януарий
Яромир
Ярополк
Ярослав
Барни
Бендер
Бэтмен
Винни
Волдеморт
Гарри
Гэндальф
Дамблдор
Дарт
Декард
Джесси
Кратос
Карлсон
Лебовски
Локи
Луиджи
Люцифер
Марио
Нео
Папа
Пикачу
Снейп
Соник
Терминатор
Тор
Уолтер
Фродо
Чебурашка
Шерлок
Шрек
Йода
+286
View File
@@ -0,0 +1,286 @@
Абрамов
Авдеев
Агафонов
Аксёнов
Александров
Алексеев
Андреев
Анисимов
Анохин
Антипов
Антонов
Арсеньев
Архипов
Афанасьев
Бабушкин
Балашов
Баранов
Барсуков
Белов
Белый
Бельский
Беляев
Бирюков
Блохин
Богданов
Бойко
Большаков
Бондарев
Борисов
Бородин
Бочаров
Брагин
Буров
Быков
Валуев
Варламов
Васильев
Вдовин
Великий
Викторов
Виноградов
Винокуров
Власов
Волков
Воробьёв
Воронин
Воронов
Воронцов
Гаврилов
Галкин
Герасимов
Глебов
Глухов
Голиков
Голубев
Гончаров
Горбунов
Горелов
Горшков
Григорьев
Гришин
Громов
Гурьев
Гусев
Давыдов
Демидов
Денисов
Дмитриев
Дорофеев
Дроздов
Дубинин
Дьяков
Евдокимов
Егоров
Емельянов
Ермаков
Ермилов
Ерофеев
Ефимов
Ефремов
Жданов
Жилин
Жуков
Журавлёв
Зайцев
Захаров
Зимин
Зиновьев
Золотарёв
Зорин
Зуев
Иванов
Ивлев
Игнатов
Игнатьев
Ильин
Исаев
Истомин
Кабанов
Казаков
Калашников
Калинин
Капустин
Карпов
Касаткин
Киреев
Киселёв
Климов
Кобзев
Ковалёв
Козлов
Комаров
Кондратьев
Коновалов
Константинов
Копылов
Корнилов
Королёв
Коротков
Костин
Котов
Кочетков
Кошелев
Крамской
Краснов
Крылов
Крючков
Кудрявцев
Кудряшов
Кузнецов
Кузьмин
Куликов
Курочкин
Лавров
Латыпов
Лебедев
Логинов
Лопухин
Лукин
Львов
Любимов
Майоров
Макаров
Максимов
Мамонтов
Мартынов
Маслов
Матвеев
Медведев
Мельников
Меньшов
Мещеряков
Миронов
Митрофанов
Михайлов
Михеев
Молчанов
Морозов
Москвин
Мухин
Назаров
Наумов
Некрасов
Нестеров
Никитин
Никифоров
Николаев
Новиков
Овчинников
Одинцов
Олейников
Орлов
Осипов
Островский
Павлов
Пахомов
Пестов
Петров
Покровский
Поляков
Пономарёв
Попов
Прокофьев
Прохоров
Пугачёв
Пушкин
Раевский
Родионов
Рожков
Романов
Русаков
Рыбаков
Савельев
Савин
Сазонов
Самойлов
Сафонов
Селезнёв
Семёнов
Сергеев
Сидоров
Силин
Сильвестров
Симонов
Смирнов
Соболев
Соколов
Соловьёв
Соломин
Сорокин
Сотников
Степанов
Стрельников
Субботин
Суворов
Сухов
Тарасов
Тимофеев
Титов
Тихомиров
Тихонов
Толстой
Третьяков
Трубецкой
Туманов
Усов
Устинов
Ушаков
Фадеев
Федосеев
Филиппов
Фокин
Фомин
Фролов
Фёдоров
Хохлов
Худяков
Цветков
Чайковский
Чернов
Черный
Шаров
Шашков
Швецов
Шилов
Ширяев
Шишкин
Щербаков
Юдин
Яковлев
Аддамс
Балалайкин
Бонд
Гриффин
Гэтсби
Дамблдор
Дурсль
Картошкин
Кеннеди
Корлеоне
Лебовски
Лонгботтом
Малфой
Огурцов
Пинкман
Помидоров
Поттер
Райан
Самоваров
Самогонов
Симпсон
Скайуокер
Сноу
Снейп
Сопрано
Сосискин
Старк
Сталлоне
Тайсон
Таргариен
Уайт
Уизли
Хлебов
Холмс
Чаплин
Шварценеггер
+80
View File
@@ -0,0 +1,80 @@
// Package namegen produces random Russian-style display names for
// client identities. Name pools are embedded from data/*.txt.
package namegen
import (
_ "embed"
"math/rand/v2"
"strings"
)
//go:embed data/first_names_male.txt
var rawMaleFirstNames string
//go:embed data/first_names_female.txt
var rawFemaleFirstNames string
//go:embed data/last_names.txt
var rawLastNames string
var (
maleFirstNames = parseLines(rawMaleFirstNames)
femaleFirstNames = parseLines(rawFemaleFirstNames)
lastNames = parseLines(rawLastNames)
)
func parseLines(s string) []string {
lines := strings.Split(s, "\n")
out := make([]string, 0, len(lines))
for _, l := range lines {
l = strings.TrimSpace(l)
if l != "" {
out = append(out, l)
}
}
return out
}
// feminizeSurname converts a Russian male surname to its female form.
// Operates on runes since Cyrillic letters are multibyte in UTF-8.
// Surnames whose suffixes do not match Russian patterns are returned
// unchanged (covers foreign / meme surnames).
func feminizeSurname(surname string) string {
rs := []rune(surname)
n := len(rs)
if n < 2 {
return surname
}
switch string(rs[n-2:]) {
case "ий", "ый", "ой":
return string(rs[:n-2]) + "ая"
case "ов", "ев", "ёв", "ин", "ын":
return surname + "а"
}
return surname
}
// SurnameProbability is the chance that Generate returns a name with a surname.
const SurnameProbability = 0.7
// Generate returns a random "FirstName" or "FirstName LastName".
// Gender is chosen uniformly; surnames are feminized for female names.
func Generate() string {
isFemale := rand.IntN(2) == 0
pool := maleFirstNames
if isFemale {
pool = femaleFirstNames
}
fn := pool[rand.IntN(len(pool))]
if rand.Float64() >= SurnameProbability {
return fn
}
ln := lastNames[rand.IntN(len(lastNames))]
if isFemale {
ln = feminizeSurname(ln)
}
return fn + " " + ln
}
+162
View File
@@ -0,0 +1,162 @@
package namegen
import (
"strings"
"testing"
"unicode/utf8"
)
func TestParseLinesStripsBlanksAndWhitespace(t *testing.T) {
in := " Иван \n\nПётр\n\t\nСидор\n"
got := parseLines(in)
want := []string{"Иван", "Пётр", "Сидор"}
if len(got) != len(want) {
t.Fatalf("got %v, want %v", got, want)
}
for i := range want {
if got[i] != want[i] {
t.Errorf("idx %d: got %q, want %q", i, got[i], want[i])
}
}
}
func TestFeminizeSurname(t *testing.T) {
cases := map[string]string{
// -ов / -ев / -ёв / -ин / -ын -> +а
"Иванов": "Иванова",
"Лебедев": "Лебедева",
"Соловьёв": "Соловьёва",
"Никитин": "Никитина",
"Солженицын": "Солженицына",
// -ий / -ый / -ой -> -ая
"Чайковский": "Чайковская",
"Белый": "Белая",
"Толстой": "Толстая",
"Великий": "Великая",
"Раевский": "Раевская",
// Foreign / meme: unchanged
"Скайуокер": "Скайуокер",
"Поттер": "Поттер",
"Бонд": "Бонд",
"Сноу": "Сноу",
"Корлеоне": "Корлеоне",
// Edge cases
"": "",
"А": "А",
}
for in, want := range cases {
if got := feminizeSurname(in); got != want {
t.Errorf("feminizeSurname(%q) = %q, want %q", in, got, want)
}
}
}
func TestPoolsLoaded(t *testing.T) {
if len(maleFirstNames) < 100 {
t.Errorf("male pool too small: %d", len(maleFirstNames))
}
if len(femaleFirstNames) < 50 {
t.Errorf("female pool too small: %d", len(femaleFirstNames))
}
if len(lastNames) < 100 {
t.Errorf("last names pool too small: %d", len(lastNames))
}
t.Logf("pools: male=%d female=%d last=%d", len(maleFirstNames), len(femaleFirstNames), len(lastNames))
}
func TestPoolsNoBlankNoDuplicates(t *testing.T) {
for _, p := range []struct {
name string
data []string
}{
{"male", maleFirstNames},
{"female", femaleFirstNames},
{"last", lastNames},
} {
seen := map[string]bool{}
for _, v := range p.data {
if v == "" {
t.Errorf("%s pool: blank entry", p.name)
}
if !utf8.ValidString(v) {
t.Errorf("%s pool: invalid utf8 %q", p.name, v)
}
if seen[v] {
t.Errorf("%s pool: duplicate %q", p.name, v)
}
seen[v] = true
}
}
}
func TestGenerateProducesPlausibleName(t *testing.T) {
// Build prefix set of valid first names (may contain spaces, e.g. "Абд аль-Узза").
firstNameSet := map[string]bool{}
for _, n := range maleFirstNames {
firstNameSet[n] = true
}
for _, n := range femaleFirstNames {
firstNameSet[n] = true
}
withSurname := 0
const iters = 2000
for range iters {
n := Generate()
if n == "" {
t.Fatal("Generate returned empty string")
}
// Either the whole string is a first name, or it splits into
// "<first name> <surname>" at the LAST space.
if firstNameSet[n] {
continue
}
idx := strings.LastIndex(n, " ")
if idx < 0 {
t.Errorf("unrecognized name %q", n)
continue
}
first, last := n[:idx], n[idx+1:]
if !firstNameSet[first] {
t.Errorf("unknown first-name prefix in %q", n)
}
if last == "" {
t.Errorf("empty surname in %q", n)
}
withSurname++
}
// SurnameProbability = 0.7; allow generous slack to avoid flake.
ratio := float64(withSurname) / float64(iters)
if ratio < 0.6 || ratio > 0.8 {
t.Errorf("surname ratio %.2f out of expected band [0.60, 0.80]", ratio)
}
}
func TestGenerateCoversBothGenders(t *testing.T) {
maleSet := map[string]bool{}
for _, n := range maleFirstNames {
maleSet[n] = true
}
femaleSet := map[string]bool{}
for _, n := range femaleFirstNames {
femaleSet[n] = true
}
sawMale, sawFemale := false, false
for i := 0; i < 5000 && !(sawMale && sawFemale); i++ { //nolint:intrange // need early exit
n := Generate()
first := strings.SplitN(n, " ", 2)[0]
if maleSet[first] {
sawMale = true
}
if femaleSet[first] {
sawFemale = true
}
}
if !sawMale {
t.Error("no male names seen in 5000 iterations")
}
if !sawFemale {
t.Error("no female names seen in 5000 iterations")
}
}
+2 -1
View File
@@ -31,6 +31,7 @@ import (
"github.com/cacggghp/vk-turn-proxy/client/internal/browserprofile"
"github.com/cacggghp/vk-turn-proxy/client/internal/captcha"
"github.com/cacggghp/vk-turn-proxy/client/internal/dnsdial"
"github.com/cacggghp/vk-turn-proxy/client/internal/namegen"
"github.com/cacggghp/vk-turn-proxy/tcputil"
"github.com/cbeuw/connutil"
"github.com/google/uuid"
@@ -584,7 +585,7 @@ func getTokenChain(ctx context.Context, link string, streamID int, creds VKCrede
return "", "", nil, fmt.Errorf("failed to initialize tls_client: %w", err)
}
name := generateName()
name := namegen.Generate()
escapedName := neturl.QueryEscape(name)
log.Printf("[STREAM %d] [VK Auth] Connecting Identity - Name: %s | User-Agent: %s", streamID, name, profile.UserAgent)
-883
View File
@@ -1,883 +0,0 @@
package main
import (
"fmt"
"math/rand"
"strings"
)
var maleFirstNames = []string{
"Аарон",
"Аба",
"Аббас",
"Абд аль-Узза",
"Абдуллах",
"Абид",
"Аботур",
"Аввакум",
"Август",
"Авдей",
"Авель",
"Аверкий",
"Авигдор",
"Авирмэд",
"Авксентий",
"Авл",
"Авнер",
"Аврелий",
"Автандил",
"Автоном",
"Агапит",
"Агафангел",
"Агафодор",
"Агафон",
"Аги",
"Агриппа",
"Адам",
"Адар",
"Адиль",
"Адольф",
"Адонирам",
"Адриан",
"Азамат",
"Азарий",
"Азат",
"Азиз",
"Азим",
"Айварс",
"Айдар",
"Айрат",
"Акакий",
"Аквилий",
"Акиф",
"Акоп",
"Аксель",
"Алан",
"Аланус",
"Алек",
"Александр",
"Алексей",
"Алемдар",
"Алик",
"Алим",
"Алипий",
"Алишер",
"Алмат",
"Алоиз",
"Алон",
"Альберик",
"Альберт",
"Альбин",
"Альваро",
"Альвиан",
"Альвизе",
"Альфонс",
"Альфред",
"Амадис",
"Амвросий",
"Амедей",
"Амин",
"Амир",
"Амр",
"Амфилохий",
"Анания",
"Анас",
"Анастасий",
"Анатолий",
"Ангеляр",
"Андокид",
"Андрей",
"Андроник",
"Аннерс",
"Анри",
"Ансельм",
"Антипа",
"Антон",
"Антоний",
"Антонин",
"Антуан",
"Арам",
"Арефа",
"Арзуман",
"Аристарх",
"Аристон",
"Ариф",
"Аркадий",
"Арсений",
"Артём",
"Артур",
"Арфаксад",
"Асаф",
"Атанасий",
"Атом",
"Аттик",
"Афанасий",
"Афинагор",
"Афиней",
"Афиф",
"Африкан",
"Ахилл",
"Ахмад",
"Ахтям",
"Ашот",
"Бадар",
"Барни",
"Бартоломео",
"Басир",
"Бахтияр",
"Баян",
"Безсон",
"Бен",
"Беньямин",
"Берт",
"Бехруз",
"Билял",
"Богдан",
"Болеслав",
"Бонавентура",
"Борис",
"Борислав",
"Боян",
"Бронислав",
"Брячислав",
"Бурхан",
"Бутрос",
"Бямбасурэн",
"Вадим",
"Валентин",
"Валентино",
"Валерий",
"Валерьян",
"Вальдемар",
"Вангьял",
"Варлам",
"Варнава",
"Варфоломей",
"Василий",
"Вахтанг",
"Велвел",
"Венансио",
"Венедикт",
"Вениамин",
"Венцеслав",
"Вигго",
"Викентий",
"Виктор",
"Викторин",
"Вильгельм",
"Винцас",
"Виссарион",
"Виталий",
"Витаутас",
"Вито",
"Владимир",
"Владислав",
"Владлен",
"Влас",
"Воислав",
"Володарь",
"Вольфганг",
"Вописк",
"Всеволод",
"Всеслав",
"Вук",
"Вукол",
"Вышеслав",
"Вячеслав",
"Габриеле",
"Гавриил",
"Гай",
"Галактион",
"Галымжан",
"Гамлет",
"Гаспар",
"Гафур",
"Гвидо",
"Гейдар",
"Геласий",
"Гелий",
"Гельмут",
"Геннадий",
"Генри",
"Генрих",
"Георге",
"Георгий",
"Гераклид",
"Герасим",
"Герберт",
"Герман",
"Германн",
"Геронтий",
"Герхард",
"Гийом",
"Гильем",
"Гинкмар",
"Глеб",
"Гней",
"Гоар",
"Горацио",
"Гордей",
"Градислав",
"Григорий",
"Гримоальд",
"Гуго",
"Гурий",
"Густав",
"Гьялцен",
"Давид",
"Дамдинсурэн",
"Дамир",
"Даниил",
"Дарий",
"Демид",
"Демьян",
"Денеш",
"Денис",
"Децим",
"Джаббар",
"Джамиль",
"Джан",
"Джанер",
"Джанфранко",
"Джафар",
"Джейкоб",
"Джихангир",
"Джованни",
"Джон",
"Джохар",
"Джулиано",
"Джулиус",
"Дино",
"Диодор",
"Дитер",
"Дитмар",
"Дитрих",
"Дмитрий",
"Доминик",
"Дональд",
"Донат",
"Дорофей",
"Досифей",
"Евгений",
"Евграф",
"Евдоким",
"Еврит",
"Евсей",
"Евстафий",
"Евтихан",
"Евтихий",
"Егор",
"Елеазар",
"Елисей",
"Емельян",
"Епифаний",
"Ербол",
"Ерванд",
"Еремей",
"Ермак",
"Ермолай",
"Ерофей",
"Ефим",
"Ефрем",
"Жан",
"Ждан",
"Жером",
"Жоан",
"Захар",
"Захария",
"Збигнев",
"Зденек",
"Зейналабдин",
"Зенон",
"Зеэв",
"Зигмунд",
"Зинон",
"Зия",
"Золтан",
"Зосима",
"Иакинф",
"Иан",
"Ибрагим",
"Ибрахим",
"Иван",
"Игнатий",
"Игорь",
"Иероним",
"Иерофей",
"Израиль",
"Икрима",
"Иларий",
"Илия",
"Илларион",
"Илмари",
"Ильфат",
"Илья",
"Имран",
"Иннокентий",
"Иоаким",
"Иоанн",
"Иоанникий",
"Иоахим",
"Иов",
"Иоганн",
"Иоганнес",
"Ионафан",
"Иосафат",
"Ираклий",
"Иржи",
"Иринарх",
"Ириней",
"Иродион",
"Иса",
"Исаак",
"Исаакий",
"Исаия",
"Исидор",
"Ислам",
"Исмаил",
"Истислав",
"Истома",
"Истукарий",
"Иштван",
"Йюрген",
"Кадваллон",
"Кадир",
"Казимир",
"Каликст",
"Калин",
"Каллистрат",
"Кальман",
"Канат",
"Карен",
"Карлос",
"Карп",
"Картерий",
"Кассиан",
"Кассий",
"Касторий",
"Касьян",
"Катберт",
"Квинт",
"Кехлер",
"Киллиан",
"Ким",
"Кир",
"Кириак",
"Кирилл",
"Клаас",
"Клавдиан",
"Клеоник",
"Климент",
"Кондрат",
"Конон",
"Конрад",
"Константин",
"Корнелиус",
"Корнилий",
"Коррадо",
"Косьма",
"Кратет",
"Кратипп",
"Крис",
"Криспин",
"Кристиан",
"Кронид",
"Кузьма",
"Куприян",
"Курбан",
"Курт",
"Кутлуг-Буга",
"Кэлин",
"Лаврентий",
"Лавс",
"Ладислав",
"Лазарь",
"Лайл",
"Лампрехт",
"Ландульф",
"Лев",
"Леви",
"Ленни",
"Леонид",
"Леонтий",
"Леонхард",
"Лиам",
"Линкей",
"Логгин",
"Лоренц",
"Лоренцо",
"Луи",
"Луитпольд",
"Лука",
"Лукас",
"Лукий",
"Лукьян",
"Луций",
"Людовик",
"Люцифер",
"Макар",
"Максим",
"Максимиан",
"Максимилиан",
"Малик",
"Малх",
"Мамбет",
"Маний",
"Мануил",
"Мануэль",
"Мариан",
"Мариус",
"Марк",
"Маркел",
"Мартын",
"Марчелло",
"Матвей",
"Матео",
"Матиас",
"Матфей",
"Матфий",
"Махмуд",
"Меир",
"Мелентий",
"Мелитон",
"Менахем-Мендель",
"Месроп",
"Мефодий",
"Мечислав",
"Мика",
"Микеланджело",
"Микулаш",
"Милорад",
"Мина",
"Мирко",
"Мирон",
"Мирослав",
"Митрофан",
"Михаил",
"Михей",
"Младан",
"Модест",
"Моисей",
"Мордехай",
"Мстислав",
"Мурад",
"Мухаммед",
"Мэдисон",
"Мэлор",
"Мэлс",
"Назар",
"Наиль",
"Насиф",
"Натан",
"Натаниэль",
"Наум",
"Нафанаил",
"Нацагдорж",
"Нестор",
"Никандр",
"Никанор",
"Никита",
"Никифор",
"Никодим",
"Николай",
"Нил",
"Нильс",
"Ноа",
"Ной",
"Норд",
"Нуржан",
"Нурлан",
"Овадья",
"Оге",
"Одинец",
"Октав",
"Октавиан",
"Октавий",
"Октавио",
"Олаф",
"Оле",
"Олег",
"Оливер",
"Ольгерд",
"Онисим",
"Орест",
"Осип",
"Оскар",
"Осман",
"Отто",
"Оттон",
"Очирбат",
"Пабло",
"Павел",
"Павлин",
"Павсикакий",
"Паисий",
"Палладий",
"Панкратий",
"Пантелеймон",
"Папа",
"Паруйр",
"Парфений",
"Патрик",
"Пафнутий",
"Пахомий",
"Педро",
"Пётр",
"Пимен",
"Пинхас",
"Пипин",
"Питирим",
"Пол",
"Полидор",
"Полиевкт",
"Поликарп",
"Поликрат",
"Порфирий",
"Потап",
"Предраг",
"Премысл",
"Приск",
"Прокл",
"Прокопий",
"Прокул",
"Протасий",
"Прохор",
"Публий",
"Рагнар",
"Рагуил",
"Радмир",
"Радослав",
"Разумник",
"Раймонд",
"Рамадан",
"Рамазан",
"Рахман",
"Рашад",
"Рейнхард",
"Ренат",
"Реститут",
"Ричард",
"Роберт",
"Родерик",
"Родион",
"Рожер",
"Розарио",
"Роман",
"Ромен",
"Рон",
"Ронан",
"Ростислав",
"Рудольф",
"Руслан",
"Руф",
"Руфин",
"Рушан",
"Сабит",
"Савва",
"Савватий",
"Савелий",
"Савин",
"Саддам",
"Садик",
"Саид",
"Салават",
"Салих",
"Саллюстий",
"Салман",
"Самуил",
"Сармат",
"Святослав",
"Севастьян",
"Северин",
"Секст",
"Секунд",
"Семён",
"Септимий",
"Серапион",
"Сергей",
"Серж",
"Сигеберт",
"Сильвестр",
"Симеон",
"Симон",
"Созон",
"Соломон",
"Сонам",
"Софрон",
"Спиридон",
"Срджан",
"Станислав",
"Степан",
"Стефано",
"Стивен",
"Таврион",
"Тавус",
"Тадеуш",
"Тарас",
"Тарасий",
"Тейс",
"Тендзин",
"Теофил",
"Терентий",
"Терри",
"Тиберий",
"Тигран",
"Тимофей",
"Тимур",
"Тихомир",
"Тихон",
"Томас",
"Томоми",
"Торос",
"Тофик",
"Трифон",
"Трофим",
"Тудхалия",
"Тутмос",
"Тьерри",
"Тьяго",
"Уве",
"Уильям",
"Улдис",
"Ульрих",
"Ульф",
"Умар",
"Урызмаг",
"Усама",
"Усман",
"Фавст",
"Фаддей",
"Файзулла",
"Фарид",
"Фахраддин",
"Федериго",
"Фёдор",
"Федосей",
"Федот",
"Фейсал",
"Феликс",
"Феоктист",
"Феофан",
"Феофил",
"Феофилакт",
"Фердинанд",
"Ференц",
"Фидель",
"Филарет",
"Филат",
"Филип",
"Филипп",
"Философ",
"Филострат",
"Фирс",
"Фока",
"Фома",
"Фотий",
"Франц",
"Франческо",
"Фредерик",
"Фридрих",
"Фродо",
"Фрол",
"Фульк",
"Хайме",
"Ханс",
"Харальд",
"Харитон",
"Харри",
"Харрисон",
"Хасан",
"Хетаг",
"Хильдерик",
"Хирам",
"Хлодвиг",
"Хокон",
"Хорив",
"Хоселито",
"Хосрой",
"Хрисанф",
"Христофор",
"Хуан",
"Цэрэндорж",
"Чеслав",
"Шалом",
"Шамиль",
"Шамсуддин",
"Шапур",
"Шарль",
"Шейх-Хайдар",
"Шон",
"Эберхард",
"Эдмунд",
"Эдна",
"Эдуард",
"Элбэгдорж",
"Элджернон",
"Элиас",
"Эллиот",
"Эмиль",
"Энрик",
"Энрико",
"Энтони",
"Эразм",
"Эраст",
"Эрик",
"Эрнст",
"Эсекьель",
"Эстебан",
"Этьен",
"Ювеналий",
"Юлиан",
"Юлий",
"Юлиус",
"Юрий",
"Юстас",
"Юстин",
"Яков",
"Якуб",
"Якун",
"Ян",
"Яни",
"Януарий",
"Яромир",
"Ярополк",
"Ярослав",
}
var femaleFirstNames = []string{
"Алина",
"Алёна",
"Анастасия",
"Ангелина",
"Анна",
"Вера",
"Вероника",
"Виктория",
"Дарья",
"Ева",
"Екатерина",
"Елена",
"Елизавета",
"Ирина",
"Кира",
"Кристина",
"Ксения",
"Любовь",
"Маргарита",
"Марина",
"Мария",
"Милана",
"Надежда",
"Наталья",
"Ольга",
"Полина",
"Светлана",
"София",
"Татьяна",
"Юлия",
"Яна",
}
var lastNames = []string{
"Алексеев",
"Андреев",
"Антонов",
"Баранов",
"Белов",
"Белый",
"Бельский",
"Беляев",
"Борисов",
"Васильев",
"Великий",
"Волков",
"Воробьёв",
"Григорьев",
"Давыдов",
"Егоров",
"Жуков",
"Зайцев",
"Захаров",
"Иванов",
"Калинин",
"Ковалёв",
"Козлов",
"Комаров",
"Крамской",
"Кузнецов",
"Кузьмин",
"Лебедев",
"Макаров",
"Медведев",
"Михайлов",
"Морозов",
"Никитин",
"Николаев",
"Новиков",
"Орлов",
"Островский",
"Павлов",
"Петров",
"Покровский",
"Попов",
"Раевский",
"Романов",
"Семёнов",
"Сергеев",
"Смирнов",
"Соколов",
"Соловьёв",
"Степанов",
"Тарасов",
"Титов",
"Толстой",
"Трубецкой",
"Филиппов",
"Фролов",
"Фёдоров",
"Чайковский",
"Черный",
"Яковлев",
}
// convertToFemaleSurname handles Russian suffix rules
func convertToFemaleSurname(surname string) string {
// Handle adjective-style surnames:
if strings.HasSuffix(surname, "ий") || strings.HasSuffix(surname, "ый") || strings.HasSuffix(surname, "ой") {
return surname[:len(surname)-4] + "ая"
}
// Handle standard possessive surnames:
if strings.HasSuffix(surname, "ов") || strings.HasSuffix(surname, "ев") ||
strings.HasSuffix(surname, "ин") || strings.HasSuffix(surname, "ын") ||
strings.HasSuffix(surname, "ёв") {
return surname + "а"
}
// Foreign or unchangeable
return surname
}
func generateName() string {
// Decide gender first
isFemale := rand.Intn(2) == 0
var fn string
if isFemale {
fn = femaleFirstNames[rand.Intn(len(femaleFirstNames))]
} else {
fn = maleFirstNames[rand.Intn(len(maleFirstNames))]
}
// 70% chance to have a last name
if rand.Float32() < 0.3 {
return fn
}
ln := lastNames[rand.Intn(len(lastNames))]
if isFemale {
ln = convertToFemaleSurname(ln)
}
return fmt.Sprintf("%s %s", fn, ln)
}