Wikipedia:Archiv/Alternative Benutzerstatistik/Programme/aktivitaet

Diese Seite gehört zum Wikipedia-Archiv.

# !/usr/bin/perl

use Time::Local;

$debug = 0;       # 1 = debuggen, 0 = nicht debuggen
$bs    = "Linux"; # Windows oder Linux

$aktuell = 90*86400;

mkdir "sort-tmp" unless -d "sort-tmp";

# Stand: 06.07.2006
$admins = "
   1. 1001 �$-1òî(Administrator)
   2. AHZ �$-1òî(Administrator)
   3. APPER �$-1òî(Administrator)
   4. Achim Raschka �$-1òî(Administrator)
   5. Aglarech �$-1òî(Administrator)
   6. Aineias �$-1òî(Administrator)
   7. Aka �$-1òî(Administrator)
   8. AlexR �$-1òî(Administrator)
   9. Alexander Z. �$-1òî(Administrator)
  10. Alkuin �$-1òî(Administrator)
  11. Alma �$-1òî(Administrator)
  12. AndreasPraefcke �$-1òî(Administrator)
  13. Anneke Wolf �$-1òî(Administrator)
  14. Aristeides �$-1òî(Administrator)
  15. Arnomane �$-1òî(Administrator)
  16. ArtMechanic �$-1òî(Administrator)
  17. Asb �$-1òî(Administrator)
  18. Atamari �$-1òî(Administrator)
  19. Avatar �$-1òî(Administrator)
  20. BLueFiSH.as �$-1òî(Administrator)
  21. Baldhur �$-1òî(Administrator)
  22. Bdk �$-1òî(Administrator)
  23. Ben-Zin �$-1òî(Administrator)
  24. Berlin-Jurist �$-1òî(Administrator)
  25. Bernhard55 �$-1òî(Administrator)
  26. Beyer �$-1òî(Administrator)
  27. Birger Fricke �$-1òî(Administrator)
  28. Blaite �$-1òî(Administrator)
  29. Bradypus �$-1òî(Administrator)
  30. Bubo bubo �$-1òî(Administrator)
  31. Carbidfischer �$-1òî(Administrator)
  32. CdaMVvWgS �$-1òî(Administrator)
  33. Chb �$-1òî(Administrator)
  34. Chef �$-1òî(Administrator)
  35. Christian Günther �$-1òî(Administrator)
  36. ChristophLanger �$-1òî(Administrator)
  37. Chrkl �$-1òî(Administrator)
  38. Crux �$-1òî(Administrator)
  39. D �$-1òî(Administrator)
  40. DaB. �$-1òî(Administrator)
  41. Darkone �$-1òî(Administrator)
  42. Davidl �$-1òî(Administrator)
  43. Dbenzhuser �$-1òî(Administrator)
  44. Dickbauch �$-1òî(Administrator)
  45. Dishayloo �$-1òî(Administrator)
  46. Duesentrieb �$-1òî(Administrator)
  47. Dundak �$-1òî(Administrator)
  48. EBB �$-1òî(Administrator)
  49. Echoray �$-1òî(Administrator)
  50. Eike sauer �$-1òî(Administrator)
  51. ElRaki �$-1òî(Administrator)
  52. Elian �$-1òî(Administrator)
  53. Eloquence �$-1òî(developer, Administrator)
  54. Elya �$-1òî(Administrator)
  55. Erwin E aus U �$-1òî(Administrator)
  56. Factumquintus �$-1òî(Administrator)
  57. Fantasy �$-1òî(Administrator)
  58. Fb78 �$-1òî(Administrator)
  59. Filzstift �$-1òî(Administrator)
  60. Finanzer �$-1òî(Administrator)
  61. Fire �$-1òî(Administrator)
  62. Flominator �$-1òî(Administrator)
  63. Florian Adler �$-1òî(Administrator)
  64. Flups �$-1òî(Administrator)
  65. Frank Schulenburg �$-1òî(Administrator)
  66. Fristu �$-1òî(Administrator)
  67. FritzG �$-1òî(Administrator)
  68. Fusslkopp �$-1òî(Administrator)
  69. GS �$-1òî(Administrator)
  70. Gardini �$-1òî(Administrator)
  71. Geiserich77 �$-1òî(Administrator)
  72. Geisslr �$-1òî(Administrator)
  73. Georg Slickers �$-1òî(Administrator)
  74. Geos �$-1òî(Administrator)
  75. Gerbil �$-1òî(Administrator)
  76. Gnu1742 �$-1òî(Administrator)
  77. Gunter.krebs �$-1òî(Administrator)
  78. Gunther �$-1òî(Administrator)
  79. H-stt �$-1òî(Administrator)
  80. Hadhuey �$-1òî(Administrator)
  81. Hafenbar �$-1òî(Administrator)
  82. He3nry �$-1òî(Administrator)
  83. Head �$-1òî(Administrator)
  84. Hejkal �$-1òî(Administrator)
  85. Henriette Fiebig �$-1òî(Administrator)
  86. Hermannthomas �$-1òî(Administrator)
  87. Herr Klugbeisser �$-1òî(Administrator)
  88. Hoch auf einem Baum �$-1òî(Administrator)
  89. Hoheit �$-1òî(Administrator)
  90. IGEL �$-1òî(Administrator)
  91. Idler �$-1òî(Administrator)
  92. Igelball �$-1òî(Administrator)
  93. Ilja Lorek �$-1òî(Administrator)
  94. Irmgard �$-1òî(Administrator)
  95. Ixitixel �$-1òî(Administrator)
  96. J budissin �$-1òî(Administrator)
  97. JD �$-1òî(Administrator)
  98. JHeuser �$-1òî(Administrator)
  99. JakobVoss �$-1òî(Administrator)
 100. Janneman �$-1òî(Administrator)
 101. Jcornelius �$-1òî(Administrator)
 102. Jergen �$-1òî(Administrator)
 103. Jofi �$-1òî(Administrator)
 104. John N. �$-1òî(Administrator)
 105. KMJ �$-1òî(Administrator)
 106. Kam Solusar �$-1òî(Administrator)
 107. Karl Gruber �$-1òî(Administrator)
 108. Karl-Henner �$-1òî(Administrator)
 109. Kh80 �$-1òî(Administrator)
 110. Kiker99 �$-1òî(Administrator)
 111. Kku �$-1òî(Administrator)
 112. Kubrick �$-1òî(Administrator)
 113. Kurt Jansson �$-1òî(Administrator)
 114. Langec �$-1òî(Administrator)
 115. Leipnizkeks �$-1òî(Administrator)
 116. Lennert B �$-1òî(Administrator)
 117. LeonWeber �$-1òî(Administrator)
 118. Liesel �$-1òî(Administrator)
 119. Limasign �$-1òî(Administrator)
 120. LosHawlos �$-1òî(Administrator)
 121. Lou.gruber �$-1òî(Administrator)
 122. Lung �$-1òî(Administrator)
 123. Lyzzy �$-1òî(Administrator)
 124. Maclemo �$-1òî(Administrator)
 125. Magadan �$-1òî(Administrator)
 126. Magnus Manske �$-1òî(developer, Administrator)
 127. Marcus Cyron �$-1òî(Administrator)
 128. Markus Mueller �$-1òî(Administrator)
 129. Markus Schweiß �$-1òî(Administrator)
 130. Martin-vogel �$-1òî(Administrator)
 131. Mathias Schindler �$-1òî(Administrator)
 132. Matthäus Wander �$-1òî(Administrator)
 133. Mazbln �$-1òî(Administrator)
 134. Media lib �$-1òî(Administrator)
 135. Melkom �$-1òî(Administrator)
 136. MichaelDiederich �$-1òî(Bürokrat, Administrator)
 137. Mikue �$-1òî(Administrator)
 138. Mnh �$-1òî(Administrator)
 139. Mogelzahn �$-1òî(Administrator)
 140. Napa �$-1òî(Administrator)
 141. Nb �$-1òî(Administrator)
 142. Nerd �$-1òî(Administrator)
 143. NiTenIchiRyu �$-1òî(Administrator)
 144. NickKnatterton �$-1òî(Administrator)
 145. Nina �$-1òî(Administrator)
 146. Nocturne �$-1òî(Administrator)
 147. Okatjerute �$-1òî(Administrator)
 148. Ot �$-1òî(Administrator)
 149. Pelz �$-1òî(Administrator)
 150. Perrak �$-1òî(Administrator)
 151. Peterlustig �$-1òî(Administrator)
 152. Philipendula �$-1òî(Administrator)
 153. Pischdi �$-1òî(Administrator)
 154. Pit �$-1òî(Administrator)
 155. Poupou l'quourouce �$-1òî(Administrator)
 156. RKraasch �$-1òî(Administrator)
 157. Rainer Zenz �$-1òî(Administrator)
 158. Ralf Roletschek �$-1òî(Administrator)
 159. Raven �$-1òî(Administrator)
 160. Rax �$-1òî(Administrator)
 161. Raymond �$-1òî(Administrator)
 162. Rdb �$-1òî(Administrator)
 163. Redf0x �$-1òî(Administrator)
 164. Richardfabi �$-1òî(Administrator)
 165. RobbyBer �$-1òî(Administrator)
 166. Robert Kropf �$-1òî(Administrator)
 167. Robodoc �$-1òî(Administrator)
 168. Sarazyn �$-1òî(Administrator)
 169. Schewek �$-1òî(Administrator)
 170. Schnargel �$-1òî(Administrator)
 171. Schwalbe �$-1òî(Administrator)
 172. Sechmet �$-1òî(Administrator)
 173. Seidl �$-1òî(Administrator)
 174. Sicherlich �$-1òî(Administrator)
 175. Sigune �$-1òî(Administrator)
 176. Silberchen �$-1òî(Administrator)
 177. Skriptor �$-1òî(Administrator)
 178. Slomox �$-1òî(Administrator)
 179. Smurf �$-1òî(Administrator)
 180. Southpark �$-1òî(Administrator)
 181. Srbauer �$-1òî(Administrator)
 182. Stahlkocher �$-1òî(Administrator)
 183. Stechlin �$-1òî(Administrator)
 184. Stefan Kühn �$-1òî(Bürokrat, Administrator)
 185. Stefan64 �$-1òî(Administrator)
 186. Steffen Löwe Gera �$-1òî(Administrator)
 187. Stern �$-1òî(Administrator)
 188. Steschke �$-1òî(Administrator)
 189. Stw �$-1òî(Administrator)
 190. Superbass �$-1òî(Administrator)
 191. Terabyte �$-1òî(Administrator)
 192. Thomas Luft �$-1òî(Administrator)
 193. Threedots �$-1òî(Administrator)
 194. Tigerente �$-1òî(Administrator)
 195. Tilman Berger �$-1òî(Administrator)
 196. Tobnu �$-1òî(Administrator)
 197. Tolanor �$-1òî(Administrator)
 198. TomK32 �$-1òî(Administrator)
 199. Tsor �$-1òî(Administrator)
 200. Tsui �$-1òî(Administrator)
 201. Tullius �$-1òî(Administrator)
 202. UW �$-1òî(Administrator)
 203. Ureinwohner �$-1òî(Administrator)
 204. Uwe Gille �$-1òî(Administrator)
 205. Vic Fontaine �$-1òî(Administrator)
 206. Vigala Veia �$-1òî(Administrator)
 207. Voyager �$-1òî(Administrator)
 208. Vulture �$-1òî(Administrator)
 209. W.wolny �$-1òî(Administrator)
 210. Wahrerwattwurm �$-1òî(Administrator)
 211. Waugsberg �$-1òî(Administrator)
 212. Wolfgangbeyer �$-1òî(Administrator)
 213. Wst �$-1òî(Administrator)
 214. Xocolatl �$-1òî(Administrator)
 215. Zenogantner �$-1òî(Administrator)
 216. Zenon �$-1òî(Administrator)
 217. Zinnmann �$-1òî(Administrator)
 218. Zumbo �$-1òî(Administrator)
