Wikipedia
testwiki
https://test.wikipedia.org/wiki/Main_Page
MediaWiki 1.47.0-wmf.3
first-letter
Media
Special
Talk
User
User talk
Wikipedia
Wikipedia talk
File
File talk
MediaWiki
MediaWiki talk
Template
Template talk
Help
Help talk
Category
Category talk
Thread
Thread talk
Summary
Summary talk
Test namespace 1
Test namespace 1 talk
Test namespace 2
Test namespace 2 talk
Draft
Draft talk
Campaign
Campaign talk
TimedText
TimedText talk
Module
Module talk
SecurePoll
SecurePoll talk
CNBanner
CNBanner talk
Translations
Translations talk
Event
Event talk
Topic
Newsletter
Newsletter talk
MediaWiki:Anonnotice
8
34
743932
225757
2026-05-23T10:21:45Z
Yahya
44996
743932
wikitext
text/x-wiki
<div style="background:#f8f9fa; border:1px solid #a2a9b1; border-radius:4px; padding:10px 14px; display:flex; flex-wrap:wrap; align-items:center; gap:12px; justify-content:space-between;"><div style="display:flex; align-items:center; gap:12px; flex:1 1 250px;"><div>[[File:JS Icon Edit White.svg|30px|link=|alt=]]</div><div style="line-height:1.4; color:#202122;"><b>উইকিপিডিয়া সম্পাদনা শিখতে চান?</b><br><small>আগামী <b>৬ই জুন</b> নতুনদের জন্য বিশেষ অনলাইন কর্মশালা — জুম, ফেসবুক বা ইউটিউব লাইভে যুক্ত হোন।</small></div></div><div style="flex:1 1 auto; text-align:center; margin-top:4px;"><span class="plainlinks">[https://bn.wikipedia.org/s/xq58 <span style="background:#3366cc; color:#fff; padding:8px 16px; border-radius:4px; font-weight:bold; white-space:nowrap; display:inline-block;">বিস্তারিত ও যুক্ত হোন →</span>]</span></div></div>
cnpe48d9vl2ajb0cg1wml8ropgb5wa8
743938
743932
2026-05-23T11:16:05Z
Yahya
44996
Reverted edit by [[Special:Contributions/Yahya|Yahya]] ([[User talk:Yahya|talk]]) to last revision by [[User:Krinkle|Krinkle]]
225757
wikitext
text/x-wiki
-
6za6z27cqk2qatlebqsiz85czbjf3rd
Testing
0
87019
743920
676768
2026-05-22T22:40:39Z
~2026-30590-56
74106
/* */
743920
wikitext
text/x-wiki
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing rxcc
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is tesBarackting
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing
Hello this is testing.
[[Testing]].
= What is Testing? =
== Definition ==
exercising a program under controlled conditions and verifying the results Purpose is to detect program defects.<ref>{{Cite book |title= |publisher=Chrystal Hubbard}}</ref>
Published by [[Chrystal Hubbard]]
6m1peowoegl2vjgjzzfu75c0o3p7c6d
Hitler
0
91744
743927
285376
2026-05-23T03:25:27Z
OrderNumber57
74111
743927
wikitext
text/x-wiki
poor painter, cool speaker, friend of fashion dictator goebbels, failed art school so he took over poland
5w2km1rpyp3f0c9s0wyb1xhp0rd9cdj
Balena de bec de Sowerby
0
95534
743892
314665
2026-05-22T12:24:01Z
~2026-30679-56
74099
743892
wikitext
text/x-wiki
== {{-ca-}} ==
normal edit
=== Nom ===
{{ca-nom|f}}
# {{sense accepcions}} (''[[Mesoplodon bidens]]'')
{{-sin-}}
* [[zifi de Sowerby]], [[zífid de Sowerby]].
{{-hiper-}}
* [[cetacis]] > [[odontocets]] > [[zífids]]
{{-trad-}}
{{inici}}
* {{en}}: {{trad|en|Sowerby's beaked whale}}
* {{es}}: {{trad|es|zifio de Sowerby}}
{{mig}}
* {{fr}}: {{trad|fr|baleine à bec de Sowerby}}
{{final}}
=== Referències ===
* {{ca-dicc|termcat}}
{{catllengua|ca|Mamífers marins}}
qkxa4jazr9s2zmomfm7hk6ypsa9xnsl
743893
743892
2026-05-22T12:27:25Z
~2026-30679-56
74099
showcaptcha
743893
wikitext
text/x-wiki
== {{-ca-}} ==
normal edit
af edit
=== Nom ===
{{ca-nom|f}}
# {{sense accepcions}} (''[[Mesoplodon bidens]]'')
{{-sin-}}
* [[zifi de Sowerby]], [[zífid de Sowerby]].
{{-hiper-}}
* [[cetacis]] > [[odontocets]] > [[zífids]]
{{-trad-}}
{{inici}}
* {{en}}: {{trad|en|Sowerby's beaked whale}}
* {{es}}: {{trad|es|zifio de Sowerby}}
{{mig}}
* {{fr}}: {{trad|fr|baleine à bec de Sowerby}}
{{final}}
=== Referències ===
* {{ca-dicc|termcat}}
{{catllengua|ca|Mamífers marins}}
ng17ehz2oubuid88t8indgklacjzoj4
Mwbot-rs/Save
0
122864
743891
742323
2026-05-22T12:11:07Z
Mwbot-rs test
52001
Test suite edit
743891
wikitext
text/x-wiki
It has been 1779451865 seconds since the epoch.
lwtykn1gsxby7ap2ljcwyambgipyt4q
User:SongVĩ.Bot II
2
124239
743911
743865
2026-05-22T17:00:17Z
SongVĩ.Bot II
52414
[[User:SongVĩ.Bot II|Task 0]]: Đã 1607 ngày...
743911
wikitext
text/x-wiki
Cập nhật lần cuối: 23-05-2026
Đã 1607 ngày...
843nvk0xs7hd9vkw9m20sqgccwkvj5f
743913
743911
2026-05-22T20:03:25Z
SongVĩ.Bot II
52414
[[User:SongVĩ.Bot II|Task 0]]: Đã 1608 ngày...
743913
wikitext
text/x-wiki
Cập nhật lần cuối: 23-05-2026
Đã 1608 ngày...
87ypo3u9fue8s36vup3o4ghqlqwg2gf
Wikipedia:Village pump/topic list
4
146208
743925
743882
2026-05-23T01:32:36Z
Cewbot
33876
[[User:Cewbot/log/20170915/configuration|Generate topic list: 8 topics]]
743925
wikitext
text/x-wiki
<!-- This page is auto-generated by bot. Please contact the bot operator to improve the tool. -->
{| class="wikitable sortable mw-collapsible" style="float:left;"
|-
! data-sort-type="number" style="font-weight: normal;" | <small>#</small> !! 💭 Title !! <span title="Count of comments">💬</span> !! <span title="Count of peoples in discussion">👥</span> !! 🙋 Last editor !! data-sort-type="isoDate" | <span title="Date/Time">🕒 <small>(UTC)</small></span>
|-
| style="text-align: right;" | 1
| [[Wikipedia:Village pump#Script|Script]]
| style="text-align: right;" | 8
| style="text-align: right;" | 5
| style="background-color: #bbb;" | [[User:LuniZunie|LuniZunie]]
| style="background-color: #bbb;" data-sort-type="isoDate" data-sort-value="2025-11-09T16:47:00.000Z" | 2025-11-09 <span style="color: blue;">16:47</span>
|-
| style="text-align: right;" | 2
| [[Wikipedia:Village pump#Report_concerning_Tanbiruzzammn|Report concerning Tanbiruzzammn]]
| style="text-align: right;" | 2
| style="text-align: right;" | 2
| style="background-color: #bbb;" | [[User:Barras|Barras]]
| style="background-color: #bbb;" data-sort-type="isoDate" data-sort-value="2025-12-09T21:45:00.000Z" | 2025-12-09 <span style="color: blue;">21:45</span>
|-
| style="text-align: right;" | 3
| [[Wikipedia:Village pump#Report_concerning_Bucheon|Report concerning Bucheon]]
| style="text-align: right;background-color: #fcc;" | 1
| style="text-align: right;background-color: #fcc;" | 1
| style="background-color: #bbb;" | [[User:PieWriter|PieWriter]]
| style="background-color: #bbb;" data-sort-type="isoDate" data-sort-value="2026-02-19T10:25:00.000Z" | 2026-02-19 <span style="color: blue;">10:25</span>
|-
| style="text-align: right;" | 4
| [[Wikipedia:Village pump#Versions_and_dates|Versions and dates]]
| style="text-align: right;" | 2
| style="text-align: right;background-color: #fcc;" | 1
| style="background-color: #bbb;" | [[Special:Contributions/~2026-13668-13|<span style="color: #c20;">~2026-13668-13</span>]]
| style="background-color: #bbb;" data-sort-type="isoDate" data-sort-value="2026-03-03T06:17:00.000Z" | 2026-03-03 <span style="color: blue;">06:17</span>
|-
| style="text-align: right;" | 5
| style="max-width: 24em" | <small>[[Wikipedia:Village pump#Upcoming_Wikimedia_Café_meetup_regarding_the_the_2026-2027_Wikimedia_Foundation_Annual_Plan|Upcoming Wikimedia Café meetup regarding the the 2026-2027 Wikimedia Foundation Annual Plan]]</small>
| style="text-align: right;background-color: #fcc;" | 1
| style="text-align: right;background-color: #fcc;" | 1
| style="background-color: #bbb;" | [[User:Pine|Pine]]
| style="background-color: #bbb;" data-sort-type="isoDate" data-sort-value="2026-03-30T03:46:00.000Z" | 2026-03-30 <span style="color: blue;">03:46</span>
|-
| style="text-align: right;" | 6
| [[Wikipedia:Village pump#Changes_to_electionadmin_userright|Changes to electionadmin userright]]
| style="text-align: right;" | 4
| style="text-align: right;" | 4
| style="background-color: #ddd;" | [[User:Chaotic Enby|Chaotic Enby]]
| style="background-color: #ddd;" data-sort-type="isoDate" data-sort-value="2026-04-23T15:22:00.000Z" | 2026-04-23 <span style="color: blue;">15:22</span>
|-
| style="text-align: right;" | 7
| style="max-width: 24em" | <small>[[Wikipedia:Village pump#Report_concerning_Princebarackalibarrydaddyobamaiii|Report concerning Princebarackalibarrydaddyobamaiii]]</small>
| style="text-align: right;background-color: #fcc;" | 1
| style="text-align: right;background-color: #fcc;" | 1
| [[User:MathXplore|MathXplore]]
| data-sort-type="isoDate" data-sort-value="2026-05-18T12:23:00.000Z" | 2026-05-18 <span style="color: blue;">12:23</span>
|-
| style="text-align: right;" | 8
| style="max-width: 24em" | <small>[[Wikipedia:Village pump#May_2026_Wikimedia_Café_meetups_regarding_the_Wikimedia_Foundation_Annual_Plan|May 2026 Wikimedia Café meetups regarding the Wikimedia Foundation Annual Plan]]</small>
| style="text-align: right;background-color: #fcc;" | 1
| style="text-align: right;background-color: #fcc;" | 1
| [[User:Pine|Pine]]
| data-sort-type="isoDate" data-sort-value="2026-05-21T19:54:00.000Z" | 2026-05-21 <span style="color: blue;">19:54</span>
|}
{| class="wikitable mw-collapsible mw-collapsed" style="float: left; margin-left: .5em;;{{#if:{{{no_time_legend|}}}|display:none;|}}"
! title="From the latest bot edit" | Legend
|-
| style="background-color: #efe;" |
* In the last hour
|-
| style="background-color: #eef;" |
* In the last day
|-
| |
* In the last week
|-
| style="background-color: #ddd;" |
* In the last month
|-
| style="background-color: #bbb;" |
* More than one month
|-
! Manual settings
|-
| style="max-width: 12em;" | <small>When exceptions occur,<br />please check [[User:Cewbot/log/20170915/configuration|the setting]] first.</small>
|-
|}
{{Clear}}
le46xqtk4p1qkd7axtcir59qluhyviy
User:Borhan/test.js
2
159779
743930
737576
2026-05-23T09:40:52Z
Borhan
54019
743930
javascript
text/javascript
mw.loader.load('//meta.wikimedia.org/w/index.php?title=User:Aishik Rehman/Tools/catSyncer.js&action=raw&ctype=text/javascript');
6bfv7yv0v8o3v7q90tr2obvj6dyug1c
743931
743930
2026-05-23T10:16:10Z
Borhan
54019
Blanked the page
743931
javascript
text/javascript
phoiac9h4m842xq45sp7s6u21eteeq1
TestPage12345
0
168246
743929
675321
2026-05-23T08:59:05Z
~2026-30812-53
74116
Test
743929
wikitext
text/x-wiki
New content
kiit768qp901iswnd25s28az062agep
希腊在欧洲歌唱大赛之历年表现
0
169378
743922
687601
2026-05-23T00:03:15Z
InternetArchiveBot
34092
Rescuing 1 sources and tagging 0 as dead.) #IABot (v2.0.9.5
743922
wikitext
text/x-wiki
{{Infobox Eurovision country
|Name = 希腊
|Flag = Flag of Greece.svg
|Member station = {{link-en|新希腊广播网络电视台|New Hellenic Radio, Internet and Television|新希广网电}}(NERIT){{Collapsible list
| title = '''电视台前身'''
|'''1974–2013:''' [[希腊广播电视台]](ERT)}}
|National selection event =
|hosts = {{Escyr|2006|y=1}}[[雅典]]
|ESC apps = 45(42次进入决赛)
|ESC first = {{Escyr|1974|y=1}}
|ESC last = {{Escyr|2025|y=1}}
|ESC best = 冠军:{{Escyr|2005|y=1}}
|ESC worst = 半决赛第16名:{{Escyr|2016|y=1}}
|Website = [http://www.nerit.gr/?s=Eurovision NERIT Page]
|EBU page = http://www.eurovision.tv/page/history/by-country/country?country=19
}}
'''[[希腊]]'''第一次参加[[欧洲歌唱大赛]]是在{{link-en|Eurovision Song Contest 1974|1974年欧洲歌唱大赛|1974年}},截止至2025年共参加过45次,错过6次(1975,1982,1984,1986,1999及2000年)。[[2005年欧洲歌唱大赛|2005年]]希腊凭借[[艾莲娜·帕帕里祖]]的参赛歌曲《My Number One》首次夺冠。[[希腊广播电视台|希广电]](ERT)曾负责每年国内比赛的组织和大赛的转播。<ref>Paravantes, Maria. (2005-06-11). Joy In Greece Over Eurovision Win. ''[[告示牌 (杂志)|告示牌]]'' 117(24), 17-17. Retrieved on 2009-01-16.</ref>公司后该组为{{link-en|新希腊广播网络电视台|New Hellenic Radio, Internet and Television|新希广网电}}(NERIT)。
在整个20世纪中,希腊仅有2次进入前五名的成绩,而且这2次都是刚好第5名,分别是{{link-en|Eurovision Song Contest 1977|1977年欧洲歌唱大赛|1977年}}的参赛歌曲《Mathima Solfege》和{{link-en|Eurovision Song Contest 1992|1992年欧洲歌唱大赛|1992年}}Kleopatra的参赛歌曲《Olou Tou Kosmou I Elpida》。
自2001年起,希腊开始交好运。15年来(2001-2015),希腊只有5次没能进入前10名。除2005年夺冠外,希腊近14年里还得过3个第3名,分别是[[2001年欧洲歌唱大赛|2001年]]由[[艾莲娜·帕帕里祖]]领唱的Antique组合、[[2004年欧洲歌唱大赛|2004年]]的[[萨基斯·鲁瓦斯]]以及[[2008年欧洲歌唱大赛|2008年]]的{{link-en|卡罗米拉|Kalomira}}。
2016年以前希腊和罗马尼亚、阿塞拜疆、俄罗斯及乌克兰一道,都是自2004年引入半决赛制以来,从未缺席决赛的非特权国,在2016年時希臘意外未能晉級決賽,成為該國首次缺席決賽的年度。从2004年到2014年的11年中,希腊共有9次进入前10名。而且希腊从未有过名次垫底的记录。
== 參賽情况 ==
;图例说明:
{{legend|gold|冠军}}
{{legend|silver|亚军}}
{{legend|#cc9966|季军}}
{{legend|#FE8080|垫底}}
{{legend|#A4EAA9|比赛取消/退赛}}
{| class="wikitable sortable" style="width:100%"
|-
! 年份
! 艺人
! 歌名
! 语种
! 决赛成绩
! 得分
! 半决赛成绩
! 得分
|-
! scope="row" style="text-align:center" | {{Escyr|1974}}
|[[Marinella]]
|《Krasi, thalassa kai t' agori mou》{{small|({{lang|el|Κρασί, θάλασσα και τ' αγόρι μου}})}}
|[[希腊语|希腊语]]
|align=center|11
|align=center|7
|rowspan="17" colspan="2" data-sort-value="99999" {{N/A|无半决赛机制}}
|-
! scope="row" style="text-align:center" | {{Escyr|1976}}
|[[Mariza Koch]]
|《Panagia mou, panagia mou》{{small|({{lang|el|Παναγιά μου, παναγιά μου}})}}
|希腊语
|align=center|13
|align=center|20
|-
! scope="row" style="text-align:center" | {{Escyr|1977}}
|Paschalis, Marianna, [[Robert Williams (singer)|Robert]] and [[Bessy Argyraki|Bessy]]
|《Mathima solfege》{{small|({{lang|el|Μάθημα σολφέζ}})}}
|希腊语
|align=center|5
|align=center|92
|-
! scope="row" style="text-align:center" | {{Escyr|1978}}
|[[Tania Tsanaklidou]]
|《Charlie Chaplin》 {{small|({{lang|el|Τσάρλυ Τσάπλιν}})}}
|希腊语
|align=center|8
|align=center|66
|-
! scope="row" style="text-align:center" | {{Escyr|1979}}
|[[Elpida (singer)|Elpida]]
|《Sokrati》{{small|({{lang|el|Σωκράτη}})}}
|希腊语
|align=center|8
|align=center|69
|-
! scope="row" style="text-align:center" | {{Escyr|1980}}
|[[安娜·维西|Anna Vissi]] and the Epikouri
|《Autostop》 {{small|({{lang|el|Ωτοστόπ}})}}
|希腊语
|align=center|13
|align=center|30
|-
! scope="row" style="text-align:center" | {{Escyr|1981}}
|[[希腊在欧洲歌唱大赛之历年表现|Yiannis Dimitras]]
|《Feggari kalokerino》{{small|({{lang|el|Φεγγάρι καλοκαιρινό}})}}
|希腊语
|align=center|8
|align=center|55
|-bgcolor="#A4EAA9"
! scope="row" style="text-align:center" | {{Escyr|1982}}
|[[Themis Adamantidis]]
|《Sarantapente kopelies》{{small|({{lang|el|Σαρανταπέντε κοπελιές}})}}
|希腊语
|colspan="2" {{N/A|退赛}} '''X'''
|-
! scope="row" style="text-align:center" | {{Escyr|1983}}
|[[Kristi Stassinopoulou]]
|《Mou les》{{small|({{lang|el|Μου λες}})}}
|希腊语
|align=center|14
|align=center|32
|-
! scope="row" style="text-align:center" | {{Escyr|1985}}
|[[希腊在欧洲歌唱大赛之历年表现|Takis Biniaris]]
|《Miazoume》 {{small|({{lang|el|Μοιάζουμε}})}}
|希腊语
|align=center|16
|align=center|15
|-bgcolor="#A4EAA9"
! scope="row" style="text-align:center" | {{Escyr|1986}}
|[[Polina (Greek singer)|Polina]]
|《Wagon-lit》 {{small|({{lang|el|Βαγκόν λι}})}}
|希腊语
|colspan="2" {{N/A|Withdrawn}} '''X'''
|-
! scope="row" style="text-align:center" | {{Escyr|1987}}
|[[Bang (Greek band)|Bang]]
|《Stop》 {{small|({{lang|el|Στοπ}})}}
|希腊语
|align=center|10
|align=center|64
|-
! scope="row" style="text-align:center" | {{Escyr|1988}}
|[[希腊在欧洲歌唱大赛之历年表现|Afroditi Frida]]
|《Clown》 {{small|({{lang|el|Κλόουν}})}}
|希腊语
|align=center|17
|align=center|10
|-
! scope="row" style="text-align:center" | {{Escyr|1989}}
|[[Marianna Efstratiou|Marianna]]
|《To diko sou asteri》 {{small|({{lang|el|Το δικό σου αστέρι}})}}
|希腊语
|align=center|9
|align=center|56
|-
! scope="row" style="text-align:center" | {{Escyr|1990}}
|[[Christos Callow]] and Wave
|《Horis skopo》 {{small|({{lang|el|Χωρίς σκοπό}})}}
|希腊语
|align=center|19
|align=center|11
|-
! scope="row" style="text-align:center" | {{Escyr|1991}}
|[[Sophia Vossou]]
|《I anixi》 {{small|({{lang|el|Η ανοιξη}})}}
|希腊语
|align=center|13
|align=center|36
|-
! scope="row" style="text-align:center" | {{Escyr|1992}}
|[[希腊在欧洲歌唱大赛之历年表现|Cleopatra]]
|《Olou tou kosmou i Elpida》 {{small|({{lang|el|Όλου του κόσμου η Ελπίδα}})}}
|希腊语
|align=center|5
|align=center|94
|-
! scope="row" style="text-align:center" | {{Escyr|1993}}
|[[Katy Garbi]]
|《Ellada, chora tou fotos》 {{small|({{lang|el|Ελλάδα, χώρα του φωτός}})}}
|希腊语
|align=center|9
|align=center|64
|colspan="2" data-sort-value="-9999" {{N/A|[[Kvalifikacija za Millstreet]]}}
|-
! scope="row" style="text-align:center" | {{Escyr|1994}}
|[[Kostas Bigalis]] and the Sea Lovers
|《To trehantiri (Diri Diri)》 {{small|({{lang|el|Το τρεχαντήρι (Ντίρι Ντίρι)}})}}
|希腊语
|align=center|14
|align=center|44
|colspan="2" rowspan="2" data-sort-value="99999" {{N/A|No semi-finals}}
|-
! scope="row" style="text-align:center" | {{Escyr|1995}}
|[[Elina Konstantopoulou]]
|《Pia prosefhi》 {{small|({{lang|el|Ποια προσευχή}})}}
|希腊语
|align=center|12
|align=center|68
|-
! scope="row" style="text-align:center" | {{Escyr|1996}}
|Marianna Efstratiou
|《Emis forame to himona anixiatika》 {{small|({{lang|el|Εμείς φοράμε το χειμώνα ανοιξιάτικα}})}}
|希腊语
|align=center|14
|align=center|36
|align=center|12
|align=center|45
|-
! scope="row" style="text-align:center" | {{Escyr|1997}}
|[[Marianna Zorba]]
|《Horepse》 {{small|({{lang|el|Χόρεψε}})}}
|希腊语
|align=center|12
|align=center|39
|colspan="2" rowspan="5" data-sort-value="99999" {{N/A|No semi-finals}}
|-
! scope="row" style="text-align:center" | {{Escyr|1998}}
|Thalassa
|《Mia krifi evaisthisia》 {{small|({{lang|el|Μια κρυφή ευαισθησία}})}}
|希腊语
|align=center|20
|align=center|12
|-bgcolor="#c96"
! scope="row" style="text-align:center" | {{Escyr|2001}}
|[[Antique (band)|Antique]]
|《(I Would) Die for You》
|英语, Greek
|align=center|3
|align=center|147
|-
! scope="row" style="text-align:center" | {{Escyr|2002}}
|[[Michalis Rakintzis]]
|《S.A.G.A.P.O.》
|英语
|align=center|17
|align=center|27
|-
! scope="row" style="text-align:center" | {{Escyr|2003}}
|[[Mando (singer)|Mando]]
|《Never Let You Go》
|英语
|align=center|17
|align=center|25
|-
|-bgcolor="#c96"
! scope="row" style="text-align:center" | {{Escyr|2004}}
|[[萨基斯·鲁瓦斯]]
|《Shake It》
|英语
|align=center|3
|align=center|252
|align=center|3
|align=center|238
|-bgcolor="Gold"
! scope="row" style="text-align:center" | {{Escyr|2005}}
|[[艾莲娜·帕帕里祖]]
|《My Number One》
|英语
|align=center|1
|align=center|230
|colspan="2" data-sort-value="-9999" {{N/A|上届排名前12直接晋级决赛}}{{NoteTag|name=note2|根据当时的比赛规则,排名前十的非“四大国”(Big Four)国家与“四大国”在来年自动晋级决赛,无需参加半决赛角逐,换而言之共有14个国家可以直接晋级决赛。}}
|-
! scope="row" style="text-align:center" | {{Escyr|2006}}
|Anna Vissi
|《Everything》
|英语
|align=center|9
|align=center|128
|colspan="2" data-sort-value="-9999" {{N/A|东道主直接晋级}}
|-
! scope="row" style="text-align:center" | {{Escyr|2007}}
|[[Sarbel]]
|《Yassou Maria》 {{small|({{lang|el|Γεια σου Μαρία}})}}
|英语
|align=center|7
|align=center|139
|colspan="2" data-sort-value="-9999" {{N/A|上届排名前10直接晋级决赛}}{{NoteTag|name=note2}}
|-bgcolor="#c96"
! scope="row" style="text-align:center" | {{Escyr|2008}}
|[[Kalomira]]
|《Secret Combination》
|英语
|align=center|3
|align=center|218
|bgcolor="Gold" align=center|1
|bgcolor="Gold" align=center|156
|-
! scope="row" style="text-align:center" | {{Escyr|2009}}
|Sakis Rouvas
|《This Is Our Night》
|英语
|align=center|7
|align=center|120
|align=center|4
|align=center|110
|-
! scope="row" style="text-align:center" | {{Escyr|2010}}
|[[Giorgos Alkaios]] and Friends
|《Opa (Giorgos Alkaios song)|Opa》 {{small|({{lang|el|Ώπα}})}}
|希腊语
|align=center|8
|align=center|140
|bgcolor="silver" align=center|2
|bgcolor="silver" align=center|133
|-
! scope="row" style="text-align:center" | {{Escyr|2011}}
|[[Loukas Yorkas]] feat. [[Stereo Mike]]
|《Watch My Dance》
|希腊语、英语
|align=center|7
|align=center|120
|bgcolor="Gold" align=center|1
|bgcolor="Gold" align=center|133
|-
! scope="row" style="text-align:center" | {{Escyr|2012}}
|[[Eleftheria Eleftheriou]]
|《Aphrodisiac》
|英语
|align=center|17
|align=center|64
|align=center|4
|align=center|116
|-
! scope="row" style="text-align:center" | {{Escyr|2013}}
|[[Koza Mostra]] feat. [[Agathonas Iakovidis|Agathon Iakovidis]]
|《Alcohol Is Free》
|希腊语、英语
|align=center|6
|align=center|152
|bgcolor="silver" align=center|2
|bgcolor="silver" align=center|121
|-
! scope="row" style="text-align:center" | {{Escyr|2014}}
|[[Freaky Fortune]] feat. [[RiskyKidd]]
|《Rise Up》
|英语
|align=center|20
|align=center|35
|align=center|7
|align=center|74
|-
! scope="row" style="text-align:center" | {{Escyr|2015}}
|[[Maria Elena Kyriakou]]
|《One Last Breath》
|英语
|align=center|19
|align=center|23
|align=center|6
|align=center|81
|-
! scope="row" style="text-align:center" | {{Escyr|2016}}
|Argo
|《Utopian Land》
|希腊语、英语
|colspan="2" {{N/A|未能晋级决赛}}
|align=center|16
|align=center|44
|-
! scope="row" style="text-align:center" | {{Escyr|2017}}
|[[Demy (singer)|Demy]]
|《This Is Love》
|英语
|align=center|19
|align=center|77
|align=center|10
|align=center|115
|-
! scope="row" style="text-align:center" | {{Escyr|2018}}
|[[Yianna Terzi]]
|《Oniro mou》 {{small|({{lang|el|Όνειρό μου}})}}
|希腊语
|colspan="2" {{N/A|未能晋级决赛}}
|align=center|14
|align=center|81
|-
! scope="row" style="text-align:center" | {{Escyr|2019}}
|[[Katerine Duska]]
|《Better Love》
|英语
|align=center|21
|align=center|74
|align=center|5
|align=center|185
|-bgcolor="#A4EAA9"
! scope="row" style="text-align:center" | {{Escyr|2020}}
|[[史蒂芬妮娅·利伯拉卡基斯]]
|《Supergirl》
|英语
|colspan="4" {{N/A|比赛因[[2019冠状病毒病疫情]]取消、}} '''X'''
|-
! scope="row" style="text-align:center" | {{Escyr|2021}}
|史蒂芬妮娅·利伯拉卡基斯
|《Last Dance》
|英语
|align=center|10
|align=center|170
|align=center|6
|align=center|184
|-
! scope="row" style="text-align:center" | {{Escyr|2022}}
| [[Amanda Tenfjord|Amanda Georgiadi Tenfjord]]
|《Die Together》
|英语
|align=center|8
|align=center|215
|bgcolor=#c96 align=center|3
|bgcolor=#c96 align=center|211
|-
! scope="row" style="text-align:center" | {{Escyr|2023}}
|[[Victor Vernicos]]
|《What They Say》
|英语
| colspan="2" {{N/A|未能晋级决赛}}
|align=center|13
|align=center|14
|-
! scope="row" style="text-align:center;" | {{Escyr|2024}}
| [[Marina Satti]]
|《Zari》{{small|({{lang|el|Ζάρι}})}}
| 希腊语
| style="text-align:center;" | 11
| style="text-align:center;" | 126
| style="text-align:center;" | 5
| style="text-align:center;" | 86
|-
! scope="row" style="text-align:center;" | {{Escyr|2025}}
| [[Klavdia (singer)|Klavdia]]
| 《Asteromata》{{small|({{lang|el|Αστερομάτα}})}}
| 希腊语
| style="text-align:center;" | 6
| style="text-align:center;" | 231
| style="text-align:center;" | 4
| style="text-align:center;" | 112
|}
;注释
{{NoteFoot}}
== 比赛火热度 ==
到2001年为止,希腊一直是最不成功的参赛国之一,所以该国国民对比赛的热情一直不高。但自从Antique在2001年获得第3名后,该比赛开始在希腊获得广泛关注,并成为估计拥有5百万收视率的年度热门节目之一。希腊民众对该比赛给予了很高的关注,甚至搞得有点像是国家节日一样,这在当地社会也引起了广泛争论。希腊观众一直期望他们的歌曲可以保住前10名的成绩,但2012年成绩不佳,排到了第17。但2013年,希腊再次进入前10,取得第6名。<ref>{{cite web|url=http://www.esctoday.com/news/read/13610|title=Introducing the 2009 entries: Greece|last=Klier|first=Marcus|date=2009-03-30|publisher=''ESCToday''|accessdate=2009-03-30|archive-date=2009-04-01|archive-url=https://web.archive.org/web/20090401124744/http://www.esctoday.com/news/read/13610|dead-url=no}}</ref>从2000年到2009年,希腊获得了1次冠军和3次前3名。
== 欧洲歌唱大赛50周年庆典 ==
{{further2|[[欧洲歌唱大赛50周年庆典]]}}
;图例说明:
{{legend|gold|冠军}}
{{legend|silver|亚军}}
{{legend|#cc9966|季军}}
{{legend|#FE8080|垫底}}
{| class="wikitable sortable" style="width:100%"
|-
! 年份
! 艺人
! 语种
! 歌名
! 决赛成绩
! 得分
! 半决赛成绩
! 得分
! 名次 ([[2005年欧洲歌唱大赛|2005]])
! 得分 ([[2005年欧洲歌唱大赛|2005]])
|-
| [[2005年欧洲歌唱大赛|2005]]
| [[艾莲娜·帕帕里祖]]
| [[英语]]
| 《My Number One》
| 4
| 245
| 4
| 167
| bgcolor="gold"| 1
| bgcolor="gold"| 230
|}
== 影集 ==
<gallery mode=packed heights=130px>
Image:Sakis Rouvas ESC 2004 Istanbul.jpg|[[萨基斯·鲁瓦斯]]在于[[伊斯坦布尔]]举办的[[2004年欧洲歌唱大赛]]上献艺
Image:ESC 2007 Greece - Sarbel-Yassou Maria2.jpg|Sarbel在于[[赫尔辛基]]举办的[[2007年欧洲歌唱大赛]]上献艺
Image:ESC 2008 - Greece - Kalomira, 1st semifinal.jpg|{{link-en|卡罗米拉|Kalomira}}在于[[贝尔格莱德]]举办的[[2008年欧洲歌唱大赛]]上献艺
Image:Sakis Rouvas Raising Greek Flag.jpg|萨基斯·鲁瓦斯在于[[莫斯科]]举办的[[2009年欧洲歌唱大赛]]上献艺
Image:Giorgos Alkaios 01.JPG|Giorgos Alkaios和Friends在于[[贝鲁姆]]举办的[[2010年欧洲歌唱大赛]]上献艺
Image:ESC2013 - Greece 01.jpg|Koza Mostra和Agathonas Iakovidis在于[[马尔默]]举办的[[2013年欧洲歌唱大赛]]上献艺
Image:ESC2014 - Greece 11.jpg|Freaky Fortune和Riskykidd在于[[哥本哈根]]举办的[[2014年欧洲歌唱大赛]]上献艺
</gallery>
== Participation ==
[[希腊广播电视公司]]([[ERT]])是[[欧洲广播联盟]](EBU)的正式成员,因此有资格在[[欧洲歌唱大赛]]中代表[[希腊]]参赛。在所有希腊参赛作品中,只有三首不是由ERT选送。该国在第19届、即1974年的比赛中首次亮相时,是由ERT的前身——[[国家广播电视基金会]](EIRT)负责参赛;而在2014年和2015年的希腊参赛作品,则由ERT在停播期间的替代机构“[[新希腊广播、互联网与电视]]”(NERIT)选送。
在[[希腊]]参加[[欧洲歌唱大赛]]之前,一些[[希腊人]]歌手曾代表其他国家参赛。这些歌手包括代表[[奥地利]]参赛的[[吉米·马库利斯]](1961年),代表[[瑞士]]参赛的[[约万娜]](1965年),以及代表[[卢森堡]]参赛的[[娜娜·穆斯库里]](1963年)和[[维姬·莱安德罗斯]](1967年和1972年)。
== 另见 ==
* {{link-en|欧视歌曲——疯狂之秀|Eurosong - A MAD Show}}
== 脚注 ==
{{reflist}}
== 外部链接 ==
* [http://www.eurovisioncovers.co.uk/xtgre.htm 希腊的得分和给分情况汇总]{{Webarchive|url=https://web.archive.org/web/20201031043436/http://www.eurovisioncovers.co.uk/xtgre.htm |date=2020-10-31 }} ''eurovisioncovers.co.uk''
{{欧洲歌唱大赛}}
{{DEFAULTSORT:Greece In The Eurovision Song Contest}}
[[Category:各國在歐洲歌唱大賽之歷年表現]]
[[Category:希腊电视]]
[[Category:希腊音樂]]
oums3yraij91zbmr1oq6ss7pn1o272h
Page 44
0
169803
743897
703785
2026-05-22T13:50:21Z
~2026-30508-20
74100
743897
wikitext
text/x-wiki
c9eede95024e5bf4cea92629aea0cb3a
testcaptcha
57atwo4gnis0nwdvhnz9mv4r23lpcq7
WET Awards 2002
0
175148
743902
740389
2026-05-22T13:56:14Z
~2026-30728-52
74101
743902
wikitext
text/x-wiki
{{Short description|American entertainment awards ceremony}}
{{one source|date=June 2025}}
{{Use mdy dates|date=February 2025}}
{{Infobox award
| name = 2nd WET Awards
| image =
| caption =
| date = June 25, 2002
| location = [[Dolby Theatre|Kodak Theatre]], [[Los Angeles]], [[California]]
| presenter = [[WET (TV channel)|White Entertainment Television]]
| host = [[Vince McMahon]] <br />[[Shane McMahon]]
| network = [[WET (TV channel)|WET]]
| producer =
| previous = [[WET Awards 2001|1st]]
| main = {{nowrap|[[WET Awards]]}}
| next = [[WET Awards 2003|3rd]]
}}
The '''2nd [[WET Awards]]''' took place at the [[Dolby Theatre|Kodak Theatre]] in [[Los Angeles]], [[California]] on June 25, 2002. The awards recognized Americans in music, acting, sports, and other fields of entertainment over the past year. Professional wrestler [[Vince McMahon]] and [[Shane McMahon]] hosted the event for the second time.
==Performances==
==Presenters==
==Winners and nominees==
==References==
{{reflist}}
==External links==
{{WET Awards}}
[[Category:WET Awards]]
[[Category:2002 awards in the United States]]
{{US-tv-stub}}
dexmjochbd6vruh7g3dt3ejbxoos4mf
WET Awards 2001
0
175155
743900
740786
2026-05-22T13:53:36Z
~2026-30728-52
74101
743900
wikitext
text/x-wiki
{{Short description|Award ceremony in Las Vegas, Nevada}}
{{One source|date=June 2025}}
{{Use mdy dates|date=February 2025}}
{{Infobox award
| name = 1st WET Awards
| image =
| caption =
| date = June 19, 2001
| location = [[Paris Las Vegas|Paris Hotel]], [[Las Vegas]], [[Nevada]]
| presenter = [[WET (TV channel)|White Entertainment Television]]
| host = [[Vince McMahon]] <br />[[Shane McMahon]]
| network = [[WET (TV channel)|WET]]
| previous =
| main = {{nowrap|[[WET Awards]]}}
| next = [[WET Awards 2002|2nd]]
}}
The '''1st [[WET Awards]]''' took place at the [[Paris Las Vegas|Paris Hotel]] in [[Las Vegas]], [[Nevada]] on June 19, 2001. The awards recognized Americans in Music, Acting, Sports, and other fields of entertainment over the past year. Professional wrestler [[Vince McMahon]] and [[Shane McMahon]] hosted the event for the first time.
==Performances=
==Presenters==
==Winners and nominees==
==References==
{{reflist}}
{{WET Awards}}
[[Category:WET Awards]]
[[Category:2001 awards in the United States]]
{{US-tv-stub}}
9k2mlsx3oci6ysqprpk6pk4vtlsp9sr
743901
743900
2026-05-22T13:55:30Z
~2026-30728-52
74101
743901
wikitext
text/x-wiki
{{Short description|Award ceremony in Las Vegas, Nevada}}
{{One source|date=June 2025}}
{{Use mdy dates|date=February 2025}}
{{Infobox award
| name = 1st WET Awards
| image =
| caption =
| date = June 19, 2001
| location = [[Paris Las Vegas|Paris Hotel]], [[Las Vegas]], [[Nevada]]
| presenter = [[WET (TV channel)|White Entertainment Television]]
| host = [[Vince McMahon]] <br />[[Shane McMahon]]
| network = [[WET (TV channel)|WET]]
| previous =
| main = {{nowrap|[[WET Awards]]}}
| next = [[WET Awards 2002|2nd]]
}}
The '''1st [[WET Awards]]''' took place at the [[Paris Las Vegas|Paris Hotel]] in [[Las Vegas]], [[Nevada]] on June 19, 2001. The awards recognized Americans in Music, Acting, Sports, and other fields of entertainment over the past year. Professional wrestler [[Vince McMahon]] and [[Shane McMahon]] hosted the event for the first time.
==Performances==
==Presenters==
==Winners and nominees==
==References==
{{reflist}}
{{WET Awards}}
[[Category:WET Awards]]
[[Category:2001 awards in the United States]]
{{US-tv-stub}}
b97o8rxbi1y62wp49c0z4s0xd0ph4kk
User:GearsDatapacks/MovePlus.js
2
175186
743909
740565
2026-05-22T16:24:37Z
GearsDatapacks
72666
Add initial version of smart move
743909
javascript
text/javascript
const WATCHLISTPAGES = false;
//movePlus
//<nowiki>
var movePlus = {
numberOfMoves: 0,
multiMove: false,
destinations: [],
parsedDate: undefined,
pages: [],
templateIndex: -1,
moveQueue: [],
editQueue: [],
activeIntervals: [], // NEW: Track all intervals for cleanup
linkAdjustWarning: '\t<span style="color: red;"><b>Warning:</b></span> This will automatically update pages, retargeting all links from the current value to the value you specify. You take full responsibility for any action you perform using this script.'
};
window.movePlus = movePlus;
// Store references for cleanup
movePlus.eventHandlers = {
closeButton: null,
relistButton: null,
confirmButton: null,
cancelButton: null,
notifyButton: null,
portletLink: null
};
movePlus.attachEventHandlers = function () {
if (document.getElementById("requestedmovetag") !== null && Morebits.pageNameNorm.indexOf("alk:") !== -1 && mw.config.get('wgCategories').includes('Requested moves') && !document.getElementById("wikiPreview") && mw.config.get('wgDiffOldId') == null) {
document.getElementById("requestedmovetag").innerHTML = "<button id='movePlusClose'>Close</button><button id='movePlusRelist'>Relist</button><button id='movePlusNotify'>Notify WikiProjects</button><span id='movePlusRelistOptions' style='display:none'><input id='movePlusRelistComment' placeholder='Relisting comment' oninput='if(this.value.length>20){this.size=this.value.length} else{this.size=20}'/><br><button id='movePlusConfirm'>Confirm relist</button><button id='movePlusCancel'>Cancel relist</button></span>";
// Use event delegation or store handlers for cleanup
movePlus.eventHandlers.closeButton = $('#movePlusClose').on('click', movePlus.callback);
movePlus.eventHandlers.relistButton = $('#movePlusRelist').on('click', movePlus.confirmRelist);
movePlus.eventHandlers.confirmButton = $('#movePlusConfirm').on('click', movePlus.relist);
movePlus.eventHandlers.cancelButton = $('#movePlusCancel').on('click', movePlus.cancelRelist);
movePlus.eventHandlers.notifyButton = $('#movePlusNotify').on('click', movePlus.notify);
}
var portletLink = mw.util.addPortletLink("p-cactions", "#movePlusMove", "Move\+",
"ca-movepages", "Move pages (expanded options)");
movePlus.eventHandlers.portletLink = $(portletLink).on('click', movePlus.displayWindowMove);
};
movePlus.removeEventHandlers = function () {
$('#movePlusClose').off('click', movePlus.callback);
$('#movePlusRelist').off('click', movePlus.confirmRelist);
$('#movePlusConfirm').off('click', movePlus.relist);
$('#movePlusCancel').off('click', movePlus.cancelRelist);
$('#movePlusNotify').off('click', movePlus.notify);
if (movePlus.eventHandlers.portletLink) {
movePlus.eventHandlers.portletLink.off('click', movePlus.displayWindowMove);
}
};
$.when(
mw.loader.using(['mediawiki.api', 'ext.gadget.morebits', 'ext.gadget.libExtraUtil']),
$.ready
).then(function () {
movePlus.attachEventHandlers();
});
// Cleanup on page unload
$(window).on('beforeunload', function () {
movePlus.removeEventHandlers();
movePlus.cleanupIntervals();
});
movePlus.confirmRelist = function movePlusConfirmRelist(e) {
if (e) e.preventDefault();
document.getElementById("movePlusRelistOptions").style.display = "inline";
document.getElementById("movePlusClose").style.display = "none";
document.getElementById("movePlusRelist").style.display = "none";
document.getElementById("movePlusNotify").style.display = "none";
};
movePlus.cancelRelist = function movePlusCancelRelist(e) {
if (e) e.preventDefault();
document.getElementById("movePlusRelistOptions").style.display = "none";
document.getElementById("movePlusClose").style.display = "inline";
document.getElementById("movePlusRelist").style.display = "inline";
document.getElementById("movePlusNotify").style.display = "inline";
};
movePlus.advert = ' using [[User:BilledMammal/Move+|Move+]]';
movePlus.preEvaluate = async function () {
try {
const talkPageContent = await loadTalkPage();
return extractTemplateData(talkPageContent);
} catch (error) {
console.error('Error during pre-evaluation:', error);
}
};
async function loadTalkPage() {
var title_obj = mw.Title.newFromText(Morebits.pageNameNorm);
const talkpage = new Morebits.wiki.page(title_obj.getTalkPage().toText(), 'Retrive move proposals.');
return new Promise((resolve, reject) => {
talkpage.load(function (talkpage) {
if (talkpage.exists()) {
resolve(talkpage.getPageText());
} else {
reject('Page does not exist');
}
}, reject);
});
}
function extractTemplateData(text) {
const templatesOnPage = extraJs.parseTemplates(text, false);
let templateData = {};
templatesOnPage.forEach(template => {
if (template.name.toLowerCase() === "requested move/dated") {
templateData = { ...templateData, ...parseRequestedMoveTemplate(template) };
}
});
return templateData;
}
function parseRequestedMoveTemplate(template) {
const data = {
moves: [],
multiMove: template.parameters.some(param => param.name === "multiple")
};
const pairs = {};
template.parameters.forEach(param => {
const match = param.name.toString().match(/^(current|new)?(\d+)$/);
if (match) {
const type = match[1] ? match[1] : "new";
const index = match[2];
if (!pairs[index]) {
pairs[index] = {};
}
if (!pairs[index][type] || param.value != "") {
pairs[index][type] = param.value;
}
}
});
if (!pairs[1]["current"]) {
let title_obj = mw.Title.newFromText(Morebits.pageNameNorm);
pairs[1]["current"] = title_obj.getSubjectPage().toText();
}
Object.keys(pairs).forEach(index => {
const pair = pairs[index];
if (pair.current && pair.new) {
data.moves.push({ current: pair.current, destination: pair.new });
}
});
return data;
}
movePlus.callback = async function movePlusCallback(e) {
e.preventDefault(e);
try {
const evaluationData = await movePlus.preEvaluate();
if (evaluationData) {
movePlus.displayWindowClose(evaluationData);
} else {
throw new Error("Failed to retrieve necessary data for processing.");
}
} catch (error) {
console.error('Error during callback execution:', error);
}
};
movePlus.displayWindowClose = function movePlusDisplayWindowClose(data) {
let checkboxStates = {};
movePlus.Window = new Morebits.simpleWindow(600, 450);
movePlus.Window.setTitle("Close requested move");
movePlus.Window.setScriptName('Move+');
movePlus.Window.addFooterLink('RM Closing instruction', 'WP:RMCI');
movePlus.Window.addFooterLink('Script documentation', 'User:BilledMammal/Move+');
movePlus.Window.addFooterLink('Give feedback', 'User talk:BilledMammal/Move+');
var form = new Morebits.quickForm(function (e) {
movePlus.evaluate(e, data);
});
setupForm();
function setupForm() {
var resultContainer = form.append({
type: 'div',
style: 'display: flex; flex-direction: row; gap: 10px;'
});
var resultField = setupResultOptions(resultContainer);
setupCustomResult(resultField);
var movedOptionsField = setupMoveOptions(resultContainer);
setupCustomTitles();
setupClosingComment(form);
}
function setupResultOptions(container) {
var resultField = container.append({
type: 'field',
label: 'Result',
style: 'flex: 1;'
});
resultField.append({
type: 'radio',
name: 'result',
required: true,
list: [
{
label: 'Moved',
value: 'moved',
event: function () { updateResultOptions('moved'); }
},
{
label: 'Not moved',
value: 'not moved',
event: function () { updateResultOptions('not moved'); }
},
{
label: 'No consensus',
value: 'no consensus',
event: function () { updateResultOptions('no consensus'); }
},
{
label: 'Custom',
value: 'custom',
event: function () { updateResultOptions('custom'); }
}
]
});
return resultField;
}
function updateResultOptions(result) {
const customResultDisplay = document.getElementsByName('customResult')[0];
const movedOptionsDisplay = document.getElementsByName('movedOptionsField')[0];
const customTitlesDisplay = document.getElementById('customTitles');
const checkboxes = document.querySelectorAll('input[name="movedOptionsInputs"]');
// Default settings
customResultDisplay.style.display = 'none';
customResultDisplay.required = false;
movedOptionsDisplay.style.display = 'none';
customTitlesDisplay.style.display = 'none';
// Unset move options
if (result != 'moved') {
checkboxes.forEach(checkbox => {
if (checkbox.checked) {
checkboxStates[checkbox.value] = true;
checkbox.checked = false;
const event = new Event('change');
checkbox.dispatchEvent(event);
} else {
checkboxStates[checkbox.value] = false;
}
});
}
switch (result) {
case 'moved':
movedOptionsDisplay.style.display = 'block';
// Reset move options
checkboxes.forEach(checkbox => {
if (checkboxStates[checkbox.value]) {
checkbox.checked = true;
const event = new Event('change');
checkbox.dispatchEvent(event);
}
});
break;
case 'custom':
customResultDisplay.style.display = 'inline';
customResultDisplay.required = true;
break;
}
}
function setupMoveOptions(container) {
let originalClosingComment = '';
const movedOptionsField = container.append({
type: 'field',
label: 'Specify move type',
style: 'display: none; flex: 1;',
name: 'movedOptionsField'
});
movedOptionsField.append({
type: 'checkbox',
name: 'movedOptionsInputs',
list: [
{
label: 'Close as uncontested',
value: 'moved-uncontested',
tooltip: 'We treat discussions where no objections have been raised, but community support has also not been demonstrated, as uncontested technical requests.',
event: function (event) {
const closingComment = document.getElementsByName('closingComment')[0];
if (event.target.checked) {
originalClosingComment = closingComment ? closingComment.value : '';
closingComment.value = 'Moved as an [[WP:RMNOMIN|uncontested request with minimal participation]]. If there is any objection within a reasonable time frame, please ask me to reopen the discussion; if I am not available, please ask at the [[WP:RM/TR#Requests to revert undiscussed moves|technical requests]] page.';
} else {
closingComment.value = originalClosingComment;
}
}
},
{
label: 'Specify different titles',
value: 'moved-different-title',
tooltip: 'If no title was originally proposed, or if there is a consensus to move to a title other than that which was originally proposed.',
event: function () {
if (event.target.checked) {
customTitles.style.display = 'block';
} else {
customTitles.style.display = 'none';
}
}
}
]
});
return movedOptionsField;
}
function setupCustomResult(resultField) {
resultField.append({
type: 'input',
name: 'customResult',
style: 'display: none;'
});
}
function setupCustomTitles() {
const customTitles = form.append({
type: 'field',
label: 'Specify titles',
id: 'customTitles',
name: 'customTitles',
style: 'display: none;'
});
data.moves.forEach((pair, index) => {
const titleField = customTitles.append({
type: 'div',
className: 'customTitleInput',
style: 'display: flex; align-items: center; margin-bottom: 5px;'
});
titleField.append({
type: 'div',
style: 'flex: 0 1 47.5%; text-align: left;',
label: pair.current
});
titleField.append({
type: 'div',
style: 'flex: 0 1 5%; text-align: center;',
label: '→'
});
const inputDiv = titleField.append({
type: 'div',
style: 'flex: 1;'
});
inputDiv.append({
type: 'input',
name: pair.current,
value: pair.destination,
style: 'width: 95%; text-align: left;'
});
});
const toggleButton = customTitles.append({
type: 'button',
label: 'Hide titles',
event: function (event) {
const titleInputs = document.querySelectorAll('.customTitleInput');
const button = event.target;
titleInputs.forEach(input => {
if (input.style.display === 'none' || input.style.display === '') {
input.style.display = 'flex';
button.value = 'Hide titles';
} else {
input.style.display = 'none';
button.value = 'Show titles';
}
});
}
});
}
function setupClosingComment(form) {
const closingCommentField = form.append({
type: 'field',
label: 'Closing comment'
});
closingCommentField.append({
type: 'textarea',
name: 'closingComment'
});
}
form.append({ type: 'submit', label: 'Submit' });
var formResult = form.render();
movePlus.Window.setContent(formResult);
movePlus.Window.display();
};
movePlus.displayWindowMove = function movePlusDisplayWindowMove() {
var title_obj = mw.Title.newFromText(Morebits.pageNameNorm);
movePlus.title = title_obj.getSubjectPage().toText();
movePlus.displayWindowInit();
movePlus.displayWindowAction();
}
movePlus.displayWindowInit = function movePlusDisplayWindowInit() {
movePlus.Window = new Morebits.simpleWindow(600, 450);
movePlus.Window.setScriptName('Move+');
movePlus.Window.addFooterLink('Moving instructions', 'Wikipedia:Moving a page');
movePlus.Window.addFooterLink('Script documentation', 'User:BilledMammal/Move+');
movePlus.Window.addFooterLink('Give feedback', 'User talk:BilledMammal/Move+');
}
movePlus.displayWindowAction = function movePlusDisplayWindowAction() {
var moveData = [{
current: movePlus.title,
target: ''
}];
var retargetData = [{
current: '',
target: ''
}];
var config = {
move: {
data: moveData,
reason: '',
label: 'Specify moves',
reasonLabel: 'Move reason',
reasonName: 'moveReason',
actionLimit: 100,
buttonLabel: 'Add move',
title: 'Move pages',
information: ''
},
retarget: {
data: retargetData,
reason: '',
label: 'Specify link retargets',
reasonLabel: 'Link retarget reason',
reasonName: 'retargetReason',
actionLimit: 2,
buttonLabel: 'Add retarget',
title: 'Retarget links',
information: movePlus.linkAdjustWarning
}
};
function updateForm(action) {
movePlus.Window.setTitle(config[action].title);
function updateActionDataFromForm() {
config[action].data = [];
config[action].reason = document.querySelector(`textarea[name="${config[action].reasonName}"]`).value;
var currentInputs = document.querySelectorAll('input[name="curr"]');
var targetInputs = document.querySelectorAll('input[name="dest"]');
currentInputs.forEach((input, index) => {
config[action].data.push({
current: input.value,
target: targetInputs[index].value
});
});
};
var form = new Morebits.quickForm(function (e) {
e.preventDefault();
movePlus.params = Morebits.quickForm.getInputData(e.target);
var currentPages = [];
var targetPages = [];
$('input[name="curr"]').each(function (index) {
var currentPage = $(this).val();
var targetPage = $('input[name="dest"]').eq(index).val();
if (currentPage && targetPage) {
currentPages.push(currentPage);
targetPages.push(targetPage);
}
});
if (action == 'move') {
movePlus.movePages(currentPages, targetPages, movePlus.params.moveReason, false);
}
if (action == 'retarget') {
movePlus.retargetLinks(currentPages, targetPages, movePlus.params.retargetReason);
}
});
movePlus.appendOptions(form, action, updateForm, updateActionDataFromForm);
var actionsContainer = form.append({
type: 'field',
label: config[action].label,
id: 'actionList',
name: 'actionList'
});
config[action].data.forEach((data, index) => {
const titleField = actionsContainer.append({
type: 'div',
className: 'titleInput',
style: 'display: flex; align-items: center; margin-bottom: 5px;'
});
const currentDiv = titleField.append({
type: 'div',
style: 'flex: 0 1 47.5%; text-align: left;'
});
currentDiv.append({
type: 'input',
name: 'curr',
value: data.current,
placeholder: 'Current page',
required: true,
style: 'width: 95%; text-align: left;'
});
titleField.append({
type: 'div',
style: 'flex: 0 1 5%; text-align: center;',
label: '→'
});
const destDiv = titleField.append({
type: 'div',
style: 'flex: 0 1 47.5%; text-align: left;'
});
destDiv.append({
type: 'input',
name: 'dest',
value: data.target,
required: true,
placeholder: 'Target page',
style: 'width: 95%; text-align: left;'
});
titleField.append({
type: 'button',
label: 'Remove',
disabled: config[action].data.length < 2 ? true : false,
event: function () {
updateActionDataFromForm();
config[action].data.splice(index, 1);
updateForm(action);
}
});
});
actionsContainer.append({
type: 'button',
label: config[action].buttonLabel,
disabled: config[action].data.length < config[action].actionLimit ? false : true,
event: function () {
updateActionDataFromForm();
config[action].data.push({ current: '', target: '' });
updateForm(action);
}
});
movePlus.appendReason(form, config[action].reasonLabel, config[action].reasonName, config[action].reason);
form.append({
type: 'div',
label: config[action].information,
style: 'margin-left: 15px; margin-right: 15px;'
});
form.append({ type: 'submit', label: 'Submit' });
var formResult = form.render();
movePlus.Window.setContent(formResult);
movePlus.appendReasonAlert(config[action].reasonLabel, config[action].reasonName);
movePlus.Window.display();
}
updateForm('move');
}
movePlus.retargetLinks = async function movePlusRetargetLinks(currentLinks, targetLinks, reason) {
var form = new Morebits.quickForm();
var actionContainer = form.append({
type: 'field',
label: 'Retargeting'
});
actionContainer.append({
type: 'div',
className: 'movePlusProgressBox',
label: ''
});
var multiple = currentLinks[1] ? true : false;
var config = {
currTarget: targetLinks[0],
destTarget: multiple ? targetLinks[1] : ''
}
var formResult = form.render();
movePlus.Window.setContent(formResult);
movePlus.Window.display();
const progressBox = document.querySelector('.movePlusProgressBox');
movePlus.linkEditSummary = reason + ': ';
await movePlus.correctLinks(currentLinks[0], multiple ? currentLinks[1] : '', config, progressBox);
progressBox.innerText = 'Done.'
setTimeout(function () { movePlus.Window.close(); }, 1250);
}
movePlus.appendOptions = function movePlusAppendOptions(form, action, updateForm, updateActionDataFromForm) {
var optionsContainer = form.append({
type: 'field',
label: 'Options',
style: 'display: flex; flex-direction: row;'
});
optionsContainer.append({
type: 'button',
label: 'Move pages',
name: 'movePages',
disabled: action == 'move' ? true : false,
event: function () {
updateActionDataFromForm();
updateForm('move');
}
});
optionsContainer.append({
type: 'button',
label: 'Retarget page links',
name: 'retargetLinks',
disabled: action == 'retarget' ? true : false,
event: function () {
updateActionDataFromForm();
updateForm('retarget');
}
});
}
movePlus.appendReason = function movePlusAppendReason(form, label, name, value) {
var moveReason = form.append({
type: 'field',
label: label
});
moveReason.append({
type: 'textarea',
name: name,
value: value,
required: true
});
moveReason.append({
type: 'div',
name: name + 'Alert',
style: 'display: block',
label: ''
});
}
movePlus.appendReasonAlert = function appendReasonAlert(label, name) {
const reasonAlert = document.getElementsByName(name + 'Alert')[0];
$(`textarea[name="${name}"]`).on('input', function () {
if (this.value.length > 400) {
reasonAlert.innerHTML = `<span style="color: red;"><b>Warning:</b></span> ${label} contains ${this.value.length} characters. It may be truncated in the edit summary.`;
reasonAlert.style.display = 'block';
} else {
reasonAlert.style.display = 'none';
}
});
}
movePlus.evaluate = function (e, data) {
var form = e.target;
movePlus.params = Morebits.quickForm.getInputData(form);
Morebits.simpleWindow.setButtonsEnabled(false);
Morebits.status.init(form);
// Store both the talk page and the pages being moved from template data
var title_obj = mw.Title.newFromText(Morebits.pageNameNorm);
movePlus.talktitle = title_obj.getTalkPage().toText(); // The talk page we're on
// Store all pages being moved from the template data
movePlus.pagesToMove = [];
if (data.moves && data.moves.length > 0) {
data.moves.forEach(function (move) {
movePlus.pagesToMove.push({
current: move.current,
destination: move.destination
});
});
// Set the primary page (first in list) for backward compatibility
movePlus.title = data.moves[0].current;
} else {
// Fallback if template data is missing
movePlus.title = title_obj.getSubjectPage().toText();
movePlus.pagesToMove = [{
current: movePlus.title,
destination: "?"
}];
}
var result = movePlus.params.result;
if (result == 'custom') {
result = movePlus.params.customResult;
}
var closingComment = movePlus.params.closingComment;
if (closingComment != "") {
closingComment = ' ' + closingComment;
closingComment = closingComment.replace(/\|/g, "{{!}}");
closingComment = closingComment.replace(/=/g, "{{=}}");
}
// Update destinations if custom titles were specified
if (movePlus.params.movedOptionsInputs && movePlus.params.movedOptionsInputs.includes('moved-different-title')) {
movePlus.pagesToMove.forEach(function (pair, index) {
if (movePlus.params[pair.current]) {
movePlus.pagesToMove[index].destination = movePlus.params[pair.current];
}
});
}
var talkpage = new Morebits.wiki.page(movePlus.talktitle, 'Closing move');
if (WATCHLISTPAGES) {
talkpage.setWatchlist('watch');
}
movePlus.closeMove(talkpage, result, closingComment, function ({ parsedDate, rmSection }) {
var link = movePlus.setOldMoves(talkpage, parsedDate, rmSection, result, function (link) {
if (result === "moved") {
let destinations = [];
let currents = [];
for (var m = 0; m < movePlus.pagesToMove.length; m++) {
destinations.push(movePlus.pagesToMove[m].destination);
currents.push(movePlus.pagesToMove[m].current);
}
movePlus.movePages(currents, destinations, link);
} else {
setTimeout(function () {
location.reload();
}, 2000);
}
});
});
};
movePlus.closeMove = function (talkpage, result, closingComment, done) {
talkpage.load(function (talkpage) {
var text = talkpage.getPageText();
var textToFind = text.split("\n");
var templateFound = false;
var templateIndex = -1;
var rmSection = "";
var nextSection = false;
var parsedDate = "";
var line;
// Find start of RM
for (var i = 0; i < textToFind.length; i++) {
line = textToFind[i];
if (templateFound === false) {
if (/{{[Rr]equested move\/dated/.test(line)) {
templateFound = true;
templateIndex = i;
}
} else {
if (/ \(UTC\)/.test(line)) {
line = line.substring(line.indexOf("This is a contested technical request"));
parsedDate = line.match(/, ([0-9]{1,2} (January|February|March|April|May|June|July|August|September|October|November|December) [0-9]{4}) \(UTC\)/)[1];
break;
}
}
}
// Find RM section
for (var j = templateIndex; j >= 0; j--) {
line = textToFind[j];
if (line.match(/^(==)[^=].+\1/)) {
rmSection = line.match(/^(==)[^=](.+)\1/)[2].trim();
break;
}
}
// Find end of RM
for (var k = templateIndex + 1; k < textToFind.length; k++) {
line = textToFind[k];
if (line.match(/^(==)[^=].+\1/)) {
nextSection = true;
var escapedLine = line.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
var regex = new RegExp("(" + escapedLine + ")(?![\\s\\S]*(" + escapedLine + "))", "m");
text = text.replace(regex, "{{subst:RM bottom}}\n\n" + line);
break;
}
}
var userGroupText = "";
if (Morebits.userIsInGroup("sysop")) {
userGroupText = "";
} else if (Morebits.userIsInGroup("extendedmover")) {
userGroupText = "|pmc=y";
} else {
userGroupText = "|nac=y";
}
text = text.replace(
/{{[Rr]equested move\/dated\|.*\n?[^\[{]*}}/,
"{{subst:RM top|'''" + result + ".'''" + closingComment + userGroupText + "}}"
);
if (!nextSection) {
text += "\n{{subst:RM bottom}}";
}
talkpage.setPageText(text);
talkpage.setEditSummary("Closing requested move; " + result + movePlus.advert);
talkpage.save(function () {
setTimeout(function () {
done({ parsedDate: parsedDate, rmSection: rmSection });
}, 1000);
});
});
};
movePlus.setOldMoves = function (talkpage, date, rmSection, result, done) {
talkpage.load(function (talkpage) {
const link = "Special:Permalink/" + talkpage.getCurrentID() + "#" + rmSection;
let m = 0;
function processNextPage() {
if (m >= movePlus.pagesToMove.length) {
done(link);
return;
}
const pageToMove = movePlus.pagesToMove[m];
const otherTalkPageTitle = mw.Title.newFromText(pageToMove.current).getTalkPage().toText();
const otherTalkPage = new Morebits.wiki.page(
otherTalkPageTitle,
"Adding {{old move}} to " + otherTalkPageTitle + "."
);
otherTalkPage.load(function (otherTalkPage) {
const otherText = createOldMoveText(
otherTalkPage,
date,
pageToMove.current,
pageToMove.destination,
result,
link
);
otherTalkPage.setPageText(otherText);
otherTalkPage.setEditSummary("Closing requested move; " + result + movePlus.advert);
otherTalkPage.save(function () {
m++;
setTimeout(processNextPage, 500);
});
});
}
processNextPage();
});
};
function createOldMoveText(page, date, from, destination, result, link) {
const pageText = page.getPageText();
const templatesOnPage = extraJs.parseTemplates(pageText, false);
const otherOldMovesPresent = templatesOnPage.filter((template) => {
const name = template.name.toLowerCase();
return name === "old moves" || name === "old move";
});
const keys = ["date", "from", "destination", "result", "link"];
const oldMoves = [];
const getOldMoveParam = (params, key, index) => {
if (index === 1) {
return params[key] ??
params[`${key}1`] ??
"";
}
return params[`${key}${index}`] ?? "";
};
for (const oldMove of otherOldMovesPresent) {
const params = Object.fromEntries(
(oldMove.parameters ?? []).map((param) => [param.name, param.value])
);
for (let index = 1; ; index++) {
const move = Object.fromEntries(
keys.map((key) => [key, getOldMoveParam(params, key, index)])
);
const hasAnyValue = Object.values(move).some((value) => value !== "");
if (!hasAnyValue) {
break;
}
oldMoves.push(move);
}
}
oldMoves.push({ date, from, destination, result, link });
const useUnnumberedParams = oldMoves.length === 1;
const movesText = `{{old moves ${oldMoves
.flatMap((move, index) => {
const suffix = useUnnumberedParams ? "" : index + 1;
return keys.map((key) => `| ${key}${suffix} = ${move[key] ?? ""} `);
})
.join("")}}}\n`;
const oldMovesPattern = /\{\{Old\s+(?:moves|move)(?:(?!}})[\s\S])*\}\}/i;
const oldMovesPatternGlobal = /\{\{Old\s+(?:moves|move)(?:(?!}})[\s\S])*\}\}/gi;
let updatedPageText;
if (oldMovesPattern.test(pageText)) {
let replacedFirst = false;
updatedPageText = pageText.replace(oldMovesPatternGlobal, () => {
if (!replacedFirst) {
replacedFirst = true;
return movesText;
}
return "";
});
} else {
const insertionMatch =
pageText.match(/\{\{[Aa]rchives/) ||
pageText.match(/\{\{[Aa]rchive box/) ||
pageText.match(/\{\{[Aa]rchivebox/) ||
pageText.match(/^==.*==/m);
if (insertionMatch) {
updatedPageText = pageText.replace(
insertionMatch[0],
`${movesText}${insertionMatch[0]}`
);
} else {
updatedPageText = `${movesText}${pageText}`;
}
}
return updatedPageText;
}
getTalkPageTitles = function getTalkPageTitles(curr, dest) {
var currTitleObj = new mw.Title(curr);
var destTitleObj = new mw.Title(dest);
var currTalkPage = currTitleObj.getTalkPage().getPrefixedText();
var destTalkPage = destTitleObj.getTalkPage().getPrefixedText();
return {
currTalk: currTalkPage,
destTalk: destTalkPage
};
}
getPageByTitle = function getPageByTitle(data, title) {
return data.find(page => page.title === title);
}
movePlus.checkPage = async function movePlusCheckPage(curr, dest) {
let talkPages = getTalkPageTitles(curr, dest);
let query = {
action: 'query',
prop: 'info|revisions',
inprop: 'protection',
titles: `${curr}|${talkPages.currTalk}|${dest}|${talkPages.destTalk}`,
format: 'json',
rvprop: 'ids'
};
let redirectsQuery = {
...query,
redirects: 1
}
let protection = {
curr: {
article: {}
},
dest: {
article: {}
},
createLabel: function (type) {
let protections = [];
let data = this[type];
let label = '';
if (data.move) protections.push("move");
if (data.create) protections.push("create");
if (protections.length > 0) {
const formattedProtection = protections.join(" and ");
label = ` (${formattedProtection} protected)`;
}
//As only sysop's can overwrite pages with history we only warn sysops
if (data.history && Morebits.userIsInGroup('sysop')) {
label = label + ' <span style="color: red;">(<b>Warning:</b> Page has history)</span>';
}
return label;
},
checkProtection: function () {
return this.curr.all || this.dest.all
},
checkSysopProtection: function () {
return this.curr.admin || this.dest.admin
},
checkHistory: function () {
return this.dest.history
},
checkRedirect: function () {
return this.dest.redirect
},
checkTarget: function () {
return this.curr.target
},
checkClosed: function () {
return (this.curr.article.redirect && this.dest.article.target) || (this.dest.article.redirect && this.curr.article.target)
},
checkAlreadyMoved: function () {
return this.alreadyMoved === true;
}
}
function getRedirectByTitle(data, title) {
if (data) {
let redirect = data.find(redirect => redirect.from === title);
return redirect ? redirect : [];
}
return [];
}
try {
const pageResponse = await new Morebits.wiki.api(`Accessing information on about edit restrictions on ${dest} and ${curr}`, query).post();
const currData = getPageByTitle(pageResponse.response.query.pages, curr)
const currTalkData = getPageByTitle(pageResponse.response.query.pages, talkPages.currTalk)
const destData = getPageByTitle(pageResponse.response.query.pages, dest)
const destTalkData = getPageByTitle(pageResponse.response.query.pages, talkPages.destTalk)
function checkProtection(data, admin = false) {
return data.protection.some(protection => {
if (admin) {
return protection.level == "sysop";
} else {
return !(Morebits.userIsInGroup(protection.level) || Morebits.userIsSysop);
}
});
}
function checkHistory(data) {
if (data.revisions) {
return data.revisions[0].parentid === 0;
}
return true;
}
function checkMissing(data) {
return data.missing
}
function processHistory(data, talkData) {
protection.dest.history = !checkHistory(data) || !checkHistory(talkData);
}
async function processRedirects() {
const redirectResponse = await new Morebits.wiki.api(`Accessing information about redirect status of ${curr} and ${dest}`, redirectsQuery).post();
processRedirect(redirectResponse, dest, curr, protection.dest, protection.curr);
processRedirect(redirectResponse, talkPages.destTalk, talkPages.currTalk, protection.dest, protection.curr);
processRedirect(redirectResponse, curr, dest, protection.curr.article, protection.dest.article);
processRedirect(redirectResponse, dest, curr, protection.dest.article, protection.curr.article);
}
function processRedirect(redirectData, origin, target, originStatus, targetStatus) {
let data = getRedirectByTitle(redirectData.response.query.redirects, origin)
originStatus.redirect = originStatus.redirect !== undefined ? originStatus.redirect : true;
targetStatus.target = targetStatus.target !== undefined ? targetStatus.target : true;
if (data.length == 0) {
if (!checkMissing(getPageByTitle(redirectData.response.query.pages, origin))) {
originStatus.history = true;
originStatus.redirect = false;
targetStatus.target = false;
}
return;
}
if (data.to != target) {
targetStatus.target = false;
}
}
protection.curr.all = checkProtection(currData) || checkProtection(currTalkData);
protection.curr.admin = checkProtection(currData, true) || checkProtection(currTalkData, true);
protection.dest.all = checkProtection(destData) || checkProtection(destTalkData);
protection.dest.admin = checkProtection(destData, true) || checkProtection(destTalkData, true);
protection.dest.history = !checkHistory(destData) || !checkHistory(destTalkData);
// Normalise both titles via mw.Title and compare
try {
var currNorm = new mw.Title(curr).getPrefixedText();
var destNorm = new mw.Title(dest).getPrefixedText();
protection.alreadyMoved = (currNorm === destNorm);
} catch (e) {
protection.alreadyMoved = false;
}
await processRedirects();
return protection;
} catch (error) {
console.error('Failed to fetch page details:', error);
throw error;
}
};
movePlus.movePages = function movePlusMovePages(currList, destList, link, closer = true) {
movePlus.numberToRemove = currList.length;
movePlus.talktitle = mw.Title.newFromText(Morebits.pageNameNorm).getTalkPage().toText();
var pageAndSection = link;
var moveSummary, rmtrReason;
var promises = [];
var configurations = [];
function sanitizeClassName(name) {
return name.replace(/[^a-zA-Z0-9\-_]/g, '-');
}
if (closer) {
if (movePlus.params.movedOptionsInputs.includes('moved-uncontested')) {
moveSummary = 'Moved, as an [[WP:RMTR|uncontested technical request]], per [[' + pageAndSection + ']]';
rmtrReason = 'Per lack of objection at [[' + pageAndSection + ']].';
} else {
moveSummary = 'Moved per [[' + pageAndSection + ']]';
rmtrReason = 'Per consensus at [[' + pageAndSection + ']].';
}
} else {
moveSummary = link;
rmtrReason = link;
}
var form = new Morebits.quickForm();
var movesContainer = form.append({
type: 'field',
label: 'Moves'
});
function addButtons(curr, dest, config) {
const moveContainer = movesContainer.append({
type: 'div',
className: 'movePlusMovePagesRow' + sanitizeClassName(curr),
style: 'display: flex; flex-direction: column; margin-bottom: 7px',
label: ''
});
const rowContainer = moveContainer.append({
type: 'div',
className: 'movePlusMovePagesSubRow' + sanitizeClassName(curr),
style: 'display: flex; flex-direction: row;',
label: ''
});
const actionContainer = rowContainer.append({
type: 'div',
style: 'display: flex; flex-direction: column; flex: 75%; text-align: left;',
className: 'moves'
});
const optionsContainer = rowContainer.append({
type: 'div',
style: 'display: flex; flex: 25%; text-align: left;',
className: 'moveOptions' + sanitizeClassName(curr)
});
actionContainer.append({
type: 'div',
className: 'movePlusMovePagesLabel',
label: config.label
});
actionContainer.append({
type: 'div',
className: 'movePlusProgressBox',
name: sanitizeClassName(curr),
label: '',
style: 'margin-left: 15px'
});
const buttonsContainer = actionContainer.append({
type: 'div',
style: 'display: flex; flex-direction: row; margin-left: 15px'
});
const linksContainer = moveContainer.append({
type: 'field',
label: 'Specify new link targets',
style: 'display: none',
className: 'specifyLinks' + sanitizeClassName(curr),
name: 'specifyLinks',
id: 'specifyLinks'
});
addRedirectSpecification(linksContainer, curr, dest);
addRedirectSpecification(linksContainer, dest, curr);
linksContainer.append({
type: 'div',
label: movePlus.linkAdjustWarning
});
var isSysop = Morebits.userIsInGroup('sysop');
var isMover = Morebits.userIsInGroup('extendedmover');
// NEW: If the page is already at the proposed destination, show an
// informational message and skip all move buttons entirely.
if (config.isAlreadyMoved) {
actionContainer.append({
type: 'div',
className: 'movePlusProgressBox',
name: sanitizeClassName(curr),
label: 'Already at target location — no move needed.',
style: 'margin-left: 15px; color: green;'
});
// Decrement counter immediately so the close-window interval
// doesn't stall waiting for a move that will never happen.
movePlus.numberToRemove--;
return;
}
if (!config.isProtected) {
if (config.hasHistory) {
if (isMover || isSysop) {
addCheckboxes(optionsContainer, curr, isSysop, true, true, !config.isClosed);
if (isSysop) {
addButton(buttonsContainer, curr, dest, "moveOverPage", true);
}
addButton(buttonsContainer, curr, dest, 'roundRobin');
} else {
addButton(buttonsContainer, curr, dest, 'technicalRequest', config.isSysopProtected);
}
} else if (config.isRedirect && !config.isTarget) {
if (isSysop || isMover) {
addCheckboxes(optionsContainer, curr, true, true, true, false);
addButton(buttonsContainer, curr, dest, "moveOverPage")
} else {
addButton(buttonsContainer, curr, dest, 'technicalRequest', config.isSysopProtected);
}
} else {
addButton(buttonsContainer, curr, dest, "move");
if (isSysop || isMover) {
addCheckboxes(optionsContainer, curr, true, true, true, false);
} else {
addCheckboxes(optionsContainer, curr, false, false, true, false);
}
}
} else {
addButton(buttonsContainer, curr, dest, 'technicalRequest', config.isSysopProtected);
}
}
function addRedirectSpecification(container, origin, target) {
const titleField = container.append({
type: 'div',
className: 'titleInput',
style: 'display: flex; align-items: center; margin-bottom: 5px;'
});
const currentDiv = titleField.append({
type: 'div',
style: 'flex: 0 1 47.5%; text-align: left;'
});
currentDiv.append({
type: 'div',
label: origin,
style: 'width: 95%; text-align: left;'
});
titleField.append({
type: 'div',
style: 'flex: 0 1 5%; text-align: center;',
label: '→'
});
const futDiv = titleField.append({
type: 'div',
style: 'flex: 0 1 47.5%; text-align: left;'
});
futDiv.append({
type: 'input',
id: 'specifyLinks' + sanitizeClassName(origin),
value: target,
placeholder: 'Future page',
style: 'width: 95%; text-align: left;'
});
}
function addCheckboxes(container, label, suppressRedirect, moveSubpages, moveTalkPage, correctLinks) {
let options = [];
if (correctLinks) {
options.push({
name: 'correctLinks' + sanitizeClassName(label),
label: "Correct links",
checked: false,
event: function () {
if (event.target.checked) {
document.querySelector('.specifyLinks' + sanitizeClassName(label)).style.display = 'block';
} else {
document.querySelector('.specifyLinks' + sanitizeClassName(label)).style.display = 'none';
}
}
});
}
if (suppressRedirect) {
options.push({
name: 'suppressRedirect' + sanitizeClassName(label),
label: "Suppress redirect",
checked: false
});
};
if (moveSubpages) {
options.push({
name: 'moveSubpages' + sanitizeClassName(label),
label: 'Move subpages',
checked: true
});
};
if (moveTalkPage) {
options.push({
name: 'moveTalkPage' + sanitizeClassName(label),
label: 'Move talk page',
checked: true
});
};
container.append({
type: 'checkbox',
style: 'display: flex; flex-direction: column; align-items: left; margin-right: 10px;',
list: options
});
}
function addButton(container, curr, dest, type, admin = false) {
let config;
let operation;
let label;
let id;
let tooltip = "";
let disabled = false;
switch (type) {
case "move":
operation = async function (progressBox) {
config = checkCheckboxes();
await movePlus.movePage(this.name, this.extra, moveSummary, progressBox, config);
};
label = 'Move directly';
id = 'moveDirectly';
break;
case "moveOverPage":
operation = async function (progressBox) {
config = checkCheckboxes();
await movePlus.moveOverPage(this.name, this.extra, config.suppressRedirect, moveSummary, admin, progressBox, config.moveSubpages, config.moveTalkPage);
};
label = 'Move directly (o)';
id = 'moveOverPage';
break;
case "roundRobin":
operation = async function (progressBox) {
config = checkCheckboxes();
await movePlus.moveRoundRobin(this.name, this.extra, moveSummary, progressBox, config);
};
label = 'Move via Round Robin';
id = 'roundRobin';
break;
case "technicalRequest":
operation = async function (progressBox) {
config = checkCheckboxes();
await movePlus.submitRMTR(this.name, this.extra, admin, rmtrReason, progressBox);
};
label = 'Submit technical request';
id = 'rmtr';
break;
}
container.append({
type: 'button',
className: 'movePlusMovePages' + sanitizeClassName(curr),
name: curr,
extra: dest,
label: label,
tooltip: tooltip,
disabled: disabled,
id: id,
event: async function () {
const rowElements = document.querySelectorAll('.movePlusMovePages' + sanitizeClassName(curr));
rowElements.forEach(element => {
element.style.display = 'none';
});
const progressBox = document.querySelector('.movePlusProgressBox[name="' + sanitizeClassName(curr) + '"]');
if (progressBox) {
progressBox.textContent = 'In progress...';
try {
await operation.call(this, progressBox);
progressBox.textContent = 'Completed!';
setTimeout(() => {
document.querySelector('.movePlusMovePagesRow' + sanitizeClassName(curr)).style.display = 'none';
movePlus.numberToRemove--;
}, 1000);
} catch (error) {
progressBox.textContent = 'Failed. Please implement manually and report this error to the script maintainer. ' + error;
}
}
}
});
function checkCheckboxes() {
const suppressRedirectElem = document.querySelector('input[name="suppressRedirect' + sanitizeClassName(curr) + '"]');
const moveSubpagesElem = document.querySelector('input[name="moveSubpages' + sanitizeClassName(curr) + '"]');
const moveTalkPageElem = document.querySelector('input[name="moveTalkPage' + sanitizeClassName(curr) + '"]');
const correctLinksElem = document.querySelector('input[name="correctLinks' + sanitizeClassName(curr) + '"]');
let suppressRedirect = suppressRedirectElem ? suppressRedirectElem.checked : false;
let moveSubpages = moveSubpagesElem ? moveSubpagesElem.checked : true;
let moveTalkPage = moveTalkPageElem ? moveTalkPageElem.checked : true;
let correctLinks = correctLinksElem ? correctLinksElem.checked : false;
let currTarget, destTarget;
if (correctLinks) {
currTarget = document.querySelector('#specifyLinks' + sanitizeClassName(curr)).value;
destTarget = document.querySelector('#specifyLinks' + sanitizeClassName(dest)).value;
}
document.querySelector('.specifyLinks' + sanitizeClassName(curr)).style.display = 'none';
document.querySelector('.moveOptions' + sanitizeClassName(curr)).style.display = 'none';
return {
suppressRedirect: suppressRedirect,
moveSubpages: moveSubpages,
moveTalkPage: moveTalkPage,
correctLinks: correctLinks,
currTarget: currTarget,
destTarget: destTarget
}
}
}
function actions(fromList, toList) {
if (fromList.length !== toList.length) {
throw new Error("Mismatched moves");
}
const moves = [];
const sources = [];
const destinations = [];
for (let i = 0; i < fromList.length; i++) {
moves.push({ from: fromList[i], to: toList[i] });
}
for (const move of moves) {
if (destinations.includes(move.to)) {
throw new Error("Trying to move two articles to the same place");
}
if (sources.includes(move.from)) {
throw new Error("Trying to move the same article twice");
}
destinations.push(move.to);
sources.push(move.from);
}
const firstMoves = [];
const secondMoves = [];
const redirects = [];
for (const move of moves) {
if (destinations.includes(move.from)) {
firstMoves.push({ type: "move", ...move });
} else {
secondMoves.push({ type: "move", ...move });
}
if (sources.includes(move.to)) {
redirects.push({ type: "retarget", from: move.from, to: move.to });
}
}
return [...firstMoves, ...secondMoves, ...redirects];
}
for (let i = 0; i < currList.length; i++) {
let promise = movePlus.checkPage(currList[i], destList[i]).then(data => {
configurations[i] = {
label: currList[i] + data.createLabel("curr") + ' → ' + destList[i] + data.createLabel("dest"),
isProtected: data.checkProtection(),
isSysopProtected: data.checkSysopProtection(),
hasHistory: data.checkHistory(),
isRedirect: data.checkRedirect(),
isTarget: data.checkTarget(),
isClosed: data.checkClosed(),
isAlreadyMoved: data.checkAlreadyMoved()
}
});
promises.push(promise)
}
function setupMulti() {
var multiContainer = form.append({
type: 'field',
label: 'Multi-action',
style: 'display: flex; flex-direction: row'
});
multiContainer.append({
type: 'button',
label: 'Move all',
tooltip: 'Moves all pages. If there are multiple options it will move the page via round robin instead of overwriting history at the destination.',
event: async function () {
const rows = document.querySelectorAll('[class^="movePlusMovePagesRow"]');
for (const row of rows) {
const moveDirectlyButton = row.querySelector('div span input#moveDirectly');
const roundRobinButton = row.querySelector('div span input#roundRobin');
const technicalRequestButton = row.querySelector('div span input#rmtr');
if (moveDirectlyButton) {
await moveDirectlyButton.click();
} else if (roundRobinButton) {
await roundRobinButton.click();
} else if (technicalRequestButton) {
await technicalRequestButton.click();
}
}
}
});
multiContainer.append({
type: 'button',
label: 'Shuffle',
tooltip: 'Moves all pages in a smart way if the pages overlap',
event: async function () {
const actions = actions(currList, destList);
for (const action of actions) {
// if (action.type === "move") {
// movePlus.movePage(action.from, action.to, "", progressBox, config)
// }
console.log("I would like to", action)
}
}
});
var multiOptionContainer = multiContainer.append({
type: 'div',
style: "display: flex; flex-direction: row; justify-content: flex-end; width: 85%;"
});
multiOptionContainer.append({
type: 'button',
label: 'Suppress all redirects',
event: function () {
const buttons = document.querySelectorAll('input[name^="suppressRedirect"]');
const button = event.target;
const currentLabel = button.value;
buttons.forEach(button => {
button.checked = currentLabel === 'Suppress all redirects';
});
button.value = currentLabel === 'Suppress all redirects' ? 'Suppress no redirects' : 'Suppress all redirects';
}
});
multiOptionContainer.append({
type: 'button',
label: 'Move no subpages',
event: function () {
const buttons = document.querySelectorAll('input[name^="moveSubpages"]');
const button = event.target;
const currentLabel = button.value;
buttons.forEach(button => {
button.checked = currentLabel === 'Move all subpages';
});
button.value = currentLabel === 'Move all subpages' ? 'Move no subpages' : 'Move all subpages';
}
});
multiOptionContainer.append({
type: 'button',
label: 'Move no talk pages',
event: function () {
const buttons = document.querySelectorAll('input[name^="moveTalkPage"]');
const button = event.target;
const currentLabel = button.value;
buttons.forEach(button => {
button.checked = currentLabel === 'Move all talk pages';
});
button.value = currentLabel === 'Move all talk pages' ? 'Move no talk pages' : 'Move all talk pages';
}
});
}
Promise.all(promises).then(() => {
configurations.forEach((config, index) => {
addButtons(currList[index], destList[index], config);
});
setupMulti();
var formResult = form.render();
movePlus.Window.setContent(formResult);
movePlus.Window.display();
// UPDATED: Track interval for cleanup with safety timeout
var moveInterval = setInterval(function () {
if (movePlus.numberToRemove == 0) {
movePlus.Window.close();
clearInterval(moveInterval);
var index = movePlus.activeIntervals.indexOf(moveInterval);
if (index > -1) {
movePlus.activeIntervals.splice(index, 1);
}
setTimeout(function () { location.reload() }, 750);
}
}, 500);
// Track interval for cleanup
movePlus.activeIntervals.push(moveInterval);
// Add safety timeout (2 minutes)
setTimeout(function () {
if (moveInterval) {
clearInterval(moveInterval);
var index = movePlus.activeIntervals.indexOf(moveInterval);
if (index > -1) {
movePlus.activeIntervals.splice(index, 1);
}
console.warn('Move interval timed out after 2 minutes');
}
}, 120000);
});
};
movePlus.moveOverPage = function movePlusMoveOverPage(curr, dest, suppressRedirect, editSummary, warn, progressBox, subpages = true, talkpage = true) {
let destSplit = movePlus.splitPageName(dest);
if (warn) {
if (!confirm('Warning: You are about to delete a page with history. Do you want to proceed?')) {
progressBox.innerText = 'Move cancelled';
throw new Error('Move cancelled.');
}
}
return new Promise((resolve, reject) => {
const moveTask = async () => {
progressBox.innerText = `Moving ${curr} to ${dest}.`;
const url = 'https://en.wikipedia.org/w/index.php?title=Special:MovePage&action=submit';
const formData = new FormData();
formData.append('wpNewTitleNs', destSplit.namespace);
formData.append('wpNewTitleMain', destSplit.pageName);
formData.append('wpReasonList', 'other');
formData.append('wpReason', editSummary + movePlus.advert);
formData.append('wpWatch', '0');
formData.append('wpLeaveRedirect', suppressRedirect ? '0' : '1');
formData.append('wpMovetalk', talkpage ? '1' : '0');
formData.append('wpMovesubpages', subpages ? '1' : '0');
formData.append('wpDeleteAndMove', '1');
formData.append('wpMove', 'Move page');
formData.append('wpOldTitle', curr);
formData.append('wpEditToken', mw.user.tokens.get('csrfToken'));
const response = await fetch(url, {
method: 'POST',
body: formData,
credentials: 'include'
});
if (response.ok) {
progressBox.innerText = `Moved ${curr} to ${dest}.`;
Morebits.status.actionCompleted('Moved.');
resolve();
} else {
progressBox.innerText = `Failed to move ${curr} to ${dest}.`;
reject('Move request failed');
}
};
movePlus.moveQueue.push(moveTask);
movePlus.startMoveQueue();
});
};
movePlus.movePage = function movePlusMovePage(from, to, editSummary, progressBox, config) {
return new Promise((resolve, reject) => {
const moveTask = () => {
progressBox.innerText = `Moving ${from} to ${to}...`;
let pageToMove = new Morebits.wiki.page(from, `Moving ${from} to ${to}.`);
if (WATCHLISTPAGES) {
pageToMove.setWatchlist('watch');
}
pageToMove.setMoveDestination(to);
pageToMove.setMoveSubpages(config.moveSubpages);
pageToMove.setMoveTalkPage(config.moveTalkPage);
pageToMove.setMoveSuppressRedirect(config.suppressRedirect);
pageToMove.setEditSummary(`${editSummary}${movePlus.advert}`);
console.log(`Moving ${from} to ${to}`);
pageToMove.move(() => {
progressBox.innerText = `Moved ${from} to ${to}.`;
Morebits.status.actionCompleted('Moved.');
resolve();
}, (error) => {
reject(error);
});
};
movePlus.moveQueue.push(moveTask);
movePlus.startMoveQueue();
});
};
movePlus.moveRoundRobin = async function movePlusMoveRoundRobin(curr, dest, editSummary, progressBox, config) {
progressBox.innerText = 'Round robin pending...';
config.suppressRedirect = true;
try {
var destDetails = movePlus.splitPageName(dest);
var intermediateTitle = `Draft:Move/${destDetails.pageName}`;
editSummary = `${editSummary} via a [[WP:ROUNDROBIN|round robin]]`;
progressBox.innerText = `Moving ${dest} to ${intermediateTitle}...`;
await movePlus.movePage(dest, intermediateTitle, editSummary, progressBox, config);
progressBox.innerText = `Moving ${curr} to ${dest}...`;
await movePlus.movePage(curr, dest, editSummary, progressBox, config);
progressBox.innerText = `Moving ${intermediateTitle} to ${curr}...`;
await movePlus.movePage(intermediateTitle, curr, editSummary, progressBox, config);
progressBox.innerText = `Cleaning up round robin for ${curr} and ${dest}...`;
await movePlus.roundRobinCleanup(curr, dest, config);
if (config.moveTalkPage) {
await movePlus.roundRobinCleanup(movePlus.getTalkPageName(curr), movePlus.getTalkPageName(dest), config);
}
if (config.correctLinks) {
movePlus.linkEditSummary = `Post-move cleanup, following [[WP:ROBIN|swap]] of [[${curr}]] and [[${dest}]]: `
progressBox.innerText = `Correcting redirects for ${curr} and ${dest}...`;
movePlus.correctRedirects(curr, dest, config);
progressBox.innerText = `Correcting links for ${curr} and ${dest}...`;
await movePlus.correctLinks(curr, dest, config, progressBox);
}
} catch (error) {
console.error('Error during move operation:', error);
}
};
movePlus.getLinksHere = async function movePlusGetLinksHere(page) {
let query = {
action: 'query',
prop: 'linkshere',
titles: page,
lhlimit: 'max',
format: 'json',
lhnamespace: `${movePlus.splitPageName(page).namespace}|10|14`,
rawcontinue: 1
};
let pages = [];
do {
let response = await new Morebits.wiki.api(`Listing links to ${page}`, query).post();
if (response.response.query.pages[0].linkshere) {
pages = pages.concat(response.response.query.pages[0].linkshere);
}
query.lhcontinue = response.response['query-continue'] ? response.response['query-continue'].linkshere.lhcontinue : 0;
} while (query.lhcontinue)
return pages;
}
movePlus.roundRobinCleanup = async function movePlusRoundRobinCleanup(curr, dest, config) {
async function queryPagesAndRedirects(page) {
let details = movePlus.splitPageName(page);
let query = {
action: 'query',
list: 'allpages',
apfrom: `${details.pageName}/`,
apto: `${details.pageName}0`,
apnamespace: details.namespace,
format: 'json'
};
let allpages = [];
if (config.moveSubpages) {
const response = await new Morebits.wiki.api(`Listing subpages of ${details.pageName}`, query).post();
allpages = response.response.query.allpages || [];
}
let pageTitles = allpages.map(page => page.title).join('|');
if (pageTitles) {
pageTitles += '|';
}
pageTitles += page;
let pageQuery = {
action: "query",
format: "json",
prop: "",
titles: pageTitles
}
const responsePages = await new Morebits.wiki.api(`Getting details of subpages of ${details.pageName}`, pageQuery).post();
const pages = (responsePages.response.query.pages || []).filter(page => !page.missing);
pageQuery.redirects = 1;
const responseRedirects = await new Morebits.wiki.api(`Getting details of subpages of ${details.pageName}`, pageQuery).post();
const redirects = responseRedirects.response.query.redirects || [];
return { redirects, pages };
};
function getPagePairs(pages, pair, self) {
return pages.map(page => {
const subpageName = movePlus.splitSubpageName(page.title, self);
const pagename = subpageName === '' ? pair : `${pair}/${subpageName}`;
return {
pagename: pagename,
target: page.title
};
});
}
function getRedirectPairs(redirects, pair, self) {
return redirects.filter(redirect => redirect.from !== redirect.to).map(redirect => {
const subpageName = movePlus.splitSubpageName(redirect.from, self);
const pagename = subpageName === '' ? pair : `${pair}/${subpageName}`;
return {
pagename: pagename,
target: redirect.to
};
});
}
function findSelfRedirects(redirects, pair, self) {
return redirects.filter(redirect => redirect.from === redirect.to).map(redirect => {
const subpageName = movePlus.splitSubpageName(redirect.from, self);
const target = subpageName === '' ? pair : `${pair}/${subpageName}`;
return {
pagename: redirect.from,
target: target
};
});
}
async function processPages(pairs, existingPages, existingRedirects) {
const existingPageNames = new Set(existingPages.map(page => page.title));
const existingRedirectNames = new Set(existingRedirects.map(redirect => redirect.from));
for (const pair of pairs) {
if (!existingPageNames.has(pair.pagename) && !existingRedirectNames.has(pair.pagename)) {
await movePlus.createRedirect(pair.pagename, pair.target,
`Redirecting to [[${pair.target}]] as part of post-[[WP:ROUNDROBIN|round robin]] cleanup${movePlus.advert}`);
}
};
};
const currResponse = await queryPagesAndRedirects(curr);
const destResponse = await queryPagesAndRedirects(dest);
const currRedirects = currResponse.redirects;
const currPages = currResponse.pages;
const destRedirects = destResponse.redirects;
const destPages = destResponse.pages;
const currPagePairs = getPagePairs(currPages, dest, curr);
const currRedirectPairs = getRedirectPairs(currRedirects, dest, curr);
const currSelfRedirects = findSelfRedirects(currRedirects, dest, curr);
const destPagePairs = getPagePairs(destPages, curr, dest);
const destRedirectPairs = getRedirectPairs(destRedirects, curr, dest);
const destSelfRedirects = findSelfRedirects(destRedirects, curr, dest);
await processPages(currPagePairs, destPages, destRedirects);
await processPages(currRedirectPairs, destPages, destRedirects);
await processPages(destPagePairs, currPages, currRedirects);
await processPages(destRedirectPairs, currPages, currRedirects);
for (const pair of currSelfRedirects.concat(destSelfRedirects)) {
await movePlus.createRedirect(pair.pagename, pair.target, `Redirecting to [[${pair.target}]] as part of post-[[WP:ROUNDROBIN|round robin]] cleanup${movePlus.advert}`);
}
};
movePlus.correctRedirects = async function movePlusCorrectRedirects(curr, dest, config) {
if (config.currTarget != dest && config.currTarget != curr) {
await movePlus.createRedirectPair(dest, config.destTarget, `Redirecting to [[${config.destTarget}]] as part of post-[[WP:ROUNDROBIN|round robin]] cleanup${movePlus.advert}`, config);
}
if (config.destTarget != curr && config.destTarget != dest) {
await movePlus.createRedirect(curr, config.currTarget, `Redirecting to [[${config.currTarget}]] as part of post-[[WP:ROUNDROBIN|round robin]] cleanup${movePlus.advert}`);
}
}
movePlus.correctLinks = async function movePlusCorrectLinks(curr, dest, config, progressBox) {
let currPages = [];
let destPages = [];
progressBox.innerText = `Getting links to ${curr}...`;
if (curr != config.currTarget) {
currPages = await movePlus.getLinksHere(curr);
}
progressBox.innerText = `Getting links to ${dest}...`;
if (dest != "" && dest != config.destTarget) {
destPages = await movePlus.getLinksHere(dest);
}
const pageIdsCurr = new Set(currPages.map(item => item.pageid));
const pageIdsDest = new Set(destPages.map(item => item.pageid));
await processBatches(curr, config.currTarget, currPages, pageIdsDest, progressBox, true, dest, config.destTarget);
await processBatches(dest, config.destTarget, destPages, pageIdsCurr, progressBox, false);
async function processBatches(origin, target, pages, otherPages, progressBox, processDuplicates, otherOrigin = "", otherTarget = "") {
if (origin == target) {
return;
}
let query = {
action: "query",
format: "json",
prop: "categories",
titles: "",
clcategories: "Category:All_disambiguation_pages|Category:All_set_index_articles"
}
for (let i = 0; i < pages.length; i += 50) {
const batch = pages.slice(i, i + 50);
query.titles = batch.map(item => item.title).join('|');
const response = await new Morebits.wiki.api(`Listing categories of pages linking to ${origin}`, query).post();
const dabPages = new Set();
response.response.query.pages.forEach(page => {
if (page.categories && page.categories.length > 0) {
dabPages.add(page.pageid);
}
});
let j = i
for (const item of batch) {
j++;
//Skip archives
if (item.ns != 0 && item.title.toLowerCase().includes('/archive')) {
continue;
}
progressBox.innerHTML = `${origin} → ${target} (${j}/${pages.length}):<br>Updating <a href="https://en.wikipedia.org/wiki/${item.title}" target="_blank" rel="noopener noreferrer">${item.title}</a>...`;
if (otherPages.has(item.pageid)) {
if (processDuplicates) {
await movePlus.correctLink(item, origin, target, dabPages.has(item.pageid), otherOrigin, otherTarget);
}
} else {
await movePlus.correctLink(item, origin, target, dabPages.has(item.pageid));
}
}
}
}
}
movePlus.correctLink = function movePlusCorrectLink(item, from, to, dab, otherFrom = "", otherTo = "") {
return new Promise((resolve, reject) => {
console.log(`Updating links at ${item.title}`);
let page = new Morebits.wiki.page(item.title, `Updating links at ${item.title}`);
if (WATCHLISTPAGES) {
page.setWatchlist('watch');
}
page.load(function (linkCorrection) {
let originalText = page.getPageText();
if (!allowBots(originalText, mw.config.get('wgUserName'))) {
console.log(`Forbidden from making edits at ${item.title}`)
resolve();
return;
}
if (otherFrom != "" && otherTo != "") {
var updatedText = updateTextRoundRobin(originalText, item, from, to, otherFrom, otherTo, dab);
} else {
var updatedText = updateText(originalText, item, from, to, dab);
}
if (updatedText.matches == 0) {
console.log(`No edits to make at ${item.title}`);
resolve();
return;
}
let text = updatedText.text;
let editSummary = updatedText.editSummary;
const editTask = () => {
page.setPageText(text);
page.setEditSummary(editSummary);
page.setMinorEdit(true);
page.setBotEdit(true);
console.log(`Successfully updated ${item.title}`);
page.save(() => {
Morebits.status.actionCompleted(`Replaced link to ${from} with link to ${to} at ${item.title}.`);
resolve();
}, (error) => {
reject(error);
});
};
movePlus.editQueue.push(editTask);
movePlus.startEditQueue();
});
});
function updateText(text, item, from, to, dab) {
let updatedText = processText(text, item, from, to, dab);
let editSummary = `${movePlus.linkEditSummary}Changed link from [[${from}]] to [[${to}]]${updatedText.matches > 1 ? ` (×${updatedText.matches})` : ""}${movePlus.advert}`;
return { text: updatedText.text, editSummary: editSummary, matches: updatedText.matches };
}
function updateTextRoundRobin(text, item, from, to, otherFrom, otherTo, dab) {
let stageOneText = processText(text, item, from, "INTERMEDIARYSTAGE", dab);
let stageTwoText = processText(stageOneText.text, item, otherFrom, otherTo, dab);
let updatedText = processText(stageTwoText.text, item, "INTERMEDIARYSTAGE", to, dab);
let editSummary = `${movePlus.linkEditSummary}Changed link from [[${from}]] to [[${to}]] ${stageOneText.matches > 1 ? `(×${stageOneText.matches}) ` : ""}and from [[${otherFrom}]] to [[${otherTo}]]${stageTwoText.matches > 1 ? ` (×${stageTwoText.matches})` : ""}${movePlus.advert}`;
return { text: updatedText.text, editSummary: editSummary, matches: stageOneText.matches + stageTwoText.matches };
}
function processText(text, item, from, to, dab) {
function escapeRegExp(string) {
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
const linkRegex = new RegExp(`\\[\\[${escapeRegExp(from)}(\\|.+|#.*)?\\]\\]`, 'g');
const matches = text.match(linkRegex);
if (!matches) {
return { text: text, matches: 0 }
}
let updatedText = text.replace(linkRegex, match => {
const hashedMatch = match.includes('#');
const pipedMatch = match.includes('|');
if (hashedMatch) {
return match.replace(from, to);
}
if (item.redirect || (dab && !pipedMatch)) {
return `[[${to}]]`;
}
if (pipedMatch) {
var link = match.replace(from, to);
link = link.replace(`${to}|${to}`, to);
return link
}
return `[[${to}|${from}]]`;
});
return { text: updatedText, matches: matches.length };
}
};
movePlus.createRedirectPair = async function movePlusCreateRedirectPair(page, target, editSummary, config) {
await movePlus.createRedirect(page, target, editSummary);
if (config.moveTalkPage) {
let currTalk = movePlus.getTalkPageName(page);
let targetTalk = movePlus.getTalkPageName(target);
await movePlus.createRedirect(currTalk, targetTalk, editSummary);
}
}
movePlus.createRedirect = async function movePlusCreateRedirect(page, target, editSummary) {
return new Promise((resolve, reject) => {
const editTask = () => {
let redirect = new Morebits.wiki.page(page, `Creating redirect to ${target}`);
if (WATCHLISTPAGES) {
redirect.setWatchlist('watch');
}
redirect.load(function (redirect) {
redirect.setPageText(`#REDIRECT [[${target}]]\n{{Rcat shell|\n{{R from move}}\n}}`);
redirect.setEditSummary(editSummary);
console.log(`Attempting to redirect ${page} to ${target}`);
redirect.save(() => {
Morebits.status.actionCompleted(`Cleaned up ${page}.`);
resolve();
}, (error) => {
reject(error);
});
});
};
movePlus.editQueue.push(editTask);
movePlus.startEditQueue();
});
};
movePlus.splitPageName = function movePlusSplitPageName(page) {
// Use MediaWiki's Title object for reliable parsing
const title = mw.Title.newFromText(page);
if (!title) {
// Fallback to original method if Title parsing fails
const namespaceSeparator = ':';
const namespaceMap = {
'': 0, 'Talk': 1, 'User': 2, 'User talk': 3, 'Wikipedia': 4, 'Wikipedia talk': 5,
'File': 6, 'File talk': 7, 'MediaWiki': 8, 'MediaWiki talk': 9, 'Template': 10,
'Template talk': 11, 'Help': 12, 'Help talk': 13, 'Category': 14, 'Category talk': 15,
'Portal': 100, 'Draft': 118, 'Draft talk': 119, 'TimedText': 710, 'TimedText talk': 711,
'Module': 828, 'Module talk': 829
};
const separatorIndex = page.indexOf(namespaceSeparator);
if (separatorIndex === -1) {
return { namespace: 0, pageName: page };
}
const potentialNamespace = page.substring(0, separatorIndex).trim();
const pageName = page.substring(separatorIndex + 1).trim();
const namespaceNumber = namespaceMap.hasOwnProperty(potentialNamespace) ?
namespaceMap[potentialNamespace] : 0;
if (namespaceNumber === 0) {
return { namespace: 0, pageName: page };
}
return { namespace: namespaceNumber, pageName: pageName };
}
return {
namespace: title.namespace,
pageName: title.getName()
};
};
movePlus.getTalkPageName = function movePlusGetTalkPageName(page) {
// Use MediaWiki's Title object for more reliable namespace handling
const title = mw.Title.newFromText(page);
if (!title) {
return null;
}
const talkTitle = title.getTalkPage();
if (!talkTitle) {
return null;
}
return talkTitle.getPrefixedText();
};
movePlus.splitSubpageName = function movePlusSplitSubpageName(page, self) {
let selfIndex = page.indexOf(self);
if (selfIndex === -1 || selfIndex === page.length - self.length) {
return "";
}
return page.substring(selfIndex + self.length + 1);
}
movePlus.submitRMTR = function movePlusSubmitRMTR(curr, dest, adminRequired, reason, progressBox) {
progressBox.innerText = `Submitting technical request for ${curr} to ${dest}...`;
var rmtr = new Morebits.wiki.page('Wikipedia:Requested moves/Technical requests', 'Submitting request at WP:RM/TR');
rmtr.load(function (page) {
if (adminRequired) {
rmtr.setAppendText('{{subst:RMassist|1=' + curr + '|2=' + dest + '|reason=' + reason + '}}');
} else {
var text = rmtr.getPageText();
var textToFind = /\n{1,}(==== ?Requests to revert undiscussed moves ?====)/i;
var rmtrText = '{{subst:RMassist|1=' + curr + '|2=' + dest + '|reason=' + reason + '}}';
text = text.replace(textToFind, '\n' + rmtrText + '\n\n$1');
rmtr.setPageText(text);
}
rmtr.setEditSummary('Add request' + movePlus.advert);
rmtr.save(() => {
progressBox.innerText = 'Technical request submitted';
Morebits.status.actionCompleted('Requested.')
});
});
};
movePlus.relist = function movePlusRelist(e) {
if (e) e.preventDefault();
var title_obj = mw.Title.newFromText(Morebits.pageNameNorm);
movePlus.talktitle = title_obj.getTalkPage().toText();
var talkpage = new Morebits.wiki.page(movePlus.talktitle, 'Relisting.');
var relistingComment = document.getElementById('movePlusRelistComment').value;
talkpage.load(function (talkpage) {
var text = talkpage.getPageText();
var templateFound = false;
var sig;
var line;
var templateIndex = -1;
var textToFind = text.split('\n');
for (var i = 0; i < textToFind.length; i++) {
line = textToFind[i];
if (templateFound == false) {
if (/{{[Rr]equested move\/dated/.test(line)) {
templateFound = true;
templateIndex = i;
}
} else if (templateFound == true) {
if (/ \(UTC\)/.test(line)) {
sig = line;
break;
}
}
}
text = text.replace(sig, sig + " {{subst:RM relist}}");
if (relistingComment != '') {
var nextSection = false;
for (var i = templateIndex + 1; i < textToFind.length; i++) {
line = textToFind[i];
if (line.match(/^(==)[^=].+\1/)) {
nextSection = true;
var escapedLine = line.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&')
var regex = new RegExp('(' + escapedLine + ')(?![\s\S]*(' + escapedLine + '))', 'm');
text = text.replace(regex, ':<small>\'\'\'Relisting comment\'\'\': ' + relistingComment + ' ~~~~</small>\n\n' + line);
break;
}
}
if (!nextSection) {
text += '\n:<small>\'\'\'Relisting comment\'\'\': ' + relistingComment + ' ~~~~</small>';
}
}
talkpage.setPageText(text);
talkpage.setEditSummary('Relisted requested move' + movePlus.advert);
talkpage.save(Morebits.status.actionCompleted('Relisted.'));
document.getElementById("requestedmovetag").innerHTML = "";
setTimeout(function () { location.reload() }, 2000);
});
};
movePlus.notify = function movePlusNotify(e) {
if (e) e.preventDefault();
var wikiProjectTemplates = document.getElementsByClassName("wpb-project_link");
var wikiProjectNames = [];
var wikiProjects = [];
for (var i = 0; i < wikiProjectTemplates.length; i++) {
var wikiProjectName = wikiProjectTemplates[i].innerHTML;
var wikiProjectTalk = mw.Title.newFromText(wikiProjectTemplates[i].innerHTML).getTalkPage().toText();
if (!wikiProjectNames.includes(wikiProjectName)) {
wikiProjectNames.push(wikiProjectName);
wikiProjects.push(wikiProjectTalk);
}
}
var wikiProjectBannerShellHeaders = document.getElementsByClassName("wpb-header-combined");
for (var i = 0; i < wikiProjectBannerShellHeaders.length; i++) {
var subprojectList = wikiProjectBannerShellHeaders[i];
if (subprojectList.hasChildNodes() && subprojectList.children.length > 2) {
subprojectList = subprojectList.children[2];
if (subprojectList.hasChildNodes() && subprojectList.children.length > 0) {
subprojectList = subprojectList.children;
for (var j = 0; j < subprojectList.length; j++) {
var wikiProjectName = subprojectList[j].title;
if (mw.Title.newFromText(wikiProjectName)) {
var wikiProjectTalk = mw.Title.newFromText(wikiProjectName).getTalkPage().toText();
if (!wikiProjectNames.includes(wikiProjectName)) {
wikiProjectNames.push(wikiProjectName);
wikiProjects.push(wikiProjectTalk);
}
}
}
}
}
}
if (wikiProjects.length == 0) {
mw.notify('No WikiProject banners found on this page');
} else {
var Window = new Morebits.simpleWindow(600, 450);
Window.setTitle("Notify WikiProjects about requested move");
Window.setScriptName('Move+');
Window.addFooterLink('Script documentation', 'User:BilledMammal/Move+');
Window.addFooterLink('Give feedback', 'User talk:BilledMammal/Move+');
var form = new Morebits.quickForm(movePlus.notifyCheck);
form.append({
type: 'div',
label: 'WikiProjects with banners on this page:'
});
form.append({
type: 'checkbox',
name: 'wikiProject',
list: wikiProjects.map(function (wp) {
var wplabel = wikiProjectNames[wikiProjects.indexOf(wp)];
return { type: 'option', label: wplabel, value: wp };
})
});
if (wikiProjects[0] != 'none') {
form.append({ type: 'submit', label: 'Notify selected WikiProject(s)' });
}
var formResult = form.render();
Window.setContent(formResult);
Window.display();
}
};
movePlus.notifyCheck = function (e) {
var form = e.target;
movePlus.params = Morebits.quickForm.getInputData(form);
Morebits.simpleWindow.setButtonsEnabled(false);
Morebits.status.init(form);
var wikiProjectsToNotify = movePlus.params.wikiProject;
if (wikiProjectsToNotify.length == 0) {
Morebits.status.error('Error', 'No WikiProjects selected');
} else {
var uniqueWikiProjects = [];
var wikiProjectCount = 0;
for (var i = 0; i < wikiProjectsToNotify.length; i++) {
var talkpage = new Morebits.wiki.page(wikiProjectsToNotify[i], 'Checking ' + wikiProjectsToNotify[i] + '.');
talkpage.setFollowRedirect(true);
talkpage.load(function (talkpage) {
var wikiProjectToNotify = talkpage.getPageName();
if (!uniqueWikiProjects.includes(wikiProjectToNotify)) {
uniqueWikiProjects.push(wikiProjectToNotify);
}
wikiProjectCount++;
if (wikiProjectCount == wikiProjectsToNotify.length && uniqueWikiProjects.length > 0) {
movePlus.notifyGetSection(uniqueWikiProjects);
}
});
}
}
};
movePlus.notifyGetSection = function (wikiProjectsToNotify) {
var title_obj = mw.Title.newFromText(Morebits.pageNameNorm);
movePlus.talktitle = title_obj.getTalkPage().toText();
var talkpage = new Morebits.wiki.page(movePlus.talktitle, 'Getting section.');
talkpage.load(function (talkpage) {
var text = talkpage.getPageText();
var line;
var templateIndex = -1;
var rmSection;
var textToFind = text.split('\n');
for (var i = 0; i < textToFind.length; i++) {
line = textToFind[i];
if (/{{[Rr]equested move\/dated/.test(line)) {
templateIndex = i;
break;
}
}
for (var i = templateIndex; i >= 0; i--) {
line = textToFind[i];
if (line.match(/^(==)[^=].+\1/)) {
rmSection = line.match(/^(==)[^=](.+)\1/)[2].trim();
break;
}
}
movePlus.notifyEvaluate(wikiProjectsToNotify, rmSection);
});
};
movePlus.notifyEvaluate = function (wikiProjectsToNotify, moveSection) {
var wikiProjectsNotified = [];
var wikiProjectCount = 0;
for (var j = 0; j < wikiProjectsToNotify.length; j++) {
var talkpage = new Morebits.wiki.page(wikiProjectsToNotify[j], 'Notifying ' + wikiProjectsToNotify[j] + '.');
talkpage.setFollowRedirect(true);
talkpage.load(function (talkpage) {
var wikiProjectToNotify = talkpage.getPageName();
var text = talkpage.getPageText();
movePlus.talktitle = mw.Title.newFromText(Morebits.pageNameNorm).getTalkPage().toText();
var pageAndSection = movePlus.talktitle + "#" + moveSection;
var notified;
if (confirm("\"" + wikiProjectToNotify + "\" may have already been notified of the discussion. Do you wish to proceed?")) {
text += "\n\n== Requested move at [[" + pageAndSection + "]] ==\n[[File:Information.svg|30px|left]] There is a requested move discussion at [[" + pageAndSection + "]] that may be of interest to members of this WikiProject. ~~~~";
talkpage.setPageText(text);
talkpage.setEditSummary('Notifying of [[' + pageAndSection + '\|requested move]]' + movePlus.advert);
talkpage.save(Morebits.status.actionCompleted('Notified.'));
notified = true;
} else {
var cancelNotify = new Morebits.status('Error', 'Notification canceled', 'error');
notified = false;
}
if (notified) {
wikiProjectsNotified.push(wikiProjectToNotify);
}
wikiProjectCount++;
if (wikiProjectCount == wikiProjectsToNotify.length && wikiProjectsNotified.length > 0) {
movePlus.notifyListOnTalkPage(wikiProjectsNotified);
}
});
}
};
movePlus.notifyListOnTalkPage = function (wikiProjectsNotified) {
var discussionPage = new Morebits.wiki.page(movePlus.talktitle, 'Adding note about notification to requested move');
discussionPage.load(function (discussionPage) {
var discussionPageText = discussionPage.getPageText();
var templateFound = false;
var line;
var nextSection = false;
var textToFind = discussionPageText.split('\n');
for (var i = 0; i < textToFind.length; i++) {
line = textToFind[i];
if (templateFound == false) {
if (/{{[Rr]equested move\/dated/.test(line)) {
templateFound = true;
}
} else if (templateFound == true) {
if (line.match(/^(==)[^=].+\1/)) {
nextSection = true;
var escapedLine = line.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&')
var regex = new RegExp('(' + escapedLine + ')(?![\s\S]*(' + escapedLine + '))', 'm');
if (wikiProjectsNotified.length == 1) {
var wikiProjectToNotify = wikiProjectsNotified[0];
var displayName = wikiProjectToNotify.startsWith("Wikipedia talk:") ?
wikiProjectToNotify.substring("Wikipedia talk:".length) :
wikiProjectToNotify;
discussionPageText = discussionPageText.replace(regex, ':<small>Note: [[' + wikiProjectToNotify + '|' + displayName + ']] has been notified of this discussion. ~~~~</small>\n\n' + line);
} else {
var textToInsert = ':<small>Note: ';
for (var j = 0; j < wikiProjectsNotified.length; j++) {
var wikiProjectToNotify = wikiProjectsNotified[j];
var displayName = wikiProjectToNotify.startsWith("Wikipedia talk:") ?
wikiProjectToNotify.substring("Wikipedia talk:".length) :
wikiProjectToNotify;
textToInsert += '[[' + wikiProjectToNotify + '|' + displayName + ']]';
if (j == wikiProjectsNotified.length - 2) {
if (wikiProjectsNotified.length == 2) {
textToInsert += ' and ';
} else {
textToInsert += ', and ';
}
} else if (j != wikiProjectsNotified.length - 1) {
textToInsert += ', ';
}
}
textToInsert += ' have been notified of this discussion. ~~~~</small>\n\n';
discussionPageText = discussionPageText.replace(regex, textToInsert + line);
}
break;
}
}
}
if (!nextSection) {
if (wikiProjectsNotified.length == 1) {
var wikiProjectToNotify = wikiProjectsNotified[0];
var displayName = wikiProjectToNotify.startsWith("Wikipedia talk:") ?
wikiProjectToNotify.substring("Wikipedia talk:".length) :
wikiProjectToNotify;
discussionPageText += '\n:<small>Note: [[' + wikiProjectToNotify + '|' + displayName + ']] has been notified of this discussion. ~~~~</small>';
} else {
discussionPageText += '\n:<small>Note: ';
for (var j = 0; j < wikiProjectsNotified.length; j++) {
var wikiProjectToNotify = wikiProjectsNotified[j];
var displayName = wikiProjectToNotify.startsWith("Wikipedia talk:") ?
wikiProjectToNotify.substring("Wikipedia talk:".length) :
wikiProjectToNotify;
discussionPageText += '[[' + wikiProjectToNotify + '|' + displayName + ']]';
if (j == wikiProjectsNotified.length - 2) {
if (wikiProjectsNotified.length == 2) {
discussionPageText += ' and ';
} else {
discussionPageText += ', and ';
}
} else if (j != wikiProjectsNotified.length - 1) {
discussionPageText += ', ';
}
}
discussionPageText += ' have been notified of this discussion. ~~~~</small>';
}
}
discussionPage.setPageText(discussionPageText);
discussionPage.setEditSummary('Added note about notifying WikiProject about requested move' + movePlus.advert);
discussionPage.save(Morebits.status.actionCompleted('Note added.'));
setTimeout(function () { location.reload() }, 2000);
});
};
//Queues
// Add cleanup function
movePlus.cleanupIntervals = function movePlusCleanupIntervals() {
if (movePlus.moveInterval) {
clearInterval(movePlus.moveInterval);
movePlus.moveInterval = null;
}
if (movePlus.editInterval) {
clearInterval(movePlus.editInterval);
movePlus.editInterval = null;
}
// Clear any tracked intervals
if (movePlus.activeIntervals && movePlus.activeIntervals.length > 0) {
movePlus.activeIntervals.forEach(function (interval) {
if (interval) {
clearInterval(interval);
}
});
movePlus.activeIntervals = [];
}
};
movePlus.processMoveQueue = function movePlusProcessMoveQueue() {
if (movePlus.moveQueue.length > 0) {
let moveTask = movePlus.moveQueue.shift();
moveTask();
} else if (movePlus.moveQueue.length === 0) {
// Clear interval when queue is empty
if (movePlus.moveInterval) {
clearInterval(movePlus.moveInterval);
movePlus.moveInterval = null;
}
}
};
movePlus.startMoveQueue = function movePlusStartMoveQueue() {
if (!movePlus.moveInterval) {
var moveRateLimit = Morebits.userIsInGroup('sysop') ? 39 : Morebits.userIsInGroup('extendedmover') ? 15 : 7;
movePlus.moveInterval = setInterval(movePlus.processMoveQueue, 60000 / moveRateLimit);
}
};
movePlus.processEditQueue = function movePlusProcessEditQueue() {
if (movePlus.editQueue.length > 0) {
let editTask = movePlus.editQueue.shift();
editTask();
} else if (movePlus.editQueue.length === 0) {
// Clear interval when queue is empty
if (movePlus.editInterval) {
clearInterval(movePlus.editInterval);
movePlus.editInterval = null;
}
}
};
movePlus.startEditQueue = function movePlusStartEditQueue() {
if (!movePlus.editInterval) {
var editRateLimit = 20;
movePlus.editInterval = setInterval(movePlus.processEditQueue, 60000 / editRateLimit);
}
};
function allowBots(text, user) {
if (!new RegExp("\\{\\{\\s*(nobots|bots[^}]*)\\s*\\}\\}", "i").test(text)) return true;
return (new RegExp("\\{\\{\\s*bots\\s*\\|\\s*deny\\s*=\\s*([^}]*,\\s*)*" + user.replace(/([\(\)\*\+\?\.\-\:\!\=\/\^\$])/g, "\\$1") + "\\s*(?=[,\\}])[^}]*\\s*\\}\\}", "i").test(text)) ? false : new RegExp("\\{\\{\\s*((?!nobots)|bots(\\s*\\|\\s*allow\\s*=\\s*((?!none)|([^}]*,\\s*)*" + user.replace(/([\(\)\*\+\?\.\-\:\!\=\/\^\$])/g, "\\$1") + "\\s*(?=[,\\}])[^}]*|all))?|bots\\s*\\|\\s*deny\\s*=\\s*(?!all)[^}]*|bots\\s*\\|\\s*optout=(?!all)[^}]*)\\s*\\}\\}", "i").test(text);
}
//</nowiki>
ba2jg6aw91ho7itoe8i68h7c7corskq
743910
743909
2026-05-22T16:26:44Z
GearsDatapacks
72666
Fix out-of-order declarations
743910
javascript
text/javascript
const WATCHLISTPAGES = false;
//movePlus
//<nowiki>
var movePlus = {
numberOfMoves: 0,
multiMove: false,
destinations: [],
parsedDate: undefined,
pages: [],
templateIndex: -1,
moveQueue: [],
editQueue: [],
activeIntervals: [], // NEW: Track all intervals for cleanup
linkAdjustWarning: '\t<span style="color: red;"><b>Warning:</b></span> This will automatically update pages, retargeting all links from the current value to the value you specify. You take full responsibility for any action you perform using this script.'
};
window.movePlus = movePlus;
// Store references for cleanup
movePlus.eventHandlers = {
closeButton: null,
relistButton: null,
confirmButton: null,
cancelButton: null,
notifyButton: null,
portletLink: null
};
movePlus.attachEventHandlers = function () {
if (document.getElementById("requestedmovetag") !== null && Morebits.pageNameNorm.indexOf("alk:") !== -1 && mw.config.get('wgCategories').includes('Requested moves') && !document.getElementById("wikiPreview") && mw.config.get('wgDiffOldId') == null) {
document.getElementById("requestedmovetag").innerHTML = "<button id='movePlusClose'>Close</button><button id='movePlusRelist'>Relist</button><button id='movePlusNotify'>Notify WikiProjects</button><span id='movePlusRelistOptions' style='display:none'><input id='movePlusRelistComment' placeholder='Relisting comment' oninput='if(this.value.length>20){this.size=this.value.length} else{this.size=20}'/><br><button id='movePlusConfirm'>Confirm relist</button><button id='movePlusCancel'>Cancel relist</button></span>";
// Use event delegation or store handlers for cleanup
movePlus.eventHandlers.closeButton = $('#movePlusClose').on('click', movePlus.callback);
movePlus.eventHandlers.relistButton = $('#movePlusRelist').on('click', movePlus.confirmRelist);
movePlus.eventHandlers.confirmButton = $('#movePlusConfirm').on('click', movePlus.relist);
movePlus.eventHandlers.cancelButton = $('#movePlusCancel').on('click', movePlus.cancelRelist);
movePlus.eventHandlers.notifyButton = $('#movePlusNotify').on('click', movePlus.notify);
}
var portletLink = mw.util.addPortletLink("p-cactions", "#movePlusMove", "Move\+",
"ca-movepages", "Move pages (expanded options)");
movePlus.eventHandlers.portletLink = $(portletLink).on('click', movePlus.displayWindowMove);
};
movePlus.removeEventHandlers = function () {
$('#movePlusClose').off('click', movePlus.callback);
$('#movePlusRelist').off('click', movePlus.confirmRelist);
$('#movePlusConfirm').off('click', movePlus.relist);
$('#movePlusCancel').off('click', movePlus.cancelRelist);
$('#movePlusNotify').off('click', movePlus.notify);
if (movePlus.eventHandlers.portletLink) {
movePlus.eventHandlers.portletLink.off('click', movePlus.displayWindowMove);
}
};
$.when(
mw.loader.using(['mediawiki.api', 'ext.gadget.morebits', 'ext.gadget.libExtraUtil']),
$.ready
).then(function () {
movePlus.attachEventHandlers();
});
// Cleanup on page unload
$(window).on('beforeunload', function () {
movePlus.removeEventHandlers();
movePlus.cleanupIntervals();
});
movePlus.confirmRelist = function movePlusConfirmRelist(e) {
if (e) e.preventDefault();
document.getElementById("movePlusRelistOptions").style.display = "inline";
document.getElementById("movePlusClose").style.display = "none";
document.getElementById("movePlusRelist").style.display = "none";
document.getElementById("movePlusNotify").style.display = "none";
};
movePlus.cancelRelist = function movePlusCancelRelist(e) {
if (e) e.preventDefault();
document.getElementById("movePlusRelistOptions").style.display = "none";
document.getElementById("movePlusClose").style.display = "inline";
document.getElementById("movePlusRelist").style.display = "inline";
document.getElementById("movePlusNotify").style.display = "inline";
};
movePlus.advert = ' using [[User:BilledMammal/Move+|Move+]]';
movePlus.preEvaluate = async function () {
try {
const talkPageContent = await loadTalkPage();
return extractTemplateData(talkPageContent);
} catch (error) {
console.error('Error during pre-evaluation:', error);
}
};
async function loadTalkPage() {
var title_obj = mw.Title.newFromText(Morebits.pageNameNorm);
const talkpage = new Morebits.wiki.page(title_obj.getTalkPage().toText(), 'Retrive move proposals.');
return new Promise((resolve, reject) => {
talkpage.load(function (talkpage) {
if (talkpage.exists()) {
resolve(talkpage.getPageText());
} else {
reject('Page does not exist');
}
}, reject);
});
}
function extractTemplateData(text) {
const templatesOnPage = extraJs.parseTemplates(text, false);
let templateData = {};
templatesOnPage.forEach(template => {
if (template.name.toLowerCase() === "requested move/dated") {
templateData = { ...templateData, ...parseRequestedMoveTemplate(template) };
}
});
return templateData;
}
function parseRequestedMoveTemplate(template) {
const data = {
moves: [],
multiMove: template.parameters.some(param => param.name === "multiple")
};
const pairs = {};
template.parameters.forEach(param => {
const match = param.name.toString().match(/^(current|new)?(\d+)$/);
if (match) {
const type = match[1] ? match[1] : "new";
const index = match[2];
if (!pairs[index]) {
pairs[index] = {};
}
if (!pairs[index][type] || param.value != "") {
pairs[index][type] = param.value;
}
}
});
if (!pairs[1]["current"]) {
let title_obj = mw.Title.newFromText(Morebits.pageNameNorm);
pairs[1]["current"] = title_obj.getSubjectPage().toText();
}
Object.keys(pairs).forEach(index => {
const pair = pairs[index];
if (pair.current && pair.new) {
data.moves.push({ current: pair.current, destination: pair.new });
}
});
return data;
}
movePlus.callback = async function movePlusCallback(e) {
e.preventDefault(e);
try {
const evaluationData = await movePlus.preEvaluate();
if (evaluationData) {
movePlus.displayWindowClose(evaluationData);
} else {
throw new Error("Failed to retrieve necessary data for processing.");
}
} catch (error) {
console.error('Error during callback execution:', error);
}
};
movePlus.displayWindowClose = function movePlusDisplayWindowClose(data) {
let checkboxStates = {};
movePlus.Window = new Morebits.simpleWindow(600, 450);
movePlus.Window.setTitle("Close requested move");
movePlus.Window.setScriptName('Move+');
movePlus.Window.addFooterLink('RM Closing instruction', 'WP:RMCI');
movePlus.Window.addFooterLink('Script documentation', 'User:BilledMammal/Move+');
movePlus.Window.addFooterLink('Give feedback', 'User talk:BilledMammal/Move+');
var form = new Morebits.quickForm(function (e) {
movePlus.evaluate(e, data);
});
setupForm();
function setupForm() {
var resultContainer = form.append({
type: 'div',
style: 'display: flex; flex-direction: row; gap: 10px;'
});
var resultField = setupResultOptions(resultContainer);
setupCustomResult(resultField);
var movedOptionsField = setupMoveOptions(resultContainer);
setupCustomTitles();
setupClosingComment(form);
}
function setupResultOptions(container) {
var resultField = container.append({
type: 'field',
label: 'Result',
style: 'flex: 1;'
});
resultField.append({
type: 'radio',
name: 'result',
required: true,
list: [
{
label: 'Moved',
value: 'moved',
event: function () { updateResultOptions('moved'); }
},
{
label: 'Not moved',
value: 'not moved',
event: function () { updateResultOptions('not moved'); }
},
{
label: 'No consensus',
value: 'no consensus',
event: function () { updateResultOptions('no consensus'); }
},
{
label: 'Custom',
value: 'custom',
event: function () { updateResultOptions('custom'); }
}
]
});
return resultField;
}
function updateResultOptions(result) {
const customResultDisplay = document.getElementsByName('customResult')[0];
const movedOptionsDisplay = document.getElementsByName('movedOptionsField')[0];
const customTitlesDisplay = document.getElementById('customTitles');
const checkboxes = document.querySelectorAll('input[name="movedOptionsInputs"]');
// Default settings
customResultDisplay.style.display = 'none';
customResultDisplay.required = false;
movedOptionsDisplay.style.display = 'none';
customTitlesDisplay.style.display = 'none';
// Unset move options
if (result != 'moved') {
checkboxes.forEach(checkbox => {
if (checkbox.checked) {
checkboxStates[checkbox.value] = true;
checkbox.checked = false;
const event = new Event('change');
checkbox.dispatchEvent(event);
} else {
checkboxStates[checkbox.value] = false;
}
});
}
switch (result) {
case 'moved':
movedOptionsDisplay.style.display = 'block';
// Reset move options
checkboxes.forEach(checkbox => {
if (checkboxStates[checkbox.value]) {
checkbox.checked = true;
const event = new Event('change');
checkbox.dispatchEvent(event);
}
});
break;
case 'custom':
customResultDisplay.style.display = 'inline';
customResultDisplay.required = true;
break;
}
}
function setupMoveOptions(container) {
let originalClosingComment = '';
const movedOptionsField = container.append({
type: 'field',
label: 'Specify move type',
style: 'display: none; flex: 1;',
name: 'movedOptionsField'
});
movedOptionsField.append({
type: 'checkbox',
name: 'movedOptionsInputs',
list: [
{
label: 'Close as uncontested',
value: 'moved-uncontested',
tooltip: 'We treat discussions where no objections have been raised, but community support has also not been demonstrated, as uncontested technical requests.',
event: function (event) {
const closingComment = document.getElementsByName('closingComment')[0];
if (event.target.checked) {
originalClosingComment = closingComment ? closingComment.value : '';
closingComment.value = 'Moved as an [[WP:RMNOMIN|uncontested request with minimal participation]]. If there is any objection within a reasonable time frame, please ask me to reopen the discussion; if I am not available, please ask at the [[WP:RM/TR#Requests to revert undiscussed moves|technical requests]] page.';
} else {
closingComment.value = originalClosingComment;
}
}
},
{
label: 'Specify different titles',
value: 'moved-different-title',
tooltip: 'If no title was originally proposed, or if there is a consensus to move to a title other than that which was originally proposed.',
event: function () {
if (event.target.checked) {
customTitles.style.display = 'block';
} else {
customTitles.style.display = 'none';
}
}
}
]
});
return movedOptionsField;
}
function setupCustomResult(resultField) {
resultField.append({
type: 'input',
name: 'customResult',
style: 'display: none;'
});
}
function setupCustomTitles() {
const customTitles = form.append({
type: 'field',
label: 'Specify titles',
id: 'customTitles',
name: 'customTitles',
style: 'display: none;'
});
data.moves.forEach((pair, index) => {
const titleField = customTitles.append({
type: 'div',
className: 'customTitleInput',
style: 'display: flex; align-items: center; margin-bottom: 5px;'
});
titleField.append({
type: 'div',
style: 'flex: 0 1 47.5%; text-align: left;',
label: pair.current
});
titleField.append({
type: 'div',
style: 'flex: 0 1 5%; text-align: center;',
label: '→'
});
const inputDiv = titleField.append({
type: 'div',
style: 'flex: 1;'
});
inputDiv.append({
type: 'input',
name: pair.current,
value: pair.destination,
style: 'width: 95%; text-align: left;'
});
});
const toggleButton = customTitles.append({
type: 'button',
label: 'Hide titles',
event: function (event) {
const titleInputs = document.querySelectorAll('.customTitleInput');
const button = event.target;
titleInputs.forEach(input => {
if (input.style.display === 'none' || input.style.display === '') {
input.style.display = 'flex';
button.value = 'Hide titles';
} else {
input.style.display = 'none';
button.value = 'Show titles';
}
});
}
});
}
function setupClosingComment(form) {
const closingCommentField = form.append({
type: 'field',
label: 'Closing comment'
});
closingCommentField.append({
type: 'textarea',
name: 'closingComment'
});
}
form.append({ type: 'submit', label: 'Submit' });
var formResult = form.render();
movePlus.Window.setContent(formResult);
movePlus.Window.display();
};
movePlus.displayWindowMove = function movePlusDisplayWindowMove() {
var title_obj = mw.Title.newFromText(Morebits.pageNameNorm);
movePlus.title = title_obj.getSubjectPage().toText();
movePlus.displayWindowInit();
movePlus.displayWindowAction();
}
movePlus.displayWindowInit = function movePlusDisplayWindowInit() {
movePlus.Window = new Morebits.simpleWindow(600, 450);
movePlus.Window.setScriptName('Move+');
movePlus.Window.addFooterLink('Moving instructions', 'Wikipedia:Moving a page');
movePlus.Window.addFooterLink('Script documentation', 'User:BilledMammal/Move+');
movePlus.Window.addFooterLink('Give feedback', 'User talk:BilledMammal/Move+');
}
movePlus.displayWindowAction = function movePlusDisplayWindowAction() {
var moveData = [{
current: movePlus.title,
target: ''
}];
var retargetData = [{
current: '',
target: ''
}];
var config = {
move: {
data: moveData,
reason: '',
label: 'Specify moves',
reasonLabel: 'Move reason',
reasonName: 'moveReason',
actionLimit: 100,
buttonLabel: 'Add move',
title: 'Move pages',
information: ''
},
retarget: {
data: retargetData,
reason: '',
label: 'Specify link retargets',
reasonLabel: 'Link retarget reason',
reasonName: 'retargetReason',
actionLimit: 2,
buttonLabel: 'Add retarget',
title: 'Retarget links',
information: movePlus.linkAdjustWarning
}
};
function updateForm(action) {
movePlus.Window.setTitle(config[action].title);
function updateActionDataFromForm() {
config[action].data = [];
config[action].reason = document.querySelector(`textarea[name="${config[action].reasonName}"]`).value;
var currentInputs = document.querySelectorAll('input[name="curr"]');
var targetInputs = document.querySelectorAll('input[name="dest"]');
currentInputs.forEach((input, index) => {
config[action].data.push({
current: input.value,
target: targetInputs[index].value
});
});
};
var form = new Morebits.quickForm(function (e) {
e.preventDefault();
movePlus.params = Morebits.quickForm.getInputData(e.target);
var currentPages = [];
var targetPages = [];
$('input[name="curr"]').each(function (index) {
var currentPage = $(this).val();
var targetPage = $('input[name="dest"]').eq(index).val();
if (currentPage && targetPage) {
currentPages.push(currentPage);
targetPages.push(targetPage);
}
});
if (action == 'move') {
movePlus.movePages(currentPages, targetPages, movePlus.params.moveReason, false);
}
if (action == 'retarget') {
movePlus.retargetLinks(currentPages, targetPages, movePlus.params.retargetReason);
}
});
movePlus.appendOptions(form, action, updateForm, updateActionDataFromForm);
var actionsContainer = form.append({
type: 'field',
label: config[action].label,
id: 'actionList',
name: 'actionList'
});
config[action].data.forEach((data, index) => {
const titleField = actionsContainer.append({
type: 'div',
className: 'titleInput',
style: 'display: flex; align-items: center; margin-bottom: 5px;'
});
const currentDiv = titleField.append({
type: 'div',
style: 'flex: 0 1 47.5%; text-align: left;'
});
currentDiv.append({
type: 'input',
name: 'curr',
value: data.current,
placeholder: 'Current page',
required: true,
style: 'width: 95%; text-align: left;'
});
titleField.append({
type: 'div',
style: 'flex: 0 1 5%; text-align: center;',
label: '→'
});
const destDiv = titleField.append({
type: 'div',
style: 'flex: 0 1 47.5%; text-align: left;'
});
destDiv.append({
type: 'input',
name: 'dest',
value: data.target,
required: true,
placeholder: 'Target page',
style: 'width: 95%; text-align: left;'
});
titleField.append({
type: 'button',
label: 'Remove',
disabled: config[action].data.length < 2 ? true : false,
event: function () {
updateActionDataFromForm();
config[action].data.splice(index, 1);
updateForm(action);
}
});
});
actionsContainer.append({
type: 'button',
label: config[action].buttonLabel,
disabled: config[action].data.length < config[action].actionLimit ? false : true,
event: function () {
updateActionDataFromForm();
config[action].data.push({ current: '', target: '' });
updateForm(action);
}
});
movePlus.appendReason(form, config[action].reasonLabel, config[action].reasonName, config[action].reason);
form.append({
type: 'div',
label: config[action].information,
style: 'margin-left: 15px; margin-right: 15px;'
});
form.append({ type: 'submit', label: 'Submit' });
var formResult = form.render();
movePlus.Window.setContent(formResult);
movePlus.appendReasonAlert(config[action].reasonLabel, config[action].reasonName);
movePlus.Window.display();
}
updateForm('move');
}
movePlus.retargetLinks = async function movePlusRetargetLinks(currentLinks, targetLinks, reason) {
var form = new Morebits.quickForm();
var actionContainer = form.append({
type: 'field',
label: 'Retargeting'
});
actionContainer.append({
type: 'div',
className: 'movePlusProgressBox',
label: ''
});
var multiple = currentLinks[1] ? true : false;
var config = {
currTarget: targetLinks[0],
destTarget: multiple ? targetLinks[1] : ''
}
var formResult = form.render();
movePlus.Window.setContent(formResult);
movePlus.Window.display();
const progressBox = document.querySelector('.movePlusProgressBox');
movePlus.linkEditSummary = reason + ': ';
await movePlus.correctLinks(currentLinks[0], multiple ? currentLinks[1] : '', config, progressBox);
progressBox.innerText = 'Done.'
setTimeout(function () { movePlus.Window.close(); }, 1250);
}
movePlus.appendOptions = function movePlusAppendOptions(form, action, updateForm, updateActionDataFromForm) {
var optionsContainer = form.append({
type: 'field',
label: 'Options',
style: 'display: flex; flex-direction: row;'
});
optionsContainer.append({
type: 'button',
label: 'Move pages',
name: 'movePages',
disabled: action == 'move' ? true : false,
event: function () {
updateActionDataFromForm();
updateForm('move');
}
});
optionsContainer.append({
type: 'button',
label: 'Retarget page links',
name: 'retargetLinks',
disabled: action == 'retarget' ? true : false,
event: function () {
updateActionDataFromForm();
updateForm('retarget');
}
});
}
movePlus.appendReason = function movePlusAppendReason(form, label, name, value) {
var moveReason = form.append({
type: 'field',
label: label
});
moveReason.append({
type: 'textarea',
name: name,
value: value,
required: true
});
moveReason.append({
type: 'div',
name: name + 'Alert',
style: 'display: block',
label: ''
});
}
movePlus.appendReasonAlert = function appendReasonAlert(label, name) {
const reasonAlert = document.getElementsByName(name + 'Alert')[0];
$(`textarea[name="${name}"]`).on('input', function () {
if (this.value.length > 400) {
reasonAlert.innerHTML = `<span style="color: red;"><b>Warning:</b></span> ${label} contains ${this.value.length} characters. It may be truncated in the edit summary.`;
reasonAlert.style.display = 'block';
} else {
reasonAlert.style.display = 'none';
}
});
}
movePlus.evaluate = function (e, data) {
var form = e.target;
movePlus.params = Morebits.quickForm.getInputData(form);
Morebits.simpleWindow.setButtonsEnabled(false);
Morebits.status.init(form);
// Store both the talk page and the pages being moved from template data
var title_obj = mw.Title.newFromText(Morebits.pageNameNorm);
movePlus.talktitle = title_obj.getTalkPage().toText(); // The talk page we're on
// Store all pages being moved from the template data
movePlus.pagesToMove = [];
if (data.moves && data.moves.length > 0) {
data.moves.forEach(function (move) {
movePlus.pagesToMove.push({
current: move.current,
destination: move.destination
});
});
// Set the primary page (first in list) for backward compatibility
movePlus.title = data.moves[0].current;
} else {
// Fallback if template data is missing
movePlus.title = title_obj.getSubjectPage().toText();
movePlus.pagesToMove = [{
current: movePlus.title,
destination: "?"
}];
}
var result = movePlus.params.result;
if (result == 'custom') {
result = movePlus.params.customResult;
}
var closingComment = movePlus.params.closingComment;
if (closingComment != "") {
closingComment = ' ' + closingComment;
closingComment = closingComment.replace(/\|/g, "{{!}}");
closingComment = closingComment.replace(/=/g, "{{=}}");
}
// Update destinations if custom titles were specified
if (movePlus.params.movedOptionsInputs && movePlus.params.movedOptionsInputs.includes('moved-different-title')) {
movePlus.pagesToMove.forEach(function (pair, index) {
if (movePlus.params[pair.current]) {
movePlus.pagesToMove[index].destination = movePlus.params[pair.current];
}
});
}
var talkpage = new Morebits.wiki.page(movePlus.talktitle, 'Closing move');
if (WATCHLISTPAGES) {
talkpage.setWatchlist('watch');
}
movePlus.closeMove(talkpage, result, closingComment, function ({ parsedDate, rmSection }) {
var link = movePlus.setOldMoves(talkpage, parsedDate, rmSection, result, function (link) {
if (result === "moved") {
let destinations = [];
let currents = [];
for (var m = 0; m < movePlus.pagesToMove.length; m++) {
destinations.push(movePlus.pagesToMove[m].destination);
currents.push(movePlus.pagesToMove[m].current);
}
movePlus.movePages(currents, destinations, link);
} else {
setTimeout(function () {
location.reload();
}, 2000);
}
});
});
};
movePlus.closeMove = function (talkpage, result, closingComment, done) {
talkpage.load(function (talkpage) {
var text = talkpage.getPageText();
var textToFind = text.split("\n");
var templateFound = false;
var templateIndex = -1;
var rmSection = "";
var nextSection = false;
var parsedDate = "";
var line;
// Find start of RM
for (var i = 0; i < textToFind.length; i++) {
line = textToFind[i];
if (templateFound === false) {
if (/{{[Rr]equested move\/dated/.test(line)) {
templateFound = true;
templateIndex = i;
}
} else {
if (/ \(UTC\)/.test(line)) {
line = line.substring(line.indexOf("This is a contested technical request"));
parsedDate = line.match(/, ([0-9]{1,2} (January|February|March|April|May|June|July|August|September|October|November|December) [0-9]{4}) \(UTC\)/)[1];
break;
}
}
}
// Find RM section
for (var j = templateIndex; j >= 0; j--) {
line = textToFind[j];
if (line.match(/^(==)[^=].+\1/)) {
rmSection = line.match(/^(==)[^=](.+)\1/)[2].trim();
break;
}
}
// Find end of RM
for (var k = templateIndex + 1; k < textToFind.length; k++) {
line = textToFind[k];
if (line.match(/^(==)[^=].+\1/)) {
nextSection = true;
var escapedLine = line.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
var regex = new RegExp("(" + escapedLine + ")(?![\\s\\S]*(" + escapedLine + "))", "m");
text = text.replace(regex, "{{subst:RM bottom}}\n\n" + line);
break;
}
}
var userGroupText = "";
if (Morebits.userIsInGroup("sysop")) {
userGroupText = "";
} else if (Morebits.userIsInGroup("extendedmover")) {
userGroupText = "|pmc=y";
} else {
userGroupText = "|nac=y";
}
text = text.replace(
/{{[Rr]equested move\/dated\|.*\n?[^\[{]*}}/,
"{{subst:RM top|'''" + result + ".'''" + closingComment + userGroupText + "}}"
);
if (!nextSection) {
text += "\n{{subst:RM bottom}}";
}
talkpage.setPageText(text);
talkpage.setEditSummary("Closing requested move; " + result + movePlus.advert);
talkpage.save(function () {
setTimeout(function () {
done({ parsedDate: parsedDate, rmSection: rmSection });
}, 1000);
});
});
};
movePlus.setOldMoves = function (talkpage, date, rmSection, result, done) {
talkpage.load(function (talkpage) {
const link = "Special:Permalink/" + talkpage.getCurrentID() + "#" + rmSection;
let m = 0;
function processNextPage() {
if (m >= movePlus.pagesToMove.length) {
done(link);
return;
}
const pageToMove = movePlus.pagesToMove[m];
const otherTalkPageTitle = mw.Title.newFromText(pageToMove.current).getTalkPage().toText();
const otherTalkPage = new Morebits.wiki.page(
otherTalkPageTitle,
"Adding {{old move}} to " + otherTalkPageTitle + "."
);
otherTalkPage.load(function (otherTalkPage) {
const otherText = createOldMoveText(
otherTalkPage,
date,
pageToMove.current,
pageToMove.destination,
result,
link
);
otherTalkPage.setPageText(otherText);
otherTalkPage.setEditSummary("Closing requested move; " + result + movePlus.advert);
otherTalkPage.save(function () {
m++;
setTimeout(processNextPage, 500);
});
});
}
processNextPage();
});
};
function createOldMoveText(page, date, from, destination, result, link) {
const pageText = page.getPageText();
const templatesOnPage = extraJs.parseTemplates(pageText, false);
const otherOldMovesPresent = templatesOnPage.filter((template) => {
const name = template.name.toLowerCase();
return name === "old moves" || name === "old move";
});
const keys = ["date", "from", "destination", "result", "link"];
const oldMoves = [];
const getOldMoveParam = (params, key, index) => {
if (index === 1) {
return params[key] ??
params[`${key}1`] ??
"";
}
return params[`${key}${index}`] ?? "";
};
for (const oldMove of otherOldMovesPresent) {
const params = Object.fromEntries(
(oldMove.parameters ?? []).map((param) => [param.name, param.value])
);
for (let index = 1; ; index++) {
const move = Object.fromEntries(
keys.map((key) => [key, getOldMoveParam(params, key, index)])
);
const hasAnyValue = Object.values(move).some((value) => value !== "");
if (!hasAnyValue) {
break;
}
oldMoves.push(move);
}
}
oldMoves.push({ date, from, destination, result, link });
const useUnnumberedParams = oldMoves.length === 1;
const movesText = `{{old moves ${oldMoves
.flatMap((move, index) => {
const suffix = useUnnumberedParams ? "" : index + 1;
return keys.map((key) => `| ${key}${suffix} = ${move[key] ?? ""} `);
})
.join("")}}}\n`;
const oldMovesPattern = /\{\{Old\s+(?:moves|move)(?:(?!}})[\s\S])*\}\}/i;
const oldMovesPatternGlobal = /\{\{Old\s+(?:moves|move)(?:(?!}})[\s\S])*\}\}/gi;
let updatedPageText;
if (oldMovesPattern.test(pageText)) {
let replacedFirst = false;
updatedPageText = pageText.replace(oldMovesPatternGlobal, () => {
if (!replacedFirst) {
replacedFirst = true;
return movesText;
}
return "";
});
} else {
const insertionMatch =
pageText.match(/\{\{[Aa]rchives/) ||
pageText.match(/\{\{[Aa]rchive box/) ||
pageText.match(/\{\{[Aa]rchivebox/) ||
pageText.match(/^==.*==/m);
if (insertionMatch) {
updatedPageText = pageText.replace(
insertionMatch[0],
`${movesText}${insertionMatch[0]}`
);
} else {
updatedPageText = `${movesText}${pageText}`;
}
}
return updatedPageText;
}
getTalkPageTitles = function getTalkPageTitles(curr, dest) {
var currTitleObj = new mw.Title(curr);
var destTitleObj = new mw.Title(dest);
var currTalkPage = currTitleObj.getTalkPage().getPrefixedText();
var destTalkPage = destTitleObj.getTalkPage().getPrefixedText();
return {
currTalk: currTalkPage,
destTalk: destTalkPage
};
}
getPageByTitle = function getPageByTitle(data, title) {
return data.find(page => page.title === title);
}
movePlus.checkPage = async function movePlusCheckPage(curr, dest) {
let talkPages = getTalkPageTitles(curr, dest);
let query = {
action: 'query',
prop: 'info|revisions',
inprop: 'protection',
titles: `${curr}|${talkPages.currTalk}|${dest}|${talkPages.destTalk}`,
format: 'json',
rvprop: 'ids'
};
let redirectsQuery = {
...query,
redirects: 1
}
let protection = {
curr: {
article: {}
},
dest: {
article: {}
},
createLabel: function (type) {
let protections = [];
let data = this[type];
let label = '';
if (data.move) protections.push("move");
if (data.create) protections.push("create");
if (protections.length > 0) {
const formattedProtection = protections.join(" and ");
label = ` (${formattedProtection} protected)`;
}
//As only sysop's can overwrite pages with history we only warn sysops
if (data.history && Morebits.userIsInGroup('sysop')) {
label = label + ' <span style="color: red;">(<b>Warning:</b> Page has history)</span>';
}
return label;
},
checkProtection: function () {
return this.curr.all || this.dest.all
},
checkSysopProtection: function () {
return this.curr.admin || this.dest.admin
},
checkHistory: function () {
return this.dest.history
},
checkRedirect: function () {
return this.dest.redirect
},
checkTarget: function () {
return this.curr.target
},
checkClosed: function () {
return (this.curr.article.redirect && this.dest.article.target) || (this.dest.article.redirect && this.curr.article.target)
},
checkAlreadyMoved: function () {
return this.alreadyMoved === true;
}
}
function getRedirectByTitle(data, title) {
if (data) {
let redirect = data.find(redirect => redirect.from === title);
return redirect ? redirect : [];
}
return [];
}
try {
const pageResponse = await new Morebits.wiki.api(`Accessing information on about edit restrictions on ${dest} and ${curr}`, query).post();
const currData = getPageByTitle(pageResponse.response.query.pages, curr)
const currTalkData = getPageByTitle(pageResponse.response.query.pages, talkPages.currTalk)
const destData = getPageByTitle(pageResponse.response.query.pages, dest)
const destTalkData = getPageByTitle(pageResponse.response.query.pages, talkPages.destTalk)
function checkProtection(data, admin = false) {
return data.protection.some(protection => {
if (admin) {
return protection.level == "sysop";
} else {
return !(Morebits.userIsInGroup(protection.level) || Morebits.userIsSysop);
}
});
}
function checkHistory(data) {
if (data.revisions) {
return data.revisions[0].parentid === 0;
}
return true;
}
function checkMissing(data) {
return data.missing
}
function processHistory(data, talkData) {
protection.dest.history = !checkHistory(data) || !checkHistory(talkData);
}
async function processRedirects() {
const redirectResponse = await new Morebits.wiki.api(`Accessing information about redirect status of ${curr} and ${dest}`, redirectsQuery).post();
processRedirect(redirectResponse, dest, curr, protection.dest, protection.curr);
processRedirect(redirectResponse, talkPages.destTalk, talkPages.currTalk, protection.dest, protection.curr);
processRedirect(redirectResponse, curr, dest, protection.curr.article, protection.dest.article);
processRedirect(redirectResponse, dest, curr, protection.dest.article, protection.curr.article);
}
function processRedirect(redirectData, origin, target, originStatus, targetStatus) {
let data = getRedirectByTitle(redirectData.response.query.redirects, origin)
originStatus.redirect = originStatus.redirect !== undefined ? originStatus.redirect : true;
targetStatus.target = targetStatus.target !== undefined ? targetStatus.target : true;
if (data.length == 0) {
if (!checkMissing(getPageByTitle(redirectData.response.query.pages, origin))) {
originStatus.history = true;
originStatus.redirect = false;
targetStatus.target = false;
}
return;
}
if (data.to != target) {
targetStatus.target = false;
}
}
protection.curr.all = checkProtection(currData) || checkProtection(currTalkData);
protection.curr.admin = checkProtection(currData, true) || checkProtection(currTalkData, true);
protection.dest.all = checkProtection(destData) || checkProtection(destTalkData);
protection.dest.admin = checkProtection(destData, true) || checkProtection(destTalkData, true);
protection.dest.history = !checkHistory(destData) || !checkHistory(destTalkData);
// Normalise both titles via mw.Title and compare
try {
var currNorm = new mw.Title(curr).getPrefixedText();
var destNorm = new mw.Title(dest).getPrefixedText();
protection.alreadyMoved = (currNorm === destNorm);
} catch (e) {
protection.alreadyMoved = false;
}
await processRedirects();
return protection;
} catch (error) {
console.error('Failed to fetch page details:', error);
throw error;
}
};
movePlus.movePages = function movePlusMovePages(currList, destList, link, closer = true) {
movePlus.numberToRemove = currList.length;
movePlus.talktitle = mw.Title.newFromText(Morebits.pageNameNorm).getTalkPage().toText();
var pageAndSection = link;
var moveSummary, rmtrReason;
var promises = [];
var configurations = [];
function sanitizeClassName(name) {
return name.replace(/[^a-zA-Z0-9\-_]/g, '-');
}
if (closer) {
if (movePlus.params.movedOptionsInputs.includes('moved-uncontested')) {
moveSummary = 'Moved, as an [[WP:RMTR|uncontested technical request]], per [[' + pageAndSection + ']]';
rmtrReason = 'Per lack of objection at [[' + pageAndSection + ']].';
} else {
moveSummary = 'Moved per [[' + pageAndSection + ']]';
rmtrReason = 'Per consensus at [[' + pageAndSection + ']].';
}
} else {
moveSummary = link;
rmtrReason = link;
}
var form = new Morebits.quickForm();
var movesContainer = form.append({
type: 'field',
label: 'Moves'
});
function addButtons(curr, dest, config) {
const moveContainer = movesContainer.append({
type: 'div',
className: 'movePlusMovePagesRow' + sanitizeClassName(curr),
style: 'display: flex; flex-direction: column; margin-bottom: 7px',
label: ''
});
const rowContainer = moveContainer.append({
type: 'div',
className: 'movePlusMovePagesSubRow' + sanitizeClassName(curr),
style: 'display: flex; flex-direction: row;',
label: ''
});
const actionContainer = rowContainer.append({
type: 'div',
style: 'display: flex; flex-direction: column; flex: 75%; text-align: left;',
className: 'moves'
});
const optionsContainer = rowContainer.append({
type: 'div',
style: 'display: flex; flex: 25%; text-align: left;',
className: 'moveOptions' + sanitizeClassName(curr)
});
actionContainer.append({
type: 'div',
className: 'movePlusMovePagesLabel',
label: config.label
});
actionContainer.append({
type: 'div',
className: 'movePlusProgressBox',
name: sanitizeClassName(curr),
label: '',
style: 'margin-left: 15px'
});
const buttonsContainer = actionContainer.append({
type: 'div',
style: 'display: flex; flex-direction: row; margin-left: 15px'
});
const linksContainer = moveContainer.append({
type: 'field',
label: 'Specify new link targets',
style: 'display: none',
className: 'specifyLinks' + sanitizeClassName(curr),
name: 'specifyLinks',
id: 'specifyLinks'
});
addRedirectSpecification(linksContainer, curr, dest);
addRedirectSpecification(linksContainer, dest, curr);
linksContainer.append({
type: 'div',
label: movePlus.linkAdjustWarning
});
var isSysop = Morebits.userIsInGroup('sysop');
var isMover = Morebits.userIsInGroup('extendedmover');
// NEW: If the page is already at the proposed destination, show an
// informational message and skip all move buttons entirely.
if (config.isAlreadyMoved) {
actionContainer.append({
type: 'div',
className: 'movePlusProgressBox',
name: sanitizeClassName(curr),
label: 'Already at target location — no move needed.',
style: 'margin-left: 15px; color: green;'
});
// Decrement counter immediately so the close-window interval
// doesn't stall waiting for a move that will never happen.
movePlus.numberToRemove--;
return;
}
if (!config.isProtected) {
if (config.hasHistory) {
if (isMover || isSysop) {
addCheckboxes(optionsContainer, curr, isSysop, true, true, !config.isClosed);
if (isSysop) {
addButton(buttonsContainer, curr, dest, "moveOverPage", true);
}
addButton(buttonsContainer, curr, dest, 'roundRobin');
} else {
addButton(buttonsContainer, curr, dest, 'technicalRequest', config.isSysopProtected);
}
} else if (config.isRedirect && !config.isTarget) {
if (isSysop || isMover) {
addCheckboxes(optionsContainer, curr, true, true, true, false);
addButton(buttonsContainer, curr, dest, "moveOverPage")
} else {
addButton(buttonsContainer, curr, dest, 'technicalRequest', config.isSysopProtected);
}
} else {
addButton(buttonsContainer, curr, dest, "move");
if (isSysop || isMover) {
addCheckboxes(optionsContainer, curr, true, true, true, false);
} else {
addCheckboxes(optionsContainer, curr, false, false, true, false);
}
}
} else {
addButton(buttonsContainer, curr, dest, 'technicalRequest', config.isSysopProtected);
}
}
function addRedirectSpecification(container, origin, target) {
const titleField = container.append({
type: 'div',
className: 'titleInput',
style: 'display: flex; align-items: center; margin-bottom: 5px;'
});
const currentDiv = titleField.append({
type: 'div',
style: 'flex: 0 1 47.5%; text-align: left;'
});
currentDiv.append({
type: 'div',
label: origin,
style: 'width: 95%; text-align: left;'
});
titleField.append({
type: 'div',
style: 'flex: 0 1 5%; text-align: center;',
label: '→'
});
const futDiv = titleField.append({
type: 'div',
style: 'flex: 0 1 47.5%; text-align: left;'
});
futDiv.append({
type: 'input',
id: 'specifyLinks' + sanitizeClassName(origin),
value: target,
placeholder: 'Future page',
style: 'width: 95%; text-align: left;'
});
}
function addCheckboxes(container, label, suppressRedirect, moveSubpages, moveTalkPage, correctLinks) {
let options = [];
if (correctLinks) {
options.push({
name: 'correctLinks' + sanitizeClassName(label),
label: "Correct links",
checked: false,
event: function () {
if (event.target.checked) {
document.querySelector('.specifyLinks' + sanitizeClassName(label)).style.display = 'block';
} else {
document.querySelector('.specifyLinks' + sanitizeClassName(label)).style.display = 'none';
}
}
});
}
if (suppressRedirect) {
options.push({
name: 'suppressRedirect' + sanitizeClassName(label),
label: "Suppress redirect",
checked: false
});
};
if (moveSubpages) {
options.push({
name: 'moveSubpages' + sanitizeClassName(label),
label: 'Move subpages',
checked: true
});
};
if (moveTalkPage) {
options.push({
name: 'moveTalkPage' + sanitizeClassName(label),
label: 'Move talk page',
checked: true
});
};
container.append({
type: 'checkbox',
style: 'display: flex; flex-direction: column; align-items: left; margin-right: 10px;',
list: options
});
}
function addButton(container, curr, dest, type, admin = false) {
let config;
let operation;
let label;
let id;
let tooltip = "";
let disabled = false;
switch (type) {
case "move":
operation = async function (progressBox) {
config = checkCheckboxes();
await movePlus.movePage(this.name, this.extra, moveSummary, progressBox, config);
};
label = 'Move directly';
id = 'moveDirectly';
break;
case "moveOverPage":
operation = async function (progressBox) {
config = checkCheckboxes();
await movePlus.moveOverPage(this.name, this.extra, config.suppressRedirect, moveSummary, admin, progressBox, config.moveSubpages, config.moveTalkPage);
};
label = 'Move directly (o)';
id = 'moveOverPage';
break;
case "roundRobin":
operation = async function (progressBox) {
config = checkCheckboxes();
await movePlus.moveRoundRobin(this.name, this.extra, moveSummary, progressBox, config);
};
label = 'Move via Round Robin';
id = 'roundRobin';
break;
case "technicalRequest":
operation = async function (progressBox) {
config = checkCheckboxes();
await movePlus.submitRMTR(this.name, this.extra, admin, rmtrReason, progressBox);
};
label = 'Submit technical request';
id = 'rmtr';
break;
}
container.append({
type: 'button',
className: 'movePlusMovePages' + sanitizeClassName(curr),
name: curr,
extra: dest,
label: label,
tooltip: tooltip,
disabled: disabled,
id: id,
event: async function () {
const rowElements = document.querySelectorAll('.movePlusMovePages' + sanitizeClassName(curr));
rowElements.forEach(element => {
element.style.display = 'none';
});
const progressBox = document.querySelector('.movePlusProgressBox[name="' + sanitizeClassName(curr) + '"]');
if (progressBox) {
progressBox.textContent = 'In progress...';
try {
await operation.call(this, progressBox);
progressBox.textContent = 'Completed!';
setTimeout(() => {
document.querySelector('.movePlusMovePagesRow' + sanitizeClassName(curr)).style.display = 'none';
movePlus.numberToRemove--;
}, 1000);
} catch (error) {
progressBox.textContent = 'Failed. Please implement manually and report this error to the script maintainer. ' + error;
}
}
}
});
function checkCheckboxes() {
const suppressRedirectElem = document.querySelector('input[name="suppressRedirect' + sanitizeClassName(curr) + '"]');
const moveSubpagesElem = document.querySelector('input[name="moveSubpages' + sanitizeClassName(curr) + '"]');
const moveTalkPageElem = document.querySelector('input[name="moveTalkPage' + sanitizeClassName(curr) + '"]');
const correctLinksElem = document.querySelector('input[name="correctLinks' + sanitizeClassName(curr) + '"]');
let suppressRedirect = suppressRedirectElem ? suppressRedirectElem.checked : false;
let moveSubpages = moveSubpagesElem ? moveSubpagesElem.checked : true;
let moveTalkPage = moveTalkPageElem ? moveTalkPageElem.checked : true;
let correctLinks = correctLinksElem ? correctLinksElem.checked : false;
let currTarget, destTarget;
if (correctLinks) {
currTarget = document.querySelector('#specifyLinks' + sanitizeClassName(curr)).value;
destTarget = document.querySelector('#specifyLinks' + sanitizeClassName(dest)).value;
}
document.querySelector('.specifyLinks' + sanitizeClassName(curr)).style.display = 'none';
document.querySelector('.moveOptions' + sanitizeClassName(curr)).style.display = 'none';
return {
suppressRedirect: suppressRedirect,
moveSubpages: moveSubpages,
moveTalkPage: moveTalkPage,
correctLinks: correctLinks,
currTarget: currTarget,
destTarget: destTarget
}
}
}
function getActions(fromList, toList) {
if (fromList.length !== toList.length) {
throw new Error("Mismatched moves");
}
const moves = [];
const sources = [];
const destinations = [];
for (let i = 0; i < fromList.length; i++) {
moves.push({ from: fromList[i], to: toList[i] });
}
for (const move of moves) {
if (destinations.includes(move.to)) {
throw new Error("Trying to move two articles to the same place");
}
if (sources.includes(move.from)) {
throw new Error("Trying to move the same article twice");
}
destinations.push(move.to);
sources.push(move.from);
}
const firstMoves = [];
const secondMoves = [];
const redirects = [];
for (const move of moves) {
if (destinations.includes(move.from)) {
firstMoves.push({ type: "move", ...move });
} else {
secondMoves.push({ type: "move", ...move });
}
if (sources.includes(move.to)) {
redirects.push({ type: "retarget", from: move.from, to: move.to });
}
}
return [...firstMoves, ...secondMoves, ...redirects];
}
for (let i = 0; i < currList.length; i++) {
let promise = movePlus.checkPage(currList[i], destList[i]).then(data => {
configurations[i] = {
label: currList[i] + data.createLabel("curr") + ' → ' + destList[i] + data.createLabel("dest"),
isProtected: data.checkProtection(),
isSysopProtected: data.checkSysopProtection(),
hasHistory: data.checkHistory(),
isRedirect: data.checkRedirect(),
isTarget: data.checkTarget(),
isClosed: data.checkClosed(),
isAlreadyMoved: data.checkAlreadyMoved()
}
});
promises.push(promise)
}
function setupMulti() {
var multiContainer = form.append({
type: 'field',
label: 'Multi-action',
style: 'display: flex; flex-direction: row'
});
multiContainer.append({
type: 'button',
label: 'Move all',
tooltip: 'Moves all pages. If there are multiple options it will move the page via round robin instead of overwriting history at the destination.',
event: async function () {
const rows = document.querySelectorAll('[class^="movePlusMovePagesRow"]');
for (const row of rows) {
const moveDirectlyButton = row.querySelector('div span input#moveDirectly');
const roundRobinButton = row.querySelector('div span input#roundRobin');
const technicalRequestButton = row.querySelector('div span input#rmtr');
if (moveDirectlyButton) {
await moveDirectlyButton.click();
} else if (roundRobinButton) {
await roundRobinButton.click();
} else if (technicalRequestButton) {
await technicalRequestButton.click();
}
}
}
});
multiContainer.append({
type: 'button',
label: 'Shuffle',
tooltip: 'Moves all pages in a smart way if the pages overlap',
event: async function () {
const actions = getActions(currList, destList);
for (const action of actions) {
// if (action.type === "move") {
// movePlus.movePage(action.from, action.to, "", progressBox, config)
// }
console.log("I would like to", action)
}
}
});
var multiOptionContainer = multiContainer.append({
type: 'div',
style: "display: flex; flex-direction: row; justify-content: flex-end; width: 85%;"
});
multiOptionContainer.append({
type: 'button',
label: 'Suppress all redirects',
event: function () {
const buttons = document.querySelectorAll('input[name^="suppressRedirect"]');
const button = event.target;
const currentLabel = button.value;
buttons.forEach(button => {
button.checked = currentLabel === 'Suppress all redirects';
});
button.value = currentLabel === 'Suppress all redirects' ? 'Suppress no redirects' : 'Suppress all redirects';
}
});
multiOptionContainer.append({
type: 'button',
label: 'Move no subpages',
event: function () {
const buttons = document.querySelectorAll('input[name^="moveSubpages"]');
const button = event.target;
const currentLabel = button.value;
buttons.forEach(button => {
button.checked = currentLabel === 'Move all subpages';
});
button.value = currentLabel === 'Move all subpages' ? 'Move no subpages' : 'Move all subpages';
}
});
multiOptionContainer.append({
type: 'button',
label: 'Move no talk pages',
event: function () {
const buttons = document.querySelectorAll('input[name^="moveTalkPage"]');
const button = event.target;
const currentLabel = button.value;
buttons.forEach(button => {
button.checked = currentLabel === 'Move all talk pages';
});
button.value = currentLabel === 'Move all talk pages' ? 'Move no talk pages' : 'Move all talk pages';
}
});
}
Promise.all(promises).then(() => {
configurations.forEach((config, index) => {
addButtons(currList[index], destList[index], config);
});
setupMulti();
var formResult = form.render();
movePlus.Window.setContent(formResult);
movePlus.Window.display();
// UPDATED: Track interval for cleanup with safety timeout
var moveInterval = setInterval(function () {
if (movePlus.numberToRemove == 0) {
movePlus.Window.close();
clearInterval(moveInterval);
var index = movePlus.activeIntervals.indexOf(moveInterval);
if (index > -1) {
movePlus.activeIntervals.splice(index, 1);
}
setTimeout(function () { location.reload() }, 750);
}
}, 500);
// Track interval for cleanup
movePlus.activeIntervals.push(moveInterval);
// Add safety timeout (2 minutes)
setTimeout(function () {
if (moveInterval) {
clearInterval(moveInterval);
var index = movePlus.activeIntervals.indexOf(moveInterval);
if (index > -1) {
movePlus.activeIntervals.splice(index, 1);
}
console.warn('Move interval timed out after 2 minutes');
}
}, 120000);
});
};
movePlus.moveOverPage = function movePlusMoveOverPage(curr, dest, suppressRedirect, editSummary, warn, progressBox, subpages = true, talkpage = true) {
let destSplit = movePlus.splitPageName(dest);
if (warn) {
if (!confirm('Warning: You are about to delete a page with history. Do you want to proceed?')) {
progressBox.innerText = 'Move cancelled';
throw new Error('Move cancelled.');
}
}
return new Promise((resolve, reject) => {
const moveTask = async () => {
progressBox.innerText = `Moving ${curr} to ${dest}.`;
const url = 'https://en.wikipedia.org/w/index.php?title=Special:MovePage&action=submit';
const formData = new FormData();
formData.append('wpNewTitleNs', destSplit.namespace);
formData.append('wpNewTitleMain', destSplit.pageName);
formData.append('wpReasonList', 'other');
formData.append('wpReason', editSummary + movePlus.advert);
formData.append('wpWatch', '0');
formData.append('wpLeaveRedirect', suppressRedirect ? '0' : '1');
formData.append('wpMovetalk', talkpage ? '1' : '0');
formData.append('wpMovesubpages', subpages ? '1' : '0');
formData.append('wpDeleteAndMove', '1');
formData.append('wpMove', 'Move page');
formData.append('wpOldTitle', curr);
formData.append('wpEditToken', mw.user.tokens.get('csrfToken'));
const response = await fetch(url, {
method: 'POST',
body: formData,
credentials: 'include'
});
if (response.ok) {
progressBox.innerText = `Moved ${curr} to ${dest}.`;
Morebits.status.actionCompleted('Moved.');
resolve();
} else {
progressBox.innerText = `Failed to move ${curr} to ${dest}.`;
reject('Move request failed');
}
};
movePlus.moveQueue.push(moveTask);
movePlus.startMoveQueue();
});
};
movePlus.movePage = function movePlusMovePage(from, to, editSummary, progressBox, config) {
return new Promise((resolve, reject) => {
const moveTask = () => {
progressBox.innerText = `Moving ${from} to ${to}...`;
let pageToMove = new Morebits.wiki.page(from, `Moving ${from} to ${to}.`);
if (WATCHLISTPAGES) {
pageToMove.setWatchlist('watch');
}
pageToMove.setMoveDestination(to);
pageToMove.setMoveSubpages(config.moveSubpages);
pageToMove.setMoveTalkPage(config.moveTalkPage);
pageToMove.setMoveSuppressRedirect(config.suppressRedirect);
pageToMove.setEditSummary(`${editSummary}${movePlus.advert}`);
console.log(`Moving ${from} to ${to}`);
pageToMove.move(() => {
progressBox.innerText = `Moved ${from} to ${to}.`;
Morebits.status.actionCompleted('Moved.');
resolve();
}, (error) => {
reject(error);
});
};
movePlus.moveQueue.push(moveTask);
movePlus.startMoveQueue();
});
};
movePlus.moveRoundRobin = async function movePlusMoveRoundRobin(curr, dest, editSummary, progressBox, config) {
progressBox.innerText = 'Round robin pending...';
config.suppressRedirect = true;
try {
var destDetails = movePlus.splitPageName(dest);
var intermediateTitle = `Draft:Move/${destDetails.pageName}`;
editSummary = `${editSummary} via a [[WP:ROUNDROBIN|round robin]]`;
progressBox.innerText = `Moving ${dest} to ${intermediateTitle}...`;
await movePlus.movePage(dest, intermediateTitle, editSummary, progressBox, config);
progressBox.innerText = `Moving ${curr} to ${dest}...`;
await movePlus.movePage(curr, dest, editSummary, progressBox, config);
progressBox.innerText = `Moving ${intermediateTitle} to ${curr}...`;
await movePlus.movePage(intermediateTitle, curr, editSummary, progressBox, config);
progressBox.innerText = `Cleaning up round robin for ${curr} and ${dest}...`;
await movePlus.roundRobinCleanup(curr, dest, config);
if (config.moveTalkPage) {
await movePlus.roundRobinCleanup(movePlus.getTalkPageName(curr), movePlus.getTalkPageName(dest), config);
}
if (config.correctLinks) {
movePlus.linkEditSummary = `Post-move cleanup, following [[WP:ROBIN|swap]] of [[${curr}]] and [[${dest}]]: `
progressBox.innerText = `Correcting redirects for ${curr} and ${dest}...`;
movePlus.correctRedirects(curr, dest, config);
progressBox.innerText = `Correcting links for ${curr} and ${dest}...`;
await movePlus.correctLinks(curr, dest, config, progressBox);
}
} catch (error) {
console.error('Error during move operation:', error);
}
};
movePlus.getLinksHere = async function movePlusGetLinksHere(page) {
let query = {
action: 'query',
prop: 'linkshere',
titles: page,
lhlimit: 'max',
format: 'json',
lhnamespace: `${movePlus.splitPageName(page).namespace}|10|14`,
rawcontinue: 1
};
let pages = [];
do {
let response = await new Morebits.wiki.api(`Listing links to ${page}`, query).post();
if (response.response.query.pages[0].linkshere) {
pages = pages.concat(response.response.query.pages[0].linkshere);
}
query.lhcontinue = response.response['query-continue'] ? response.response['query-continue'].linkshere.lhcontinue : 0;
} while (query.lhcontinue)
return pages;
}
movePlus.roundRobinCleanup = async function movePlusRoundRobinCleanup(curr, dest, config) {
async function queryPagesAndRedirects(page) {
let details = movePlus.splitPageName(page);
let query = {
action: 'query',
list: 'allpages',
apfrom: `${details.pageName}/`,
apto: `${details.pageName}0`,
apnamespace: details.namespace,
format: 'json'
};
let allpages = [];
if (config.moveSubpages) {
const response = await new Morebits.wiki.api(`Listing subpages of ${details.pageName}`, query).post();
allpages = response.response.query.allpages || [];
}
let pageTitles = allpages.map(page => page.title).join('|');
if (pageTitles) {
pageTitles += '|';
}
pageTitles += page;
let pageQuery = {
action: "query",
format: "json",
prop: "",
titles: pageTitles
}
const responsePages = await new Morebits.wiki.api(`Getting details of subpages of ${details.pageName}`, pageQuery).post();
const pages = (responsePages.response.query.pages || []).filter(page => !page.missing);
pageQuery.redirects = 1;
const responseRedirects = await new Morebits.wiki.api(`Getting details of subpages of ${details.pageName}`, pageQuery).post();
const redirects = responseRedirects.response.query.redirects || [];
return { redirects, pages };
};
function getPagePairs(pages, pair, self) {
return pages.map(page => {
const subpageName = movePlus.splitSubpageName(page.title, self);
const pagename = subpageName === '' ? pair : `${pair}/${subpageName}`;
return {
pagename: pagename,
target: page.title
};
});
}
function getRedirectPairs(redirects, pair, self) {
return redirects.filter(redirect => redirect.from !== redirect.to).map(redirect => {
const subpageName = movePlus.splitSubpageName(redirect.from, self);
const pagename = subpageName === '' ? pair : `${pair}/${subpageName}`;
return {
pagename: pagename,
target: redirect.to
};
});
}
function findSelfRedirects(redirects, pair, self) {
return redirects.filter(redirect => redirect.from === redirect.to).map(redirect => {
const subpageName = movePlus.splitSubpageName(redirect.from, self);
const target = subpageName === '' ? pair : `${pair}/${subpageName}`;
return {
pagename: redirect.from,
target: target
};
});
}
async function processPages(pairs, existingPages, existingRedirects) {
const existingPageNames = new Set(existingPages.map(page => page.title));
const existingRedirectNames = new Set(existingRedirects.map(redirect => redirect.from));
for (const pair of pairs) {
if (!existingPageNames.has(pair.pagename) && !existingRedirectNames.has(pair.pagename)) {
await movePlus.createRedirect(pair.pagename, pair.target,
`Redirecting to [[${pair.target}]] as part of post-[[WP:ROUNDROBIN|round robin]] cleanup${movePlus.advert}`);
}
};
};
const currResponse = await queryPagesAndRedirects(curr);
const destResponse = await queryPagesAndRedirects(dest);
const currRedirects = currResponse.redirects;
const currPages = currResponse.pages;
const destRedirects = destResponse.redirects;
const destPages = destResponse.pages;
const currPagePairs = getPagePairs(currPages, dest, curr);
const currRedirectPairs = getRedirectPairs(currRedirects, dest, curr);
const currSelfRedirects = findSelfRedirects(currRedirects, dest, curr);
const destPagePairs = getPagePairs(destPages, curr, dest);
const destRedirectPairs = getRedirectPairs(destRedirects, curr, dest);
const destSelfRedirects = findSelfRedirects(destRedirects, curr, dest);
await processPages(currPagePairs, destPages, destRedirects);
await processPages(currRedirectPairs, destPages, destRedirects);
await processPages(destPagePairs, currPages, currRedirects);
await processPages(destRedirectPairs, currPages, currRedirects);
for (const pair of currSelfRedirects.concat(destSelfRedirects)) {
await movePlus.createRedirect(pair.pagename, pair.target, `Redirecting to [[${pair.target}]] as part of post-[[WP:ROUNDROBIN|round robin]] cleanup${movePlus.advert}`);
}
};
movePlus.correctRedirects = async function movePlusCorrectRedirects(curr, dest, config) {
if (config.currTarget != dest && config.currTarget != curr) {
await movePlus.createRedirectPair(dest, config.destTarget, `Redirecting to [[${config.destTarget}]] as part of post-[[WP:ROUNDROBIN|round robin]] cleanup${movePlus.advert}`, config);
}
if (config.destTarget != curr && config.destTarget != dest) {
await movePlus.createRedirect(curr, config.currTarget, `Redirecting to [[${config.currTarget}]] as part of post-[[WP:ROUNDROBIN|round robin]] cleanup${movePlus.advert}`);
}
}
movePlus.correctLinks = async function movePlusCorrectLinks(curr, dest, config, progressBox) {
let currPages = [];
let destPages = [];
progressBox.innerText = `Getting links to ${curr}...`;
if (curr != config.currTarget) {
currPages = await movePlus.getLinksHere(curr);
}
progressBox.innerText = `Getting links to ${dest}...`;
if (dest != "" && dest != config.destTarget) {
destPages = await movePlus.getLinksHere(dest);
}
const pageIdsCurr = new Set(currPages.map(item => item.pageid));
const pageIdsDest = new Set(destPages.map(item => item.pageid));
await processBatches(curr, config.currTarget, currPages, pageIdsDest, progressBox, true, dest, config.destTarget);
await processBatches(dest, config.destTarget, destPages, pageIdsCurr, progressBox, false);
async function processBatches(origin, target, pages, otherPages, progressBox, processDuplicates, otherOrigin = "", otherTarget = "") {
if (origin == target) {
return;
}
let query = {
action: "query",
format: "json",
prop: "categories",
titles: "",
clcategories: "Category:All_disambiguation_pages|Category:All_set_index_articles"
}
for (let i = 0; i < pages.length; i += 50) {
const batch = pages.slice(i, i + 50);
query.titles = batch.map(item => item.title).join('|');
const response = await new Morebits.wiki.api(`Listing categories of pages linking to ${origin}`, query).post();
const dabPages = new Set();
response.response.query.pages.forEach(page => {
if (page.categories && page.categories.length > 0) {
dabPages.add(page.pageid);
}
});
let j = i
for (const item of batch) {
j++;
//Skip archives
if (item.ns != 0 && item.title.toLowerCase().includes('/archive')) {
continue;
}
progressBox.innerHTML = `${origin} → ${target} (${j}/${pages.length}):<br>Updating <a href="https://en.wikipedia.org/wiki/${item.title}" target="_blank" rel="noopener noreferrer">${item.title}</a>...`;
if (otherPages.has(item.pageid)) {
if (processDuplicates) {
await movePlus.correctLink(item, origin, target, dabPages.has(item.pageid), otherOrigin, otherTarget);
}
} else {
await movePlus.correctLink(item, origin, target, dabPages.has(item.pageid));
}
}
}
}
}
movePlus.correctLink = function movePlusCorrectLink(item, from, to, dab, otherFrom = "", otherTo = "") {
return new Promise((resolve, reject) => {
console.log(`Updating links at ${item.title}`);
let page = new Morebits.wiki.page(item.title, `Updating links at ${item.title}`);
if (WATCHLISTPAGES) {
page.setWatchlist('watch');
}
page.load(function (linkCorrection) {
let originalText = page.getPageText();
if (!allowBots(originalText, mw.config.get('wgUserName'))) {
console.log(`Forbidden from making edits at ${item.title}`)
resolve();
return;
}
if (otherFrom != "" && otherTo != "") {
var updatedText = updateTextRoundRobin(originalText, item, from, to, otherFrom, otherTo, dab);
} else {
var updatedText = updateText(originalText, item, from, to, dab);
}
if (updatedText.matches == 0) {
console.log(`No edits to make at ${item.title}`);
resolve();
return;
}
let text = updatedText.text;
let editSummary = updatedText.editSummary;
const editTask = () => {
page.setPageText(text);
page.setEditSummary(editSummary);
page.setMinorEdit(true);
page.setBotEdit(true);
console.log(`Successfully updated ${item.title}`);
page.save(() => {
Morebits.status.actionCompleted(`Replaced link to ${from} with link to ${to} at ${item.title}.`);
resolve();
}, (error) => {
reject(error);
});
};
movePlus.editQueue.push(editTask);
movePlus.startEditQueue();
});
});
function updateText(text, item, from, to, dab) {
let updatedText = processText(text, item, from, to, dab);
let editSummary = `${movePlus.linkEditSummary}Changed link from [[${from}]] to [[${to}]]${updatedText.matches > 1 ? ` (×${updatedText.matches})` : ""}${movePlus.advert}`;
return { text: updatedText.text, editSummary: editSummary, matches: updatedText.matches };
}
function updateTextRoundRobin(text, item, from, to, otherFrom, otherTo, dab) {
let stageOneText = processText(text, item, from, "INTERMEDIARYSTAGE", dab);
let stageTwoText = processText(stageOneText.text, item, otherFrom, otherTo, dab);
let updatedText = processText(stageTwoText.text, item, "INTERMEDIARYSTAGE", to, dab);
let editSummary = `${movePlus.linkEditSummary}Changed link from [[${from}]] to [[${to}]] ${stageOneText.matches > 1 ? `(×${stageOneText.matches}) ` : ""}and from [[${otherFrom}]] to [[${otherTo}]]${stageTwoText.matches > 1 ? ` (×${stageTwoText.matches})` : ""}${movePlus.advert}`;
return { text: updatedText.text, editSummary: editSummary, matches: stageOneText.matches + stageTwoText.matches };
}
function processText(text, item, from, to, dab) {
function escapeRegExp(string) {
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
const linkRegex = new RegExp(`\\[\\[${escapeRegExp(from)}(\\|.+|#.*)?\\]\\]`, 'g');
const matches = text.match(linkRegex);
if (!matches) {
return { text: text, matches: 0 }
}
let updatedText = text.replace(linkRegex, match => {
const hashedMatch = match.includes('#');
const pipedMatch = match.includes('|');
if (hashedMatch) {
return match.replace(from, to);
}
if (item.redirect || (dab && !pipedMatch)) {
return `[[${to}]]`;
}
if (pipedMatch) {
var link = match.replace(from, to);
link = link.replace(`${to}|${to}`, to);
return link
}
return `[[${to}|${from}]]`;
});
return { text: updatedText, matches: matches.length };
}
};
movePlus.createRedirectPair = async function movePlusCreateRedirectPair(page, target, editSummary, config) {
await movePlus.createRedirect(page, target, editSummary);
if (config.moveTalkPage) {
let currTalk = movePlus.getTalkPageName(page);
let targetTalk = movePlus.getTalkPageName(target);
await movePlus.createRedirect(currTalk, targetTalk, editSummary);
}
}
movePlus.createRedirect = async function movePlusCreateRedirect(page, target, editSummary) {
return new Promise((resolve, reject) => {
const editTask = () => {
let redirect = new Morebits.wiki.page(page, `Creating redirect to ${target}`);
if (WATCHLISTPAGES) {
redirect.setWatchlist('watch');
}
redirect.load(function (redirect) {
redirect.setPageText(`#REDIRECT [[${target}]]\n{{Rcat shell|\n{{R from move}}\n}}`);
redirect.setEditSummary(editSummary);
console.log(`Attempting to redirect ${page} to ${target}`);
redirect.save(() => {
Morebits.status.actionCompleted(`Cleaned up ${page}.`);
resolve();
}, (error) => {
reject(error);
});
});
};
movePlus.editQueue.push(editTask);
movePlus.startEditQueue();
});
};
movePlus.splitPageName = function movePlusSplitPageName(page) {
// Use MediaWiki's Title object for reliable parsing
const title = mw.Title.newFromText(page);
if (!title) {
// Fallback to original method if Title parsing fails
const namespaceSeparator = ':';
const namespaceMap = {
'': 0, 'Talk': 1, 'User': 2, 'User talk': 3, 'Wikipedia': 4, 'Wikipedia talk': 5,
'File': 6, 'File talk': 7, 'MediaWiki': 8, 'MediaWiki talk': 9, 'Template': 10,
'Template talk': 11, 'Help': 12, 'Help talk': 13, 'Category': 14, 'Category talk': 15,
'Portal': 100, 'Draft': 118, 'Draft talk': 119, 'TimedText': 710, 'TimedText talk': 711,
'Module': 828, 'Module talk': 829
};
const separatorIndex = page.indexOf(namespaceSeparator);
if (separatorIndex === -1) {
return { namespace: 0, pageName: page };
}
const potentialNamespace = page.substring(0, separatorIndex).trim();
const pageName = page.substring(separatorIndex + 1).trim();
const namespaceNumber = namespaceMap.hasOwnProperty(potentialNamespace) ?
namespaceMap[potentialNamespace] : 0;
if (namespaceNumber === 0) {
return { namespace: 0, pageName: page };
}
return { namespace: namespaceNumber, pageName: pageName };
}
return {
namespace: title.namespace,
pageName: title.getName()
};
};
movePlus.getTalkPageName = function movePlusGetTalkPageName(page) {
// Use MediaWiki's Title object for more reliable namespace handling
const title = mw.Title.newFromText(page);
if (!title) {
return null;
}
const talkTitle = title.getTalkPage();
if (!talkTitle) {
return null;
}
return talkTitle.getPrefixedText();
};
movePlus.splitSubpageName = function movePlusSplitSubpageName(page, self) {
let selfIndex = page.indexOf(self);
if (selfIndex === -1 || selfIndex === page.length - self.length) {
return "";
}
return page.substring(selfIndex + self.length + 1);
}
movePlus.submitRMTR = function movePlusSubmitRMTR(curr, dest, adminRequired, reason, progressBox) {
progressBox.innerText = `Submitting technical request for ${curr} to ${dest}...`;
var rmtr = new Morebits.wiki.page('Wikipedia:Requested moves/Technical requests', 'Submitting request at WP:RM/TR');
rmtr.load(function (page) {
if (adminRequired) {
rmtr.setAppendText('{{subst:RMassist|1=' + curr + '|2=' + dest + '|reason=' + reason + '}}');
} else {
var text = rmtr.getPageText();
var textToFind = /\n{1,}(==== ?Requests to revert undiscussed moves ?====)/i;
var rmtrText = '{{subst:RMassist|1=' + curr + '|2=' + dest + '|reason=' + reason + '}}';
text = text.replace(textToFind, '\n' + rmtrText + '\n\n$1');
rmtr.setPageText(text);
}
rmtr.setEditSummary('Add request' + movePlus.advert);
rmtr.save(() => {
progressBox.innerText = 'Technical request submitted';
Morebits.status.actionCompleted('Requested.')
});
});
};
movePlus.relist = function movePlusRelist(e) {
if (e) e.preventDefault();
var title_obj = mw.Title.newFromText(Morebits.pageNameNorm);
movePlus.talktitle = title_obj.getTalkPage().toText();
var talkpage = new Morebits.wiki.page(movePlus.talktitle, 'Relisting.');
var relistingComment = document.getElementById('movePlusRelistComment').value;
talkpage.load(function (talkpage) {
var text = talkpage.getPageText();
var templateFound = false;
var sig;
var line;
var templateIndex = -1;
var textToFind = text.split('\n');
for (var i = 0; i < textToFind.length; i++) {
line = textToFind[i];
if (templateFound == false) {
if (/{{[Rr]equested move\/dated/.test(line)) {
templateFound = true;
templateIndex = i;
}
} else if (templateFound == true) {
if (/ \(UTC\)/.test(line)) {
sig = line;
break;
}
}
}
text = text.replace(sig, sig + " {{subst:RM relist}}");
if (relistingComment != '') {
var nextSection = false;
for (var i = templateIndex + 1; i < textToFind.length; i++) {
line = textToFind[i];
if (line.match(/^(==)[^=].+\1/)) {
nextSection = true;
var escapedLine = line.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&')
var regex = new RegExp('(' + escapedLine + ')(?![\s\S]*(' + escapedLine + '))', 'm');
text = text.replace(regex, ':<small>\'\'\'Relisting comment\'\'\': ' + relistingComment + ' ~~~~</small>\n\n' + line);
break;
}
}
if (!nextSection) {
text += '\n:<small>\'\'\'Relisting comment\'\'\': ' + relistingComment + ' ~~~~</small>';
}
}
talkpage.setPageText(text);
talkpage.setEditSummary('Relisted requested move' + movePlus.advert);
talkpage.save(Morebits.status.actionCompleted('Relisted.'));
document.getElementById("requestedmovetag").innerHTML = "";
setTimeout(function () { location.reload() }, 2000);
});
};
movePlus.notify = function movePlusNotify(e) {
if (e) e.preventDefault();
var wikiProjectTemplates = document.getElementsByClassName("wpb-project_link");
var wikiProjectNames = [];
var wikiProjects = [];
for (var i = 0; i < wikiProjectTemplates.length; i++) {
var wikiProjectName = wikiProjectTemplates[i].innerHTML;
var wikiProjectTalk = mw.Title.newFromText(wikiProjectTemplates[i].innerHTML).getTalkPage().toText();
if (!wikiProjectNames.includes(wikiProjectName)) {
wikiProjectNames.push(wikiProjectName);
wikiProjects.push(wikiProjectTalk);
}
}
var wikiProjectBannerShellHeaders = document.getElementsByClassName("wpb-header-combined");
for (var i = 0; i < wikiProjectBannerShellHeaders.length; i++) {
var subprojectList = wikiProjectBannerShellHeaders[i];
if (subprojectList.hasChildNodes() && subprojectList.children.length > 2) {
subprojectList = subprojectList.children[2];
if (subprojectList.hasChildNodes() && subprojectList.children.length > 0) {
subprojectList = subprojectList.children;
for (var j = 0; j < subprojectList.length; j++) {
var wikiProjectName = subprojectList[j].title;
if (mw.Title.newFromText(wikiProjectName)) {
var wikiProjectTalk = mw.Title.newFromText(wikiProjectName).getTalkPage().toText();
if (!wikiProjectNames.includes(wikiProjectName)) {
wikiProjectNames.push(wikiProjectName);
wikiProjects.push(wikiProjectTalk);
}
}
}
}
}
}
if (wikiProjects.length == 0) {
mw.notify('No WikiProject banners found on this page');
} else {
var Window = new Morebits.simpleWindow(600, 450);
Window.setTitle("Notify WikiProjects about requested move");
Window.setScriptName('Move+');
Window.addFooterLink('Script documentation', 'User:BilledMammal/Move+');
Window.addFooterLink('Give feedback', 'User talk:BilledMammal/Move+');
var form = new Morebits.quickForm(movePlus.notifyCheck);
form.append({
type: 'div',
label: 'WikiProjects with banners on this page:'
});
form.append({
type: 'checkbox',
name: 'wikiProject',
list: wikiProjects.map(function (wp) {
var wplabel = wikiProjectNames[wikiProjects.indexOf(wp)];
return { type: 'option', label: wplabel, value: wp };
})
});
if (wikiProjects[0] != 'none') {
form.append({ type: 'submit', label: 'Notify selected WikiProject(s)' });
}
var formResult = form.render();
Window.setContent(formResult);
Window.display();
}
};
movePlus.notifyCheck = function (e) {
var form = e.target;
movePlus.params = Morebits.quickForm.getInputData(form);
Morebits.simpleWindow.setButtonsEnabled(false);
Morebits.status.init(form);
var wikiProjectsToNotify = movePlus.params.wikiProject;
if (wikiProjectsToNotify.length == 0) {
Morebits.status.error('Error', 'No WikiProjects selected');
} else {
var uniqueWikiProjects = [];
var wikiProjectCount = 0;
for (var i = 0; i < wikiProjectsToNotify.length; i++) {
var talkpage = new Morebits.wiki.page(wikiProjectsToNotify[i], 'Checking ' + wikiProjectsToNotify[i] + '.');
talkpage.setFollowRedirect(true);
talkpage.load(function (talkpage) {
var wikiProjectToNotify = talkpage.getPageName();
if (!uniqueWikiProjects.includes(wikiProjectToNotify)) {
uniqueWikiProjects.push(wikiProjectToNotify);
}
wikiProjectCount++;
if (wikiProjectCount == wikiProjectsToNotify.length && uniqueWikiProjects.length > 0) {
movePlus.notifyGetSection(uniqueWikiProjects);
}
});
}
}
};
movePlus.notifyGetSection = function (wikiProjectsToNotify) {
var title_obj = mw.Title.newFromText(Morebits.pageNameNorm);
movePlus.talktitle = title_obj.getTalkPage().toText();
var talkpage = new Morebits.wiki.page(movePlus.talktitle, 'Getting section.');
talkpage.load(function (talkpage) {
var text = talkpage.getPageText();
var line;
var templateIndex = -1;
var rmSection;
var textToFind = text.split('\n');
for (var i = 0; i < textToFind.length; i++) {
line = textToFind[i];
if (/{{[Rr]equested move\/dated/.test(line)) {
templateIndex = i;
break;
}
}
for (var i = templateIndex; i >= 0; i--) {
line = textToFind[i];
if (line.match(/^(==)[^=].+\1/)) {
rmSection = line.match(/^(==)[^=](.+)\1/)[2].trim();
break;
}
}
movePlus.notifyEvaluate(wikiProjectsToNotify, rmSection);
});
};
movePlus.notifyEvaluate = function (wikiProjectsToNotify, moveSection) {
var wikiProjectsNotified = [];
var wikiProjectCount = 0;
for (var j = 0; j < wikiProjectsToNotify.length; j++) {
var talkpage = new Morebits.wiki.page(wikiProjectsToNotify[j], 'Notifying ' + wikiProjectsToNotify[j] + '.');
talkpage.setFollowRedirect(true);
talkpage.load(function (talkpage) {
var wikiProjectToNotify = talkpage.getPageName();
var text = talkpage.getPageText();
movePlus.talktitle = mw.Title.newFromText(Morebits.pageNameNorm).getTalkPage().toText();
var pageAndSection = movePlus.talktitle + "#" + moveSection;
var notified;
if (confirm("\"" + wikiProjectToNotify + "\" may have already been notified of the discussion. Do you wish to proceed?")) {
text += "\n\n== Requested move at [[" + pageAndSection + "]] ==\n[[File:Information.svg|30px|left]] There is a requested move discussion at [[" + pageAndSection + "]] that may be of interest to members of this WikiProject. ~~~~";
talkpage.setPageText(text);
talkpage.setEditSummary('Notifying of [[' + pageAndSection + '\|requested move]]' + movePlus.advert);
talkpage.save(Morebits.status.actionCompleted('Notified.'));
notified = true;
} else {
var cancelNotify = new Morebits.status('Error', 'Notification canceled', 'error');
notified = false;
}
if (notified) {
wikiProjectsNotified.push(wikiProjectToNotify);
}
wikiProjectCount++;
if (wikiProjectCount == wikiProjectsToNotify.length && wikiProjectsNotified.length > 0) {
movePlus.notifyListOnTalkPage(wikiProjectsNotified);
}
});
}
};
movePlus.notifyListOnTalkPage = function (wikiProjectsNotified) {
var discussionPage = new Morebits.wiki.page(movePlus.talktitle, 'Adding note about notification to requested move');
discussionPage.load(function (discussionPage) {
var discussionPageText = discussionPage.getPageText();
var templateFound = false;
var line;
var nextSection = false;
var textToFind = discussionPageText.split('\n');
for (var i = 0; i < textToFind.length; i++) {
line = textToFind[i];
if (templateFound == false) {
if (/{{[Rr]equested move\/dated/.test(line)) {
templateFound = true;
}
} else if (templateFound == true) {
if (line.match(/^(==)[^=].+\1/)) {
nextSection = true;
var escapedLine = line.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&')
var regex = new RegExp('(' + escapedLine + ')(?![\s\S]*(' + escapedLine + '))', 'm');
if (wikiProjectsNotified.length == 1) {
var wikiProjectToNotify = wikiProjectsNotified[0];
var displayName = wikiProjectToNotify.startsWith("Wikipedia talk:") ?
wikiProjectToNotify.substring("Wikipedia talk:".length) :
wikiProjectToNotify;
discussionPageText = discussionPageText.replace(regex, ':<small>Note: [[' + wikiProjectToNotify + '|' + displayName + ']] has been notified of this discussion. ~~~~</small>\n\n' + line);
} else {
var textToInsert = ':<small>Note: ';
for (var j = 0; j < wikiProjectsNotified.length; j++) {
var wikiProjectToNotify = wikiProjectsNotified[j];
var displayName = wikiProjectToNotify.startsWith("Wikipedia talk:") ?
wikiProjectToNotify.substring("Wikipedia talk:".length) :
wikiProjectToNotify;
textToInsert += '[[' + wikiProjectToNotify + '|' + displayName + ']]';
if (j == wikiProjectsNotified.length - 2) {
if (wikiProjectsNotified.length == 2) {
textToInsert += ' and ';
} else {
textToInsert += ', and ';
}
} else if (j != wikiProjectsNotified.length - 1) {
textToInsert += ', ';
}
}
textToInsert += ' have been notified of this discussion. ~~~~</small>\n\n';
discussionPageText = discussionPageText.replace(regex, textToInsert + line);
}
break;
}
}
}
if (!nextSection) {
if (wikiProjectsNotified.length == 1) {
var wikiProjectToNotify = wikiProjectsNotified[0];
var displayName = wikiProjectToNotify.startsWith("Wikipedia talk:") ?
wikiProjectToNotify.substring("Wikipedia talk:".length) :
wikiProjectToNotify;
discussionPageText += '\n:<small>Note: [[' + wikiProjectToNotify + '|' + displayName + ']] has been notified of this discussion. ~~~~</small>';
} else {
discussionPageText += '\n:<small>Note: ';
for (var j = 0; j < wikiProjectsNotified.length; j++) {
var wikiProjectToNotify = wikiProjectsNotified[j];
var displayName = wikiProjectToNotify.startsWith("Wikipedia talk:") ?
wikiProjectToNotify.substring("Wikipedia talk:".length) :
wikiProjectToNotify;
discussionPageText += '[[' + wikiProjectToNotify + '|' + displayName + ']]';
if (j == wikiProjectsNotified.length - 2) {
if (wikiProjectsNotified.length == 2) {
discussionPageText += ' and ';
} else {
discussionPageText += ', and ';
}
} else if (j != wikiProjectsNotified.length - 1) {
discussionPageText += ', ';
}
}
discussionPageText += ' have been notified of this discussion. ~~~~</small>';
}
}
discussionPage.setPageText(discussionPageText);
discussionPage.setEditSummary('Added note about notifying WikiProject about requested move' + movePlus.advert);
discussionPage.save(Morebits.status.actionCompleted('Note added.'));
setTimeout(function () { location.reload() }, 2000);
});
};
//Queues
// Add cleanup function
movePlus.cleanupIntervals = function movePlusCleanupIntervals() {
if (movePlus.moveInterval) {
clearInterval(movePlus.moveInterval);
movePlus.moveInterval = null;
}
if (movePlus.editInterval) {
clearInterval(movePlus.editInterval);
movePlus.editInterval = null;
}
// Clear any tracked intervals
if (movePlus.activeIntervals && movePlus.activeIntervals.length > 0) {
movePlus.activeIntervals.forEach(function (interval) {
if (interval) {
clearInterval(interval);
}
});
movePlus.activeIntervals = [];
}
};
movePlus.processMoveQueue = function movePlusProcessMoveQueue() {
if (movePlus.moveQueue.length > 0) {
let moveTask = movePlus.moveQueue.shift();
moveTask();
} else if (movePlus.moveQueue.length === 0) {
// Clear interval when queue is empty
if (movePlus.moveInterval) {
clearInterval(movePlus.moveInterval);
movePlus.moveInterval = null;
}
}
};
movePlus.startMoveQueue = function movePlusStartMoveQueue() {
if (!movePlus.moveInterval) {
var moveRateLimit = Morebits.userIsInGroup('sysop') ? 39 : Morebits.userIsInGroup('extendedmover') ? 15 : 7;
movePlus.moveInterval = setInterval(movePlus.processMoveQueue, 60000 / moveRateLimit);
}
};
movePlus.processEditQueue = function movePlusProcessEditQueue() {
if (movePlus.editQueue.length > 0) {
let editTask = movePlus.editQueue.shift();
editTask();
} else if (movePlus.editQueue.length === 0) {
// Clear interval when queue is empty
if (movePlus.editInterval) {
clearInterval(movePlus.editInterval);
movePlus.editInterval = null;
}
}
};
movePlus.startEditQueue = function movePlusStartEditQueue() {
if (!movePlus.editInterval) {
var editRateLimit = 20;
movePlus.editInterval = setInterval(movePlus.processEditQueue, 60000 / editRateLimit);
}
};
function allowBots(text, user) {
if (!new RegExp("\\{\\{\\s*(nobots|bots[^}]*)\\s*\\}\\}", "i").test(text)) return true;
return (new RegExp("\\{\\{\\s*bots\\s*\\|\\s*deny\\s*=\\s*([^}]*,\\s*)*" + user.replace(/([\(\)\*\+\?\.\-\:\!\=\/\^\$])/g, "\\$1") + "\\s*(?=[,\\}])[^}]*\\s*\\}\\}", "i").test(text)) ? false : new RegExp("\\{\\{\\s*((?!nobots)|bots(\\s*\\|\\s*allow\\s*=\\s*((?!none)|([^}]*,\\s*)*" + user.replace(/([\(\)\*\+\?\.\-\:\!\=\/\^\$])/g, "\\$1") + "\\s*(?=[,\\}])[^}]*|all))?|bots\\s*\\|\\s*deny\\s*=\\s*(?!all)[^}]*|bots\\s*\\|\\s*optout=(?!all)[^}]*)\\s*\\}\\}", "i").test(text);
}
//</nowiki>
lpxz8hshn3uxuanktblesmipynhm3f5
User:Cryptocurrency777/sandbox1
2
175334
743926
743880
2026-05-23T02:10:17Z
Cryptocurrency777
73698
743926
wikitext
text/x-wiki
'''TEST'''
{{Infobox musical artist|Name=Anti-Light|image=Antilight2025.png|caption=Anti-Light in 2025|Birth_name=Daniel|birth_date=August 15, 2003|birth_place=Denmark|Origin=Denmark|Genre=
*EDM
*Pop|Occupation=Singer, producer|Instrument=Vocals|Years_active=2023-present|website=https://anti-light.com|anti-light.com]}}
'''Anti-Light''' (real name '''Daniel'''; born Aug 15 2003) is a Danish singer-songwriter and producer. He started making music since the early 2020s. He is known for releasing his most successful single "[[On Sight]]" in 2025<ref>{{Citation | year=2025 | title=ON SIGHT | url=https://music.apple.com/us/song/on-sight-feat-pr%C3%B6z/1806778674 | access-date=18 May 2026}}</ref>.
== Early Life ==
Daniel was born on August 15, 2003 in Denmark. He got into the hobby of making music early as his parents both prominently played music.<ref name="TS">{{Citation | year=2025 | title=Anti-Light History | url=https://www.youtube.com/watch?v=ZEKdAAVGPa0 | access-date=20 May 2026|website=YouTube|language=en}}</ref> He often played guitar and soon transitioned to using digital apps to make music, such as Garageband and later [[FL Studio]].<ref name="TS"></ref> He became interested in EDM and hyperpop music at around the early 2020s. His musical influences included singers like [[Charli XCX]], [[Justin Bieber]], and [[Bladee]].<ref name="TS"></ref>
== Career ==
He started releasing music as Anti-Light in 2022 with the single "No Options", which was placed on a Spotify Editorial playlist. He later met fellow Danish singer Lytra in 2023 and started working on collaborations together.
== Personal Life ==
Daniel owned several cats. He got his stage name from his struggle with ocd and daydreaming, and decided his OC being an angel character fits those descriptions.
==Discography==
{| class="wikitable plainrowheaders" style="text-align:center;"
|+ List of singles, showing year released and album name
! scope="col" style="width:14em;" | Title
! scope="col"| Album
! scope="col" | Year
|-
! scope="row"|"No Options"
| rowspan="20" {{n/a|Non-album single}}
| rowspan="1"|2022
|-
! scope="row"|"Scene Slut" featuring Lytra
| rowspan="2"|2023
|-
! scope="row"|"Suffering" featuring Lytra
|-
! scope="row"|"Karma" featuring Lytra
| rowspan="3"|2024
|-
! scope="row"|"[[Not Too Late]]" featuring [[Clover (singer)|Clover]]
|-
! scope="row"|"Higher Dose" featuring Zhunii & [[4ortake]]
|-
! scope="row"|"Whats Ur Vibe" featuring [[Kalia]]
| rowspan="12"|2025
|-
! scope="row"|"[[On Sight]]" featuring EPITXME & Zhunii
|-
! scope="row"|"Smothered" featuring Qyurisuu & Kets4eki
|-
! scope="row"|"Silent Treatment" featuring [[Hydrakuma13]]
|-
! scope="row"|"Knives Out" featuring [[Xaduma]]
|-
! scope="row"|"Deadangel" featuring AfterDrk
|-
! scope="row"|"[[Cameras On]]"
|-
! scope="row"|"Oh My"
|-
! scope="row"|"Hot Topic"
|-
! scope="row"|"[[Upside Down]]"
|-
! scope="row"|"Kiss And Tell"
|-
! scope="row"|"Dynamite” featuring [[Clover (singer)|Clover]]
|-
! scope="row"|"Make you Jealous"
| rowspan="2"|2026
|-
! scope="row"|"Lifeline" featuring Lytra
|}
=== As Featured Artist ===
{| class="wikitable plainrowheaders" style="text-align:center;"
|+ List of singles, showing year released and album name
! scope="col" style="width:14em;" | Title
! scope="col"| Album
! scope="col" | Year
|-
! scope="row"|"[[Decay (song)|Decay]]" (AfterDrk featuring Anti-Light, Xyle, & [[Xaduma]])
| rowspan="2" {{n/a|Non-album single}}
| rowspan="2"|2025
|-
! scope="row"|"No More" (CR0T0N featuring Anti-Light)
|-
! scope="row"|"Spontaneous" (CR0T0N featuring Anti-Light)
| rowspan="1"|''Red Carpet Walk''
| rowspan="2"|2026
|-
! scope="row"|"Sex In The Air" ([[Xaduma]] featuring Anti-Light)
| rowspan="2" {{n/a|Non-album single}}
|-
|}
== References ==
{{reflist}}
[[Category:2003 births]]
[[Category:Living people]]
6ixpuil8fmu2lkfsk7g9nbxxsgizh64
User:Chaotic Enby/AIDiffBrowser.js
2
175433
743918
743877
2026-05-22T21:47:52Z
Chaotic Enby
58843
743918
javascript
text/javascript
// Chapter 0: I really wanted this in an object and I could've just as well used regex
const emptyRev = 742978 // 1354670824 for enwiki
const AINBStatusStyle = {
needsreview: {
bg: "#FAEEDA",
fg: "#854F0B",
label: "Needs review",
toReview: true,
},
inprogress: {
bg: "#E6F1FB",
fg: "#0C447C",
label: "In progress",
toReview: true
},
clean: {
bg: "#EAF3DE",
fg: "#27500A",
label: "Clean",
toReview: false
},
draftified: {
bg: "#F1EFE8",
fg: "#2C2C2A",
label: "Draftified",
toReview: false
},
stubified: {
bg: "#EEEDFE",
fg: "#3C3489",
label: "Stubified",
toReview: false
},
g15: {
bg: "#FAECE7",
fg: "#4A1B0C",
label: "G15 eligible",
toReview: true
},
afd: {
bg: "#FAEEDA",
fg: "#633806",
label: "AfD",
toReview: false
},
deleted: {
bg: "#FCEBEB",
fg: "#501313",
label: "Deleted",
toReview: false
},
kept: {
bg: "#E1F5EE",
fg: "#085041",
label: "Kept",
toReview: false
},
restored: {
bg: "#E6F1FB",
fg: "#185FA5",
label: "Restored",
toReview: false
},
default: {
bg: "#F1EFE8",
fg: "#2C2C2A",
label: "Unknown",
toReview: true
}
};
// Chapter 1: When we build the main window thing
function setupAppShell() {
const root = document.body;
root.innerHTML = "";
const app = document.createElement("div");
app.id = "ainb-app";
const sidebar = document.createElement("div");
sidebar.id = "ainb-sidebar";
const main = document.createElement("div");
main.id = "ainb-main";
app.appendChild(sidebar);
app.appendChild(main);
root.appendChild(app);
}
// Chapter 2: When we load the AINB data and build the sidebar thing
function pruneIndex(index) {
const cleaned = {};
for (const [user, cats] of Object.entries(index)) {
const nonEmptyCats = {};
for (const [status, items] of Object.entries(cats)) {
if (items && items.length > 0) {
nonEmptyCats[status] = items;
}
}
if (Object.keys(nonEmptyCats).length > 0) {
cleaned[user] = nonEmptyCats;
}
}
return cleaned;
}
function buildAINBIndexFromWikitext(wikitext) {
const result = {};
// --- Split into level-2 sections ---
const sectionRegex = /^==\s*(.+?)\s*==\s*$/gm;
const sections = [];
let match;
let lastIndex = 0;
while ((match = sectionRegex.exec(wikitext)) !== null) {
const heading = match[1].trim();
const start = match.index;
if (sections.length > 0) {
sections[sections.length - 1].text = wikitext.slice(lastIndex, start);
}
sections.push({ heading, text: "" });
lastIndex = sectionRegex.lastIndex;
}
if (sections.length > 0) {
sections[sections.length - 1].text = wikitext.slice(lastIndex);
}
// --- Process each section ---
for (const section of sections) {
const text = section.text;
// 1) Extract username from {{AINB status ...}}
const statusTplRegex = /\{\{\s*AINB\s+status([\s\S]*?)\}\}/i;
const statusMatch = text.match(statusTplRegex);
if (!statusMatch) continue;
const tplBody = statusMatch[1];
const userMatch = tplBody.match(/\|\s*user\s*=\s*([^\|\n]+)/i);
if (!userMatch) continue;
const username = userMatch[1].trim();
if (!username) continue;
if (!result[username]) {
result[username] = {};
}
// 2) Extract the AINB summary HTML block
const summaryRegex = /<!--\s*AINB-SUMMARY\s*-->([\s\S]*?)<!--\s*\/AINB-SUMMARY\s*-->/i;
const summaryMatch = text.match(summaryRegex);
if (!summaryMatch) continue;
const summaryHTML = summaryMatch[1];
// 3) Parse that HTML with DOMParser
const doc = new DOMParser().parseFromString(summaryHTML, "text/html");
const grid = doc.querySelector(".ainb-summary-grid");
if (!grid) continue;
const columns = grid.querySelectorAll(".ainb-summary-column");
columns.forEach(col => {
let statusKey = null;
// Check all defined statuses dynamically
for (const status of Object.keys(AINBStatusStyle)) {
if (col.classList.contains(`ainb-status-${status}`)) {
statusKey = status;
break;
}
}
if (!statusKey) return;
const items = Array.from(col.querySelectorAll("li")).map(li => {
const link = li.querySelector("a");
return (link ? link.textContent : li.textContent).trim().replace(/^\[\[(.*?)\]\]$/, "$1");
});
result[username][statusKey] = items;
});
}
return pruneIndex(result);
}
function loadAINBIndex() {
const api = new mw.Api();
return api.get({
action: "query",
prop: "revisions",
titles: "Wikipedia:AI noticeboard",
rvslots: "main",
rvprop: "content",
formatversion: 2
}).then(data => {
const page = data.query.pages[0];
const wikitext = page.revisions[0].slots.main.content;
return buildAINBIndexFromWikitext(wikitext);
});
}
function renderSidebar(index) {
const sidebar = document.getElementById("ainb-sidebar");
sidebar.innerHTML = "<h2>Review queue</h2>";
for (const [user, categories] of Object.entries(index)) {
const userDiv = document.createElement("div");
userDiv.className = "ainb-collapsible";
const userHeader = document.createElement("div");
userHeader.className = "ainb-collapsible-header";
userHeader.textContent = "▸ " + user;
userHeader.onclick = () => {
// Close other users
document.querySelectorAll("#ainb-sidebar > .ainb-collapsible-open").forEach(el => {
if (el !== userDiv) {
el.classList.remove("ainb-collapsible-open");
const otherHeader = el.querySelector(".ainb-collapsible-header");
if (otherHeader) {
otherHeader.textContent = "▸ " + otherHeader.textContent.substring(2);
}
}
});
userDiv.classList.toggle("ainb-collapsible-open");
userHeader.textContent =
(userDiv.classList.contains("ainb-collapsible-open") ? "▾ " : "▸ ") + user;
};
const userContent = document.createElement("div");
userContent.className = "ainb-collapsible-content";
// Status categories
for (const [status, items] of Object.entries(categories)) {
const statusDiv = document.createElement("div");
statusDiv.className = "ainb-collapsible";
const statusStyle = AINBStatusStyle[status] || AINBStatusStyle.default;
// Determine if this status should be open by default (statuses that need review action)
const shouldOpenByDefault = AINBStatusStyle[status] ? AINBStatusStyle[status].toReview : AINBStatusStyle.default.toReview;
if (shouldOpenByDefault) {
statusDiv.classList.add("ainb-collapsible-open");
}
const statusHeader = document.createElement("div");
statusHeader.className = "ainb-collapsible-header";
const arrow = shouldOpenByDefault ? "▾" : "▸";
statusHeader.innerHTML = `
<span class="ainb-pill" style="
background:${statusStyle.bg};
color:${statusStyle.fg};
">${arrow} ${statusStyle.label}: ${items.length}</span>
`;
statusHeader.onclick = () => {
statusDiv.classList.toggle("ainb-collapsible-open");
const arrow = statusDiv.classList.contains("ainb-collapsible-open") ? "▾" : "▸";
statusHeader.innerHTML = `
<span class="ainb-pill" style="
background:${statusStyle.bg};
color:${statusStyle.fg};
">${arrow} ${statusStyle.label}: ${items.length}</span>
`;
};
const statusContent = document.createElement("div");
statusContent.className = "ainb-collapsible-content";
const ul = document.createElement("ul");
items.forEach(title => {
const li = document.createElement("li");
li.textContent = title;
li.style.cursor = "pointer";
li.onclick = () => openArticle(title, user);
ul.appendChild(li);
});
statusContent.appendChild(ul);
statusDiv.appendChild(statusHeader);
statusDiv.appendChild(statusContent);
userContent.appendChild(statusDiv);
}
userDiv.appendChild(userHeader);
userDiv.appendChild(userContent);
sidebar.appendChild(userDiv);
}
}
// Chapter 3: When we do the thing we do
function fetchRecentEdits(title) {
const api = new mw.Api();
return api.get({
action: "query",
prop: "revisions",
titles: title,
rvlimit: 500,
rvprop: "ids|timestamp|user",
rvdir: "older",
formatversion: 2
}).then(data => {
const page = data.query.pages[0];
return page.revisions || [];
});
}
function findEarliestEditByUser(revisions, username) {
// Filter all edits by the user
const userEdits = revisions.filter(rev => rev.user === username);
if (userEdits.length === 0) return null;
// Revisions are newest → oldest, so the earliest is the LAST one
return userEdits[userEdits.length - 1];
}
function fetchInlineDiff(fromRev, toRev) {
const api = new mw.Api();
return api.get({
action: "compare",
fromrev: fromRev,
torev: toRev,
prop: "diff",
difftype: "inline",
formatversion: 2
}).then(data => data.compare.body);
}
function fetchRevisionWikitext(revid) {
const api = new mw.Api();
return api.get({
action: "query",
prop: "revisions",
revids: revid,
rvslots: "main",
rvprop: "content",
formatversion: 2
}).then(data => {
const page = data.query.pages[0];
return page.revisions[0].slots.main.content;
});
}
function parseInlineDiffHTML(html) {
const wrapped = `<table>${html}</table>`;
return new DOMParser().parseFromString(wrapped, "text/html");
}
function splitWikitextLines(text) {
return text ? text.match(/[^\r\n]*\r?\n|[^\r\n]+/g) || [] : [];
}
function joinWikitextLines(lines) {
return lines.join("");
}
function ensureTrailingLinebreak(text) {
if (!text) {
return "";
}
return /\r?\n$/.test(text) ? text : text + "\n";
}
function parseLineRange(label) {
if (!label) {
return null;
}
const numbers = label.match(/\d+/g);
if (!numbers || numbers.length === 0) {
return null;
}
const start = Number(numbers[0]);
const end = numbers.length > 1 ? Number(numbers[1]) : start;
if (!Number.isFinite(start) || !Number.isFinite(end)) {
return null;
}
return { start, end: Math.max(start, end) };
}
function extractInlineBlocks(doc) {
const blocks = [];
const rows = doc.querySelectorAll("tr");
let currentHeader = null;
let currentSourceLine = 1;
rows.forEach(tr => {
const cell = tr.querySelector("td, th");
if (!cell) return;
for (const child of cell.children) {
if (child.classList.contains("mw-diff-inline-header")) {
currentHeader = child.textContent.trim();
const parsed = parseLineRange(currentHeader);
if (parsed) {
currentSourceLine = parsed.start;
}
continue;
}
let type = null;
let beforeText = "";
let afterText = "";
let displayBeforeHTML = "";
let displayAfterHTML = "";
if (child.classList.contains("mw-diff-inline-context")) {
type = "context";
beforeText = child.textContent;
afterText = child.textContent;
displayBeforeHTML = child.textContent.trim();
displayAfterHTML = child.textContent.trim();
} else if (child.classList.contains("mw-diff-inline-changed")) {
type = "changed";
const parsed = parseChangedBlock(child);
beforeText = parsed.beforeText;
afterText = parsed.afterText;
displayBeforeHTML = parsed.displayBeforeHTML;
displayAfterHTML = parsed.displayAfterHTML;
} else if (child.classList.contains("mw-diff-inline-added") || child.classList.contains("mw-diff-inline-moved-destination")) {
type = "added";
beforeText = "";
afterText = child.textContent;
displayBeforeHTML = "";
displayAfterHTML = child.textContent.trim();
} else if (child.classList.contains("mw-diff-inline-deleted") || child.classList.contains("mw-diff-inline-moved-source")) {
type = "deleted";
beforeText = child.textContent;
afterText = "";
displayBeforeHTML = child.textContent.trim();
displayAfterHTML = "";
}
if (type) {
const sourceLineCount = (type === "added") ? 0 : splitWikitextLines(beforeText).length;
blocks.push({
type,
header: currentHeader,
sourceStartLine: currentSourceLine,
sourceLineCount,
beforeText,
afterText,
displayBeforeHTML,
displayAfterHTML
});
currentSourceLine += sourceLineCount;
currentHeader = null;
}
}
});
return blocks;
}
function parseChangedBlock(div) {
let beforeText = "";
let afterText = "";
let beforeHTML = "";
let afterHTML = "";
div.childNodes.forEach(node => {
if (node.nodeType === Node.TEXT_NODE) {
beforeText += node.textContent;
afterText += node.textContent;
beforeHTML += node.textContent;
afterHTML += node.textContent;
} else if (node.tagName === "DEL") {
beforeText += node.textContent;
beforeHTML += `<del>${node.textContent}</del>`;
} else if (node.tagName === "INS") {
afterText += node.textContent;
afterHTML += `<ins>${node.textContent}</ins>`;
}
});
return {
type: "changed",
beforeText,
afterText,
beforeHTML,
afterHTML,
displayBeforeHTML: beforeHTML.trim(),
displayAfterHTML: afterHTML.trim(),
html: div.innerHTML.trim()
};
}
function applyInlineStyling(html) {
return html
.replace(/<del>(.*?)<\/del>/g, '<span class="ainb-inline-del">$1</span>')
.replace(/<ins>(.*?)<\/ins>/g, '<span class="ainb-inline-ins">$1</span>');
}
const blockIcons = {
"changed": ["+", "+"],
"added": ["−", "+"],
"deleted": ["+", "−"],
"context": ["=", "="],
};
function renderBlocks(diffModel, title, username) {
const blocks = diffModel.blocks || [];
const container = document.createElement("div");
container.className = "ainb-diff-container";
blocks.forEach(block => {
// Default selection to "before"
block.selection = "before";
const row = document.createElement("div");
row.className = `ainb-diff-block ${block.type}`;
// Optional header (Line X:)
if (block.header) {
const header = document.createElement("div");
header.className = "ainb-diff-header";
header.textContent = block.header;
row.appendChild(header);
}
// --- LEFT SIDE (before) ---
const left = document.createElement("div");
left.className = "ainb-diff-side before";
left.innerHTML = `<div class="ainb-diff-text">${applyInlineStyling(block.displayBeforeHTML || block.beforeHTML || block.displayBeforeHTML || block.beforeText || "")}</div>`;
// --- CENTER BUTTON ---
const center = document.createElement("div");
center.className = "ainb-diff-center";
let centerBtn = null;
if (block.type === "context") {
const equalSign = document.createElement("span");
equalSign.className = "ainb-diff-equal";
equalSign.textContent = "=";
center.appendChild(equalSign);
} else {
centerBtn = document.createElement("button");
centerBtn.className = "ainb-diff-btn";
center.appendChild(centerBtn);
}
// --- RIGHT SIDE (after) ---
const right = document.createElement("div");
right.className = "ainb-diff-side after";
right.innerHTML = `<div class="ainb-diff-text">${applyInlineStyling(block.displayAfterHTML || block.afterHTML || block.displayAfterHTML || block.afterText || "")}</div>`;
// --- SELECTION HANDLERS ---
function updateSelectionUI() {
// Reset classes
left.classList.remove("selected", "dimmed");
right.classList.remove("selected", "dimmed");
if (centerBtn) {
centerBtn.classList.remove("selected-before", "selected-after");
}
if (block.selection === "before") {
left.classList.add("selected");
right.classList.add("dimmed");
if (centerBtn) {
centerBtn.classList.add("selected-before");
centerBtn.textContent = "◀";
}
} else if (block.selection === "after") {
right.classList.add("selected");
left.classList.add("dimmed");
if (centerBtn) {
centerBtn.classList.add("selected-after");
centerBtn.textContent = "▶";
}
}
}
if (centerBtn) {
centerBtn.addEventListener("click", () => {
block.selection = block.selection === "before" ? "after" : "before";
updateSelectionUI();
});
}
// Initial UI state
updateSelectionUI();
// Append sides
row.appendChild(left);
row.appendChild(center);
row.appendChild(right);
container.appendChild(row);
});
return container;
}
// Chapter 4: Where we take an aside to build a preview screen
function reconstructWikitext(diffData) {
const originalLines = splitWikitextLines(diffData.originalWikitext || "");
const blocks = (diffData.blocks || []).filter(block => block.type !== "context");
const outputLines = [];
let cursor = 0; // 0-indexed current line in originalLines
for (const block of blocks) {
const startIdx = block.sourceStartLine - 1; // 0-indexed
// Catch up unmodified lines
if (startIdx > cursor) {
outputLines.push(...originalLines.slice(cursor, startIdx));
cursor = startIdx;
}
// Append the selected text
const selectedText = block.selection === "after" ? (block.afterText || "") : (block.beforeText || "");
if (selectedText) {
outputLines.push(ensureTrailingLinebreak(selectedText));
}
// Advance cursor over the original lines that this block replaces
cursor = startIdx + block.sourceLineCount;
}
// Append any remaining original lines
if (cursor < originalLines.length) {
outputLines.push(...originalLines.slice(cursor));
}
return joinWikitextLines(outputLines);
}
function showPreviewScreen(diffData, title, username) {
const main = document.getElementById("ainb-main");
main.innerHTML = ""; // Clear diff UI
const header = document.createElement("div");
header.className = "ainb-main-header";
header.innerHTML = `<h2><b>Article:</b> ${title} <span class="title-notice">(preview)</span> <span class="ainb-user-badge">(User: ${username})</span></h2>`;
const body = document.createElement("div");
body.className = "ainb-main-body ainb-preview-wrapper";
const textarea = document.createElement("textarea");
textarea.className = "ainb-preview-textarea";
textarea.value = reconstructWikitext(diffData);
body.appendChild(textarea);
const footer = document.createElement("div");
footer.className = "ainb-main-footer";
const backBtn = document.createElement("button");
backBtn.textContent = "Back to diff";
backBtn.className = "ainb-action-btn ainb-action-preview";
backBtn.addEventListener("click", () => {
openArticle(title, username);
});
footer.appendChild(backBtn);
main.appendChild(header);
main.appendChild(body);
main.appendChild(footer);
}
function postArticleEdit(diffData, title, username) {
const main = document.getElementById("ainb-main");
const originalHTML = main.innerHTML;
main.innerHTML = `
<div class="ainb-main-header">
<h2>${title} / <span class="ainb-user-badge"> ${username}</span></h2>
</div>
<div class="ainb-main-body">
<div class="ainb-status">Posting edit to <b>${title}</b>...</div>
</div>
`;
const newWikitext = reconstructWikitext(diffData);
const api = new mw.Api();
api.postWithToken("csrf", {
action: "edit",
title: title,
text: newWikitext,
summary: `Cleaned up suspected AI-generated edits by [[User:${username}]] via [[User:Chaotic_Enby/AIDiffBrowser|AIDiffBrowser]]`,
bot: false
}).then(() => {
main.innerHTML = `
<div class="ainb-main-header">
<h2>${title} / <span class="ainb-user-badge"> ${username}</span></h2>
</div>
<div class="ainb-main-body">
<div class="ainb-status" style="color: #6aab6a;">Success! Edit posted to <b>${title}</b>.</div>
</div>
`;
}).catch(err => {
main.innerHTML = `
<div class="ainb-main-header">
<h2>${title} / <span class="ainb-user-badge"> ${username}</span></h2>
</div>
<div class="ainb-main-body">
<div class="ainb-status" style="color: #c95c5c;">Error posting edit: ${err}</div>
</div>
<div class="ainb-main-footer">
<button class="ainb-action-btn ainb-action-preview" id="ainb-error-back-btn">Back to diff</button>
</div>
`;
document.getElementById("ainb-error-back-btn").addEventListener("click", () => {
main.innerHTML = originalHTML;
// Rebind events since replacing innerHTML destroys them
openArticle(title, username);
});
});
}
function tagPage(revId, title, username, tag) {
if (tag === "g15") {
tagCode = "{{db-g15}}\n\n";
summary = 'Tagged for [[WP:G15|CSD G15]]';
} else if (tag === "prod") {
tagCode = "{{subst:prod llm}}\n\n";
summary = 'Tagged for [[WP:LLMPROD|LLMPROD]]';
}
const main = document.getElementById("ainb-main");
main.innerHTML = `
<div class="ainb-main-header">
<h2>${title} / <span class="ainb-user-badge"> ${username}</span></h2>
</div>
<div class="ainb-main-body">
<div class="ainb-status">Tagging page for ${tag === "g15" ? "G15 deletion" : "LLMPROD"}...</div>
</div>
`;
const api = new mw.Api();
fetchRevisionWikitext(revId).then((wikitext) => {
api.postWithToken("csrf", {
action: "edit",
title: title,
text: tagCode + wikitext,
summary: summary + " via [[User:Chaotic_Enby/AIDiffBrowser|AIDiffBrowser]]",
bot: false
})}).then(() => {
main.innerHTML = `
<div class="ainb-main-header">
<h2>${title} / <span class="ainb-user-badge"> ${username}</span></h2>
</div>
<div class="ainb-main-body">
<div class="ainb-status" style="color: #6aab6a;">Success! Page tagged for ${tag === "g15" ? "G15 deletion" : "LLMPROD"}.</div>
</div>
`;
}).catch(err => {
main.innerHTML = `
<div class="ainb-main-header">
<h2>${title} / <span class="ainb-user-badge"> ${username}</span></h2>
</div>
<div class="ainb-main-body">
<div class="ainb-status" style="color: #c95c5c;">Error tagging page: ${err}</div>
</div>
`;
});
}
// Chapter 3.2: Where we go back to the main screen
function openArticle(title, username) {
const main = document.getElementById("ainb-main");
main.innerHTML = `
<div class="ainb-main-header">
<h2>${title} / <span class="ainb-user-badge"> ${username}</span></h2>
</div>
<div class="ainb-main-body">
<div class="ainb-status">Loading diff...</div>
</div>
`;
fetchRecentEdits(title)
.then(revs => {
const beforeRevObj = findEarliestEditByUser(revs, username);
if (!beforeRevObj) {
main.innerHTML = `
<div class="ainb-main-header">
<h2>${title} / <span class="ainb-user-badge"> ${username}</span></h2>
</div>
<div class="ainb-main-body">
<div class="ainb-status">No edits by <b>${username}</b> could be found.</div>
</div>
`;
return null;
}
const beforeRev = beforeRevObj.parentid || emptyRev; // Use empty revision ID for first edits
const isFirstEdit = !beforeRevObj.parentid; // Track if this is a first-edit scenario
const currentRev = revs[0].revid; // newest revision
return Promise.all([
fetchRevisionWikitext(beforeRev),
fetchInlineDiff(beforeRev, currentRev)
]).then(([originalWikitext, diffHTML]) => ({
originalWikitext,
diffHTML,
isFirstEdit,
currentRev
}));
})
.then(diffData => {
if (!diffData) return;
const doc = parseInlineDiffHTML(diffData.diffHTML);
const blocks = extractInlineBlocks(doc);
const diffModel = {
originalWikitext: diffData.originalWikitext,
blocks,
isFirstEdit: diffData.isFirstEdit,
currentRev: diffData.currentRev
};
main.innerHTML = "";
const header = document.createElement("div");
header.className = "ainb-main-header";
if(diffData.isFirstEdit) {
header.innerHTML = `<h2>${title} / <span class="ainb-user-badge"> ${username}</span> <span class="ainb-page-badge">(page creator)</span></h2>`;
} else {
header.innerHTML = `<h2>${title} / <span class="ainb-user-badge"> ${username}</span></h2>`;
}
const body = document.createElement("div");
body.className = "ainb-main-body";
body.appendChild(renderBlocks(diffModel, title, username));
const footer = document.createElement("div");
footer.className = "ainb-main-footer";
const previewBtn = document.createElement("button");
previewBtn.textContent = "Preview";
previewBtn.className = "ainb-action-btn ainb-action-preview";
previewBtn.addEventListener("click", () => {
showPreviewScreen(diffModel, title, username);
});
const postBtn = document.createElement("button");
postBtn.textContent = "Post";
postBtn.className = "ainb-action-btn ainb-action-post";
postBtn.addEventListener("click", () => {
postArticleEdit(diffModel, title, username);
});
footer.appendChild(previewBtn);
footer.appendChild(postBtn);
// Add extra buttons for first-edit articles
if (diffModel.isFirstEdit) {
const prodBtn = document.createElement("button");
prodBtn.textContent = "LLMPROD";
prodBtn.className = "ainb-action-btn ainb-action-destructive";
prodBtn.addEventListener("click", () => {
tagPage(diffModel.currentRev, title, username, "prod");
});
footer.appendChild(prodBtn);
const g15Btn = document.createElement("button");
g15Btn.textContent = "G15";
g15Btn.className = "ainb-action-btn ainb-action-destructive";
g15Btn.addEventListener("click", () => {
tagPage(diffModel.currentRev, title, username, "g15");
});
footer.appendChild(g15Btn);
}
main.appendChild(header);
main.appendChild(body);
main.appendChild(footer);
})
.catch(err => {
main.innerHTML = `
<div class="ainb-main-header">
<h2>${title} / <span class="ainb-user-badge"> ${username}</span></h2>
</div>
<div class="ainb-main-body">
<div class="ainb-status">Error loading diff: ${err}</div>
</div>
`;
});
}
// Chapter N-1: The fancy stuff
function setupCSS(){
mw.util.addCSS(`
:root {
--ainb-hue: 220;
--ainb-hue-2: 240;
--ainb-hue-accent: 293;
--ainb-hue-accent: 324;
}
#ainb-app {
background-color: hsl(var(--ainb-hue), 10%, 10%);
color: white;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
font-family: system-ui, sans-serif;
}
#ainb-app h2 {
font-family: system-ui, sans-serif;
font-weight: 600;
letter-spacing: 1.5px;
padding-left: 10px;
border-bottom: none;
color: hsl(var(--ainb-hue), 70%, 93%);
}
#ainb-sidebar {
padding: 0px;
background: linear-gradient(135deg, hsl(var(--ainb-hue), 30%, 12%) 0%, hsl(var(--ainb-hue-2), 30%, 14%) 100%);
z-index: 1;
width: 280px;
overflow-y: auto;
letter-spacing: 0.5px;
}
#ainb-sidebar h2 {
margin: 10px;
height: 34px;
}
.ainb-collapsible-header {
cursor: pointer;
user-select: none;
padding: 5px 0;
}
.ainb-collapsible-content li:hover {
color: #e7e7e7;
}
.ainb-collapsible-content {
display: none;
margin-left: 12px;
}
#ainb-sidebar > .ainb-collapsible {
padding: 6px 6px 6px 11px;
color: hsl(var(--ainb-hue), var(--ainb-sat), 60%);
}
#ainb-sidebar > .ainb-collapsible:not(.ainb-collapsible-open):hover {
background: linear-gradient(135deg, hsl(var(--ainb-hue), 30%, 14%) 0%, hsl(var(--ainb-hue-2), 30%, 15%) 100%);
color: white;
}
#ainb-sidebar > .ainb-collapsible-open {
background: linear-gradient(135deg, hsl(var(--ainb-hue-accent), 78%, 23%) 0%, hsl(var(--ainb-hue-accent-2), 81%, 31%) 100%);
color: white;
}
.ainb-collapsible-open > .ainb-collapsible-content {
display: block;
}
.ainb-pill {
display: inline-block;
padding: 1px 8px;
border-radius: 10px;
font-size: 88%;
font-weight: 500;
}
.ainb-collapsible-content ul {
margin: 4px 0 6px 6px;
}
.ainb-collapsible-content li {
list-style: none;
font-size: 88%;
margin: 7px 0;
}
#ainb-main {
flex: 1 1 0%;
display: flex;
flex-direction: column;
overflow: hidden;
background: linear-gradient(135deg, hsl(var(--ainb-hue), 32%, 15%) 0%, hsl(var(--ainb-hue-2), 42%, 15%) 100%);
}
.ainb-main-header {
flex-shrink: 0;
padding: 15px 20px;
display: flex;
align-items: center;
height: 40px;
}
.ainb-main-header h2 {
margin: 0;
font-size: 18px;
padding-left: 0 !important;
}
.ainb-user-badge {
color: hsl(var(--ainb-hue), 90%, 70%);
}
.ainb-page-badge {
font-size: 70%;
}
.ainb-main-body {
flex: 1 1 auto;
overflow-y: auto;
background: linear-gradient(135deg, hsl(var(--ainb-hue), 30%, 17%) 0%, hsl(var(--ainb-hue-2), 40%, 17%) 100%);
display: flex;
}
.ainb-main-footer {
flex-shrink: 0;
padding: 12px 20px;
display: flex;
justify-content: flex-end;
gap: 20px;
}
.ainb-status {
margin: auto;
text-align: center;
}
.ainb-diff-container {
display: flex;
flex-direction: column;
font-family: monospace, system-ui, sans-serif;
width: 100%;
}
.ainb-diff-block {
display: grid;
grid-template-columns: 1fr auto 1fr;
}
.ainb-diff-center {
display: flex;
justify-content: center;
align-items: center;
}
.ainb-diff-btn, .ainb-diff-equal {
flex-grow: 1;
height: 100%;
display: flex;
align-items: center;
border: none;
padding-top: 0.2em;
padding-bottom: 0.28em;
}
.ainb-diff-equal {
display: flex;
align-items: center;
justify-content: center;
color: hsl(var(--ainb-hue), 10%, 60%);
font-weight: bold;
font-size: 21px;
width: 40px;
}
.ainb-diff-btn {
transition: background-color 0.15s, color 0.15s;
width: 40px;
justify-content: center;
font-size: 15px;
cursor: pointer;
background: none;
}
.ainb-diff-btn.selected-before {
color: #f447a0;
}
.ainb-diff-btn.selected-after {
color: #d4ac6a;
}
.added .ainb-diff-btn.selected-before, .deleted .ainb-diff-btn.selected-after {
color: hsl(var(--ainb-hue), 10%, 70%);
}
.ainb-diff-side {
white-space: pre-wrap;
line-height: 1.45;
font-size: 14px;
display: flex;
justify-content: space-between;
align-items: center;
overflow: hidden;
padding: 5px 20px;
}
.before, .after {
flex-direction: row;
}
.context :is(.before, .after) {
background-color: hsla(var(--ainb-hue), 20%, 26%, 30%);
}
:is(.changed, .deleted) .before {
background-color: #97567d;
}
:is(.changed, .added) .after {
background-color: #a49379;
}
:is(.added .before, .deleted .after) .ainb-diff-text {
text-align: center;
width: 100%;
}
:is(.added .before, .deleted .after) .ainb-diff-text::before {
content: "∅";
color: #c2c2c2;
}
.ainb-diff-header {
grid-column: 1 / -1;
font-size: 14px;
text-align: center;
font-weight: 600;
color: hsl(var(--ainb-hue), var(--ainb-sat), 60%);
padding-top: 0.5em;
padding-bottom: 0.58em;
}
.ainb-inline-del {
background: #ffe5e5;
color: #b30000;
text-decoration: line-through;
padding: 0 2px;
border-radius: 3px;
}
.ainb-inline-ins {
background: #e6ffe6;
color: #006600;
padding: 0 2px;
border-radius: 3px;
}
.ainb-diff-side.dimmed:not(.context .ainb-diff-side) {
opacity: 0.3;
}
.ainb-action-btn {
padding: 8px 16px;
font-size: 15px;
letter-spacing: 1px;
border: none;
background: transparent;
cursor: pointer;
transition: color 0.15s;
margin: auto 0;
font-family: system-ui, sans-serif;
font-weight: 600;
}
.ainb-action-preview {
color: hsl(var(--ainb-hue-accent), 50%, 90%);
}
.ainb-action-preview:hover {
color: hsl(var(--ainb-hue-accent), 50%, 95%);
}
.ainb-action-post {
color: hsl(var(--ainb-hue-accent), 90%, 70%);
}
.ainb-action-post:hover {
color: hsl(var(--ainb-hue-accent), 90%, 75%);
}
.ainb-action-destructive {
color: hsl(350, 70%, 70%);
}
.ainb-action-destructive:hover {
color: hsl(350, 70%, 75%);
}
.ainb-preview-wrapper {
display: flex;
flex-direction: column;
gap: 16px;
padding: 20px;
}
.ainb-preview-textarea {
width: 100%;
height: 60vh;
font-family: monospace, system-ui, sans-serif;
font-size: 14px;
padding: 12px;
border-radius: 6px;
border: 1px solid #ccc;
resize: vertical;
}
.title-notice {
font-size: 80%;
color: grey;
}
`);
}
// Chapter N: When they actually launch the thing
if(mw.config.get("wgPageName") === "User:Chaotic_Enby/AIDiffBrowser/run") {
setupCSS();
setupAppShell();
loadAINBIndex().then(index => {
renderSidebar(index);
});
}
qeau9jia1vmcpzpfz8nlqrcyssm2giq
743919
743918
2026-05-22T21:55:12Z
Chaotic Enby
58843
743919
javascript
text/javascript
// Chapter 0: I really wanted this in an object and I could've just as well used regex
const emptyRev = 742978 // 1354670824 for enwiki
const AINBStatusStyle = {
needsreview: {
bg: "#FAEEDA",
fg: "#854F0B",
label: "Needs review",
toReview: true,
},
inprogress: {
bg: "#E6F1FB",
fg: "#0C447C",
label: "In progress",
toReview: true
},
clean: {
bg: "#EAF3DE",
fg: "#27500A",
label: "Clean",
toReview: false
},
draftified: {
bg: "#F1EFE8",
fg: "#2C2C2A",
label: "Draftified",
toReview: false
},
stubified: {
bg: "#EEEDFE",
fg: "#3C3489",
label: "Stubified",
toReview: false
},
g15: {
bg: "#FAECE7",
fg: "#4A1B0C",
label: "G15 eligible",
toReview: true
},
afd: {
bg: "#FAEEDA",
fg: "#633806",
label: "AfD",
toReview: false
},
deleted: {
bg: "#FCEBEB",
fg: "#501313",
label: "Deleted",
toReview: false
},
kept: {
bg: "#E1F5EE",
fg: "#085041",
label: "Kept",
toReview: false
},
restored: {
bg: "#E6F1FB",
fg: "#185FA5",
label: "Restored",
toReview: false
},
default: {
bg: "#F1EFE8",
fg: "#2C2C2A",
label: "Unknown",
toReview: true
}
};
// Chapter 1: When we build the main window thing
function setupAppShell() {
const root = document.body;
root.innerHTML = "";
const app = document.createElement("div");
app.id = "ainb-app";
const sidebar = document.createElement("div");
sidebar.id = "ainb-sidebar";
const main = document.createElement("div");
main.id = "ainb-main";
app.appendChild(sidebar);
app.appendChild(main);
root.appendChild(app);
}
// Chapter 2: When we load the AINB data and build the sidebar thing
function pruneIndex(index) {
const cleaned = {};
for (const [user, cats] of Object.entries(index)) {
const nonEmptyCats = {};
for (const [status, items] of Object.entries(cats)) {
if (items && items.length > 0) {
nonEmptyCats[status] = items;
}
}
if (Object.keys(nonEmptyCats).length > 0) {
cleaned[user] = nonEmptyCats;
}
}
return cleaned;
}
function buildAINBIndexFromWikitext(wikitext) {
const result = {};
// --- Split into level-2 sections ---
const sectionRegex = /^==\s*(.+?)\s*==\s*$/gm;
const sections = [];
let match;
let lastIndex = 0;
while ((match = sectionRegex.exec(wikitext)) !== null) {
const heading = match[1].trim();
const start = match.index;
if (sections.length > 0) {
sections[sections.length - 1].text = wikitext.slice(lastIndex, start);
}
sections.push({ heading, text: "" });
lastIndex = sectionRegex.lastIndex;
}
if (sections.length > 0) {
sections[sections.length - 1].text = wikitext.slice(lastIndex);
}
// --- Process each section ---
for (const section of sections) {
const text = section.text;
// 1) Extract username from {{AINB status ...}}
const statusTplRegex = /\{\{\s*AINB\s+status([\s\S]*?)\}\}/i;
const statusMatch = text.match(statusTplRegex);
if (!statusMatch) continue;
const tplBody = statusMatch[1];
const userMatch = tplBody.match(/\|\s*user\s*=\s*([^\|\n]+)/i);
if (!userMatch) continue;
const username = userMatch[1].trim();
if (!username) continue;
if (!result[username]) {
result[username] = {};
}
// 2) Extract the AINB summary HTML block
const summaryRegex = /<!--\s*AINB-SUMMARY\s*-->([\s\S]*?)<!--\s*\/AINB-SUMMARY\s*-->/i;
const summaryMatch = text.match(summaryRegex);
if (!summaryMatch) continue;
const summaryHTML = summaryMatch[1];
// 3) Parse that HTML with DOMParser
const doc = new DOMParser().parseFromString(summaryHTML, "text/html");
const grid = doc.querySelector(".ainb-summary-grid");
if (!grid) continue;
const columns = grid.querySelectorAll(".ainb-summary-column");
columns.forEach(col => {
let statusKey = null;
// Check all defined statuses dynamically
for (const status of Object.keys(AINBStatusStyle)) {
if (col.classList.contains(`ainb-status-${status}`)) {
statusKey = status;
break;
}
}
if (!statusKey) return;
const items = Array.from(col.querySelectorAll("li")).map(li => {
const link = li.querySelector("a");
return (link ? link.textContent : li.textContent).trim().replace(/^\[\[(.*?)\]\]$/, "$1");
});
result[username][statusKey] = items;
});
}
return pruneIndex(result);
}
function loadAINBIndex() {
const api = new mw.Api();
return api.get({
action: "query",
prop: "revisions",
titles: "Wikipedia:AI noticeboard",
rvslots: "main",
rvprop: "content",
formatversion: 2
}).then(data => {
const page = data.query.pages[0];
const wikitext = page.revisions[0].slots.main.content;
return buildAINBIndexFromWikitext(wikitext);
});
}
function renderSidebar(index) {
const sidebar = document.getElementById("ainb-sidebar");
sidebar.innerHTML = "<h2>Review queue</h2>";
for (const [user, categories] of Object.entries(index)) {
const userDiv = document.createElement("div");
userDiv.className = "ainb-collapsible";
const userHeader = document.createElement("div");
userHeader.className = "ainb-collapsible-header";
userHeader.textContent = "▸ " + user;
userHeader.onclick = () => {
// Close other users
document.querySelectorAll("#ainb-sidebar > .ainb-collapsible-open").forEach(el => {
if (el !== userDiv) {
el.classList.remove("ainb-collapsible-open");
const otherHeader = el.querySelector(".ainb-collapsible-header");
if (otherHeader) {
otherHeader.textContent = "▸ " + otherHeader.textContent.substring(2);
}
}
});
userDiv.classList.toggle("ainb-collapsible-open");
userHeader.textContent =
(userDiv.classList.contains("ainb-collapsible-open") ? "▾ " : "▸ ") + user;
};
const userContent = document.createElement("div");
userContent.className = "ainb-collapsible-content";
// Status categories
for (const [status, items] of Object.entries(categories)) {
const statusDiv = document.createElement("div");
statusDiv.className = "ainb-collapsible";
const statusStyle = AINBStatusStyle[status] || AINBStatusStyle.default;
// Determine if this status should be open by default (statuses that need review action)
const shouldOpenByDefault = AINBStatusStyle[status] ? AINBStatusStyle[status].toReview : AINBStatusStyle.default.toReview;
if (shouldOpenByDefault) {
statusDiv.classList.add("ainb-collapsible-open");
}
const statusHeader = document.createElement("div");
statusHeader.className = "ainb-collapsible-header";
const arrow = shouldOpenByDefault ? "▾" : "▸";
statusHeader.innerHTML = `
<span class="ainb-pill" style="
background:${statusStyle.bg};
color:${statusStyle.fg};
">${arrow} ${statusStyle.label}: ${items.length}</span>
`;
statusHeader.onclick = () => {
statusDiv.classList.toggle("ainb-collapsible-open");
const arrow = statusDiv.classList.contains("ainb-collapsible-open") ? "▾" : "▸";
statusHeader.innerHTML = `
<span class="ainb-pill" style="
background:${statusStyle.bg};
color:${statusStyle.fg};
">${arrow} ${statusStyle.label}: ${items.length}</span>
`;
};
const statusContent = document.createElement("div");
statusContent.className = "ainb-collapsible-content";
const ul = document.createElement("ul");
items.forEach(title => {
const li = document.createElement("li");
li.textContent = title;
li.style.cursor = "pointer";
li.onclick = () => openArticle(title, user);
ul.appendChild(li);
});
statusContent.appendChild(ul);
statusDiv.appendChild(statusHeader);
statusDiv.appendChild(statusContent);
userContent.appendChild(statusDiv);
}
userDiv.appendChild(userHeader);
userDiv.appendChild(userContent);
sidebar.appendChild(userDiv);
}
}
// Chapter 3: When we do the thing we do
function fetchRecentEdits(title) {
const api = new mw.Api();
return api.get({
action: "query",
prop: "revisions",
titles: title,
rvlimit: 500,
rvprop: "ids|timestamp|user",
rvdir: "older",
formatversion: 2
}).then(data => {
const page = data.query.pages[0];
return page.revisions || [];
});
}
function findEarliestEditByUser(revisions, username) {
// Filter all edits by the user
const userEdits = revisions.filter(rev => rev.user === username);
if (userEdits.length === 0) return null;
// Revisions are newest → oldest, so the earliest is the LAST one
return userEdits[userEdits.length - 1];
}
function fetchInlineDiff(fromRev, toRev) {
const api = new mw.Api();
return api.get({
action: "compare",
fromrev: fromRev,
torev: toRev,
prop: "diff",
difftype: "inline",
formatversion: 2
}).then(data => data.compare.body);
}
function fetchRevisionWikitext(revid) {
const api = new mw.Api();
return api.get({
action: "query",
prop: "revisions",
revids: revid,
rvslots: "main",
rvprop: "content",
formatversion: 2
}).then(data => {
const page = data.query.pages[0];
return page.revisions[0].slots.main.content;
});
}
function parseInlineDiffHTML(html) {
const wrapped = `<table>${html}</table>`;
return new DOMParser().parseFromString(wrapped, "text/html");
}
function splitWikitextLines(text) {
return text ? text.match(/[^\r\n]*\r?\n|[^\r\n]+/g) || [] : [];
}
function joinWikitextLines(lines) {
return lines.join("");
}
function ensureTrailingLinebreak(text) {
if (!text) {
return "";
}
return /\r?\n$/.test(text) ? text : text + "\n";
}
function parseLineRange(label) {
if (!label) {
return null;
}
const numbers = label.match(/\d+/g);
if (!numbers || numbers.length === 0) {
return null;
}
const start = Number(numbers[0]);
const end = numbers.length > 1 ? Number(numbers[1]) : start;
if (!Number.isFinite(start) || !Number.isFinite(end)) {
return null;
}
return { start, end: Math.max(start, end) };
}
function extractInlineBlocks(doc) {
const blocks = [];
const rows = doc.querySelectorAll("tr");
let currentHeader = null;
let currentSourceLine = 1;
rows.forEach(tr => {
const cell = tr.querySelector("td, th");
if (!cell) return;
for (const child of cell.children) {
if (child.classList.contains("mw-diff-inline-header")) {
currentHeader = child.textContent.trim();
const parsed = parseLineRange(currentHeader);
if (parsed) {
currentSourceLine = parsed.start;
}
continue;
}
let type = null;
let beforeText = "";
let afterText = "";
let displayBeforeHTML = "";
let displayAfterHTML = "";
if (child.classList.contains("mw-diff-inline-context")) {
type = "context";
beforeText = child.textContent;
afterText = child.textContent;
displayBeforeHTML = child.textContent.trim();
displayAfterHTML = child.textContent.trim();
} else if (child.classList.contains("mw-diff-inline-changed")) {
type = "changed";
const parsed = parseChangedBlock(child);
beforeText = parsed.beforeText;
afterText = parsed.afterText;
displayBeforeHTML = parsed.displayBeforeHTML;
displayAfterHTML = parsed.displayAfterHTML;
} else if (child.classList.contains("mw-diff-inline-added") || child.classList.contains("mw-diff-inline-moved-destination")) {
type = "added";
beforeText = "";
afterText = child.textContent;
displayBeforeHTML = "";
displayAfterHTML = child.textContent.trim();
} else if (child.classList.contains("mw-diff-inline-deleted") || child.classList.contains("mw-diff-inline-moved-source")) {
type = "deleted";
beforeText = child.textContent;
afterText = "";
displayBeforeHTML = child.textContent.trim();
displayAfterHTML = "";
}
if (type) {
const sourceLineCount = (type === "added") ? 0 : splitWikitextLines(beforeText).length;
blocks.push({
type,
header: currentHeader,
sourceStartLine: currentSourceLine,
sourceLineCount,
beforeText,
afterText,
displayBeforeHTML,
displayAfterHTML
});
currentSourceLine += sourceLineCount;
currentHeader = null;
}
}
});
return blocks;
}
function parseChangedBlock(div) {
let beforeText = "";
let afterText = "";
let beforeHTML = "";
let afterHTML = "";
div.childNodes.forEach(node => {
if (node.nodeType === Node.TEXT_NODE) {
beforeText += node.textContent;
afterText += node.textContent;
beforeHTML += node.textContent;
afterHTML += node.textContent;
} else if (node.tagName === "DEL") {
beforeText += node.textContent;
beforeHTML += `<del>${node.textContent}</del>`;
} else if (node.tagName === "INS") {
afterText += node.textContent;
afterHTML += `<ins>${node.textContent}</ins>`;
}
});
return {
type: "changed",
beforeText,
afterText,
beforeHTML,
afterHTML,
displayBeforeHTML: beforeHTML.trim(),
displayAfterHTML: afterHTML.trim(),
html: div.innerHTML.trim()
};
}
function applyInlineStyling(html) {
return html
.replace(/<del>(.*?)<\/del>/g, '<span class="ainb-inline-del">$1</span>')
.replace(/<ins>(.*?)<\/ins>/g, '<span class="ainb-inline-ins">$1</span>');
}
const blockIcons = {
"changed": ["+", "+"],
"added": ["−", "+"],
"deleted": ["+", "−"],
"context": ["=", "="],
};
function renderBlocks(diffModel, title, username) {
const blocks = diffModel.blocks || [];
const container = document.createElement("div");
container.className = "ainb-diff-container";
blocks.forEach(block => {
// Default selection to "before"
block.selection = "before";
const row = document.createElement("div");
row.className = `ainb-diff-block ${block.type}`;
// Optional header (Line X:)
if (block.header) {
const header = document.createElement("div");
header.className = "ainb-diff-header";
header.textContent = block.header;
row.appendChild(header);
}
// --- LEFT SIDE (before) ---
const left = document.createElement("div");
left.className = "ainb-diff-side before";
left.innerHTML = `<div class="ainb-diff-text">${applyInlineStyling(block.displayBeforeHTML || block.beforeHTML || block.displayBeforeHTML || block.beforeText || "")}</div>`;
// --- CENTER BUTTON ---
const center = document.createElement("div");
center.className = "ainb-diff-center";
let centerBtn = null;
if (block.type === "context") {
const equalSign = document.createElement("span");
equalSign.className = "ainb-diff-equal";
equalSign.textContent = "=";
center.appendChild(equalSign);
} else {
centerBtn = document.createElement("button");
centerBtn.className = "ainb-diff-btn";
center.appendChild(centerBtn);
}
// --- RIGHT SIDE (after) ---
const right = document.createElement("div");
right.className = "ainb-diff-side after";
right.innerHTML = `<div class="ainb-diff-text">${applyInlineStyling(block.displayAfterHTML || block.afterHTML || block.displayAfterHTML || block.afterText || "")}</div>`;
// --- SELECTION HANDLERS ---
function updateSelectionUI() {
// Reset classes
left.classList.remove("selected", "dimmed");
right.classList.remove("selected", "dimmed");
if (centerBtn) {
centerBtn.classList.remove("selected-before", "selected-after");
}
if (block.selection === "before") {
left.classList.add("selected");
right.classList.add("dimmed");
if (centerBtn) {
centerBtn.classList.add("selected-before");
centerBtn.textContent = "◀";
}
} else if (block.selection === "after") {
right.classList.add("selected");
left.classList.add("dimmed");
if (centerBtn) {
centerBtn.classList.add("selected-after");
centerBtn.textContent = "▶";
}
}
}
if (centerBtn) {
centerBtn.addEventListener("click", () => {
block.selection = block.selection === "before" ? "after" : "before";
updateSelectionUI();
});
}
// Initial UI state
updateSelectionUI();
// Append sides
row.appendChild(left);
row.appendChild(center);
row.appendChild(right);
container.appendChild(row);
});
return container;
}
// Chapter 4: Where we take an aside to build a preview screen
function reconstructWikitext(diffData) {
const originalLines = splitWikitextLines(diffData.originalWikitext || "");
const blocks = (diffData.blocks || []).filter(block => block.type !== "context");
const outputLines = [];
let cursor = 0; // 0-indexed current line in originalLines
for (const block of blocks) {
const startIdx = block.sourceStartLine - 1; // 0-indexed
// Catch up unmodified lines
if (startIdx > cursor) {
outputLines.push(...originalLines.slice(cursor, startIdx));
cursor = startIdx;
}
// Append the selected text
const selectedText = block.selection === "after" ? (block.afterText || "") : (block.beforeText || "");
if (selectedText) {
outputLines.push(ensureTrailingLinebreak(selectedText));
}
// Advance cursor over the original lines that this block replaces
cursor = startIdx + block.sourceLineCount;
}
// Append any remaining original lines
if (cursor < originalLines.length) {
outputLines.push(...originalLines.slice(cursor));
}
return joinWikitextLines(outputLines);
}
function showPreviewScreen(diffData, title, username) {
const main = document.getElementById("ainb-main");
main.innerHTML = ""; // Clear diff UI
const header = document.createElement("div");
header.className = "ainb-main-header";
header.innerHTML = `<h2><b>Article:</b> ${title} <span class="title-notice">(preview)</span> <span class="ainb-user-badge">(User: ${username})</span></h2>`;
const body = document.createElement("div");
body.className = "ainb-main-body ainb-preview-wrapper";
const textarea = document.createElement("textarea");
textarea.className = "ainb-preview-textarea";
textarea.value = reconstructWikitext(diffData);
body.appendChild(textarea);
const footer = document.createElement("div");
footer.className = "ainb-main-footer";
const backBtn = document.createElement("button");
backBtn.textContent = "Back to diff";
backBtn.className = "ainb-action-btn ainb-action-preview";
backBtn.addEventListener("click", () => {
openArticle(title, username);
});
footer.appendChild(backBtn);
main.appendChild(header);
main.appendChild(body);
main.appendChild(footer);
}
function postArticleEdit(diffData, title, username) {
const main = document.getElementById("ainb-main");
const originalHTML = main.innerHTML;
main.innerHTML = `
<div class="ainb-main-header">
<h2>${title} / <span class="ainb-user-badge"> ${username}</span></h2>
</div>
<div class="ainb-main-body">
<div class="ainb-status">Posting edit to <b>${title}</b>...</div>
</div>
`;
const newWikitext = reconstructWikitext(diffData);
const api = new mw.Api();
api.postWithToken("csrf", {
action: "edit",
title: title,
text: newWikitext,
summary: `Cleaned up suspected AI-generated edits by [[User:${username}]] via [[User:Chaotic_Enby/AIDiffBrowser|AIDiffBrowser]]`,
bot: false
}).then(() => {
main.innerHTML = `
<div class="ainb-main-header">
<h2>${title} / <span class="ainb-user-badge"> ${username}</span></h2>
</div>
<div class="ainb-main-body">
<div class="ainb-status" style="color: #6aab6a;">Success! Edit posted to <b>${title}</b>.</div>
</div>
`;
}).catch(err => {
main.innerHTML = `
<div class="ainb-main-header">
<h2>${title} / <span class="ainb-user-badge"> ${username}</span></h2>
</div>
<div class="ainb-main-body">
<div class="ainb-status" style="color: #c95c5c;">Error posting edit: ${err}</div>
</div>
<div class="ainb-main-footer">
<button class="ainb-action-btn ainb-action-preview" id="ainb-error-back-btn">Back to diff</button>
</div>
`;
document.getElementById("ainb-error-back-btn").addEventListener("click", () => {
main.innerHTML = originalHTML;
// Rebind events since replacing innerHTML destroys them
openArticle(title, username);
});
});
}
function tagPage(revId, title, username, tag) {
if (tag === "g15") {
tagCode = "{{db-g15}}\n\n";
summary = 'Tagged for [[WP:G15|CSD G15]]';
} else if (tag === "prod") {
tagCode = "{{subst:prod llm}}\n\n";
summary = 'Tagged for [[WP:LLMPROD|LLMPROD]]';
}
const main = document.getElementById("ainb-main");
main.innerHTML = `
<div class="ainb-main-header">
<h2>${title} / <span class="ainb-user-badge"> ${username}</span></h2>
</div>
<div class="ainb-main-body">
<div class="ainb-status">Tagging page for ${tag === "g15" ? "G15 deletion" : "LLMPROD"}...</div>
</div>
`;
const api = new mw.Api();
fetchRevisionWikitext(revId).then((wikitext) => {
api.postWithToken("csrf", {
action: "edit",
title: title,
text: tagCode + wikitext,
summary: summary + " via [[User:Chaotic_Enby/AIDiffBrowser|AIDiffBrowser]]",
bot: false
})}).then(() => {
main.innerHTML = `
<div class="ainb-main-header">
<h2>${title} / <span class="ainb-user-badge"> ${username}</span></h2>
</div>
<div class="ainb-main-body">
<div class="ainb-status" style="color: #6aab6a;">Success! Page tagged for ${tag === "g15" ? "G15 deletion" : "LLMPROD"}.</div>
</div>
`;
}).catch(err => {
main.innerHTML = `
<div class="ainb-main-header">
<h2>${title} / <span class="ainb-user-badge"> ${username}</span></h2>
</div>
<div class="ainb-main-body">
<div class="ainb-status" style="color: #c95c5c;">Error tagging page: ${err}</div>
</div>
`;
});
}
// Chapter 3.2: Where we go back to the main screen
function openArticle(title, username) {
const main = document.getElementById("ainb-main");
main.innerHTML = `
<div class="ainb-main-header">
<h2>${title} / <span class="ainb-user-badge"> ${username}</span></h2>
</div>
<div class="ainb-main-body">
<div class="ainb-status">Loading diff...</div>
</div>
`;
fetchRecentEdits(title)
.then(revs => {
const beforeRevObj = findEarliestEditByUser(revs, username);
if (!beforeRevObj) {
main.innerHTML = `
<div class="ainb-main-header">
<h2>${title} / <span class="ainb-user-badge"> ${username}</span></h2>
</div>
<div class="ainb-main-body">
<div class="ainb-status">No edits by <b>${username}</b> could be found.</div>
</div>
`;
return null;
}
const beforeRev = beforeRevObj.parentid || emptyRev; // Use empty revision ID for first edits
const isFirstEdit = !beforeRevObj.parentid; // Track if this is a first-edit scenario
const currentRev = revs[0].revid; // newest revision
return Promise.all([
fetchRevisionWikitext(beforeRev),
fetchInlineDiff(beforeRev, currentRev)
]).then(([originalWikitext, diffHTML]) => ({
originalWikitext,
diffHTML,
isFirstEdit,
currentRev
}));
})
.then(diffData => {
if (!diffData) return;
const doc = parseInlineDiffHTML(diffData.diffHTML);
const blocks = extractInlineBlocks(doc);
const diffModel = {
originalWikitext: diffData.originalWikitext,
blocks,
isFirstEdit: diffData.isFirstEdit,
currentRev: diffData.currentRev
};
main.innerHTML = "";
const header = document.createElement("div");
header.className = "ainb-main-header";
if(diffData.isFirstEdit) {
header.innerHTML = `<h2>${title} / <span class="ainb-user-badge"> ${username}</span> <span class="ainb-page-badge">(page creator)</span></h2>`;
} else {
header.innerHTML = `<h2>${title} / <span class="ainb-user-badge"> ${username}</span></h2>`;
}
const body = document.createElement("div");
body.className = "ainb-main-body";
body.appendChild(renderBlocks(diffModel, title, username));
const footer = document.createElement("div");
footer.className = "ainb-main-footer";
const previewBtn = document.createElement("button");
previewBtn.textContent = "Preview";
previewBtn.className = "ainb-action-btn ainb-action-preview";
previewBtn.addEventListener("click", () => {
showPreviewScreen(diffModel, title, username);
});
const postBtn = document.createElement("button");
postBtn.textContent = "Post";
postBtn.className = "ainb-action-btn ainb-action-post";
postBtn.addEventListener("click", () => {
postArticleEdit(diffModel, title, username);
});
footer.appendChild(previewBtn);
footer.appendChild(postBtn);
// Add extra buttons for first-edit articles
if (diffModel.isFirstEdit) {
const prodBtn = document.createElement("button");
prodBtn.textContent = "LLMPROD";
prodBtn.className = "ainb-action-btn ainb-action-destructive";
prodBtn.addEventListener("click", () => {
tagPage(diffModel.currentRev, title, username, "prod");
});
footer.appendChild(prodBtn);
const g15Btn = document.createElement("button");
g15Btn.textContent = "G15";
g15Btn.className = "ainb-action-btn ainb-action-destructive";
g15Btn.addEventListener("click", () => {
tagPage(diffModel.currentRev, title, username, "g15");
});
footer.appendChild(g15Btn);
}
main.appendChild(header);
main.appendChild(body);
main.appendChild(footer);
})
.catch(err => {
main.innerHTML = `
<div class="ainb-main-header">
<h2>${title} / <span class="ainb-user-badge"> ${username}</span></h2>
</div>
<div class="ainb-main-body">
<div class="ainb-status">Error loading diff: ${err}</div>
</div>
`;
});
}
// Chapter N-1: The fancy stuff
function setupCSS(){
mw.util.addCSS(`
:root {
--ainb-hue: 220;
--ainb-hue-2: 240;
--ainb-hue-accent: 293;
--ainb-hue-accent-2: 324;
}
#ainb-app {
background-color: hsl(var(--ainb-hue), 10%, 10%);
color: white;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
font-family: system-ui, sans-serif;
}
#ainb-app h2 {
font-family: system-ui, sans-serif;
font-weight: 600;
letter-spacing: 1.5px;
padding-left: 10px;
border-bottom: none;
color: hsl(var(--ainb-hue), 70%, 93%);
}
#ainb-sidebar {
padding: 0px;
background: linear-gradient(135deg, hsl(var(--ainb-hue), 30%, 12%) 0%, hsl(var(--ainb-hue-2), 30%, 14%) 100%);
z-index: 1;
width: 280px;
overflow-y: auto;
letter-spacing: 0.5px;
}
#ainb-sidebar h2 {
margin: 10px;
height: 34px;
}
.ainb-collapsible-header {
cursor: pointer;
user-select: none;
padding: 5px 0;
}
.ainb-collapsible-content li:hover {
color: #e7e7e7;
}
.ainb-collapsible-content {
display: none;
margin-left: 12px;
}
#ainb-sidebar > .ainb-collapsible {
padding: 6px 6px 6px 11px;
color: hsl(var(--ainb-hue), 10%, 60%);
}
#ainb-sidebar > .ainb-collapsible:not(.ainb-collapsible-open):hover {
background: linear-gradient(135deg, hsl(var(--ainb-hue), 30%, 14%) 0%, hsl(var(--ainb-hue-2), 30%, 15%) 100%);
color: white;
}
#ainb-sidebar > .ainb-collapsible-open {
background: linear-gradient(135deg, hsl(var(--ainb-hue-accent), 78%, 23%) 0%, hsl(var(--ainb-hue-accent-2), 81%, 31%) 100%);
color: white;
}
.ainb-collapsible-open > .ainb-collapsible-content {
display: block;
}
.ainb-pill {
display: inline-block;
padding: 1px 8px;
border-radius: 10px;
font-size: 88%;
font-weight: 500;
}
.ainb-collapsible-content ul {
margin: 4px 0 6px 6px;
}
.ainb-collapsible-content li {
list-style: none;
font-size: 88%;
margin: 7px 0;
}
#ainb-main {
flex: 1 1 0%;
display: flex;
flex-direction: column;
overflow: hidden;
background: linear-gradient(135deg, hsl(var(--ainb-hue), 32%, 15%) 0%, hsl(var(--ainb-hue-2), 42%, 15%) 100%);
}
.ainb-main-header {
flex-shrink: 0;
padding: 15px 20px;
display: flex;
align-items: center;
height: 40px;
}
.ainb-main-header h2 {
margin: 0;
font-size: 18px;
padding-left: 0 !important;
}
.ainb-user-badge {
color: hsl(var(--ainb-hue), 90%, 70%);
}
.ainb-page-badge {
font-size: 70%;
}
.ainb-main-body {
flex: 1 1 auto;
overflow-y: auto;
background: linear-gradient(135deg, hsl(var(--ainb-hue), 30%, 17%) 0%, hsl(var(--ainb-hue-2), 40%, 17%) 100%);
display: flex;
}
.ainb-main-footer {
flex-shrink: 0;
padding: 12px 20px;
display: flex;
justify-content: flex-end;
gap: 20px;
}
.ainb-status {
margin: auto;
text-align: center;
}
.ainb-diff-container {
display: flex;
flex-direction: column;
font-family: monospace, system-ui, sans-serif;
width: 100%;
}
.ainb-diff-block {
display: grid;
grid-template-columns: 1fr auto 1fr;
}
.ainb-diff-center {
display: flex;
justify-content: center;
align-items: center;
}
.ainb-diff-btn, .ainb-diff-equal {
flex-grow: 1;
height: 100%;
display: flex;
align-items: center;
border: none;
padding-top: 0.2em;
padding-bottom: 0.28em;
}
.ainb-diff-equal {
display: flex;
align-items: center;
justify-content: center;
color: hsl(var(--ainb-hue), 10%, 60%);
font-weight: bold;
font-size: 21px;
width: 40px;
}
.ainb-diff-btn {
transition: background-color 0.15s, color 0.15s;
width: 40px;
justify-content: center;
font-size: 15px;
cursor: pointer;
background: none;
}
.ainb-diff-btn.selected-before {
color: #f447a0;
}
.ainb-diff-btn.selected-after {
color: #d4ac6a;
}
.added .ainb-diff-btn.selected-before, .deleted .ainb-diff-btn.selected-after {
color: hsl(var(--ainb-hue), 10%, 70%);
}
.ainb-diff-side {
white-space: pre-wrap;
line-height: 1.45;
font-size: 14px;
display: flex;
justify-content: space-between;
align-items: center;
overflow: hidden;
padding: 5px 20px;
}
.before, .after {
flex-direction: row;
}
.context :is(.before, .after) {
background-color: hsla(var(--ainb-hue), 20%, 26%, 30%);
}
:is(.changed, .deleted) .before {
background-color: #97567d;
}
:is(.changed, .added) .after {
background-color: #a49379;
}
:is(.added .before, .deleted .after) .ainb-diff-text {
text-align: center;
width: 100%;
}
:is(.added .before, .deleted .after) .ainb-diff-text::before {
content: "∅";
color: #c2c2c2;
}
.ainb-diff-header {
grid-column: 1 / -1;
font-size: 14px;
text-align: center;
font-weight: 600;
color: hsl(var(--ainb-hue), var(--ainb-sat), 60%);
padding-top: 0.5em;
padding-bottom: 0.58em;
}
.ainb-inline-del {
background: #ffe5e5;
color: #b30000;
text-decoration: line-through;
padding: 0 2px;
border-radius: 3px;
}
.ainb-inline-ins {
background: #e6ffe6;
color: #006600;
padding: 0 2px;
border-radius: 3px;
}
.ainb-diff-side.dimmed:not(.context .ainb-diff-side) {
opacity: 0.3;
}
.ainb-action-btn {
padding: 8px 16px;
font-size: 15px;
letter-spacing: 1px;
border: none;
background: transparent;
cursor: pointer;
transition: color 0.15s;
margin: auto 0;
font-family: system-ui, sans-serif;
font-weight: 600;
}
.ainb-action-preview {
color: hsl(var(--ainb-hue), 50%, 90%);
}
.ainb-action-preview:hover {
color: hsl(var(--ainb-hue), 50%, 95%);
}
.ainb-action-post {
color: hsl(var(--ainb-hue-accent), 90%, 70%);
}
.ainb-action-post:hover {
color: hsl(var(--ainb-hue-accent), 90%, 75%);
}
.ainb-action-destructive {
color: hsl(350, 70%, 70%);
}
.ainb-action-destructive:hover {
color: hsl(350, 70%, 75%);
}
.ainb-preview-wrapper {
display: flex;
flex-direction: column;
gap: 16px;
padding: 20px;
}
.ainb-preview-textarea {
width: 100%;
height: 60vh;
font-family: monospace, system-ui, sans-serif;
font-size: 14px;
padding: 12px;
border-radius: 6px;
border: 1px solid #ccc;
resize: vertical;
}
.title-notice {
font-size: 80%;
color: grey;
}
`);
}
// Chapter N: When they actually launch the thing
if(mw.config.get("wgPageName") === "User:Chaotic_Enby/AIDiffBrowser/run") {
setupCSS();
setupAppShell();
loadAINBIndex().then(index => {
renderSidebar(index);
});
}
nwl1d0k67q8mna9qoaawm5rfhxt9tt8
743921
743919
2026-05-22T23:53:10Z
Chaotic Enby
58843
minor style fixes, + moving to red and green for diff colors
743921
javascript
text/javascript
// Chapter 0: I really wanted this in an object and I could've just as well used regex
const emptyRev = 742978 // 1354670824 for enwiki
const AINBStatusStyle = {
needsreview: {
bg: "#FAEEDA",
fg: "#854F0B",
label: "Needs review",
toReview: true,
},
inprogress: {
bg: "#E6F1FB",
fg: "#0C447C",
label: "In progress",
toReview: true
},
clean: {
bg: "#EAF3DE",
fg: "#27500A",
label: "Clean",
toReview: false
},
draftified: {
bg: "#F1EFE8",
fg: "#2C2C2A",
label: "Draftified",
toReview: false
},
stubified: {
bg: "#EEEDFE",
fg: "#3C3489",
label: "Stubified",
toReview: false
},
g15: {
bg: "#FAECE7",
fg: "#4A1B0C",
label: "G15 eligible",
toReview: true
},
afd: {
bg: "#FAEEDA",
fg: "#633806",
label: "AfD",
toReview: false
},
deleted: {
bg: "#FCEBEB",
fg: "#501313",
label: "Deleted",
toReview: false
},
kept: {
bg: "#E1F5EE",
fg: "#085041",
label: "Kept",
toReview: false
},
restored: {
bg: "#E6F1FB",
fg: "#185FA5",
label: "Restored",
toReview: false
},
default: {
bg: "#F1EFE8",
fg: "#2C2C2A",
label: "Unknown",
toReview: true
}
};
// Chapter 1: When we build the main window thing
function setupAppShell() {
const root = document.body;
root.innerHTML = "";
const app = document.createElement("div");
app.id = "ainb-app";
const sidebar = document.createElement("div");
sidebar.id = "ainb-sidebar";
const main = document.createElement("div");
main.id = "ainb-main";
app.appendChild(sidebar);
app.appendChild(main);
root.appendChild(app);
}
// Chapter 2: When we load the AINB data and build the sidebar thing
function pruneIndex(index) {
const cleaned = {};
for (const [user, cats] of Object.entries(index)) {
const nonEmptyCats = {};
for (const [status, items] of Object.entries(cats)) {
if (items && items.length > 0) {
nonEmptyCats[status] = items;
}
}
if (Object.keys(nonEmptyCats).length > 0) {
cleaned[user] = nonEmptyCats;
}
}
return cleaned;
}
function buildAINBIndexFromWikitext(wikitext) {
const result = {};
// --- Split into level-2 sections ---
const sectionRegex = /^==\s*(.+?)\s*==\s*$/gm;
const sections = [];
let match;
let lastIndex = 0;
while ((match = sectionRegex.exec(wikitext)) !== null) {
const heading = match[1].trim();
const start = match.index;
if (sections.length > 0) {
sections[sections.length - 1].text = wikitext.slice(lastIndex, start);
}
sections.push({ heading, text: "" });
lastIndex = sectionRegex.lastIndex;
}
if (sections.length > 0) {
sections[sections.length - 1].text = wikitext.slice(lastIndex);
}
// --- Process each section ---
for (const section of sections) {
const text = section.text;
// 1) Extract username from {{AINB status ...}}
const statusTplRegex = /\{\{\s*AINB\s+status([\s\S]*?)\}\}/i;
const statusMatch = text.match(statusTplRegex);
if (!statusMatch) continue;
const tplBody = statusMatch[1];
const userMatch = tplBody.match(/\|\s*user\s*=\s*([^\|\n]+)/i);
if (!userMatch) continue;
const username = userMatch[1].trim();
if (!username) continue;
if (!result[username]) {
result[username] = {};
}
// 2) Extract the AINB summary HTML block
const summaryRegex = /<!--\s*AINB-SUMMARY\s*-->([\s\S]*?)<!--\s*\/AINB-SUMMARY\s*-->/i;
const summaryMatch = text.match(summaryRegex);
if (!summaryMatch) continue;
const summaryHTML = summaryMatch[1];
// 3) Parse that HTML with DOMParser
const doc = new DOMParser().parseFromString(summaryHTML, "text/html");
const grid = doc.querySelector(".ainb-summary-grid");
if (!grid) continue;
const columns = grid.querySelectorAll(".ainb-summary-column");
columns.forEach(col => {
let statusKey = null;
// Check all defined statuses dynamically
for (const status of Object.keys(AINBStatusStyle)) {
if (col.classList.contains(`ainb-status-${status}`)) {
statusKey = status;
break;
}
}
if (!statusKey) return;
const items = Array.from(col.querySelectorAll("li")).map(li => {
const link = li.querySelector("a");
return (link ? link.textContent : li.textContent).trim().replace(/^\[\[(.*?)\]\]$/, "$1");
});
result[username][statusKey] = items;
});
}
return pruneIndex(result);
}
function loadAINBIndex() {
const api = new mw.Api();
return api.get({
action: "query",
prop: "revisions",
titles: "Wikipedia:AI noticeboard",
rvslots: "main",
rvprop: "content",
formatversion: 2
}).then(data => {
const page = data.query.pages[0];
const wikitext = page.revisions[0].slots.main.content;
return buildAINBIndexFromWikitext(wikitext);
});
}
function renderSidebar(index) {
const sidebar = document.getElementById("ainb-sidebar");
sidebar.innerHTML = "<h2>Review queue</h2>";
for (const [user, categories] of Object.entries(index)) {
const userDiv = document.createElement("div");
userDiv.className = "ainb-collapsible";
const userHeader = document.createElement("div");
userHeader.className = "ainb-collapsible-header";
userHeader.textContent = "▸ " + user;
userHeader.onclick = () => {
// Close other users
document.querySelectorAll("#ainb-sidebar > .ainb-collapsible-open").forEach(el => {
if (el !== userDiv) {
el.classList.remove("ainb-collapsible-open");
const otherHeader = el.querySelector(".ainb-collapsible-header");
if (otherHeader) {
otherHeader.textContent = "▸ " + otherHeader.textContent.substring(2);
}
}
});
userDiv.classList.toggle("ainb-collapsible-open");
userHeader.textContent =
(userDiv.classList.contains("ainb-collapsible-open") ? "▾ " : "▸ ") + user;
};
const userContent = document.createElement("div");
userContent.className = "ainb-collapsible-content";
// Status categories
for (const [status, items] of Object.entries(categories)) {
const statusDiv = document.createElement("div");
statusDiv.className = "ainb-collapsible";
const statusStyle = AINBStatusStyle[status] || AINBStatusStyle.default;
// Determine if this status should be open by default (statuses that need review action)
const shouldOpenByDefault = AINBStatusStyle[status] ? AINBStatusStyle[status].toReview : AINBStatusStyle.default.toReview;
if (shouldOpenByDefault) {
statusDiv.classList.add("ainb-collapsible-open");
}
const statusHeader = document.createElement("div");
statusHeader.className = "ainb-collapsible-header";
const arrow = shouldOpenByDefault ? "▾" : "▸";
statusHeader.innerHTML = `
<span class="ainb-pill" style="
background:${statusStyle.bg};
color:${statusStyle.fg};
">${arrow} ${statusStyle.label}: ${items.length}</span>
`;
statusHeader.onclick = () => {
statusDiv.classList.toggle("ainb-collapsible-open");
const arrow = statusDiv.classList.contains("ainb-collapsible-open") ? "▾" : "▸";
statusHeader.innerHTML = `
<span class="ainb-pill" style="
background:${statusStyle.bg};
color:${statusStyle.fg};
">${arrow} ${statusStyle.label}: ${items.length}</span>
`;
};
const statusContent = document.createElement("div");
statusContent.className = "ainb-collapsible-content";
const ul = document.createElement("ul");
items.forEach(title => {
const li = document.createElement("li");
li.textContent = title;
li.style.cursor = "pointer";
li.onclick = () => openArticle(title, user);
ul.appendChild(li);
});
statusContent.appendChild(ul);
statusDiv.appendChild(statusHeader);
statusDiv.appendChild(statusContent);
userContent.appendChild(statusDiv);
}
userDiv.appendChild(userHeader);
userDiv.appendChild(userContent);
sidebar.appendChild(userDiv);
}
}
// Chapter 3: When we do the thing we do
function fetchRecentEdits(title) {
const api = new mw.Api();
return api.get({
action: "query",
prop: "revisions",
titles: title,
rvlimit: 500,
rvprop: "ids|timestamp|user",
rvdir: "older",
formatversion: 2
}).then(data => {
const page = data.query.pages[0];
return page.revisions || [];
});
}
function findEarliestEditByUser(revisions, username) {
// Filter all edits by the user
const userEdits = revisions.filter(rev => rev.user === username);
if (userEdits.length === 0) return null;
// Revisions are newest → oldest, so the earliest is the LAST one
return userEdits[userEdits.length - 1];
}
function fetchInlineDiff(fromRev, toRev) {
const api = new mw.Api();
return api.get({
action: "compare",
fromrev: fromRev,
torev: toRev,
prop: "diff",
difftype: "inline",
formatversion: 2
}).then(data => data.compare.body);
}
function fetchRevisionWikitext(revid) {
const api = new mw.Api();
return api.get({
action: "query",
prop: "revisions",
revids: revid,
rvslots: "main",
rvprop: "content",
formatversion: 2
}).then(data => {
const page = data.query.pages[0];
return page.revisions[0].slots.main.content;
});
}
function parseInlineDiffHTML(html) {
const wrapped = `<table>${html}</table>`;
return new DOMParser().parseFromString(wrapped, "text/html");
}
function splitWikitextLines(text) {
return text ? text.match(/[^\r\n]*\r?\n|[^\r\n]+/g) || [] : [];
}
function joinWikitextLines(lines) {
return lines.join("");
}
function ensureTrailingLinebreak(text) {
if (!text) {
return "";
}
return /\r?\n$/.test(text) ? text : text + "\n";
}
function parseLineRange(label) {
if (!label) {
return null;
}
const numbers = label.match(/\d+/g);
if (!numbers || numbers.length === 0) {
return null;
}
const start = Number(numbers[0]);
const end = numbers.length > 1 ? Number(numbers[1]) : start;
if (!Number.isFinite(start) || !Number.isFinite(end)) {
return null;
}
return { start, end: Math.max(start, end) };
}
function extractInlineBlocks(doc) {
const blocks = [];
const rows = doc.querySelectorAll("tr");
let currentHeader = null;
let currentSourceLine = 1;
rows.forEach(tr => {
const cell = tr.querySelector("td, th");
if (!cell) return;
for (const child of cell.children) {
if (child.classList.contains("mw-diff-inline-header")) {
currentHeader = child.textContent.trim();
const parsed = parseLineRange(currentHeader);
if (parsed) {
currentSourceLine = parsed.start;
}
continue;
}
let type = null;
let beforeText = "";
let afterText = "";
let displayBeforeHTML = "";
let displayAfterHTML = "";
if (child.classList.contains("mw-diff-inline-context")) {
type = "context";
beforeText = child.textContent;
afterText = child.textContent;
displayBeforeHTML = child.textContent.trim();
displayAfterHTML = child.textContent.trim();
} else if (child.classList.contains("mw-diff-inline-changed")) {
type = "changed";
const parsed = parseChangedBlock(child);
beforeText = parsed.beforeText;
afterText = parsed.afterText;
displayBeforeHTML = parsed.displayBeforeHTML;
displayAfterHTML = parsed.displayAfterHTML;
} else if (child.classList.contains("mw-diff-inline-added") || child.classList.contains("mw-diff-inline-moved-destination")) {
type = "added";
beforeText = "";
afterText = child.textContent;
displayBeforeHTML = "";
displayAfterHTML = child.textContent.trim();
} else if (child.classList.contains("mw-diff-inline-deleted") || child.classList.contains("mw-diff-inline-moved-source")) {
type = "deleted";
beforeText = child.textContent;
afterText = "";
displayBeforeHTML = child.textContent.trim();
displayAfterHTML = "";
}
if (type) {
const sourceLineCount = (type === "added") ? 0 : splitWikitextLines(beforeText).length;
blocks.push({
type,
header: currentHeader,
sourceStartLine: currentSourceLine,
sourceLineCount,
beforeText,
afterText,
displayBeforeHTML,
displayAfterHTML
});
currentSourceLine += sourceLineCount;
currentHeader = null;
}
}
});
return blocks;
}
function parseChangedBlock(div) {
let beforeText = "";
let afterText = "";
let beforeHTML = "";
let afterHTML = "";
div.childNodes.forEach(node => {
if (node.nodeType === Node.TEXT_NODE) {
beforeText += node.textContent;
afterText += node.textContent;
beforeHTML += node.textContent;
afterHTML += node.textContent;
} else if (node.tagName === "DEL") {
beforeText += node.textContent;
beforeHTML += `<del>${node.textContent}</del>`;
} else if (node.tagName === "INS") {
afterText += node.textContent;
afterHTML += `<ins>${node.textContent}</ins>`;
}
});
return {
type: "changed",
beforeText,
afterText,
beforeHTML,
afterHTML,
displayBeforeHTML: beforeHTML.trim(),
displayAfterHTML: afterHTML.trim(),
html: div.innerHTML.trim()
};
}
function applyInlineStyling(html) {
return html
.replace(/<del>(.*?)<\/del>/g, '<span class="ainb-inline-del">$1</span>')
.replace(/<ins>(.*?)<\/ins>/g, '<span class="ainb-inline-ins">$1</span>');
}
const blockIcons = {
"changed": ["+", "+"],
"added": ["−", "+"],
"deleted": ["+", "−"],
"context": ["=", "="],
};
function renderBlocks(diffModel, title, username) {
const blocks = diffModel.blocks || [];
const container = document.createElement("div");
container.className = "ainb-diff-container";
blocks.forEach(block => {
// Default selection to "before"
block.selection = "before";
const row = document.createElement("div");
row.className = `ainb-diff-block ${block.type}`;
// Optional header (Line X:)
if (block.header) {
const header = document.createElement("div");
header.className = "ainb-diff-header";
header.textContent = block.header;
row.appendChild(header);
}
// --- LEFT SIDE (before) ---
const left = document.createElement("div");
left.className = "ainb-diff-side before";
left.innerHTML = `<div class="ainb-diff-text">${applyInlineStyling(block.displayBeforeHTML || block.beforeHTML || block.displayBeforeHTML || block.beforeText || "")}</div>`;
// --- CENTER BUTTON ---
const center = document.createElement("div");
center.className = "ainb-diff-center";
let centerBtn = null;
if (block.type === "context") {
const equalSign = document.createElement("span");
equalSign.className = "ainb-diff-equal";
equalSign.textContent = "=";
center.appendChild(equalSign);
} else {
centerBtn = document.createElement("button");
centerBtn.className = "ainb-diff-btn";
center.appendChild(centerBtn);
}
// --- RIGHT SIDE (after) ---
const right = document.createElement("div");
right.className = "ainb-diff-side after";
right.innerHTML = `<div class="ainb-diff-text">${applyInlineStyling(block.displayAfterHTML || block.afterHTML || block.displayAfterHTML || block.afterText || "")}</div>`;
// --- SELECTION HANDLERS ---
function updateSelectionUI() {
// Reset classes
left.classList.remove("selected", "dimmed");
right.classList.remove("selected", "dimmed");
if (centerBtn) {
centerBtn.classList.remove("selected-before", "selected-after");
}
if (block.selection === "before") {
left.classList.add("selected");
right.classList.add("dimmed");
if (centerBtn) {
centerBtn.classList.add("selected-before");
centerBtn.textContent = "◀";
}
} else if (block.selection === "after") {
right.classList.add("selected");
left.classList.add("dimmed");
if (centerBtn) {
centerBtn.classList.add("selected-after");
centerBtn.textContent = "▶";
}
}
}
if (centerBtn) {
centerBtn.addEventListener("click", () => {
block.selection = block.selection === "before" ? "after" : "before";
updateSelectionUI();
});
}
// Initial UI state
updateSelectionUI();
// Append sides
row.appendChild(left);
row.appendChild(center);
row.appendChild(right);
container.appendChild(row);
});
return container;
}
// Chapter 4: Where we take an aside to build a preview screen
function reconstructWikitext(diffData) {
const originalLines = splitWikitextLines(diffData.originalWikitext || "");
const blocks = (diffData.blocks || []).filter(block => block.type !== "context");
const outputLines = [];
let cursor = 0; // 0-indexed current line in originalLines
for (const block of blocks) {
const startIdx = block.sourceStartLine - 1; // 0-indexed
// Catch up unmodified lines
if (startIdx > cursor) {
outputLines.push(...originalLines.slice(cursor, startIdx));
cursor = startIdx;
}
// Append the selected text
const selectedText = block.selection === "after" ? (block.afterText || "") : (block.beforeText || "");
if (selectedText) {
outputLines.push(ensureTrailingLinebreak(selectedText));
}
// Advance cursor over the original lines that this block replaces
cursor = startIdx + block.sourceLineCount;
}
// Append any remaining original lines
if (cursor < originalLines.length) {
outputLines.push(...originalLines.slice(cursor));
}
return joinWikitextLines(outputLines);
}
function showPreviewScreen(diffData, title, username) {
const main = document.getElementById("ainb-main");
main.innerHTML = ""; // Clear diff UI
const header = document.createElement("div");
header.className = "ainb-main-header";
header.innerHTML = `<h2><b>Article:</b> ${title} <span class="title-notice">(preview)</span> <span class="ainb-user-badge">(User: ${username})</span></h2>`;
const body = document.createElement("div");
body.className = "ainb-main-body ainb-preview-wrapper";
const textarea = document.createElement("textarea");
textarea.className = "ainb-preview-textarea";
textarea.value = reconstructWikitext(diffData);
body.appendChild(textarea);
const footer = document.createElement("div");
footer.className = "ainb-main-footer";
const backBtn = document.createElement("button");
backBtn.textContent = "Back to diff";
backBtn.className = "ainb-action-btn ainb-action-preview";
backBtn.addEventListener("click", () => {
openArticle(title, username);
});
footer.appendChild(backBtn);
main.appendChild(header);
main.appendChild(body);
main.appendChild(footer);
}
function postArticleEdit(diffData, title, username) {
const main = document.getElementById("ainb-main");
const originalHTML = main.innerHTML;
main.innerHTML = `
<div class="ainb-main-header">
<h2>${title} / <span class="ainb-user-badge"> ${username}</span></h2>
</div>
<div class="ainb-main-body">
<div class="ainb-status">Posting edit to <b>${title}</b>...</div>
</div>
`;
const newWikitext = reconstructWikitext(diffData);
const api = new mw.Api();
api.postWithToken("csrf", {
action: "edit",
title: title,
text: newWikitext,
summary: `Cleaned up suspected AI-generated edits by [[User:${username}]] via [[User:Chaotic_Enby/AIDiffBrowser|AIDiffBrowser]]`,
bot: false
}).then(() => {
main.innerHTML = `
<div class="ainb-main-header">
<h2>${title} / <span class="ainb-user-badge"> ${username}</span></h2>
</div>
<div class="ainb-main-body">
<div class="ainb-status" style="color: #6aab6a;">Success! Edit posted to <b>${title}</b>.</div>
</div>
`;
}).catch(err => {
main.innerHTML = `
<div class="ainb-main-header">
<h2>${title} / <span class="ainb-user-badge"> ${username}</span></h2>
</div>
<div class="ainb-main-body">
<div class="ainb-status" style="color: #c95c5c;">Error posting edit: ${err}</div>
</div>
<div class="ainb-main-footer">
<button class="ainb-action-btn ainb-action-preview" id="ainb-error-back-btn">Back to diff</button>
</div>
`;
document.getElementById("ainb-error-back-btn").addEventListener("click", () => {
main.innerHTML = originalHTML;
// Rebind events since replacing innerHTML destroys them
openArticle(title, username);
});
});
}
function tagPage(revId, title, username, tag) {
if (tag === "g15") {
tagCode = "{{db-g15}}\n\n";
summary = 'Tagged for [[WP:G15|CSD G15]]';
} else if (tag === "prod") {
tagCode = "{{subst:prod llm}}\n\n";
summary = 'Tagged for [[WP:LLMPROD|LLMPROD]]';
}
const main = document.getElementById("ainb-main");
main.innerHTML = `
<div class="ainb-main-header">
<h2>${title} / <span class="ainb-user-badge"> ${username}</span></h2>
</div>
<div class="ainb-main-body">
<div class="ainb-status">Tagging page for ${tag === "g15" ? "G15 deletion" : "LLMPROD"}...</div>
</div>
`;
const api = new mw.Api();
fetchRevisionWikitext(revId).then((wikitext) => {
api.postWithToken("csrf", {
action: "edit",
title: title,
text: tagCode + wikitext,
summary: summary + " via [[User:Chaotic_Enby/AIDiffBrowser|AIDiffBrowser]]",
bot: false
})}).then(() => {
main.innerHTML = `
<div class="ainb-main-header">
<h2>${title} / <span class="ainb-user-badge"> ${username}</span></h2>
</div>
<div class="ainb-main-body">
<div class="ainb-status" style="color: #6aab6a;">Success! Page tagged for ${tag === "g15" ? "G15 deletion" : "LLMPROD"}.</div>
</div>
`;
}).catch(err => {
main.innerHTML = `
<div class="ainb-main-header">
<h2>${title} / <span class="ainb-user-badge"> ${username}</span></h2>
</div>
<div class="ainb-main-body">
<div class="ainb-status" style="color: #c95c5c;">Error tagging page: ${err}</div>
</div>
`;
});
}
// Chapter 3.2: Where we go back to the main screen
function openArticle(title, username) {
const main = document.getElementById("ainb-main");
main.innerHTML = `
<div class="ainb-main-header">
<h2>${title} / <span class="ainb-user-badge"> ${username}</span></h2>
</div>
<div class="ainb-main-body">
<div class="ainb-status">Loading diff...</div>
</div>
`;
fetchRecentEdits(title)
.then(revs => {
const beforeRevObj = findEarliestEditByUser(revs, username);
if (!beforeRevObj) {
main.innerHTML = `
<div class="ainb-main-header">
<h2>${title} / <span class="ainb-user-badge"> ${username}</span></h2>
</div>
<div class="ainb-main-body">
<div class="ainb-status">No edits by <b>${username}</b> could be found.</div>
</div>
`;
return null;
}
const beforeRev = beforeRevObj.parentid || emptyRev; // Use empty revision ID for first edits
const isFirstEdit = !beforeRevObj.parentid; // Track if this is a first-edit scenario
const currentRev = revs[0].revid; // newest revision
return Promise.all([
fetchRevisionWikitext(beforeRev),
fetchInlineDiff(beforeRev, currentRev)
]).then(([originalWikitext, diffHTML]) => ({
originalWikitext,
diffHTML,
isFirstEdit,
currentRev
}));
})
.then(diffData => {
if (!diffData) return;
const doc = parseInlineDiffHTML(diffData.diffHTML);
const blocks = extractInlineBlocks(doc);
const diffModel = {
originalWikitext: diffData.originalWikitext,
blocks,
isFirstEdit: diffData.isFirstEdit,
currentRev: diffData.currentRev
};
main.innerHTML = "";
const header = document.createElement("div");
header.className = "ainb-main-header";
if(diffData.isFirstEdit) {
header.innerHTML = `<h2>${title} / <span class="ainb-user-badge"> ${username}</span> <span class="ainb-page-badge">(page creator)</span></h2>`;
} else {
header.innerHTML = `<h2>${title} / <span class="ainb-user-badge"> ${username}</span></h2>`;
}
const body = document.createElement("div");
body.className = "ainb-main-body";
body.appendChild(renderBlocks(diffModel, title, username));
const footer = document.createElement("div");
footer.className = "ainb-main-footer";
const previewBtn = document.createElement("button");
previewBtn.textContent = "Preview";
previewBtn.className = "ainb-action-btn ainb-action-preview";
previewBtn.addEventListener("click", () => {
showPreviewScreen(diffModel, title, username);
});
const postBtn = document.createElement("button");
postBtn.textContent = "Post";
postBtn.className = "ainb-action-btn ainb-action-post";
postBtn.addEventListener("click", () => {
postArticleEdit(diffModel, title, username);
});
footer.appendChild(previewBtn);
footer.appendChild(postBtn);
// Add extra buttons for first-edit articles
if (diffModel.isFirstEdit) {
const prodBtn = document.createElement("button");
prodBtn.textContent = "LLMPROD";
prodBtn.className = "ainb-action-btn ainb-action-destructive";
prodBtn.addEventListener("click", () => {
tagPage(diffModel.currentRev, title, username, "prod");
});
footer.appendChild(prodBtn);
const g15Btn = document.createElement("button");
g15Btn.textContent = "G15";
g15Btn.className = "ainb-action-btn ainb-action-destructive";
g15Btn.addEventListener("click", () => {
tagPage(diffModel.currentRev, title, username, "g15");
});
footer.appendChild(g15Btn);
}
main.appendChild(header);
main.appendChild(body);
main.appendChild(footer);
})
.catch(err => {
main.innerHTML = `
<div class="ainb-main-header">
<h2>${title} ⋅ <span class="ainb-user-badge"> ${username}</span></h2>
</div>
<div class="ainb-main-body">
<div class="ainb-status">Error loading diff: ${err}</div>
</div>
`;
});
}
// Chapter N-1: The fancy stuff
function setupCSS(){
mw.util.addCSS(`
:root {
--ainb-hue: 220;
--ainb-hue-2: 240;
--ainb-hue-accent: 293;
--ainb-hue-accent-2: 324;
}
#ainb-app {
background-color: hsl(var(--ainb-hue), 10%, 10%);
color: white;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
font-family: system-ui, sans-serif;
}
#ainb-app h2 {
font-family: system-ui, sans-serif;
font-weight: 600;
letter-spacing: 1.5px;
padding-left: 10px;
border-bottom: none;
color: white;
}
#ainb-sidebar {
padding: 0px;
background: linear-gradient(135deg, hsl(var(--ainb-hue), 30%, 12%) 0%, hsl(var(--ainb-hue-2), 30%, 14%) 100%);
z-index: 1;
width: 280px;
overflow-y: auto;
letter-spacing: 0.5px;
}
#ainb-sidebar h2 {
margin: 10px;
height: 34px;
}
.ainb-collapsible-header {
cursor: pointer;
user-select: none;
padding: 5px 0;
}
.ainb-collapsible-content li:hover {
color: #e7e7e7;
}
.ainb-collapsible-content {
display: none;
margin-left: 12px;
}
#ainb-sidebar > .ainb-collapsible {
padding: 6px 6px 6px 11px;
color: hsl(var(--ainb-hue), 10%, 60%);
}
#ainb-sidebar > .ainb-collapsible:not(.ainb-collapsible-open):hover {
background: linear-gradient(135deg, hsl(var(--ainb-hue), 30%, 14%) 0%, hsl(var(--ainb-hue-2), 30%, 15%) 100%);
color: white;
}
#ainb-sidebar > .ainb-collapsible-open {
background: linear-gradient(135deg, hsl(var(--ainb-hue-accent), 78%, 23%) 0%, hsl(var(--ainb-hue-accent-2), 81%, 31%) 100%);
color: white;
}
.ainb-collapsible-open > .ainb-collapsible-content {
display: block;
}
.ainb-pill {
display: inline-block;
padding: 1px 8px;
border-radius: 10px;
font-size: 88%;
font-weight: 500;
}
.ainb-collapsible-content ul {
margin: 4px 0 6px 6px;
}
.ainb-collapsible-content li {
list-style: none;
font-size: 88%;
margin: 7px 0;
}
#ainb-main {
flex: 1 1 0%;
display: flex;
flex-direction: column;
overflow: hidden;
background: linear-gradient(135deg, hsl(var(--ainb-hue), 32%, 15%) 0%, hsl(var(--ainb-hue-2), 42%, 15%) 100%);
}
.ainb-main-header {
flex-shrink: 0;
padding: 15px 20px;
display: flex;
align-items: center;
height: 40px;
justify-content: center;
}
.ainb-main-header h2 {
margin: 0;
font-size: 18px;
padding-left: 0 !important;
}
.ainb-user-badge {
}
.ainb-page-badge {
font-size: 70%;
}
.ainb-main-body {
flex: 1 1 auto;
overflow-y: auto;
background: linear-gradient(135deg, hsl(var(--ainb-hue), 30%, 17%) 0%, hsl(var(--ainb-hue-2), 40%, 17%) 100%);
display: flex;
}
.ainb-main-footer {
flex-shrink: 0;
padding: 12px 20px;
display: flex;
justify-content: flex-end;
gap: 20px;
}
.ainb-status {
margin: auto;
text-align: center;
}
.ainb-diff-container {
display: flex;
flex-direction: column;
font-family: monospace, system-ui, sans-serif;
width: 100%;
}
.ainb-diff-block {
display: grid;
grid-template-columns: 1fr auto 1fr;
}
.ainb-diff-center {
display: flex;
justify-content: center;
align-items: center;
}
.ainb-diff-btn, .ainb-diff-equal {
flex-grow: 1;
height: 100%;
display: flex;
align-items: center;
border: none;
padding-top: 0.2em;
padding-bottom: 0.28em;
}
.ainb-diff-equal {
display: flex;
align-items: center;
justify-content: center;
color: hsl(var(--ainb-hue), 10%, 60%);
font-weight: bold;
font-size: 21px;
width: 40px;
}
.ainb-diff-btn {
transition: background-color 0.15s, color 0.15s;
width: 40px;
justify-content: center;
font-size: 15px;
cursor: pointer;
background: none;
}
.ainb-diff-btn.selected-before {
color: #913057;
}
.ainb-diff-btn.selected-after {
color: #467d52;
}
.added .ainb-diff-btn.selected-before, .deleted .ainb-diff-btn.selected-after {
color: hsl(var(--ainb-hue), 10%, 70%);
}
.ainb-diff-side {
white-space: pre-wrap;
line-height: 1.45;
font-size: 14px;
display: flex;
justify-content: space-between;
align-items: center;
overflow: hidden;
padding: 5px 20px;
}
.before, .after {
flex-direction: row;
}
.context :is(.before, .after) {
background-color: hsla(var(--ainb-hue), 20%, 26%, 30%);
}
:is(.changed, .deleted) .before {
background-color: #913057;
}
:is(.changed, .added) .after {
background-color: #467d52;
}
:is(.added .before, .deleted .after) .ainb-diff-text {
text-align: center;
width: 100%;
}
:is(.added .before, .deleted .after) .ainb-diff-text::before {
content: "∅";
color: #c2c2c2;
}
.ainb-diff-header {
grid-column: 1 / -1;
font-size: 14px;
text-align: center;
font-weight: 600;
color: hsl(var(--ainb-hue), var(--ainb-sat), 60%);
padding-top: 0.5em;
padding-bottom: 0.58em;
}
.ainb-inline-del {
background: #ffe5e5;
color: #b30000;
text-decoration: line-through;
padding: 0 2px;
border-radius: 3px;
}
.ainb-inline-ins {
background: #e6ffe6;
color: #006600;
padding: 0 2px;
border-radius: 3px;
}
.ainb-diff-side.dimmed:not(.context .ainb-diff-side) {
opacity: 0.3;
}
.ainb-action-btn {
padding: 8px 16px;
font-size: 15px;
letter-spacing: 1px;
border: none;
background: transparent;
cursor: pointer;
transition: color 0.15s;
margin: auto 0;
font-family: system-ui, sans-serif;
font-weight: 600;
}
.ainb-action-preview {
color: hsl(var(--ainb-hue), 50%, 90%);
}
.ainb-action-preview:hover {
color: hsl(var(--ainb-hue), 50%, 95%);
}
.ainb-action-post {
color: hsl(var(--ainb-hue-accent), 90%, 70%);
}
.ainb-action-post:hover {
color: hsl(var(--ainb-hue-accent), 90%, 75%);
}
.ainb-action-destructive {
color: hsl(350, 70%, 70%);
}
.ainb-action-destructive:hover {
color: hsl(350, 70%, 75%);
}
.ainb-preview-wrapper {
display: flex;
flex-direction: column;
gap: 16px;
padding: 20px;
}
.ainb-preview-textarea {
width: 100%;
height: 60vh;
font-family: monospace, system-ui, sans-serif;
font-size: 14px;
padding: 12px;
border-radius: 6px;
border: 1px solid #ccc;
resize: vertical;
}
.title-notice {
font-size: 80%;
color: grey;
}
`);
}
// Chapter N: When they actually launch the thing
if(mw.config.get("wgPageName") === "User:Chaotic_Enby/AIDiffBrowser/run") {
setupCSS();
setupAppShell();
loadAINBIndex().then(index => {
renderSidebar(index);
});
}
ax6mta4wu47pgv10lnjipptem0gqb58
743923
743921
2026-05-23T00:12:01Z
Chaotic Enby
58843
743923
javascript
text/javascript
// Chapter 0: I really wanted this in an object and I could've just as well used regex
const emptyRev = 742978 // 1354670824 for enwiki
const AINBStatusStyle = {
needsreview: {
bg: "#FAEEDA",
fg: "#854F0B",
label: "Needs review",
toReview: true,
},
inprogress: {
bg: "#E6F1FB",
fg: "#0C447C",
label: "In progress",
toReview: true
},
clean: {
bg: "#EAF3DE",
fg: "#27500A",
label: "Clean",
toReview: false
},
draftified: {
bg: "#F1EFE8",
fg: "#2C2C2A",
label: "Draftified",
toReview: false
},
stubified: {
bg: "#EEEDFE",
fg: "#3C3489",
label: "Stubified",
toReview: false
},
g15: {
bg: "#FAECE7",
fg: "#4A1B0C",
label: "G15 eligible",
toReview: true
},
afd: {
bg: "#FAEEDA",
fg: "#633806",
label: "AfD",
toReview: false
},
deleted: {
bg: "#FCEBEB",
fg: "#501313",
label: "Deleted",
toReview: false
},
kept: {
bg: "#E1F5EE",
fg: "#085041",
label: "Kept",
toReview: false
},
restored: {
bg: "#E6F1FB",
fg: "#185FA5",
label: "Restored",
toReview: false
},
default: {
bg: "#F1EFE8",
fg: "#2C2C2A",
label: "Unknown",
toReview: true
}
};
// Chapter 1: When we build the main window thing
function setupAppShell() {
const root = document.body;
root.innerHTML = "";
const app = document.createElement("div");
app.id = "ainb-app";
const sidebar = document.createElement("div");
sidebar.id = "ainb-sidebar";
const main = document.createElement("div");
main.id = "ainb-main";
app.appendChild(sidebar);
app.appendChild(main);
root.appendChild(app);
}
// Chapter 2: When we load the AINB data and build the sidebar thing
function pruneIndex(index) {
const cleaned = {};
for (const [user, cats] of Object.entries(index)) {
const nonEmptyCats = {};
for (const [status, items] of Object.entries(cats)) {
if (items && items.length > 0) {
nonEmptyCats[status] = items;
}
}
if (Object.keys(nonEmptyCats).length > 0) {
cleaned[user] = nonEmptyCats;
}
}
return cleaned;
}
function buildAINBIndexFromWikitext(wikitext) {
const result = {};
// --- Split into level-2 sections ---
const sectionRegex = /^==\s*(.+?)\s*==\s*$/gm;
const sections = [];
let match;
let lastIndex = 0;
while ((match = sectionRegex.exec(wikitext)) !== null) {
const heading = match[1].trim();
const start = match.index;
if (sections.length > 0) {
sections[sections.length - 1].text = wikitext.slice(lastIndex, start);
}
sections.push({ heading, text: "" });
lastIndex = sectionRegex.lastIndex;
}
if (sections.length > 0) {
sections[sections.length - 1].text = wikitext.slice(lastIndex);
}
// --- Process each section ---
for (const section of sections) {
const text = section.text;
// 1) Extract username from {{AINB status ...}}
const statusTplRegex = /\{\{\s*AINB\s+status([\s\S]*?)\}\}/i;
const statusMatch = text.match(statusTplRegex);
if (!statusMatch) continue;
const tplBody = statusMatch[1];
const userMatch = tplBody.match(/\|\s*user\s*=\s*([^\|\n]+)/i);
if (!userMatch) continue;
const username = userMatch[1].trim();
if (!username) continue;
if (!result[username]) {
result[username] = {};
}
// 2) Extract the AINB summary HTML block
const summaryRegex = /<!--\s*AINB-SUMMARY\s*-->([\s\S]*?)<!--\s*\/AINB-SUMMARY\s*-->/i;
const summaryMatch = text.match(summaryRegex);
if (!summaryMatch) continue;
const summaryHTML = summaryMatch[1];
// 3) Parse that HTML with DOMParser
const doc = new DOMParser().parseFromString(summaryHTML, "text/html");
const grid = doc.querySelector(".ainb-summary-grid");
if (!grid) continue;
const columns = grid.querySelectorAll(".ainb-summary-column");
columns.forEach(col => {
let statusKey = null;
// Check all defined statuses dynamically
for (const status of Object.keys(AINBStatusStyle)) {
if (col.classList.contains(`ainb-status-${status}`)) {
statusKey = status;
break;
}
}
if (!statusKey) return;
const items = Array.from(col.querySelectorAll("li")).map(li => {
const link = li.querySelector("a");
return (link ? link.textContent : li.textContent).trim().replace(/^\[\[(.*?)\]\]$/, "$1");
});
result[username][statusKey] = items;
});
}
return pruneIndex(result);
}
function loadAINBIndex() {
const api = new mw.Api();
return api.get({
action: "query",
prop: "revisions",
titles: "Wikipedia:AI noticeboard",
rvslots: "main",
rvprop: "content",
formatversion: 2
}).then(data => {
const page = data.query.pages[0];
const wikitext = page.revisions[0].slots.main.content;
return buildAINBIndexFromWikitext(wikitext);
});
}
function renderSidebar(index) {
const sidebar = document.getElementById("ainb-sidebar");
sidebar.innerHTML = "<h2>Review queue</h2>";
for (const [user, categories] of Object.entries(index)) {
const userDiv = document.createElement("div");
userDiv.className = "ainb-collapsible";
const userHeader = document.createElement("div");
userHeader.className = "ainb-collapsible-header";
userHeader.textContent = "▸ " + user;
userHeader.onclick = () => {
// Close other users
document.querySelectorAll("#ainb-sidebar > .ainb-collapsible-open").forEach(el => {
if (el !== userDiv) {
el.classList.remove("ainb-collapsible-open");
const otherHeader = el.querySelector(".ainb-collapsible-header");
if (otherHeader) {
otherHeader.textContent = "▸ " + otherHeader.textContent.substring(2);
}
}
});
userDiv.classList.toggle("ainb-collapsible-open");
userHeader.textContent =
(userDiv.classList.contains("ainb-collapsible-open") ? "▾ " : "▸ ") + user;
};
const userContent = document.createElement("div");
userContent.className = "ainb-collapsible-content";
// Status categories
for (const [status, items] of Object.entries(categories)) {
const statusDiv = document.createElement("div");
statusDiv.className = "ainb-collapsible";
const statusStyle = AINBStatusStyle[status] || AINBStatusStyle.default;
// Determine if this status should be open by default (statuses that need review action)
const shouldOpenByDefault = AINBStatusStyle[status] ? AINBStatusStyle[status].toReview : AINBStatusStyle.default.toReview;
if (shouldOpenByDefault) {
statusDiv.classList.add("ainb-collapsible-open");
}
const statusHeader = document.createElement("div");
statusHeader.className = "ainb-collapsible-header";
const arrow = shouldOpenByDefault ? "▾" : "▸";
statusHeader.innerHTML = `
<span class="ainb-pill" style="
background:${statusStyle.bg};
color:${statusStyle.fg};
">${arrow} ${statusStyle.label}: ${items.length}</span>
`;
statusHeader.onclick = () => {
statusDiv.classList.toggle("ainb-collapsible-open");
const arrow = statusDiv.classList.contains("ainb-collapsible-open") ? "▾" : "▸";
statusHeader.innerHTML = `
<span class="ainb-pill" style="
background:${statusStyle.bg};
color:${statusStyle.fg};
">${arrow} ${statusStyle.label}: ${items.length}</span>
`;
};
const statusContent = document.createElement("div");
statusContent.className = "ainb-collapsible-content";
const ul = document.createElement("ul");
items.forEach(title => {
const li = document.createElement("li");
li.textContent = title;
li.style.cursor = "pointer";
li.onclick = () => openArticle(title, user);
ul.appendChild(li);
});
statusContent.appendChild(ul);
statusDiv.appendChild(statusHeader);
statusDiv.appendChild(statusContent);
userContent.appendChild(statusDiv);
}
userDiv.appendChild(userHeader);
userDiv.appendChild(userContent);
sidebar.appendChild(userDiv);
}
}
// Chapter 3: When we do the thing we do
function fetchRecentEdits(title) {
const api = new mw.Api();
return api.get({
action: "query",
prop: "revisions",
titles: title,
rvlimit: 500,
rvprop: "ids|timestamp|user",
rvdir: "older",
formatversion: 2
}).then(data => {
const page = data.query.pages[0];
return page.revisions || [];
});
}
function findEarliestEditByUser(revisions, username) {
// Filter all edits by the user
const userEdits = revisions.filter(rev => rev.user === username);
if (userEdits.length === 0) return null;
// Revisions are newest → oldest, so the earliest is the LAST one
return userEdits[userEdits.length - 1];
}
function fetchInlineDiff(fromRev, toRev) {
const api = new mw.Api();
return api.get({
action: "compare",
fromrev: fromRev,
torev: toRev,
prop: "diff",
difftype: "inline",
formatversion: 2
}).then(data => data.compare.body);
}
function fetchRevisionWikitext(revid) {
const api = new mw.Api();
return api.get({
action: "query",
prop: "revisions",
revids: revid,
rvslots: "main",
rvprop: "content",
formatversion: 2
}).then(data => {
const page = data.query.pages[0];
return page.revisions[0].slots.main.content;
});
}
function parseInlineDiffHTML(html) {
const wrapped = `<table>${html}</table>`;
return new DOMParser().parseFromString(wrapped, "text/html");
}
function splitWikitextLines(text) {
return text ? text.match(/[^\r\n]*\r?\n|[^\r\n]+/g) || [] : [];
}
function joinWikitextLines(lines) {
return lines.join("");
}
function ensureTrailingLinebreak(text) {
if (!text) {
return "";
}
return /\r?\n$/.test(text) ? text : text + "\n";
}
function parseLineRange(label) {
if (!label) {
return null;
}
const numbers = label.match(/\d+/g);
if (!numbers || numbers.length === 0) {
return null;
}
const start = Number(numbers[0]);
const end = numbers.length > 1 ? Number(numbers[1]) : start;
if (!Number.isFinite(start) || !Number.isFinite(end)) {
return null;
}
return { start, end: Math.max(start, end) };
}
function extractInlineBlocks(doc) {
const blocks = [];
const rows = doc.querySelectorAll("tr");
let currentHeader = null;
let currentSourceLine = 1;
rows.forEach(tr => {
const cell = tr.querySelector("td, th");
if (!cell) return;
for (const child of cell.children) {
if (child.classList.contains("mw-diff-inline-header")) {
currentHeader = child.textContent.trim();
const parsed = parseLineRange(currentHeader);
if (parsed) {
currentSourceLine = parsed.start;
}
continue;
}
let type = null;
let beforeText = "";
let afterText = "";
let displayBeforeHTML = "";
let displayAfterHTML = "";
if (child.classList.contains("mw-diff-inline-context")) {
type = "context";
beforeText = child.textContent;
afterText = child.textContent;
displayBeforeHTML = child.textContent.trim();
displayAfterHTML = child.textContent.trim();
} else if (child.classList.contains("mw-diff-inline-changed")) {
type = "changed";
const parsed = parseChangedBlock(child);
beforeText = parsed.beforeText;
afterText = parsed.afterText;
displayBeforeHTML = parsed.displayBeforeHTML;
displayAfterHTML = parsed.displayAfterHTML;
} else if (child.classList.contains("mw-diff-inline-added") || child.classList.contains("mw-diff-inline-moved-destination")) {
type = "added";
beforeText = "";
afterText = child.textContent;
displayBeforeHTML = "";
displayAfterHTML = child.textContent.trim();
} else if (child.classList.contains("mw-diff-inline-deleted") || child.classList.contains("mw-diff-inline-moved-source")) {
type = "deleted";
beforeText = child.textContent;
afterText = "";
displayBeforeHTML = child.textContent.trim();
displayAfterHTML = "";
}
if (type) {
const sourceLineCount = (type === "added") ? 0 : splitWikitextLines(beforeText).length;
blocks.push({
type,
header: currentHeader,
sourceStartLine: currentSourceLine,
sourceLineCount,
beforeText,
afterText,
displayBeforeHTML,
displayAfterHTML
});
currentSourceLine += sourceLineCount;
currentHeader = null;
}
}
});
return blocks;
}
function parseChangedBlock(div) {
let beforeText = "";
let afterText = "";
let beforeHTML = "";
let afterHTML = "";
div.childNodes.forEach(node => {
if (node.nodeType === Node.TEXT_NODE) {
beforeText += node.textContent;
afterText += node.textContent;
beforeHTML += node.textContent;
afterHTML += node.textContent;
} else if (node.tagName === "DEL") {
beforeText += node.textContent;
beforeHTML += `<del>${node.textContent}</del>`;
} else if (node.tagName === "INS") {
afterText += node.textContent;
afterHTML += `<ins>${node.textContent}</ins>`;
}
});
return {
type: "changed",
beforeText,
afterText,
beforeHTML,
afterHTML,
displayBeforeHTML: beforeHTML.trim(),
displayAfterHTML: afterHTML.trim(),
html: div.innerHTML.trim()
};
}
function applyInlineStyling(html) {
return html
.replace(/<del>(.*?)<\/del>/g, '<span class="ainb-inline-del">$1</span>')
.replace(/<ins>(.*?)<\/ins>/g, '<span class="ainb-inline-ins">$1</span>');
}
const blockIcons = {
"changed": ["+", "+"],
"added": ["−", "+"],
"deleted": ["+", "−"],
"context": ["=", "="],
};
function renderBlocks(diffModel, title, username) {
const blocks = diffModel.blocks || [];
const container = document.createElement("div");
container.className = "ainb-diff-container";
blocks.forEach(block => {
// Default selection to "before"
block.selection = "before";
const row = document.createElement("div");
row.className = `ainb-diff-block ${block.type}`;
// Optional header (Line X:)
if (block.header) {
const header = document.createElement("div");
header.className = "ainb-diff-header";
header.textContent = block.header;
row.appendChild(header);
}
// --- LEFT SIDE (before) ---
const left = document.createElement("div");
left.className = "ainb-diff-side before";
left.innerHTML = `<div class="ainb-diff-text">${applyInlineStyling(block.displayBeforeHTML || block.beforeHTML || block.displayBeforeHTML || block.beforeText || "")}</div>`;
// --- CENTER BUTTON ---
const center = document.createElement("div");
center.className = "ainb-diff-center";
let centerBtn = null;
if (block.type === "context") {
const equalSign = document.createElement("span");
equalSign.className = "ainb-diff-equal";
equalSign.textContent = "=";
center.appendChild(equalSign);
} else {
centerBtn = document.createElement("button");
centerBtn.className = "ainb-diff-btn";
center.appendChild(centerBtn);
}
// --- RIGHT SIDE (after) ---
const right = document.createElement("div");
right.className = "ainb-diff-side after";
right.innerHTML = `<div class="ainb-diff-text">${applyInlineStyling(block.displayAfterHTML || block.afterHTML || block.displayAfterHTML || block.afterText || "")}</div>`;
// --- SELECTION HANDLERS ---
function updateSelectionUI() {
// Reset classes
left.classList.remove("selected", "dimmed");
right.classList.remove("selected", "dimmed");
if (centerBtn) {
centerBtn.classList.remove("selected-before", "selected-after");
}
if (block.selection === "before") {
left.classList.add("selected");
right.classList.add("dimmed");
if (centerBtn) {
centerBtn.classList.add("selected-before");
centerBtn.textContent = "◀";
}
} else if (block.selection === "after") {
right.classList.add("selected");
left.classList.add("dimmed");
if (centerBtn) {
centerBtn.classList.add("selected-after");
centerBtn.textContent = "▶";
}
}
}
if (centerBtn) {
centerBtn.addEventListener("click", () => {
block.selection = block.selection === "before" ? "after" : "before";
updateSelectionUI();
});
}
// Initial UI state
updateSelectionUI();
// Append sides
row.appendChild(left);
row.appendChild(center);
row.appendChild(right);
container.appendChild(row);
});
return container;
}
// Chapter 4: Where we take an aside to build a preview screen
function reconstructWikitext(diffData) {
const originalLines = splitWikitextLines(diffData.originalWikitext || "");
const blocks = (diffData.blocks || []).filter(block => block.type !== "context");
const outputLines = [];
let cursor = 0; // 0-indexed current line in originalLines
for (const block of blocks) {
const startIdx = block.sourceStartLine - 1; // 0-indexed
// Catch up unmodified lines
if (startIdx > cursor) {
outputLines.push(...originalLines.slice(cursor, startIdx));
cursor = startIdx;
}
// Append the selected text
const selectedText = block.selection === "after" ? (block.afterText || "") : (block.beforeText || "");
if (selectedText) {
outputLines.push(ensureTrailingLinebreak(selectedText));
}
// Advance cursor over the original lines that this block replaces
cursor = startIdx + block.sourceLineCount;
}
// Append any remaining original lines
if (cursor < originalLines.length) {
outputLines.push(...originalLines.slice(cursor));
}
return joinWikitextLines(outputLines);
}
function showPreviewScreen(diffData, title, username) {
const main = document.getElementById("ainb-main");
main.innerHTML = ""; // Clear diff UI
const header = document.createElement("div");
header.className = "ainb-main-header";
header.innerHTML = `<h2><span class="ainb-page-badge">${title}</span> ⋅ <span class="ainb-user-badge"> ${username}</span></h2>`;
const body = document.createElement("div");
body.className = "ainb-main-body ainb-preview-wrapper";
const textarea = document.createElement("textarea");
textarea.className = "ainb-preview-textarea";
textarea.value = reconstructWikitext(diffData);
body.appendChild(textarea);
const footer = document.createElement("div");
footer.className = "ainb-main-footer";
const backBtn = document.createElement("button");
backBtn.textContent = "Back to diff";
backBtn.className = "ainb-action-btn ainb-action-preview";
backBtn.addEventListener("click", () => {
openArticle(title, username);
});
footer.appendChild(backBtn);
main.appendChild(header);
main.appendChild(body);
main.appendChild(footer);
}
function postArticleEdit(diffData, title, username) {
const main = document.getElementById("ainb-main");
const originalHTML = main.innerHTML;
main.innerHTML = `
<div class="ainb-main-header">
<h2><span class="ainb-page-badge">${title}</span> ⋅ <span class="ainb-user-badge"> ${username}</span></h2>
</div>
<div class="ainb-main-body">
<div class="ainb-status">Posting edit to <b>${title}</b>...</div>
</div>
`;
const newWikitext = reconstructWikitext(diffData);
const api = new mw.Api();
api.postWithToken("csrf", {
action: "edit",
title: title,
text: newWikitext,
summary: `Cleaned up suspected AI-generated edits by [[User:${username}]] via [[User:Chaotic_Enby/AIDiffBrowser|AIDiffBrowser]]`,
bot: false
}).then(() => {
main.innerHTML = `
<div class="ainb-main-header">
<h2><span class="ainb-page-badge">${title}</span> ⋅ <span class="ainb-user-badge"> ${username}</span></h2>
</div>
<div class="ainb-main-body">
<div class="ainb-status" style="color: #6aab6a;">Success! Edit posted to <b>${title}</b>.</div>
</div>
`;
}).catch(err => {
main.innerHTML = `
<div class="ainb-main-header">
<h2><span class="ainb-page-badge">${title}</span> ⋅ <span class="ainb-user-badge"> ${username}</span></h2>
</div>
<div class="ainb-main-body">
<div class="ainb-status" style="color: #c95c5c;">Error posting edit: ${err}</div>
</div>
<div class="ainb-main-footer">
<button class="ainb-action-btn ainb-action-preview" id="ainb-error-back-btn">Back to diff</button>
</div>
`;
document.getElementById("ainb-error-back-btn").addEventListener("click", () => {
main.innerHTML = originalHTML;
// Rebind events since replacing innerHTML destroys them
openArticle(title, username);
});
});
}
function tagPage(revId, title, username, tag) {
if (tag === "g15") {
tagCode = "{{db-g15}}\n\n";
summary = 'Tagged for [[WP:G15|CSD G15]]';
} else if (tag === "prod") {
tagCode = "{{subst:prod llm}}\n\n";
summary = 'Tagged for [[WP:LLMPROD|LLMPROD]]';
}
const main = document.getElementById("ainb-main");
main.innerHTML = `
<div class="ainb-main-header">
<h2><span class="ainb-page-badge">${title}</span> ⋅ <span class="ainb-user-badge"> ${username}</span></h2>
</div>
<div class="ainb-main-body">
<div class="ainb-status">Tagging page for ${tag === "g15" ? "G15 deletion" : "LLMPROD"}...</div>
</div>
`;
const api = new mw.Api();
fetchRevisionWikitext(revId).then((wikitext) => {
api.postWithToken("csrf", {
action: "edit",
title: title,
text: tagCode + wikitext,
summary: summary + " via [[User:Chaotic_Enby/AIDiffBrowser|AIDiffBrowser]]",
bot: false
})}).then(() => {
main.innerHTML = `
<div class="ainb-main-header">
<h2><span class="ainb-page-badge">${title}</span> ⋅ <span class="ainb-user-badge"> ${username}</span></h2>
</div>
<div class="ainb-main-body">
<div class="ainb-status" style="color: #6aab6a;">Success! Page tagged for ${tag === "g15" ? "G15 deletion" : "LLMPROD"}.</div>
</div>
`;
}).catch(err => {
main.innerHTML = `
<div class="ainb-main-header">
<h2><span class="ainb-page-badge">${title}</span> ⋅ <span class="ainb-user-badge"> ${username}</span></h2>
</div>
<div class="ainb-main-body">
<div class="ainb-status" style="color: #c95c5c;">Error tagging page: ${err}</div>
</div>
`;
});
}
// Chapter 3.2: Where we go back to the main screen
function openArticle(title, username) {
const main = document.getElementById("ainb-main");
main.innerHTML = `
<div class="ainb-main-header">
<h2><span class="ainb-page-badge">${title}</span> ⋅ <span class="ainb-user-badge"> ${username}</span></h2>
</div>
<div class="ainb-main-body">
<div class="ainb-status">Loading diff...</div>
</div>
`;
fetchRecentEdits(title)
.then(revs => {
const beforeRevObj = findEarliestEditByUser(revs, username);
if (!beforeRevObj) {
main.innerHTML = `
<div class="ainb-main-header">
<h2><span class="ainb-page-badge">${title}</span> ⋅ <span class="ainb-user-badge"> ${username}</span></h2>
</div>
<div class="ainb-main-body">
<div class="ainb-status">No edits by <b>${username}</b> could be found.</div>
</div>
`;
return null;
}
const beforeRev = beforeRevObj.parentid || emptyRev; // Use empty revision ID for first edits
const isFirstEdit = !beforeRevObj.parentid; // Track if this is a first-edit scenario
const currentRev = revs[0].revid; // newest revision
return Promise.all([
fetchRevisionWikitext(beforeRev),
fetchInlineDiff(beforeRev, currentRev)
]).then(([originalWikitext, diffHTML]) => ({
originalWikitext,
diffHTML,
isFirstEdit,
currentRev
}));
})
.then(diffData => {
if (!diffData) return;
const doc = parseInlineDiffHTML(diffData.diffHTML);
const blocks = extractInlineBlocks(doc);
const diffModel = {
originalWikitext: diffData.originalWikitext,
blocks,
isFirstEdit: diffData.isFirstEdit,
currentRev: diffData.currentRev
};
main.innerHTML = "";
const header = document.createElement("div");
header.className = "ainb-main-header";
if(diffData.isFirstEdit) {
header.innerHTML = `<h2><span class="ainb-page-badge">${title}</span> ⋅ <span class="ainb-user-badge"> ${username}</span> <span class="ainb-page-creator-badge">(page creator)</span></h2>`;
} else {
header.innerHTML = `<h2><span class="ainb-page-badge">${title}</span> ⋅ <span class="ainb-user-badge"> ${username}</span></h2>`;
}
const body = document.createElement("div");
body.className = "ainb-main-body";
body.appendChild(renderBlocks(diffModel, title, username));
const footer = document.createElement("div");
footer.className = "ainb-main-footer";
const previewBtn = document.createElement("button");
previewBtn.textContent = "Preview";
previewBtn.className = "ainb-action-btn ainb-action-preview";
previewBtn.addEventListener("click", () => {
showPreviewScreen(diffModel, title, username);
});
const postBtn = document.createElement("button");
postBtn.textContent = "Post";
postBtn.className = "ainb-action-btn ainb-action-post";
postBtn.addEventListener("click", () => {
postArticleEdit(diffModel, title, username);
});
footer.appendChild(previewBtn);
footer.appendChild(postBtn);
// Add extra buttons for first-edit articles
if (diffModel.isFirstEdit) {
const prodBtn = document.createElement("button");
prodBtn.textContent = "LLMPROD";
prodBtn.className = "ainb-action-btn ainb-action-destructive";
prodBtn.addEventListener("click", () => {
tagPage(diffModel.currentRev, title, username, "prod");
});
footer.appendChild(prodBtn);
const g15Btn = document.createElement("button");
g15Btn.textContent = "G15";
g15Btn.className = "ainb-action-btn ainb-action-destructive";
g15Btn.addEventListener("click", () => {
tagPage(diffModel.currentRev, title, username, "g15");
});
footer.appendChild(g15Btn);
}
main.appendChild(header);
main.appendChild(body);
main.appendChild(footer);
})
.catch(err => {
main.innerHTML = `
<div class="ainb-main-header">
<h2><span class="ainb-page-badge">${title}</span> ⋅ <span class="ainb-user-badge"> ${username}</span></h2>
</div>
<div class="ainb-main-body">
<div class="ainb-status">Error loading diff: ${err}</div>
</div>
`;
});
}
// Chapter N-1: The fancy stuff
function setupCSS(){
mw.util.addCSS(`
:root {
--ainb-hue: 220;
--ainb-hue-2: 240;
--ainb-hue-accent: 293;
--ainb-hue-accent-2: 324;
}
#ainb-app {
background-color: hsl(var(--ainb-hue), 10%, 10%);
color: white;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
font-family: system-ui, sans-serif;
}
#ainb-app h2 {
font-family: system-ui, sans-serif;
font-weight: 600;
letter-spacing: 1.5px;
padding-left: 10px;
border-bottom: none;
color: white;
}
#ainb-sidebar {
padding: 0px;
background: linear-gradient(135deg, hsl(var(--ainb-hue), 30%, 12%) 0%, hsl(var(--ainb-hue-2), 30%, 14%) 100%);
z-index: 1;
width: 280px;
overflow-y: auto;
letter-spacing: 0.5px;
}
#ainb-sidebar h2 {
margin: 10px;
height: 34px;
}
.ainb-collapsible-header {
cursor: pointer;
user-select: none;
padding: 5px 0;
}
.ainb-collapsible-content li:hover {
color: #e7e7e7;
}
.ainb-collapsible-content {
display: none;
margin-left: 12px;
}
#ainb-sidebar > .ainb-collapsible {
padding: 6px 6px 6px 11px;
color: hsl(var(--ainb-hue), 10%, 60%);
}
#ainb-sidebar > .ainb-collapsible:not(.ainb-collapsible-open):hover {
background: linear-gradient(135deg, hsl(var(--ainb-hue), 30%, 14%) 0%, hsl(var(--ainb-hue-2), 30%, 15%) 100%);
color: white;
}
#ainb-sidebar > .ainb-collapsible-open {
background: linear-gradient(135deg, hsl(var(--ainb-hue-accent), 78%, 23%) 0%, hsl(var(--ainb-hue-accent-2), 81%, 31%) 100%);
color: white;
}
.ainb-collapsible-open > .ainb-collapsible-content {
display: block;
}
.ainb-pill {
display: inline-block;
padding: 1px 8px;
border-radius: 10px;
font-size: 88%;
font-weight: 500;
}
.ainb-collapsible-content ul {
margin: 4px 0 6px 6px;
}
.ainb-collapsible-content li {
list-style: none;
font-size: 88%;
margin: 7px 0;
}
#ainb-main {
flex: 1 1 0%;
display: flex;
flex-direction: column;
overflow: hidden;
background: linear-gradient(135deg, hsl(var(--ainb-hue), 32%, 15%) 0%, hsl(var(--ainb-hue-2), 42%, 15%) 100%);
}
.ainb-main-header {
flex-shrink: 0;
padding: 15px 20px;
display: flex;
align-items: center;
height: 40px;
justify-content: center;
}
.ainb-main-header h2 {
margin: 0;
font-size: 18px;
padding-left: 0 !important;
}
.ainb-page-creator-badge {
font-size: 70%;
}
.ainb-main-body {
flex: 1 1 auto;
overflow-y: auto;
background: linear-gradient(135deg, hsl(var(--ainb-hue), 30%, 17%) 0%, hsl(var(--ainb-hue-2), 40%, 17%) 100%);
display: flex;
}
.ainb-main-footer {
flex-shrink: 0;
padding: 12px 20px;
display: flex;
justify-content: flex-end;
gap: 20px;
}
.ainb-status {
margin: auto;
text-align: center;
}
.ainb-diff-container {
display: flex;
flex-direction: column;
font-family: monospace, system-ui, sans-serif;
width: 100%;
}
.ainb-diff-block {
display: grid;
grid-template-columns: 1fr auto 1fr;
}
.ainb-diff-center {
display: flex;
justify-content: center;
align-items: center;
}
.ainb-diff-btn, .ainb-diff-equal {
flex-grow: 1;
height: 100%;
display: flex;
align-items: center;
border: none;
padding-top: 0.2em;
padding-bottom: 0.28em;
}
.ainb-diff-equal {
display: flex;
align-items: center;
justify-content: center;
color: hsl(var(--ainb-hue), 10%, 60%);
font-weight: bold;
font-size: 21px;
width: 40px;
}
.ainb-diff-btn {
transition: background-color 0.15s, color 0.15s;
width: 40px;
justify-content: center;
font-size: 15px;
cursor: pointer;
background: none;
}
.ainb-diff-btn.selected-before {
color: #913057;
}
.ainb-diff-btn.selected-after {
color: #467d52;
}
.added .ainb-diff-btn.selected-before, .deleted .ainb-diff-btn.selected-after {
color: hsl(var(--ainb-hue), 10%, 70%);
}
.ainb-diff-side {
white-space: pre-wrap;
line-height: 1.45;
font-size: 14px;
display: flex;
justify-content: space-between;
align-items: center;
overflow: hidden;
padding: 5px 20px;
}
.before, .after {
flex-direction: row;
}
.context :is(.before, .after) {
background-color: hsla(var(--ainb-hue), 20%, 26%, 30%);
}
:is(.changed, .deleted) .before {
background-color: #913057;
}
:is(.changed, .added) .after {
background-color: #467d52;
}
:is(.added .before, .deleted .after) .ainb-diff-text {
text-align: center;
width: 100%;
}
:is(.added .before, .deleted .after) .ainb-diff-text::before {
content: "∅";
color: #c2c2c2;
}
.ainb-diff-header {
grid-column: 1 / -1;
font-size: 14px;
text-align: center;
font-weight: 600;
color: hsl(var(--ainb-hue), var(--ainb-sat), 60%);
padding-top: 0.5em;
padding-bottom: 0.58em;
}
.ainb-inline-del {
background: #ffe5e5;
color: #b30000;
text-decoration: line-through;
padding: 0 2px;
border-radius: 3px;
}
.ainb-inline-ins {
background: #e6ffe6;
color: #006600;
padding: 0 2px;
border-radius: 3px;
}
.ainb-diff-side.dimmed:not(.context .ainb-diff-side) {
opacity: 0.3;
}
.ainb-action-btn {
padding: 8px 16px;
font-size: 15px;
letter-spacing: 1px;
border: none;
background: transparent;
cursor: pointer;
transition: color 0.15s;
margin: auto 0;
font-family: system-ui, sans-serif;
font-weight: 600;
}
.ainb-action-preview {
color: hsl(var(--ainb-hue), 50%, 90%);
}
.ainb-action-preview:hover {
color: hsl(var(--ainb-hue), 50%, 95%);
}
.ainb-action-post {
color: hsl(var(--ainb-hue-accent), 90%, 70%);
}
.ainb-action-post:hover {
color: hsl(var(--ainb-hue-accent), 90%, 75%);
}
.ainb-action-destructive {
color: hsl(350, 70%, 70%);
}
.ainb-action-destructive:hover {
color: hsl(350, 70%, 75%);
}
.ainb-preview-wrapper {
display: flex;
flex-direction: column;
gap: 16px;
padding: 20px;
}
.ainb-preview-textarea {
width: 100%;
height: 60vh;
font-family: monospace, system-ui, sans-serif;
font-size: 14px;
padding: 12px;
border-radius: 6px;
border: 1px solid #ccc;
resize: vertical;
}
.title-notice {
font-size: 80%;
color: grey;
}
`);
}
// Chapter N: When they actually launch the thing
if(mw.config.get("wgPageName") === "User:Chaotic_Enby/AIDiffBrowser/run") {
setupCSS();
setupAppShell();
loadAINBIndex().then(index => {
renderSidebar(index);
});
}
trl3xt2tg0txfq3xuco787oq4w8xkpt
743924
743923
2026-05-23T00:20:25Z
Chaotic Enby
58843
preview
743924
javascript
text/javascript
// Chapter 0: I really wanted this in an object and I could've just as well used regex
const emptyRev = 742978 // 1354670824 for enwiki
const AINBStatusStyle = {
needsreview: {
bg: "#FAEEDA",
fg: "#854F0B",
label: "Needs review",
toReview: true,
},
inprogress: {
bg: "#E6F1FB",
fg: "#0C447C",
label: "In progress",
toReview: true
},
clean: {
bg: "#EAF3DE",
fg: "#27500A",
label: "Clean",
toReview: false
},
draftified: {
bg: "#F1EFE8",
fg: "#2C2C2A",
label: "Draftified",
toReview: false
},
stubified: {
bg: "#EEEDFE",
fg: "#3C3489",
label: "Stubified",
toReview: false
},
g15: {
bg: "#FAECE7",
fg: "#4A1B0C",
label: "G15 eligible",
toReview: true
},
afd: {
bg: "#FAEEDA",
fg: "#633806",
label: "AfD",
toReview: false
},
deleted: {
bg: "#FCEBEB",
fg: "#501313",
label: "Deleted",
toReview: false
},
kept: {
bg: "#E1F5EE",
fg: "#085041",
label: "Kept",
toReview: false
},
restored: {
bg: "#E6F1FB",
fg: "#185FA5",
label: "Restored",
toReview: false
},
default: {
bg: "#F1EFE8",
fg: "#2C2C2A",
label: "Unknown",
toReview: true
}
};
// Chapter 1: When we build the main window thing
function setupAppShell() {
const root = document.body;
root.innerHTML = "";
const app = document.createElement("div");
app.id = "ainb-app";
const sidebar = document.createElement("div");
sidebar.id = "ainb-sidebar";
const main = document.createElement("div");
main.id = "ainb-main";
app.appendChild(sidebar);
app.appendChild(main);
root.appendChild(app);
}
// Chapter 2: When we load the AINB data and build the sidebar thing
function pruneIndex(index) {
const cleaned = {};
for (const [user, cats] of Object.entries(index)) {
const nonEmptyCats = {};
for (const [status, items] of Object.entries(cats)) {
if (items && items.length > 0) {
nonEmptyCats[status] = items;
}
}
if (Object.keys(nonEmptyCats).length > 0) {
cleaned[user] = nonEmptyCats;
}
}
return cleaned;
}
function buildAINBIndexFromWikitext(wikitext) {
const result = {};
// --- Split into level-2 sections ---
const sectionRegex = /^==\s*(.+?)\s*==\s*$/gm;
const sections = [];
let match;
let lastIndex = 0;
while ((match = sectionRegex.exec(wikitext)) !== null) {
const heading = match[1].trim();
const start = match.index;
if (sections.length > 0) {
sections[sections.length - 1].text = wikitext.slice(lastIndex, start);
}
sections.push({ heading, text: "" });
lastIndex = sectionRegex.lastIndex;
}
if (sections.length > 0) {
sections[sections.length - 1].text = wikitext.slice(lastIndex);
}
// --- Process each section ---
for (const section of sections) {
const text = section.text;
// 1) Extract username from {{AINB status ...}}
const statusTplRegex = /\{\{\s*AINB\s+status([\s\S]*?)\}\}/i;
const statusMatch = text.match(statusTplRegex);
if (!statusMatch) continue;
const tplBody = statusMatch[1];
const userMatch = tplBody.match(/\|\s*user\s*=\s*([^\|\n]+)/i);
if (!userMatch) continue;
const username = userMatch[1].trim();
if (!username) continue;
if (!result[username]) {
result[username] = {};
}
// 2) Extract the AINB summary HTML block
const summaryRegex = /<!--\s*AINB-SUMMARY\s*-->([\s\S]*?)<!--\s*\/AINB-SUMMARY\s*-->/i;
const summaryMatch = text.match(summaryRegex);
if (!summaryMatch) continue;
const summaryHTML = summaryMatch[1];
// 3) Parse that HTML with DOMParser
const doc = new DOMParser().parseFromString(summaryHTML, "text/html");
const grid = doc.querySelector(".ainb-summary-grid");
if (!grid) continue;
const columns = grid.querySelectorAll(".ainb-summary-column");
columns.forEach(col => {
let statusKey = null;
// Check all defined statuses dynamically
for (const status of Object.keys(AINBStatusStyle)) {
if (col.classList.contains(`ainb-status-${status}`)) {
statusKey = status;
break;
}
}
if (!statusKey) return;
const items = Array.from(col.querySelectorAll("li")).map(li => {
const link = li.querySelector("a");
return (link ? link.textContent : li.textContent).trim().replace(/^\[\[(.*?)\]\]$/, "$1");
});
result[username][statusKey] = items;
});
}
return pruneIndex(result);
}
function loadAINBIndex() {
const api = new mw.Api();
return api.get({
action: "query",
prop: "revisions",
titles: "Wikipedia:AI noticeboard",
rvslots: "main",
rvprop: "content",
formatversion: 2
}).then(data => {
const page = data.query.pages[0];
const wikitext = page.revisions[0].slots.main.content;
return buildAINBIndexFromWikitext(wikitext);
});
}
function renderSidebar(index) {
const sidebar = document.getElementById("ainb-sidebar");
sidebar.innerHTML = "<h2>Review queue</h2>";
for (const [user, categories] of Object.entries(index)) {
const userDiv = document.createElement("div");
userDiv.className = "ainb-collapsible";
const userHeader = document.createElement("div");
userHeader.className = "ainb-collapsible-header";
userHeader.textContent = "▸ " + user;
userHeader.onclick = () => {
// Close other users
document.querySelectorAll("#ainb-sidebar > .ainb-collapsible-open").forEach(el => {
if (el !== userDiv) {
el.classList.remove("ainb-collapsible-open");
const otherHeader = el.querySelector(".ainb-collapsible-header");
if (otherHeader) {
otherHeader.textContent = "▸ " + otherHeader.textContent.substring(2);
}
}
});
userDiv.classList.toggle("ainb-collapsible-open");
userHeader.textContent =
(userDiv.classList.contains("ainb-collapsible-open") ? "▾ " : "▸ ") + user;
};
const userContent = document.createElement("div");
userContent.className = "ainb-collapsible-content";
// Status categories
for (const [status, items] of Object.entries(categories)) {
const statusDiv = document.createElement("div");
statusDiv.className = "ainb-collapsible";
const statusStyle = AINBStatusStyle[status] || AINBStatusStyle.default;
// Determine if this status should be open by default (statuses that need review action)
const shouldOpenByDefault = AINBStatusStyle[status] ? AINBStatusStyle[status].toReview : AINBStatusStyle.default.toReview;
if (shouldOpenByDefault) {
statusDiv.classList.add("ainb-collapsible-open");
}
const statusHeader = document.createElement("div");
statusHeader.className = "ainb-collapsible-header";
const arrow = shouldOpenByDefault ? "▾" : "▸";
statusHeader.innerHTML = `
<span class="ainb-pill" style="
background:${statusStyle.bg};
color:${statusStyle.fg};
">${arrow} ${statusStyle.label}: ${items.length}</span>
`;
statusHeader.onclick = () => {
statusDiv.classList.toggle("ainb-collapsible-open");
const arrow = statusDiv.classList.contains("ainb-collapsible-open") ? "▾" : "▸";
statusHeader.innerHTML = `
<span class="ainb-pill" style="
background:${statusStyle.bg};
color:${statusStyle.fg};
">${arrow} ${statusStyle.label}: ${items.length}</span>
`;
};
const statusContent = document.createElement("div");
statusContent.className = "ainb-collapsible-content";
const ul = document.createElement("ul");
items.forEach(title => {
const li = document.createElement("li");
li.textContent = title;
li.style.cursor = "pointer";
li.onclick = () => openArticle(title, user);
ul.appendChild(li);
});
statusContent.appendChild(ul);
statusDiv.appendChild(statusHeader);
statusDiv.appendChild(statusContent);
userContent.appendChild(statusDiv);
}
userDiv.appendChild(userHeader);
userDiv.appendChild(userContent);
sidebar.appendChild(userDiv);
}
}
// Chapter 3: When we do the thing we do
function fetchRecentEdits(title) {
const api = new mw.Api();
return api.get({
action: "query",
prop: "revisions",
titles: title,
rvlimit: 500,
rvprop: "ids|timestamp|user",
rvdir: "older",
formatversion: 2
}).then(data => {
const page = data.query.pages[0];
return page.revisions || [];
});
}
function findEarliestEditByUser(revisions, username) {
// Filter all edits by the user
const userEdits = revisions.filter(rev => rev.user === username);
if (userEdits.length === 0) return null;
// Revisions are newest → oldest, so the earliest is the LAST one
return userEdits[userEdits.length - 1];
}
function fetchInlineDiff(fromRev, toRev) {
const api = new mw.Api();
return api.get({
action: "compare",
fromrev: fromRev,
torev: toRev,
prop: "diff",
difftype: "inline",
formatversion: 2
}).then(data => data.compare.body);
}
function fetchRevisionWikitext(revid) {
const api = new mw.Api();
return api.get({
action: "query",
prop: "revisions",
revids: revid,
rvslots: "main",
rvprop: "content",
formatversion: 2
}).then(data => {
const page = data.query.pages[0];
return page.revisions[0].slots.main.content;
});
}
function parseInlineDiffHTML(html) {
const wrapped = `<table>${html}</table>`;
return new DOMParser().parseFromString(wrapped, "text/html");
}
function splitWikitextLines(text) {
return text ? text.match(/[^\r\n]*\r?\n|[^\r\n]+/g) || [] : [];
}
function joinWikitextLines(lines) {
return lines.join("");
}
function ensureTrailingLinebreak(text) {
if (!text) {
return "";
}
return /\r?\n$/.test(text) ? text : text + "\n";
}
function parseLineRange(label) {
if (!label) {
return null;
}
const numbers = label.match(/\d+/g);
if (!numbers || numbers.length === 0) {
return null;
}
const start = Number(numbers[0]);
const end = numbers.length > 1 ? Number(numbers[1]) : start;
if (!Number.isFinite(start) || !Number.isFinite(end)) {
return null;
}
return { start, end: Math.max(start, end) };
}
function extractInlineBlocks(doc) {
const blocks = [];
const rows = doc.querySelectorAll("tr");
let currentHeader = null;
let currentSourceLine = 1;
rows.forEach(tr => {
const cell = tr.querySelector("td, th");
if (!cell) return;
for (const child of cell.children) {
if (child.classList.contains("mw-diff-inline-header")) {
currentHeader = child.textContent.trim();
const parsed = parseLineRange(currentHeader);
if (parsed) {
currentSourceLine = parsed.start;
}
continue;
}
let type = null;
let beforeText = "";
let afterText = "";
let displayBeforeHTML = "";
let displayAfterHTML = "";
if (child.classList.contains("mw-diff-inline-context")) {
type = "context";
beforeText = child.textContent;
afterText = child.textContent;
displayBeforeHTML = child.textContent.trim();
displayAfterHTML = child.textContent.trim();
} else if (child.classList.contains("mw-diff-inline-changed")) {
type = "changed";
const parsed = parseChangedBlock(child);
beforeText = parsed.beforeText;
afterText = parsed.afterText;
displayBeforeHTML = parsed.displayBeforeHTML;
displayAfterHTML = parsed.displayAfterHTML;
} else if (child.classList.contains("mw-diff-inline-added") || child.classList.contains("mw-diff-inline-moved-destination")) {
type = "added";
beforeText = "";
afterText = child.textContent;
displayBeforeHTML = "";
displayAfterHTML = child.textContent.trim();
} else if (child.classList.contains("mw-diff-inline-deleted") || child.classList.contains("mw-diff-inline-moved-source")) {
type = "deleted";
beforeText = child.textContent;
afterText = "";
displayBeforeHTML = child.textContent.trim();
displayAfterHTML = "";
}
if (type) {
const sourceLineCount = (type === "added") ? 0 : splitWikitextLines(beforeText).length;
blocks.push({
type,
header: currentHeader,
sourceStartLine: currentSourceLine,
sourceLineCount,
beforeText,
afterText,
displayBeforeHTML,
displayAfterHTML
});
currentSourceLine += sourceLineCount;
currentHeader = null;
}
}
});
return blocks;
}
function parseChangedBlock(div) {
let beforeText = "";
let afterText = "";
let beforeHTML = "";
let afterHTML = "";
div.childNodes.forEach(node => {
if (node.nodeType === Node.TEXT_NODE) {
beforeText += node.textContent;
afterText += node.textContent;
beforeHTML += node.textContent;
afterHTML += node.textContent;
} else if (node.tagName === "DEL") {
beforeText += node.textContent;
beforeHTML += `<del>${node.textContent}</del>`;
} else if (node.tagName === "INS") {
afterText += node.textContent;
afterHTML += `<ins>${node.textContent}</ins>`;
}
});
return {
type: "changed",
beforeText,
afterText,
beforeHTML,
afterHTML,
displayBeforeHTML: beforeHTML.trim(),
displayAfterHTML: afterHTML.trim(),
html: div.innerHTML.trim()
};
}
function applyInlineStyling(html) {
return html
.replace(/<del>(.*?)<\/del>/g, '<span class="ainb-inline-del">$1</span>')
.replace(/<ins>(.*?)<\/ins>/g, '<span class="ainb-inline-ins">$1</span>');
}
const blockIcons = {
"changed": ["+", "+"],
"added": ["−", "+"],
"deleted": ["+", "−"],
"context": ["=", "="],
};
function renderBlocks(diffModel, title, username) {
const blocks = diffModel.blocks || [];
const container = document.createElement("div");
container.className = "ainb-diff-container";
blocks.forEach(block => {
// Default selection to "before"
block.selection = "before";
const row = document.createElement("div");
row.className = `ainb-diff-block ${block.type}`;
// Optional header (Line X:)
if (block.header) {
const header = document.createElement("div");
header.className = "ainb-diff-header";
header.textContent = block.header;
row.appendChild(header);
}
// --- LEFT SIDE (before) ---
const left = document.createElement("div");
left.className = "ainb-diff-side before";
left.innerHTML = `<div class="ainb-diff-text">${applyInlineStyling(block.displayBeforeHTML || block.beforeHTML || block.displayBeforeHTML || block.beforeText || "")}</div>`;
// --- CENTER BUTTON ---
const center = document.createElement("div");
center.className = "ainb-diff-center";
let centerBtn = null;
if (block.type === "context") {
const equalSign = document.createElement("span");
equalSign.className = "ainb-diff-equal";
equalSign.textContent = "=";
center.appendChild(equalSign);
} else {
centerBtn = document.createElement("button");
centerBtn.className = "ainb-diff-btn";
center.appendChild(centerBtn);
}
// --- RIGHT SIDE (after) ---
const right = document.createElement("div");
right.className = "ainb-diff-side after";
right.innerHTML = `<div class="ainb-diff-text">${applyInlineStyling(block.displayAfterHTML || block.afterHTML || block.displayAfterHTML || block.afterText || "")}</div>`;
// --- SELECTION HANDLERS ---
function updateSelectionUI() {
// Reset classes
left.classList.remove("selected", "dimmed");
right.classList.remove("selected", "dimmed");
if (centerBtn) {
centerBtn.classList.remove("selected-before", "selected-after");
}
if (block.selection === "before") {
left.classList.add("selected");
right.classList.add("dimmed");
if (centerBtn) {
centerBtn.classList.add("selected-before");
centerBtn.textContent = "◀";
}
} else if (block.selection === "after") {
right.classList.add("selected");
left.classList.add("dimmed");
if (centerBtn) {
centerBtn.classList.add("selected-after");
centerBtn.textContent = "▶";
}
}
}
if (centerBtn) {
centerBtn.addEventListener("click", () => {
block.selection = block.selection === "before" ? "after" : "before";
updateSelectionUI();
});
}
// Initial UI state
updateSelectionUI();
// Append sides
row.appendChild(left);
row.appendChild(center);
row.appendChild(right);
container.appendChild(row);
});
return container;
}
// Chapter 4: Where we take an aside to build a preview screen
function reconstructWikitext(diffData) {
const originalLines = splitWikitextLines(diffData.originalWikitext || "");
const blocks = (diffData.blocks || []).filter(block => block.type !== "context");
const outputLines = [];
let cursor = 0; // 0-indexed current line in originalLines
for (const block of blocks) {
const startIdx = block.sourceStartLine - 1; // 0-indexed
// Catch up unmodified lines
if (startIdx > cursor) {
outputLines.push(...originalLines.slice(cursor, startIdx));
cursor = startIdx;
}
// Append the selected text
const selectedText = block.selection === "after" ? (block.afterText || "") : (block.beforeText || "");
if (selectedText) {
outputLines.push(ensureTrailingLinebreak(selectedText));
}
// Advance cursor over the original lines that this block replaces
cursor = startIdx + block.sourceLineCount;
}
// Append any remaining original lines
if (cursor < originalLines.length) {
outputLines.push(...originalLines.slice(cursor));
}
return joinWikitextLines(outputLines);
}
function showPreviewScreen(diffData, title, username) {
const main = document.getElementById("ainb-main");
main.innerHTML = ""; // Clear diff UI
const header = document.createElement("div");
header.className = "ainb-main-header";
header.innerHTML = `<h2><span class="ainb-page-badge">${title}</span> ⋅ <span class="ainb-user-badge"> ${username}</span></h2>`;
const body = document.createElement("div");
body.className = "ainb-main-body ainb-preview-wrapper";
const textarea = document.createElement("textarea");
textarea.className = "ainb-preview-textarea";
textarea.value = reconstructWikitext(diffData);
body.appendChild(textarea);
const footer = document.createElement("div");
footer.className = "ainb-main-footer";
const backBtn = document.createElement("button");
backBtn.textContent = "Back";
backBtn.className = "ainb-action-btn ainb-action-preview";
backBtn.addEventListener("click", () => {
openArticle(title, username);
});
footer.appendChild(backBtn);
main.appendChild(header);
main.appendChild(body);
main.appendChild(footer);
}
function postArticleEdit(diffData, title, username) {
const main = document.getElementById("ainb-main");
const originalHTML = main.innerHTML;
main.innerHTML = `
<div class="ainb-main-header">
<h2><span class="ainb-page-badge">${title}</span> ⋅ <span class="ainb-user-badge"> ${username}</span></h2>
</div>
<div class="ainb-main-body">
<div class="ainb-status">Posting edit to <b>${title}</b>...</div>
</div>
`;
const newWikitext = reconstructWikitext(diffData);
const api = new mw.Api();
api.postWithToken("csrf", {
action: "edit",
title: title,
text: newWikitext,
summary: `Cleaned up suspected AI-generated edits by [[User:${username}]] via [[User:Chaotic_Enby/AIDiffBrowser|AIDiffBrowser]]`,
bot: false
}).then(() => {
main.innerHTML = `
<div class="ainb-main-header">
<h2><span class="ainb-page-badge">${title}</span> ⋅ <span class="ainb-user-badge"> ${username}</span></h2>
</div>
<div class="ainb-main-body">
<div class="ainb-status" style="color: #6aab6a;">Success! Edit posted to <b>${title}</b>.</div>
</div>
`;
}).catch(err => {
main.innerHTML = `
<div class="ainb-main-header">
<h2><span class="ainb-page-badge">${title}</span> ⋅ <span class="ainb-user-badge"> ${username}</span></h2>
</div>
<div class="ainb-main-body">
<div class="ainb-status" style="color: #c95c5c;">Error posting edit: ${err}</div>
</div>
<div class="ainb-main-footer">
<button class="ainb-action-btn ainb-action-preview" id="ainb-error-back-btn">Back</button>
</div>
`;
document.getElementById("ainb-error-back-btn").addEventListener("click", () => {
main.innerHTML = originalHTML;
// Rebind events since replacing innerHTML destroys them
openArticle(title, username);
});
});
}
function tagPage(revId, title, username, tag) {
if (tag === "g15") {
tagCode = "{{db-g15}}\n\n";
summary = 'Tagged for [[WP:G15|CSD G15]]';
} else if (tag === "prod") {
tagCode = "{{subst:prod llm}}\n\n";
summary = 'Tagged for [[WP:LLMPROD|LLMPROD]]';
}
const main = document.getElementById("ainb-main");
main.innerHTML = `
<div class="ainb-main-header">
<h2><span class="ainb-page-badge">${title}</span> ⋅ <span class="ainb-user-badge"> ${username}</span></h2>
</div>
<div class="ainb-main-body">
<div class="ainb-status">Tagging page for ${tag === "g15" ? "G15 deletion" : "LLMPROD"}...</div>
</div>
`;
const api = new mw.Api();
fetchRevisionWikitext(revId).then((wikitext) => {
api.postWithToken("csrf", {
action: "edit",
title: title,
text: tagCode + wikitext,
summary: summary + " via [[User:Chaotic_Enby/AIDiffBrowser|AIDiffBrowser]]",
bot: false
})}).then(() => {
main.innerHTML = `
<div class="ainb-main-header">
<h2><span class="ainb-page-badge">${title}</span> ⋅ <span class="ainb-user-badge"> ${username}</span></h2>
</div>
<div class="ainb-main-body">
<div class="ainb-status" style="color: #6aab6a;">Success! Page tagged for ${tag === "g15" ? "G15 deletion" : "LLMPROD"}.</div>
</div>
`;
}).catch(err => {
main.innerHTML = `
<div class="ainb-main-header">
<h2><span class="ainb-page-badge">${title}</span> ⋅ <span class="ainb-user-badge"> ${username}</span></h2>
</div>
<div class="ainb-main-body">
<div class="ainb-status" style="color: #c95c5c;">Error tagging page: ${err}</div>
</div>
`;
});
}
// Chapter 3.2: Where we go back to the main screen
function openArticle(title, username) {
const main = document.getElementById("ainb-main");
main.innerHTML = `
<div class="ainb-main-header">
<h2><span class="ainb-page-badge">${title}</span> ⋅ <span class="ainb-user-badge"> ${username}</span></h2>
</div>
<div class="ainb-main-body">
<div class="ainb-status">Loading diff...</div>
</div>
`;
fetchRecentEdits(title)
.then(revs => {
const beforeRevObj = findEarliestEditByUser(revs, username);
if (!beforeRevObj) {
main.innerHTML = `
<div class="ainb-main-header">
<h2><span class="ainb-page-badge">${title}</span> ⋅ <span class="ainb-user-badge"> ${username}</span></h2>
</div>
<div class="ainb-main-body">
<div class="ainb-status">No edits by <b>${username}</b> could be found.</div>
</div>
`;
return null;
}
const beforeRev = beforeRevObj.parentid || emptyRev; // Use empty revision ID for first edits
const isFirstEdit = !beforeRevObj.parentid; // Track if this is a first-edit scenario
const currentRev = revs[0].revid; // newest revision
return Promise.all([
fetchRevisionWikitext(beforeRev),
fetchInlineDiff(beforeRev, currentRev)
]).then(([originalWikitext, diffHTML]) => ({
originalWikitext,
diffHTML,
isFirstEdit,
currentRev
}));
})
.then(diffData => {
if (!diffData) return;
const doc = parseInlineDiffHTML(diffData.diffHTML);
const blocks = extractInlineBlocks(doc);
const diffModel = {
originalWikitext: diffData.originalWikitext,
blocks,
isFirstEdit: diffData.isFirstEdit,
currentRev: diffData.currentRev
};
main.innerHTML = "";
const header = document.createElement("div");
header.className = "ainb-main-header";
if(diffData.isFirstEdit) {
header.innerHTML = `<h2><span class="ainb-page-badge">${title}</span> ⋅ <span class="ainb-user-badge"> ${username}</span> <span class="ainb-page-creator-badge">(page creator)</span></h2>`;
} else {
header.innerHTML = `<h2><span class="ainb-page-badge">${title}</span> ⋅ <span class="ainb-user-badge"> ${username}</span></h2>`;
}
const body = document.createElement("div");
body.className = "ainb-main-body";
body.appendChild(renderBlocks(diffModel, title, username));
const footer = document.createElement("div");
footer.className = "ainb-main-footer";
const previewBtn = document.createElement("button");
previewBtn.textContent = "Preview";
previewBtn.className = "ainb-action-btn ainb-action-preview";
previewBtn.addEventListener("click", () => {
showPreviewScreen(diffModel, title, username);
});
const postBtn = document.createElement("button");
postBtn.textContent = "Post";
postBtn.className = "ainb-action-btn ainb-action-post";
postBtn.addEventListener("click", () => {
postArticleEdit(diffModel, title, username);
});
footer.appendChild(previewBtn);
footer.appendChild(postBtn);
// Add extra buttons for first-edit articles
if (diffModel.isFirstEdit) {
const prodBtn = document.createElement("button");
prodBtn.textContent = "LLMPROD";
prodBtn.className = "ainb-action-btn ainb-action-destructive";
prodBtn.addEventListener("click", () => {
tagPage(diffModel.currentRev, title, username, "prod");
});
footer.appendChild(prodBtn);
const g15Btn = document.createElement("button");
g15Btn.textContent = "G15";
g15Btn.className = "ainb-action-btn ainb-action-destructive";
g15Btn.addEventListener("click", () => {
tagPage(diffModel.currentRev, title, username, "g15");
});
footer.appendChild(g15Btn);
}
main.appendChild(header);
main.appendChild(body);
main.appendChild(footer);
})
.catch(err => {
main.innerHTML = `
<div class="ainb-main-header">
<h2><span class="ainb-page-badge">${title}</span> ⋅ <span class="ainb-user-badge"> ${username}</span></h2>
</div>
<div class="ainb-main-body">
<div class="ainb-status">Error loading diff: ${err}</div>
</div>
`;
});
}
// Chapter N-1: The fancy stuff
function setupCSS(){
mw.util.addCSS(`
:root {
--ainb-hue: 220;
--ainb-hue-2: 240;
--ainb-hue-accent: 293;
--ainb-hue-accent-2: 324;
}
#ainb-app {
background-color: hsl(var(--ainb-hue), 10%, 10%);
color: white;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
font-family: system-ui, sans-serif;
}
#ainb-app h2 {
font-family: system-ui, sans-serif;
font-weight: 600;
letter-spacing: 1.5px;
padding-left: 10px;
border-bottom: none;
color: white;
}
#ainb-sidebar {
padding: 0px;
background: linear-gradient(135deg, hsl(var(--ainb-hue), 30%, 12%) 0%, hsl(var(--ainb-hue-2), 30%, 14%) 100%);
z-index: 1;
width: 280px;
overflow-y: auto;
letter-spacing: 0.5px;
}
#ainb-sidebar h2 {
margin: 10px;
height: 34px;
}
.ainb-collapsible-header {
cursor: pointer;
user-select: none;
padding: 5px 0;
}
.ainb-collapsible-content li:hover {
color: #e7e7e7;
}
.ainb-collapsible-content {
display: none;
margin-left: 12px;
}
#ainb-sidebar > .ainb-collapsible {
padding: 6px 6px 6px 11px;
color: hsl(var(--ainb-hue), 10%, 60%);
}
#ainb-sidebar > .ainb-collapsible:not(.ainb-collapsible-open):hover {
background: linear-gradient(135deg, hsl(var(--ainb-hue), 30%, 14%) 0%, hsl(var(--ainb-hue-2), 30%, 15%) 100%);
color: white;
}
#ainb-sidebar > .ainb-collapsible-open {
background: linear-gradient(135deg, hsl(var(--ainb-hue-accent), 78%, 23%) 0%, hsl(var(--ainb-hue-accent-2), 81%, 31%) 100%);
color: white;
}
.ainb-collapsible-open > .ainb-collapsible-content {
display: block;
}
.ainb-pill {
display: inline-block;
padding: 1px 8px;
border-radius: 10px;
font-size: 88%;
font-weight: 500;
}
.ainb-collapsible-content ul {
margin: 4px 0 6px 6px;
}
.ainb-collapsible-content li {
list-style: none;
font-size: 88%;
margin: 7px 0;
}
#ainb-main {
flex: 1 1 0%;
display: flex;
flex-direction: column;
overflow: hidden;
background: linear-gradient(135deg, hsl(var(--ainb-hue), 32%, 15%) 0%, hsl(var(--ainb-hue-2), 42%, 15%) 100%);
}
.ainb-main-header {
flex-shrink: 0;
padding: 15px 20px;
display: flex;
align-items: center;
height: 40px;
justify-content: center;
}
.ainb-main-header h2 {
margin: 0;
font-size: 18px;
padding-left: 0 !important;
}
.ainb-page-creator-badge {
font-size: 70%;
}
.ainb-main-body {
flex: 1 1 auto;
overflow-y: auto;
background: linear-gradient(135deg, hsl(var(--ainb-hue), 30%, 17%) 0%, hsl(var(--ainb-hue-2), 40%, 17%) 100%);
display: flex;
}
.ainb-main-footer {
flex-shrink: 0;
padding: 12px 20px;
display: flex;
justify-content: flex-end;
gap: 20px;
}
.ainb-status {
margin: auto;
text-align: center;
}
.ainb-diff-container {
display: flex;
flex-direction: column;
font-family: monospace, system-ui, sans-serif;
width: 100%;
}
.ainb-diff-block {
display: grid;
grid-template-columns: 1fr auto 1fr;
}
.ainb-diff-center {
display: flex;
justify-content: center;
align-items: center;
}
.ainb-diff-btn, .ainb-diff-equal {
flex-grow: 1;
height: 100%;
display: flex;
align-items: center;
border: none;
padding-top: 0.2em;
padding-bottom: 0.28em;
}
.ainb-diff-equal {
display: flex;
align-items: center;
justify-content: center;
color: hsl(var(--ainb-hue), 10%, 60%);
font-weight: bold;
font-size: 21px;
width: 40px;
}
.ainb-diff-btn {
transition: background-color 0.15s, color 0.15s;
width: 40px;
justify-content: center;
font-size: 15px;
cursor: pointer;
background: none;
}
.ainb-diff-btn.selected-before {
color: #913057;
}
.ainb-diff-btn.selected-after {
color: #467d52;
}
.added .ainb-diff-btn.selected-before, .deleted .ainb-diff-btn.selected-after {
color: hsl(var(--ainb-hue), 10%, 70%);
}
.ainb-diff-side {
white-space: pre-wrap;
line-height: 1.45;
font-size: 14px;
display: flex;
justify-content: space-between;
align-items: center;
overflow: hidden;
padding: 5px 20px;
}
.before, .after {
flex-direction: row;
}
.context :is(.before, .after) {
background-color: hsla(var(--ainb-hue), 20%, 26%, 30%);
}
:is(.changed, .deleted) .before {
background-color: #913057;
}
:is(.changed, .added) .after {
background-color: #467d52;
}
:is(.added .before, .deleted .after) .ainb-diff-text {
text-align: center;
width: 100%;
}
:is(.added .before, .deleted .after) .ainb-diff-text::before {
content: "∅";
color: #c2c2c2;
}
.ainb-diff-header {
grid-column: 1 / -1;
font-size: 14px;
text-align: center;
font-weight: 600;
color: hsl(var(--ainb-hue), var(--ainb-sat), 60%);
padding-top: 0.5em;
padding-bottom: 0.58em;
}
.ainb-inline-del {
background: #ffe5e5;
color: #b30000;
text-decoration: line-through;
padding: 0 2px;
border-radius: 3px;
}
.ainb-inline-ins {
background: #e6ffe6;
color: #006600;
padding: 0 2px;
border-radius: 3px;
}
.ainb-diff-side.dimmed:not(.context .ainb-diff-side) {
opacity: 0.3;
}
.ainb-action-btn {
padding: 8px 16px;
font-size: 15px;
letter-spacing: 1px;
border: none;
background: transparent;
cursor: pointer;
transition: color 0.15s;
margin: auto 0;
font-family: system-ui, sans-serif;
font-weight: 600;
}
.ainb-action-preview {
color: hsl(var(--ainb-hue), 50%, 90%);
}
.ainb-action-preview:hover {
color: hsl(var(--ainb-hue), 50%, 95%);
}
.ainb-action-post {
color: hsl(var(--ainb-hue-accent), 90%, 70%);
}
.ainb-action-post:hover {
color: hsl(var(--ainb-hue-accent), 90%, 75%);
}
.ainb-action-destructive {
color: hsl(350, 70%, 70%);
}
.ainb-action-destructive:hover {
color: hsl(350, 70%, 75%);
}
.ainb-preview-wrapper {
display: flex;
flex-direction: column;
gap: 16px;
padding: 20px;
}
.ainb-preview-textarea {
width: 100%;
height: 100%;
font-family: monospace, system-ui, sans-serif;
font-size: 14px;
padding: 12px;
resize: none;
background-color: hsla(var(--ainb-hue), 20%, 26%, 30%);
color: white;
border: none;
}
.title-notice {
font-size: 80%;
color: grey;
}
`);
}
// Chapter N: When they actually launch the thing
if(mw.config.get("wgPageName") === "User:Chaotic_Enby/AIDiffBrowser/run") {
setupCSS();
setupAppShell();
loadAINBIndex().then(index => {
renderSidebar(index);
});
}
dcjxazo13ir8myjhiznav8gqbnlemf3
User:Cryptocurrency777/sandbox5
2
175597
743894
743663
2026-05-22T13:34:19Z
Cryptocurrency777
73698
743894
wikitext
text/x-wiki
{{Infobox song|Name=Decay|Type=Single|Artist=AfterDRK, Xaduma, Xyle, and [[Anti-Light]]|Released=March 2025|Language=English}}
'''Decay''' (stylized in all caps) is a song by AfterDRK, [[Xaduma]], Xyle, and [[Anti-Light]] released in March 2025. It was produced by DaniDV. It has a
BPM of 145. It contains elements of EDM and discusses topics like relationships and self harm and attachment. It was recorded from late 2024 to early 2025. Rox3s was supposed to appear on the song, but he never showed up for the open, so Anti-Light became a feature on this song instead.
ij2sjdme54uul25b4b5mytotfao1ayd
Template:Projekt-gutenberg.org/a.json
10
175606
743895
743818
2026-05-22T13:49:07Z
PerfektesChaos
18104
2026-05-21
743895
json
application/json
{
"suite": "projekt-gutenberg.org",
"sub": "a",
"serial": "2026-05-21",
"item": 0,
"hash": {
"hans-aanrud": "Hans Aanrud",
"edmond-about": "Edmond About",
"schalom-jakob-abramowitsch": "Schalom Jakob Abramowitsch",
"franz-heinrich-achermann": "Franz Heinrich Achermann",
"arthur-achleitner": "Arthur Achleitner",
"alfred-adler": "Alfred Adler",
"paul-adler": "Paul Adler",
"eufemia-von-adlersfeld-ballestrem": "Eufemia von Adlersfeld-Ballestrem",
"karl-adolph": "Karl Adolph",
"aesop": "Aesop",
"luise-ahlborn": "Luise Ahlborn",
"jacob-ahlers": "Jacob Ahlers",
"juhani-aho": "Juhani Aho",
"gustave-aimard": "Gustave Aimard",
"aischylos": "Aischylos",
"sergei-timofejewitsch-aksakow": "Sergei Timofejewitsch Aksakow",
"pedro-antonio-de-alarcn": "Pedro Antonio de Alarcón",
"herbert-alberti": "Herbert Alberti",
"karl-alberti": "Karl Alberti",
"sophie-albrecht": "Sophie Albrecht",
"ernest-alby": "Ernest Alby",
"marianna-alcoforado": "Marianna Alcoforado",
"willibald-alexis": "Willibald Alexis",
"luise-algenstaedt": "Luise Algenstaedt",
"dante-alighieri": "Dante Alighieri",
"alkiphron": "Alkiphron",
"alphonse-allais": "Alphonse Allais",
"henri-allais": "Henri Allais",
"frank-allan": "Frank Allan",
"peter-altenberg": "Peter Altenberg",
"anton-altrichter": "Anton Altrichter",
"johann-baptist-von-alxinger": "Johann Baptist von Alxinger",
"frieda-amerlan": "Frieda Amerlan",
"edmondo-de-amicis": "Edmondo De Amicis",
"gerhard-von-amyntor": "Gerhard von Amyntor",
"hans-christian-andersen": "Hans Christian Andersen",
"lou-andreas-salome": "Lou Andreas-Salomé",
"leonid-andrejew": "Leonid Andrejew",
"wassilij-andrejew": "Wassilij Andrejew",
"louise-anklam": "Louise Anklam",
"wilhelm-anthony": "Wilhelm Anthony",
"marcus-aurelius-antonius": "Marcus Aurelius Antonius",
"ludwig-anzengruber": "Ludwig Anzengruber",
"august-apel": "August Apel",
"paul-apel": "Paul Apel",
"sture-appelberg": "Sture Appelberg",
"johann-conrad-appenzeller": "Johann Conrad Appenzeller",
"george-webb-appleton": "George Webb Appleton",
"apuleius": "Apuleius",
"johann-wilhelm-von-archenholz": "Johann Wilhelm von Archenholz",
"henriette-arendt": "Henriette Arendt",
"paul-arene": "Paul Arène",
"pietro-aretino": "Pietro Aretino",
"gertrude-aretz": "Gertrude Aretz",
"francesco-argelati": "Francesco Argelati",
"ludovico-ariosto": "Ludovico Ariosto",
"aristophanes": "Aristophanes",
"aristoteles": "Aristoteles",
"friedrich-arnd": "Friedrich Arnd",
"ernst-moritz-arndt": "Ernst Moritz Arndt",
"achim-von-arnim": "Achim von Arnim",
"bettina-von-arnim": "Bettina von Arnim",
"gisela-von-arnim": "Gisela von Arnim",
"edwin-arnold": "Edwin Arnold",
"philipp-aronstein": "Philipp Aronstein",
"michail-petrowitsch-arzybaschew": "Michail Petrowitsch Arzybaschew",
"peter-christen-asbjrnsen": "Peter Christen Asbjørnsen",
"hans-anton-aschenborn": "Hans Anton Aschenborn",
"robert-maximilian-ascher": "Robert Maximilian Ascher",
"saul-ascher": "Saul Ascher",
"wilhelm-asmus": "Wilhelm Asmus",
"georg-asmussen": "Georg Asmussen",
"alfred-assollant": "Alfred Assollant",
"luise-aston": "Luise Aston",
"farid-ed-din-attar": "Farid-ed-Din Attar",
"per-daniel-amadeus-atterbom": "Per Daniel Amadeus Atterbom",
"victor-auburtin": "Victor Auburtin",
"marguerite-audoux": "Marguerite Audoux",
"hartmann-von-aue": "Hartmann von Aue",
"adelheid-von-auer": "Adelheid von Auer",
"grethe-auer": "Grethe Auer",
"berthold-auerbach": "Berthold Auerbach",
"raoul-auernheimer": "Raoul Auernheimer",
"anton-alexander-graf-von-auersperg": "Anton Alexander Graf von Auersperg",
"aurelius-augustinus": "Aurelius Augustinus",
"ludwig-aurbacher": "Ludwig Aurbacher",
"jane-austen": "Jane Austen",
"ferdinand-avenarius": "Ferdinand Avenarius",
"elise-averdieck": "Elise Averdieck",
"arkadi-timofejewitsch-awertschenko": "Arkadi Timofejewitsch Awertschenko",
"johannes-theodor-baargeld": "Johannes Theodor Baargeld",
"julius-bab": "Julius Bab",
"francis-bacon": "Francis Bacon",
"wilfrid-bade": "Wilfrid Bade",
"hermann-baeblich": "Hermann Baeblich",
"jens-baggesen": "Jens Baggesen",
"bonaventura-da-bagnoregio": "Bonaventura da Bagnoregio",
"hermann-bahr": "Hermann Bahr",
"li-bai": "Li Bai",
"josef-baierlein": "Josef Baierlein",
"olaf-baker": "Olaf Baker",
"michael-bakunin": "Michael Bakunin",
"mabel-baldwin": "Mabel Baldwin",
"hugo-ball": "Hugo Ball",
"konstantin-balmont": "Konstantin Balmont",
"honore-de-balzac": "Honoré de Balzac",
"matteo-bandello": "Matteo Bandello",
"herman-bang": "Herman Bang",
"hugo-barbeck": "Hugo Barbeck",
"henri-barbusse": "Henri Barbusse",
"pedro-caldern-de-la-barca": "Pedro Calderón de la Barca",
"thorkil-barfod": "Thorkil Barfod",
"ernst-barlach": "Ernst Barlach",
"maurice-barres": "Maurice Barrès",
"elizabeth-barrett-browning": "Elizabeth Barrett-Browning",
"max-bartels": "Max Bartels",
"ernst-barthel": "Ernst Barthel",
"max-barthel": "Max Barthel",
"felix-mendelssohn-bartholdy": "Felix Mendelssohn Bartholdy",
"rudolf-hans-bartsch": "Rudolf Hans Bartsch",
"m-bartz": "M. Bartz",
"giambattista-basile": "Giambattista Basile",
"gerdt-von-bassewitz": "Gerdt von Bassewitz",
"wilhelm-bauberger": "Wilhelm Bauberger",
"charles-baudelaire": "Charles Baudelaire",
"graf-ulrich-von-baudissin": "Graf Ulrich von Baudissin",
"wolf-graf-von-baudissin": "Wolf Graf von Baudissin",
"wolf-heinrich-graf-von-baudissin": "Wolf Heinrich Graf von Baudissin",
"sophus-bauditz": "Sophus Bauditz",
"clara-bauer": "Clara Bauer",
"adolf-baeuerle": "Adolf Bäuerle",
"eduard-bauernfeld": "Eduard Bauernfeld",
"vicki-baum": "Vicki Baum",
"joseph-baumann": "Joseph Baumann",
"rudolf-baumbach": "Rudolf Baumbach",
"gertrud-baeumer": "Gertrud Bäumer",
"alexandra-von-bayern": "Alexandra von Bayern",
"ludwig-i-von-bayern": "Ludwig I. von Bayern",
"ludwig-ii-von-bayern": "Ludwig II. von Bayern",
"therese-von-bayern": "Therese von Bayern",
"wilhelmine-von-bayreuth": "Wilhelmine von Bayreuth",
"aubrey-beardsley": "Aubrey Beardsley",
"pierre-de-beaumarchais": "Pierre de Beaumarchais",
"jeanne-marie-leprince-de-beaumont": "Jeanne-Marie Leprince de Beaumont",
"august-bebel": "August Bebel",
"ludwig-bechstein": "Ludwig Bechstein",
"august-becker": "August Becker",
"herbert-becker": "Herbert Becker",
"karl-friedrich-becker": "Karl Friedrich Becker",
"artur-w-a-beckett": "Artur W. A. Beckett",
"john-beckford": "John [William] Beckford",
"gustavo-adolfo-becquer": "Gustavo Adolfo Bécquer",
"kaethe-van-beeker": "Käthe van Beeker",
"johann-beer": "Johann Beer",
"richard-beer-hofmann": "Richard Beer-Hofmann",
"alfred-beetschen": "Alfred Beetschen",
"berta-behrens": "Berta Behrens",
"stephanie-von-belgien": "Stephanie von Belgien",
"edward-bellamy": "Edward Bellamy",
"hilaire-belloc": "Hilaire Belloc",
"andrej-bely": "Andrej Bely",
"arno-alexander-benjamin": "Arno Alexander Benjamin",
"walter-benjamin": "Walter Benjamin",
"gottfried-benn": "Gottfried Benn",
"arnold-bennett": "Arnold Bennett",
"henry-benrath": "Henry Benrath",
"robert-hugh-benson": "Robert Hugh Benson",
"martin-beradt": "Martin Beradt",
"johannes-berbig": "Johannes Berbig",
"alice-berend": "Alice Berend",
"leo-berg": "Leo Berg",
"siegfried-bergengruen": "Siegfried Bergengruen",
"a-berger": "A. Berger",
"alfred-freiherrn-von-berger": "Alfred Freiherr von Berger",
"philipp-berges": "Philipp Berges",
"hjalmar-bergman": "Hjalmar Bergman",
"hilda-bergmann": "Hilda Bergmann",
"henri-bergson": "Henri Bergson",
"josef-august-beringer": "Josef August Beringer",
"lina-von-berlepsch": "Lina von Berlepsch",
"hector-berlioz": "Hector Berlioz",
"richard-arnold-bermann": "Richard Arnold Bermann",
"maximilian-bern": "Maximilian Bern",
"georges-bernanos": "Georges Bernanos",
"f-bernard": "F. Bernard",
"tristan-bernard": "Tristan Bernard",
"hugo-bernatzik": "Hugo Bernatzik",
"otto-berndt": "Otto Berndt",
"marie-bernhard": "Marie Bernhard",
"carl-albrecht-bernoulli": "Carl Albrecht Bernoulli",
"aron-david-bernstein": "Aron David Bernstein",
"luigi-bertelli": "Luigi Bertelli",
"theodor-berthold": "Theodor Berthold",
"elsa-beskow": "Elsa Beskow",
"emil-bessels": "Emil Bessels",
"hermann-bessemer": "Hermann Bessemer",
"hans-bethge": "Hans Bethge",
"roland-betsch": "Roland Betsch",
"hugo-bettauer": "Hugo Bettauer",
"anton-bettelheim": "Anton Bettelheim",
"frederic-bettex": "Frédéric Bettex",
"margarete-beutler": "Margarete Beutler",
"essad-bey": "Essad Bey",
"franz-adam-beyerlein": "Franz Adam Beyerlein",
"henri-beyle": "Henri Beyle",
"viktor-bibl": "Viktor Bibl",
"oscar-bie": "Oscar Bie",
"otto-julius-bierbaum": "Otto Julius Bierbaum",
"ambrose-gwinnett-bierce": "Ambrose Gwinnett Bierce",
"georg-biermann": "Georg Biermann",
"karl-biernatzki": "Karl Biernatzki",
"earl-derr-biggers": "Earl Derr Biggers",
"emma-biller": "Emma Biller",
"rudolf-georg-binding": "Rudolf Georg Binding",
"ida-bindschedler": "Ida Bindschedler",
"hildegard-von-bingen": "Hildegard von Bingen",
"charlotte-birch-pfeiffer": "Charlotte Birch-Pfeiffer",
"theodor-birt": "Theodor Birt",
"charitas-bischoff": "Charitas Bischoff",
"joseph-eduard-konrad-bischoff": "Joseph Eduard Konrad Bischoff",
"otto-von-bismarck": "Otto von Bismarck",
"bjrnstjerne-bjrnson": "Bjørnstjerne Bjørnson",
"r-d-blackmore": "R. D. Blackmore",
"therese-blanc": "Thérèse Blanc",
"matthias-blank": "Matthias Blank",
"ernst-blass": "Ernst Blass",
"rdolfs-blaumanis": "Rūdolfs Blaumanis",
"franz-blei": "Franz Blei",
"karl-bleibtreu": "Karl Bleibtreu",
"franz-bley": "Franz Bley",
"fritz-bley": "Fritz Bley",
"steen-steensen-blicher": "Steen Steensen Blicher",
"jenny-blicher-clausen": "Jenny Blicher-Clausen",
"paul-bliss": "Paul Bliß",
"walter-bloem": "Walter Bloem",
"hugo-freiherr-von-blomberg": "Hugo Freiherr von Blomberg",
"aloys-blumauer": "Aloys Blumauer",
"wilhelm-blumenhagen": "Wilhelm Blumenhagen",
"paul-blumenreich": "Paul Blumenreich",
"oscar-blumenthal": "Oscar Blumenthal",
"clara-bluethgen": "Clara Blüthgen",
"viktor-bluethgen": "Viktor Blüthgen",
"giovanni-boccaccio": "Giovanni Boccaccio",
"alfred-bock": "Alfred Bock",
"wilhelm-von-bode": "Wilhelm von Bode",
"friedrich-von-bodenstedt": "Friedrich von Bodenstedt",
"mathias-mcdonnell-bodkin": "Mathias McDonnell Bodkin",
"johann-jakob-bodmer": "Johann Jakob Bodmer",
"etienne-de-la-botie": "Étienne de La Boëtie",
"helene-boehlau": "Helene Böhlau",
"hans-boehm": "Hans Böhm",
"margarete-boehme": "Margarete Böhme",
"margarete-boie": "Margarete Boie",
"fortune-de-boisgobey": "Fortuné de Boisgobey",
"emil-heinrich-du-bois-reymond": "Emil Heinrich du Bois-Reymond",
"oswald-boelcke": "Oswald Bölcke",
"paul-boldt": "Paul Boldt",
"wilhelm-bolin": "Wilhelm Bolin",
"william-bolitho": "William Bolitho",
"wilhelm-boelsche": "Wilhelm Bölsche",
"waldemar-bonsels": "Waldemar Bonsels",
"jens-booysen": "Jens Booysen",
"wolfgang-borchert": "Wolfgang Borchert",
"ernst-borkowsky": "Ernst Borkowsky",
"ludwig-boerne": "Ludwig Börne",
"johann-ernst-daniel-bornschein": "Johann Ernst Daniel Bornschein",
"paul-bornstein": "Paul Bornstein",
"jakob-bosshart": "Jakob Boßhart",
"hermann-bote": "Hermann Bote",
"adolf-boettger": "Adolf Böttger",
"georg-boetticher": "Georg Bötticher",
"mathilde-bourdon": "Mathilde Bourdon",
"paul-bourget": "Paul Bourget",
"frederic-boutet": "Frédéric Boutet",
"ida-boy-ed": "Ida Boy-Ed",
"hjalmar-hjorth-boyesen": "Hjalmar Hjorth Boyesen",
"gian-francesco-poggio-bracciolini": "Gian Francesco Poggio Bracciolini",
"albert-emil-brachvogel": "Albert Emil Brachvogel",
"carry-brachvogel": "Carry Brachvogel",
"ferdinande-freiin-von-brackel": "Ferdinande Freiin von Brackel",
"ulrich-braeker": "Ulrich Bräker",
"georg-brandes": "Georg Brandes",
"titus-brandsma": "Titus Brandsma",
"sebastian-brant": "Sebastian Brant",
"pierre-de-brantme": "Pierre de Brantôme",
"lilly-braumann-honsell": "Lilly Braumann-Honsell",
"isabella-braun": "Isabella Braun",
"lily-braun": "Lily Braun",
"rudolf-braune": "Rudolf Braune",
"artur-brausewetter": "Artur Brausewetter",
"joachim-wilhelm-von-brawe": "Joachim Wilhelm von Brawe",
"bertolt-brecht": "Bertolt Brecht",
"johann-jakob-brechter": "Johann Jakob Brechter",
"heinrich-bredow": "Heinrich Bredow",
"alfred-edmund-brehm": "Alfred Edmund Brehm",
"arthur-brehmer": "Arthur Brehmer",
"friedrich-breining": "Friedrich Breining",
"agnes-breitzmann": "Agnes Breitzmann",
"medardus-bremeneck": "Medardus Bremeneck",
"fredrika-bremer": "Fredrika Bremer",
"emil-brenning": "Emil Brenning",
"clemens-brentano": "Clemens Brentano",
"hanny-brentano": "Hanny Brentano",
"sophie-friederike-brentano": "Sophie Friederike Brentano",
"nicolas-edmonde-retif-de-la-bretonne": "Nicolas Edmonde Rétif de la Bretonne",
"henriette-brey": "Henriette Brey",
"jean-anthelme-brillat-savarin": "Jean Anthelme Brillat-Savarin",
"valerij-brjussow": "Valerij Brjussow",
"hermann-broch": "Hermann Broch",
"barthold-heinrich-brockes": "Barthold Heinrich Brockes",
"ferdinand-brockes": "Ferdinand Brockes",
"karl-gustav-broendsted": "Karl Gustav Broendsted",
"karl-broeger": "Karl Bröger",
"benno-bronner": "Benno Bronner",
"franz-xaver-bronner": "Franz Xaver Bronner",
"karl-bronner": "Karl Bronner",
"charlotte-bront": "Charlotte Brontë",
"emily-bront": "Emily Brontë",
"carl-brosbll": "Carl Brosbøll",
"charles-brockden-brown": "Charles Brockden Brown",
"artur-brueckmann": "Artur Brückmann",
"eugen-brunfaut": "Eugen Brunfaut",
"ludwig-brunier": "Ludwig Brunier",
"giordano-bruno": "Giordano Bruno",
"max-bruns": "Max Bruns",
"alfred-brust": "Alfred Brust",
"laurids-bruun": "Laurids Bruun",
"robert-buchanan": "Robert Buchanan",
"georg-buechner": "Georg Büchner",
"martin-buecking": "Martin Bücking",
"robert-budzinski": "Robert Budzinski",
"friedrich-von-buelau": "Friedrich von Bülau",
"albert-e-bull": "Albert E. Bull",
"frieda-von-buelow": "Frieda von Bülow",
"edward-bulwer-lytton": "Edward Bulwer-Lytton",
"iwan-alexejewitsch-bunin": "Iwan Alexejewitsch Bunin",
"maria-buol": "Maria Buol",
"max-eugen-burckhard": "Max Eugen Burckhard",
"jacob-burckhardt": "Jacob Burckhardt",
"bruno-hans-buergel": "Bruno Hans Bürgel",
"gottfried-august-buerger": "Gottfried August Bürger",
"otto-buerger": "Otto Bürger",
"frances-hodgson-burnett": "Frances Hodgson Burnett",
"clara-louise-burnham": "Clara Louise Burnham",
"edgar-rice-burroughs": "Edgar Rice Burroughs",
"wilhelm-busch": "Wilhelm Busch",
"carl-busse": "Carl Busse",
"hermann-eris-busse": "Hermann Eris Busse",
"paul-busson": "Paul Busson",
"robert-byr": "Robert Byr",
"george-gordon-nol-byron": "George Gordon Noël Byron",
"thomas-henry-hall-caine": "Thomas Henry Hall Caine",
"luis-vaz-de-cames": "Luis Vaz de Camões",
"gilbert-campbell": "Gilbert Campbell",
"joachim-heinrich-campe": "Joachim Heinrich Campe",
"karel-capek": "Karel Capek",
"hermann-cardauns": "Hermann Cardauns",
"giosue-carducci": "Giosuè Carducci",
"erwin-carle": "Erwin Carlé",
"thomas-carlyle": "Thomas Carlyle",
"andrew-carnegie": "Andrew Carnegie",
"frederic-grosvenor-carnochan": "Frederic Grosvenor Carnochan",
"hans-carossa": "Hans Carossa",
"edward-carpenter": "Edward Carpenter",
"felix-lope-de-vega-carpio": "Félix Lope de Vega Carpio",
"enrique-gmez-carrillo": "Enrique Gómez Carrillo",
"howard-carter": "Howard Carter",
"carl-gustav-carus": "Carl Gustav Carus",
"giacomo-casanova": "Giacomo Casanova",
"karl-heinrich-caspari": "Karl Heinrich Caspari",
"ernst-cassirer": "Ernst Cassirer",
"ignaz-franz-castelli": "Ignaz Franz Castelli",
"catharina-regina-von-greiffenberg-geb-freiin-von-seyssenegg": "Catharina Regina von Greiffenberg, geb. Freiin von Seyssenegg",
"george-catlin": "George Catlin",
"jacques-cazotte": "Jacques Cazotte",
"benvenuto-cellini": "Benvenuto Cellini",
"paul-b-du-chaillu": "Paul B. Du Chaillu",
"omar-chajjam": "Omar Chajjam",
"houston-stewart-chamberlain": "Houston Stewart Chamberlain",
"adelbert-von-chamisso": "Adelbert von Chamisso",
"suse-la-chapelle-roobol": "Suse La Chapelle-Roobol",
"elisabeth-rundle-charles": "Elisabeth Rundle Charles",
"francois-rene-chateaubriand": "François René Chateaubriand",
"alphonse-de-chateaubriant": "Alphonse de Chateaubriant",
"alessandre-chatrian": "Alessandre Chatrian",
"geoffrey-chaucer": "Geoffrey Chaucer",
"alice-cherbonnel": "Alice Cherbonnel",
"george-randolph-chester": "George Randolph Chester",
"gilbert-keith-chesterton": "Gilbert Keith Chesterton",
"peter-cheyney": "Peter Cheyney",
"vincenz-chiavacci": "Vincenz Chiavacci",
"john-jay-chichester": "John Jay Chichester",
"hans-chlumberg": "Hans Chlumberg",
"werner-chomton": "Werner Chomton",
"lena-christ": "Lena Christ",
"helene-christaller": "Helene Christaller",
"walter-christmas": "Walter Christmas",
"marcus-tullius-cicero": "Marcus Tullius Cicero",
"abraham-a-sancta-clara": "Abraham a Sancta Clara",
"jules-claretie": "Jules Claretie",
"felicia-buttz-clark": "Felicia Buttz Clark",
"walther-friedrich-classen": "Walther Friedrich Classen",
"paul-claudel": "Paul Claudel",
"matthias-claudius": "Matthias Claudius",
"ernst-clausen": "Ernst Clausen",
"carl-von-clausewitz": "Carl von Clausewitz",
"ernst-clefeld": "Ernst Clefeld",
"berta-clement": "Berta Clément",
"hugo-de-clercq": "H[ugo] de Clercq",
"thomas-cobb": "Thomas Cobb",
"helen-cody": "Helen Cody",
"emil-bernhard-cohn": "Emil Bernhard Cohn",
"egmont-colerus": "Egmont Colerus",
"colette": "Colette",
"william-wilkie-collins": "William Wilkie Collins",
"carlo-collodi": "Carlo Collodi",
"luis-coloma": "Luis Coloma",
"josephine-colomb": "Joséphine Colomb",
"heinrich-conrad": "Heinrich Conrad",
"joseph-conrad": "Joseph Conrad",
"michael-georg-conrad": "Michael Georg Conrad",
"hermann-conradi": "Hermann Conradi",
"hendrik-conscience": "Hendrik Conscience",
"ernst-consentius": "Ernst Consentius",
"ernst-constantin": "Ernst Constantin",
"carl-wilhelm-salice-contessa": "Carl Wilhelm Salice Contessa",
"james-fenimore-cooper": "James Fenimore Cooper",
"francois-coppee": "François Coppée",
"lovis-corinth": "Lovis Corinth",
"pierre-corneille": "Pierre Corneille",
"wilhelm-cornelius": "Wilhelm Cornelius",
"blanda-corony": "Blanda Corony",
"egon-caesar-conte-corti": "Egon Cäsar Conte Corti",
"otto-julius-bernhard-von-corvin-wiersbitzki": "Otto Julius Bernhard von Corvin-Wiersbitzki",
"charles-theodore-henri-de-coster": "Charles Théodore Henri De Coster",
"heinrich-graf-coudenhove-kalergi": "Heinrich Graf Coudenhove-Kalergi",
"henri-coudon": "Henri Coudon",
"louis-couperus": "Louis Couperus",
"hedwig-courths-mahler": "Hedwig Courths-Mahler",
"maria-cranz": "Maria Cranz",
"claude-prosper-jolyot-de-crebillon": "Claude Prosper Jolyot de Crébillon",
"carl-crede": "Carl Credé",
"wilhelm-cremer": "Wilhelm Cremer",
"rudolf-creutz": "Rudolf Creutz",
"anna-croissant-rust": "Anna Croissant-Rust",
"bithia-mary-croker": "Bithia Mary Croker",
"rudolf-cronau": "Rudolf Cronau",
"julie-van-rensselaer-cruger": "Julie Van Rensselaer Cruger",
"magnus-jacob-crusenstolpe": "Magnus Jacob Crusenstolpe",
"ridgwell-cullum": "Ridgwell Cullum",
"catherine-cuthbertson": "Catherine Cuthbertson",
"frau-von-d": "Frau von D.",
"simon-dach": "Simon Dach",
"marie-dagoult": "Marie d’Agoult",
"felix-dahn": "Felix Dahn",
"albert-daiber": "Albert Daiber",
"jean-le-rond-dalembert": "Jean Le Rond d’Alembert",
"adolf-dalwig-hohenrode": "Adolf Dalwig-Hohenrode",
"adolf-damaschke": "Adolf Damaschke",
"gabriele-dannunzio": "Gabriele D’Annunzio",
"charles-darwin": "Charles Darwin",
"theodor-daeubler": "Theodor Däubler",
"godard-daucour": "Godard D’Aucour",
"alphonse-daudet": "Alphonse Daudet",
"leon-daudet": "Léon Daudet",
"jules-amedee-barbey-daurevilly": "Jules Amédée Barbey d’Aurevilly",
"elisabeth-dauthendey": "Elisabeth Dauthendey",
"max-dauthendey": "Max Dauthendey",
"jakob-julius-david": "Jakob Julius David",
"henriette-davidis": "Henriette Davidis",
"richard-harding-davis": "Richard Harding Davis",
"nikolaus-decius": "Nikolaus Decius",
"auguste-von-der-decken": "Auguste von der Decken",
"ernst-decsey": "Ernst Decsey",
"eugen-hermann-von-dedenroth": "Eugen Hermann von Dedenroth",
"daniel-defoe": "Daniel Defoe",
"paula-dehmel": "Paula Dehmel",
"richard-dehmel": "Richard Dehmel",
"eduard-douwes-dekker": "Eduard Douwes Dekker",
"joachim-von-delbrueck": "Joachim von Delbrück",
"grazia-deledda": "Grazia Deledda",
"friedrich-delitzsch": "Friedrich Delitzsch",
"madelon-st-denis": "Madelon St. Denis",
"august-egbert-von-derschau": "August Egbert von Derschau",
"juliane-dery": "Juliane Déry",
"rene-descartes": "René Descartes",
"johann-hermann-detmold": "Johann Hermann Detmold",
"lev-grigorievich-deutsch": "Lev Grigorievich Deutsch",
"eduard-devrient": "Eduard Devrient",
"charles-dickens": "Charles Dickens",
"denis-diderot": "Denis Diderot",
"ernst-didring": "Ernst Didring",
"bernhard-diebold": "Bernhard Diebold",
"franz-diederich": "Franz Diederich",
"anton-dietrich": "Anton Dietrich",
"johann-dietz": "Johann Dietz",
"georgi-dimitroff": "Georgi Dimitroff",
"friedrich-von-dincklage-campe": "Friedrich von Dincklage-Campe",
"franz-von-dingelstedt": "Franz von Dingelstedt",
"jenny-dirnboeck-schulz": "Jenny Dirnböck-Schulz",
"benjamin-disraeli": "Benjamin Disraeli",
"charles-lutwidge-dodgson": "Charles Lutwidge Dodgson",
"otto-doerry": "Otto Doerry",
"hedwig-dohm": "Hedwig Dohm",
"karl-doehring": "Karl Döhring",
"georg-domel": "Georg Domel",
"hans-dominik": "Hans Dominik",
"adolph-donath": "Adolph Donath",
"hans-doerfler": "Hans Dörfler",
"georg-doering": "Georg Döring",
"felix-doermann": "Felix Dörmann",
"hedwig-dorn": "Hedwig Dorn",
"johannes-dose": "Johannes Dose",
"fjodor-michailowitsch-dostojewski": "Fjodor Michailowitsch Dostojewski",
"lloyd-c-douglas": "LLoyd C. Douglas",
"lord-alfred-douglas": "Lord Alfred Douglas",
"arthur-conan-doyle": "Arthur Conan Doyle",
"ferdinand-draak": "Ferdinand Draak",
"holger-drachmann": "Holger Drachmann",
"hedwig-dransfeld": "Hedwig Dransfeld",
"max-dreyer": "Max Dreyer",
"alfred-dreyfus": "Alfred Dreyfus",
"max-dreysel": "Max Dreysel",
"hans-driesch": "Hans Driesch",
"erwin-drinneberg": "Erwin Drinneberg",
"ernst-dronke": "Ernst Dronke",
"emil-droonberg": "Emil Droonberg",
"fritz-droop": "Fritz Droop",
"annette-von-droste-huelshoff": "Annette von Droste-Hülshoff",
"johann-gustav-droysen": "Johann Gustav Droysen",
"mong-ds": "Mong Dsï",
"charles-edouard-duboc": "Charles Edouard Duboc",
"eduard-duller": "Eduard Duller",
"dora-duncker": "Dora Duncker",
"adolf-dunkmann": "Adolf Dunkmann",
"ida-von-dueringsfeld": "Ida von Düringsfeld",
"josef-duerr": "Josef Dürr",
"max-duerr": "Max Dürr",
"olav-duun": "Olav Duun",
"hermann-ebbinghaus": "Hermann Ebbinghaus",
"august-gottlob-eberhard": "August Gottlob Eberhard",
"georg-ebers": "Georg Ebers",
"clara-ebert": "Clara Ebert",
"friedrich-ebert": "Friedrich Ebert",
"georg-karl-wilhelm-adolf-ebert": "(Georg Karl Wilhelm) Adolf Ebert",
"marie-von-ebner-eschenbach": "Marie von Ebner-Eschenbach",
"erich-ebstein": "Erich Ebstein",
"jose-echegaray": "José Echegaray",
"johann-peter-eckermann": "Johann Peter Eckermann",
"ernst-eckstein": "Ernst Eckstein",
"bertha-eckstein-diener": "Bertha Eckstein-Diener",
"edmund-edel": "Edmund Edel",
"annie-edwards": "Annie Edwards",
"anton-edzardi": "Anton Edzardi",
"frederik-van-eeden": "Frederik van Eeden",
"georges-eekhoud": "Georges Eekhoud",
"luise-egloff": "Luise Egloff",
"albert-ehrenstein": "Albert Ehrenstein",
"hans-heinrich-ehrler": "Hans Heinrich Ehrler",
"marianne-ehrmann": "Marianne Ehrmann",
"reinhold-eichacker": "Reinhold Eichacker",
"joseph-von-eichendorff": "Joseph von Eichendorff",
"ludwig-eichrodt": "Ludwig Eichrodt",
"august-eigner": "August Eigner",
"carl-einstein": "Carl Einstein",
"george-dyre-eldridge": "George Dyre Eldridge",
"julie-elias": "Julie Elias",
"alexander-eliasberg": "Alexander Eliasberg",
"christian-elster": "Christian Elster",
"sven-elvestad": "Sven Elvestad",
"ralph-waldo-emerson": "Ralph Waldo Emerson",
"ferdinand-emmerich": "Ferdinand Emmerich",
"paul-enderling": "Paul Enderling",
"fred-endrikat": "Fred Endrikat",
"eduard-engel": "Eduard Engel",
"georg-engel": "Georg Engel",
"johann-jakob-engel": "Johann Jakob Engel",
"carla-alexandra-von-engelhorn": "Carla Alexandra von Engelhorn",
"gerrit-engelke": "Gerrit Engelke",
"friedrich-engels": "Friedrich Engels",
"ottomar-enking": "Ottomar Enking",
"richard-e-enright": "Richard E. Enright",
"karl-august-varnhagen-von-ense": "Karl August Varnhagen von Ense",
"rahel-varnhagen-von-ense": "Rahel Varnhagen von Ense",
"josef-von-eoetvoes": "Josef von Eötvös",
"epiktet": "Epiktet",
"emile-erckmann": "Emile Erckmann",
"christian-ernst": "Christian Ernst",
"otto-ernst": "Otto Ernst",
"paul-ernst": "Paul Ernst",
"john-erskine": "John Erskine",
"emil-ertl": "Emil Ertl",
"bruno-ertler": "Bruno Ertler",
"wolfram-von-eschenbach": "Wolfram von Eschenbach",
"emilie-escherich": "Emilie Escherich",
"mathilde-von-eschstruth": "Mathilde von Eschstruth",
"nataly-von-eschstruth": "Nataly von Eschstruth",
"hermann-essig": "Hermann Essig",
"alois-essigmann": "Alois Essigmann",
"josef-moritz-ettlinger": "Josef Moritz Ettlinger",
"karl-ettlinger": "Karl Ettlinger",
"ludwig-ettmueller": "Ludwig Ettmüller",
"rudolf-christoph-eucken": "Rudolf Christoph Eucken",
"herbert-eulenberg": "Herbert Eulenberg",
"philipp-fuerst-zu-eulenburg-hertefeld": "Philipp Fürst zu Eulenburg-Hertefeld",
"euripides": "Euripides",
"mary-anne-evans": "Mary Anne Evans",
"franz-evers": "Franz Evers",
"karl-ewald": "Karl Ewald",
"hanns-heinz-ewers": "Hanns Heinz Ewers",
"luise-ey": "Luise Ey",
"carola-freiin-von-eynatten": "Carola Freiin von Eynatten",
"max-eyth": "Max Eyth",
"kurt-faber": "Kurt Faber",
"johannes-daniel-falk": "Johannes Daniel Falk",
"gustav-falke": "Gustav Falke",
"konrad-falke": "Konrad Falke",
"carl-falkenhorst": "Carl Falkenhorst",
"leonhard-falkner": "Leonhard Falkner",
"hans-fallada": "Hans Fallada",
"hoffmann-von-fallersleben": "Hoffmann von Fallersleben",
"ignaz-familler": "Ignaz Familler",
"frederick-john-fargus": "Frederick John Fargus",
"salvatore-farina": "Salvatore Farina",
"claude-farrere": "Claude Farrère",
"hermann-faulhaber": "Hermann Faulhaber",
"frederick-schiller-faust": "Frederick Schiller Faust",
"marie-madeleine-la-fayette": "Marie-Madeleine La Fayette",
"felix-fechenbach": "Felix Fechenbach",
"anna-fechner": "Anna Fechner",
"gustav-theodor-fechner": "Gustav Theodor Fechner",
"wolfgang-federau": "Wolfgang Federau",
"heinrich-federer": "Heinrich Federer",
"karl-federn": "Karl Federn",
"etta-federn-kohlhaas": "Etta Federn-Kohlhaas",
"johann-hinrich-fehrs": "Johann Hinrich Fehrs",
"caroline-von-feilitzsch": "Caroline von Feilitzsch",
"anton-fendrich": "Anton Fendrich",
"john-ferguson": "John Ferguson",
"gabriel-ferry": "Gabriel Ferry",
"carl-august-fetzer": "Carl August Fetzer",
"ernst-von-feuchtersleben": "Ernst von Feuchtersleben",
"anselm-feuerbach": "Anselm Feuerbach",
"ludwig-feuerbach": "Ludwig Feuerbach",
"paul-johann-anselm-ritter-von-feuerbach": "Paul Johann Anselm Ritter von Feuerbach",
"johann-gottlieb-fichte": "Johann Gottlieb Fichte",
"henry-fielding": "Henry Fielding",
"wera-figner": "Wera Figner",
"johann-fischart": "Johann Fischart",
"caroline-auguste-fischer": "Caroline Auguste Fischer",
"hans-fischer": "Hans Fischer",
"johann-georg-fischer": "Johann Georg Fischer",
"marthe-renate-fischer": "Marthe Renate Fischer",
"wilhelm-fischer": "Wilhelm Fischer",
"wilhelm-fischer-2": "Wilhelm Fischer",
"hans-fischer-stockern": "Hans Fischer-Stockern",
"arthur-fitger": "Arthur Fitger",
"f-scott-fitzgerald": "F. Scott Fitzgerald",
"caesar-flaischlen": "Cäsar Flaischlen",
"otto-flake": "Otto Flake",
"gustave-flaubert": "Gustave Flaubert",
"max-fleischer": "Max Fleischer",
"otto-fleischmann": "Otto Fleischmann",
"paul-fleming": "Paul Fleming",
"joseph-smith-fletcher": "Joseph Smith Fletcher",
"zenade-fleuriot": "Zenaïde Fleuriot",
"walter-flex": "Walter Flex",
"kurt-floericke": "Kurt Floericke",
"hanns-floerke": "Hanns Floerke",
"gorch-fock": "Gorch Fock",
"antonio-fogazzaro": "Antonio Fogazzaro",
"friedrich-foltz": "Friedrich Foltz",
"jean-de-la-fontaine": "Jean de La Fontaine",
"theodor-fontane": "Theodor Fontane",
"hulbert-footner": "Hulbert Footner",
"irene-anna-maria-magdalena-gisela-gabriele-forbes-mosse": "Irene Anna Maria Magdalena Gisela Gabriele Forbes-Mosse",
"georg-forster": "Georg Forster",
"john-forster": "John Forster",
"friedrich-foerster": "Friedrich Förster",
"friedrich-de-la-motte-fouque": "Friedrich de la Motte Fouqué",
"martin-fraenkel": "Martin Fraenkel",
"ludwig-frahm": "Ludwig Frahm",
"anatole-france": "Anatole France",
"marie-de-france": "Marie de France",
"raoul-heinrich-france": "Raoul Heinrich Francé",
"louise-von-francois": "Louise von François",
"adolf-frank": "Adolf Frank",
"anne-frank": "Anne Frank",
"bruno-frank": "Bruno Frank",
"else-franken": "Else Franken",
"renate-franken": "Renate Franken",
"richard-otto-frankfurter": "Richard Otto Frankfurter",
"benjamin-franklin": "Benjamin Franklin",
"john-franklin": "John Franklin",
"constantin-frantz": "Constantin Frantz",
"agnes-franz": "Agnes Franz",
"ignaz-franz-1": "Ignaz Franz",
"franz-joseph-von-oesterreich": "Franz Joseph von Österreich",
"karl-emil-franzos": "Karl Emil Franzos",
"ilse-frapan": "Ilse Frapan",
"joseph-fraessle": "Joseph Fräßle",
"bertha-frederich": "Bertha Frederich",
"richard-austin-freeman": "Richard Austin Freeman",
"ferdinand-freiligrath": "Ferdinand Freiligrath",
"ernst-wolfgang-freissler": "Ernst Wolfgang Freissler",
"helene-frenkel": "Helene Frenkel",
"gustav-frenssen": "Gustav Frenssen",
"sigmund-freud": "Sigmund Freud",
"johannes-freumbichler": "Johannes Freumbichler",
"leo-freund": "Leo Freund",
"jakob-frey": "Jakob Frey",
"gustav-freytag": "Gustav Freytag",
"egon-friedell": "Egon Friedell",
"albert-friedenthal": "Albert Friedenthal",
"ludwig-friedlaender": "Ludwig Friedlaender",
"salomon-friedlaender": "Salomon Friedlaender",
"hugo-friedlaender": "Hugo Friedländer",
"emanuel-friedli": "Emanuel Friedli",
"hermann-friedrich-friedrich": "Hermann Friedrich Friedrich",
"efraim-frisch": "Efraim Frisch",
"leo-frobenius": "Leo Frobenius",
"abraham-emanuel-froehlich": "Abraham Emanuel Fröhlich",
"jean-froissart": "Jean Froissart",
"carl-wilhelm-froelich": "Carl Wilhelm Frölich",
"henriette-froelich": "Henriette Frölich",
"emil-wilhelm-frommel": "Emil Wilhelm Frommel",
"sextus-julius-frontinus": "Sextus Julius Frontinus",
"eduard-fuchs": "Eduard Fuchs",
"robert-fuchs-liska": "Robert Fuchs-Liska",
"ludwig-fulda": "Ludwig Fulda",
"artur-fuerst": "Artur Fürst",
"a-gaber": "A. Gaber",
"emile-gaboriau": "Émile Gaboriau",
"friedrich-frhr-von-gagern": "Friedrich Frhr. von Gagern",
"benito-perez-galds": "Benito Pérez Galdós",
"philipp-galen": "Philipp Galen",
"else-galen-gube": "Else Galen-Gube",
"abbe-galiani": "Abbé Galiani",
"louise-von-gall": "Louise von Gall",
"john-galsworthy": "John Galsworthy",
"ludwig-ganghofer": "Ludwig Ganghofer",
"josef-gangl": "Josef Gangl",
"samuel-major-gardenhire": "Samuel Major Gardenhire",
"giuseppe-garibaldi": "Giuseppe Garibaldi",
"wsewolod-michailowitsch-garschin": "Wsewolod Michailowitsch Garschin",
"franz-freiherr-von-gaudy": "Franz Freiherr von Gaudy",
"theophile-gautier": "Théophile Gautier",
"emanuel-geibel": "Emanuel Geibel",
"peter-geibel": "Peter Geibel",
"gustaf-af-geijerstam": "Gustaf af Geijerstam",
"max-geissler": "Max Geißler",
"adolf-gelber": "Adolf Gelber",
"christian-fuerchtegott-gellert": "Christian Fürchtegott Gellert",
"georg-gellert": "Georg Gellert",
"august-heinrich-christian-gelpke": "August Heinrich Christian Gelpke",
"rudolf-genee": "Rudolf Genée",
"pamphilus-gengenbach": "Pamphilus Gengenbach",
"stefan-george": "Stefan George",
"adolph-von-gerhardt": "Adolph von Gerhardt",
"paul-gerhardt": "Paul Gerhardt",
"reinhard-gerling": "Reinhard Gerling",
"karl-gerok": "Karl Gerok",
"friedrich-gerstaecker": "Friedrich Gerstäcker",
"silvio-gesell": "Silvio Gesell",
"salomon-gessner": "Salomon Geßner",
"kurt-geucke": "Kurt Geucke",
"simon-gfeller": "Simon Gfeller",
"edward-gibbon": "Edward Gibbon",
"floyd-gibbons": "Floyd Gibbons",
"andre-gide": "André Gide",
"emmy-giehrl": "Emmy Giehrl",
"leo-gilbert": "Leo Gilbert",
"otto-gildemeister": "Otto Gildemeister",
"johannes-gillhoff": "Johannes Gillhoff",
"jean-giraudoux": "Jean Giraudoux",
"robert-giseke": "Robert Giseke",
"otto-gittinger": "Otto Gittinger",
"karl-adolph-gjellerup": "Karl Adolph Gjellerup",
"got-gjems-selmer": "Ågot Gjems-Selmer",
"adolf-glaser": "Adolf Glaser",
"susan-glaspell": "Susan Glaspell",
"luise-glass": "Luise Glass",
"adolf-glassbrenner": "Adolf Glaßbrenner",
"i-j-glaesser": "I. Glässer",
"friedrich-glauser": "Friedrich Glauser",
"joseph-alois-gleich": "Joseph Alois Gleich",
"johann-wilhelm-ludwig-gleim": "Johann Wilhelm Ludwig Gleim",
"claire-von-gluemer": "Claire von Glümer",
"august-graf-neidhardt-von-gneisenau": "August Graf Neidhardt von Gneisenau",
"arthur-de-gobineau": "Arthur de Gobineau",
"marie-amelie-freiin-von-godin": "Marie Amelie Freiin von Godin",
"leopold-friedrich-guenther-von-goeckingk": "Leopold Friedrich Günther von Goeckingk",
"elisabeth-goedicke": "Elisabeth Goedicke",
"hermann-ottomar-friedrich-goedsche": "Hermann Ottomar Friedrich Goedsche",
"reinoudina-de-goeje": "Reinoudina de Goeje",
"reinhard-goering": "Reinhard Goering",
"johann-wolfgang-von-goethe": "Johann Wolfgang von Goethe",
"katharina-elisabetha-goethe": "Katharina Elisabetha Goethe",
"vincent-van-gogh": "Vincent van Gogh",
"nikolai-gogol": "Nikolai Gogol",
"paul-goehre": "Paul Göhre",
"otto-goldmann": "Otto Goldmann",
"oliver-goldsmith": "Oliver Goldsmith",
"bogumil-goltz": "Bogumil Goltz",
"edmond-de-goncourt": "Edmond de Goncourt",
"jules-de-goncourt": "Jules de Goncourt",
"susette-gontard": "Susette Gontard",
"iwan-gontscharow": "Iwan Gontscharow",
"john-goodwin": "John Goodwin",
"evans-gordon": "Evans Gordon",
"maxim-gorki": "Maxim Gorki",
"joseph-von-goerres": "Joseph von Görres",
"marie-luise-gothein": "Marie Luise Gothein",
"emil-servatius-goett": "Emil Servatius Gött",
"jeremias-gotthelf": "Jeremias Gotthelf",
"rudolf-carl-von-gottschall": "Rudolf (Carl) von Gottschall",
"johann-christoph-gottsched": "Johann Christoph Gottsched",
"johann-nikolaus-goetz": "Johann Nikolaus Götz",
"hermann-grab": "Hermann Grab",
"christian-dietrich-grabbe": "Christian Dietrich Grabbe",
"paul-grabein": "Paul Grabein",
"max-grad": "Max Grad",
"l-w-graepp": "L. W. Graepp",
"erdmann-graeser": "Erdmann Graeser",
"franz-arnold-graeffer": "Franz Arnold Gräffer",
"kenneth-grahame": "Kenneth Grahame",
"hans-grasberger": "Hans Grasberger",
"johann-georg-theodor-graesse": "Johann Georg Theodor Gräße",
"ferdinand-grautoff": "Ferdinand Grautoff",
"marie-eugenie-delle-grazie": "Marie Eugenie Delle Grazie",
"anna-katherine-green": "Anna Katherine Green",
"fitzhugh-green": "Fitzhugh Green",
"gregoria": "Gregoria",
"ferdinand-gregorovius": "Ferdinand Gregorovius",
"martin-greif": "Martin Greif",
"leo-greiner": "Leo Greiner",
"rudolf-heinrich-greinz": "Rudolf (Heinrich) Greinz",
"georg-gretor": "Georg Gretor",
"henry-greville": "Henry Gréville",
"zane-grey": "Zane Grey",
"otto-von-greyerz": "Otto von Greyerz",
"francis-gribble": "Francis Gribble",
"j-c-l-griefer": "J. C. L. Griefer",
"johannes-christian-ludwig-grieser": "Johannes Christian Ludwig Grieser",
"arthur-griffiths": "Arthur Griffiths",
"franz-grillparzer": "Franz Grillparzer",
"brueder-grimm": "Brüder Grimm",
"herman-grimm": "Herman Grimm",
"jakob-grimm": "Jakob Grimm",
"hans-jakob-christoffel-von-grimmelshausen": "Hans Jakob Christoffel von Grimmelshausen",
"eduard-grisebach": "Eduard Grisebach",
"georg-groddeck": "Georg Groddeck",
"balduin-groller": "Balduin Groller",
"auguste-groner": "Auguste Groner",
"hans-gross": "Hans Gross",
"julius-grosse": "Julius Grosse",
"karl-grosse": "Karl Grosse",
"stefan-grossmann": "Stefan Großmann",
"klaus-groth": "Klaus Groth",
"curt-grottewitz": "Curt Grottewitz",
"august-wilhelm-grube": "August Wilhelm Grube",
"august-wilhelm-grube-2": "August Wilhelm Grube",
"anton-grumann": "Anton Grumann",
"fritz-gruenbaum": "Fritz Grünbaum",
"carl-grunert": "Carl Grunert",
"andreas-gryphius": "Andreas Gryphius",
"emile-guillaumin": "Émile Guillaumin",
"ricardo-guiraldes": "Ricardo Guiraldes",
"martin-gumpert": "Martin Gumpert",
"hanns-theodor-wilhelm-freiherr-von-gumppenberg": "Hanns Theodor Wilhelm Freiherr von Gumppenberg",
"lotte-gumtau": "Lotte Gumtau",
"karoline-von-guenderrode": "Karoline von Günderrode",
"archibald-clavering-gunter": "Archibald Clavering Gunter",
"agnes-guenther": "Agnes Günther",
"johann-christian-guenther": "Johann Christian Günther",
"paul-gurk": "Paul Gurk",
"cornelius-gurlitt": "Cornelius Gurlitt",
"maria-sophie-von-la-roche-geb-gutermann": "(Maria) Sophie von La Roche geb. Gutermann",
"julius-guttmann": "Julius Guttmann",
"karl-gutzkow": "Karl Gutzkow",
"alexander-xaver-gwerder": "Alexander Xaver Gwerder",
"gyp": "Gyp",
"julius-r-haarhaus": "Julius R. Haarhaus",
"john-habberton": "John Habberton",
"karl-ludwig-haeberlin": "Karl Ludwig Häberlin",
"ludwig-habicht": "Ludwig Habicht",
"maximilian-i-von-habsburg": "Maximilian I. von Habsburg",
"friedrich-wilhelm-hacklaender": "Friedrich Wilhelm Hackländer",
"heinrich-hackmann": "Heinrich Hackmann",
"victor-hadwiger": "Victor Hadwiger",
"ernst-haeckel": "Ernst Haeckel",
"theodor-haecker": "Theodor Haecker",
"sophie-haemmerli-marti": "Sophie Haemmerli-Marti",
"hafis": "Hafis",
"friedrich-von-hagedorn": "Friedrich von Hagedorn",
"joseph-matthias-haegele": "Joseph Matthias Hägele",
"august-hagen": "August Hagen",
"john-hagenbeck": "John Hagenbeck",
"henry-rider-haggard": "Henry Rider Haggard",
"edmund-reinhold-hahn": "Edmund Reinhold Hahn",
"johann-hahn": "Johann Hahn",
"julius-hahn": "Julius Hahn",
"samuel-hahnemann": "Samuel Hahnemann",
"ida-von-hahn-hahn": "Ida von Hahn-Hahn",
"max-halbe": "Max Halbe",
"wilhelm-haldy": "[Wilhelm?] Haldy",
"albrecht-von-haller": "Albrecht von Haller",
"lilli-haller": "Lilli Haller",
"paul-haller": "Paul Haller",
"friedrich-halm": "Friedrich Halm",
"josef-haltrich": "Josef Haltrich",
"johann-georg-hamann": "Johann Georg Hamann",
"paul-hambruch": "Paul Hambruch",
"robert-hamerling": "Robert Hamerling",
"anthony-graf-hamilton": "Anthony Graf Hamilton",
"nanny-hammarstroem": "Nanny Hammarström",
"joseph-von-hammer-purgstall": "Joseph von Hammer-Purgstall",
"wilhelm-hammond-norden": "Wilhelm Hammond-Norden",
"knut-hamsun": "Knut Hamsun",
"enrica-von-handel-mazzetti": "Enrica von Handel-Mazzetti",
"julius-bab-willy-handl": "Julius Bab / Willy Handl",
"willi-handl": "Willi Handl",
"hermann-hango": "Hermann Hango",
"norbert-hanrieder-2": "Norbert Hanrieder",
"norbert-hanrieder": "Norbert Hanrieder",
"robert-hansen": "Robert Hansen",
"hans-freiherr-von-hammerstein-equord": "Hans Freiherr von Hammerstein-Equord",
"heinrich-hansjakob": "Heinrich Hansjakob",
"paul-hansmann": "Paul Hansmann",
"ludwig-adalbert-von-hanstein": "(Ludwig) Adalbert von Hanstein",
"thea-von-harbou": "Thea von Harbou",
"maximilian-harden": "Maximilian Harden",
"agnes-harder": "Agnes Harder",
"friedrich-wilhelm-ernst-hardt": "(Friedrich Wilhelm) Ernst Hardt",
"victor-hardung": "Victor Hardung",
"walther-harich": "Walther Harich",
"jakob-haringer": "Jakob Haringer",
"henry-harland": "Henry Harland",
"otto-harnack": "Otto Harnack",
"frank-harris": "Frank Harris",
"zsolt-von-harsnyi": "Zsolt von Harsányi",
"georg-philipp-harsdoerfer": "Georg Philipp Harsdörfer",
"hans-hart": "Hans Hart",
"heinrich-hart": "Heinrich Hart",
"julius-hart": "Julius Hart",
"bret-harte": "Bret Harte",
"angelica-harten": "Angelica Harten",
"johann-friedrich-von-harten": "Johann Friedrich von Harten",
"felix-hartlaub": "Felix Hartlaub",
"otto-erich-hartleben": "Otto Erich Hartleben",
"moritz-hartmann": "Moritz Hartmann",
"jaroslav-haek": "Jaroslav Hašek",
"walter-hasenclever": "Walter Hasenclever",
"david-hatschek": "David Hatschek",
"carl-hau": "Carl Hau",
"richard-georg-spiller-von-hauenschild": "Richard Georg Spiller von Hauenschild",
"wilhelm-hauff": "Wilhelm Hauff",
"johann-christoph-friedrich-haug": "(Johann Christoph) Friedrich Haug",
"carl-hauptmann": "Carl Hauptmann",
"gerhart-hauptmann": "Gerhart Hauptmann",
"a-w-hauschild": "A. W. Hauschild",
"friedrich-von-hausen": "Friedrich von Hausen",
"heinrich-hauser": "Heinrich Hauser",
"adolf-hausrath": "Adolf Hausrath",
"august-hausrath": "August Hausrath",
"rudolf-hawel": "Rudolf Hawel",
"julian-hawthorne": "Julian Hawthorne",
"nathaniel-hawthorne": "Nathaniel Hawthorne",
"ernest-haycox": "Ernest Haycox",
"lafcadio-hearn": "Lafcadio Hearn",
"christian-friedrich-hebbel": "Christian Friedrich Hebbel",
"johann-peter-hebel": "Johann Peter Hebel",
"alfred-von-hedenstjerna": "Alfred von Hedenstjerna",
"sven-hedin": "Sven Hedin",
"jacob-christoph-heer": "Jacob Christoph Heer",
"gustav-adolf-von-heeringen": "Gustav Adolf von Heeringen",
"georg-wilhelm-friedrich-hegel": "Georg Wilhelm Friedrich Hegel",
"wilhelm-hegeler": "Wilhelm Hegeler",
"werner-hegemann": "Werner Hegemann",
"ulrich-hegner": "Ulrich Hegner",
"viktor-hehn": "Viktor Hehn",
"hermann-heiberg": "Hermann Heiberg",
"verner-von-heidenstam": "Verner von Heidenstam",
"karl-von-heigel": "Karl von Heigel",
"adolf-heilborn": "Adolf Heilborn",
"ernst-heilborn": "Ernst Heilborn",
"georg-heim": "Georg Heim",
"moritz-heimann": "Moritz Heimann",
"heinrich-heimanns": "Heinrich Heimanns",
"anselma-heine": "Anselma Heine",
"heinrich-heine": "Heinrich Heine",
"thomas-theodor-heine": "Thomas Theodor Heine",
"karl-borromaeus-heinrich": "Karl Borromaeus Heinrich",
"o-f-heinrich": "O. F. Heinrich",
"elisabeth-heinroth": "Elisabeth Heinroth",
"johann-jakob-wilhelm-heinse": "(Johann Jakob) Wilhelm Heinse",
"friedrich-helbig": "Friedrich Helbig",
"johann-lorenz-helbig": "Johann Lorenz Helbig",
"t-von-held": "T. von Held",
"karl-theodor-helfferich": "Karl Theodor Helfferich",
"frank-heller": "Frank Heller",
"wolfgang-hellmert": "Wolfgang Hellmert",
"hermann-ludwig-ferdinand-von-helmholtz": "Hermann Ludwig Ferdinand von Helmholtz",
"jarl-hemmer": "Jarl Hemmer",
"karl-friedrich-hempfing": "Karl Friedrich Hempfing",
"karl-henckell": "Karl Henckell",
"paul-henkes": "Paul Henkes",
"richard-hennig": "Richard Hennig",
"max-henning": "Max Henning",
"emmy-hennings": "Emmy Hennings",
"hedwig-henrich-wilhelmi": "Hedwig Henrich-Wilhelmi",
"alfred-henschke": "Alfred Henschke",
"luise-hensel": "Luise Hensel",
"karl-friedrich-hensler": "Karl Friedrich Hensler",
"wilhelm-herchenbach": "Wilhelm Herchenbach",
"ferenc-herczeg": "Ferenc Herczeg",
"johann-gottfried-herder": "Johann Gottfried Herder",
"joseph-hergesheimer": "Joseph Hergesheimer",
"karl-herlosssohn": "Karl Herloßsohn",
"georg-hermann": "Georg Hermann",
"hermann-von-gilm-ritter-zu-rosenegg": "Hermann von Gilm, Ritter zu Rosenegg",
"herodot": "Herodot",
"franz-herold": "Franz Herold",
"max-herrmann-neisse": "Max Herrmann-Neiße",
"betty-hertel": "Betty Hertel",
"heinrich-hertz": "Heinrich Hertz",
"wilhelm-hertz": "Wilhelm Hertz",
"harry-hervey": "Harry Hervey",
"georg-herwegh": "Georg Herwegh",
"alexander-herzen": "Alexander Herzen",
"theodor-herzl": "Theodor Herzl",
"rudolf-herzog": "Rudolf Herzog",
"georg-hesekiel": "Georg Hesekiel",
"hesiod": "Hesiod",
"david-hess": "David Hess",
"hermann-hesse": "Hermann Hesse",
"franz-hessel": "Franz Hessel",
"robert-hessen": "Robert Hessen",
"carl-gottlieb-samuel-heun": "Carl Gottlieb Samuel Heun",
"johanna-spyri-geb-heusser": "Johanna Spyri geb. Heusser",
"ludwig-hevesi": "Ludwig Hevesi",
"johann-wilhelm-hey": "(Johann) Wilhelm Hey",
"artur-heye": "Artur Heye",
"hermann-heyermans": "Hermann Heyermans",
"elisabeth-von-heyking": "Elisabeth von Heyking",
"georg-heym": "Georg Heym",
"robert-heymann": "Robert Heymann",
"paul-heyse": "Paul Heyse",
"werner-hildebrand": "Werner Hildebrand",
"richard-hildreth": "Richard Hildreth",
"headon-hill": "Headon Hill",
"gunter-hille": "Gunter Hille",
"peter-hille": "Peter Hille",
"karl-hillebrand": "Karl Hillebrand",
"wilhelmine-von-hillern": "Wilhelmine von Hillern",
"franz-himmelbauer": "Franz Himmelbauer",
"carsten-hinz": "Carsten Hinz",
"theodor-gottlieb-von-hippel": "Theodor Gottlieb von Hippel",
"sinaida-hippius": "Sinaida Hippius",
"jenny-hirsch": "Jenny Hirsch",
"julian-hirsch": "Julian Hirsch",
"marie-hirsch": "Marie Hirsch",
"herbert-hirschberg": "Herbert Hirschberg",
"leopold-hirschberg": "Leopold Hirschberg",
"georg-hirschfeld": "Georg Hirschfeld",
"hermann-hirschfeld": "Hermann Hirschfeld",
"magnus-hirschfeld": "Magnus Hirschfeld",
"ginez-perez-de-hita": "Ginez Perez de Hita",
"julius-eduard-hitzig": "Julius Eduard Hitzig",
"thomas-hobbes": "Thomas Hobbes",
"gustav-hochstetter": "Gustav Hochstetter",
"oskar-hoecker": "Oskar Höcker",
"jakob-van-hoddis": "Jakob van Hoddis",
"sophie-hoechstetter": "Sophie Hoechstetter",
"edmund-hoefer": "Edmund Hoefer",
"herbert-von-hoerner": "Herbert von Hoerner",
"josef-hofbauer": "Josef Hofbauer",
"c-hoffmann": "C. Hoffmann",
"camill-hoffmann": "Camill Hoffmann",
"eta-hoffmann": "E.T.A. Hoffmann",
"franz-hoffmann": "Franz Hoffmann",
"hans-hoffmann": "Hans Hoffmann",
"heinrich-hoffmann": "Heinrich Hoffmann",
"else-hofmann": "Else Hofmann",
"max-hofmann": "Max Hofmann",
"hugo-von-hofmannsthal": "Hugo von Hofmannsthal",
"christian-hofmann-von-hofmannswaldau": "Christian Hofmann von Hofmannswaldau",
"josef-hofmiller": "Josef Hofmiller",
"wernher-von-hohenberg": "Wernher von Hohenberg",
"ludvig-holberg": "Ludvig Holberg",
"friedrich-hoelderlin": "Friedrich Hölderlin",
"wenzel-holek": "Wenzel Holek",
"arnold-holitscher": "Arnold Holitscher",
"arthur-holitscher": "Arthur Holitscher",
"felix-hollaender": "Felix Hollaender",
"else-von-hollander-lossow": "Else von Hollander-Lossow",
"korfiz-holm": "Korfiz Holm",
"karl-von-holtei": "Karl von Holtei",
"carl-holtschmidt": "Carl Holtschmidt",
"ludwig-heinrich-christoph-hoelty": "Ludwig Heinrich Christoph Hölty",
"friedrich-holtze": "Friedrich Holtze",
"arno-holz": "Arno Holz",
"wilhelm-holzamer": "Wilhelm Holzamer",
"homer": "Homer",
"forrestine-c-hooker": "Forrestine C. Hooker",
"hans-ritter-von-hopfen": "Hans Ritter von Hopfen",
"horaz": "Horaz",
"friedrich-robert-horn": "Friedrich Rufus Nord",
"ernest-william-hornung": "Ernest William Hornung",
"walter-horst": "Walter Horst",
"oedoen-von-horvth": "Ödön von Horváth",
"albert-hotopp": "Albert Hotopp",
"annie-hruschka": "Annie Hruschka",
"helene-huebener": "Helene Hübener",
"therese-huber": "Therese Huber",
"friedrich-huch": "Friedrich Huch",
"ricarda-huch": "Ricarda Huch",
"rudolf-huch": "Rudolf Huch",
"fernand-hue": "Fernand Hue",
"oliver-madox-hueffer": "Oliver Madox Hueffer",
"hermine-hug-hellmuth": "Hermine Hug-Hellmuth",
"victor-hugo": "Victor Hugo",
"friedrich-wilhelm-christian-karl-ferdinand-freiherr-von-humboldt": "(Friedrich) Wilhelm (Christian Karl Ferdinand) Freiherr von Humboldt",
"friedrich-wilhelm-heinrich-alexander-freiherr-von-humboldt": "(Friedrich Wilhelm Heinrich) Alexander Freiherr von Humboldt",
"david-hume": "David Hume",
"frida-hummel": "Frida Hummel",
"ludwig-huna": "Ludwig Huna",
"egon-hundeiker": "Egon Hundeiker",
"monika-hunnius": "Monika Hunnius",
"christian-friedrich-hunold": "Christian Friedrich Hunold",
"ulrich-von-hutten": "Ulrich von Hutten",
"hans-hyan": "Hans Hyan",
"hans-volker-hyan": "Hans-Volker Hyan",
"henri-hymans": "Henri Hymans",
"c-j-cutcliffe-hyne": "C. J. Cutcliffe Hyne",
"vicente-blasco-ibanez": "Vicente Blasco Ibañez",
"henrik-ibsen": "Henrik Ibsen",
"eliza-ichenhaeuser": "Eliza Ichenhaeuser",
"oscar-iden-zeller": "Oscar Iden-Zeller",
"august-wilhelm-iffland": "August Wilhelm Iffland",
"rudolf-von-ihering": "Rudolf von Ihering",
"katharina-ii": "Katharina II.",
"karl-immermann": "Karl Immermann",
"john-kells-ingram": "John Kells Ingram",
"washington-irving": "Washington Irving",
"mohammed-ibn-ishak": "Mohammed Ibn Ishak",
"panait-istrati": "Panait Istrati",
"iwan-ivan-yvan-goll": "Iwan Goll",
"friedrich-heinrich-jacobi": "Friedrich Heinrich Jacobi",
"johann-georg-jacobi": "Johann Georg Jacobi",
"johann-georg-friedrich-jacobi": "Johann Georg Friedrich Jacobi",
"ludwig-jacobowski": "Ludwig Jacobowski",
"jens-peter-jacobsen": "Jens Peter Jacobsen",
"caroline-jacobshagen": "Caroline Jacobshagen",
"siegfried-jacobsohn": "Siegfried Jacobsohn",
"norbert-jacques": "Norbert Jacques",
"ernst-jaedicke": "Ernst Jaedicke",
"hans-henrik-jger": "Hans Henrik Jæger",
"friedrich-jaksch": "Friedrich Jaksch",
"francis-jammes": "Francis Jammes",
"maria-janitschek": "Maria Janitschek",
"jean-baptiste-de-boyer-marquis-dargens": "Jean-Baptiste de Boyer, Marquis d’Argens",
"jean-baptiste-de-boyer-marquis-dargens-2": "Jean-Baptiste de Boyer, Marquis d’Argens",
"benzion-ben-jehuda": "Benzion Ben Jehuda",
"oskar-jellinek": "Oskar Jellinek",
"ina-jens": "Ina Jens",
"johannes-vilhelm-jensen": "Johannes Vilhelm Jensen",
"wilhelm-jensen": "Wilhelm Jensen",
"carl-jentsch": "Carl Jentsch",
"jerome-klapka-jerome": "Jerome Klapka Jerome",
"douglas-jerrold": "Douglas Jerrold",
"hartwig-jess": "Hartwig Jess",
"alois-jirsek": "Alois Jirásek",
"johann-rudolf-wyss-der-juengere": "Johann Rudolf Wyß der Jüngere",
"t-h-johansen": "T. H. Johansen",
"paul-john": "Paul John",
"maurus-jkai": "Maurus Jókai",
"w-jolanda": "W. Jolanda",
"ben-jonson": "Ben Jonson",
"wilhelm-jordan": "Wilhelm Jordan",
"ignaz-anton-joseph": "Ignaz Anton Joseph",
"alexander-jung": "Alexander Jung",
"johann-heinrich-jung": "Johann Heinrich Jung",
"alexandre-dumas-der-juengere": "Alexandre Dumas der Jüngere",
"max-jungnickel": "Max Jungnickel",
"walther-kabel": "Walther Kabel",
"theodor-kabelitz": "Theodor Kabelitz",
"franz-kafka": "Franz Kafka",
"arthur-kahane": "Arthur Kahane",
"kaiserin-elisabeth-von-oesterreich": "Kaiserin Elisabeth von Österreich",
"wolf-graf-von-kalckreuth": "Wolf Graf von Kalckreuth",
"david-kalisch": "David Kalisch",
"ludwig-kalisch": "Ludwig Kalisch",
"josef-kallinikow": "Josef Kallinikow",
"johannes-kaltenboeck": "Johannes Kaltenboeck",
"richard-kandt": "Richard Kandt",
"elisha-kent-kane": "Elisha Kent Kane",
"immanuel-kant": "Immanuel Kant",
"franziska-von-kapff-essenther": "Franziska von Kapff-Essenther",
"egon-georg-von-kapherr": "Egon Georg von Kapherr",
"friedrich-kapp": "Friedrich Kapp",
"rudolf-von-kapri": "Rudolf von Kapri",
"anna-karbe": "Anna Karbe",
"alma-karlin": "Alma Karlin",
"carl-karlweis": "Carl Karlweis",
"adam-karrillon": "Adam Karrillon",
"josef-kastein": "Josef Kastein",
"erich-kaestner": "Erich Kästner",
"berta-katscher": "Berta Katscher",
"leopold-katscher": "Leopold Katscher",
"max-rudolf-kaufmann": "Max Rudolf Kaufmann",
"hermann-kaulbach": "Hermann Kaulbach",
"karl-kautsky": "Karl Kautsky",
"john-keats": "John Keats",
"franz-keim": "Franz Keim",
"bodo-keith": "Bodo Keith",
"alexander-keller": "Alexander Keller",
"augustin-keller": "Augustin Keller",
"gottfried-keller": "Gottfried Keller",
"paul-keller": "Paul Keller",
"samuel-keller": "Samuel Keller",
"bernhard-kellermann": "Bernhard Kellermann",
"thomas-von-kempen": "Thomas von Kempen",
"friederike-kempner": "Friederike Kempner",
"george-kennan": "George Kennan",
"grace-kennedy": "Grace Kennedy",
"maximilian-kern": "Maximilian Kern",
"johann-georg-kerner": "Johann Georg Kerner",
"justinus-kerner": "Justinus Kerner",
"marie-kerner": "Marie Kerner",
"ottokar-kernstock": "Ottokar Kernstock",
"alfred-kerr": "Alfred Kerr",
"carl-von-kessel": "Carl von Kessel",
"harry-kessler": "Harry Kessler",
"ellen-key": "Ellen Key",
"eduard-graf-von-keyserling": "Eduard Graf von Keyserling",
"graf-hermann-keyserling": "Graf Hermann Keyserling",
"alexander-lange-kielland": "Alexander Lange Kielland",
"sren-kierkegaard": "Søren Kierkegaard",
"hans-e-kinck": "Hans E. Kinck",
"johann-friedrich-kind": "(Johann) Friedrich Kind",
"charles-kingsley": "Charles Kingsley",
"gottfried-kinkel": "Gottfried Kinkel",
"johanna-kinkel": "Johanna Kinkel",
"rudyard-kipling": "Rudyard Kipling",
"wolfgang-kirchbach": "Wolfgang Kirchbach",
"paul-kirchberger": "Paul Kirchberger",
"hans-wilhelm-kirchhof": "Hans Wilhelm Kirchhof",
"theodor-kirchhoff": "Theodor Kirchhoff",
"johannes-kirschweng": "Johannes Kirschweng",
"egon-erwin-kisch": "Egon Erwin Kisch",
"hermann-klaatsch": "Hermann Klaatsch",
"theodor-klaiber": "Theodor Klaiber",
"oskar-klaussmann": "Oskar Klaußmann",
"paul-klee": "Paul Klee",
"ernst-klein": "Ernst Klein",
"karl-klein": "Karl Klein",
"johann-kleinfercher": "Johann Kleinfercher",
"heinrich-von-kleist": "Heinrich von Kleist",
"johanna-klemm": "Johanna Klemm",
"hermann-klencke": "Hermann Klencke",
"jochen-klepper": "Jochen Klepper",
"august-klingemann": "August Klingemann",
"friedrich-maximilian-klinger": "Friedrich Maximilian Klinger",
"hans-kloepfer": "Hans Kloepfer",
"walther-kloepffer": "Walther Kloepffer",
"sophie-kloerss": "Sophie Kloerss",
"friedrich-gottlieb-klopstock": "Friedrich Gottlieb Klopstock",
"carl-klostermann": "Carl Klostermann",
"kurt-kluge": "Kurt Kluge",
"heinrich-w-klutschak": "Heinrich W. Klutschak",
"erich-knauf": "Erich Knauf",
"sebastian-kneipp": "Sebastian Kneipp",
"hubert-renfro-knickerbocker": "Hubert Renfro Knickerbocker",
"philipp-kniest": "Philipp Kniest",
"adolph-freiherr-knigge": "Adolph Freiherr Knigge",
"viktor-von-knobelsdorff": "Viktor von Knobelsdorff",
"theodor-von-kobbe": "Theodor von Kobbe",
"franz-ritter-von-kobell": "Franz Ritter von Kobell",
"ernst-koch": "Ernst Koch",
"henny-koch": "Henny Koch",
"oscar-koch": "Oscar Koch",
"louise-koch-schicht": "Louise Koch-Schicht",
"charles-paul-de-kock": "Charles Paul de Kock",
"gustav-koehler": "Gustav Koehler",
"adolf-koelsch": "Adolf Koelsch",
"alma-johanna-koenig": "Alma Johanna Koenig",
"aage-von-kohl": "Aage von Kohl",
"viktor-von-kohlenegg": "Viktor von Kohlenegg",
"ludwig-koehler": "Ludwig Köhler",
"ernst-koehler-haussen": "Ernst Köhler-Haußen",
"robert-kohlrausch": "Robert Kohlrausch",
"joseph-seligmann-kohn": "Joseph Seligmann Kohn",
"leopold-kolbe": "Leopold Kolbe",
"adolf-kolping": "Adolf Kolping",
"leopold-kompert": "Leopold Kompert",
"konfuzius": "Konfuzius",
"bruno-emil-koenig": "Bruno Emil König",
"eberhard-koenig": "Eberhard König",
"heinrich-koenig": "Heinrich König",
"wolfgang-mueller-von-koenigswinter": "Wolfgang Müller von Königswinter",
"marya-konopnicka": "Marya Konopnicka",
"august-kopisch": "August Kopisch",
"rudolf-anastasius-koepke": "Rudolf Anastasius Köpke",
"edlef-koeppen": "Edlef Köppen",
"karl-theodor-koerner": "(Karl) Theodor Körner",
"paul-kornfeld": "Paul Kornfeld",
"wladimir-galaktionovich-korolenko": "Wladimir Galaktionovich Korolenko",
"dr-med-carl-arnold-kortum": "Dr. med. Carl Arnold Kortum",
"gotthard-ludwig-kosegarten": "Gotthard Ludwig Kosegarten",
"karl-ludwig-ernst-kossak": "(Karl Ludwig) Ernst Kossak",
"julius-koestlin": "Julius Köstlin",
"stefan-von-kotze": "Stefan von Kotze",
"august-von-kotzebue": "August von Kotzebue",
"otto-von-kotzebue": "Otto von Kotzebue",
"sofja-wassiljewna-kowalewskaja": "Sofja Wassiljewna Kowalewskaja",
"richard-von-krafft-ebing": "Richard von Krafft-Ebing",
"robert-kraft": "Robert Kraft",
"kraft-buendgens-kaethe": "Käthe Kraft-Bündgens",
"thomas-krag": "Thomas Krag",
"richard-von-kralik": "Richard von Kralik",
"heinrich-kramer": "Heinrich Kramer",
"wilhelm-kranzler": "Wilhelm Kranzler",
"jzef-ignacy-kraszewski": "Józef Ignacy Kraszewski",
"ernst-kratzmann": "Ernst Kratzmann",
"karl-kraus": "Karl Kraus",
"johannes-krause": "Johannes Krause",
"friedrich-solomon-krauss": "Friedrich Solomon Krauss",
"friederike-henriette-kraze": "Friederike Henriette Kraze",
"julius-kreis": "Julius Kreis",
"max-kretzer": "Max Kretzer",
"ferdinand-kringsteiner": "Ferdinand Kringsteiner",
"timm-kroeger": "Timm Kröger",
"christian-krollmann": "Christian Krollmann",
"heinrich-ernst-kromer": "Heinrich Ernst Kromer",
"max-kronberg": "Max Kronberg",
"pjotr-alexejewitsch-kropotkin": "Pjotr Alexejewitsch Kropotkin",
"bartholomaeus-krueger": "Bartholomäus Krüger",
"hermann-anders-krueger": "Hermann Anders Krüger",
"paul-krueger": "Paul Krüger",
"heinrich-kruse": "Heinrich Kruse",
"franz-krutter": "Franz Krutter",
"iwan-andrejewitsch-krylow": "Iwan Andrejewitsch Krylow",
"otfried-krzyzanowski": "Otfried Krzyzanowski",
"rudolf-kubitschek": "Rudolf Kubitschek",
"kurt-kuechler": "Kurt Küchler",
"franz-kuenlin": "Franz Kuenlin",
"wilhelm-von-kuegelgen": "Wilhelm von Kügelgen",
"franz-kugler": "Franz Kugler",
"anton-kuh": "Anton Kuh",
"ludwig-kuhlenbeck": "Ludwig Kuhlenbeck",
"gottlieb-jakob-kuhn": "Gottlieb Jakob Kuhn",
"gisela-kuehn": "Gisela Kühn",
"ferdinand-gustav-kuehne": "Ferdinand Gustav Kühne",
"richard-kuehnelt": "Richard Kühnelt",
"heinz-kuekelhaus": "Heinz Kükelhaus",
"luise-adelgunde-victorie-gottsched-geb-kulmus": "Luise Adelgunde Victorie Gottsched geb. Kulmus",
"frances-kuelpe": "Frances Külpe",
"ludwig-kuelz": "Ludwig Külz",
"johann-kuenzle": "Johann Künzle",
"ferdinand-kuernberger": "Ferdinand Kürnberger",
"hermann-kurz": "Hermann Kurz",
"isolde-kurz": "Isolde Kurz",
"michail-kusmin": "Michail Kusmin",
"adolf-kussmaul": "Adolf Kussmaul",
"manfred-kyber": "Manfred Kyber",
"hedwig-kym": "Hedwig Kym",
"k-labacher": "K. Labacher",
"louze-labe": "Louïze Labé",
"hedwig-lachmann": "Hedwig Lachmann",
"volkmar-lachmann": "Volkmar Lachmann",
"pierre-ambroise-francois-choderlos-de-laclos": "Pierre-Ambroise-François Choderlos de Laclos",
"paul-lafargue": "Paul Lafargue",
"august-lafontaine": "August Lafontaine",
"paul-de-lagarde": "Paul de Lagarde",
"selma-lagerloef": "Selma Lagerlöf",
"angelika-von-lagerstroem": "Angelika von Lagerström",
"alphonse-de-prat-lamartine": "Alphonse de Prat Lamartine",
"nanny-lambrecht": "Nanny Lambrecht",
"friedo-lampe": "Friedo Lampe",
"jakob-friedrich-lamprecht": "Jakob Friedrich Lamprecht",
"gustav-landauer": "Gustav Landauer",
"walter-savage-landor": "Walter Savage Landor",
"hans-landsberg": "Hans Landsberg",
"artur-landsberger": "Artur Landsberger",
"karl-heinrich-von-lang": "Karl Heinrich von Lang",
"willy-lang": "Willy Lang",
"julius-langbehn": "Julius Langbehn",
"august-friedrich-ernst-langbein": "August Friedrich Ernst Langbein",
"friedrich-albert-lange": "Friedrich Albert Lange",
"helene-lange": "Helene Lange",
"sven-lange": "Sven Lange",
"paul-langenscheidt": "Paul Langenscheidt",
"adam-langer": "Adam Langer",
"wilhelm-langewiesche": "Wilhelm Langewiesche",
"elisabeth-langgaesser": "Elisabeth Langgässer",
"georg-heinrich-freiherr-von-langsdorff": "Georg Heinrich Freiherr von Langsdorff",
"laotse": "Laotse",
"georg-michael-frank-von-laroche": "Georg Michael Frank von LaRoche",
"else-lasker-schueler": "Else Lasker-Schüler",
"ferdinand-lassalle": "Ferdinand Lassalle",
"kurd-lasswitz": "Kurd Laßwitz",
"andreas-latzko": "Andreas Latzko",
"heinrich-laube": "Heinrich Laube",
"joseph-von-lauff": "Joseph von Lauff",
"otto-lauffer": "Otto Lauffer",
"friedrich-christian-laukhard": "Friedrich Christian Laukhard",
"heinrich-lautensack": "Heinrich Lautensack",
"johann-caspar-lavater": "Johann Caspar Lavater",
"d-h-lawrence": "D. H. Lawrence",
"john-lawrence": "John Lawrence",
"thomas-edward-lawrence": "Thomas Edward Lawrence",
"louis-lax": "Louis Lax",
"maria-lazar": "Maria Lazar",
"charles-webster-leadbeater": "Charles Webster Leadbeater",
"maurice-leblanc": "Maurice Leblanc",
"cornelie-lechler": "Cornelie Lechler",
"anne-charlotte-leffler": "Anne Charlotte Leffler",
"hans-henrik-lefolii": "Hans Henrik Lefolii",
"lilli-lehmann": "Lilli Lehmann",
"emmy-lehr-prey": "Emmy Lehr-Prey",
"gottfried-wilhelm-freiherr-von-leibniz": "Gottfried Wilhelm Freiherr von Leibniz",
"georg-leichner": "Georg Leichner",
"hugo-leichtentritt": "Hugo Leichtentritt",
"hans-leifhelm": "Hans Leifhelm",
"leon-leipziger": "Leo(n) Leipziger",
"johann-anton-leisewitz": "Johann Anton Leisewitz",
"josef-leitgeb": "Josef Leitgeb",
"maria-leitner": "Maria Leitner",
"otto-von-leixner": "Otto von Leixner",
"eugene-lemercier": "Eugène Lemercier",
"camille-lemonnier": "Camille Lemonnier",
"nikolaus-lenau": "Nikolaus Lenau",
"ninon-de-lenclos": "Ninon de Lenclos",
"lenin": "Lenin",
"jakob-michael-reinhold-lenz": "Jakob Michael Reinhold Lenz",
"giacomo-leopardi": "Giacomo Leopardi",
"edmond-lepelletier": "Edmond Lepelletier",
"paul-leppin": "Paul Leppin",
"johannes-lepsius": "Johannes Lepsius",
"karl-lerbs": "Karl Lerbs",
"hanns-lerch": "Hanns Lerch",
"jules-lermina": "Jules Lermina",
"michael-lermontoff": "Michael Lermontoff",
"heinrich-lersch": "Heinrich Lersch",
"alain-lesage": "Alain Lesage",
"longos-von-lesbos": "Longos von Lesbos",
"catherine-lescombat": "Catherine Lescombat",
"julie-de-lespinasse": "Julie de Lespinasse",
"gotthold-ephraim-lessing": "Gotthold Ephraim Lessing",
"theodor-lessing": "Theodor Lessing",
"gustav-leutelt": "Gustav Leutelt",
"heinrich-leuthold": "Heinrich Leuthold",
"maurice-level": "Maurice Level",
"oskar-levertin": "Oskar Levertin",
"oswald-levett": "Oswald Levett",
"giuseppe-levi": "Giuseppe Levi",
"paul-levin": "Paul Levin",
"fanny-lewald": "Fanny Lewald",
"george-henry-lewes": "George Henry Lewes",
"sinclair-lewis": "Sinclair Lewis",
"ludwig-lewisohn": "Ludwig Lewisohn",
"heinrich-lhotzky": "Heinrich Lhotzky",
"georg-christoph-lichtenberg": "Georg Christoph Lichtenberg",
"andre-lichtenberger": "André Lichtenberger",
"alfred-lichtenstein": "Alfred Lichtenstein",
"ulrich-von-lichtenstein": "Ulrich von Lichtenstein",
"alfred-lichtwark": "Alfred Lichtwark",
"magnus-gottfried-lichtwer": "Magnus Gottfried Lichtwer",
"bernt-lie": "Bernt Lie",
"jonas-lie": "Jonas Lie",
"max-liebermann": "Max Liebermann",
"wilhelm-liebknecht": "Wilhelm Liebknecht",
"severin-lieblein": "Severin Lieblein",
"hans-liebstoeckl": "Hans Liebstöckl",
"meinrad-lienert": "Meinrad Lienert",
"friedrich-lienhard": "Friedrich Lienhard",
"adda-freifrau-von-liliencron": "Adda Freifrau von Liliencron",
"detlev-freiherr-von-liliencron": "Detlev Freiherr von Liliencron",
"heinrich-lilienfein": "Heinrich Lilienfein",
"natalie-s-lincoln": "Natalie S. Lincoln",
"paul-lindau": "Paul Lindau",
"rudolf-lindau": "Rudolf Lindau",
"otto-zur-linde": "Otto zur Linde",
"e-lindemann": "E. Lindemann",
"maurus-lindemayr": "Maurus Lindemayr",
"heinrich-lindenau": "Heinrich Lindenau",
"michael-lindener": "Michael Lindener",
"hermann-von-lingg": "Hermann von Lingg",
"simon-nicolas-henri-linguet": "Simon Nicolas Henri Linguet",
"johannes-linnankoski": "Johannes Linnankoski",
"julius-ernst-lips": "Julius Ernst Lips",
"maria-lipsius": "Maria Lipsius",
"auguste-de-villiers-de-lisle-adam": "Auguste de Villiers de L’Isle-Adam",
"irmgard-litten": "Irmgard Litten",
"r-litten": "R. Litten",
"titus-livius": "Titus Livius",
"nikolai-semjonowitsch-ljesskow": "Nikolai Semjonowitsch Ljesskow",
"john-locke": "John Locke",
"william-john-locke": "William John Locke",
"oskar-loerke": "Oskar Loerke",
"leopold-loewenfeld": "Leopold Loewenfeld",
"friedrich-von-logau": "Friedrich von Logau",
"daniel-casper-von-lohenstein": "Daniel Casper von Lohenstein",
"franz-von-loeher": "Franz von Löher",
"anna-loehn": "Anna Löhn",
"cesare-lombroso": "Cesare Lombroso",
"jack-london": "Jack London",
"henry-wadsworth-longfellow": "Henry Wadsworth Longfellow",
"elias-loennrot": "Elias Lönnrot",
"hermann-loens": "Hermann Löns",
"adolf-loos": "Adolf Loos",
"jakob-lorber": "Jakob Lorber",
"rudolf-von-lossow": "Rudolf von Lossow",
"pierre-loti": "Pierre Loti",
"ernst-wilhelm-lotz": "Ernst Wilhelm Lotz",
"rudolf-hermann-lotze": "Rudolf Hermann Lotze",
"louis-de-rouvroy-duc-de-saint-simon": "Louis de Rouvroy, duc de Saint-Simon",
"jean-baptiste-louvet": "Jean-Baptiste Louvet",
"pierre-lous": "Pierre Louÿs",
"johann-friedrich-loewen": "Johann Friedrich Löwen",
"oscar-friedrich-luchner": "Oscar Friedrich Luchner",
"emil-lucka": "Emil Lucka",
"georg-paul-luecke": "Georg Paul Lücke",
"maria-ludolfs": "Maria Ludolfs",
"emil-ludwig": "Emil Ludwig",
"emilie-ludwig": "Emilie Ludwig",
"otto-ludwig": "Otto Ludwig",
"martin-luther": "Martin Luther",
"joseph-august-lux": "Joseph August Lux",
"rosa-luxemburg": "Rosa Luxemburg",
"lawrence-l-lynch": "Lawrence L. Lynch",
"gordon-maccreagh": "Gordon Maccreagh",
"ernst-mach": "Ernst Mach",
"niccol-machiavelli": "Niccolò Machiavelli",
"john-henry-mackay": "John Henry Mackay",
"marie-madeleine-1": "Marie Madeleine",
"aage-madelung": "Aage Madelung",
"friedrich-wilhelm-mader": "Friedrich Wilhelm Mader",
"maurice-maeterlinck": "Maurice Maeterlinck",
"erwin-magnus": "Erwin Magnus",
"august-mahlmann": "August Mahlmann",
"stephane-mallarme": "Stéphane Mallarmé",
"mathilde-malling": "Mathilde Malling",
"hector-malot": "Hector Malot",
"karl-balthasar-malss": "Karl Balthasar Malß",
"elisabeth-von-maltzahn": "Elisabeth von Maltzahn",
"heinrich-von-maltzan": "Heinrich von Maltzan",
"marie-mancke": "Marie Mancke",
"bernard-mandeville": "Bernard Mandeville",
"franziska-mann": "Franziska Mann",
"heinrich-mann": "Heinrich Mann",
"klaus-heinrich-thomas-mann": "Klaus Heinrich Thomas Mann",
"thomas-mann": "Thomas Mann",
"viktor-mann": "Viktor Mann",
"paolo-mantegazza": "Paolo Mantegazza",
"hans-rudolf-manuel": "Hans Rudolf Manuel",
"niklaus-manuel": "Niklaus Manuel",
"gustav-manz": "Gustav Manz",
"alessandro-manzoni": "Alessandro Manzoni",
"hermann-marggraff": "Hermann Marggraff",
"paul-margot": "Paul Margot",
"paul-margueritte-2": "Paul Margueritte",
"paul-margueritte": "Paul Margueritte",
"victor-margueritte": "Victor Margueritte",
"maria-theresia-von-oesterreich": "Maria Theresia von Österreich",
"marie-de-rabutin-chantal-marquise-de-sevigne": "Marie de Rabutin-Chantal, Marquise de Sévigné",
"karl-edler-von-marinelli": "Karl Edler von Marinelli",
"eugenie-marlitt": "Eugenie Marlitt",
"jeanne-marni": "Jeanne Marni",
"florence-marryat": "Florence Marryat",
"frederick-marryat": "Frederick Marryat",
"emma-marshall": "Emma Marshall",
"kurt-martens": "Kurt Martens",
"hugo-marti": "Hugo Marti",
"karl-marx": "Karl Marx",
"arnold-masarey": "Arnold Masarey",
"tom-garrigue-masaryk": "Tomáš Garrigue Masaryk",
"hermann-masius": "Hermann Masius",
"walter-s-masterman": "Walter S. Masterman",
"paul-de-mathies": "Paul de Mathies",
"maximilian-maulbecker": "Maximilian Maulbecker",
"guy-de-maupassant": "Guy de Maupassant",
"august-maurer": "August Maurer",
"martin-maurice": "Martin Maurice",
"george-du-maurier": "George du Maurier",
"fritz-mauthner": "Fritz Mauthner",
"maximilian-schmidt-gen-waldschmidt": "Maximilian Schmidt, genannt Waldschmidt",
"e-j-may": "E. J. May",
"karl-may": "Karl May",
"sophia-may": "Sophia May",
"erich-august-mayer": "Erich August Mayer",
"wilhelm-mayer": "Wilhelm Mayer",
"edouard-maynial": "Edouard Maynial",
"rosa-mayreder": "Rosa Mayreder",
"justin-huntly-mccarthy": "Justin Huntly McCarthy",
"herman-cyril-mcneile": "Herman Cyril McNeile",
"oskar-meding": "Oskar Meding",
"johann-richard-zur-megede": "Johann Richard zur Megede",
"franz-mehring": "Franz Mehring",
"emerenz-meier": "Emerenz Meier",
"johann-wilhelm-meinhold": "(Johann) Wilhelm Meinhold",
"grete-meisel-hess": "Grete Meisel-Hess",
"heinrich-meisner": "Heinrich Meisner",
"alfred-meissner": "Alfred Meißner",
"august-gottlieb-meissner": "August Gottlieb Meißner",
"friedrich-meister": "Friedrich Meister",
"philipp-melanchthon": "Philipp Melanchthon",
"herman-melville": "Herman Melville",
"moses-mendelssohn": "Moses Mendelssohn",
"catulle-mendes": "Catulle Mendès",
"johann-mentzer": "Johann Mentzer",
"george-meredith": "George Meredith",
"dmitri-sergejewitsch-mereschkowski": "Dmitri Sergejewitsch Mereschkowski",
"matthaeus-merian": "Matthaeus Merian",
"prosper-merimee": "Prosper Mérimée",
"emma-merk": "Emma Merk",
"ludwig-von-mertens": "Ludwig von Mertens",
"samuel-merwin": "Samuel Merwin",
"max-messer": "Max Messer",
"therese-messerer": "Therese Messerer",
"josef-messner": "Josef Meßner",
"paul-messner": "Paul Meßner",
"julien-offray-de-la-mettrie": "Julien Offray de La Mettrie",
"stanislas-meunier": "Stanislas Meunier",
"conrad-ferdinand-meyer": "Conrad Ferdinand Meyer",
"johann-meyer": "Johann Meyer",
"johann-rudolf-meyer": "Johann Rudolf Meyer",
"max-wilhelm-meyer": "Max Wilhelm Meyer",
"wilhelm-meyer-1": "Wilhelm Meyer",
"wilhelm-meyer-foerster": "Wilhelm Meyer-Förster",
"erna-meyer-koenig": "Erna Meyer-Koenig",
"hans-meyer-krafft": "Hans Meyer-Krafft",
"theodor-meyer-merian": "Theodor Meyer-Merian",
"melchior-meyr": "Melchior Meyr",
"gustav-meyrink": "Gustav Meyrink",
"malwida-von-meysenbug": "Malwida von Meysenbug",
"karin-michalis": "Karin Michaëlis",
"margarete-michaelson": "Margarete Michaelson",
"michelangelo": "Michelangelo",
"jules-michelet": "Jules Michelet",
"adam-mickiewicz": "Adam Mickiewicz",
"jakob-micko": "Jakob Micko",
"otto-mielke": "Otto Mielke",
"klmn-mikszth": "Kálmán Mikszáth",
"w-mikulitsch": "W. Mikulitsch",
"werner-milch": "Werner Milch",
"john-stuart-mill": "John Stuart Mill",
"pierre-mille": "Pierre Mille",
"max-von-millenkovich": "Max von Millenkovich",
"stephan-von-millenkovich": "Stephan von Millenkovich",
"elisabeth-york-miller": "Elisabeth York Miller",
"john-milton": "John Milton",
"margarethe-miltschinsky": "Margarethe Miltschinsky",
"octave-mirbeau": "Octave Mirbeau",
"frederic-mistral": "Frédéric Mistral",
"edmund-mitchell": "Edmund Mitchell",
"paul-julius-moebius": "Paul Julius Möbius",
"paula-modersohn-becker": "Paula Modersohn-Becker",
"prophet-mohammed": "Prophet Mohammed",
"adrian-mohr": "Adrian Mohr",
"max-mohr": "Max Mohr",
"moliere": "Molière",
"tirso-de-molina": "Tirso de Molina",
"balduin-moellhausen": "Balduin Möllhausen",
"j-fitzgerald-molloy": "J. Fitzgerald Molloy",
"ferenc-molnr": "Ferenc Molnár",
"helmuth-karl-bernhard-von-moltke": "Helmuth Karl Bernhard von Moltke",
"alfred-mombert": "Alfred Mombert",
"theodor-mommsen": "Theodor Mommsen",
"michel-de-montaigne": "Michel de Montaigne",
"martin-montanus": "Martin Montanus",
"montesquieu": "Montesquieu",
"malla-montgomery-silfverstolpe": "Malla Montgomery-Silfverstolpe",
"george-moore": "George Moore",
"thomas-moore": "Thomas Moore",
"baltasar-gracin-y-morales": "Baltasar Gracián y Morales",
"christian-morgenstern": "Christian Morgenstern",
"hans-morgenthaler": "Hans Morgenthaler",
"james-morier": "James Morier",
"eduard-moerike": "Eduard Mörike",
"karl-philipp-moritz": "Karl Philipp Moritz",
"arthur-morrison": "Arthur Morrison",
"thomas-morus": "Thomas Morus",
"johann-hans-michael-moscherosch": "[Johann] Hans Michael Moscherosch",
"julius-mosen": "Julius Mosen",
"salomon-hermann-ritter-von-mosenthal": "Salomon Hermann Ritter von Mosenthal",
"ernst-moser": "Ernst Moser",
"justus-moeser": "Justus Möser",
"alexander-moszkowski": "Alexander Moszkowski",
"francois-de-salignac-de-la-mothe-fenelon": "François de Salignac de La Mothe-Fénelon",
"wolfgang-amadeus-mozart": "Wolfgang Amadeus Mozart",
"ernst-muellenbach": "Ernst Muellenbach",
"theodor-muegge": "Theodor Mügge",
"helene-von-muehlau": "Helene von Mühlau",
"luise-muehlbach": "Luise Mühlbach",
"erich-muehsam": "Erich Mühsam",
"dhan-gopal-mukerdschi": "Dhan Gopal Mukerdschi",
"prentice-mulford": "Prentice Mulford",
"karl-muellenhoff": "Karl Müllenhoff",
"adam-heinrich-mueller": "Adam Heinrich Müller",
"carl-mueller": "Carl Müller",
"heinrich-august-mueller": "Heinrich August Müller",
"johann-gottwerth-mueller": "Johann Gottwerth Müller",
"johann-ludwig-wilhelm-mueller": "(Johann Ludwig) Wilhelm Müller",
"robert-mueller": "Robert Müller",
"adam-mueller-guttenbrunn": "Adam Müller-Guttenbrunn",
"clara-mueller-jahnke": "Clara Müller-Jahnke",
"fritz-mueller-partenkirchen": "Fritz Müller-Partenkirchen",
"hans-multerer": "Hans Multerer",
"theodor-mundt": "Theodor Mundt",
"oskar-muensterberg": "Oskar Münsterberg",
"henri-murger": "Henri Murger",
"david-christie-murray": "David Christie Murray",
"johann-karl-august-musaeus": "Johann Karl August Musäus",
"robert-musil": "Robert Musil",
"alfred-de-musset": "Alfred de Musset",
"albert-carl-richard-muther": "Albert Carl Richard Muther",
"adolf-muetzelburg": "Adolf Mützelburg",
"carl-muusmann": "Carl Muusmann",
"gustav-nachtigal": "Gustav Nachtigal",
"fritjof-nansen": "Fritjof Nansen",
"peter-nansen": "Peter Nansen",
"iwan-naschiwin": "Iwan Naschiwin",
"marie-nathusius": "Marie Nathusius",
"paul-natorp": "Paul Natorp",
"christiane-benedikte-naubert": "Christiane Benedikte Naubert",
"friedrich-naumann": "Friedrich Naumann",
"margarete-von-navarra": "Margarete von Navarra",
"joachim-neander": "Joachim Neander",
"scheik-nefzaui": "Scheik Nefzaui",
"ada-negri": "Ada Negri",
"gerard-de-nerval": "Gérard de Nerval",
"e-von-nesselrot": "E. von Nesselrot",
"johann-nestroy": "Johann Nestroy",
"joachim-nettelbeck": "Joachim Nettelbeck",
"max-nettlau": "Max Nettlau",
"paul-neubauer": "Paul Neubauer",
"alfred-neumann": "Alfred Neumann",
"carl-wilhelm-neumann": "Carl Wilhelm Neumann",
"johann-philipp-neumann": "Johann Philipp Neumann",
"karl-eugen-neumann": "Karl Eugen Neumann",
"georg-von-neumayer": "Georg von Neumayer",
"friedrich-neumeyer": "Friedrich Neumeyer",
"martin-andersen-nexoe": "Martin Andersen Nexö",
"christoph-friedrich-nicolai": "(Christoph) Friedrich Nicolai",
"philipp-nicolai": "Philipp Nicolai",
"ernst-elias-niebergall": "Ernst Elias Niebergall",
"felix-niedner": "Felix Niedner",
"zakarias-nielsen": "Zakarias Nielsen",
"august-wilhelm-otto-niemann": "August Wilhelm Otto Niemann",
"charlotte-niese": "Charlotte Niese",
"hermann-niess": "Hermann Nieß",
"frieda-nietlispach": "Frieda Nietlispach",
"hermann-nietschmann": "Hermann Nietschmann",
"friedrich-wilhelm-nietzsche": "Friedrich Wilhelm Nietzsche",
"florence-nightingale": "Florence Nightingale",
"walther-nithack-stahn": "Walther Nithack-Stahn",
"charles-nodier": "Charles Nodier",
"ludwig-nohl": "Ludwig Nohl",
"max-nordau": "Max Nordau",
"otto-nordenskjoeld": "Otto Nordenskjöld",
"richard-nordhausen": "Richard Nordhausen",
"charles-bernhard-nordhoff": "Charles Bernhard Nordhoff",
"suzanne-normand": "Suzanne Normand",
"frank-norris": "Frank Norris",
"william-edward-norris": "William Edward Norris",
"helene-nostitz": "Helene Nostitz",
"novalis": "Novalis",
"karl-friedrich-nowak": "Karl Friedrich Nowak",
"woldemar-nuernberger": "Woldemar Nürnberger",
"marie-oberparleiter": "Marie Oberparleiter",
"arthur-obst": "Arthur Obst",
"adam-gottlob-oehlenschlaeger": "Adam Gottlob Oehlenschläger",
"margarete-von-oertzen": "Margarete von Oertzen",
"hermann-oeser": "Hermann Oeser",
"august-oetker": "August Oetker",
"nikolai-ognjew": "Nikolai Ognjew",
"georges-ohnet": "Georges Ohnet",
"anton-ohorn": "Anton Ohorn",
"erich-ohser": "Erich Ohser",
"kakuzo-okakura": "Kakuzo Okakura",
"ivan-olbracht": "Ivan Olbracht",
"balder-olden": "Balder Olden",
"marie-von-olfers": "Marie von Olfers",
"margaret-oliphant": "Margaret Oliphant",
"alfred-ollivant": "Alfred Ollivant",
"hermine-olten": "Hermine Olten",
"georg-freiherr-von-ompteda": "Georg Freiherr von Ompteda",
"eugene-oneill": "Eugene O’Neill",
"sophia-henritte-kautzmann-van-oosterzee": "Sophia Henriëtte Kautzmann-van Oosterzee",
"martin-opitz": "Martin Opitz",
"friedrich-von-oppeln-bronikowski": "Friedrich von Oppeln-Bronikowski",
"edward-phillips-oppenheim": "Edward Phillips Oppenheim",
"heinrich-albert-oppermann": "Heinrich Albert Oppermann",
"elisabeth-charlotte-von-orleans": "Elisabeth Charlotte von Orléans",
"fuerst-nikolai-orloff": "Fürst Nikolai Orloff",
"reinhold-ortmann": "Reinhold Ortmann",
"eliza-orzeszkowa": "Eliza Orzeszkowa",
"ferdinand-ossendowski": "Ferdinand Ossendowski",
"carl-von-ossietzky": "Carl von Ossietzky",
"hans-ostwald": "Hans Ostwald",
"wilhelm-ostwald": "Wilhelm Ostwald",
"friedrich-otten": "Friedrich Otten",
"victor-ottmann": "Victor Ottmann",
"victor-ottmann-2": "Victor Ottmann",
"rodrigues-ottolengui": "Rodrigues Ottolengui",
"ernst-ottwalt": "Ernst Ottwalt",
"ovid": "Ovid",
"henriette-paalzow": "Henriette Paalzow",
"hans-paasche": "Hans Paasche",
"herbert-paatz": "Herbert Paatz",
"johann-gottfried-pahl": "Johann Gottfried Pahl",
"friedrich-joachim-pajeken": "Friedrich Joachim Pajeken",
"leopold-hermann-oskar-panizza": "(Leopold Hermann) Oskar Panizza",
"max-pannwitz": "Max Pannwitz",
"theodor-hermann-pantenius": "Theodor Hermann Pantenius",
"betty-paoli": "Betty Paoli",
"kaethe-papke": "Käthe Papke",
"bertha-pappenheim": "Bertha Pappenheim",
"alfons-paquet": "Alfons Paquet",
"joseph-paquet": "Joseph Paquet",
"blaise-pascal": "Blaise Pascal",
"willy-pastor": "Willy Pastor",
"rpd-psztor": "Árpád Pásztor",
"walter-pater": "Walter Pater",
"adolf-paul": "Adolf Paul",
"hermann-paul": "Hermann Paul",
"jean-paul": "Jean Paul",
"gustav-pauli": "Gustav Pauli",
"karl-pauli": "Karl Pauli",
"eduard-paulus": "Eduard Paulus",
"julius-payer": "Julius Payer",
"james-payn": "James Payn",
"robert-edwin-peary": "Robert Edwin Peary",
"felix-peipers": "Felix Peipers",
"josephin-peladan": "Joséphin Péladan",
"silvio-pellico": "Silvio Pellico",
"ernst-penzoldt": "Ernst Penzoldt",
"anton-von-perfall": "Anton von Perfall",
"karl-von-perfall": "Karl von Perfall",
"fritz-geron-pernauhm": "Fritz Geron Pernauhm",
"charles-perrault": "Charles Perrault",
"johann-heinrich-pestalozzi": "Johann Heinrich Pestalozzi",
"johann-peter-1": "Johann Peter",
"august-peters": "August Peters",
"nis-petersen": "Nis Petersen",
"sndor-petoefi": "Sándor Petöfi",
"titus-petronius": "Titus Petronius",
"eveline-petrovits": "Eveline Petrovits",
"alfons-petzold": "Alfons Petzold",
"paul-peuker": "Paul Peuker",
"julie-pfannenschmidt-burow": "Julie Pfannenschmidt-Burow",
"gottlieb-konrad-pfeffel": "Gottlieb Konrad Pfeffel",
"georg-wilhelm-pfeiffer": "Georg Wilhelm Pfeiffer",
"ida-pfeiffer": "Ida Pfeiffer",
"ludwig-pfister": "Ludwig Pfister",
"artur-jost-pfleghar": "Artur Jost Pfleghar",
"charles-louis-philippe": "Charles Louis Philippe",
"felix-philippi": "Felix Philippi",
"francis-charles-philips": "Francis Charles Philips",
"alessandro-piccolomini": "Alessandro Piccolomini",
"adolf-pichler": "Adolf Pichler",
"karoline-pierson": "Karoline Pierson",
"hermann-pies": "Hermann Pies",
"traugott-pilf": "Traugott Pilf",
"luigi-pirandello": "Luigi Pirandello",
"siegfried-placzek": "Siegfried Placzek",
"max-planck": "Max Planck",
"august-von-platen": "August von Platen",
"jeanne-marie-roland-de-la-platiere": "Jeanne-Marie Roland de La Platière",
"platon": "Platon",
"titus-maccius-plautus": "Titus Maccius Plautus",
"auguste-plehn": "Auguste Plehn",
"theodor-plievier": "Theodor Plievier",
"gunther-plueschow": "Gunther Plüschow",
"franz-graf-von-pocci": "Franz Graf von Pocci",
"edgar-allan-poe": "Edgar Allan Poe",
"wilhelm-poeck": "Wilhelm Poeck",
"eduard-poeppig": "Eduard Poeppig",
"henri-poincare": "Henri Poincaré",
"wilhelm-von-polenz": "Wilhelm von Polenz",
"alfred-polgar": "Alfred Polgar",
"elise-polko": "Elise Polko",
"anna-graefin-pongrcz": "Anna Gräfin Pongrácz",
"lorenzo-da-ponte": "Lorenzo Da Ponte",
"josef-ponten": "Josef Ponten",
"henrik-pontoppidan": "Henrik Pontoppidan",
"alexander-pope": "Alexander Pope",
"felix-poppenberg": "Felix Poppenberg",
"marguerite-poradowska": "Marguerite Poradowska",
"jakob-elias-poritzky": "Jakob Elias Poritzky",
"luigi-da-porto": "Luigi da Porto",
"eduard-poetzl": "Eduard Pötzl",
"johannes-praetorius": "Johannes Praetorius",
"josef-praxmarer": "Josef Praxmarer",
"ernst-preczang": "Ernst Preczang",
"ludwig-preller": "Ludwig Preller",
"gertrud-prellwitz": "Gertrud Prellwitz",
"max-prels": "Max Prels",
"paula-von-preradovi": "Paula von Preradović",
"hermann-otto-rudolf-presber": "(Hermann Otto) Rudolf Presber",
"hermione-von-preuschen": "Hermione von Preuschen",
"friedrich-ii-von-preussen": "Friedrich II. von Preußen",
"wilhelm-von-preussen": "Wilhelm von Preußen",
"marcel-prevost": "Marcel Prévost",
"antoine-francois-prevost-dexiles-abbe-prevost": "Antoine François Prévost d’Exiles (Abbé Prévost)",
"william-preyer": "William Preyer",
"fred-w-primer": "Fred. W. Primer",
"dumas-le-prince": "Dumas-Le Prince",
"hans-prinzhorn": "Hans Prinzhorn",
"michail-prischwin": "Michail Prischwin",
"johannes-proelss": "Johannes Proelß",
"hedwig-prohl": "Hedwig Prohl",
"heinrich-proehle": "Heinrich Pröhle",
"properz-sextus-aurelius-propertius": "Properz (Sextus Aurelius Propertius)",
"peter-prosch": "Peter Prosch",
"marcel-proust": "Marcel Proust",
"robert-eduard-prutz": "Robert Eduard Prutz",
"kazimierz-przerwa-tetmajer": "Kazimierz Przerwa-Tetmajer",
"stanislaw-przybyszewski": "Stanislaw Przybyszewski",
"hermann-von-pueckler-muskau": "Hermann von Pückler-Muskau",
"max-pulver": "Max Pulver",
"alexander-sergejewitsch-puschkin": "Alexander Sergejewitsch Puschkin",
"gustav-heinrich-gans-zu-putlitz": "Gustav Heinrich Gans zu Putlitz",
"eugen-de-putti": "Eugen de Putti",
"alberta-von-puttkamer": "Alberta von Puttkamer",
"friedrich-heinz-putz": "Friedrich Heinz Putz",
"johann-ladislaus-pyrker": "(Johann) Ladislaus Pyrker",
"jose-maria-eca-de-queiroz": "José Maria Eça de Queiroz",
"georg-queri": "Georg Queri",
"william-le-queux": "William Le Queux",
"don-francisco-gomez-de-quevedo": "Don Francisco Gomez de Quevedo",
"ludwig-quidde": "Ludwig Quidde",
"thomas-de-quincey": "Thomas de Quincey",
"wilhelm-raabe": "Wilhelm Raabe",
"francois-rabelais": "François Rabelais",
"fr-rabener": "Fr. Rabener",
"gottlieb-wilhelm-rabener": "Gottlieb Wilhelm Rabener",
"a-s-rabinowicz": "A. S. Rabinowicz",
"jean-racine": "Jean Racine",
"gustav-radbruch": "Gustav Radbruch",
"ann-radcliffe": "Ann Radcliffe",
"karl-radek": "Karl Radek",
"ferdinand-raimund": "Ferdinand Raimund",
"johann-jacob-rambach": "Johann Jacob Rambach",
"johann-heinrich-ramberg": "Johann Heinrich Ramberg",
"josef-rank": "Josef Rank",
"friedrich-ranke": "Friedrich Ranke",
"leopold-von-ranke": "Leopold von Ranke",
"gerard-ras": "Gerard Ras",
"knud-rasmussen": "Knud Rasmussen",
"e-g-rassow": "E. G. Rassow",
"max-rathcke": "Max Rathcke",
"walther-rathenau": "Walther Rathenau",
"friedrich-ratzel": "Friedrich Ratzel",
"friedrich-ludwig-georg-von-raumer": "Friedrich Ludwig Georg von Raumer",
"ernst-benjamin-salomo-raupach": "Ernst Benjamin Salomo Raupach",
"ernst-rauscher": "Ernst Rauscher",
"felix-ravaisson": "Felix Ravaisson",
"paul-rebhun-rebhuhn": "Paul Rebhun (Rebhuhn)",
"georg-friedrich-rebmann": "Georg Friedrich Rebmann",
"elisa-von-der-recke": "Elisa von der Recke",
"fritz-reck-mallaczewen": "Fritz Reck-Mallaczewen",
"oscar-von-redwitz": "Oscar von Redwitz",
"henri-de-regnier": "Henri de Régnier",
"franz-rehbein": "Franz Rehbein",
"rudolf-reichenau": "Rudolf Reichenau",
"julius-reiner": "Julius Reiner",
"carl-reinhardt": "Carl Reinhardt",
"luise-reinhardt": "Luise Reinhardt",
"e-w-a-reinhart": "E. W. A. Reinhart",
"robert-reinick": "Robert Reinick",
"hans-reiser": "Hans Reiser",
"theodor-reismann-grone": "Theodor Reismann-Grone",
"larissa-reissner": "Larissa Reissner",
"johann-jakob-reithard": "Johann Jakob Reithard",
"robert-reitzel": "Robert Reitzel",
"hans-joachim-von-reitzenstein": "Hans Joachim von Reitzenstein",
"heinrich-friedrich-ludwig-rellstab": "(Heinrich Friedrich) Ludwig Rellstab",
"ernest-renan": "Ernest Renan",
"maurice-renard": "Maurice Renard",
"carl-ressner": "Carl Reßner",
"carlot-gottfrid-reuling": "Carlot Gottfrid Reuling",
"rudolf-reusch": "Rudolf Reusch",
"christian-reuter": "Christian Reuter",
"gabriele-reuter": "Gabriele Reuter",
"heinrich-ludwig-christian-fritz-reuter": "(Heinrich Ludwig Christian) Fritz Reuter",
"hugo-alphonso-revel": "Hugo Alphonso Revel",
"franziska-zu-reventlow": "Franziska zu Reventlow",
"michael-revon": "Michael Revon",
"wadysaw-stanisaw-reymont": "Władysław Stanisław Reymont",
"walter-rheiner": "Walter Rheiner",
"emil-alphons-rheinhardt": "Emil Alphons Rheinhardt",
"emmy-von-rhoden": "Emmy von Rhoden",
"otto-henne-am-rhyn": "Otto Henne am Rhyn",
"carl-theodor-ritter-von-riba": "Carl Theodor Ritter von Riba",
"fritz-richter": "Fritz Richter",
"hans-richter": "Hans Richter",
"joseph-richter": "Joseph Richter",
"ludwig-richter": "Ludwig Richter",
"max-richter": "Max Richter",
"otto-richter": "Otto Richter",
"manfred-von-richthofen": "Manfred von Richthofen",
"therese-rie": "Therese Rie",
"louis-riedel": "Louis Riedel",
"wilhelm-heinrich-von-riehl": "Wilhelm Heinrich von Riehl",
"c-e-ries": "C. E. Ries",
"johann-kaspar-riesbeck": "Johann Kaspar Riesbeck",
"friedrich-wilhelm-riese": "Friedrich Wilhelm Riese",
"rainer-maria-rilke": "Rainer Maria Rilke",
"mary-roberts-rinehart": "Mary Roberts Rinehart",
"barbara-ring": "Barbara Ring",
"max-ring": "Max Ring",
"joachim-ringelnatz": "Joachim Ringelnatz",
"friedrich-rinne": "Friedrich Rinne",
"johann-rist": "Johann Rist",
"jean-qui-rit": "Jean Qui Rit",
"johann-wilhelm-ritter": "Johann Wilhelm Ritter",
"charles-g-d-roberts": "Charles G. D. Roberts",
"charles-rocco": "Charles Rocco",
"friedrich-rochlitz": "Friedrich Rochlitz",
"edouard-rod": "Edouard Rod",
"georges-rodenbach": "Georges Rodenbach",
"julius-rodenberg": "Julius Rodenberg",
"francois-auguste-rene-rodin": "François-Auguste-René Rodin",
"reinhard-roehle": "Reinhard Roehle",
"gerhard-rohlfs": "Gerhard Rohlfs",
"carl-roehrmann": "Carl Röhrmann",
"egon-roland": "Egon Roland",
"romain-rolland": "Romain Rolland",
"wilhelm-von-rolshausen": "Wilhelm von Rolshausen",
"ole-edvart-rlvaag": "Ole Edvart Rølvaag",
"theodore-von-rommel": "Theodore von Rommel",
"anna-maria-roos": "Anna Maria Roos",
"franklin-d-roosevelt": "Franklin D. Roosevelt",
"chevalier-von-roquesant": "Chevalier von Roquesant",
"otto-roquette": "Otto Roquette",
"felicitas-rose": "Felicitas Rose",
"hans-ludwig-rosegger": "Hans Ludwig Rosegger",
"peter-rosegger": "Peter Rosegger",
"erwin-rosenberger": "Erwin Rosenberger",
"eugenie-rosenberger": "Eugenie Rosenberger",
"sndor-friedrich-rosenfeld": "Sándor Friedrich Rosenfeld",
"gustaf-rosengren": "Gustaf Rosengren",
"paul-rosenhayn": "Paul Rosenhayn",
"palle-adam-vilhelm-rosenkrantz": "Palle Adam Vilhelm Rosenkrantz",
"emil-rosenow": "Emil Rosenow",
"karl-rosner": "Karl Rosner",
"colin-ross": "Colin Ross",
"james-clark-ross": "James Clark Roß",
"johann-christoph-rost": "Johann Christoph Rost",
"edmond-rostand": "Edmond Rostand",
"franz-roswalt": "Franz Roswalt",
"joseph-roth": "Joseph Roth",
"anna-rothpletz": "Anna Rothpletz",
"johann-rottenhoefer": "Johann Rottenhöfer",
"erasmus-von-rotterdam": "Erasmus von Rotterdam",
"jean-jacques-rousseau": "Jean Jacques Rousseau",
"ludwig-rubiner": "Ludwig Rubiner",
"alan-st-rubyn": "Alan St. Rubyn",
"friedrich-rueckert": "Friedrich Rückert",
"minna-ruediger": "Minna Rüdiger",
"willy-wolf-rudinoff": "Willy Wolf Rudinoff",
"rudolf-kronprinz-von-oesterreich-ungarn": "Rudolf, Kronprinz von Österreich-Ungarn",
"josef-ruederer": "Josef Ruederer",
"herrmann-ruf": "Herrmann Ruf",
"arnold-ruge": "Arnold Ruge",
"arnold-ruge-2": "Arnold Ruge",
"wilhelm-ruland": "Wilhelm Ruland",
"elisabeth-von-rumaenien": "Elisabeth von Rumänien",
"dschalal-ad-din-muhammad-rumi": "Dschalal ad-Din Muhammad Rumi",
"karl-friedrich-von-rumohr": "Karl Friedrich von Rumohr",
"johann-rump": "Johann Rump",
"johan-ludvig-runeberg": "Johan Ludvig Runeberg",
"otto-rung": "Otto Rung",
"ferdinand-runkel": "Ferdinand Runkel",
"albert-ruppersberg": "Albert Ruppersberg",
"otto-ruppius": "Otto Ruppius",
"georg-ruseler": "Georg Ruseler",
"karl-russ": "Karl Ruß",
"william-russell": "William Russell",
"rudolf-von-ruets": "Rudolf von Rüts",
"benno-ruettenauer": "Benno Rüttenauer",
"johann-jakob-rutz": "Johann Jakob Rutz",
"ferdinand-von-saar": "Ferdinand von Saar",
"miguel-de-cervantes-saavedra": "Miguel de Cervantes Saavedra",
"eduard-sachau": "Eduard Sachau",
"arthur-wolfgang-von-sacher-masoch": "Arthur Wolfgang von Sacher-Masoch",
"leopold-ritter-von-sacher-masoch": "Leopold Ritter von Sacher-Masoch",
"wanda-von-sacher-masoch": "Wanda von Sacher-Masoch",
"hans-sachs": "Hans Sachs",
"johann-koenig-von-sachsen": "Johann König von Sachsen",
"gustav-sack": "Gustav Sack",
"donatien-alphonse-francois-de-sade": "Donatien Alphonse François de Sade",
"musliheddin-sadi": "Musliheddin Sadi",
"johann-michael-sailer": "Johann Michael Sailer",
"sebastian-sailer": "Sebastian Sailer",
"antoine-de-saint-exupery": "Antoine de Saint-Exupéry",
"emile-marco-de-saint-hilaire": "Emile Marco de Saint-Hilaire",
"abbe-castel-de-saint-pierre": "Abbé Castel de Saint-Pierre",
"jacques-henri-bernardin-de-saint-pierre": "Jacques-Henri Bernardin de Saint-Pierre",
"moritz-saint-thomas": "Moritz Saint-Thomas",
"edith-graefin-salburg": "Edith Gräfin Salburg",
"antoine-de-la-sale": "Antoine de La Sale",
"emilio-salgari": "Emilio Salgari",
"johann-gaudenz-von-salis-seewis": "Johann Gaudenz von Salis-Seewis",
"friedrich-von-sallet": "Friedrich von Sallet",
"erich-salomon": "Erich Salomon",
"ludwig-salomon": "Ludwig Salomon",
"felix-salten": "Felix Salten",
"hugo-salus": "Hugo Salus",
"christian-gotthilf-salzmann": "Christian Gotthilf Salzmann",
"albert-samain": "Albert Samain",
"lukian-von-samosata": "Lukian von Samosata",
"george-sand": "George Sand",
"adele-sandrock": "Adele Sandrock",
"emil-sandt": "Emil Sandt",
"henry-sanson": "Henry Sanson",
"jorge-augustn-nicols-ruiz-de-santayan": "Jorge Augustín Nicolás Ruiz de Santayan",
"rahel-sanzara": "Rahel Sanzara",
"moritz-gottlieb-saphir": "Moritz Gottlieb Saphir",
"agnes-sapper": "Agnes Sapper",
"karl-marquard-sauer": "Karl Marquard Sauer",
"max-sauerlandt": "Max Sauerlandt",
"ferdinand-sauter": "Ferdinand Sauter",
"paul-scarron": "Paul Scarron",
"sven-schacht": "Sven Schacht",
"adolf-friedrich-von-schack": "Adolf Friedrich von Schack",
"albrecht-schaeffer": "Albrecht Schaeffer",
"eugenie-schaeuffelen": "Eugenie Schaeuffelen",
"wilhelm-schaefer": "Wilhelm Schäfer",
"jakob-schaffner": "Jakob Schaffner",
"frida-schanz": "Frida Schanz",
"oskar-franz-schardt": "Oskar Franz Schardt",
"henrik-scharling": "Henrik Scharling",
"heinrich-scharrelmann": "Heinrich Scharrelmann",
"wilhelm-scharrelmann": "Wilhelm Scharrelmann",
"gebhard-schaetzler-perasini": "Gebhard Schätzler-Perasini",
"franz-schauerte": "Franz Schauerte",
"richard-von-schaukal": "Richard von Schaukal",
"heinrich-schaumberger": "Heinrich Schaumberger",
"paul-scheerbart": "Paul Scheerbart",
"leopold-schefer": "Leopold Schefer",
"fritz-scheffel": "Fritz Scheffel",
"victor-von-scheffel": "Victor von Scheffel",
"karl-scheffler": "Karl Scheffler",
"johann-georg-scheffner": "Johann Georg Scheffner",
"hermann-heinrich-schefter": "Hermann Heinrich Schefter",
"philipp-scheidemann": "Philipp Scheidemann",
"max-scheler": "Max Scheler",
"caroline-schelling": "Caroline Schelling",
"friedrich-wilhelm-joseph-von-schelling": "Friedrich Wilhelm Joseph von Schelling",
"max-von-schenkendorf": "Max von Schenkendorf",
"peter-scher": "Peter Scher",
"christian-friedrich-scherenberg": "Christian Friedrich Scherenberg",
"wilhelm-scherer": "Wilhelm Scherer",
"johannes-scherr": "Johannes Scherr",
"gottlieb-scheuffler": "Gottlieb Scheuffler",
"erich-scheurmann": "Erich Scheurmann",
"rene-schickele": "René Schickele",
"daniel-schiebeler": "Daniel Schiebeler",
"hans-schiebelhuth": "Hans Schiebelhuth",
"anna-schieber": "Anna Schieber",
"friedrich-schiller": "Friedrich Schiller",
"gustav-schilling": "Gustav Schilling",
"carl-georg-schillings": "Carl Georg Schillings",
"georg-gottlieb-schirges": "Georg Gottlieb Schirges",
"kaethe-schirmacher": "Käthe Schirmacher",
"alfred-schirokauer": "Alfred Schirokauer",
"johannes-schlaf": "Johannes Schlaf",
"august-wilhelm-schlegel": "August Wilhelm Schlegel",
"dorothea-schlegel": "Dorothea Schlegel",
"friedrich-schlegel": "Friedrich Schlegel",
"johann-elias-schlegel": "Johann Elias Schlegel",
"carl-ludwig-schleich": "Carl Ludwig Schleich",
"friedrich-schleiermacher": "Friedrich Schleiermacher",
"paul-schlenther": "Paul Schlenther",
"paul-schlesinger": "Paul Schlesinger",
"freiherr-von-schlicht": "Freiherr von Schlicht",
"moritz-schlick": "Moritz Schlick",
"heinrich-schliemann": "Heinrich Schliemann",
"hans-schliepmann": "Hans Schliepmann",
"gabriele-freifrau-von-schlippenbach": "Gabriele Freifrau von Schlippenbach",
"friedrich-schloegl": "Friedrich Schlögl",
"christoph-von-schmid": "Christoph von Schmid",
"euchar-albrecht-schmid": "Euchar Albrecht Schmid",
"herman-schmid": "Herman Schmid",
"erwin-schmidhuber": "Erwin Schmidhuber",
"heinrich-schmidt": "Heinrich Schmidt",
"johann-schmidt": "Johann Schmidt",
"kurt-wilhelm-schmidt": "Kurt Wilhelm Schmidt",
"lothar-schmidt": "Lothar Schmidt",
"wilhelm-schmidtbonn": "Wilhelm Schmidtbonn",
"richard-schmidt-cabanis": "Richard Schmidt-Cabanis",
"adolf-schmitthenner": "Adolf Schmitthenner",
"auguste-luise-supper-geb-schmitz": "Auguste (Luise) Supper geb. Schmitz",
"hermann-harry-schmitz": "Hermann Harry Schmitz",
"maria-schmitz": "Maria Schmitz",
"oscar-adolf-hermann-schmitz": "Oscar Adolf Hermann Schmitz",
"gustav-schmoller": "Gustav Schmoller",
"johann-gottfried-schnabel": "Johann Gottfried Schnabel",
"gustav-schneider": "Gustav Schneider",
"manfred-schneider": "Manfred Schneider",
"thekla-schneider": "Thekla Schneider",
"josephine-schneider-foerstl": "Josephine Schneider-Foerstl",
"joseph-anton-schneiderfranken": "Joseph Anton Schneiderfranken",
"arthur-schnitzler": "Arthur Schnitzler",
"hedwig-schobert": "Hedwig Schobert",
"prinz-emil-von-schoenaich-carolath": "Prinz Emil von Schoenaich-Carolath",
"hans-und-sophie-scholl": "Hans und Sophie Scholl",
"adolf-schoell": "Adolf Schöll",
"arthur-a-schoenhausen": "Arthur A. Schönhausen",
"karl-schoenherr": "Karl Schönherr",
"paul-von-schoenthan": "Paul von Schönthan",
"franz-xaver-von-schoenwerth": "Franz Xaver von Schönwerth",
"arthur-schopenhauer": "Arthur Schopenhauer",
"johanna-schopenhauer": "Johanna Schopenhauer",
"luise-adelaide-lavinia-schopenhauer": "(Luise) Adel(aid)e (Lavinia) Schopenhauer",
"jean-schopfer": "Jean Schopfer",
"alexander-schoeppner": "Alexander Schöppner",
"adelheid-von-schorn": "Adelheid von Schorn",
"anton-schott": "Anton Schott",
"clara-schott": "Clara Schott",
"richard-schott": "Richard Schott",
"josef-schramek": "Josef Schramek",
"albert-schramm": "Albert Schramm",
"daniel-paul-schreber": "Daniel Paul Schreber",
"moritz-schreber": "Moritz Schreber",
"paul-schreckenbach": "Paul Schreckenbach",
"clara-schreiber": "Clara Schreiber",
"hippolyt-schreiber": "Hippolyt Schreiber",
"wilhelm-schreiner": "Wilhelm Schreiner",
"christoph-schrempf": "Christoph Schrempf",
"joseph-schreyvogel": "Joseph Schreyvogel",
"gustav-schroeer": "Gustav Schröer",
"hans-schrott-fiechtl": "Hans Schrott-Fiechtl",
"christian-friedrich-daniel-schubart": "Christian Friedrich Daniel Schubart",
"ossip-schubin": "Ossip Schubin",
"elisabeth-schucht": "Elisabeth Schucht",
"levin-schuecking": "Levin Schücking",
"jacob-schudt": "Jacob Schudt",
"carl-schueler": "Carl Schüler",
"gustav-schueler": "Gustav Schüler",
"james-willard-schultz": "James Willard Schultz",
"jeanne-schultz": "Jeanne Schultz",
"karl-theodor-schultz": "Karl Theodor Schultz",
"heinrich-schulz": "Heinrich Schulz",
"ernst-schulze": "Ernst Schulze",
"friedrich-august-schulze": "Friedrich August Schulze",
"bernhardine-schulze-smidt": "Bernhardine Schulze-Smidt",
"heinrich-vollrat-schumacher": "Heinrich Vollrat Schumacher",
"tony-schumacher": "Tony Schumacher",
"j-c-schumann": "J. C. Schumann",
"robert-schumann": "Robert Schumann",
"johann-gottlieb-schummel": "Johann Gottlieb Schummel",
"johannes-martin-schupp": "Johannes Martin Schupp",
"oskar-schuerer": "Oskar Schürer",
"arthur-schurig": "Arthur Schurig",
"carl-schurz": "Carl Schurz",
"eugene-schuyler": "Eugene Schuyler",
"gustav-schwab": "Gustav Schwab",
"marie-sophie-schwartz": "Marie Sophie Schwartz",
"georg-schwarz": "Georg Schwarz",
"hermann-schwarz": "Hermann Schwarz",
"rudolf-schwarz": "Rudolf Schwarz",
"annemarie-schwarzenbach": "Annemarie Schwarzenbach",
"fuerst-friedrich-zu-schwarzenberg": "Fürst Friedrich zu Schwarzenberg",
"robert-schweichel": "Robert Schweichel",
"georg-schweinfurth": "Georg Schweinfurth",
"josephine-schwerin": "Josephine Schwerin",
"otto-schwerin": "Otto Schwerin",
"moritz-von-schwind": "Moritz von Schwind",
"kurt-schwitters": "Kurt Schwitters",
"marcel-schwob": "Marcel Schwob",
"robert-falcon-scott": "Robert Falcon Scott",
"walter-scott": "Walter Scott",
"charles-sealsfield": "Charles Sealsfield",
"hans-von-seeckt": "Hans von Seeckt",
"heinrich-seidel": "Heinrich Seidel",
"willy-seidel": "Willy Seidel",
"johann-gabriel-seidl": "Johann Gabriel Seidl",
"walter-seidl": "Walter Seidl",
"robert-seitz": "Robert Seitz",
"lydia-sejfullina": "Lydia Sejfullina",
"karl-semper": "Karl Semper",
"walter-serner": "Walter Serner",
"franz-servaes": "Franz Servaes",
"ernest-thompson-seton": "Ernest Thompson Seton",
"johann-gottfried-seume": "Johann Gottfried Seume",
"william-shakespeare": "William Shakespeare",
"george-bernard-shaw": "George Bernard Shaw",
"patrick-a-sheehan": "Patrick A. Sheehan",
"mary-shelley": "Mary Shelley",
"percy-bysshe-shelley": "Percy Bysshe Shelley",
"richard-brinsley-sheridan": "Richard Brinsley Sheridan",
"viacheslav-shishkov": "Viacheslav Shishkov",
"jules-siber": "Jules Siber",
"ingeborg-maria-sick": "Ingeborg Maria Sick",
"josephine-siebe": "Josephine Siebe",
"herman-siebeck": "Herman Siebeck",
"paul-eugen-sieg": "Paul Eugen Sieg",
"richard-siegemund": "Richard Siegemund",
"walther-siegfried": "Walther Siegfried",
"werner-von-siemens": "Werner von Siemens",
"henryk-sienkiewicz": "Henryk Sienkiewicz",
"amalie-sieveking": "Amalie Sieveking",
"silberstein-august-karl": "August (Karl)Silberstein",
"angelus-silesius": "Angelus Silesius",
"georg-simmel": "Georg Simmel",
"emma-simon": "Emma Simon",
"robert-simpson": "Robert Simpson",
"karl-simrock": "Karl Simrock",
"george-robert-sims": "George Robert Sims",
"hermann-sinsheimer": "Hermann Sinsheimer",
"johan-skjoldborg": "Johan Skjoldborg",
"fritz-skowronnek": "Fritz Skowronnek",
"richard-skowronnek": "Richard Skowronnek",
"amalie-skram": "Amalie Skram",
"heinrich-smidt": "Heinrich Smidt",
"samuel-smiles": "Samuel Smiles",
"adam-smith": "Adam Smith",
"tobias-smollett": "Tobias Smollett",
"karl-soehle": "Karl Söhle",
"heinrich-sohnrey": "Heinrich Sohnrey",
"sokrates": "Sokrates",
"wilhelm-gottlieb-soldan": "Wilhelm Gottlieb Soldan",
"iwan-solonewitsch": "Iwan Solonewitsch",
"fedor-sommer": "Fedor Sommer",
"adolf-sommerfeld": "Adolf Sommerfeld",
"hugo-sonnenschein": "Hugo Sonnenschein",
"alois-theodor-sonnleitner": "Alois Theodor Sonnleitner",
"friedrich-von-sontheim": "Friedrich von Sontheim",
"moritz-wilhelm-sophar": "Moritz Wilhelm Sophar",
"sophokles": "Sophokles",
"reinhard-johannes-sorge": "Reinhard Johannes Sorge",
"wolfgang-sorge": "Wolfgang Sorge",
"robert-southey": "Robert Southey",
"jura-soyfer": "Jura Soyfer",
"christian-herman-sparre": "Christian Herman Sparre",
"else-sparwasser": "Else Sparwasser",
"doris-freiin-von-spaettgen": "Doris Freiin von Spättgen",
"diedrich-speckmann": "Diedrich Speckmann",
"mordecai-spector": "Mordecai Spector",
"friedrich-spee": "Friedrich Spee",
"oswald-spengler": "Oswald Spengler",
"august-sperl": "August Sperl",
"wilhelm-speyer": "Wilhelm Speyer",
"friedrich-spielhagen": "Friedrich Spielhagen",
"heinrich-spiero": "Heinrich Spiero",
"philipp-spiess": "Philipp Spieß",
"joseph-spillmann": "Joseph Spillmann",
"karl-spindler": "Karl Spindler",
"baruch-de-spinoza": "Baruch de Spinoza",
"alexander-spiridovich": "Alexander Spiridovich",
"carl-spitteler": "Carl Spitteler",
"heinrich-spoerl": "Heinrich Spoerl",
"louis-spohr": "Louis Spohr",
"jakob-sprenger": "Jakob Sprenger",
"paul-ssymank": "Paul Ssymank",
"ilse-von-stach": "Ilse von Stach",
"henry-de-vere-stacpoole": "Henry de Vere Stacpoole",
"hans-staden": "Hans Staden",
"ernst-stadler": "Ernst Stadler",
"frau-von-stal": "Frau von Staël",
"marie-stahl": "Marie Stahl",
"josef-stalin": "Josef Stalin",
"henry-morton-stanley": "Henry Morton Stanley",
"adolf-stark": "Adolf Stark",
"franz-stassen": "Franz Stassen",
"ludwig-stave": "Ludwig Stave",
"fritz-stavenhagen": "Fritz Stavenhagen",
"gustaf-f-steffen": "Gustaf F. Steffen",
"henrich-steffens": "Henrich Steffens",
"hermann-stegemann": "Hermann Stegemann",
"hermann-stehr": "Hermann Stehr",
"heinrich-friedrich-karl-reichsfreiherr-vom-und-zum-stein": "Heinrich Friedrich Karl Reichsfreiherr vom und zum Stein",
"richard-heinrich-stein": "Richard Heinrich Stein",
"julius-steinberg": "Julius Steinberg",
"rudolf-steiner": "Rudolf Steiner",
"heinrich-steinhausen": "Heinrich Steinhausen",
"max-steinitzer": "Max Steinitzer",
"paul-steinmueller": "Paul Steinmüller",
"franz-stelzhamer": "Franz Stelzhamer",
"adolf-stern": "Adolf Stern",
"bernhard-stern": "Bernhard Stern",
"leo-sternberg": "Leo Sternberg",
"laurence-sterne": "Laurence Sterne",
"carl-sternheim": "Carl Sternheim",
"julius-stettenheim": "Julius Stettenheim",
"ludwig-steub": "Ludwig Steub",
"johann-kaspar-steube": "Johann Kaspar Steube",
"robert-louis-stevenson": "Robert Louis Stevenson",
"charlotte-stieglitz": "Charlotte Stieglitz",
"dora-stieler": "Dora Stieler",
"karl-stieler": "Karl Stieler",
"adelheid-stier": "Adelheid Stier",
"adalbert-stifter": "Adalbert Stifter",
"edward-stilgebauer": "Edward Stilgebauer",
"charlotte-stiller": "Charlotte Stiller",
"heinrich-stilling": "Heinrich Stilling",
"julius-stinde": "Julius Stinde",
"max-stirner": "Max Stirner",
"helene-stoecker": "Helene Stöcker",
"francis-richard-stockton": "Francis Richard Stockton",
"otto-stoessl": "Otto Stoessl",
"bram-stoker": "Bram Stoker",
"karl-adolf-stoltze": "(Karl) Adolf Stoltze",
"maria-stona": "Maria Stona",
"ludwig-storch": "Ludwig Storch",
"karl-storck": "Karl Storck",
"theodor-storm": "Theodor Storm",
"harriett-beecher-stowe": "Harriett Beecher Stowe",
"moritz-graf-von-strachwitz": "Moritz Graf von Strachwitz",
"august-stramm": "August Stramm",
"giovanni-francesco-straparola": "Giovanni Francesco Straparola",
"gottfried-von-strassburg": "Gottfried von Straßburg",
"charlot-strasser": "Charlot Strasser",
"karl-theodor-strasser": "Karl Theodor Strasser",
"hesba-stratton": "Hesba Stratton",
"rudolf-stratz": "Rudolf Stratz",
"otto-strauss": "Otto Strauss",
"david-friedrich-strauss": "David Friedrich Strauß",
"ludwig-strauss": "Ludwig Strauß",
"g-f-streckfuss": "G. F. Streckfuss",
"adolf-streckfuss": "Adolf Streckfuß",
"georg-strelisker": "Georg Strelisker",
"gustav-stresemann": "Gustav Stresemann",
"johan-august-strindberg": "(Johan) August Strindberg",
"karl-hans-strobl": "Karl Hans Strobl",
"adolf-strodtmann": "Adolf Strodtmann",
"friedrich-strubberg": "Friedrich Strubberg",
"franz-strunz": "Franz Strunz",
"fritz-stueber-gunther": "Fritz Stüber-Gunther",
"eduard-stucken": "Eduard Stucken",
"hans-sturm": "H[ans] Sturm",
"julius-sturm": "Julius Sturm",
"helfrich-peter-sturz": "Helfrich Peter Sturz",
"marie-tihanyi-graefin-sturza": "Marie Tihanyi Gräfin Sturza",
"rudolf-stuerzer": "Rudolf Stürzer",
"clara-sudermann": "Clara Sudermann",
"hermann-sudermann": "Hermann Sudermann",
"eugene-sue": "Eugène Sue",
"sueton": "Sueton",
"friedrich-sundermann": "Friedrich Sundermann",
"j-m-sutcliffe": "J. M. Sutcliffe",
"otto-sutermeister": "Otto Sutermeister",
"p-sutter": "P. Sutter",
"bertha-von-suttner": "Bertha von Suttner",
"jn-svensson": "Jón Svensson",
"italo-svevo": "Italo Svevo",
"emanuel-von-swedenborg": "Emanuel von Swedenborg",
"jonathan-swift": "Jonathan Swift",
"charles-swinburne": "Charles Swinburne",
"margarete-von-sydow": "Margarete von Sydow",
"publius-cornelius-tacitus": "Publius Cornelius Tacitus",
"albert-tafel": "Albert Tafel",
"rabindranath-tagore": "Rabindranath Tagore",
"a-h-tammsaare": "A. H. Tammsaare",
"riutei-tanefiko": "Riutei Tanefiko",
"carl-tanera": "Carl Tanera",
"booth-tarkington": "Booth Tarkington",
"ubald-tartaruga": "Ubald Tartaruga",
"ernst-ludwig-taschenberg": "Ernst Ludwig Taschenberg",
"torquato-tasso": "Torquato Tasso",
"rudolf-von-tavel": "Rudolf von Tavel",
"esaias-tegner": "Esaias Tegnér",
"konrad-telmann": "Konrad Telmann",
"hubertus-temme": "Hubertus Temme",
"alfred-tennyson": "Alfred Tennyson",
"johannes-von-tepl": "Johannes von Tepl",
"gerhard-tersteegen": "Gerhard Tersteegen",
"fjodor-kusmitsch-teternikow": "Fjodor Kusmitsch Teternikow",
"william-makepeace-thackeray": "William Makepeace Thackeray",
"ernst-thaelmann": "Ernst Thälmann",
"dietrich-theden": "Dietrich Theden",
"hans-theis": "Hans Theis",
"andre-theuriet": "André Theuriet",
"maria-von-thilo": "Maria von Thilo",
"heinrich-thode": "Heinrich Thode",
"andreas-thom": "Andreas Thom",
"ludwig-thoma": "Ludwig Thoma",
"henry-thoreau": "Henry Thoreau",
"magdalene-thoresen": "Magdalene Thoresen",
"moritz-august-von-thuemmel": "Moritz August von Thümmel",
"ernest-temple-thurston": "Ernest Temple Thurston",
"heinrich-tiaden": "Heinrich Tiaden",
"ludwig-tieck": "Ludwig Tieck",
"oswald-tiedemann": "Oswald Tiedemann",
"claude-tillier": "Claude Tillier",
"alexander-von-tilly": "Alexander von Tilly",
"ernst-toller": "Ernst Toller",
"alexei-konstantinowitsch-tolstoi": "Alexei Konstantinowitsch Tolstoi",
"alexei-nikolajewitsch-tolstoi": "Alexei Nikolajewitsch Tolstoi",
"leo-lvovich-tolstoi": "Leo Lvovich Tolstoi",
"lew-tolstoi": "Lew Tolstoi",
"zacharias-topelius": "Zacharias Topelius",
"rudolf-toepffer": "Rudolf Töpffer",
"heinz-tovote": "Heinz Tovote",
"georg-trakl": "Georg Trakl",
"eugen-trapp": "Eugen Trapp",
"horace-traubel": "Horace Traubel",
"franz-trautmann": "Franz Trautmann",
"hanns-trautner": "Hanns Trautner",
"susanne-trautwein": "Susanne Trautwein",
"heinrich-von-treitschke": "Heinrich von Treitschke",
"edward-john-trelawny": "Edward John Trelawny",
"franz-treller": "Franz Treller",
"friedrich-von-der-trenck": "Friedrich von der Trenck",
"albert-von-trentini": "Albert von Trentini",
"josef-treumann": "Josef Treumann",
"daniel-wilhelm-triller": "Daniel Wilhelm Triller",
"august-trinius": "August Trinius",
"emil-trinkler": "Emil Trinkler",
"gustav-trockenbrodt": "Gustav Trockenbrodt",
"johannes-trojan": "Johannes Trojan",
"c-v-trojanowsky": "C. v. Trojanowsky",
"magda-trott": "Magda Trott",
"leo-trotzki": "Leo Trotzki",
"peter-tschaikowsky": "Peter Tschaikowsky",
"anton-tschechov": "Anton Tschechov",
"kurt-tucholsky": "Kurt Tucholsky",
"jim-tully": "Jim Tully",
"ivan-sergejevich-turgenev": "Ivan Sergejevich Turgenev",
"john-victor-turner": "John Victor Turner",
"r-turner": "R. Turner",
"joseph-turquan": "Joseph Turquan",
"mark-twain": "Mark Twain",
"juri-nikolajewitsch-tynjanow": "Juri Nikolajewitsch Tynjanow",
"hans-erich-tzschirner": "Hans-Erich Tzschirner",
"hermann-ubell": "Hermann Ubell",
"ernst-udet": "Ernst Udet",
"emilie-uhland": "Emilie Uhland",
"ludwig-uhland": "Ludwig Uhland",
"ernst-ule": "Ernst Ule",
"leonora-christina-graefin-ulfeldt": "Leonora Christina Gräfin Ulfeldt",
"karl-heinrich-ulrichs": "Karl Heinrich Ulrichs",
"evelyn-underhill": "Evelyn Underhill",
"sigrid-undset": "Sigrid Undset",
"hermann-ungar": "Hermann Ungar",
"alexander-von-ungern-sternberg": "Alexander von Ungern-Sternberg",
"walter-zur-ungnad": "Walter zur Ungnad",
"allen-upward": "Allen Upward",
"else-ury": "Else Ury",
"ulf-uweson": "Ulf Uweson",
"woldemar-baron-von-uxkull": "Woldemar Baron von Uxkull",
"johann-peter-uz": "Johann Peter Uz",
"eugen-von-vaerst": "Eugen von Vaerst",
"karl-valentin": "Karl Valentin",
"juan-valera": "Juan Valera",
"pierre-valmigere": "Pierre Valmigère",
"margaretha-von-valois": "Margaretha von Valois",
"fernand-vanderem": "Fernand Vandérem",
"giorgio-vasari": "Giorgio Vasari",
"carl-franz-van-der-velde": "Carl Franz van der Velde",
"giovanni-verga": "Giovanni Verga",
"vergil": "Vergil",
"emile-verhaeren": "Emile Verhaeren",
"paul-verlaine": "Paul Verlaine",
"august-vermeylen": "August Vermeylen",
"jules-verne": "Jules Verne",
"paul-verne": "Paul Verne",
"clara-viebig": "Clara Viebig",
"berthold-viertel": "Berthold Viertel",
"alfred-de-vigny": "Alfred de Vigny",
"hermine-villinger": "Hermine Villinger",
"francois-villon": "François Villon",
"karl-von-vincenti": "Karl von Vincenti",
"otto-violan": "Otto Violan",
"rudolf-virchow": "Rudolf Virchow",
"friedrich-theodor-vischer": "Friedrich Theodor Vischer",
"carl-ferdinand-van-vleuten": "Carl Ferdinand van Vleuten",
"eduard-vogel": "Eduard Vogel",
"walther-von-der-vogelweide": "Walther von der Vogelweide",
"max-vogler": "Max Vogler",
"mathias-voglers": "Mathias Voglers",
"adolf-voegtlin": "Adolf Vögtlin",
"johannes-voigt": "Johannes Voigt",
"wilhelm-voigt": "Wilhelm Voigt",
"abbe-von-voisenon": "Abbé von Voisenon",
"theodor-volbehr": "Theodor Volbehr",
"herbert-volck": "Herbert Volck",
"richard-von-volkmann": "Richard von Volkmann",
"karl-voll": "Karl Voll",
"agnes-vollmar": "Agnes Vollmar",
"ingeborg-vollquartz": "Ingeborg Vollquartz",
"francois-marie-arouet-de-voltaire": "François Marie Arouet de Voltaire",
"karl-vorlaender": "Karl Vorländer",
"johann-heinrich-voss": "Johann Heinrich Voß",
"julius-von-voss": "Julius von Voß",
"richard-voss": "Richard Voß",
"jaroslav-vrchlick": "Jaroslav Vrchlický",
"christian-august-vulpius": "Christian August Vulpius",
"anton-de-waal": "Anton de Waal",
"hans-wachenhusen": "Hans Wachenhusen",
"friedrich-ludwig-von-wachholtz": "Friedrich Ludwig von Wachholtz",
"oskar-waechter": "Oskar Wächter",
"wilhelm-heinrich-wackenroder": "Wilhelm Heinrich Wackenroder",
"christian-jacob-wagenseil": "Christian Jacob Wagenseil",
"christian-wagner": "Christian Wagner",
"hedda-wagner": "Hedda Wagner",
"heinrich-leopold-wagner": "Heinrich Leopold Wagner",
"hermann-wagner": "Hermann Wagner",
"hermann-wagner-2": "Hermann Wagner",
"johannes-andreas-freiherr-von-wagner": "Johannes Andreas Freiherr von Wagner",
"wilhelm-richard-wagner": "(Wilhelm) Richard Wagner",
"wilhelm-friedrich-waiblinger": "Wilhelm (Friedrich) Waiblinger",
"heinrich-suso-waldeck": "Heinrich Suso Waldeck",
"j-walden": "J. Walden",
"burkhard-waldis": "Burkhard Waldis",
"edgar-wallace": "Edgar Wallace",
"lewis-wallace": "Lewis Wallace",
"wilhelm-walloth": "Wilhelm Walloth",
"james-morgan-walsh": "James Morgan Walsh",
"karl-wartenburg": "Karl Wartenburg",
"waescha-kwonnesin": "Wäscha-kwonnesin",
"maria-waser": "Maria Waser",
"wilhelm-joseph-von-wasielewski": "Wilhelm Joseph von Wasielewski",
"iwan-wasow": "Iwan Wasow",
"jakob-wassermann": "Jakob Wassermann",
"hans-watzlik": "Hans Watzlik",
"annie-webb-peploe": "Annie Webb-Peploe",
"ernst-heinrich-weber": "Ernst Heinrich Weber",
"franz-sylvester-weber": "Franz Sylvester Weber",
"friedrich-wilhelm-weber": "Friedrich Wilhelm Weber",
"fritz-karl-weber": "Fritz Karl Weber",
"gotthold-august-weber": "Gotthold August Weber",
"leopold-weber": "Leopold Weber",
"max-weber": "Max Weber",
"henry-kitchell-webster": "Henry Kitchell Webster",
"frank-wedekind": "Frank Wedekind",
"georg-weerth": "Georg Weerth",
"michael-wefers": "Michael Wefers",
"alfred-wegener": "Alfred Wegener",
"georg-wegener": "Georg Wegener",
"christian-friedrich-weichmann": "Christian Friedrich Weichmann",
"wilhelm-weigand": "Wilhelm Weigand",
"gustav-weil": "Gustav Weil",
"robert-weil": "Robert Weil",
"louis-weinert-wilton-2": "Louis Weinert-Wilton",
"louis-weinert-wilton": "Louis Weinert-Wilton",
"otto-weininger": "Otto Weininger",
"david-friedrich-weinland": "David Friedrich Weinland",
"christian-weise": "Christian Weise",
"paul-weise": "Paul Weise",
"pauline-weise": "Pauline Weise",
"carl-weisflog": "Carl Weisflog",
"franz-carl-weiskopf": "Franz Carl Weiskopf",
"ernst-weiss": "Ernst Weiß",
"weiss-ferdl": "Weiß Ferdl",
"christian-felix-weisse": "Christian Felix Weiße",
"maximiliane-franul-von-weissenthurn": "Maximiliane Franul von Weissenthurn",
"adolf-weissmann": "Adolf Weissmann",
"carl-weitbrecht": "Carl Weitbrecht",
"carl-borromaeus-weitzmann": "Carl Borromäus Weitzmann",
"wilhelm-ludwig-wekhrlin": "Wilhelm Ludwig Wekhrlin",
"herbert-george-wells": "Herbert George Wells",
"john-welten": "John Welten",
"helene-welti": "Helene Welti",
"richard-weltrich": "Richard Weltrich",
"georg-wende": "Georg Wende",
"franz-wendelmuth": "Franz Wendelmuth",
"lisa-wenger": "Lisa Wenger",
"josef-gottlieb-wenter": "Josef (Gottlieb) Wenter",
"josef-wenzig": "Josef Wenzig",
"franz-werfel": "Franz Werfel",
"elisabeth-werner": "Elisabeth Werner",
"johannes-werner": "Johannes Werner",
"reinhold-von-werner": "Reinhold von Werner",
"paul-wertheimer": "Paul Wertheimer",
"mathilde-wesendonck": "Mathilde Wesendonck",
"luise-westkirch": "Luise Westkirch",
"karl-friedrich-gottlob-wetzel": "Karl Friedrich Gottlob Wetzel",
"alfred-wey": "Alfred Wey",
"johann-karl-wezel": "Johann Karl Wezel",
"edith-wharton": "Edith Wharton",
"walt-whitman": "Walt Whitman",
"ernst-wichert": "Ernst Wichert",
"franz-wichmann": "Franz Wichmann",
"josef-wichner": "Josef Wichner",
"joerg-wickram": "Jörg Wickram",
"josef-victor-widmann": "Josef Victor Widmann",
"ernst-wiechert": "Ernst Wiechert",
"gustav-johannes-wied": "Gustav Johannes Wied",
"k-m-wiegandt": "K. M. Wiegandt",
"paul-wiegler": "Paul Wiegler",
"christoph-martin-wieland": "Christoph Martin Wieland",
"ludolf-wienbarg": "Ludolf Wienbarg",
"oskar-wiener": "Oskar Wiener",
"wilhelm-wiesebach": "Wilhelm Wiesebach",
"adolf-wilbrandt": "Adolf Wilbrandt",
"oscar-wilde": "Oscar Wilde",
"ernst-von-wildenbruch": "Ernst von Wildenbruch",
"else-wildenhagen": "Else Wildenhagen",
"ottilie-wildermuth-geb-rooschuez": "Ottilie Wildermuth geb. Rooschüz",
"anton-wildgans": "Anton Wildgans",
"richard-wilhelm": "Richard Wilhelm",
"max-wilke": "Max Wilke",
"bruno-wille": "Bruno Wille",
"valentin-williams": "Valentin Williams",
"ernst-adolf-willkomm": "Ernst Adolf Willkomm",
"agnes-willms-wildermuth": "Agnes Willms-Wildermuth",
"johann-joachim-winckelmann": "Johann Joachim Winckelmann",
"wilhelm-windelband": "Wilhelm Windelband",
"ludwig-winder": "Ludwig Winder",
"max-wing": "Max Wing",
"eugen-gottlob-winkler": "Eugen Gottlob Winkler",
"christa-winsloe": "Christa Winsloe",
"helen-maria-winslow": "Helen Maria Winslow",
"adolf-von-winterfeld": "Adolf von Winterfeld",
"emmy-von-winterfeld-warnow": "Emmy von Winterfeld-Warnow",
"albrecht-wirth": "Albrecht Wirth",
"nicholas-patrick-stephen-wiseman": "Nicholas Patrick Stephen Wiseman",
"hermann-wilhelm-leopold-ludwig-von-wissmann": "Hermann Wilhelm Leopold Ludwig von Wissmann",
"augusta-de-wit": "Augusta de Wit",
"johann-philipp-lorenz-withof": "Johann Philipp Lorenz Withof",
"engelbert-wittich": "Engelbert Wittich",
"emil-witting": "Emil Witting",
"egid-filek-edler-von-wittinghausen": "Egid Filek Edler von Wittinghausen",
"josef-wittmann": "Josef Wittmann",
"karl-woermann": "Karl Woermann",
"olga-wohlbrueck": "Olga Wohlbrück",
"oskar-woehrle": "Oskar Wöhrle",
"friedrich-wolf": "Friedrich Wolf",
"gustav-wolf": "Gustav Wolf",
"johann-wilhelm-wolf": "Johann Wilhelm Wolf",
"thomas-wolfe": "Thomas Wolfe",
"alfred-wolfenstein": "Alfred Wolfenstein",
"julius-wolff": "Julius Wolff",
"ludwig-wolff": "Ludwig Wolff",
"max-josef-wolff": "Max Josef Wolff",
"theodor-wolff": "Theodor Wolff",
"theodor-wolff-2": "Theodor Wolff",
"heinrich-woelfflin": "Heinrich Wölfflin",
"karl-august-woll": "Karl August Woll",
"ernst-von-wolzogen": "Ernst von Wolzogen",
"hans-von-wolzogen": "Hans von Wolzogen",
"virginia-woolf": "Virginia Woolf",
"helmut-woerdemann": "Helmut Wördemann",
"sophie-woerishoeffer": "Sophie Wörishöffer",
"anny-wothe": "Anny Wothe",
"willard-huntington-wright": "Willard Huntington Wright",
"erich-wulffen": "Erich Wulffen",
"theodor-wundt": "Theodor Wundt",
"wilhelm-maximilian-wundt": "Wilhelm Maximilian Wundt",
"konrad-von-wuerzburg": "Konrad von Würzburg",
"jakob-wychgram": "Jakob Wychgram",
"johann-david-wyss": "Johann David Wyß",
"xenophon": "Xenophon",
"francisco-de-xerez": "Francisco de Xerez",
"william-butler-yeats": "William Butler Yeats",
"curtis-yorke": "Curtis Yorke",
"edward-young": "Edward Young",
"egerton-r-young": "Egerton R. Young",
"eugen-zabel": "Eugen Zabel",
"ernst-zahn": "Ernst Zahn",
"israel-zangwill": "Israel Zangwill",
"arthur-zapp": "Arthur Zapp",
"sidonia-hedwig-zaeunemann": "Sidonia Hedwig Zäunemann",
"paul-zech": "Paul Zech",
"friedrich-zeckendorf": "Friedrich Zeckendorf",
"marie-zedelius": "Marie Zedelius",
"joseph-christian-freiherr-von-zedlitz": "Joseph Christian Freiherr von Zedlitz",
"theodor-zell": "Theodor Zell",
"guido-zernatto": "Guido Zernatto",
"philipp-von-zesen": "Philipp von Zesen",
"clara-zetkin": "Clara Zetkin",
"zephyrin-zettl": "Zephyrin Zettl",
"paul-zifferer": "Paul Zifferer",
"heinrich-zille": "Heinrich Zille",
"heinrich-zimmer": "Heinrich Zimmer",
"wilhelm-zimmermann": "Wilhelm Zimmermann",
"julius-wilhelm-zincgref": "Julius Wilhelm Zincgref",
"ignaz-vinzenz-zingerle": "Ignaz Vinzenz Zingerle",
"j-zink": "J. Zink",
"nikolaus-ludwig-von-zinzendorf": "Nikolaus Ludwig von Zinzendorf",
"hans-zitt": "Hans Zitt",
"franz-josef-zlatnik": "Franz Josef Zlatnik",
"fedor-von-zobeltitz": "Fedor von Zobeltitz",
"martha-von-zobeltitz": "Martha von Zobeltitz",
"emile-zola": "Emile Zola",
"hektor-zollikofer": "Hektor Zollikofer",
"theophil-zolling": "Theophil Zolling",
"albin-zollinger": "Albin Zollinger",
"richard-zoozmann": "Richard Zoozmann",
"heinrich-zschalig": "Heinrich Zschalig",
"heinrich-zschokke": "Heinrich Zschokke",
"johanna-zuercher-siebel": "Johanna Zürcher-Siebel",
"stefan-zweig": "Stefan Zweig",
"leo-zznafer": "Leo Zznafer"
}
}
bi2u8vwviftgz2jmxa6ff3gstq4k578
Template:Projekt-gutenberg.org/AexStr.json
10
175620
743896
743820
2026-05-22T13:49:55Z
PerfektesChaos
18104
2026-05-21
743896
json
application/json
{
"suite": "projekt-gutenberg.org",
"sub": "AexStr",
"serial": "2026-05-21",
"hash": {
"anonymus": "anonyme-oder-unbekannte-autoren",
"antholog": "anthologien",
"about": "edmond-about",
"abraham": "abraham-a-sancta-clara",
"achleitn": "arthur-achleitner",
"adlerrev": "paul-adler",
"adlersfe": "eufemia-von-adlersfeld-ballestrem",
"alarcon": "pedro-antonio-de-alarcn",
"alcofora": "marianna-alcoforado",
"alexandr": "alexandra-von-bayern",
"alkiphro": "alkiphron",
"amicis": "edmondo-de-amicis",
"amyntor": "gerhard-von-amyntor",
"apel": "august-apel",
"appenzel": "johann-conrad-appenzeller",
"archenho": "johann-wilhelm-von-archenholz",
"arcybase": "michail-petrowitsch-arzybaschew",
"argens": "jean-baptiste-de-boyer-marquis-dargens",
"ariosto": "ludovico-ariosto",
"arndf": "friedrich-arnd",
"asmus": "wilhelm-asmus",
"asmussen": "georg-asmussen",
"attar": "farid-ed-din-attar",
"atterbom": "per-daniel-amadeus-atterbom",
"audoux": "marguerite-audoux",
"auernhei": "raoul-auernheimer",
"augusti": "auguste-plehn",
"bacon": "francis-bacon",
"baggesen": "jens-baggesen",
"bakunin": "michael-bakunin",
"balmont": "konstantin-balmont",
"bartels": "max-bartels",
"bartsch": "rudolf-hans-bartsch",
"baum": "vicki-baum",
"beardsle": "aubrey-beardsley",
"beaumarc": "pierre-de-beaumarchais",
"bechstei": "ludwig-bechstein",
"beckford": "john-beckford",
"becquer": "gustavo-adolfo-becquer",
"beeker": "kaethe-van-beeker",
"beer": "richard-beer-hofmann",
"bely": "andrej-bely",
"benjamin": "walter-benjamin",
"benn": "gottfried-benn",
"bennett": "arnold-bennett",
"benrath": "henry-benrath",
"beradt": "martin-beradt",
"bergengr": "siegfried-bergengruen",
"berger": "alfred-freiherrn-von-berger",
"bergman": "hjalmar-bergman",
"bergmann": "hilda-bergmann",
"bergson": "henri-bergson",
"berlioz": "hector-berlioz",
"bern": "maximilian-bern",
"bernhard": "marie-bernhard",
"bernhatr": "tristan-bernard",
"bernoull": "carl-albrecht-bernoulli",
"berthold": "theodor-berthold",
"bethge": "hans-bethge",
"betsch": "roland-betsch",
"bettelhe": "anton-bettelheim",
"beutler": "margarete-beutler",
"beyerln": "franz-adam-beyerlein",
"bierce": "ambrose-gwinnett-bierce",
"blascoib": "vicente-blasco-ibanez",
"blass": "ernst-blass",
"blaumani": "rdolfs-blaumanis",
"bleifran": "franz-blei",
"bleyfrit": "fritz-bley",
"bloem": "walter-bloem",
"blomberg": "hugo-freiherr-von-blomberg",
"blumauer": "aloys-blumauer",
"blumenha": "wilhelm-blumenhagen",
"bode": "wilhelm-von-bode",
"boehmh": "hans-boehm",
"boettger": "adolf-boettger",
"boie": "margarete-boie",
"bois-rey": "emil-heinrich-du-bois-reymond",
"bolanden": "joseph-eduard-konrad-bischoff",
"bonsels": "waldemar-bonsels",
"booysen": "jens-booysen",
"bourget": "paul-bourget",
"boutet": "frederic-boutet",
"boyesen": "hjalmar-hjorth-boyesen",
"brand": "frederick-schiller-faust",
"brandes": "georg-brandes",
"braune": "rudolf-braune",
"brausewe": "artur-brausewetter",
"bremer": "fredrika-bremer",
"brentanh": "hanny-brentano",
"brillat": "jean-anthelme-brillat-savarin",
"brjussow": "valerij-brjussow",
"broch": "hermann-broch",
"brockden": "charles-brockden-brown",
"bruno": "giordano-bruno",
"bruns": "max-bruns",
"buchanan": "robert-buchanan",
"buelau": "friedrich-von-buelau",
"buergel": "bruno-hans-buergel",
"buol": "maria-buol",
"burrough": "edgar-rice-burroughs",
"busch": "wilhelm-busch",
"busse": "carl-busse",
"busse-he": "hermann-eris-busse",
"byr": "robert-byr",
"calderon": "pedro-caldern-de-la-barca",
"camoes": "luis-vaz-de-cames",
"campe": "joachim-heinrich-campe",
"capek": "karel-capek",
"cardauns": "hermann-cardauns",
"carducci": "giosue-carducci",
"carlyle": "thomas-carlyle",
"carnegie": "andrew-carnegie",
"carossa": "hans-carossa",
"carpente": "edward-carpenter",
"carroll": "charles-lutwidge-dodgson",
"carter": "howard-carter",
"castel": "abbe-castel-de-saint-pierre",
"castell": "willy-lang",
"cazotte": "jacques-cazotte",
"cellini": "benvenuto-cellini",
"chajjam": "omar-chajjam",
"chamberl": "houston-stewart-chamberlain",
"chatrian": "alessandre-chatrian",
"chaucer": "geoffrey-chaucer",
"chlumbrg": "hans-chlumberg",
"christal": "helene-christaller",
"claretie": "jules-claretie",
"clement": "berta-clement",
"colerus": "egmont-colerus",
"collodi": "carlo-collodi",
"coloma": "luis-coloma",
"conscien": "hendrik-conscience",
"coppee": "francois-coppee",
"corinth": "lovis-corinth",
"couperus": "louis-couperus",
"crebillo": "claude-prosper-jolyot-de-crebillon",
"crede": "carl-crede",
"croissan": "anna-croissant-rust",
"croker": "bithia-mary-croker",
"cronau": "rudolf-cronau",
"daiber": "albert-daiber",
"damaschk": "adolf-damaschke",
"dannunzi": "gabriele-dannunzio",
"daporto": "luigi-da-porto",
"darwin": "charles-darwin",
"daudetle": "leon-daudet",
"dauthene": "elisabeth-dauthendey",
"davis": "richard-harding-davis",
"decius": "nikolaus-decius",
"dedenrot": "eugen-hermann-von-dedenroth",
"defoe": "daniel-defoe",
"deledda": "grazia-deledda",
"delitz": "friedrich-delitzsch",
"derschau": "august-egbert-von-derschau",
"dery": "juliane-dery",
"descarte": "rene-descartes",
"detmold": "johann-hermann-detmold",
"deutsch": "lev-grigorievich-deutsch",
"didring": "ernst-didring",
"diebold": "bernhard-diebold",
"diederic": "franz-diederich",
"diener": "bertha-eckstein-diener",
"dimitrof": "georgi-dimitroff",
"dincklag": "friedrich-von-dincklage-campe",
"dine": "willard-huntington-wright",
"dingelst": "franz-von-dingelstedt",
"doermann": "felix-doermann",
"dominik": "hans-dominik",
"donath": "adolph-donath",
"dostojew": "fjodor-michailowitsch-dostojewski",
"douglas": "lord-alfred-douglas",
"dransfel": "hedwig-dransfeld",
"dreyer": "max-dreyer",
"dronke": "ernst-dronke",
"droysen": "johann-gustav-droysen",
"duboc": "charles-edouard-duboc",
"duller": "eduard-duller",
"dumasjun": "alexandre-dumas-der-juengere",
"dumaurie": "george-du-maurier",
"duncker": "dora-duncker",
"duun": "olav-duun",
"eberhard": "august-gottlob-eberhard",
"ebertfr": "friedrich-ebert",
"ebstein": "erich-ebstein",
"echegara": "jose-echegaray",
"edel": "edmund-edel",
"edzardi": "anton-edzardi",
"eeden": "frederik-van-eeden",
"eekhoud": "georges-eekhoud",
"eichacke": "reinhold-eichacker",
"eichrodt": "ludwig-eichrodt",
"einsteic": "carl-einstein",
"eliasber": "alexander-eliasberg",
"elisabet": "kaiserin-elisabeth-von-oesterreich",
"emerson": "ralph-waldo-emerson",
"enderlin": "paul-enderling",
"endrikat": "fred-endrikat",
"engele": "eduard-engel",
"enking": "ottomar-enking",
"eoetvoes": "josef-von-eoetvoes",
"erasmus": "erasmus-von-rotterdam",
"ertl": "emil-ertl",
"ettlinge": "josef-moritz-ettlinger",
"eulenbur": "philipp-fuerst-zu-eulenburg-hertefeld",
"eversfra": "franz-evers",
"ey": "luise-ey",
"farina": "salvatore-farina",
"farrere": "claude-farrere",
"fechenba": "felix-fechenbach",
"federn": "karl-federn",
"felde": "johannes-kaltenboeck",
"feuchter": "ernst-von-feuchtersleben",
"feuerbaa": "anselm-feuerbach",
"feuerbac": "paul-johann-anselm-ritter-von-feuerbach",
"feuerbal": "ludwig-feuerbach",
"figner": "wera-figner",
"fischart": "johann-fischart",
"fischerw": "wilhelm-fischer",
"fischeww": "wilhelm-fischer-2",
"fitzgera": "f-scott-fitzgerald",
"flaischl": "caesar-flaischlen",
"fletcher": "joseph-smith-fletcher",
"floerick": "kurt-floericke",
"floerkeh": "hanns-floerke",
"foerstef": "friedrich-foerster",
"fogazzar": "antonio-fogazzaro",
"forbesmo": "irene-anna-maria-magdalena-gisela-gabriele-forbes-mosse",
"forsterj": "john-forster",
"franka": "anne-frank",
"frankljo": "john-franklin",
"franzign": "ignaz-franz-1",
"franzjos": "franz-joseph-von-oesterreich",
"freeman": "richard-austin-freeman",
"freissle": "ernst-wolfgang-freissler",
"friedlae": "ludwig-friedlaender",
"friedlas": "salomon-friedlaender",
"friedlhu": "hugo-friedlaender",
"frisch": "efraim-frisch",
"frobeniu": "leo-frobenius",
"froehlia": "abraham-emanuel-froehlich",
"frontinu": "sextus-julius-frontinus",
"fuchs-li": "robert-fuchs-liska",
"fuerst": "artur-fuerst",
"fvhausen": "friedrich-von-hausen",
"gaboriau": "emile-gaboriau",
"gagern": "friedrich-frhr-von-gagern",
"galen": "philipp-galen",
"gall": "louise-von-gall",
"galswort": "john-galsworthy",
"gangl": "josef-gangl",
"garschin": "wsewolod-michailowitsch-garschin",
"geibelp": "peter-geibel",
"geissler": "max-geissler",
"gelpke": "august-heinrich-christian-gelpke",
"genee": "rudolf-genee",
"gengenba": "pamphilus-gengenbach",
"gerharda": "adolph-von-gerhardt",
"gesell": "silvio-gesell",
"gfeller": "simon-gfeller",
"gide": "andre-gide",
"gildemei": "otto-gildemeister",
"giraudou": "jean-giraudoux",
"giseke": "robert-giseke",
"glaser": "adolf-glaser",
"glaspell": "susan-glaspell",
"glass": "luise-glass",
"gobineau": "arthur-de-gobineau",
"goecking": "leopold-friedrich-guenther-von-goeckingk",
"goedicke": "elisabeth-goedicke",
"goerres": "joseph-von-goerres",
"goetheke": "katharina-elisabetha-goethe",
"goett": "emil-servatius-goett",
"goldmann": "otto-goldmann",
"goldsmit": "oliver-goldsmith",
"goltz": "bogumil-goltz",
"gontscha": "iwan-gontscharow",
"gorki": "maxim-gorki",
"gothein": "marie-luise-gothein",
"gottscha": "rudolf-carl-von-gottschall",
"gracian": "baltasar-gracin-y-morales",
"grad": "max-grad",
"graeser": "erdmann-graeser",
"grahame": "kenneth-grahame",
"grasberg": "hans-grasberger",
"grazie": "marie-eugenie-delle-grazie",
"green": "anna-katherine-green",
"greif": "martin-greif",
"greiner": "leo-greiner",
"greinz": "rudolf-heinrich-greinz",
"greville": "henry-greville",
"greyerzo": "otto-von-greyerz",
"grisebac": "eduard-grisebach",
"groddeck": "georg-groddeck",
"groller": "balduin-groller",
"groner": "auguste-groner",
"grosse": "julius-grosse",
"grosseka": "karl-grosse",
"grossh": "hans-gross",
"grubeaw": "august-wilhelm-grube-2",
"gruenbau": "fritz-gruenbaum",
"grunert": "carl-grunert",
"gumppenb": "hanns-theodor-wilhelm-freiherr-von-gumppenberg",
"gurlitt": "cornelius-gurlitt",
"gutzkow": "karl-gutzkow",
"haarhaus": "julius-r-haarhaus",
"hadwiger": "victor-hadwiger",
"haeberli": "karl-ludwig-haeberlin",
"hagen": "august-hagen",
"hammerst": "hans-freiherr-von-hammerstein-equord",
"hamsun": "knut-hamsun",
"handl": "willi-handl",
"hanried": "norbert-hanrieder-2",
"hardt": "friedrich-wilhelm-ernst-hardt",
"harland": "henry-harland",
"harris": "frank-harris",
"harsdoer": "georg-philipp-harsdoerfer",
"hasek": "jaroslav-haek",
"hawthorn": "nathaniel-hawthorne",
"hedin": "sven-hedin",
"heilboad": "adolf-heilborn",
"heimburg": "berta-behrens",
"heineth": "thomas-theodor-heine",
"helmhltz": "hermann-ludwig-ferdinand-von-helmholtz",
"hennings": "emmy-hennings",
"henrich": "hedwig-henrich-wilhelmi",
"herold": "franz-herold",
"hesse": "hermann-hesse",
"hill": "headon-hill",
"hirschbe": "leopold-hirschberg",
"hirschfe": "magnus-hirschfeld",
"hoerner": "herbert-von-hoerner",
"hofbauer": "josef-hofbauer",
"holek": "wenzel-holek",
"holtze": "friedrich-holtze",
"hruschka": "annie-hruschka",
"hume": "david-hume",
"hymans": "henri-hymans",
"iffland": "august-wilhelm-iffland",
"ingram": "john-kells-ingram",
"jacobi": "johann-georg-jacobi",
"jaegerh": "hans-henrik-jger",
"jammes": "francis-jammes",
"janitsch": "maria-janitschek",
"jens": "ina-jens",
"jerrold": "douglas-jerrold",
"jhering": "rudolf-von-ihering",
"jirasek": "alois-jirsek",
"jokai": "maurus-jkai",
"jonson": "ben-jonson",
"jungstil": "heinrich-stilling",
"kabel": "walther-kabel",
"kafka": "franz-kafka",
"kahane": "arthur-kahane",
"kalckreu": "wolf-graf-von-kalckreuth",
"kalisch": "david-kalisch",
"kane": "elisha-kent-kane",
"kant": "immanuel-kant",
"kapffess": "franziska-von-kapff-essenther",
"kapp": "friedrich-kapp",
"kapri": "rudolf-von-kapri",
"karlin": "alma-karlin",
"karlweis": "carl-karlweis",
"karrillo": "adam-karrillon",
"kastein": "josef-kastein",
"katscher": "leopold-katscher",
"kaulbach": "hermann-kaulbach",
"kautsky": "karl-kautsky",
"keats": "john-keats",
"keim": "franz-keim",
"keller": "gottfried-keller",
"kellera": "augustin-keller",
"kellerma": "bernhard-kellermann",
"kellerp": "paul-keller",
"kempner": "friederike-kempner",
"kennan": "george-kennan",
"kern": "maximilian-kern",
"kernerj": "justinus-kerner",
"kernerjg": "johann-georg-kerner",
"kernerma": "marie-kerner",
"kernstoc": "ottokar-kernstock",
"kerr": "alfred-kerr",
"kessler": "harry-kessler",
"key": "ellen-key",
"keyserlg": "eduard-graf-von-keyserling",
"keyserlh": "graf-hermann-keyserling",
"kielland": "alexander-lange-kielland",
"kierkega": "sren-kierkegaard",
"kind": "johann-friedrich-kind",
"kinkel": "gottfried-kinkel",
"kinkeljo": "johanna-kinkel",
"kipling": "rudyard-kipling",
"kirchbac": "wolfgang-kirchbach",
"kirchhoh": "hans-wilhelm-kirchhof",
"kisch": "egon-erwin-kisch",
"klee": "paul-klee",
"kleinern": "ernst-klein",
"kleinfer": "johann-kleinfercher",
"kleist": "heinrich-von-kleist",
"klemm": "johanna-klemm",
"klepper": "jochen-klepper",
"klingema": "august-klingemann",
"klinger": "friedrich-maximilian-klinger",
"klopstoc": "friedrich-gottlieb-klopstock",
"klosterm": "carl-klostermann",
"kluge": "kurt-kluge",
"klutscha": "heinrich-w-klutschak",
"knigge": "adolph-freiherr-knigge",
"kobbe": "theodor-von-kobbe",
"kobell": "franz-ritter-von-kobell",
"koch": "henny-koch",
"koche": "ernst-koch",
"kock": "charles-paul-de-kock",
"koehler": "ludwig-koehler",
"koelsch": "adolf-koelsch",
"koenig": "alma-johanna-koenig",
"koenige": "eberhard-koenig",
"koepke": "rudolf-anastasius-koepke",
"koeppene": "edlef-koeppen",
"koerner": "karl-theodor-koerner",
"koestlin": "julius-koestlin",
"kohlraus": "robert-kohlrausch",
"kolbe": "leopold-kolbe",
"kolping": "adolf-kolping",
"kompert": "leopold-kompert",
"konfuziu": "konfuzius",
"konopnic": "marya-konopnicka",
"kopisch": "august-kopisch",
"kornfeld": "paul-kornfeld",
"korolenk": "wladimir-galaktionovich-korolenko",
"kortum": "dr-med-carl-arnold-kortum",
"kosegart": "gotthard-ludwig-kosegarten",
"kossak": "karl-ludwig-ernst-kossak",
"kotzebue": "august-von-kotzebue",
"kraffteb": "richard-von-krafft-ebing",
"kraftr": "robert-kraft",
"krag": "thomas-krag",
"kralik": "richard-von-kralik",
"kramer": "heinrich-kramer",
"kraszews": "jzef-ignacy-kraszewski",
"kraus": "karl-kraus",
"krauss": "friedrich-solomon-krauss",
"kraze": "friederike-henriette-kraze",
"kreis": "julius-kreis",
"kretzer": "max-kretzer",
"kroeger": "timm-kroeger",
"kronoff": "frida-hummel",
"kropotki": "pjotr-alexejewitsch-kropotkin",
"kruegerh": "hermann-anders-krueger",
"kruse": "heinrich-kruse",
"krutter": "franz-krutter",
"krylow": "iwan-andrejewitsch-krylow",
"krzyzano": "otfried-krzyzanowski",
"kubitsch": "rudolf-kubitschek",
"kuegelgn": "wilhelm-von-kuegelgen",
"kuehne": "ferdinand-gustav-kuehne",
"kuehnelt": "richard-kuehnelt",
"kuekelha": "heinz-kuekelhaus",
"kuelpe": "frances-kuelpe",
"kuelz": "ludwig-kuelz",
"kuernber": "ferdinand-kuernberger",
"kugler": "franz-kugler",
"kuh": "anton-kuh",
"kuhn": "gottlieb-jakob-kuhn",
"kurz": "hermann-kurz",
"kurzi": "isolde-kurz",
"kusmin": "michail-kusmin",
"kussmaul": "adolf-kussmaul",
"kvwuerzb": "konrad-von-wuerzburg",
"kyber": "manfred-kyber",
"labe": "louze-labe",
"labrete": "alice-cherbonnel",
"lachmann": "hedwig-lachmann",
"lachmanv": "volkmar-lachmann",
"laclos": "pierre-ambroise-francois-choderlos-de-laclos",
"lafargue": "paul-lafargue",
"lafayett": "marie-madeleine-la-fayette",
"lafonta": "august-lafontaine",
"lagerloe": "selma-lagerloef",
"lamartin": "alphonse-de-prat-lamartine",
"lambrech": "nanny-lambrecht",
"lampe": "friedo-lampe",
"landauer": "gustav-landauer",
"landor": "walter-savage-landor",
"landsbrg": "artur-landsberger",
"langbehn": "julius-langbehn",
"langbein": "august-friedrich-ernst-langbein",
"langef": "friedrich-albert-lange",
"langeh": "helene-lange",
"langens": "paul-langenscheidt",
"langewie": "wilhelm-langewiesche",
"langhein": "karl-heinrich-von-lang",
"laroche": "maria-sophie-von-la-roche-geb-gutermann",
"lasale": "antoine-de-la-sale",
"lasker": "else-lasker-schueler",
"lasssalle": "ferdinand-lassalle",
"latzko": "andreas-latzko",
"lauffer": "otto-lauffer",
"lawrencd": "d-h-lawrence",
"lawrence": "thomas-edward-lawrence",
"leadbeat": "charles-webster-leadbeater",
"leffler": "anne-charlotte-leffler",
"leifhelm": "hans-leifhelm",
"leipzige": "leon-leipziger",
"leitner": "maria-leitner",
"leixner": "otto-von-leixner",
"lemonnie": "camille-lemonnier",
"lenclos": "ninon-de-lenclos",
"leppin": "paul-leppin",
"lequeux": "william-le-queux",
"lerbs": "karl-lerbs",
"leutelt": "gustav-leutelt",
"levertin": "oskar-levertin",
"levett": "oswald-levett",
"lewes": "george-henry-lewes",
"lewis": "sinclair-lewis",
"lhotzky": "heinrich-lhotzky",
"libai": "li-bai",
"lichtwar": "alfred-lichtwark",
"lichtwer": "magnus-gottfried-lichtwer",
"lieberma": "max-liebermann",
"liebknec": "wilhelm-liebknecht",
"liebstoe": "hans-liebstoeckl",
"lienhard": "friedrich-lienhard",
"lilienca": "adda-freifrau-von-liliencron",
"lindaup": "paul-lindau",
"lindener": "michael-lindener",
"linguet": "simon-nicolas-henri-linguet",
"lipsius": "maria-lipsius",
"locke": "john-locke",
"loerke": "oskar-loerke",
"loewenfe": "leopold-loewenfeld",
"longfell": "henry-wadsworth-longfellow",
"loos": "adolf-loos",
"loti": "pierre-loti",
"louvet": "jean-baptiste-louvet",
"louys": "pierre-lous",
"lucka": "emil-lucka",
"ludwig2": "ludwig-ii-von-bayern",
"ludwige": "emil-ludwig",
"lux": "joseph-august-lux",
"mader": "friedrich-wilhelm-mader",
"maeterli": "maurice-maeterlinck",
"magnus": "erwin-magnus",
"mallarme": "stephane-mallarme",
"malot": "hector-malot",
"malss": "karl-balthasar-malss",
"maltzahe": "elisabeth-von-maltzahn",
"maltzan": "heinrich-von-maltzan",
"mannh": "heinrich-mann",
"mannk": "klaus-heinrich-thomas-mann",
"manueln": "niklaus-manuel",
"marguerv": "victor-margueritte",
"margvalo": "margaretha-von-valois",
"mariathe": "maria-theresia-von-oesterreich",
"mariefra": "marie-de-france",
"marni": "jeanne-marni",
"marryat": "frederick-marryat",
"marryatf": "florence-marryat",
"martens": "kurt-martens",
"marti": "hugo-marti",
"masaryk": "tom-garrigue-masaryk",
"maximili": "maximilian-i-von-habsburg",
"may": "karl-may",
"mehring": "franz-mehring",
"meissnea": "august-gottlieb-meissner",
"meissner": "alfred-meissner",
"mendelba": "felix-mendelssohn-bartholdy",
"mendes": "catulle-mendes",
"mentzer": "johann-mentzer",
"meredith": "george-meredith",
"mereschk": "dmitri-sergejewitsch-mereschkowski",
"merian": "matthaeus-merian",
"messer": "max-messer",
"messner": "josef-messner",
"meyerj": "johann-meyer",
"meyermer": "theodor-meyer-merian",
"meyr": "melchior-meyr",
"meysenbu": "malwida-von-meysenbug",
"michaeli": "karin-michalis",
"michelet": "jules-michelet",
"mickiewi": "adam-mickiewicz",
"milow": "stephan-von-millenkovich",
"mirbeau": "octave-mirbeau",
"modersoh": "paula-modersohn-becker",
"moebius": "paul-julius-moebius",
"mohrmax": "max-mohr",
"molina": "tirso-de-molina",
"mongdsi": "mong-ds",
"montaign": "michel-de-montaigne",
"montanus": "martin-montanus",
"montesqu": "montesquieu",
"montgome": "malla-montgomery-silfverstolpe",
"mooreg": "george-moore",
"mooret": "thomas-moore",
"morgenst": "christian-morgenstern",
"morgenth": "hans-morgenthaler",
"morier": "james-morier",
"moritz": "karl-philipp-moritz",
"morold": "max-von-millenkovich",
"morrison": "arthur-morrison",
"moschero": "johann-hans-michael-moscherosch",
"mosen": "julius-mosen",
"moser": "ernst-moser",
"muehlbac": "luise-muehlbach",
"muellenh": "karl-muellenhoff",
"muellera": "adam-mueller-guttenbrunn",
"muetzelb": "adolf-muetzelburg",
"muhammad": "prophet-mohammed",
"mulford": "prentice-mulford",
"multerer": "hans-multerer",
"mundt": "theodor-mundt",
"musil": "robert-musil",
"nathusiu": "marie-nathusius",
"natorp": "paul-natorp",
"naumann": "friedrich-naumann",
"neander": "joachim-neander",
"neumannk": "karl-eugen-neumann",
"neumayer": "georg-von-neumayer",
"nicolaip": "philipp-nicolai",
"niemanna": "august-wilhelm-otto-niemann",
"nighting": "florence-nightingale",
"nohl": "ludwig-nohl",
"nordau": "max-nordau",
"nordensk": "otto-nordenskjoeld",
"nordhaus": "richard-nordhausen",
"norris": "frank-norris",
"nostitz": "helene-nostitz",
"nowak": "karl-friedrich-nowak",
"obst": "arthur-obst",
"oehlensc": "adam-gottlob-oehlenschlaeger",
"oeser": "hermann-oeser",
"oetker": "august-oetker",
"okakura": "kakuzo-okakura",
"olden": "balder-olden",
"olfers": "marie-von-olfers",
"oliphant": "margaret-oliphant",
"ompteda": "georg-freiherr-von-ompteda",
"opitz": "martin-opitz",
"oppenhei": "edward-phillips-oppenheim",
"orzeszko": "eliza-orzeszkowa",
"ostwald": "wilhelm-ostwald",
"ostwaldh": "hans-ostwald",
"ottwalt": "ernst-ottwalt",
"paalzow": "henriette-paalzow",
"paatz": "herbert-paatz",
"pajeken": "friedrich-joachim-pajeken",
"pannwitz": "max-pannwitz",
"panteniu": "theodor-hermann-pantenius",
"pappenhe": "bertha-pappenheim",
"paquet": "alfons-paquet",
"parabell": "ferdinand-grautoff",
"pascal": "blaise-pascal",
"pastor": "willy-pastor",
"paula": "adolf-paul",
"paulig": "gustav-pauli",
"paulus": "eduard-paulus",
"peary": "robert-edwin-peary",
"pellico": "silvio-pellico",
"perezdeh": "ginez-perez-de-hita",
"perezgal": "benito-perez-galds",
"perfall": "anton-von-perfall",
"perfallk": "karl-von-perfall",
"petoefi": "sndor-petoefi",
"petroniu": "titus-petronius",
"pfeiffer": "ida-pfeiffer",
"pfeiffgw": "georg-wilhelm-pfeiffer",
"philippe": "charles-louis-philippe",
"piccolom": "alessandro-piccolomini",
"pichler": "adolf-pichler",
"pierson": "karoline-pierson",
"pirandel": "luigi-pirandello",
"placzek": "siegfried-placzek",
"plautus": "titus-maccius-plautus",
"poeck": "wilhelm-poeck",
"poetzl": "eduard-poetzl",
"ponten": "josef-ponten",
"pontoppi": "henrik-pontoppidan",
"poradows": "marguerite-poradowska",
"poritzky": "jakob-elias-poritzky",
"praetori": "johannes-praetorius",
"prellwit": "gertrud-prellwitz",
"prevostm": "marcel-prevost",
"prinzhor": "hans-prinzhorn",
"proehle": "heinrich-proehle",
"proelss": "johannes-proelss",
"prosch": "peter-prosch",
"proust": "marcel-proust",
"prutz": "robert-eduard-prutz",
"przerwa": "kazimierz-przerwa-tetmajer",
"putlitz": "gustav-heinrich-gans-zu-putlitz",
"puttkamr": "alberta-von-puttkamer",
"queri": "georg-queri",
"quevedo": "don-francisco-gomez-de-quevedo",
"quidde": "ludwig-quidde",
"quincey": "thomas-de-quincey",
"radbruch": "gustav-radbruch",
"radek": "karl-radek",
"ranke": "leopold-von-ranke",
"rankef": "friedrich-ranke",
"rankjo": "josef-rank",
"rathenau": "walther-rathenau",
"ratzel": "friedrich-ratzel",
"raumer": "friedrich-ludwig-georg-von-raumer",
"raupach": "ernst-benjamin-salomo-raupach",
"ravendro": "karl-doehring",
"rebhun": "paul-rebhun-rebhuhn",
"rebmann": "georg-friedrich-rebmann",
"reck": "fritz-reck-mallaczewen",
"regnier": "henri-de-regnier",
"reichena": "rudolf-reichenau",
"reinhard": "luise-reinhardt",
"reiser": "hans-reiser",
"reissner": "larissa-reissner",
"reitzel": "robert-reitzel",
"renan": "ernest-renan",
"reusch": "rudolf-reusch",
"revel": "hugo-alphonso-revel",
"reymont": "wadysaw-stanisaw-reymont",
"rheinhar": "emil-alphons-rheinhardt",
"richterj": "joseph-richter",
"richterl": "ludwig-richter",
"richthof": "manfred-von-richthofen",
"ring": "max-ring",
"rist": "johann-rist",
"ritter": "johann-wilhelm-ritter",
"rochlitz": "friedrich-rochlitz",
"rod": "edouard-rod",
"rodaroda": "sndor-friedrich-rosenfeld",
"rodenbac": "georges-rodenbach",
"rodenber": "julius-rodenberg",
"roehle": "reinhard-roehle",
"roelvaag": "ole-edvart-rlvaag",
"roessler": "carl-ressner",
"rollandr": "romain-rolland",
"roquette": "otto-roquette",
"rose": "felicitas-rose",
"rosegghl": "hans-ludwig-rosegger",
"rosenhay": "paul-rosenhayn",
"rosenkra": "palle-adam-vilhelm-rosenkrantz",
"rost": "johann-christoph-rost",
"rostand": "edmond-rostand",
"roth": "joseph-roth",
"rothplet": "anna-rothpletz",
"rudolfvh": "rudolf-kronprinz-von-oesterreich-ungarn",
"ruederer": "josef-ruederer",
"rumi": "dschalal-ad-din-muhammad-rumi",
"rumohr": "karl-friedrich-von-rumohr",
"ruppersb": "albert-ruppersberg",
"ruppius": "otto-ruppius",
"sack": "gustav-sack",
"sade": "donatien-alphonse-francois-de-sade",
"sadi": "musliheddin-sadi",
"sailerj": "johann-michael-sailer",
"saint-si": "louis-de-rouvroy-duc-de-saint-simon",
"salburg": "edith-graefin-salburg",
"salgari": "emilio-salgari",
"salome": "lou-andreas-salome",
"salomoer": "erich-salomon",
"salus": "hugo-salus",
"samain": "albert-samain",
"santayan": "jorge-augustn-nicols-ruiz-de-santayan",
"sapper": "agnes-sapper",
"sauerlan": "max-sauerlandt",
"scarron": "paul-scarron",
"schack": "adolf-friedrich-von-schack",
"schaefal": "albrecht-schaeffer",
"schaefer": "wilhelm-schaefer",
"schaffne": "jakob-schaffner",
"schanz": "frida-schanz",
"scharlin": "henrik-scharling",
"schaukal": "richard-von-schaukal",
"schaumbe": "heinrich-schaumberger",
"scheerba": "paul-scheerbart",
"schefer": "leopold-schefer",
"scheidema": "philipp-scheidemann",
"scheler": "max-scheler",
"schellic": "caroline-schelling",
"schenken": "max-von-schenkendorf",
"scherer": "wilhelm-scherer",
"schickel": "rene-schickele",
"schieber": "anna-schieber",
"schihuth": "hans-schiebelhuth",
"schillcg": "carl-georg-schillings",
"schillin": "gustav-schilling",
"schirges": "georg-gottlieb-schirges",
"schirmac": "kaethe-schirmacher",
"schiroka": "alfred-schirokauer",
"schlaf": "johannes-schlaf",
"schlegld": "dorothea-schlegel",
"schlenth": "paul-schlenther",
"schliema": "heinrich-schliemann",
"schliepm": "hans-schliepmann",
"schlippe": "gabriele-freifrau-von-schlippenbach",
"schloegl": "friedrich-schloegl",
"schmitzo": "oscar-adolf-hermann-schmitz",
"schmolle": "gustav-schmoller",
"schneidt": "thekla-schneider",
"schoell": "adolf-schoell",
"schoenhe": "karl-schoenherr",
"schoenw": "franz-xaver-von-schoenwerth",
"schorn": "adelheid-von-schorn",
"schrebem": "moritz-schreber",
"schreber": "daniel-paul-schreber",
"schreibe": "clara-schreiber",
"schreyvo": "joseph-schreyvogel",
"schudt": "jacob-schudt",
"schueler": "gustav-schueler",
"schulzea": "friedrich-august-schulze",
"schulzsm": "bernhardine-schulze-smidt",
"schumact": "tony-schumacher",
"schumanr": "robert-schumann",
"schummel": "johann-gottlieb-schummel",
"schupp": "johannes-martin-schupp",
"schwarze": "annemarie-schwarzenbach",
"schwarzg": "georg-schwarz",
"schweich": "robert-schweichel",
"schwerio": "otto-schwerin",
"schwob": "marcel-schwob",
"scottf": "robert-falcon-scott",
"seeckt": "hans-von-seeckt",
"seidlw": "walter-seidl",
"seitz": "robert-seitz",
"serner": "walter-serner",
"servaes": "franz-servaes",
"seton": "ernest-thompson-seton",
"sevigne": "marie-de-rabutin-chantal-marquise-de-sevigne",
"shelley": "mary-shelley",
"shelleyp": "percy-bysshe-shelley",
"siber": "jules-siber",
"siebe": "josephine-siebe",
"sievekin": "amalie-sieveking",
"skjoldbo": "johan-skjoldborg",
"skowronf": "fritz-skowronnek",
"skowronr": "richard-skowronnek",
"skram": "amalie-skram",
"sling": "paul-schlesinger",
"smiles": "samuel-smiles",
"smollett": "tobias-smollett",
"soehle": "karl-soehle",
"sohnrey": "heinrich-sohnrey",
"soldan": "wilhelm-gottlieb-soldan",
"sologub": "fjodor-kusmitsch-teternikow",
"sophar": "moritz-wilhelm-sophar",
"southey": "robert-southey",
"speckman": "diedrich-speckmann",
"spector": "mordecai-spector",
"spiero": "heinrich-spiero",
"spinoza": "baruch-de-spinoza",
"spohr": "louis-spohr",
"sprenger": "jakob-sprenger",
"ssymank": "paul-ssymank",
"stach": "ilse-von-stach",
"stacpool": "henry-de-vere-stacpoole",
"stael": "frau-von-stal",
"stanley": "henry-morton-stanley",
"stavenhg": "fritz-stavenhagen",
"stefbelg": "stephanie-von-belgien",
"steffen": "gustaf-f-steffen",
"steffens": "henrich-steffens",
"stegeman": "hermann-stegemann",
"stehr": "hermann-stehr",
"steinhau": "heinrich-steinhausen",
"steinvom": "heinrich-friedrich-karl-reichsfreiherr-vom-und-zum-stein",
"sternado": "adolf-stern",
"sternber": "leo-sternberg",
"sternhei": "carl-sternheim",
"stettenh": "julius-stettenheim",
"stieler": "karl-stieler",
"stier": "adelheid-stier",
"stilgeba": "edward-stilgebauer",
"stona": "maria-stona",
"storch": "ludwig-storch",
"straparo": "giovanni-francesco-straparola",
"stratz": "rudolf-stratz",
"strauss": "david-friedrich-strauss",
"streckfua": "adolf-streckfuss",
"stresema": "gustav-stresemann",
"strobl": "karl-hans-strobl",
"stuerzer": "rudolf-stuerzer",
"sturm": "julius-sturm",
"sturz": "helfrich-peter-sturz",
"sutermei": "otto-sutermeister",
"svensson": "jn-svensson",
"svevo": "italo-svevo",
"swinburn": "charles-swinburne",
"sydow": "margarete-von-sydow",
"sylva": "elisabeth-von-rumaenien",
"tacitus": "publius-cornelius-tacitus",
"tagore": "rabindranath-tagore",
"tanera": "carl-tanera",
"tartarug": "ubald-tartaruga",
"taschenb": "ernst-ludwig-taschenberg",
"taura": "august-peters",
"tegner": "esaias-tegner",
"telmann": "konrad-telmann",
"temme": "hubertus-temme",
"tennyson": "alfred-tennyson",
"theden": "dietrich-theden",
"theis": "hans-theis",
"theresba": "therese-von-bayern",
"theuriet": "andre-theuriet",
"thode": "heinrich-thode",
"thomasvk": "thomas-von-kempen",
"thoresen": "magdalene-thoresen",
"tillier": "claude-tillier",
"toepffer": "rudolf-toepffer",
"tolstiak": "alexei-konstantinowitsch-tolstoi",
"tolstoia": "alexei-nikolajewitsch-tolstoi",
"tovote": "heinz-tovote",
"treitsch": "heinrich-von-treitschke",
"trelawny": "edward-john-trelawny",
"treller": "franz-treller",
"triller": "daniel-wilhelm-triller",
"trinius": "august-trinius",
"trojan": "johannes-trojan",
"trotzki": "leo-trotzki",
"ubell": "hermann-ubell",
"udet": "ernst-udet",
"ule": "ernst-ule",
"ulrichs": "karl-heinrich-ulrichs",
"undset": "sigrid-undset",
"ungern": "alexander-von-ungern-sternberg",
"valentin": "karl-valentin",
"verlaine": "paul-verlaine",
"viebig": "clara-viebig",
"villinge": "hermine-villinger",
"vleuten": "carl-ferdinand-van-vleuten",
"voegtlin": "adolf-voegtlin",
"voigtw": "wilhelm-voigt",
"voll": "karl-voll",
"vollrat": "heinrich-vollrat-schumacher",
"voltaire": "francois-marie-arouet-de-voltaire",
"vorlaend": "karl-vorlaender",
"vossjul": "julius-von-voss",
"vrchlick": "jaroslav-vrchlick",
"vulpius": "christian-august-vulpius",
"wachenhu": "hans-wachenhusen",
"wagnerhe": "hermann-wagner-2",
"waldeck": "heinrich-suso-waldeck",
"weissecf": "christian-felix-weisse",
"weissfer": "weiss-ferdl",
"willkomm": "ernst-adolf-willkomm",
"wiseman": "nicholas-patrick-stephen-wiseman",
"zahn": "ernst-zahn",
"zweig": "stefan-zweig"
}
}
qcr2661cutm6okoliz9zsdt5nec8rz7
Template:Projekt-gutenberg.org/config.json
10
175621
743899
743822
2026-05-22T13:52:50Z
PerfektesChaos
18104
2026-05-21
743899
json
application/json
{
"suite": "projekt-gutenberg.org",
"serial": "2026-05-21",
"item": 0,
"site": "https://projekt-gutenberg.org/",
"a": {
"slice": "authors/"
},
"w": {
"slice": "books/"
},
"n": {
"slice": "chapter/"
},
"err": {
"0json": "JSON fehlt",
"0site": "Website fehlt",
"0a": "Bezeichner a= fehlt",
"0hash": "hash fehlt",
"redir": "Weiterleitung undefiniert",
"invalid": "Ungültiger Bezeichner",
"unknown": "Unbekannter Bezeichner",
"cat": "Wikipedia:Vorlagenfehler/Vorlage:projekt-gutenberg.org"
}
}
sgvj8f4oqzvrn9k05u0y5gksluj98kq
Wikipedia:Template messages
4
175643
743898
2026-05-22T13:52:36Z
~2026-30728-52
74101
Redirected page to [[Wikipedia:Template index]]
743898
wikitext
text/x-wiki
#REDIRECT [[Wikipedia:Template index]]
qn2j5adwirjss43q1vmcx3uvaouetyv
Talk:Page118
1
175644
743903
2026-05-22T13:59:38Z
~2026-23062-17
73557
/* new subject */ new section
743903
wikitext
text/x-wiki
== new subject ==
normal edit [[Special:Contributions/~2026-23062-17|~2026-23062-17]] ([[User talk:~2026-23062-17|talk]]) 13:59, 22 May 2026 (UTC)
02z4b50odqiem55rug2cihegacwb499
743904
743903
2026-05-22T14:00:49Z
~2026-23062-17
73557
showcaptcha
743904
wikitext
text/x-wiki
== new subject ==
normal edit [[Special:Contributions/~2026-23062-17|~2026-23062-17]] ([[User talk:~2026-23062-17|talk]]) 13:59, 22 May 2026 (UTC)
:af edit [[Special:Contributions/~2026-23062-17|~2026-23062-17]] ([[User talk:~2026-23062-17|talk]]) 14:00, 22 May 2026 (UTC)
lua8rx2hbr5dli04syx7m2c4sv6zhoe
743905
743904
2026-05-22T14:01:52Z
~2026-23062-17
73557
/* another new subject */ new section
743905
wikitext
text/x-wiki
== new subject ==
normal edit [[Special:Contributions/~2026-23062-17|~2026-23062-17]] ([[User talk:~2026-23062-17|talk]]) 13:59, 22 May 2026 (UTC)
:af edit [[Special:Contributions/~2026-23062-17|~2026-23062-17]] ([[User talk:~2026-23062-17|talk]]) 14:00, 22 May 2026 (UTC)
== another new subject ==
normal edit [[Special:Contributions/~2026-23062-17|~2026-23062-17]] ([[User talk:~2026-23062-17|talk]]) 14:01, 22 May 2026 (UTC)
0woj8lx9xo5r33mlna0ys9eqshkqlnw
743908
743905
2026-05-22T14:04:17Z
~2026-23062-17
73557
/* another new subject */ Reply
743908
wikitext
text/x-wiki
== new subject ==
normal edit [[Special:Contributions/~2026-23062-17|~2026-23062-17]] ([[User talk:~2026-23062-17|talk]]) 13:59, 22 May 2026 (UTC)
:af edit [[Special:Contributions/~2026-23062-17|~2026-23062-17]] ([[User talk:~2026-23062-17|talk]]) 14:00, 22 May 2026 (UTC)
== another new subject ==
normal edit [[Special:Contributions/~2026-23062-17|~2026-23062-17]] ([[User talk:~2026-23062-17|talk]]) 14:01, 22 May 2026 (UTC)
:[https://foobar.com] [[Special:Contributions/~2026-23062-17|~2026-23062-17]] ([[User talk:~2026-23062-17|talk]]) 14:04, 22 May 2026 (UTC)
ql0n0d9wi6948lgt4g698l03rsgdtex
Talk:AAC
1
175645
743906
2026-05-22T14:03:35Z
~2026-30734-12
74102
showcaptcha
743906
wikitext
text/x-wiki
== New subject ==
af edit [[Special:Contributions/~2026-30734-12|~2026-30734-12]] ([[User talk:~2026-30734-12|talk]]) 14:03, 22 May 2026 (UTC)
ih7iapjgljry5or213duifvwzamv4u1
743907
743906
2026-05-22T14:04:00Z
~2026-30734-12
74102
/* New subject */ Reply
743907
wikitext
text/x-wiki
== New subject ==
af edit [[Special:Contributions/~2026-30734-12|~2026-30734-12]] ([[User talk:~2026-30734-12|talk]]) 14:03, 22 May 2026 (UTC)
:normal edit [[Special:Contributions/~2026-30734-12|~2026-30734-12]] ([[User talk:~2026-30734-12|talk]]) 14:04, 22 May 2026 (UTC)
t7qwolee5ixr9xptabqkvzog6keh8cg
User:Iiirxs/Template:Infobox person
2
175646
743912
2026-05-22T19:09:38Z
Iiirxs
49827
Created page with "{{Infobox | above = {{{name|{{PAGENAME}}}}} | image = {{{image|{{#if:{{#property:P18}}|[[File:{{#property:P18}}|frameless|upright=1|alt=]]}}}}} | caption = {{{caption|}}} | label1 = Born | data1 = {{{birth_date|{{#property:P569}}}}} <br> {{{birth_place|{{#property:P19}}}}} | label2 = Died | data2 = {{{death_date|{{#property:P570}}}}} <br> {{{death_place|{{#property:P20}}}}} | label3 = Occupation | data3 = {{{occupation|{{#property:P106}}}}} | label4 = Nationality | data4..."
743912
wikitext
text/x-wiki
{{Infobox
| above = {{{name|{{PAGENAME}}}}}
| image = {{{image|{{#if:{{#property:P18}}|[[File:{{#property:P18}}|frameless|upright=1|alt=]]}}}}}
| caption = {{{caption|}}}
| label1 = Born
| data1 = {{{birth_date|{{#property:P569}}}}} <br> {{{birth_place|{{#property:P19}}}}}
| label2 = Died
| data2 = {{{death_date|{{#property:P570}}}}} <br> {{{death_place|{{#property:P20}}}}}
| label3 = Occupation
| data3 = {{{occupation|{{#property:P106}}}}}
| label4 = Nationality
| data4 = {{{nationality|{{#property:P27}}}}}
| label5 = Education
| data5 = {{{alma_mater|{{#property:P69}}}}}
| label6 = Spouse
| data6 = {{{spouse|{{#property:P26}}}}}
| label7 = Children
| data7 = {{{children|{{#property:P40}}}}}
| label8 = Awards
| data8 = {{{awards|{{#property:P166}}}}}
| label9 = Website
| data9 = {{{website|{{#property:P856}}}}}
}}
74k8p1lok0dmptf5tegnxlbshglhx8b
743914
743912
2026-05-22T20:29:58Z
Iiirxs
49827
743914
wikitext
text/x-wiki
{{Infobox
| above = {{{name|{{PAGENAME}}}}}
| image = {{{image|{{#if:{{#property:P18}}|[[File:{{#property:P18}}|frameless|upright=1|alt=]]}}}}}
| label1 = Born
| data1 = {{{birth_date|{{#property:P569}}}}} <br> {{{birth_place|{{#property:P19}}}}}
| label3 = Occupation
| data3 = {{{occupation|{{#property:P106}}}}}
| label4 = Known for
| data4 = {{{known_for|{{#property:P800}}}}}
}}
7ufdk03nvqic7c1si7md4fmk4q9qom5
743916
743914
2026-05-22T20:39:57Z
Iiirxs
49827
743916
wikitext
text/x-wiki
{{Infobox
| above = {{{name|{{PAGENAME}}}}}
| image = {{{image|{{#if:{{#property:P18}}|[[File:{{#property:P18}}|frameless|upright=1|alt=]]}}}}}
| label1 = Born
| data1 = {{{birth_date|{{#property:P569}}}}} <br> {{{birth_place|{{#property:P19}}}}}
| label3 = Occupation
| data3 = {{{occupation|{{#property:P106}}}}}
| label4 = Known for
| data4 = {{{known_for|{{#property:P800}}}}}
}}
<noinclude>
{{documentation}}
</noinclude>
7c14ky9gat2hbg6q2393fb0we5me61g
User:Iiirxs/Template:Infobox person/doc
2
175647
743915
2026-05-22T20:39:13Z
Iiirxs
49827
Created page with "== Usage == Use this template on articles about people. All fields are optional — if omitted, values are pulled automatically from Wikidata. === Basic usage (Wikidata auto-fill) === <pre>{{Infopro person}}</pre> === With explicit values === <pre> {{Infobox person | name = Marie Curie | image = Marie Curie c1920.jpg | birth_date = 7 November 1867 | birth_place = Warsaw, Congress Poland | occupation = Physicist, chemist | known_for = Radioactivity research..."
743915
wikitext
text/x-wiki
== Usage ==
Use this template on articles about people. All fields are optional — if omitted, values are pulled automatically from Wikidata.
=== Basic usage (Wikidata auto-fill) ===
<pre>{{Infopro person}}</pre>
=== With explicit values ===
<pre>
{{Infobox person
| name = Marie Curie
| image = Marie Curie c1920.jpg
| birth_date = 7 November 1867
| birth_place = Warsaw, Congress Poland
| occupation = Physicist, chemist
| known_for = Radioactivity research
}}
</pre>
== Parameters ==
{| class="wikitable"
! Parameter !! Wikidata property !! Description
|-
| <code>name</code> || — || Person's name. Defaults to the page name.
|-
| <code>image</code> || P18 || Image filename (without <code>File:</code> prefix). Defaults to Wikidata P18.
|-
| <code>birth_date</code> || P569 || Date of birth. Defaults to Wikidata P569.
|-
| <code>birth_place</code> || P19 || Place of birth. Defaults to Wikidata P19.
|-
| <code>occupation</code> || P106 || Occupation. Defaults to Wikidata P106.
|-
| <code>known_for</code> || P800 || Notable work or reason for fame. Defaults to Wikidata P800.
|}
== Notes ==
* Requires the [[mw:Extension:Wikibase Client|WikibaseClient]] extension for Wikidata property lookup.
* Requires the [[mw:Extension:Scribunto|Scribunto]] extension and [[Module:Infobox]] for rendering.
<templatedata>
{
"description": "Infobox for people. All fields are optional and fall back to Wikidata properties automatically.",
"params": {
"name": {
"label": "Name",
"description": "Person's name. Defaults to the page name.",
"type": "string",
"suggested": true
},
"image": {
"label": "Image",
"description": "Image filename without File: prefix. Defaults to Wikidata P18.",
"type": "wiki-file-name",
"suggested": true
},
"birth_date": {
"label": "Birth date",
"description": "Date of birth. Defaults to Wikidata P569.",
"type": "date"
},
"birth_place": {
"label": "Birth place",
"description": "Place of birth. Defaults to Wikidata P19.",
"type": "string"
},
"occupation": {
"label": "Occupation",
"description": "Occupation or profession. Defaults to Wikidata P106.",
"type": "string"
},
"known_for": {
"label": "Known for",
"description": "Notable work or reason for fame. Defaults to Wikidata P800.",
"type": "string"
}
}
}
</templatedata>
2uzehu2f5wnbg6qwmg6ddpb1lo84kkr
743917
743915
2026-05-22T21:40:57Z
Iiirxs
49827
743917
wikitext
text/x-wiki
== Usage ==
Use this template on articles about people. All fields are optional — if omitted, values are pulled automatically from Wikidata.
=== Basic usage (Wikidata auto-fill) ===
<pre>{{Infobox person}}</pre>
=== With explicit values ===
<pre>
{{Infobox person
| name = Marie Curie
| image = Marie Curie c1920.jpg
| birth_date = 7 November 1867
| birth_place = Warsaw, Congress Poland
| occupation = Physicist, chemist
| known_for = Radioactivity research
}}
</pre>
== Parameters ==
{| class="wikitable"
! Parameter !! Wikidata property !! Description
|-
| <code>name</code> || — || Person's name. Defaults to the page name.
|-
| <code>image</code> || P18 || Image filename (without <code>File:</code> prefix). Defaults to Wikidata P18.
|-
| <code>birth_date</code> || P569 || Date of birth. Defaults to Wikidata P569.
|-
| <code>birth_place</code> || P19 || Place of birth. Defaults to Wikidata P19.
|-
| <code>occupation</code> || P106 || Occupation. Defaults to Wikidata P106.
|-
| <code>known_for</code> || P800 || Notable work or reason for fame. Defaults to Wikidata P800.
|}
== Notes ==
* Requires the [[mw:Extension:Wikibase Client|WikibaseClient]] extension for Wikidata property lookup.
* Requires the [[mw:Extension:Scribunto|Scribunto]] extension and [[Module:Infobox]] for rendering.
<templatedata>
{
"description": "Infobox for people. All fields are optional and fall back to Wikidata properties automatically.",
"params": {
"name": {
"label": "Name",
"description": "Person's name. Defaults to the page name.",
"type": "string",
"suggested": true
},
"image": {
"label": "Image",
"description": "Image filename without File: prefix. Defaults to Wikidata P18.",
"type": "wiki-file-name",
"suggested": true
},
"birth_date": {
"label": "Birth date",
"description": "Date of birth. Defaults to Wikidata P569.",
"type": "date"
},
"birth_place": {
"label": "Birth place",
"description": "Place of birth. Defaults to Wikidata P19.",
"type": "string"
},
"occupation": {
"label": "Occupation",
"description": "Occupation or profession. Defaults to Wikidata P106.",
"type": "string"
},
"known_for": {
"label": "Known for",
"description": "Notable work or reason for fame. Defaults to Wikidata P800.",
"type": "string"
}
}
}
</templatedata>
gemmv7layngp1zf4dxpilteq8fi2ezm
Talk:Hitler
1
175648
743928
2026-05-23T03:28:20Z
OrderNumber57
74111
/* hitler was evil */ new section
743928
wikitext
text/x-wiki
== hitler was evil ==
Also make this article bigger.. or not, this is the testing website [[User:OrderNumber57|OrderNumber57]] ([[User talk:OrderNumber57|talk]]) 03:28, 23 May 2026 (UTC)
csa8kgiip7t1nuu79dxp9p4to9h5aol
User:Iiirxs/Template:Infobox settlement
2
175649
743933
2026-05-23T11:04:54Z
Iiirxs
49827
Created page with "{{Infobox | above = {{{name|{{PAGENAME}}}}} | image = {{{image|{{#if:{{#property:P18}}|[[File:{{#property:P18}}|frameless|upright=1|alt=]]}}}}} | label1 = Country | data1 = {{{country|{{#property:P17}}}}} | label2 = Region | data2 = {{{region|{{#property:P131}}}}} | label3 = Population | data3 = {{{population|{{#property:P1082}}}}} | label4 = Coordinates | data4 = {{{coordinates|{{#property:P625}}}}} }}<noinclude> {{documentation}} </noinclude>"
743933
wikitext
text/x-wiki
{{Infobox
| above = {{{name|{{PAGENAME}}}}}
| image = {{{image|{{#if:{{#property:P18}}|[[File:{{#property:P18}}|frameless|upright=1|alt=]]}}}}}
| label1 = Country
| data1 = {{{country|{{#property:P17}}}}}
| label2 = Region
| data2 = {{{region|{{#property:P131}}}}}
| label3 = Population
| data3 = {{{population|{{#property:P1082}}}}}
| label4 = Coordinates
| data4 = {{{coordinates|{{#property:P625}}}}}
}}<noinclude>
{{documentation}}
</noinclude>
l8vu4damgy0p5cky26hfbg1ja81o6ac
743936
743933
2026-05-23T11:09:26Z
Iiirxs
49827
743936
wikitext
text/x-wiki
{{Infobox
| above = {{{name|{{PAGENAME}}}}}
| image = {{{image|{{#if:{{#property:P18}}|[[File:{{#property:P18}}|frameless|upright=1|alt=]]}}}}}
| label1 = Country
| data1 = {{{country|{{#property:P17}}}}}
| label2 = Region
| data2 = {{{region|{{#property:P131}}}}}
| label3 = Population
| data3 = {{{population|{{#property:P1082}}}}}
| label4 = Coordinates
| data4 = {{{coordinates|{{#property:P625}}}}}
}}
<noinclude>
{{documentation}}
</noinclude>
4ffm1eezt7jry44cwcyymaethp657sa
User:Iiirxs/Template:Infobox settlement/doc
2
175650
743934
2026-05-23T11:05:29Z
Iiirxs
49827
Created page with "== Usage == Use this template on articles about settlements (cities, towns, villages, etc.). All fields are optional — if omitted, values are pulled automatically from Wikidata. === Basic usage (Wikidata auto-fill) === <pre>{{Infopro settlement}}</pre> === With explicit values === <pre> {{Infopro settlement | name = Athens | image = Athens Montage.jpg | country = Greece | region = Attica | population = 3,153,000 | coordinates = 37°58′N 23°4..."
743934
wikitext
text/x-wiki
== Usage ==
Use this template on articles about settlements (cities, towns, villages, etc.). All fields are optional — if omitted, values are pulled automatically from Wikidata.
=== Basic usage (Wikidata auto-fill) ===
<pre>{{Infopro settlement}}</pre>
=== With explicit values ===
<pre>
{{Infopro settlement
| name = Athens
| image = Athens Montage.jpg
| country = Greece
| region = Attica
| population = 3,153,000
| coordinates = 37°58′N 23°43′E
}}
</pre>
== Parameters ==
{| class="wikitable"
! Parameter !! Wikidata property !! Description
|-
| <code>name</code> || — || Settlement name. Defaults to the page name.
|-
| <code>image</code> || P18 || Image filename (without <code>File:</code> prefix). Defaults to Wikidata P18.
|-
| <code>country</code> || P17 || Country the settlement is located in. Defaults to Wikidata P17.
|-
| <code>region</code> || P131 || Administrative territorial entity (region, prefecture, municipality, etc.). Defaults to Wikidata P131.
|-
| <code>population</code> || P1082 || Population figure. Defaults to Wikidata P1082.
|-
| <code>coordinates</code> || P625 || Geographic coordinates. Defaults to Wikidata P625.
|}
== Notes ==
* Labels are translatable via [[MediaWiki:Infopro-country]], [[MediaWiki:Infopro-region]], [[MediaWiki:Infopro-population]], [[MediaWiki:Infopro-coordinates]] and their <code>/lang</code> sub-pages.
* Requires the [[mw:Extension:Wikibase Client|WikibaseClient]] extension for Wikidata property lookup.
* Requires the [[mw:Extension:Scribunto|Scribunto]] extension and [[Module:Infobox]] for rendering.
<templatedata>
{
"description": "Infobox for settlements. All fields are optional and fall back to Wikidata properties automatically.",
"params": {
"name": {
"label": "Name",
"description": "Settlement name. Defaults to the page name.",
"type": "string",
"suggested": true
},
"image": {
"label": "Image",
"description": "Image filename without File: prefix. Defaults to Wikidata P18.",
"type": "wiki-file-name",
"suggested": true
},
"country": {
"label": "Country",
"description": "Country the settlement is in. Defaults to Wikidata P17.",
"type": "string"
},
"region": {
"label": "Region",
"description": "Administrative division (region, prefecture, etc.). Defaults to Wikidata P131.",
"type": "string"
},
"population": {
"label": "Population",
"description": "Population figure. Defaults to Wikidata P1082.",
"type": "number"
},
"coordinates": {
"label": "Coordinates",
"description": "Geographic coordinates. Defaults to Wikidata P625.",
"type": "string"
}
}
}
</templatedata>
<includeonly>[[Category:Settlement infobox templates]]</includeonly>
k8czxbijaaohfbvhs7y4xhvlenqdo9k
743935
743934
2026-05-23T11:06:09Z
Iiirxs
49827
743935
wikitext
text/x-wiki
== Usage ==
Use this template on articles about settlements (cities, towns, villages, etc.). All fields are optional — if omitted, values are pulled automatically from Wikidata.
=== Basic usage (Wikidata auto-fill) ===
<pre>{{Infobox settlement}}</pre>
=== With explicit values ===
<pre>
{{Infobox settlement
| name = Athens
| image = Athens Montage.jpg
| country = Greece
| region = Attica
| population = 3,153,000
| coordinates = 37°58′N 23°43′E
}}
</pre>
== Parameters ==
{| class="wikitable"
! Parameter !! Wikidata property !! Description
|-
| <code>name</code> || — || Settlement name. Defaults to the page name.
|-
| <code>image</code> || P18 || Image filename (without <code>File:</code> prefix). Defaults to Wikidata P18.
|-
| <code>country</code> || P17 || Country the settlement is located in. Defaults to Wikidata P17.
|-
| <code>region</code> || P131 || Administrative territorial entity (region, prefecture, municipality, etc.). Defaults to Wikidata P131.
|-
| <code>population</code> || P1082 || Population figure. Defaults to Wikidata P1082.
|-
| <code>coordinates</code> || P625 || Geographic coordinates. Defaults to Wikidata P625.
|}
== Notes ==
* Requires the [[mw:Extension:Wikibase Client|WikibaseClient]] extension for Wikidata property lookup.
* Requires the [[mw:Extension:Scribunto|Scribunto]] extension and [[Module:Infobox]] for rendering.
<templatedata>
{
"description": "Infobox for settlements. All fields are optional and fall back to Wikidata properties automatically.",
"params": {
"name": {
"label": "Name",
"description": "Settlement name. Defaults to the page name.",
"type": "string",
"suggested": true
},
"image": {
"label": "Image",
"description": "Image filename without File: prefix. Defaults to Wikidata P18.",
"type": "wiki-file-name",
"suggested": true
},
"country": {
"label": "Country",
"description": "Country the settlement is in. Defaults to Wikidata P17.",
"type": "string"
},
"region": {
"label": "Region",
"description": "Administrative division (region, prefecture, etc.). Defaults to Wikidata P131.",
"type": "string"
},
"population": {
"label": "Population",
"description": "Population figure. Defaults to Wikidata P1082.",
"type": "number"
},
"coordinates": {
"label": "Coordinates",
"description": "Geographic coordinates. Defaults to Wikidata P625.",
"type": "string"
}
}
}
</templatedata>
<includeonly>[[Category:Settlement infobox templates]]</includeonly>
9aw7qnpmito0t1snn446kqn51vqatjq
743937
743935
2026-05-23T11:09:49Z
Iiirxs
49827
743937
wikitext
text/x-wiki
== Usage ==
Use this template on articles about settlements (cities, towns, villages, etc.). All fields are optional — if omitted, values are pulled automatically from Wikidata.
=== Basic usage (Wikidata auto-fill) ===
<pre>{{Infobox settlement}}</pre>
=== With explicit values ===
<pre>
{{Infobox settlement
| name = Athens
| image = Athens Montage.jpg
| country = Greece
| region = Attica
| population = 3,153,000
| coordinates = 37°58′N 23°43′E
}}
</pre>
== Parameters ==
{| class="wikitable"
! Parameter !! Wikidata property !! Description
|-
| <code>name</code> || — || Settlement name. Defaults to the page name.
|-
| <code>image</code> || P18 || Image filename (without <code>File:</code> prefix). Defaults to Wikidata P18.
|-
| <code>country</code> || P17 || Country the settlement is located in. Defaults to Wikidata P17.
|-
| <code>region</code> || P131 || Administrative territorial entity (region, prefecture, municipality, etc.). Defaults to Wikidata P131.
|-
| <code>population</code> || P1082 || Population figure. Defaults to Wikidata P1082.
|-
| <code>coordinates</code> || P625 || Geographic coordinates. Defaults to Wikidata P625.
|}
== Notes ==
* Requires the [[mw:Extension:Wikibase Client|WikibaseClient]] extension for Wikidata property lookup.
* Requires the [[mw:Extension:Scribunto|Scribunto]] extension and [[Module:Infobox]] for rendering.
<templatedata>
{
"description": "Infobox for settlements. All fields are optional and fall back to Wikidata properties automatically.",
"params": {
"name": {
"label": "Name",
"description": "Settlement name. Defaults to the page name.",
"type": "string",
"suggested": true
},
"image": {
"label": "Image",
"description": "Image filename without File: prefix. Defaults to Wikidata P18.",
"type": "wiki-file-name",
"suggested": true
},
"country": {
"label": "Country",
"description": "Country the settlement is in. Defaults to Wikidata P17.",
"type": "string"
},
"region": {
"label": "Region",
"description": "Administrative division (region, prefecture, etc.). Defaults to Wikidata P131.",
"type": "string"
},
"population": {
"label": "Population",
"description": "Population figure. Defaults to Wikidata P1082.",
"type": "number"
},
"coordinates": {
"label": "Coordinates",
"description": "Geographic coordinates. Defaults to Wikidata P625.",
"type": "string"
}
}
}
</templatedata>
d1hdr68wr32f6i5rcican2ykkovk7if
User:Iiirxs/Template:Infobox organization/doc
2
175651
743939
2026-05-23T11:21:49Z
Iiirxs
49827
Created page with "== Usage == Use this template on articles about organizations (companies, institutions, NGOs, etc.). All fields are optional — if omitted, values are pulled automatically from Wikidata where available. === Basic usage (Wikidata auto-fill) === <pre>{{Infobox organization}}</pre> === With explicit values === <pre> {{Infobox organization | name = Wikimedia Foundation | image = Wikimedia Foundation RGB logo with text.svg | type = Non-profit organiz..."
743939
wikitext
text/x-wiki
== Usage ==
Use this template on articles about organizations (companies, institutions, NGOs, etc.). All fields are optional — if omitted, values are pulled automatically from Wikidata where available.
=== Basic usage (Wikidata auto-fill) ===
<pre>{{Infobox organization}}</pre>
=== With explicit values ===
<pre>
{{Infobox organization
| name = Wikimedia Foundation
| image = Wikimedia Foundation RGB logo with text.svg
| type = Non-profit organization
| founded = 2003
| headquarters = San Francisco, California
| website = https://wikimediafoundation.org
}}
</pre>
== Parameters ==
{| class="wikitable"
! Parameter !! Wikidata property !! Description
|-
| <code>name</code> || — || Organization name. Defaults to the page name.
|-
| <code>image</code> || P18 || Logo or image filename (without <code>File:</code> prefix). Defaults to Wikidata P18.
|-
| <code>type</code> || P31 || Type or instance of (e.g. non-profit, public company). Defaults to Wikidata P31.
|-
| <code>founded</code> || P571 || Date of inception/founding. Defaults to Wikidata P571.
|-
| <code>headquarters</code> || P159 || Headquarters location. Defaults to Wikidata P159.
|-
| <code>website</code> || P856 || Official website URL. Defaults to Wikidata P856.
|}
== Notes ==
* Requires the [[mw:Extension:Wikibase Client|WikibaseClient]] extension for Wikidata property lookup.
* Requires the [[mw:Extension:Scribunto|Scribunto]] extension and [[Module:Infobox]] for rendering.
<templatedata>
{
"description": "Infobox for organizations. All fields are optional and fall back to Wikidata properties automatically.",
"params": {
"name": {
"label": "Name",
"description": "Organization name. Defaults to the page name.",
"type": "string",
"suggested": true
},
"image": {
"label": "Image",
"description": "Logo or image filename without File: prefix. Defaults to Wikidata P18.",
"type": "wiki-file-name",
"suggested": true
},
"type": {
"label": "Type",
"description": "Type of organization (e.g. non-profit, public company). Defaults to Wikidata P31.",
"type": "string"
},
"founded": {
"label": "Founded",
"description": "Date of inception or founding. Defaults to Wikidata P571.",
"type": "date"
},
"headquarters": {
"label": "Headquarters",
"description": "Headquarters location. Defaults to Wikidata P159.",
"type": "string"
},
"website": {
"label": "Website",
"description": "Official website URL. Defaults to Wikidata P856.",
"type": "url"
}
}
}
</templatedata>
gtbw0cvxs21rw516ivfuhmsxjoe9ije
User:Iiirxs/Template:Infobox organization
2
175652
743940
2026-05-23T11:22:10Z
Iiirxs
49827
Created page with "{{Infobox | above = {{{name|{{PAGENAME}}}}} | image = {{{image|{{#if:{{#property:P18}}|[[File:{{#property:P18}}|frameless|upright=1|alt=]]}}}}} | label1 = Type | data1 = {{{type|{{#property:P31}}}}} | label2 = Founded | data2 = {{{founded|{{#property:P571}}}}} | label3 = Headquarters | data3 = {{{headquarters|{{#property:P159}}}}} | label4 = Website | data4 = {{{website|{{#property:P856}}}}} }} <noinclude> {{documentation}} </noinclude>"
743940
wikitext
text/x-wiki
{{Infobox
| above = {{{name|{{PAGENAME}}}}}
| image = {{{image|{{#if:{{#property:P18}}|[[File:{{#property:P18}}|frameless|upright=1|alt=]]}}}}}
| label1 = Type
| data1 = {{{type|{{#property:P31}}}}}
| label2 = Founded
| data2 = {{{founded|{{#property:P571}}}}}
| label3 = Headquarters
| data3 = {{{headquarters|{{#property:P159}}}}}
| label4 = Website
| data4 = {{{website|{{#property:P856}}}}}
}}
<noinclude>
{{documentation}}
</noinclude>
6eylbd0ej8pq0ybhtcrdyhou2ig4oyx
User:Iiirxs/Template:Infobox event/doc
2
175653
743941
2026-05-23T11:23:51Z
Iiirxs
49827
Created page with "== Usage == Use this template on articles about events (conferences, competitions, ceremonies, etc.). All fields are optional — if omitted, values are pulled automatically from Wikidata where available. === Basic usage (Wikidata auto-fill) === <pre>{{Infobox event}}</pre> === With explicit values === <pre> {{Infobox event | name = Olympic Games Athens 2004 | image = 2004 Olympics opening ceremony.jpg | date = 13–29 August 2004 | location = At..."
743941
wikitext
text/x-wiki
== Usage ==
Use this template on articles about events (conferences, competitions, ceremonies, etc.). All fields are optional — if omitted, values are pulled automatically from Wikidata where available.
=== Basic usage (Wikidata auto-fill) ===
<pre>{{Infobox event}}</pre>
=== With explicit values ===
<pre>
{{Infobox event
| name = Olympic Games Athens 2004
| image = 2004 Olympics opening ceremony.jpg
| date = 13–29 August 2004
| location = Athens, Greece
| organizer = International Olympic Committee
| description = Summer Olympic Games held in Athens.
}}
</pre>
== Parameters ==
{| class="wikitable"
! Parameter !! Wikidata property !! Description
|-
| <code>name</code> || — || Event name. Defaults to the page name.
|-
| <code>image</code> || P18 || Image filename (without <code>File:</code> prefix). Defaults to Wikidata P18.
|-
| <code>date</code> || P585 || Date or date range of the event. Defaults to Wikidata P585 (point in time).
|-
| <code>location</code> || P276 || Location where the event takes place. Defaults to Wikidata P276.
|-
| <code>organizer</code> || P664 || Organizer of the event. Defaults to Wikidata P664.
|-
| <code>description</code> || — || Short description of the event. No Wikidata fallback — always explicit.
|}
== Notes ==
* Requires the [[mw:Extension:Wikibase Client|WikibaseClient]] extension for Wikidata property lookup.
* Requires the [[mw:Extension:Scribunto|Scribunto]] extension and [[Module:Infobox]] for rendering.
<templatedata>
{
"description": "Infobox for events. Most fields fall back to Wikidata properties automatically.",
"params": {
"name": {
"label": "Name",
"description": "Event name. Defaults to the page name.",
"type": "string",
"suggested": true
},
"image": {
"label": "Image",
"description": "Image filename without File: prefix. Defaults to Wikidata P18.",
"type": "wiki-file-name",
"suggested": true
},
"date": {
"label": "Date",
"description": "Date or date range of the event. Defaults to Wikidata P585.",
"type": "date"
},
"location": {
"label": "Location",
"description": "Location of the event. Defaults to Wikidata P276.",
"type": "string"
},
"organizer": {
"label": "Organizer",
"description": "Organizer of the event. Defaults to Wikidata P664.",
"type": "string"
},
"description": {
"label": "Description",
"description": "Short description of the event. Always explicit, no Wikidata fallback.",
"type": "string"
}
}
}
</templatedata>
qyy2ibv1wga3nl5r3m0g1ya7m7bbk7e
743946
743941
2026-05-23T11:30:41Z
Iiirxs
49827
743946
wikitext
text/x-wiki
== Usage ==
Use this template on articles about events (conferences, competitions, ceremonies, etc.). All fields are optional — if omitted, values are pulled automatically from Wikidata where available.
=== Basic usage (Wikidata auto-fill) ===
<pre>{{Infobox event}}</pre>
=== With explicit values ===
<pre>
{{Infobox event
| name = Olympic Games Athens 2004
| image = 2004 Olympics opening ceremony.jpg
| date = 13–29 August 2004
| location = Athens, Greece
| organizer = International Olympic Committee
| description = Summer Olympic Games held in Athens.
}}
</pre>
== Parameters ==
{| class="wikitable"
! Parameter !! Wikidata property !! Description
|-
| <code>name</code> || — || Event name. Defaults to the page name.
|-
| <code>image</code> || P18 || Image filename (without <code>File:</code> prefix). Defaults to Wikidata P18.
|-
| <code>date</code> || P585 || Date or date range of the event. Defaults to Wikidata P585 (point in time).
|-
| <code>location</code> || P276 || Location where the event takes place. Defaults to Wikidata P276.
|-
| <code>organizer</code> || P664 || Organizer of the event. Defaults to Wikidata P664.
|-
| <code>description</code> || — || Short description of the event. No Wikidata fallback — always explicit.
|}
== Notes ==
* The <code>description</code> field has no Wikidata fallback because Wikidata entity descriptions are not accessible via <code>{{#property:}}</code>.
* Requires the [[mw:Extension:Wikibase Client|WikibaseClient]] extension for Wikidata property lookup.
* Requires the [[mw:Extension:Scribunto|Scribunto]] extension and [[Module:Infobox]] for rendering.
<templatedata>
{
"description": "Infobox for events. Most fields fall back to Wikidata properties automatically.",
"params": {
"name": {
"label": "Name",
"description": "Event name. Defaults to the page name.",
"type": "string",
"suggested": true
},
"image": {
"label": "Image",
"description": "Image filename without File: prefix. Defaults to Wikidata P18.",
"type": "wiki-file-name",
"suggested": true
},
"date": {
"label": "Date",
"description": "Date or date range of the event. Defaults to Wikidata P585.",
"type": "date"
},
"location": {
"label": "Location",
"description": "Location of the event. Defaults to Wikidata P276.",
"type": "string"
},
"organizer": {
"label": "Organizer",
"description": "Organizer of the event. Defaults to Wikidata P664.",
"type": "string"
},
"description": {
"label": "Description",
"description": "Short description of the event. Always explicit, no Wikidata fallback.",
"type": "string"
}
}
}
</templatedata>
gkjq1x3ta53ronpek4gplbme8xquwmw
743947
743946
2026-05-23T11:31:37Z
Iiirxs
49827
743947
wikitext
text/x-wiki
== Usage ==
Use this template on articles about events (conferences, competitions, ceremonies, etc.). All fields are optional — if omitted, values are pulled automatically from Wikidata where available.
=== Basic usage (Wikidata auto-fill) ===
<pre>{{Infobox event}}</pre>
=== With explicit values ===
<pre>
{{Infobox event
| name = Olympic Games Athens 2004
| image = 2004 Olympics opening ceremony.jpg
| date = 13–29 August 2004
| location = Athens, Greece
| organizer = International Olympic Committee
| description = Summer Olympic Games held in Athens.
}}
</pre>
== Parameters ==
{| class="wikitable"
! Parameter !! Wikidata property !! Description
|-
| <code>name</code> || — || Event name. Defaults to the page name.
|-
| <code>image</code> || P18 || Image filename (without <code>File:</code> prefix). Defaults to Wikidata P18.
|-
| <code>date</code> || P585 || Date or date range of the event. Defaults to Wikidata P585 (point in time).
|-
| <code>location</code> || P276 || Location where the event takes place. Defaults to Wikidata P276.
|-
| <code>organizer</code> || P664 || Organizer of the event. Defaults to Wikidata P664.
|-
| <code>description</code> || — || Short description of the event. No Wikidata fallback — always explicit.
|}
== Notes ==
* The <code>description</code> field has no Wikidata fallback.
* Requires the [[mw:Extension:Wikibase Client|WikibaseClient]] extension for Wikidata property lookup.
* Requires the [[mw:Extension:Scribunto|Scribunto]] extension and [[Module:Infobox]] for rendering.
<templatedata>
{
"description": "Infobox for events. Most fields fall back to Wikidata properties automatically.",
"params": {
"name": {
"label": "Name",
"description": "Event name. Defaults to the page name.",
"type": "string",
"suggested": true
},
"image": {
"label": "Image",
"description": "Image filename without File: prefix. Defaults to Wikidata P18.",
"type": "wiki-file-name",
"suggested": true
},
"date": {
"label": "Date",
"description": "Date or date range of the event. Defaults to Wikidata P585.",
"type": "date"
},
"location": {
"label": "Location",
"description": "Location of the event. Defaults to Wikidata P276.",
"type": "string"
},
"organizer": {
"label": "Organizer",
"description": "Organizer of the event. Defaults to Wikidata P664.",
"type": "string"
},
"description": {
"label": "Description",
"description": "Short description of the event. Always explicit, no Wikidata fallback.",
"type": "string"
}
}
}
</templatedata>
6c3arlkeqbuou3cqtir8hk7foqav0bq
User:Iiirxs/Template:Infobox event
2
175654
743942
2026-05-23T11:25:52Z
Iiirxs
49827
Created page with "{{Infobox | above = {{{name|{{PAGENAME}}}}} | image = {{{image|{{#if:{{#property:P18}}|[[File:{{#property:P18}}|frameless|upright=1|alt=]]}}}}} | label1 = Date | data1 = {{{date|{{#property:P585}}}}} | label2 = Location | data2 = {{{location|{{#property:P276}}}}} | label3 = Organizer | data3 = {{{organizer|{{#property:P664}}}}} | label4 = Description | data4 = {{{description|}}} }} <noinclude> {{documentation}} </noinclude>"
743942
wikitext
text/x-wiki
{{Infobox
| above = {{{name|{{PAGENAME}}}}}
| image = {{{image|{{#if:{{#property:P18}}|[[File:{{#property:P18}}|frameless|upright=1|alt=]]}}}}}
| label1 = Date
| data1 = {{{date|{{#property:P585}}}}}
| label2 = Location
| data2 = {{{location|{{#property:P276}}}}}
| label3 = Organizer
| data3 = {{{organizer|{{#property:P664}}}}}
| label4 = Description
| data4 = {{{description|}}}
}}
<noinclude>
{{documentation}}
</noinclude>
2omw5gjpigegklbaqaxyr4uvzc0oxz7
User:Iiirxs/Template:Infobox taxon
2
175655
743943
2026-05-23T11:27:44Z
Iiirxs
49827
Created page with "== Usage == Use this template on articles about taxa (species, genera, families, etc.). Fields with a Wikidata fallback are filled automatically when the article is connected to a Wikidata item. === Basic usage (Wikidata auto-fill where available) === <pre>{{Infobox taxon}}</pre> === With explicit values === <pre> {{Infobox taxon | name = Panthera leo | image = Lion waiting in Namibia.jpg | kingdom = Animalia | family..."
743943
wikitext
text/x-wiki
== Usage ==
Use this template on articles about taxa (species, genera, families, etc.). Fields with a Wikidata fallback are filled automatically when the article is connected to a Wikidata item.
=== Basic usage (Wikidata auto-fill where available) ===
<pre>{{Infobox taxon}}</pre>
=== With explicit values ===
<pre>
{{Infobox taxon
| name = Panthera leo
| image = Lion waiting in Namibia.jpg
| kingdom = Animalia
| family = Felidae
| genus = Panthera
| species = Panthera leo
| conservation_status = Vulnerable
}}
</pre>
== Parameters ==
{| class="wikitable"
! Parameter !! Wikidata property !! Description
|-
| <code>name</code> || — || Taxon name. Defaults to the page name.
|-
| <code>image</code> || P18 || Image filename (without <code>File:</code> prefix). Defaults to Wikidata P18.
|-
| <code>kingdom</code> || — || Biological kingdom (e.g. Animalia, Plantae). Always explicit — Wikidata encodes the full hierarchy via P171 chains with no direct kingdom property.
|-
| <code>family</code> || — || Biological family. Always explicit — same reason as kingdom.
|-
| <code>genus</code> || P171 || Immediate parent taxon (genus for a species item). Defaults to Wikidata P171.
|-
| <code>species</code> || P225 || Scientific taxon name. Defaults to Wikidata P225.
|-
| <code>conservation_status</code> || P141 || IUCN conservation status. Defaults to Wikidata P141.
|}
== Notes ==
* <code>kingdom</code> and <code>family</code> have no Wikidata fallback because Wikidata represents the taxonomic hierarchy as a chain of P171 (parent taxon) links, not as flat properties. These must always be provided explicitly.
* Requires the [[mw:Extension:Wikibase Client|WikibaseClient]] extension for Wikidata property lookup.
* Requires the [[mw:Extension:Scribunto|Scribunto]] extension and [[Module:Infobox]] for rendering.
<templatedata>
{
"description": "Infobox for taxa (species, genera, etc.). Some fields fall back to Wikidata properties automatically.",
"params": {
"name": {
"label": "Name",
"description": "Taxon name. Defaults to the page name.",
"type": "string",
"suggested": true
},
"image": {
"label": "Image",
"description": "Image filename without File: prefix. Defaults to Wikidata P18.",
"type": "wiki-file-name",
"suggested": true
},
"kingdom": {
"label": "Kingdom",
"description": "Biological kingdom (e.g. Animalia, Plantae). Always explicit.",
"type": "string"
},
"family": {
"label": "Family",
"description": "Biological family. Always explicit.",
"type": "string"
},
"genus": {
"label": "Genus",
"description": "Biological genus (immediate parent taxon). Defaults to Wikidata P171.",
"type": "string"
},
"species": {
"label": "Species",
"description": "Scientific taxon name. Defaults to Wikidata P225.",
"type": "string"
},
"conservation_status": {
"label": "Conservation status",
"description": "IUCN conservation status. Defaults to Wikidata P141.",
"type": "string"
}
}
}
</templatedata>
t80rv7c1r0ayyhc4fkshqcwmmk1hqhi
743945
743943
2026-05-23T11:29:20Z
Iiirxs
49827
743945
wikitext
text/x-wiki
{{Infobox
| above = {{{name|{{PAGENAME}}}}}
| image = {{{image|{{#if:{{#property:P18}}|[[File:{{#property:P18}}|frameless|upright=1|alt=]]}}}}}
| label1 = Kingdom
| data1 = {{{kingdom|}}}
| label2 = Family
| data2 = {{{family|}}}
| label3 = Genus
| data3 = {{{genus|{{#property:P171}}}}}
| label4 = Species
| data4 = {{{species|{{#property:P225}}}}}
| label5 = Conservation status
| data5 = {{{conservation_status|{{#property:P141}}}}}
}}
<noinclude>
{{documentation}}
</noinclude>
tusd1q5j28w4b8v1vcppf82oabzt96l
User:Iiirxs/Template:Infobox taxon/doc
2
175656
743944
2026-05-23T11:28:09Z
Iiirxs
49827
Created page with "== Usage == Use this template on articles about taxa (species, genera, families, etc.). Fields with a Wikidata fallback are filled automatically when the article is connected to a Wikidata item. === Basic usage (Wikidata auto-fill where available) === <pre>{{Infobox taxon}}</pre> === With explicit values === <pre> {{Infobox taxon | name = Panthera leo | image = Lion waiting in Namibia.jpg | kingdom = Animalia | family..."
743944
wikitext
text/x-wiki
== Usage ==
Use this template on articles about taxa (species, genera, families, etc.). Fields with a Wikidata fallback are filled automatically when the article is connected to a Wikidata item.
=== Basic usage (Wikidata auto-fill where available) ===
<pre>{{Infobox taxon}}</pre>
=== With explicit values ===
<pre>
{{Infobox taxon
| name = Panthera leo
| image = Lion waiting in Namibia.jpg
| kingdom = Animalia
| family = Felidae
| genus = Panthera
| species = Panthera leo
| conservation_status = Vulnerable
}}
</pre>
== Parameters ==
{| class="wikitable"
! Parameter !! Wikidata property !! Description
|-
| <code>name</code> || — || Taxon name. Defaults to the page name.
|-
| <code>image</code> || P18 || Image filename (without <code>File:</code> prefix). Defaults to Wikidata P18.
|-
| <code>kingdom</code> || — || Biological kingdom (e.g. Animalia, Plantae). Always explicit — Wikidata encodes the full hierarchy via P171 chains with no direct kingdom property.
|-
| <code>family</code> || — || Biological family. Always explicit — same reason as kingdom.
|-
| <code>genus</code> || P171 || Immediate parent taxon (genus for a species item). Defaults to Wikidata P171.
|-
| <code>species</code> || P225 || Scientific taxon name. Defaults to Wikidata P225.
|-
| <code>conservation_status</code> || P141 || IUCN conservation status. Defaults to Wikidata P141.
|}
== Notes ==
* <code>kingdom</code> and <code>family</code> have no Wikidata fallback because Wikidata represents the taxonomic hierarchy as a chain of P171 (parent taxon) links, not as flat properties. These must always be provided explicitly.
* Requires the [[mw:Extension:Wikibase Client|WikibaseClient]] extension for Wikidata property lookup.
* Requires the [[mw:Extension:Scribunto|Scribunto]] extension and [[Module:Infobox]] for rendering.
<templatedata>
{
"description": "Infobox for taxa (species, genera, etc.). Some fields fall back to Wikidata properties automatically.",
"params": {
"name": {
"label": "Name",
"description": "Taxon name. Defaults to the page name.",
"type": "string",
"suggested": true
},
"image": {
"label": "Image",
"description": "Image filename without File: prefix. Defaults to Wikidata P18.",
"type": "wiki-file-name",
"suggested": true
},
"kingdom": {
"label": "Kingdom",
"description": "Biological kingdom (e.g. Animalia, Plantae). Always explicit.",
"type": "string"
},
"family": {
"label": "Family",
"description": "Biological family. Always explicit.",
"type": "string"
},
"genus": {
"label": "Genus",
"description": "Biological genus (immediate parent taxon). Defaults to Wikidata P171.",
"type": "string"
},
"species": {
"label": "Species",
"description": "Scientific taxon name. Defaults to Wikidata P225.",
"type": "string"
},
"conservation_status": {
"label": "Conservation status",
"description": "IUCN conservation status. Defaults to Wikidata P141.",
"type": "string"
}
}
}
</templatedata>
t80rv7c1r0ayyhc4fkshqcwmmk1hqhi
User:Iiirxs/Template:Taxobox
2
175657
743948
2026-05-23T11:35:26Z
Iiirxs
49827
Created page with "{{Infobox | above = {{{name|{{PAGENAME}}}}} | image = {{{image|{{#if:{{#property:P18}}|[[File:{{#property:P18}}|frameless|upright=1|alt=]]}}}}} | label1 = Kingdom | data1 = {{{kingdom|}}} | label2 = Family | data2 = {{{family|}}} | label3 = Genus | data3 = {{{genus|{{#property:P171}}}}} | label4 = Species | data4 = {{{species|{{#property:P225}}}}} | label5 = Conservation status | data5 = {{{conservation_status|{{#property:P141}}}}} }} <noinclude> {{documentation}}..."
743948
wikitext
text/x-wiki
{{Infobox
| above = {{{name|{{PAGENAME}}}}}
| image = {{{image|{{#if:{{#property:P18}}|[[File:{{#property:P18}}|frameless|upright=1|alt=]]}}}}}
| label1 = Kingdom
| data1 = {{{kingdom|}}}
| label2 = Family
| data2 = {{{family|}}}
| label3 = Genus
| data3 = {{{genus|{{#property:P171}}}}}
| label4 = Species
| data4 = {{{species|{{#property:P225}}}}}
| label5 = Conservation status
| data5 = {{{conservation_status|{{#property:P141}}}}}
}}
<noinclude>
{{documentation}}
</noinclude>
tusd1q5j28w4b8v1vcppf82oabzt96l
User:Iiirxs/Template:Taxobox/doc
2
175658
743949
2026-05-23T11:35:52Z
Iiirxs
49827
Created page with "== Usage == Use this template on articles about taxa (species, genera, families, etc.). Fields with a Wikidata fallback are filled automatically when the article is connected to a Wikidata item. === Basic usage (Wikidata auto-fill where available) === <pre>{{Infobox taxon}}</pre> === With explicit values === <pre> {{Infobox taxon | name = Panthera leo | image = Lion waiting in Namibia.jpg | kingdom = Animalia | family..."
743949
wikitext
text/x-wiki
== Usage ==
Use this template on articles about taxa (species, genera, families, etc.). Fields with a Wikidata fallback are filled automatically when the article is connected to a Wikidata item.
=== Basic usage (Wikidata auto-fill where available) ===
<pre>{{Infobox taxon}}</pre>
=== With explicit values ===
<pre>
{{Infobox taxon
| name = Panthera leo
| image = Lion waiting in Namibia.jpg
| kingdom = Animalia
| family = Felidae
| genus = Panthera
| species = Panthera leo
| conservation_status = Vulnerable
}}
</pre>
== Parameters ==
{| class="wikitable"
! Parameter !! Wikidata property !! Description
|-
| <code>name</code> || — || Taxon name. Defaults to the page name.
|-
| <code>image</code> || P18 || Image filename (without <code>File:</code> prefix). Defaults to Wikidata P18.
|-
| <code>kingdom</code> || — || Biological kingdom (e.g. Animalia, Plantae). Always explicit — Wikidata encodes the full hierarchy via P171 chains with no direct kingdom property.
|-
| <code>family</code> || — || Biological family. Always explicit — same reason as kingdom.
|-
| <code>genus</code> || P171 || Immediate parent taxon (genus for a species item). Defaults to Wikidata P171.
|-
| <code>species</code> || P225 || Scientific taxon name. Defaults to Wikidata P225.
|-
| <code>conservation_status</code> || P141 || IUCN conservation status. Defaults to Wikidata P141.
|}
== Notes ==
* <code>kingdom</code> and <code>family</code> have no Wikidata fallback because Wikidata represents the taxonomic hierarchy as a chain of P171 (parent taxon) links, not as flat properties. These must always be provided explicitly.
* Requires the [[mw:Extension:Wikibase Client|WikibaseClient]] extension for Wikidata property lookup.
* Requires the [[mw:Extension:Scribunto|Scribunto]] extension and [[Module:Infobox]] for rendering.
<templatedata>
{
"description": "Infobox for taxa (species, genera, etc.). Some fields fall back to Wikidata properties automatically.",
"params": {
"name": {
"label": "Name",
"description": "Taxon name. Defaults to the page name.",
"type": "string",
"suggested": true
},
"image": {
"label": "Image",
"description": "Image filename without File: prefix. Defaults to Wikidata P18.",
"type": "wiki-file-name",
"suggested": true
},
"kingdom": {
"label": "Kingdom",
"description": "Biological kingdom (e.g. Animalia, Plantae). Always explicit.",
"type": "string"
},
"family": {
"label": "Family",
"description": "Biological family. Always explicit.",
"type": "string"
},
"genus": {
"label": "Genus",
"description": "Biological genus (immediate parent taxon). Defaults to Wikidata P171.",
"type": "string"
},
"species": {
"label": "Species",
"description": "Scientific taxon name. Defaults to Wikidata P225.",
"type": "string"
},
"conservation_status": {
"label": "Conservation status",
"description": "IUCN conservation status. Defaults to Wikidata P141.",
"type": "string"
}
}
}
</templatedata>
t80rv7c1r0ayyhc4fkshqcwmmk1hqhi