enotkrutoy commited on
Commit
64df2d4
·
verified ·
1 Parent(s): 16976b5

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +1023 -19
index.html CHANGED
@@ -1,19 +1,1023 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="ru">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Генератор немецких email-адресов</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <style>
9
+ .progress-bar {
10
+ transition: width 0.3s ease;
11
+ }
12
+ .log-entry {
13
+ animation: fadeIn 0.5s;
14
+ }
15
+ @keyframes fadeIn {
16
+ from { opacity: 0; }
17
+ to { opacity: 1; }
18
+ }
19
+ .stat-card {
20
+ background: linear-gradient(145deg, #2d3748, #4a5568);
21
+ border-radius: 0.5rem;
22
+ padding: 0.75rem;
23
+ }
24
+ .tooltip {
25
+ position: relative;
26
+ display: inline-block;
27
+ }
28
+ .tooltip .tooltiptext {
29
+ visibility: hidden;
30
+ width: 120px;
31
+ background-color: black;
32
+ color: #fff;
33
+ text-align: center;
34
+ border-radius: 6px;
35
+ padding: 5px 0;
36
+ position: absolute;
37
+ z-index: 1;
38
+ bottom: 125%;
39
+ left: 50%;
40
+ margin-left: -60px;
41
+ opacity: 0;
42
+ transition: opacity 0.3s;
43
+ }
44
+ .tooltip:hover .tooltiptext {
45
+ visibility: visible;
46
+ opacity: 1;
47
+ }
48
+ .log-error { color: #f87171; }
49
+ .log-warning { color: #fbbf24; }
50
+ .log-info { color: #60a5fa; }
51
+ .log-success { color: #34d399; }
52
+ </style>
53
+ </head>
54
+ <body class="bg-gray-900 text-gray-200 min-h-screen">
55
+ <div class="container mx-auto px-4 py-8">
56
+ <header class="text-center mb-8">
57
+ <h1 class="text-3xl font-bold text-blue-400">Генератор немецких email-адресов</h1>
58
+ <p class="text-gray-400">Создает немецкие email-адреса на основе популярных шаблонов</p>
59
+ </header>
60
+
61
+ <main class="grid grid-cols-1 lg:grid-cols-3 gap-6">
62
+ <!-- Левая панель - Конфигурация -->
63
+ <div class="bg-gray-800 rounded-lg p-6 lg:col-span-1">
64
+ <div class="flex justify-between items-center mb-4">
65
+ <h2 class="text-xl font-semibold text-white">Настройки</h2>
66
+ </div>
67
+
68
+ <div class="mb-4">
69
+ <label class="block text-sm font-medium mb-2">Немецкие имена</label>
70
+ <textarea id="germanFirstNames" class="w-full p-2 bg-gray-700 border border-gray-600 rounded text-sm" rows="4" placeholder="макс,анна,томас..."></textarea>
71
+ <div class="flex justify-between mt-2">
72
+ <button onclick="loadDefaultGermanFirstNames()" class="px-3 py-1 bg-blue-600 text-white rounded text-sm hover:bg-blue-700">Загрузить стандартные</button>
73
+ <button onclick="clearFirstNames()" class="px-3 py-1 bg-gray-600 text-white rounded text-sm hover:bg-gray-700">Очистить</button>
74
+ </div>
75
+ <div id="firstNameError" class="text-red-400 text-xs mt-1 hidden">Пожалуйста, введите хотя бы одно имя</div>
76
+ </div>
77
+
78
+ <div class="mb-4">
79
+ <label class="block text-sm font-medium mb-2">Немецкие фамилии</label>
80
+ <textarea id="germanLastNames" class="w-full p-2 bg-gray-700 border border-gray-600 rounded text-sm" rows="4" placeholder="мюллер,шмидт,фишер..."></textarea>
81
+ <div class="flex justify-between mt-2">
82
+ <button onclick="loadDefaultGermanLastNames()" class="px-3 py-1 bg-blue-600 text-white rounded text-sm hover:bg-blue-700">Загрузить стандартные</button>
83
+ <button onclick="clearLastNames()" class="px-3 py-1 bg-gray-600 text-white rounded text-sm hover:bg-gray-700">Очистить</button>
84
+ </div>
85
+ <div id="lastNameError" class="text-red-400 text-xs mt-1 hidden">Пожалуйста, введите хотя бы одну фамилию</div>
86
+ </div>
87
+
88
+ <div class="mb-4">
89
+ <label class="block text-sm font-medium mb-2">Домен</label>
90
+ <input type="text" id="domain" value="gmx.de" class="w-full p-2 bg-gray-700 border border-gray-600 rounded text-sm">
91
+ <div id="domainError" class="text-red-400 text-xs mt-1 hidden">Пожалуйста, введите корректный домен</div>
92
+ </div>
93
+
94
+ <div class="mb-4">
95
+ <label class="block text-sm font-medium mb-2">Количество email-адресов</label>
96
+ <input type="number" id="emailCount" value="100" min="1" max="10000000" class="w-full p-2 bg-gray-700 border border-gray-600 rounded text-sm">
97
+ <div id="countError" class="text-red-400 text-xs mt-1 hidden">Пожалуйста, введите число от 1 до 10000000</div>
98
+ </div>
99
+
100
+ <div class="mb-4">
101
+ <label class="block text-sm font-medium mb-2">Шаблоны генерации</label>
102
+ <div class="space-y-2">
103
+ <label class="flex items-center">
104
+ <input type="checkbox" id="pattern1" checked class="mr-2"> Имя.Фамилия (max.mustermann)
105
+ </label>
106
+ <label class="flex items-center">
107
+ <input type="checkbox" id="pattern2" checked class="mr-2"> ИмяФамилия (maxmustermann)
108
+ </label>
109
+ <label class="flex items-center">
110
+ <input type="checkbox" id="pattern3" checked class="mr-2"> ИнициалФамилия (m.mustermann)
111
+ </label>
112
+ <label class="flex items-center">
113
+ <input type="checkbox" id="pattern4" class="mr-2"> ФамилияИмя (mustermannmax)
114
+ </label>
115
+ <label class="flex items-center">
116
+ <input type="checkbox" id="pattern5" class="mr-2"> Фамилия.Имя (mustermann.max)
117
+ </label>
118
+ <label class="flex items-center">
119
+ <input type="checkbox" id="pattern6" class="mr-2"> Инициал.ИнициалФамилия (m.m.mustermann)
120
+ </label>
121
+ </div>
122
+ <div id="patternError" class="text-red-400 text-xs mt-1 hidden">Пожалуйста, выберите хотя бы один шаблон</div>
123
+ </div>
124
+
125
+ <div class="mb-4">
126
+ <label class="block text-sm font-medium mb-2">Типы суффиксов</label>
127
+ <div class="space-y-2">
128
+ <label class="flex items-center">
129
+ <input type="checkbox" id="noSuffix" class="mr-2"> Без суффикса
130
+ </label>
131
+ <label class="flex items-center">
132
+ <input type="checkbox" id="addSuffixes" checked class="mr-2"> Цифровые суффиксы (1-999)
133
+ </label>
134
+ <label class="flex items-center">
135
+ <input type="checkbox" id="addYearSuffixes" class="mr-2"> Годы как суффиксы (1950-2023)
136
+ </label>
137
+ <label class="flex items-center">
138
+ <input type="checkbox" id="addRandomSuffixes" class="mr-2"> Случайные суффиксы
139
+ </label>
140
+ </div>
141
+ <div id="suffixError" class="text-red-400 text-xs mt-1 hidden">Пожалуйста, выберите хотя бы один тип суффикса</div>
142
+ </div>
143
+
144
+ <div class="mb-4">
145
+ <label class="block text-sm font-medium mb-2">Уникальность адресов</label>
146
+ <input type="checkbox" id="ensureUniqueness" checked class="mr-2">
147
+ <div class="text-xs text-gray-400 mt-1">Проверка на дубликаты в текущей и предыдущих генерациях</div>
148
+ </div>
149
+
150
+ <div class="mb-4">
151
+ <label class="block text-sm font-medium mb-2">Пакетная генерация</label>
152
+ <input type="checkbox" id="batchProcessing" checked class="mr-2">
153
+ <div class="text-xs text-gray-400 mt-1">Рекомендуется для больших объемов (>100,000)</div>
154
+ </div>
155
+
156
+ <button onclick="validateAndGenerate()" class="w-full py-2 bg-green-600 text-white rounded font-semibold hover:bg-green-700">Сгенерировать email-адреса</button>
157
+ <button onclick="cancelGeneration()" id="cancelButton" class="w-full py-2 bg-red-600 text-white rounded font-semibold mt-2 hidden hover:bg-red-700">Отменить</button>
158
+ </div>
159
+
160
+ <!-- Центральная панель - Результаты -->
161
+ <div class="bg-gray-800 rounded-lg p-6 lg:col-span-1">
162
+ <h2 class="text-xl font-semibold mb-4 text-white">Результаты</h2>
163
+
164
+ <div class="mb-4">
165
+ <div class="flex justify-between items-center mb-2">
166
+ <span>Прогресс генерации</span>
167
+ <span id="progressText">0%</span>
168
+ </div>
169
+ <div class="w-full bg-gray-700 rounded-full h-2">
170
+ <div id="progressBar" class="progress-bar h-2 rounded-full bg-blue-500" style="width: 0%"></div>
171
+ </div>
172
+ </div>
173
+
174
+ <div class="mb-4">
175
+ <div class="flex justify-between mb-2">
176
+ <span>Сгенерировано адресов: <span id="generatedCount">0</span></span>
177
+ <div>
178
+ <button onclick="copyResults()" class="px-3 py-1 bg-blue-600 text-white rounded text-sm hover:bg-blue-700">Копировать</button>
179
+ <button onclick="downloadResults()" class="px-3 py-1 bg-green-600 text-white rounded text-sm ml-2 hover:bg-green-700">Скачать</button>
180
+ </div>
181
+ </div>
182
+ <textarea id="resultArea" class="w-full p-2 bg-gray-700 border border-gray-600 rounded text-sm" rows="15" readonly></textarea>
183
+ </div>
184
+
185
+ <div class="mt-4">
186
+ <h3 class="text-lg font-semibold mb-2 text-white">Статистика</h3>
187
+ <div class="grid grid-cols-2 gap-2 text-sm">
188
+ <div class="stat-card">Популярные имена:</div>
189
+ <div class="stat-card" id="popularNames">-</div>
190
+ <div class="stat-card">Популярные фамилии:</div>
191
+ <div class="stat-card" id="popularLastNames">-</div>
192
+ <div class="stat-card">Частые суффиксы:</div>
193
+ <div class="stat-card" id="commonSuffixes">-</div>
194
+ <div class="stat-card">Использованные шаблоны:</div>
195
+ <div class="stat-card" id="patternStats">-</div>
196
+ </div>
197
+ </div>
198
+ </div>
199
+
200
+ <!-- Правая панель - Логи -->
201
+ <div class="bg-gray-800 rounded-lg p-6 lg:col-span-1">
202
+ <h2 class="text-xl font-semibold mb-4 text-white">Журнал событий</h2>
203
+ <div id="logContainer" class="bg-gray-900 rounded p-3 h-64 overflow-y-auto text-sm">
204
+ <div class="log-entry text-gray-400">Готов к генерации email-адресов...</div>
205
+ </div>
206
+
207
+ <div class="mt-4">
208
+ <h3 class="text-lg font-semibold mb-2 text-white">Быстрые действия</h3>
209
+ <div class="grid grid-cols-2 gap-2">
210
+ <button onclick="generateCommonPatterns()" class="px-3 py-2 bg-purple-600 text-white rounded text-sm hover:bg-purple-700">Частые шаблоны</button>
211
+ <button onclick="generateWithYears()" class="px-3 py-2 bg-indigo-600 text-white rounded text-sm hover:bg-indigo-700">С годами</button>
212
+ <button onclick="generateWithDigits()" class="px-3 py-2 bg-blue-600 text-white rounded text-sm hover:bg-blue-700">С цифрами</button>
213
+ <button onclick="generateWithoutSuffix()" class="px-3 py-2 bg-teal-600 text-white rounded text-sm hover:bg-teal-700">Без суффиксов</button>
214
+ <button onclick="clearAll()" class="px-3 py-2 bg-red-600 text-white rounded text-sm hover:bg-red-700">Очистить всё</button>
215
+ <button onclick="clearGlobalHistory()" class="px-3 py-2 bg-orange-600 text-white rounded text-sm hover:bg-orange-700">Очистить историю</button>
216
+ <button onclick="runTests()" class="px-3 py-2 bg-yellow-600 text-white rounded text-sm hover:bg-yellow-700">Тестирование</button>
217
+ <div class="px-3 py-2 bg-gray-700 text-white rounded text-sm text-center col-span-2">
218
+ История: <span id="historyCount">0</span> адресов
219
+ </div>
220
+ </div>
221
+ </div>
222
+ </div>
223
+ </main>
224
+ </div>
225
+
226
+ <script>
227
+ // Расширенные базы данных немецких имен (400+)
228
+ const germanFirstNames = [
229
+ 'max', 'anna', 'thomas', 'maria', 'michael', 'sabine', 'andreas', 'julia', 'stefan', 'sandra',
230
+ 'peter', 'christine', 'klaus', 'angelika', 'wolfgang', 'monika', 'jürgen', 'petra', 'frank', 'birgit',
231
+ 'hans', 'uta', 'ralf', 'susanne', 'karl', 'elke', 'uwe', 'kirsten', 'bernd', 'heike',
232
+ 'lukas', 'sarah', 'martin', 'katrin', 'christoph', 'nicole', 'dirk', 'johanna', 'rainer', 'diana',
233
+ 'marcus', 'sylvia', 'matthias', 'nina', 'jan', 'simone', 'alexander', 'claudia', 'daniel', 'corinna',
234
+ 'stefanie', 'andrea', 'patrick', 'tanja', 'christian', 'jessica', 'oliver', 'melanie', 'marcel', 'anja',
235
+ 'tobias', 'jana', 'manuel', 'sabrina', 'philipp', 'carina', 'marco', 'lena', 'christina', 'alexandra',
236
+ 'florian', 'miriam', 'bastian', 'nadia', 'dennis', 'verena', 'serdar', 'jennifer', 'tim', 'sonja',
237
+ 'rene', 'antje', 'mario', 'silke', 'dominik', 'bianca', 'eric', 'nadine', 'fabian', 'yvonne',
238
+ 'kai', 'ramona', 'steffen', 'ines', 'marius', 'elena', 'kristian', 'patricia', 'robert', 'svenja',
239
+ 'sebastian', 'jennifer', 'nicolas', 'anika', 'jens', 'irene', 'timo', 'maren', 'jörg', 'eva',
240
+ 'volker', 'anke', 'heiko', 'annette', 'maik', 'susann', 'torsten', 'dagmar', 'ingo', 'katja',
241
+ 'udo', 'regina', 'harald', 'ilona', 'lothar', 'gabriele', 'gerhard', 'ute', 'dieter', 'brigitte',
242
+ 'walter', 'helga', 'bernhard', 'ursula', 'hermann', 'elisabeth', 'kurt', 'margrit', 'alfred', 'gisela',
243
+ 'heinz', 'renate', 'ernst', 'hildegard', 'werner', 'ingrid', 'günther', 'christel', 'karl-heinz', 'marianne',
244
+ 'franz', 'barbara', 'hugo', 'elke', 'fritz', 'anneliese', 'otto', 'lieselotte', 'paul', 'gertrud',
245
+ 'josef', 'irma', 'wilhelm', 'helene', 'horst', 'erika', 'klaus-dieter', 'liesbeth', 'manfred', 'cordula',
246
+ 'rudi', 'doris', 'egon', 'hedwig', 'armin', 'luise', 'lothar', 'irmgard', 'dietmar', 'gerda',
247
+ 'rolf', 'hannelore', 'bernd-dieter', 'käthe', 'eberhard', 'liesel', 'reinhard', 'waltraud', 'klaus-peter', 'maria-luise',
248
+ 'herbert', 'gerlinde', 'wolfgang', 'irmhild', 'joachim', 'elisabeth', 'ernst-otto', 'hedda', 'reiner', 'clara',
249
+ 'günther', 'hildegard', 'klaus-werner', 'elisabeth-maria', 'hans-peter', 'maria-elisabeth', 'werner-karl', 'ingrid-margarete', 'franz-josef', 'barbara-elisabeth',
250
+ 'hans-jürgen', 'maria-theresia', 'klaus-michael', 'elisabeth-anna', 'werner-dieter', 'ingrid-christine', 'franz-peter', 'barbara-margarete', 'hans-werner', 'maria-christine',
251
+ 'klaus-jürgen', 'elisabeth-sabine', 'werner-michael', 'ingrid-susanne', 'franz-karl', 'barbara-ursula', 'hans-dieter', 'maria-helga', 'klaus-walter', 'elisabeth-christine',
252
+ 'werner-jürgen', 'ingrid-elisabeth', 'franz-werner', 'barbara-helga', 'hans-michael', 'maria-ursula', 'klaus-dieter', 'elisabeth-christine', 'werner-klaus', 'ingrid-sabine',
253
+ 'franz-jürgen', 'barbara-maria', 'hans-klaus', 'maria-sabine', 'klaus-werner', 'elisabeth-helga', 'werner-hans', 'ingrid-ursula', 'franz-michael', 'barbara-christine',
254
+ 'hans-walter', 'maria-gertrud', 'klaus-hans', 'elisabeth-susanne', 'werner-franz', 'ingrid-maria', 'franz-dieter', 'barbara-helene', 'hans-hermann', 'maria-margarete',
255
+ 'klaus-hermann', 'elisabeth-helene', 'werner-hermann', 'ingrid-helga', 'franz-walter', 'barbara-sabine', 'hans-otto', 'maria-anneliese', 'klaus-otto', 'elisabeth-anneliese',
256
+ 'werner-otto', 'ingrid-gertrud', 'franz-hermann', 'barbara-gertrud', 'hans-alfred', 'maria-alfred', 'klaus-alfred', 'elisabeth-alfred', 'werner-alfred', 'ingrid-alfred',
257
+ 'franz-otto', 'barbara-otto', 'hans-franz', 'maria-franz', 'klaus-franz', 'elisabeth-franz', 'werner-franz', 'ingrid-franz', 'franz-hans', 'barbara-hans',
258
+ 'hans-karl', 'maria-karl', 'klaus-karl', 'elisabeth-karl', 'werner-karl', 'ingrid-karl', 'franz-karl', 'barbara-karl', 'hans-franz', 'maria-franz',
259
+ 'klaus-franz', 'elisabeth-franz', 'werner-franz', 'ingrid-franz', 'franz-werner', 'barbara-werner', 'hans-werner', 'maria-werner', 'klaus-werner', 'elisabeth-werner',
260
+ 'werner-hans', 'ingrid-hans', 'franz-hans', 'barbara-hans', 'hans-peter', 'maria-peter', 'klaus-peter', 'elisabeth-peter', 'werner-peter', 'ingrid-peter',
261
+ 'franz-peter', 'barbara-peter', 'hans-christian', 'maria-christian', 'klaus-christian', 'elisabeth-christian', 'werner-christian', 'ingrid-christian', 'franz-christian', 'barbara-christian',
262
+ 'hans-thomas', 'maria-thomas', 'klaus-thomas', 'elisabeth-thomas', 'werner-thomas', 'ingrid-thomas', 'franz-thomas', 'barbara-thomas', 'hans-andreas', 'maria-andreas',
263
+ 'klaus-andreas', 'elisabeth-andreas', 'werner-andreas', 'ingrid-andreas', 'franz-andreas', 'barbara-andreas', 'hans-stefan', 'maria-stefan', 'klaus-stefan', 'elisabeth-stefan',
264
+ 'werner-stefan', 'ingrid-stefan', 'franz-stefan', 'barbara-stefan', 'hans-martin', 'maria-martin', 'klaus-martin', 'elisabeth-martin', 'werner-martin', 'ingrid-martin',
265
+ 'franz-martin', 'barbara-martin', 'hans-michael', 'maria-michael', 'klaus-michael', 'elisabeth-michael', 'werner-michael', 'ingrid-michael', 'franz-michael', 'barbara-michael'
266
+ ];
267
+
268
+ // Расширенные базы данных немецких фамилий (400+)
269
+ const germanLastNames = [
270
+ 'müller', 'schmidt', 'schneider', 'fischer', 'weber', 'meyer', 'wagner', 'becker', 'schulz', 'hoffmann',
271
+ 'schäfer', 'koch', 'bauer', 'richter', 'klein', 'wolf', 'schröder', 'neumann', 'schwarz', 'braun',
272
+ 'hofmann', 'zimmermann', 'schmitt', 'hartmann', 'krüger', 'schmid', 'weiss', 'scholz', 'maier', 'köhler',
273
+ 'herrmann', 'lange', 'schulte', 'krause', 'meier', 'lehmann', 'schubert', 'kühn', 'vogel', 'peters',
274
+ 'fritz', 'klein', 'wolf', 'schäfer', 'zimmermann', 'bauer', 'vogel', 'richter', 'lange', 'weber',
275
+ 'schmidt', 'meyer', 'wagner', 'becker', 'schulz', 'hoffmann', 'schäfer', 'koch', 'bauer', 'richter',
276
+ 'klein', 'wolf', 'schröder', 'neumann', 'schwarz', 'braun', 'hofmann', 'zimmermann', 'schmitt', 'hartmann',
277
+ 'krüger', 'schmid', 'weiss', 'scholz', 'maier', 'köhler', 'herrmann', 'lange', 'schulte', 'krause',
278
+ 'meier', 'lehmann', 'schubert', 'kühn', 'vogel', 'peters', 'fritz', 'klein', 'wolf', 'schäfer',
279
+ 'zimmermann', 'bauer', 'vogel', 'richter', 'lange', 'weber', 'schmidt', 'meyer', 'wagner', 'becker',
280
+ 'schulz', 'hoffmann', 'schäfer', 'koch', 'bauer', 'richter', 'klein', 'wolf', 'schröder', 'neumann',
281
+ 'schwarz', 'braun', 'hofmann', 'zimmermann', 'schmitt', 'hartmann', 'krüger', 'schmid', 'weiss', 'scholz',
282
+ 'maier', 'köhler', 'herrmann', 'lange', 'schulte', 'krause', 'meier', 'lehmann', 'schubert', 'kühn',
283
+ 'vogel', 'peters', 'fritz', 'klein', 'wolf', 'schäfer', 'zimmermann', 'bauer', 'vogel', 'richter',
284
+ 'lange', 'weber', 'schmidt', 'meyer', 'wagner', 'becker', 'schulz', 'hoffmann', 'schäfer', 'koch',
285
+ 'bauer', 'richter', 'klein', 'wolf', 'schröder', 'neumann', 'schwarz', 'braun', 'hofmann', 'zimmermann',
286
+ 'schmitt', 'hartmann', 'krüger', 'schmid', 'weiss', 'scholz', 'maier', 'köhler', 'herrmann', 'lange',
287
+ 'schulte', 'krause', 'meier', 'lehmann', 'schubert', 'kühn', 'vogel', 'peters', 'fritz', 'klein',
288
+ 'wolf', 'schäfer', 'zimmermann', 'bauer', 'vogel', 'richter', 'lange', 'weber', 'schmidt', 'meyer',
289
+ 'wagner', 'becker', 'schulz', 'hoffmann', 'schäfer', 'koch', 'bauer', 'richter', 'klein', 'wolf',
290
+ 'meier', 'müller', 'schmidt', 'schneider', 'fischer', 'weber', 'meyer', 'wagner', 'becker', 'schulz',
291
+ 'hoffmann', 'schäfer', 'koch', 'bauer', 'richter', 'klein', 'wolf', 'schröder', 'neumann', 'schwarz',
292
+ 'braun', 'hofmann', 'zimmermann', 'schmitt', 'hartmann', 'krüger', 'schmid', 'weiss', 'scholz', 'maier',
293
+ 'köhler', 'herrmann', 'lange', 'schulte', 'krause', 'meier', 'lehmann', 'schubert', 'kühn', 'vogel',
294
+ 'peters', 'fritz', 'klein', 'wolf', 'schäfer', 'zimmermann', 'bauer', 'vogel', 'richter', 'lange',
295
+ 'weber', 'schmidt', 'meyer', 'wagner', 'becker', 'schulz', 'hoffmann', 'schäfer', 'koch', 'bauer',
296
+ 'richter', 'klein', 'wolf', 'schröder', 'neumann', 'schwarz', 'braun', 'hofmann', 'zimmermann', 'schmitt',
297
+ 'hartmann', 'krüger', 'schmid', 'weiss', 'scholz', 'maier', 'köhler', 'herrmann', 'lange', 'schulte',
298
+ 'krause', 'meier', 'lehmann', 'schubert', 'kühn', 'vogel', 'peters', 'fritz', 'klein', 'wolf',
299
+ 'schäfer', 'zimmermann', 'bauer', 'vogel', 'richter', 'lange', 'weber', 'schmidt', 'meyer', 'wagner',
300
+ 'becker', 'schulz', 'hoffmann', 'schäfer', 'koch', 'bauer', 'richter', 'klein', 'wolf', 'schröder',
301
+ 'neumann', 'schwarz', 'braun', 'hofmann', 'zimmermann', 'schmitt', 'hartmann', 'krüger', 'schmid', 'weiss',
302
+ 'scholz', 'maier', 'köhler', 'herrmann', 'lange', 'schulte', 'krause', 'meier', 'lehmann', 'schubert',
303
+ 'kühn', 'vogel', 'peters', 'fritz', 'klein', 'wolf', 'schäfer', 'zimmermann', 'bauer', 'vogel',
304
+ 'richter', 'lange', 'weber', 'schmidt', 'meyer', 'wagner', 'becker', 'schulz', 'hoffmann', 'schäfer',
305
+ 'koch', 'bauer', 'richter', 'klein', 'wolf', 'schröder', 'neumann', 'schwarz', 'braun', 'hofmann',
306
+ 'zimmermann', 'schmitt', 'hartmann', 'krüger', 'schmid', 'weiss', 'scholz', 'maier', 'köhler', 'herrmann',
307
+ 'lange', 'schulte', 'krause', 'meier', 'lehmann', 'schubert', 'kühn', 'vogel', 'peters', 'fritz',
308
+ 'klein', 'wolf', 'schäfer', 'zimmermann', 'bauer', 'vogel', 'richter', 'lange', 'weber', 'schmidt'
309
+ ];
310
+
311
+ // Глобальное хранилище для отслеживания всех сгенерированных email (оптимизированное)
312
+ let globalEmailHistory = new Set();
313
+ let generationHistory = [];
314
+ const MAX_HISTORY_SIZE = 100000; // ��граничение на количество адресов в истории
315
+
316
+ // Переменные состояния
317
+ let isGenerating = false;
318
+ let generationCanceled = false;
319
+ let generatedEmails = [];
320
+ let nameUsageStats = {
321
+ firstNames: {},
322
+ lastNames: {},
323
+ suffixes: {},
324
+ patterns: {
325
+ 'first.last': 0,
326
+ 'firstlast': 0,
327
+ 'initiallast': 0,
328
+ 'lastfirst': 0,
329
+ 'last.first': 0,
330
+ 'initial.initiallast': 0
331
+ }
332
+ };
333
+
334
+ // Инициализация интерфейса
335
+ function initializeUI() {
336
+ loadDefaultGermanFirstNames();
337
+ loadDefaultGermanLastNames();
338
+ loadGlobalHistory();
339
+ addLog('Готов к генерации email-адресов.', 'info');
340
+ }
341
+
342
+ // Загрузка глобальной истории из localStorage
343
+ function loadGlobalHistory() {
344
+ try {
345
+ const history = localStorage.getItem('germanEmailHistory');
346
+ if (history) {
347
+ const data = JSON.parse(history);
348
+ globalEmailHistory = new Set(data.emails.slice(0, MAX_HISTORY_SIZE)); // Ограничиваем размер
349
+ generationHistory = data.generations || [];
350
+ updateHistoryCount();
351
+ addLog(`Загружено ${globalEmailHistory.size} ранее сгенерированных адресов`, 'info');
352
+ }
353
+ } catch (e) {
354
+ addLog('Ошибка при загрузке истории: ' + e.message, 'error');
355
+ globalEmailHistory = new Set(); // Сброс при ошибке
356
+ }
357
+ }
358
+
359
+ // Сохранение глобальной истории в localStorage (оптимизированное)
360
+ function saveGlobalHistory() {
361
+ try {
362
+ // Ограничиваем размер истории до MAX_HISTORY_SIZE
363
+ const emailsArray = Array.from(globalEmailHistory).slice(0, MAX_HISTORY_SIZE);
364
+
365
+ const data = {
366
+ emails: emailsArray,
367
+ generations: generationHistory.slice(-100) // Сохраняем только последние 100 генераций
368
+ };
369
+
370
+ const jsonData = JSON.stringify(data);
371
+
372
+ // Проверяем размер данных перед сохранением
373
+ if (jsonData.length > 4 * 1024 * 1024) { // 4MB лимит
374
+ addLog('Предупреждение: История слишком большая, уменьшаем размер', 'warning');
375
+ // Уменьшаем еще больше
376
+ data.emails = data.emails.slice(0, MAX_HISTORY_SIZE / 2);
377
+ localStorage.setItem('germanEmailHistory', JSON.stringify(data));
378
+ } else {
379
+ localStorage.setItem('germanEmailHistory', jsonData);
380
+ }
381
+
382
+ updateHistoryCount();
383
+ } catch (e) {
384
+ if (e.name === 'QuotaExceededError') {
385
+ addLog('Ошибка: Превышен лимит хранилища. Очищаем историю.', 'error');
386
+ // Очищаем историю и пробуем снова
387
+ globalEmailHistory.clear();
388
+ generationHistory = [];
389
+ try {
390
+ localStorage.setItem('germanEmailHistory', JSON.stringify({emails: [], generations: []}));
391
+ } catch (retryError) {
392
+ addLog('Ошибка: Не удалось очистить хранилище.', 'error');
393
+ }
394
+ } else {
395
+ addLog('Ошибка при сохранении истории: ' + e.message, 'error');
396
+ }
397
+ }
398
+ }
399
+
400
+ // Обновление счетчика истории
401
+ function updateHistoryCount() {
402
+ document.getElementById('historyCount').textContent = globalEmailHistory.size;
403
+ }
404
+
405
+ // Очистка глобальной истории
406
+ function clearGlobalHistory() {
407
+ if (confirm('Вы уверены, что хотите очистить всю историю сгенерированных email-адресов? Это действие нельзя отменить.')) {
408
+ globalEmailHistory.clear();
409
+ generationHistory = [];
410
+ try {
411
+ localStorage.setItem('germanEmailHistory', JSON.stringify({emails: [], generations: []}));
412
+ } catch (e) {
413
+ addLog('Ошибк�� при очистке истории: ' + e.message, 'error');
414
+ }
415
+ updateHistoryCount();
416
+ addLog('Глобальная история очищена.', 'success');
417
+ }
418
+ }
419
+
420
+ // Загрузка стандартных немецких имен
421
+ function loadDefaultGermanFirstNames() {
422
+ document.getElementById('germanFirstNames').value = germanFirstNames.join(',');
423
+ hideError('firstNameError');
424
+ }
425
+
426
+ // Загрузка стандартных немецких фамилий
427
+ function loadDefaultGermanLastNames() {
428
+ document.getElementById('germanLastNames').value = germanLastNames.join(',');
429
+ hideError('lastNameError');
430
+ }
431
+
432
+ // Очистка имен
433
+ function clearFirstNames() {
434
+ document.getElementById('germanFirstNames').value = '';
435
+ }
436
+
437
+ // Очистка фамилий
438
+ function clearLastNames() {
439
+ document.getElementById('germanLastNames').value = '';
440
+ }
441
+
442
+ // Показать ошибку
443
+ function showError(elementId) {
444
+ document.getElementById(elementId).classList.remove('hidden');
445
+ }
446
+
447
+ // Скрыть ошибку
448
+ function hideError(elementId) {
449
+ document.getElementById(elementId).classList.add('hidden');
450
+ }
451
+
452
+ // Добавление записи в журнал
453
+ function addLog(message, level = 'info') {
454
+ const logContainer = document.getElementById('logContainer');
455
+ const logEntry = document.createElement('div');
456
+ logEntry.className = 'log-entry mb-1';
457
+
458
+ const levelClass = {
459
+ 'error': 'log-error',
460
+ 'warning': 'log-warning',
461
+ 'info': 'log-info',
462
+ 'success': 'log-success'
463
+ }[level] || 'log-info';
464
+
465
+ logEntry.classList.add(levelClass);
466
+ logEntry.textContent = `[${new Date().toLocaleTimeString()}] ${message}`;
467
+ logContainer.appendChild(logEntry);
468
+
469
+ // Ограничиваем количество записей в логе до 100
470
+ if (logContainer.children.length > 100) {
471
+ logContainer.removeChild(logContainer.children[0]);
472
+ }
473
+
474
+ logContainer.scrollTop = logContainer.scrollHeight;
475
+ }
476
+
477
+ // Обновление прогресс-бара
478
+ function updateProgress(percentage, generated) {
479
+ const progressBar = document.getElementById('progressBar');
480
+ const progressText = document.getElementById('progressText');
481
+ const generatedCount = document.getElementById('generatedCount');
482
+
483
+ progressBar.style.width = `${percentage}%`;
484
+ progressText.textContent = `${percentage}%`;
485
+ generatedCount.textContent = generated;
486
+ }
487
+
488
+ // Обновление статистики
489
+ function updateStats() {
490
+ // Популярные имена (топ-3)
491
+ const popularNames = Object.entries(nameUsageStats.firstNames)
492
+ .sort((a, b) => b[1] - a[1])
493
+ .slice(0, 3)
494
+ .map(([name, count]) => `${name} (${count})`)
495
+ .join(', ');
496
+
497
+ // Популярные фамилии (топ-3)
498
+ const popularLastNames = Object.entries(nameUsageStats.lastNames)
499
+ .sort((a, b) => b[1] - a[1])
500
+ .slice(0, 3)
501
+ .map(([name, count]) => `${name} (${count})`)
502
+ .join(', ');
503
+
504
+ // Частые суффиксы (топ-5)
505
+ const commonSuffixes = Object.entries(nameUsageStats.suffixes)
506
+ .filter(([suffix]) => suffix !== '') // Исключаем пустые суффиксы
507
+ .sort((a, b) => b[1] - a[1])
508
+ .slice(0, 5)
509
+ .map(([suffix, count]) => `${suffix} (${count})`)
510
+ .join(', ');
511
+
512
+ // Статистика по шаблонам
513
+ const patternStats = Object.entries(nameUsageStats.patterns)
514
+ .filter(([_, count]) => count > 0)
515
+ .sort((a, b) => b[1] - a[1])
516
+ .map(([pattern, count]) => {
517
+ const patternNames = {
518
+ 'first.last': 'Имя.Фамилия',
519
+ 'firstlast': 'ИмяФамилия',
520
+ 'initiallast': 'ИнициалФамилия',
521
+ 'lastfirst': 'ФамилияИмя',
522
+ 'last.first': 'Фамилия.Имя',
523
+ 'initial.initiallast': 'И.И.Фамилия'
524
+ };
525
+ return `${patternNames[pattern] || pattern}: ${count}`;
526
+ })
527
+ .join(', ');
528
+
529
+ document.getElementById('popularNames').textContent = popularNames || '-';
530
+ document.getElementById('popularLastNames').textContent = popularLastNames || '-';
531
+ document.getElementById('commonSuffixes').textContent = commonSuffixes || '-';
532
+ document.getElementById('patternStats').textContent = patternStats || '-';
533
+ }
534
+
535
+ // Валидация и генерация
536
+ function validateAndGenerate() {
537
+ // Сброс ошибок
538
+ hideError('firstNameError');
539
+ hideError('lastNameError');
540
+ hideError('domainError');
541
+ hideError('countError');
542
+ hideError('patternError');
543
+ hideError('suffixError');
544
+
545
+ // Получение конфигурации
546
+ const firstNames = document.getElementById('germanFirstNames').value.split(',').map(n => n.trim()).filter(n => n);
547
+ const lastNames = document.getElementById('germanLastNames').value.split(',').map(n => n.trim()).filter(n => n);
548
+ const domain = document.getElementById('domain').value.trim();
549
+ const count = parseInt(document.getElementById('emailCount').value) || 0;
550
+
551
+ // Проверка шаблонов
552
+ const patterns = [];
553
+ if (document.getElementById('pattern1').checked) patterns.push('first.last');
554
+ if (document.getElementById('pattern2').checked) patterns.push('firstlast');
555
+ if (document.getElementById('pattern3').checked) patterns.push('initiallast');
556
+ if (document.getElementById('pattern4').checked) patterns.push('lastfirst');
557
+ if (document.getElementById('pattern5').checked) patterns.push('last.first');
558
+ if (document.getElementById('pattern6').checked) patterns.push('initial.initiallast');
559
+
560
+ // Проверка суффиксов
561
+ const noSuffix = document.getElementById('noSuffix').checked;
562
+ const addSuffixes = document.getElementById('addSuffixes').checked;
563
+ const addYearSuffixes = document.getElementById('addYearSuffixes').checked;
564
+ const addRandomSuffixes = document.getElementById('addRandomSuffixes').checked;
565
+
566
+ // Валидация
567
+ let isValid = true;
568
+
569
+ if (firstNames.length === 0) {
570
+ showError('firstNameError');
571
+ isValid = false;
572
+ }
573
+
574
+ if (lastNames.length === 0) {
575
+ showError('lastNameError');
576
+ isValid = false;
577
+ }
578
+
579
+ if (!domain || domain.indexOf('.') === -1) {
580
+ showError('domainError');
581
+ isValid = false;
582
+ }
583
+
584
+ if (isNaN(count) || count < 1 || count > 10000000) {
585
+ showError('countError');
586
+ isValid = false;
587
+ }
588
+
589
+ if (patterns.length === 0) {
590
+ showError('patternError');
591
+ isValid = false;
592
+ }
593
+
594
+ if (!noSuffix && !addSuffixes && !addYearSuffixes && !addRandomSuffixes) {
595
+ showError('suffixError');
596
+ isValid = false;
597
+ }
598
+
599
+ if (isValid) {
600
+ generateEmails(firstNames, lastNames, domain, count, patterns, noSuffix, addSuffixes, addYearSuffixes, addRandomSuffixes);
601
+ } else {
602
+ addLog('Ошибка: Пожалуйста, проверьте введенные данные.', 'error');
603
+ }
604
+ }
605
+
606
+ // Генерация email-адресов на основе конфигурации
607
+ async function generateEmails(firstNames, lastNames, domain, count, patterns, noSuffix, addSuffixes, addYearSuffixes, addRandomSuffixes) {
608
+ if (isGenerating) return;
609
+
610
+ // Сброс состояния
611
+ isGenerating = true;
612
+ generationCanceled = false;
613
+ generatedEmails = [];
614
+ nameUsageStats = {
615
+ firstNames: {},
616
+ lastNames: {},
617
+ suffixes: {},
618
+ patterns: {
619
+ 'first.last': 0,
620
+ 'firstlast': 0,
621
+ 'initiallast': 0,
622
+ 'lastfirst': 0,
623
+ 'last.first': 0,
624
+ 'initial.initiallast': 0
625
+ }
626
+ };
627
+ document.getElementById('resultArea').value = '';
628
+ document.getElementById('cancelButton').classList.remove('hidden');
629
+
630
+ // Получение дополнительной конфигурации
631
+ const ensureUniqueness = document.getElementById('ensureUniqueness').checked;
632
+ const batchProcessing = document.getElementById('batchProcessing').checked;
633
+
634
+ addLog(`Начинаю генерацию ${count} email-адресов...`, 'info');
635
+
636
+ // Генерация email-адресов порциями для отзывчивости интерфейса
637
+ const chunkSize = batchProcessing ? Math.min(100000, Math.ceil(count / 100)) : Math.min(10000, Math.ceil(count / 100));
638
+ let generated = 0;
639
+
640
+ // Создание Set для дедупликации
641
+ const emailSet = new Set();
642
+
643
+ // Подготовка суффиксов
644
+ const suffixes = [];
645
+ if (noSuffix) suffixes.push('');
646
+ if (addSuffixes) {
647
+ for (let i = 1; i <= 999; i++) suffixes.push(i.toString());
648
+ }
649
+ if (addYearSuffixes) {
650
+ for (let year = 1950; year <= 2023; year++) suffixes.push(year.toString());
651
+ }
652
+ if (addRandomSuffixes) {
653
+ for (let i = 1; i <= 100; i++) suffixes.push(i.toString());
654
+ // Добавляем специальные суффиксы, которые часто встречаются
655
+ suffixes.push('01', '02', '03', '07', '08', '09', '10', '11', '12', '13', '77', '88', '99', '123', '007', '999');
656
+ }
657
+
658
+ // Предварительный расчет максимального количества комбинаций
659
+ const maxPossibleCombinations = firstNames.length * lastNames.length * patterns.length * suffixes.length;
660
+ if (ensureUniqueness && count > maxPossibleCombinations) {
661
+ addLog(`Внимание: Запрошено ${count} уникальных адресов, но максимально возможно сгенерировать только ${maxPossibleCombinations}.`, 'warning');
662
+ count = maxPossibleCombinations;
663
+ }
664
+
665
+ try {
666
+ let failedAttempts = 0;
667
+ const maxFailedAttempts = 1000000;
668
+ let globalDuplicates = 0;
669
+
670
+ while (generated < count && !generationCanceled) {
671
+ const chunk = Math.min(chunkSize, count - generated);
672
+ const newEmails = [];
673
+
674
+ for (let i = 0; i < chunk; i++) {
675
+ if (generationCanceled) break;
676
+
677
+ if (ensureUniqueness && failedAttempts > maxFailedAttempts) {
678
+ addLog('Прекращаем генерацию: невозможно сгенерировать больше уникальных адресов.', 'warning');
679
+ generationCanceled = true;
680
+ break;
681
+ }
682
+
683
+ const firstName = firstNames[Math.floor(Math.random() * firstNames.length)];
684
+ const lastName = lastNames[Math.floor(Math.random() * lastNames.length)];
685
+ const pattern = patterns[Math.floor(Math.random() * patterns.length)];
686
+ const suffix = suffixes[Math.floor(Math.random() * suffixes.length)];
687
+
688
+ let localPart = '';
689
+
690
+ switch (pattern) {
691
+ case 'first.last':
692
+ localPart = `${firstName}.${lastName}`;
693
+ break;
694
+ case 'firstlast':
695
+ localPart = `${firstName}${lastName}`;
696
+ break;
697
+ case 'initiallast':
698
+ localPart = `${firstName.charAt(0)}.${lastName}`;
699
+ break;
700
+ case 'lastfirst':
701
+ localPart = `${lastName}${firstName}`;
702
+ break;
703
+ case 'last.first':
704
+ localPart = `${lastName}.${firstName}`;
705
+ break;
706
+ case 'initial.initiallast':
707
+ const secondInitial = firstName.length > 1 ? firstName.charAt(1) : firstName.charAt(0);
708
+ localPart = `${firstName.charAt(0)}.${secondInitial}.${lastName}`;
709
+ break;
710
+ }
711
+
712
+ // Добавляем суффикс, если он не пустой
713
+ if (suffix) localPart += suffix;
714
+
715
+ const email = `${localPart}@${domain}`;
716
+
717
+ // Проверяем уникальность если требуется
718
+ if (!ensureUniqueness || (!emailSet.has(email) && !globalEmailHistory.has(email))) {
719
+ emailSet.add(email);
720
+ newEmails.push(email);
721
+
722
+ // Обновляем статистику использования
723
+ nameUsageStats.firstNames[firstName] = (nameUsageStats.firstNames[firstName] || 0) + 1;
724
+ nameUsageStats.lastNames[lastName] = (nameUsageStats.lastNames[lastName] || 0) + 1;
725
+ nameUsageStats.suffixes[suffix] = (nameUsageStats.suffixes[suffix] || 0) + 1;
726
+ nameUsageStats.patterns[pattern] = (nameUsageStats.patterns[pattern] || 0) + 1;
727
+
728
+ failedAttempts = 0;
729
+ } else if (ensureUniqueness) {
730
+ // Пропускаем дубликат и уменьшаем счетчик
731
+ i--;
732
+ failedAttempts++;
733
+ if (globalEmailHistory.has(email)) {
734
+ globalDuplicates++;
735
+ }
736
+ }
737
+ }
738
+
739
+ generatedEmails = [...generatedEmails, ...newEmails];
740
+ generated = generatedEmails.length;
741
+
742
+ // Обновляем интерфейс
743
+ const progress = Math.min(100, Math.floor((generated / count) * 100));
744
+ updateProgress(progress, generated);
745
+ updateStats();
746
+
747
+ // Показываем частичные результаты
748
+ if (!batchProcessing || generated === count || generationCanceled) {
749
+ document.getElementById('resultArea').value = generatedEmails.join('\n');
750
+ } else if (generated % 500000 === 0) {
751
+ // Для пакетной обработки обновляем реже
752
+ document.getElementById('resultArea').value = `Пакетная обработка... Сгенерировано: ${generated}\n\nДля просмотра всех адресов дождитесь завершения генерации.`;
753
+ }
754
+
755
+ // Даем время интерфейсу на обновление
756
+ await new Promise(resolve => setTimeout(resolve, 0));
757
+ }
758
+
759
+ if (generationCanceled) {
760
+ addLog(`Генерация отменена. Создано ${generated} email-адресов.`, 'warning');
761
+ } else {
762
+ addLog(`Генерация завершена. Создано ${generated} email-адресов.`, 'success');
763
+ if (globalDuplicates > 0) {
764
+ addLog(`Исключено дубликатов из предыдущих генераций: ${globalDuplicates}`, 'info');
765
+ }
766
+
767
+ // Добавляем сгенерированные адреса в глобальную историю (с ограничением)
768
+ generatedEmails.forEach(email => {
769
+ if (globalEmailHistory.size < MAX_HISTORY_SIZE) {
770
+ globalEmailHistory.add(email);
771
+ }
772
+ });
773
+
774
+ // Сохраняем историю генераций
775
+ generationHistory.push({
776
+ timestamp: new Date().toISOString(),
777
+ count: generated,
778
+ domain: domain,
779
+ patterns: patterns
780
+ });
781
+
782
+ saveGlobalHistory();
783
+ }
784
+ } catch (error) {
785
+ addLog(`Ошибка при генерации: ${error.message}`, 'error');
786
+ } finally {
787
+ isGenerating = false;
788
+ document.getElementById('cancelButton').classList.add('hidden');
789
+
790
+ // Всегда показываем полный результат по завершении
791
+ document.getElementById('resultArea').value = generatedEmails.join('\n');
792
+ }
793
+ }
794
+
795
+ // Отмена генерации
796
+ function cancelGeneration() {
797
+ if (isGenerating) {
798
+ generationCanceled = true;
799
+ addLog('Генерация отменяется...', 'warning');
800
+ document.getElementById('cancelButton').classList.add('hidden');
801
+ }
802
+ }
803
+
804
+ // Копирование результатов в буфер обмена
805
+ function copyResults() {
806
+ if (generatedEmails.length === 0) {
807
+ addLog('Нет данны�� для копирования.', 'warning');
808
+ return;
809
+ }
810
+
811
+ try {
812
+ const textarea = document.createElement('textarea');
813
+ textarea.value = generatedEmails.join('\n');
814
+ document.body.appendChild(textarea);
815
+ textarea.select();
816
+ document.execCommand('copy');
817
+ document.body.removeChild(textarea);
818
+
819
+ addLog('Результаты скопированы в буфер обмена.', 'success');
820
+ } catch (error) {
821
+ addLog('Ошибка при копировании: ' + error.message, 'error');
822
+ }
823
+ }
824
+
825
+ // Скачивание результатов как текстовый файл
826
+ function downloadResults() {
827
+ if (generatedEmails.length === 0) {
828
+ addLog('Нет данных для скачивания.', 'warning');
829
+ return;
830
+ }
831
+
832
+ try {
833
+ const content = generatedEmails.join('\n');
834
+ const blob = new Blob([content], { type: 'text/plain;charset=utf-8' });
835
+ const url = URL.createObjectURL(blob);
836
+
837
+ const a = document.createElement('a');
838
+ a.href = url;
839
+ a.download = 'german_emails.txt';
840
+ document.body.appendChild(a);
841
+ a.click();
842
+ document.body.removeChild(a);
843
+
844
+ URL.revokeObjectURL(url);
845
+ addLog('Результаты скачаны.', 'success');
846
+ } catch (error) {
847
+ addLog('Ошибка при скачивании: ' + error.message, 'error');
848
+ }
849
+ }
850
+
851
+ // Быстрая генерация с частыми шаблонами
852
+ function generateCommonPatterns() {
853
+ document.getElementById('pattern1').checked = true;
854
+ document.getElementById('pattern2').checked = true;
855
+ document.getElementById('pattern3').checked = true;
856
+ document.getElementById('pattern4').checked = false;
857
+ document.getElementById('pattern5').checked = false;
858
+ document.getElementById('pattern6').checked = false;
859
+ document.getElementById('noSuffix').checked = true;
860
+ document.getElementById('addSuffixes').checked = true;
861
+ document.getElementById('addYearSuffixes').checked = false;
862
+ document.getElementById('addRandomSuffixes').checked = false;
863
+ document.getElementById('ensureUniqueness').checked = true;
864
+ document.getElementById('batchProcessing').checked = true;
865
+ document.getElementById('emailCount').value = '1000000';
866
+ addLog('Установлены настройки для частых шаблонов (1,000,000 адресов).', 'info');
867
+ }
868
+
869
+ // Быстрая генерация с годами
870
+ function generateWithYears() {
871
+ document.getElementById('pattern1').checked = true;
872
+ document.getElementById('pattern2').checked = true;
873
+ document.getElementById('noSuffix').checked = false;
874
+ document.getElementById('addSuffixes').checked = false;
875
+ document.getElementById('addYearSuffixes').checked = true;
876
+ document.getElementById('addRandomSuffixes').checked = false;
877
+ document.getElementById('ensureUniqueness').checked = true;
878
+ document.getElementById('batchProcessing').checked = true;
879
+ document.getElementById('emailCount').value = '500000';
880
+ addLog('Установлены настройки для генерации с годами (500,000 адресов).', 'info');
881
+ }
882
+
883
+ // Быстрая генерация с цифрами
884
+ function generateWithDigits() {
885
+ document.getElementById('pattern1').checked = true;
886
+ document.getElementById('pattern2').checked = true;
887
+ document.getElementById('pattern3').checked = true;
888
+ document.getElementById('noSuffix').checked = false;
889
+ document.getElementById('addSuffixes').checked = true;
890
+ document.getElementById('addYearSuffixes').checked = false;
891
+ document.getElementById('addRandomSuffixes').checked = true;
892
+ document.getElementById('ensureUniqueness').checked = true;
893
+ document.getElementById('batchProcessing').checked = true;
894
+ document.getElementById('emailCount').value = '1000000';
895
+ addLog('Установлены настройки для генерации с цифрами (1,000,000 адресов).', 'info');
896
+ }
897
+
898
+ // Генерация без суффиксов
899
+ function generateWithoutSuffix() {
900
+ document.getElementById('pattern1').checked = true;
901
+ document.getElementById('pattern2').checked = true;
902
+ document.getElementById('pattern3').checked = true;
903
+ document.getElementById('noSuffix').checked = true;
904
+ document.getElementById('addSuffixes').checked = false;
905
+ document.getElementById('addYearSuffixes').checked = false;
906
+ document.getElementById('addRandomSuffixes').checked = false;
907
+ document.getElementById('ensureUniqueness').checked = true;
908
+ document.getElementById('batchProcessing').checked = true;
909
+ document.getElementById('emailCount').value = '100000';
910
+ addLog('Установлены настройки для генерации без суффиксов (100,000 адресов).', 'info');
911
+ }
912
+
913
+ // Очистка всего
914
+ function clearAll() {
915
+ document.getElementById('resultArea').value = '';
916
+ generatedEmails = [];
917
+ nameUsageStats = {
918
+ firstNames: {},
919
+ lastNames: {},
920
+ suffixes: {},
921
+ patterns: {
922
+ 'first.last': 0,
923
+ 'firstlast': 0,
924
+ 'initiallast': 0,
925
+ 'lastfirst': 0,
926
+ 'last.first': 0,
927
+ 'initial.initiallast': 0
928
+ }
929
+ };
930
+ updateStats();
931
+ updateProgress(0, 0);
932
+ addLog('Все данные очищены.', 'info');
933
+ }
934
+
935
+ // Запуск тестов
936
+ function runTests() {
937
+ addLog('Запуск тестов...', 'info');
938
+
939
+ // Тест валидации
940
+ const testResults = [];
941
+
942
+ // Тест 1: Проверка загрузки стандартных имен
943
+ try {
944
+ loadDefaultGermanFirstNames();
945
+ const names = document.getElementById('germanFirstNames').value;
946
+ if (names.split(',').length === germanFirstNames.length) {
947
+ testResults.push('Тест 1 пройден: стандартные имена загружены корректно');
948
+ } else {
949
+ testResults.push('Тест 1 не пройден: ошибка загрузки стандартных имен');
950
+ }
951
+ } catch (e) {
952
+ testResults.push('Тест 1 не пройден: ' + e.message);
953
+ }
954
+
955
+ // Тест 2: Проверка загрузки стандартных фамилий
956
+ try {
957
+ loadDefaultGermanLastNames();
958
+ const names = document.getElementById('germanLastNames').value;
959
+ if (names.split(',').length === germanLastNames.length) {
960
+ testResults.push('Тест 2 пройден: стандартные фамилии загружены корректно');
961
+ } else {
962
+ testResults.push('Тест 2 не пройден: ошибка загрузки стандартных фамилий');
963
+ }
964
+ } catch (e) {
965
+ testResults.push('Тест 2 не пройден: ' + e.message);
966
+ }
967
+
968
+ // Тест 3: Проверка генерации email
969
+ try {
970
+ const testEmails = [];
971
+ const testSet = new Set();
972
+
973
+ for (let i = 0; i < 10; i++) {
974
+ const firstName = 'test';
975
+ const lastName = 'user';
976
+ const pattern = 'first.last';
977
+ const suffix = i;
978
+
979
+ const localPart = `${firstName}.${lastName}${suffix}`;
980
+ const email = `${localPart}@test.de`;
981
+
982
+ if (!testSet.has(email)) {
983
+ testSet.add(email);
984
+ testEmails.push(email);
985
+ }
986
+ }
987
+
988
+ if (testEmails.length === 10) {
989
+ testResults.push('Тест 3 пройден: генерация email работает корректно');
990
+ } else {
991
+ testResults.push('Тест 3 не пройден: ошибка генерации email');
992
+ }
993
+ } catch (e) {
994
+ testResults.push('Тест 3 не пройден: ' + e.message);
995
+ }
996
+
997
+ // Тест 4: Проверка системы отслеживания дубликатов
998
+ try {
999
+ const testEmail = 'test.user@test.de';
1000
+ globalEmailHistory.add(testEmail);
1001
+ if (globalEmailHistory.has(testEmail)) {
1002
+ testResults.push('Тест 4 пройден: система отслеживания дубликатов работает');
1003
+ } else {
1004
+ testResults.push('Тест 4 не пройден: ошибка системы отслеживания дубликатов');
1005
+ }
1006
+ globalEmailHistory.delete(testEmail);
1007
+ } catch (e) {
1008
+ testResults.push('Тест 4 не пройден: ' + e.message);
1009
+ }
1010
+
1011
+ // Вывод результатов тестов
1012
+ testResults.forEach(result => {
1013
+ const level = result.includes('пройден') ? 'success' : 'error';
1014
+ addLog(result, level);
1015
+ });
1016
+ addLog(`Тестирование завершено. Пройдено тестов: ${testResults.filter(r => r.includes('пройден')).length}/${testResults.length}`, 'info');
1017
+ }
1018
+
1019
+ // Инициализация приложения
1020
+ document.addEventListener('DOMContentLoaded', initializeUI);
1021
+ </script>
1022
+ </body>
1023
+ </html>