";
while($admins =~ /\d+\. (.*?) .*?\(.*?\)\n/g) { $admin{$1} = 1; }

@keineAdmins = (
# "217", "Achim Raschka", "AN", "Andrsvoss", "Albrecht Conz", "Benowar", "Bierdimpfl", "Diana",
# "El", "ErikDunsing", "Erwin E aus U", "Fritz", "HenrikHolke", "Isis2000",
# "Keichwa", "Lienhard Schulz", "MAK", "Martin W. Richter", "Martin-vogel",
# "Odin", "Otto", "Paddy", "Pjacobi", "SirJective", "Southpark", "Stefan Volk", "Wiska Bodo"
);
map { $keinAdmin{$_} = 1 } @keineAdmins;

$bots = "
   1. AgentSpartiBot �$-1òî(Bot)
   2. AkaBot �$-1òî(Bot)
   3. ApeBot �$-1òî(Bot)
   4. BWBot �$-1òî(Bot)
   5. Botteler �$-1òî(Bot)
   6. Chlewbot �$-1òî(Bot)
   7. Chobot �$-1òî(Bot)
   8. ConBot �$-1òî(Bot)
   9. CyeZBot �$-1òî(Bot)
  10. CyroBot �$-1òî(Bot)
  11. DHN-bot �$-1òî(Bot)
  12. Eskimbot �$-1òî(Bot)
  13. FlaBot �$-1òî(Bot)
  14. Flothi bot �$-1òî(Bot)
  15. GGNBot �$-1òî(Bot)
  16. GeoBot �$-1òî(Bot)
  17. Gpvosbot �$-1òî(Bot)
  18. Heikobot �$-1òî(Bot)
  19. KocjoBot �$-1òî(Bot)
  20. KokoBot �$-1òî(Bot)
  21. LeonardoRob0t �$-1òî(Bot)
  22. LiBot �$-1òî(Bot)
  23. MelancholieBot �$-1òî(Bot)
  24. MoriBot �$-1òî(Bot)
  25. OlliBot �$-1òî(Bot)
  26. PixelBot �$-1òî(Bot)
  27. PnBot �$-1òî(Bot)
  28. PortalBot �$-1òî(Bot)
  29. PyBot �$-1òî(Bot)
  30. QS-Bot �$-1òî(Bot)
  31. RCBot �$-1òî(Bot)
  32. RKBot �$-1òî(Bot)
  33. RedBot �$-1òî(Bot)
  34. Robbot �$-1òî(Bot)
  35. RobotE �$-1òî(Bot)
  36. RobotQuistnix �$-1òî(Bot)
  37. SirBot �$-1òî(Bot)
  38. Sk-Bot �$-1òî(Bot)
  39. Slobot �$-1òî(Bot)
  40. SpBot �$-1òî(Bot)
  41. Thijs!bot �$-1òî(Bot)
  42. Tsca.bot �$-1òî(Bot)
  43. Ugur Basak Bot �$-1òî(Bot)
  44. VBot �$-1òî(Bot)
  45. YurikBot �$-1òî(Bot)
  46. Zwobot �$-1òî(Bot)
";
while($bots =~ /\d+\. (.*?) .*?\(.*?\)\n/g) { $bot{$1} = 1; }
$bot{"conversion script"} = 1;
$bot{"Template namespace initialisation script"} = 1;
$bot{"Kategobot"} = 1;
$bot{"Plattbot"} = 1;
$bot{"HotBot"} = 1;
$bot{"Newsbot"} = 1;

print int(keys %admin) . " Admins, " . int(keys %bot) . " Bots\n";

sub istAnon {
	my $user = shift;
	$user =~ /^\d+\.\d+\.\d+\.(\d+|xxx)$/ || $user =~ /\.\S*?\.(\w\w|net|com|edu)$/i;
}

sub zeit {
	my $timestamp = shift;
	$timestamp =~ /^(....)(..)(..)(..)(..)(..)/;
	timelocal($6, $5, $4, $3, $2-1, $1-1900);
}

$mitKat = -f "kattree" && -r _ && -f "katlinks" && -r _;

if($mitKat) {
	open KATTREE, "kattree";
	while(<KATTREE>) {
		chop;
		($subkat, @kat) = split;
		push @{$subkat{$_}}, $subkat for @kat;
	}
	close KATTREE;
	@hauptkategorien = sort @{$subkat{"!Hauptkategorie"}};
	foreach $hk (@hauptkategorien) {
		@kats = ($hk); %tag = ();
		while(@kats>0) {
			$kat = pop @kats;
			next if defined $tag{$kat};
			$tag{$kat} = 1;
			push @{$hauptkatKat{$kat}}, $hk;
			push @kats, @{$subkat{$kat}};
		}
	}
	# print $_ . ": " . join(",", @{$hauptkatKat{$_}}) . "\n" for keys %hauptkat;
	open KATLINKS, "katlinks";
	while(<KATLINKS>) {
		chop;
		($artikel, @kat) = split;
		%hauptkatTmp = ();
		for $kat (@kat) {
			$hauptkatTmp{$_} = 1 for @{$hauptkatKat{$kat}};
		}
		@{$hauptkat{$artikel}} = keys %hauptkatTmp;
	}
	close KATLINKS;
}

if($bs eq "Linux") {
	open IN, "tail -1 zsf|";
	$jetzt = zeit(<IN>);
} else {
	open IN, "zsf";
	while(<IN>) {
		$jetzt = zeit $_;
	}
}

print "Anzahl der Bearbeitungen bestimmen ...\n";
open IN, "zsf";
open OUT, ">zsf.tmp2";
while(<IN>) {
	chop;
	($timestamp, $l, $is_redirect, $loesch, $text, $user, $namespace, $titel) = split;
	next if $timestamp eq "00000000000000" || $user eq "_" || $titel eq "_" || $namespace == 99;
	$user = "+Anon+" if istAnon($user);
	if($namespace eq "0") {
		$ldiff = $l-$lalt{$titel};
		print OUT "$user $timestamp $titel $l $ldiff $is_redirect $loesch $text\n";
		$lalt{$titel} = $l;
	}
	$titel =~ s/_/ /g; $user =~ s/_/ /g;
	next if $ns==2 || $user eq "WikiSysop" || $user eq "WikiDeveloper";
	$nVers{$titel}++ if $namespace eq "0"; # die Keys von %nVers werden unten für die Längenberechnung benutzt
	$gesamtEdits{$user}++;
	$Zeit = zeit($timestamp);
	unless($is_redirect) {  # Die Zeitstempel einiger Redirects sind falsch.
		$erstbearbeitung{$user}  = $Zeit if !defined $erstbearbeitung{$user}  || $Zeit<$erstbearbeitung{$user};
		$letztbearbeitung{$user} = $Zeit if !defined $letztbearbeitung{$user} || $Zeit>$letztbearbeitung{$user};
	}
	if(!defined $letzteBearbeitung{"$user#$titel#$namespace"} || $Zeit-$letzteBearbeitung{"$user#$titel#$namespace"}>3600) {
		$nEchteEdits++;
		$echteEdits{$user}++;
		if($mitKat) { $echteEditsKat{$_}{$user}++ for @{$hauptkat{$titel}}; }
		if($jetzt-$Zeit<$aktuell) {
			$echteEditsAktuell{$user}++;
			if($mitKat) { $echteEditsAktuellKat{$_}{$user}++ for @{$hauptkat{$titel}}; }
		}
		$letzteBearbeitung{"$user#$titel#$namespace"} = $Zeit;
	}
	$loesch{$text}++ if $namespace==0 && $loesch;
}
close OUT; %lalt = ();

%letzteBearbeitung = undef;

# fehlerhafte Erstbearbeitungszeiten manuell korrigieren:
# grep 'benutzername' < zsf | head -10
# davon den ersten richtigen Zeitstempel verwenden
$erstbearbeitung{"AndreasPraefcke"} = zeit("20041005150418");

# print "Benutzer mit den meisten Bearbeitungen:\n";
@gesamtEditsRangfolge = sort { $gesamtEdits{$b} <=> $gesamtEdits{$a} } keys %gesamtEdits;
for($i=0; $i<@gesamtEditsRangfolge; $i++) {
	$gesamtEditsPos{$gesamtEditsRangfolge[$i]} = $i+1;
}

open OUT, ">AnzahlEdits.out";

print OUT "{| border=\"1\" cellspacing=\"0\"\n";
print OUT "|-\n";
print OUT "! Pos. || off. || Bearb. || Bearb. aktuell || zus. || Benutzer || Erstbearb. || Letztbearb. \n";
print OUT "|-\n";
@echteEditsRangfolge = sort { $echteEdits{$b} <=> $echteEdits{$a} } keys %echteEdits;
for($i=0, $j=0; $i<200+$j; $i++) {
	$user = $echteEditsRangfolge[$i];
	if($user eq "+Anon+" || defined $bot{$user}) {
		$j++;
		next;
	}
	$zus = $gesamtEdits{$user}/$echteEdits{$user};
	printf OUT "| %3i || %3i || %5i || %5i || " .
		"style=\"background:#%s;\" | %.2f || [[Benutzer:%s|%s]] || %i || %i\n",
			$i-$j+1, $gesamtEditsPos{$user}, $echteEdits{$user}, $echteEditsAktuell{$user}, $zus>1.2?($zus>1.5?"ff5050":"ffff30"):"50ff50",
			$zus, $user, $user, int(($jetzt-$erstbearbeitung{$user})/86400), int(($jetzt-$letztbearbeitung{$user})/86400);
	print OUT "|-\n";
}
print OUT "|}\n";

############################################################### print "Größe der beigetragenen Textmenge bestimmen ...\n";

sub zusammenrechnen {
	my ($aenderung, $aenderungAktuell, $max_laenge, $titel) = @_;
	my $user;
	foreach $user (keys %$aenderung) {
		$aenderung->{$user} =  $max_laenge if $aenderung->{$user} >  $max_laenge;
		$aenderung->{$user} = -$max_laenge if $aenderung->{$user} < -$max_laenge;
		$gesamtBytes{$user} += $aenderung->{$user};
		if($mitKat) { $gesamtBytesKat{$_}{$user} += $aenderung->{$user} for @{$hauptkat{$titel}}; }
		$nEchteBytes += $aenderung->{$user};
	}
	foreach $user (keys %$aenderungAktuell) {
		$aenderungAktuell->{$user} =  $max_laenge if $aenderungAktuell->{$user} >  $max_laenge;
		$aenderungAktuell->{$user} = -$max_laenge if $aenderungAktuell->{$user} < -$max_laenge;
		$gesamtBytesAktuell{$user} += $aenderungAktuell->{$user};
		if($mitKat) { $gesamtBytesAktuellKat{$_}{$user} += $aenderungAktuell->{$user} for @{$hauptkat{$titel}}; }
	}
}

# negative Längenänderungen nur in +/- 10-Minuten-Zeitraum berücksichtigen
sub schreibeVersion {
	($user, $timestamp, $titel, $l, $ldiff, $is_redirect, $loesch, $text) = @{shift @versionen};
	$ldiff=$ldiff<0?0:$ldiff;
	print OUT "$titel $timestamp $l $ldiff $is_redirect $loesch $text $user\n";
}

sortExtern("zsf.tmp2", "zsf.tmp2s");
open IN, "zsf.tmp2s";
open OUT, ">zsf.tmp";
$user_alt = "";
while(<IN>) {
  chop;
  push @versionen, [ split ];
  if($versionen[-1]->[0] ne $versionen[0]->[0]) { # neuer User
    while(@versionen>1) { schreibeVersion(); }
  }
  while(zeit($versionen[-1]->[1])-zeit($versionen[0]->[1])>600) { schreibeVersion(); }
  my ($ldiffpos, $ldiffneg) = (0, 0);
  foreach my $vers (@versionen) {
    $ldiffpos += $vers->[4] if $vers->[4]>0;
    $ldiffneg -= $vers->[4] if $vers->[4]<0;
  }
  $ldiffpos = $ldiffneg = $ldiffpos>$ldiffneg?$ldiffneg:$ldiffpos;
  foreach my $vers (@versionen) {
    if($vers->[4]>0) {
      if($vers->[4]<$ldiffpos) {
	$ldiffpos -= $vers->[4]; $vers->[4] = 0;
      } else {
	$vers->[4] -= $ldiffpos; $ldiffpos = 0;
      }
    } elsif($vers->[4]<0) {
      if(-$vers->[4]<$ldiffneg) {
	$ldiffneg += $vers->[4]; $vers->[4] = 0;
      } else {
	$vers->[4] += $ldiffneg; $ldiffneg = 0;
      }
    }
  }
}
while(@versionen>0) { schreibeVersion(); }
close OUT; unlink "zsf.tmp2s";

sortExtern("zsf.tmp", "zsf.tmps");
open IN, "zsf.tmps";
$titel_alt="";
while(<IN>) {
  chop;
  ($titel, $timestamp, $l, $ldiff, $is_redirect, $loesch, $text, $user) = split;
  $titel =~ s/_/ /g; $user =~ s/_/ /g;
  if($titel ne $titel_alt) {
    zusammenrechnen(\%aenderung, \%aenderungAktuell, $max_laenge, $titel) if $titel_alt ne "";
    $nArt++;
# printf "%3i %s\n", $nVers{$titel}, $titel;
    %text_hash = ();
    $titel2 = $titel;
    $titel2 =~ s/'/\\'/g;
    $loesch = 0; $max_laenge = 0; %aenderung = (); %aenderungAktuell = ();
    $titel_alt = $titel;
  }
  next if $user eq "WikiSysop" || $user eq "WikiDeveloper";
  $Zeit = zeit($timestamp);
  $gesamtGroesse += $l if $tab eq "cur";
  $istRev = $istLoesch = 0;
  if(defined $text_hash{$text}) {
    $reverts{$titel}++;
    $nRev++;
    $istRev=1;
  }
  if(defined $loesch{$text}) {
    $loesch=1; $istLoesch=1;
  } elsif($loesch) {
    $loesch=0; $istLoesch=1;
  }
  $aenderung{$user}+=$ldiff unless $istRev||$istLoesch;
  $aenderungAktuell{$user}+=$ldiff if($jetzt-$Zeit<$aktuell && !($istRev||$istLoesch));
  $max_laenge = $l if $l>$max_laenge;
  $text_hash{$text}++;
}
zusammenrechnen(\%aenderung, \%aenderungAktuell, $max_laenge, $titel) if $titel_alt ne "";
unlink "zsf.tmps";

@sGesamtBytes = sort { $gesamtBytes{$b} <=> $gesamtBytes{$a} } keys %gesamtBytes;

open OUT, ">AnzahlBytes.out";
print OUT "$nEchteEdits Bearbeitungen, $gesamtGroesse Bytes insgesamt, $nEchteBytes Bytes gezählt\n\n";
print OUT "{| cellspacing=\"0\" border=\"1\"\n";
print OUT "|-\n";
print OUT "! Pos. || Bytes || Bytes aktuell || Benutzer || Erstbearb. || Letztbearb.\n";
print OUT "|-\n";
for($i=0, $j=0; $i<200+$j; $i++) {
  $user = $sGesamtBytes[$i];
  if($user eq "+Anon+" || defined $bot{$user}) {
    $j++;
    next;
  }
  printf OUT "| %i || %i || %i || [[Benutzer:%s|%s]] || %i || %i\n", $i-$j+1, $gesamtBytes{$user},
    $gesamtBytesAktuell{$user}, $user, $user, int(($jetzt-$erstbearbeitung{$user})/86400),
      int(($jetzt-$letztbearbeitung{$user})/86400);
  print OUT "|-\n";
}
print OUT "|}\n";

########################################################### foreach $user (keys %gesamtBytes) {
	$Punkte{$user}        = $echteEdits{$user}+int($gesamtBytes{$user}/240);
	$PunkteAktuell{$user} = $echteEditsAktuell{$user}+int($gesamtBytesAktuell{$user}/240);
	if($mitKat) {
		foreach $kat (@hauptkategorien) {
			$PunkteKat{$kat}{$user}        = $echteEditsKat{$kat}{$user}+int($gesamtBytesKat{$kat}{$user}/240);
			$PunkteGesamtKat{$kat} += $PunkteKat{$kat}{$user};
			$PunkteAktuellKat{$kat}{$user} = $echteEditsAktuellKat{$kat}{$user}+int($gesamtBytesAktuellKat{$kat}{$user}/240);
		}
	}
	if(int(($jetzt-$letztbearbeitung{$user})/86400)<30) {
		$PunkteAktiv{$user}        = $Punkte{$user};
		$PunkteAktuellAktiv{$user} = $PunkteAktuell{$user};
	} else {
		$PunkteInaktiv{$user} = $Punkte{$user};
	}
}

@sPunkte             = sort { $Punkte{$b}             <=> $Punkte{$a}             } keys %Punkte;
@sPunkteAktiv        = sort { $PunkteAktiv{$b}        <=> $PunkteAktiv{$a}        } keys %PunkteAktiv;
@sPunkteInaktiv      = sort { $PunkteInaktiv{$b}      <=> $PunkteInaktiv{$a}      } keys %PunkteInaktiv;
@sPunkteAktuell      = sort { $PunkteAktuell{$b}      <=> $PunkteAktuell{$a}      } keys %PunkteAktuell;
@sPunkteAktuellAktiv = sort { $PunkteAktuellAktiv{$b} <=> $PunkteAktuellAktiv{$a} } keys %PunkteAktuellAktiv;

open OUT, ">Aktivitaet.txt";
foreach $user (@sPunkte) {
  printf OUT "%7i %7i %9i %7i %7i %9i %11i %11i  %s\n", $Punkte{$user}, $echteEdits{$user}, $gesamtBytes{$user},
    $PunkteAktuell{$user}, $echteEditsAktuell{$user}, $gesamtBytesAktuell{$user}, $erstbearbeitung{$user},
    $letztbearbeitung{$user}, $user;
}

open OUT, ">AnzahlPunkte.out";
print OUT "===Aktive Benutzer===\n";
print OUT "{| cellspacing=\"20\"\n";
print OUT "| Gesamtaktivität || Aktivität in den letzten 90 Tagen\n";
print OUT "|- valign=\"top\"\n";
print OUT "|\n";
print OUT "{| cellspacing=\"0\" border=\"1\"\n";
print OUT "|-\n";
print OUT "! Pos. || Punkte || Benutzer || A || Erstbearb. || Letztbearb.\n";
print OUT "|-\n";
for($i=0, $j=0, $k=0; $i<200+$j+$k; $i++) {
  $user = $sPunkteAktiv[$i];
  if($user eq "+Anon+" || defined $bot{$user}) {
    $j++;
    next;
  }
# print "$i $j $k\n";
  printf OUT "| %i || %i || [[Benutzer:%s|%s]] || %s || %i || %i\n", $i-$j-$k+1, $PunkteAktiv{$user}, $user, $user,
    ($admin{$user}?"+":($keinAdmin{$user}?"-":"")),int(($jetzt-$erstbearbeitung{$user})/86400),
    int(($jetzt-$letztbearbeitung{$user})/86400);
  print OUT "|-\n";
  $k = $PunkteAktiv{$user}==$PunkteAktiv{$sPunkteAktiv[$i+1]}?$k+1:0;
}
print OUT "|}\n";
print OUT "|\n";
print OUT "{| cellspacing=\"0\" border=\"1\"\n";
print OUT "|-\n";
print OUT "! Pos. || Punkte || Benutzer || A\n";
print OUT "|-\n";
for($i=0, $j=0, $k=0; $i<200+$j+$k; $i++) {
  $user = $sPunkteAktuellAktiv[$i];
  if($user eq "+Anon+" || defined $bot{$user}) {
    $j++;
    next;
  }
  printf OUT "| %i || %i || [[Benutzer:%s|%s]] || %s\n", $i-$j-$k+1, $PunkteAktuellAktiv{$user}, $user, $user,
   ($admin{$user}?"+":($keinAdmin{$user}?"-":""));
  print OUT "|-\n";
  $k = $PunkteAktuellAktiv{$user}==$PunkteAktuellAktiv{$sPunkteAktuellAktiv[$i+1]}?$k+1:0;
}
print OUT "|}\n";
print OUT "|}\n\n";

print OUT "===Inaktive Benutzer===\n";
print OUT "{| cellspacing=\"20\"\n";
print OUT "|\n";
print OUT "{| cellspacing=\"0\" border=\"1\"\n";
print OUT "|-\n";
print OUT "! Pos. || Punkte || Benutzer || A || Erstbearb. || Letztbearb.\n";
print OUT "|-\n";
for($i=0, $j=0, $k=0; $i<50+$j+$k; $i++) {
  $user = $sPunkteInaktiv[$i];
  if($user eq "+Anon+" || defined $bot{$user}) {
    $j++;
    next;
  }
  printf OUT "| %i || %i || [[Benutzer:%s|%s]] || %s || %i || %i\n", $i-$j-$k+1, $PunkteInaktiv{$user}, $user, $user,
    ($admin{$user}?"+":($keinAdmin{$user}?"-":"")), int(($jetzt-$erstbearbeitung{$user})/86400),
      int(($jetzt-$letztbearbeitung{$user})/86400);
  print OUT "|-\n";
  $k = $PunkteInaktiv{$user}==$PunkteInaktiv{$sPunkteInaktiv[$i+1]}?$k+1:0;
}
print OUT "|}\n";
print OUT "|}\n";
close OUT;

if($mitKat) {
	open OUT, ">AnzahlPunkteKat.out";
	foreach $kat (@hauptkategorien) {
		next if $PunkteGesamtKat{$kat}<10000;
		@sPunkteKat        = sort { $PunkteKat{$kat}{$b}        <=> $PunkteKat{$kat}{$a}        }
			keys %{$PunkteKat{$kat}};
		@sPunkteAktuellKat = sort { $PunkteAktuellKat{$kat}{$b} <=> $PunkteAktuellKat{$kat}{$a} }
			keys %{$PunkteAktuellKat{$kat}};
		$katSp = $kat;
		$katSp =~ s/_/ /g;
		print OUT "===[[:Kategorie:$katSp|$katSp]]===\n";
		print OUT "{| cellspacing=\"20\"\n";
		print OUT "| Gesamtaktivität || Aktivität in den letzten 90 Tagen\n";
		print OUT "|- valign=\"top\"\n";
		print OUT "|\n";
		print OUT "{| cellspacing=\"0\" border=\"1\"\n";
		print OUT "|-\n";
		print OUT "! Pos. || Punkte || Benutzer || A || Erstbearb. || Letztbearb.\n";
		print OUT "|-\n";
		for($i=0, $j=0, $k=0; $i<50+$j+$k; $i++) {
			$user = $sPunkteKat[$i];
			if($user eq "+Anon+" || defined $bot{$user}) {
				$j++;
				next;
			}
			printf OUT "| %i || %i || [[Benutzer:%s|%s]] || %s || %i || %i\n", $i-$j-$k+1,
				$PunkteKat{$kat}{$user}, $user, $user, ($admin{$user}?"+":($keinAdmin{$user}?"-":"")),
				int(($jetzt-$erstbearbeitung{$user})/86400), int(($jetzt-$letztbearbeitung{$user})/86400);
			print OUT "|-\n";
			$k = $PunkteKat{$kat}{$user}==$PunkteKat{$kat}{$sPunkteKat[$i+1]}?$k+1:0;
		}
		print OUT "|}\n";
		print OUT "|\n";
		print OUT "{| cellspacing=\"0\" border=\"1\"\n";
		print OUT "|-\n";
		print OUT "! Pos. || Punkte || Benutzer || A\n";
		print OUT "|-\n";
		for($i=0, $j=0, $k=0; $i<50+$j+$k; $i++) {
			$user = $sPunkteAktuellKat[$i];
			if($user eq "+Anon+" || defined $bot{$user}) {
				$j++;
				next;
			}
			printf OUT "| %i || %i || [[Benutzer:%s|%s]] || %s\n", $i-$j-$k+1, $PunkteAktuellKat{$kat}{$user},
				$user, $user, ($admin{$user}?"+":($keinAdmin{$user}?"-":""));
			print OUT "|-\n";
			$k = $PunkteAktuellKat{$kat}{$user}==$PunkteAktuellKat{$kat}{$sPunkteAktuellKat[$i+1]}?$k+1:0;
		}
		print OUT "|}\n";
		print OUT "|}\n\n";
	}
	close OUT;
}

rmdir "sort-tmp";

#################################################################### sub flushLines {
	my ($lines, $n) = @_;
	@$lines = sort @$lines;
	open OUT, ">sort-tmp/$n";
	print OUT $_ for @$lines;
	close OUT;
}

sub sortExtern {
	my ($unsorted, $sorted) = @_;
	open IN, $unsorted;
	my $n=0;
	my $lines = [];
	while(<IN>) {
		push @$lines, $_;
		if(@$lines==500000) {
			flushLines($lines, $n);
			$lines = []; $n++;
		}
	}
	flushLines($lines, $n);
	$lines = []; $n++;
	close IN;
	unlink $unsorted;

	my @in = ();
	my @z = ();
	for(my $i=0; $i<$n; $i++) {
		open $in[$i], "sort-tmp/$i";
		my $line = readline $in[$i];
		push @z, [ $line, $i ];
	}

	open OUT, ">$sorted";
	while(@z>0) {
		@z = sort { $b->[0] cmp $a->[0] } @z;
		my $y = pop @z;
		print OUT $y->[0];
		my $i = $y->[1];
		unless(eof $in[$i]) {
			my $line = readline $in[$i];
			push @z, [ $line, $i ];
		}
	}
	close OUT;

	for(my $i=0; $i<$n; $i++) {
		close $in[$i];
		unlink "sort-tmp/$i";
	}
}