Initial revision
authorLee Daniel Crocker <lcrocker@users.mediawiki.org>
Mon, 14 Apr 2003 23:10:40 +0000 (23:10 +0000)
committerLee Daniel Crocker <lcrocker@users.mediawiki.org>
Mon, 14 Apr 2003 23:10:40 +0000 (23:10 +0000)
247 files changed:
AdminSettings.sample [new file with mode: 0644]
INSTALL [new file with mode: 0644]
LocalSettings.sample [new file with mode: 0644]
README [new file with mode: 0644]
docs/deferred.doc [new file with mode: 0644]
docs/design.doc [new file with mode: 0644]
docs/globals.doc [new file with mode: 0644]
docs/language.doc [new file with mode: 0644]
docs/linkcache.doc [new file with mode: 0644]
docs/schema.doc [new file with mode: 0644]
docs/skin.doc [new file with mode: 0644]
docs/title.doc [new file with mode: 0644]
docs/user.doc [new file with mode: 0644]
images/favicon.ico [new file with mode: 0644]
images/startrek.png [new file with mode: 0644]
images/valid-html401.png [new file with mode: 0644]
images/wiki.png [new file with mode: 0644]
includes/Article.php [new file with mode: 0644]
includes/DatabaseFunctions.php [new file with mode: 0644]
includes/DefaultSettings.php [new file with mode: 0644]
includes/DifferenceEngine.php [new file with mode: 0644]
includes/FulltextStoplist.php [new file with mode: 0644]
includes/GlobalFunctions.php [new file with mode: 0644]
includes/Interwiki.php [new file with mode: 0644]
includes/LinkCache.php [new file with mode: 0644]
includes/LinksUpdate.php [new file with mode: 0644]
includes/LogPage.php [new file with mode: 0644]
includes/Namespace.php [new file with mode: 0644]
includes/OutputPage.php [new file with mode: 0644]
includes/SearchEngine.php [new file with mode: 0644]
includes/SearchUpdate.php [new file with mode: 0644]
includes/Setup.php [new file with mode: 0644]
includes/SiteStatsUpdate.php [new file with mode: 0644]
includes/Skin.php [new file with mode: 0644]
includes/SkinCologneBlue.php [new file with mode: 0644]
includes/SkinFramed.php [new file with mode: 0644]
includes/SkinNostalgia.php [new file with mode: 0644]
includes/SkinStandard.php [new file with mode: 0644]
includes/SpecialAllpages.php [new file with mode: 0644]
includes/SpecialAsksql.php [new file with mode: 0644]
includes/SpecialBlockip.php [new file with mode: 0644]
includes/SpecialBooksources.php [new file with mode: 0644]
includes/SpecialContributions.php [new file with mode: 0644]
includes/SpecialDebug.php [new file with mode: 0644]
includes/SpecialEmailuser.php [new file with mode: 0644]
includes/SpecialImagelist.php [new file with mode: 0644]
includes/SpecialIntl.php [new file with mode: 0644]
includes/SpecialIpblocklist.php [new file with mode: 0644]
includes/SpecialListusers.php [new file with mode: 0644]
includes/SpecialLockdb.php [new file with mode: 0644]
includes/SpecialLonelypages.php [new file with mode: 0644]
includes/SpecialLongpages.php [new file with mode: 0644]
includes/SpecialMaintenance.php [new file with mode: 0644]
includes/SpecialMovepage.php [new file with mode: 0644]
includes/SpecialNeglectedpages.php [new file with mode: 0644]
includes/SpecialNewpages.php [new file with mode: 0644]
includes/SpecialPopularpages.php [new file with mode: 0644]
includes/SpecialPreferences.php [new file with mode: 0644]
includes/SpecialRandompage.php [new file with mode: 0644]
includes/SpecialRecentchanges.php [new file with mode: 0644]
includes/SpecialRecentchangeslinked.php [new file with mode: 0644]
includes/SpecialShortpages.php [new file with mode: 0644]
includes/SpecialSpecialpages.php [new file with mode: 0644]
includes/SpecialStatistics.php [new file with mode: 0644]
includes/SpecialUndelete.php [new file with mode: 0644]
includes/SpecialUnlockdb.php [new file with mode: 0644]
includes/SpecialUnusedimages.php [new file with mode: 0644]
includes/SpecialUpload.php [new file with mode: 0644]
includes/SpecialUserlogin.php [new file with mode: 0644]
includes/SpecialUserlogout.php [new file with mode: 0644]
includes/SpecialVote.php [new file with mode: 0644]
includes/SpecialWantedpages.php [new file with mode: 0644]
includes/SpecialWatchlist.php [new file with mode: 0644]
includes/SpecialWhatlinkshere.php [new file with mode: 0644]
includes/Title.php [new file with mode: 0644]
includes/UpdateClasses.php [new file with mode: 0644]
includes/User.php [new file with mode: 0644]
includes/UserTalkUpdate.php [new file with mode: 0644]
includes/UserUpdate.php [new file with mode: 0644]
includes/Utf8Case.php [new file with mode: 0644]
includes/ViewCountUpdate.php [new file with mode: 0644]
install.php [new file with mode: 0644]
languages/Language.php [new file with mode: 0644]
languages/LanguageCs.php [new file with mode: 0644]
languages/LanguageDa.php [new file with mode: 0644]
languages/LanguageDe.php [new file with mode: 0644]
languages/LanguageEn.php [new file with mode: 0644]
languages/LanguageEo.php [new file with mode: 0644]
languages/LanguageEs.php [new file with mode: 0644]
languages/LanguageFr.php [new file with mode: 0644]
languages/LanguageIt.php [new file with mode: 0644]
languages/LanguageJa.php [new file with mode: 0644]
languages/LanguageKo.php [new file with mode: 0644]
languages/LanguageNl.php [new file with mode: 0644]
languages/LanguagePl.php [new file with mode: 0644]
languages/LanguageRu.php [new file with mode: 0644]
languages/LanguageSv.php [new file with mode: 0644]
languages/LanguageZh.php [new file with mode: 0644]
maintenance/README [new file with mode: 0644]
maintenance/apache-ampersand.diff [new file with mode: 0644]
maintenance/archives/convertdb.php [new file with mode: 0644]
maintenance/archives/importTests.php [new file with mode: 0644]
maintenance/archives/importUseModWiki.php [new file with mode: 0644]
maintenance/archives/patch-bot.sql [new file with mode: 0644]
maintenance/archives/patch-cache.sql [new file with mode: 0644]
maintenance/archives/patch-list.txt [new file with mode: 0644]
maintenance/archives/patch-math.sql [new file with mode: 0644]
maintenance/archives/patch-random-dateindex.sql [new file with mode: 0644]
maintenance/archives/patch-searchindex.sql [new file with mode: 0644]
maintenance/archives/patch-userindex.sql [new file with mode: 0644]
maintenance/archives/patch-usernewtalk.sql [new file with mode: 0644]
maintenance/archives/patch-watchlist.sql [new file with mode: 0644]
maintenance/archives/rebuildRecentchanges.inc [new file with mode: 0644]
maintenance/archives/upgradeWatchlist.php [new file with mode: 0644]
maintenance/build-intl-wiki.sql [new file with mode: 0644]
maintenance/cleandb.php [new file with mode: 0644]
maintenance/database.sql [new file with mode: 0644]
maintenance/fetchInterwiki.pl [new file with mode: 0644]
maintenance/indexes.sql [new file with mode: 0644]
maintenance/initialdata.sql [new file with mode: 0644]
maintenance/rebuildIndex.php [new file with mode: 0644]
maintenance/rebuildLinks.inc [new file with mode: 0644]
maintenance/rebuildLinks.php [new file with mode: 0644]
maintenance/tables.sql [new file with mode: 0644]
maintenance/users.sql [new file with mode: 0644]
math/Makefile [new file with mode: 0644]
math/README [new file with mode: 0644]
math/TODO [new file with mode: 0644]
math/html.ml [new file with mode: 0644]
math/html.mli [new file with mode: 0644]
math/lexer.mll [new file with mode: 0644]
math/mathml.ml [new file with mode: 0644]
math/mathml.mli [new file with mode: 0644]
math/parser.mly [new file with mode: 0644]
math/render.ml [new file with mode: 0644]
math/render_info.mli [new file with mode: 0644]
math/tex.mli [new file with mode: 0644]
math/texutil.ml [new file with mode: 0644]
math/texutil.mli [new file with mode: 0644]
math/texvc.ml [new file with mode: 0644]
math/texvc_cgi.ml [new file with mode: 0644]
math/texvc_test.ml [new file with mode: 0644]
math/texvc_tex.ml [new file with mode: 0644]
math/util.ml [new file with mode: 0644]
rdf/recent.phtml [new file with mode: 0644]
redirect.phtml [new file with mode: 0644]
stylesheets/cologneblue.css [new file with mode: 0644]
stylesheets/nostalgia.css [new file with mode: 0644]
stylesheets/quickbar.css [new file with mode: 0644]
stylesheets/sticky.js [new file with mode: 0644]
stylesheets/wikibits.js [new file with mode: 0644]
stylesheets/wikiprintable.css [new file with mode: 0644]
stylesheets/wikistandard.css [new file with mode: 0644]
testsuite/README [new file with mode: 0644]
testsuite/build.xml [new file with mode: 0644]
testsuite/data/Agriculture.txt [new file with mode: 0644]
testsuite/data/Anthropology.txt [new file with mode: 0644]
testsuite/data/Archaeology.txt [new file with mode: 0644]
testsuite/data/Architecture.txt [new file with mode: 0644]
testsuite/data/Astronomy_and_astrophysics.txt [new file with mode: 0644]
testsuite/data/Biology.txt [new file with mode: 0644]
testsuite/data/Blocklevels.txt [new file with mode: 0644]
testsuite/data/Bracketvars.txt [new file with mode: 0644]
testsuite/data/Business_and_industry.txt [new file with mode: 0644]
testsuite/data/Card_game.txt [new file with mode: 0644]
testsuite/data/Chemistry.txt [new file with mode: 0644]
testsuite/data/Classics.txt [new file with mode: 0644]
testsuite/data/Communication.txt [new file with mode: 0644]
testsuite/data/Computer_Science.txt [new file with mode: 0644]
testsuite/data/Cooking.txt [new file with mode: 0644]
testsuite/data/Critical_theory.txt [new file with mode: 0644]
testsuite/data/Dance.txt [new file with mode: 0644]
testsuite/data/Earth_science.txt [new file with mode: 0644]
testsuite/data/Economics.txt [new file with mode: 0644]
testsuite/data/Education.txt [new file with mode: 0644]
testsuite/data/Engineering.txt [new file with mode: 0644]
testsuite/data/Entertainment.txt [new file with mode: 0644]
testsuite/data/Equations.txt [new file with mode: 0644]
testsuite/data/ExternalLinks.txt [new file with mode: 0644]
testsuite/data/Family_and_consumer_science.txt [new file with mode: 0644]
testsuite/data/Film.txt [new file with mode: 0644]
testsuite/data/Game.txt [new file with mode: 0644]
testsuite/data/Geography.txt [new file with mode: 0644]
testsuite/data/Handicraft.txt [new file with mode: 0644]
testsuite/data/Headings.txt [new file with mode: 0644]
testsuite/data/Health_science.txt [new file with mode: 0644]
testsuite/data/History.txt [new file with mode: 0644]
testsuite/data/History_of_science_and_technology.txt [new file with mode: 0644]
testsuite/data/Hobby.txt [new file with mode: 0644]
testsuite/data/InternalLinks.txt [new file with mode: 0644]
testsuite/data/Language.txt [new file with mode: 0644]
testsuite/data/Law.txt [new file with mode: 0644]
testsuite/data/Library_and_information_science.txt [new file with mode: 0644]
testsuite/data/Linguistics.txt [new file with mode: 0644]
testsuite/data/Literature.txt [new file with mode: 0644]
testsuite/data/Magics.txt [new file with mode: 0644]
testsuite/data/Main_Page.txt [new file with mode: 0644]
testsuite/data/Mathematics.txt [new file with mode: 0644]
testsuite/data/Music.txt [new file with mode: 0644]
testsuite/data/Opera.txt [new file with mode: 0644]
testsuite/data/Painting.txt [new file with mode: 0644]
testsuite/data/Philosophy.txt [new file with mode: 0644]
testsuite/data/Physics.txt [new file with mode: 0644]
testsuite/data/Poker.txt [new file with mode: 0644]
testsuite/data/Political_science.txt [new file with mode: 0644]
testsuite/data/Psychology.txt [new file with mode: 0644]
testsuite/data/Public_affairs.txt [new file with mode: 0644]
testsuite/data/Quotes.txt [new file with mode: 0644]
testsuite/data/Recreation.txt [new file with mode: 0644]
testsuite/data/Religion.txt [new file with mode: 0644]
testsuite/data/Sculpture.txt [new file with mode: 0644]
testsuite/data/Sociology.txt [new file with mode: 0644]
testsuite/data/Sport.txt [new file with mode: 0644]
testsuite/data/Statistics.txt [new file with mode: 0644]
testsuite/data/Technology.txt [new file with mode: 0644]
testsuite/data/Theater.txt [new file with mode: 0644]
testsuite/data/Tourism.txt [new file with mode: 0644]
testsuite/data/Transport.txt [new file with mode: 0644]
testsuite/data/Visual_arts_and_design.txt [new file with mode: 0644]
testsuite/data/World_Series_of_Poker.txt [new file with mode: 0644]
testsuite/data/startrek.png [new file with mode: 0644]
testsuite/jars/httpunit.jar [new file with mode: 0755]
testsuite/jars/js.jar [new file with mode: 0755]
testsuite/jars/nekohtml.jar [new file with mode: 0755]
testsuite/jars/xercesImpl.jar [new file with mode: 0755]
testsuite/jars/xml-apis.jar [new file with mode: 0755]
testsuite/run [new file with mode: 0755]
testsuite/src/com/piclab/wikitest/DBLoader.java [new file with mode: 0644]
testsuite/src/com/piclab/wikitest/EditTest.java [new file with mode: 0644]
testsuite/src/com/piclab/wikitest/HTMLTest.java [new file with mode: 0644]
testsuite/src/com/piclab/wikitest/LinkTest.java [new file with mode: 0644]
testsuite/src/com/piclab/wikitest/MathTest.java [new file with mode: 0644]
testsuite/src/com/piclab/wikitest/ParserTest.java [new file with mode: 0644]
testsuite/src/com/piclab/wikitest/SearchTest.java [new file with mode: 0644]
testsuite/src/com/piclab/wikitest/SpecialTest.java [new file with mode: 0644]
testsuite/src/com/piclab/wikitest/Test.template [new file with mode: 0644]
testsuite/src/com/piclab/wikitest/UploadTest.java [new file with mode: 0644]
testsuite/src/com/piclab/wikitest/WikiFetchThread.java [new file with mode: 0644]
testsuite/src/com/piclab/wikitest/WikiLogFormatter.java [new file with mode: 0644]
testsuite/src/com/piclab/wikitest/WikiSearchThread.java [new file with mode: 0644]
testsuite/src/com/piclab/wikitest/WikiSuite.java [new file with mode: 0644]
testsuite/src/com/piclab/wikitest/WikiSuiteFailureException.java [new file with mode: 0644]
testsuite/src/com/piclab/wikitest/WikiTest.java [new file with mode: 0644]
testsuite/wikitest.prefs.sample [new file with mode: 0644]
texvc.phtml [new file with mode: 0644]
update.php [new file with mode: 0644]
wiki.phtml [new file with mode: 0644]

diff --git a/AdminSettings.sample b/AdminSettings.sample
new file mode 100644 (file)
index 0000000..b4d74a1
--- /dev/null
@@ -0,0 +1,19 @@
+<?
+# This file should be copied to AdminSettings.php, and modified
+# to reflect local settings.  Unlike LocalSettings.php, it is
+# not copied to the installation directory for security reasons;
+# it is used by the maintenance scripts only.  Do not check
+# AdminSettings.php into CVS!
+
+$wgDBadminuser      = "wikiadmin";
+$wgDBadminpassword  = "adminpass";
+
+# Define these if you want the installed files to be owned
+# by a specific user or group for ease of maintenance.  You
+# must run the install script as root to change owners, or
+# as a member of the group to change groups.
+#
+# $wgInstallOwner = "apache";
+# $wgInstallGroup = "apache";
+
+?>
diff --git a/INSTALL b/INSTALL
new file mode 100644 (file)
index 0000000..f4d5e2d
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,159 @@
+The Wikipedia software was developed collabortively by
+many people, so it's something of a hodgepodge. The
+main wiki software itself is written in PHP, and requires
+the Apache web server and MySQL database. The optional
+math rendering functions are written in Objective CAML,
+which is required to compile them. The test suite is
+written in Java, using several external libraries.
+
+Recommended versions are: Apache 1.3.26 or later; MySQL
+2.23.51 or later; PHP 4.2.2 or later. The installation at
+wikipedia.org also uses the APC caching software, but
+that's entirely optional and doesn't affect anything else.
+
+The math rendering functions are more complex, and will
+probably only work on Linux. Objective CAML (probably
+3.06 or later) is required to compile texvc, but produces
+static binaries. TeTeX and ImageMagick are required at
+runtime, and ImageMagick requires GhostScript. These are
+present in most Linux distributions.
+
+Before installing the software, you must copy the file
+"LocalSettings.sample" to "LocalSettings.php", and
+"AdminSettings.sample" to "AdminSettings.php", and
+customize both of the php files to your local setup
+(things like installation parh, passwords, etc.) The
+script install.php in the maintenance directory can then
+be run to install the software.
+
+Here are some more notes on building a system from scratch
+the way it was done for the Wikipedia server:
+
+Downloads:
+
+  gcc-2.95.3.tar.gz
+  mysql-3.23.51.tar.gz
+  libiconv-1.8.tar.gz
+  apache_1.3.26.tar.gz
+  php-4.2.1.tar.gz
+  apc-cvs.tar.gz
+
+And for math support:
+  ocaml-3.06.tar.gz
+  (TeTeX, ImageMagick, and GhostScript come with most Linux distros)
+
+1. MySQL strongly recommends using gcc 2.95 to compile MySQL.
+  RedHat Linux comes with 2.96 by default, so you'll have to install
+  2.95 first.  Use "../gcc*/configure --enable-shared"  If your Linux
+  installation doesn't use gcc 2.96 you can skip this step.
+
+2. Install MySQL source; add "mysql" user and group. Make sure the
+  directory into which you installed gcc 2.95 appears before the
+  directory of gcc 2.96 in your path.  Configure with:
+
+  FLAGS="-O3 -mpentiumpro" CXX=gcc CXXFLAGS="-O3 -mpentiumpro -felide-constructors -fno-exceptions -fno-rtti" ./configure --prefix=/usr/local/mysql --enable-assembler --with-mysqld-ldflags=-all-static --disable-shared --with-extra-charset=complex
+
+  Edit the file myisam/ftdefs.h, changing the define for minimum word
+  length for fulltext indexing: #define MIN_WORD_LEN 2.  Update
+  $wgDBminWordLen in LocalSettings.php to reflect this.  Build and
+  install according to instructions.  Make root user as recommended;
+  the root password will be required for the wiki installation script.
+
+3. Unpack the phase3.zip source distribution, or check out the "phase3"
+  module from CVS. Copy LocalSettings.sample to LocalSettings.php,
+  AdminSettings.sample to AdminSettings.php, and customize them for
+  things like local paths and passwords.  If desired, update
+  FulltextStoplist.php from the MySQL sources if you have customized
+  MySQL's stop list.
+
+4. Optionally, install libiconv (http://www.gnu.org/software/libiconv/).
+  This will be used by some language packages for converting
+  native-charset URLs to and from UTF-8. If you're running an
+  English-only wiki, this won't be necessary.
+
+5. Unpack Apache distribution and begin configuring, but don't finish
+  build yet. Configure with something like:
+
+   OPTIM='-O2 -mpentiumpro' ./configure --with-layout=Apache
+
+6. If you'll want to use Apache's mod_rewrite to make page-viewing URLs
+  look like static links (as wikipedia.org does), install the included
+  patch "apache-ampersand.diff" which is needed to support page titles
+  with ampersands in them:
+
+   patch -p0 < /path/to/maintenance/apache-ampersand.diff
+
+7. Unpack and configure PHP. Configure with something like:
+
+  ./configure --enable-apc --with-mysql=/usr/local/mysql --with-iconv=/usr/local/lib --with-apache=/home/lee/src/apache_1.3.26
+
+  (using your own local paths, of course). Build and install as
+  instructed. Set "register_globals" on in the config file.
+
+8. Finish building Apache. Configure with something like:
+
+  OPTIM='-O2 -mpentiumpro' ./configure --with-layout=Apache --enable-module=rewrite --activate-module=src/modules/php4/libphp4.a
+
+  Update httpd.conf as needed for your site.  For example:
+
+  <IfModule mod_php4.c>
+    AddType application/x-httpd-php .php .php4 .phtml
+    AddType application/x-httpd-php-source .phps
+  </IfModule>
+  <IfModule mod_php4.c>
+    php_admin_flag engine off
+  </IfModule>
+  <Directory "DIRECTORY_OF_WIKI_SCRIPTS">
+    <IfModule mod_php4.c>
+      php_admin_flag engine on
+    </IfModule>
+  </Directory>
+  RewriteEngine On
+  RewriteMap ampescape int:ampescape
+  RewriteRule ^/wiki/(.*)$ /wiki.phtml?title=${ampescape:$1} [L]
+
+  It is *seriously* recommended that you configure the webserver
+  to disable running of PHP scripts except in the script directories
+  (the "php_admin_flag engine off/on" directives above) to prevent
+  the uploading and running of malicious scripts.
+
+9. Optionally, install APC, following standard instructions for
+  installing as a Zend extension.
+
+10. If using embedded TeX support, be sure TeX and ImageMagick are
+  installed (they are common on most Linux distros and freely
+  downloadable). Also get and install OCaml according to its
+  instructions.
+
+  You'll need to compile the texvc helper script; enter the math
+  subdirectory of the source tree and run "make".
+
+  If you don't want embedded TeX support, disable it by setting
+
+   $wgUseTex = false;
+
+  in LocalSettings.php
+
+11. You should now be able to run the install.php script. Use PHP in
+  command-line mode, i.e., type "php install.php". Should be run as
+  root, or as a user or group able to create files and directories
+  in the installation tree.
+
+12. If you have Java installed and running, install the "ant" package
+  from Apache (http://ant.apache.org/) and run ant in the testsuite
+  directory to build the tests. Copy wikitest.prefs.sample to
+  wikitest.prefs, and edit to reflect your local settings.  Then
+  "./run WikiSuite -o -b" will run the whole test suite and report.
+
+----
+
+Don't forget that this is pre-release software under development!
+Chances are good there's a crucial step that hasn't made it
+into the documentation. You should probably sign up for the
+Wikipedia developers' mailing list; you can ask for help (please
+provide enough information to work with, and preferably be aware
+of what you're doing!) and keep track of major changes to the
+software, including performance improvements and security patches.
+
+http://www.wikipedia.org/mailman/listinfo/wikitech-l
+
diff --git a/LocalSettings.sample b/LocalSettings.sample
new file mode 100644 (file)
index 0000000..f0ac8e4
--- /dev/null
@@ -0,0 +1,53 @@
+<?
+# Local settings work like this: the file LocalSettings.sample
+# should be copied to LocalSettings.php in the source directory
+# and edited for your local file system settings and software
+# configuration preferences. The install script will copy it to
+# the installation path, but a copy should also remain in the
+# source tree so that maintenance scripts can refer to it (you
+# may want to make it a symbolic link after installation).  Do
+# not check LocalSettings.php into CVS!  It is different for
+# every installation, and must not be overridden.
+
+# The most important setting is here: $IP is the installation
+# path for the software.
+#
+
+$IP = "/usr/local/apache/htdocs/wiki";
+
+# This workaround is for the maintenance scripts:
+#
+if ( ! isset( $DP ) ) { $DP = $IP; }
+include_once( "$DP/DefaultSettings.php" );
+
+# You can customize a lot of URLs and paths, but you will
+# almost certainly want to customize the following.  The
+# ArticlePath one is especially useful if you want to use
+# mod_redirect to make page-viewing URLs look static.
+#
+$wgServer           = "http://www.myhost.com";
+$wgArticlePath      = "{$wgScript}?title=$1";
+$wgEmergencyContact = "wikiadmin@myhost.com";
+
+# MySQL settings
+#
+$wgDBserver         = "127.0.0.1";
+$wgDBname           = "wikidb";
+$wgDBpassword       = "userpass";
+#wgDBsqlpassword       = "sqlpass";
+$wgDBminWordLen                = 3;     # Match this to your MySQL fulltext
+$wgDBtransactions   = false; # Set to true if using InnoDB tables
+
+# Turn this on during database maintenance
+# $wgReadOnly = true;
+
+# Turn this on to get HTML debug comments
+# $wgDebugComments     = true;
+
+$wgUseTeX                      = false;
+$wgLocalInterwiki   = "w";
+
+$wgInputEncoding       = "ISO-8859-1";
+$wgOutputEncoding      = "ISO-8859-1";
+
+?>
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..9b0fbde
--- /dev/null
+++ b/README
@@ -0,0 +1,45 @@
+2003-04-14
+
+This is the "Phase III" codebase for the Wikipedia project
+(http://www.wikipedia.org). It is possibly usable as a
+general-purpose wiki, but it was not intended as such and
+there is little or no support available for using it as such
+from the developers, who are busy full time supporting the
+Wikipedia project. There are many good general-purpose Wikis
+in the world. I personally recommend UseMod
+(http://www.usemod.com/).
+
+The code as a whole is Copyright 2002-3 by Lee Daniel Crocker,
+Magnus Manske, Jan Hidders, Brion Vibber, Axel Boldt,
+Geoffrey T. Dairiki, Tomasz Wegrzanowski, and others,
+licensed under the terms of the GNU General Public License,
+version 2 (see http://www.fsf.org/licenses/gpl.html).
+Derivative works and later versions of the code will also be
+considered free software licensed under the same terms.
+
+Many thanks to the Wikipedia regulars for testing and
+suggestions.
+
+Sections of code written exclusively by Lee Crocker are also
+released into the public domain, wich does not impair the
+obligations of users under the GPL for use of the whole code
+or other sections thereof.
+
+The code is currently maintained at Sourceforge under the
+project "wikipedia", module name "phase3".  You can view the
+code in CVS, report bugs and make feature requests there:
+
+  http://wikipedia.sourceforge.net
+
+The code is written in PHP. It was tested mainly on version
+4.06, but it is known to run in later versions.  I requires
+MySQL 3.23 or later, and PHP-MySQL. It is now running with
+PHP 4.2.2 and MySQL 3.23.49 at http://www.wikipedia.org .
+The code was written on and for Linux, and no attempt has
+been made to make it portable to other OSs, though it may
+happen to run on some.  The math support in particular has
+run-time dependencies on things like TeTeX and GhostScript
+that are generally found in Linux but not other OSs.
+
+-- Lee Daniel Crocker <lee@piclab.com>
+
diff --git a/docs/deferred.doc b/docs/deferred.doc
new file mode 100644 (file)
index 0000000..425395f
--- /dev/null
@@ -0,0 +1,19 @@
+
+DEFERRED.DOC
+
+A few of the database updates required by various functions here
+can be deferred until after the result page is displayed to the
+user.  For example, updating the view counts, updating the
+linked-to tables after a save, etc.  PHP does not yet have any
+way to tell the server to actually return and disconnect while
+still running these updates (as a Java servelet could), but it
+might have such a feature in the future.
+
+We handle these by creating a deferred-update object (in a real
+O-O language these would be classes that implement an interface)
+and putting those objects on a global list, then executing the
+whole list after the page is displayed. We don't do anything
+smart like collating updates to the same table or such because
+the list is almost always going to have just one item on it, if
+that, so it's not worth the trouble.
+
diff --git a/docs/design.doc b/docs/design.doc
new file mode 100644 (file)
index 0000000..7c03071
--- /dev/null
@@ -0,0 +1,119 @@
+This is a brief overview of the new design.
+
+Primary source files/objects:
+
+  wiki.phtml
+    Main script. It creates the necessary global objects and parses
+    the URL to determine what to do, which it then generally passes
+    off to somebody else (depending on the action to be taken).
+
+    All of the functions to which it might delegate generally do
+    their job by sending content to the $wgOut object. After returning,
+    the script flushes that out by calling $wgOut->output(). If there
+    are any changes that need to be made to the database that can be
+    deferred until after page display, those happen at the end.
+
+    Note that the order in the includes is touchy; Language uses
+    some global functions, etc. Likewise with the creation of the
+    global variables. Don't move them around without some forethought.
+
+  User
+    Encapsulates the state of the user viewing/using the site.
+    Can be queried for things like the user's settings, name, etc.
+    Handles the details of getting and saving to the "user" table
+    of the database, and dealing with sessions and cookies.
+    More details in USER.DOC.
+
+  OutputPage
+    Encapsulates the entire HTML page that will be sent in
+    response to any server request. It is used by calling its
+    functions to add text, headers, etc., in any order, and then
+    calling output() to send it all. It could be easily changed
+    to send incrementally if that becomes useful, but I prefer
+    the flexibility. This should also do the output encoding.
+    The system allocates a global one in $wgOut. This class
+    also handles converting wikitext format to HTML.
+
+  Title
+    Represents the title of an article, and does all the work
+    of translating among various forms such as plain text, URL,
+    database key, etc. For convenience, and for historical
+    reasons, it also represents a few features of articles that
+    don't involve their text, such as access rights.
+
+  Article
+    Encapsulates access to the "cur" table of the database. The
+    object represents a Wikipedia article, and maintains state
+    such as text (in Wikitext format), flags, etc.
+
+  Skin
+    Encapsulates a "look and feel" for the wiki. All of the
+    functions that render HTML, and make choices about how to
+    render it, are here, and are called from various other
+    places when needed (most notably, OutputPage::addWikiText()).
+    The StandardSkin object is a complete implementation, and is
+    meant to be subclassed with other skins that may override
+    some of its functions. The User object contains a reference
+    to a skin (according to that user's preference), and so
+    rather than having a global skin object we just rely on the
+    global User and get the skin with $wgUser->getSkin().
+
+  Language
+    Represents the language used for incidental text, and also
+    has some character encoding functions and other locale stuff.
+    A global one is allocated in $wgLang.
+
+  LinkCache
+    Keeps information on existence of articles. See LINKCACHE.DOC.
+
+Naming/coding conventions:
+
+  These are meant to be descriptive, not dictatorial; I won't
+  presume to tell you how to program, I'm just describing the
+  methods I chose to use for myself. If you do choose to
+  follow these guidelines, it will probably be easier for you
+  to collaborate with others on the project, but if you want
+  to contribute without bothering, by all means do so (and don't
+  be surprized if I reformat your code).
+
+  - I have the code indented with tabs to save file size and
+    so that users can set their tab stops to any depth they like.
+    I use 4-space tab stops, which work well. I also use K&R brace
+    matching style. I know that's a religious issue for some,
+    so if you want to use a style that puts opening braces on the
+    next line, that's OK too, but please don't use a style where
+    closing braces don't align with either the opening brace on
+    its own line or the statement that opened the block--that's
+    confusing as hell.
+
+  - PHP doesn't have "private" member variables of functions,
+    so I've used the comment "/* private */" in some places to
+    indicate my intent. Don't access things marked that way
+    from outside the class def--use the accessor functions (or
+    make your own if you need them). Yes, even some globals
+    are marked private, because PHP is broken and doesn't
+    allow static class variables.
+
+  - Member variables are generally "mXxx" to distinguish them.
+    This should make it easier to spot errors of forgetting the
+    required "$this->", which PHP will happily accept by creating
+    a new local variable rather than complaining.
+
+  - Globals are particularly evil in PHP; it sets a lot of them
+    automatically from cookies, query strings, and such, leading to
+    namespace conflicts; when a variable name is used in a function,
+    it is silently declared as a new local masking the global, so
+    you'll get weird error because you forgot the global declaration;
+    lack of static class member variables means you have to use
+    globals for them, etc. Evil, evil.
+
+    I think I've managed to pare down the number of globals we use
+    to a scant few dozen or so, and I've prefixed them all with "wg"
+    so you can spot errors better (odds are, if you see a "wg"
+    variable being used in a function that doesn't declare it global,
+    that's probably an error).
+
+    Other conventions: Top-level functions are wfFuncname(), names
+    if session variables are wsName, cookies wcName, and form field
+    values wpName ("p" for "POST").
+
diff --git a/docs/globals.doc b/docs/globals.doc
new file mode 100644 (file)
index 0000000..ac1a609
--- /dev/null
@@ -0,0 +1,29 @@
+GLOBALS.DOC
+
+PHP loves globals. I hate them. This is not a great
+combination, but I manage. I could get rid of most of
+them by having a single "HTTP request" object, and using
+it to hold everything that's now global (which is exactly
+what I'd do in a Java servlet). But that's really
+awkward in PHP, and wouldn't really provide much benefit
+in readability or maintainability, so I go with the flow
+of PHP and use globals.  Here's documentation on the
+important globals used by the system.
+
+$wgOut
+       OutputPage object for HTTP response.
+
+$wgTitle
+       Title object created from the request URL.
+
+$wgLang
+       Language object for this request.
+
+$wgArticle
+       Article object corresponsing to $wgTitle.
+
+$wgLinkCache
+       LinkCache object.
+
+...
+
diff --git a/docs/language.doc b/docs/language.doc
new file mode 100644 (file)
index 0000000..06639f7
--- /dev/null
@@ -0,0 +1,24 @@
+LANGUAGE.DOC
+
+The Language object handles all readable text produced by the
+software. The most used function is getMessage(), usually
+called with the wrapper function wfMsg() which calls that method
+on the global language object. It just returns a piece of text
+given a text key. It is recommended that you use each key only
+once--bits of text in different contexts that happen to be
+identical in English may not be in other languages, so it's
+better to add new keys than to reuse them a lot. Likewise,
+if there is text that gets combined with things like names and
+titles, it is better to put markers like "$1" inside a piece
+of text and use str_replace() than to compose such messages in
+code, because their order may change in other languages too.
+
+While the system is running, there will be one global language
+object, which will be a subtype of Language. The methods in
+these objects will return the native text requested if available,
+otherwise they fall back to sending English text (which is why
+the LanguageEn object has no code at all--it just inherits the
+English defaults of the Language base class).
+
+The names of the namespaces are also contained in the language
+object, though the numbers are fixed.
diff --git a/docs/linkcache.doc b/docs/linkcache.doc
new file mode 100644 (file)
index 0000000..b0afbee
--- /dev/null
@@ -0,0 +1,31 @@
+LINKCACHE.DOC
+
+The LinkCache class maintains a list of article titles and
+the information about whether or not the article exists in
+the database. This is used to mark up links when displaying
+a page. If the same link appears more than once on any page,
+then it only has to be looked up once.
+
+In practice, what happens is that the global cache object
+$wgLinkCache is consulted and updated every time the function
+getArticleID() from Title is called.
+
+This has a side benefit that we take advantage of. We have
+tables "links" and "brokenlinks" which we use to do things
+like the Orphans page and Whatlinkshere page. It just so
+happens that after we update a page, we display it--and as
+we're displaying it, we look up all the links on that page,
+causing them to be put into the cache. That information is
+exactly what we need to update those two tables. So, we do
+something tricky when we update pages: just after the update
+and before we display, we clear the cache. Then we display
+the updated page. Finally, we put a LinksUpdate object onto
+the deferred updates list, which fetches its information from
+the cache.
+
+There's a minor complication: displaying a page also looks up
+a few things like the talk page link in the quick bar and the
+date links. Since we don't want those in the link tables, we
+must take care to suspend the cache while we look those up.
+Skin.php does exactly that--see dateLink(), for example.
+
diff --git a/docs/schema.doc b/docs/schema.doc
new file mode 100644 (file)
index 0000000..d28af2d
--- /dev/null
@@ -0,0 +1,224 @@
+SCHEMA.DOC
+
+The most up-to-date schema for the tables in the database
+should always be "tables.sql" in the maintenance directory,
+which is called from the installation script. Here are a
+few highlight that may be out of date:
+
+user    (Wikipedia users)
+
+  user_id
+    integer, primary key, autoincrement
+  user_name
+    Usernames must be unique, must not be in the form of
+    an IP address. _Shouldn't_ allow slashes or case
+    conflicts. Spaces are allowed, and are _not_ converted
+    to underscores like titles. (Conflicts?)
+  user_rights
+    Comma-separated list of textual flags.
+  user_password
+    Hash of current password.
+  user_newpassword
+    Generated for mail-a-new-password feature
+  user_email
+    Note -- email should be restricted, not public info.
+    Same with passwords. ;)
+  user_options
+    Newline-separated list of name=value pairs.
+
+
+
+cur     (Wikipedia "current" articles)
+
+  cur_id
+    integer, primary key, autoincrement
+  cur_namespace
+    integer index into list of namespaces.  See the
+    Namespace class for more details.
+  cur_title
+    Title of article (in dbkey form--see Title), without
+    namespace.  The combination of namespace,title should
+    be unique in this table.
+  cur_text
+    Wikitext of the article.
+  cur_comment
+    The summary of the last change.
+  cur_user
+    User id who made the last change, or 0 if unknown.
+  cur_user_text
+    Name of the user above, or IP address.
+  cur_timestamp
+    Time of the last change.
+  cur_minor_edit
+    Flag: 0 or 1 is last change was a "minor" edit.
+  cur_restrictions
+    Who may or may not edit the article.
+  cur_counter
+    Number of times this page has been viewed.
+  cur_ind_title
+    Text version of title for fulltext searches.
+  cur_ind_text
+    Plaintext version of text for fulltext searches.
+  cur_is_redirect
+    1 indicates the article is a redirect.
+  cur_minor_edit
+    1 indicates this was a minor edit.
+  cur_is_new
+    1 indicates this is the first revision of a new entry.
+
+
+
+old     (Historical versions articles. Most fields
+        correspond to the same fields in "cur")
+
+  old_id
+  old_namespace
+  old_title
+  old_text
+  old_comment
+  old_user
+  old_user_text
+  old_timestamp
+  old_minor_edit
+  old_flags
+    This last is currently unused.
+
+
+
+archive        (Temporary storage of deleted articles which may be restored.
+               Fields correspond to those of "cur" and "old")
+  ar_namespace
+  ar_title
+  ar_text
+  ar_comment
+  ar_user
+  ar_user_text
+  ar_timestamp
+  ar_minor_edit
+  ar_flags
+    This last is currently unused.
+
+
+
+links   (Internal links to existing articles)
+
+  l_from
+    ID of source article. (currently title, may be changed)
+  l_to
+    ID of target article.
+
+
+
+brokenlinks (Internal links to non-existent articles)
+
+  bl_from
+    ID of source link.
+  bl_to
+    Title of target link.
+
+
+
+imagelinks (Internal links to images via [[Image:filename]] syntax)
+
+  il_from
+    Title of target article.
+  il_to
+    Filename of target image.
+
+
+
+image (Uploaded images and other files)
+
+  img_name
+    Filename.
+  img_size
+    File size in bytes.
+  img_description
+    Description field given during upload.
+  img_user
+    User ID who uploaded the file.
+  img_user_text
+    User name who uploaded the file.
+  img_timestamp
+    Timestamp when upload took place.
+
+
+
+oldimage (Old versions of images stored for potential revert)
+
+  oi_name
+    Original filename.
+  oi_archive_name
+    Filename of stored old revision; timestamp and
+    exclaimation point prepended to oi_name
+  oi_size
+    File size in bytes.
+  oi_description
+    Description field given during upload.
+  oi_user
+    User ID who uploaded the file.
+  oi_user_text
+    User name who uploaded the file.
+  oi_timestamp
+    Timestamp when upload took place.
+
+
+
+ipblocks (IP addresses and users blocked from editing)
+
+  ipb_address
+    Blocked IP address in dotted-quad form or ""
+  ipb_user
+    Blocked user ID or 0.
+  ipb_by
+    User ID who made the block.
+  ipb_reason
+    Text comment made by blocker.
+
+
+
+random (Random page queue)
+
+  ra_current
+    1 = hasn't come up on a random page view yet.
+    >1 = has been viewed, will be ignored for a few
+  ra_title
+    Title of an article.
+
+
+
+site_stats (Site-wide statistics)
+
+  ss_row_id
+    Token for where clauses.  There's only one row in
+    this table.  At some point we might want to use a
+    date here so we can get stats-by-date.
+  ss_total_views
+    Number of total views of all pages.
+  ss_total_edits
+    Number of total page edits.
+  ss_good_articles
+    Number of "countable" articles.
+
+
+
+recentchanges
+
+  (Will document further when working)
+
+
+
+watchlist
+
+  wl_user
+    Foreign key -> user_id
+  wl_namespace
+    Namespace -> cur_namespace
+    Note that these should only include even-numbered
+    namespaces for regular pages; associated talk pages
+    (odd numbered namespaces) are folded in.
+  wl_title
+    Page title -> cur_title
+    Note also that the linked page may not exist in page
+    or talk namespace, or at all.
+
diff --git a/docs/skin.doc b/docs/skin.doc
new file mode 100644 (file)
index 0000000..cdc9cfd
--- /dev/null
@@ -0,0 +1,8 @@
+
+SKIN.DOC
+
+This document describes the overall architecture of Wikipedia's
+HTML rendering code. It is placed here rather than in comments
+in the code itself to help reduce the code size.
+
+
diff --git a/docs/title.doc b/docs/title.doc
new file mode 100644 (file)
index 0000000..1ae4456
--- /dev/null
@@ -0,0 +1,72 @@
+TITLE.DOC
+
+The Wikipedia software's "Title" class represents article
+titles, which are used for many purposes: as the human-readable
+text title of the article, in the URL used to access the article,
+the wikitext link to the article, the key into the article
+database, and so on. The class in instantiated from one of
+these forms and can be queried for the others, and for other
+attributes of the title. This is intended to be an
+immutable "value" class, so there are no mutator functions.
+
+To get a new instance, call one of the static factory
+methods WikiTitle::newFromURL(), WikiTitle::newFromDBKey(),
+or WikiTitle::newFromText(). Once instantiated, the
+other non-static accessor methods can be used, such as
+getText(), getDBKey(), getNamespace(), etc.
+
+The prefix rules: a title consists of an optional Interwiki
+prefix (such as "m:" for meta or "de:" for German), followed
+by an optional namespace, followed by the remainder of the
+title. Both Interwiki prefixes and namespace prefixes have
+the same rules: they contain only letters, digits, space, and
+underscore, must start with a letter, are case insensitive,
+and spaces and underscores are interchangeable.  Prefixes end
+with a ":". A prefix is only recognized if it is one of those
+specifically allowed by the software. For example, "de:name"
+is a link to the article "name" in the German Wikipedia, because
+"de" is recognized as one of the allowable interwikis. The
+title "talk:name" is a link to the article "name" in the "talk"
+namespace of the current wiki, because "talk" is a recognized
+namespace. Both may be present, and if so, the interwiki must
+come first, for example, "m:talk:name". If a title begins with
+a colon as its first character, no prefixes are scanned for,
+and the colon is just removed. Note that because of these
+rules, it is possible to have articles with colons in their
+names. "E. Coli 0157:H7" is a valid title, as is "2001: A Space
+Odyssey", because "E. Coli 0157" and "2001" are not valid
+interwikis or namespaces. Likewise, ":de:name" is a link to
+the article "de:name"--even though "de" is a valid interwiki,
+the initial colon stops all prefix matching.
+
+Character mapping rules: Once prefixes have been stripped, the
+rest of the title processed this way: spaces and underscores are
+treated as equivalent and each is converted to the other in the
+appropriate context (underscore in URL and database keys, spaces
+in plain text). "Extended" characters in the 0x80..0xFF range
+are allowed in all places, and are valid characters. They are
+encoded in URLs.  Other characters may be ASCII letters, digits,
+hyphen, comma, period, apostrophe, parentheses, and colon. No
+other ASCII characters are allowed, and will be deleted if found
+(they will probably cause a browser to misinterpret the URL).
+Extended characters are _not_ urlencoded when used as text or
+database keys.
+
+Character encoding rules: TODO
+
+Canonical forms: the canonical form of a title will always be
+returned by the object. In this form, the first (and only the
+first) character of the namespace and title will be uppercased;
+the rest of the namespace will be lowercased, while the title
+will be left as is. The text form will use spaces, the URL and
+DBkey forms will use underscores. Interwiki prefixes are all
+lowercase. The namespace will use underscores when returned
+alone; it will use spaces only when attached to the text title.
+
+getArticleID() needs some explanation: for "internal" articles,
+it should return the "cur_id" field if the article exists, else
+it returns 0. For all external articles it returns 0. All of
+the IDs for all instances of Title created during a request are
+cached, so they can be looked up wuickly while rendering wiki
+text with lots of internal links.
+
diff --git a/docs/user.doc b/docs/user.doc
new file mode 100644 (file)
index 0000000..2eb0dee
--- /dev/null
@@ -0,0 +1,77 @@
+
+USER.DOC
+
+Documenting the Wikipedia User object.
+
+(DISCLAIMER: The documentation is not guaranteed to be in sync with
+the code at all times. If in doubt, check the table definitions
+and User.php.)
+
+Database fields:
+
+  user_id
+    Unique integer identifier; primary key. Sent to user in
+    cookie "$WikiUserOpts".
+
+  user_name
+    Text of full user name; title of "user:" page.  Displayed
+    on change lists, etc.  Sent to user as cookie "$WikiUserName".
+    Note that user names can contain spaces, while these are
+    converted to underscores in page titles.
+
+  user_rights
+    Comma-separated list of rights. Right now, only "sysop",
+    "developer", and "bot".
+
+  user_password
+    md5 has of user login password.  If user option to
+    remember password is set, this is stored in cookie
+    "$WikiUserPassword".
+
+  user_email
+    User's e-mail address. (Optional, used for user-to-user
+    e-mail and password recovery.)
+
+  user_options
+    A urlencoded string of name=value pairs to set various
+    user options. Some of these (but not all) are encoded into
+    the cookie "$WikiUserOpts".
+
+The user object encapsulates all of the settings, and clients
+classes use the getXXX() functions to access them. These functions
+do all the work of determining whether the user is logged in,
+whether the requested option can be satisfied from cookies or
+whether a database query is needed. Most of the settings needed
+for rendering normal pages are set in the cookie to minimize use
+of the database.
+
+Options
+  The user_options field is a list of name-value pairs.  The
+  following option names are used at various points in the system:
+
+
+Cookies
+
+  $WikiUserName
+    Plain text user name directly from database
+
+  $WikiUserPassword
+    From the database; only set if the user's options are set
+    to remember passwords.
+
+  $WikiUserOpts
+    User ID and various options encoded into a compact string;
+    for example, "12e0q0s2h0u1j0n1f0y0".  The first string of digits
+    is the ID; the rest of the string a flag-letter plus number
+    pairs representing a few important options:
+
+      e = "encoding" (index into array)
+      q = "quickBar" (0=none, 1=left, 2=right)
+      s = "skin" (0=standard, 1=startrek, 2=nostalgia, 3=cologneblue)
+      h = "showHover" (1=true)
+      u = "underlineLinks" (1=true)
+      j = "justify" (1=true)
+      n = "numberHeadings" (1=true)
+      f = "viewFrames" (1=true)
+      y = 1 if user_rights include "is_sysop"
+
diff --git a/images/favicon.ico b/images/favicon.ico
new file mode 100644 (file)
index 0000000..31b0e38
Binary files /dev/null and b/images/favicon.ico differ
diff --git a/images/startrek.png b/images/startrek.png
new file mode 100644 (file)
index 0000000..d3a1053
Binary files /dev/null and b/images/startrek.png differ
diff --git a/images/valid-html401.png b/images/valid-html401.png
new file mode 100644 (file)
index 0000000..3855210
Binary files /dev/null and b/images/valid-html401.png differ
diff --git a/images/wiki.png b/images/wiki.png
new file mode 100644 (file)
index 0000000..66a1f03
Binary files /dev/null and b/images/wiki.png differ
diff --git a/includes/Article.php b/includes/Article.php
new file mode 100644 (file)
index 0000000..1d0df3b
--- /dev/null
@@ -0,0 +1,1478 @@
+<?
+# Class representing a Wikipedia article and history.
+# See design.doc for an overview.
+
+class Article {
+       /* private */ var $mContent, $mContentLoaded;
+       /* private */ var $mUser, $mTimestamp, $mUserText;
+       /* private */ var $mCounter, $mComment, $mCountAdjustment;
+       /* private */ var $mMinorEdit, $mRedirectedFrom;
+       /* private */ var $mTouched;
+
+       function Article() { $this->clear(); }
+
+       /* private */ function clear()
+       {
+               $this->mContentLoaded = false;
+               $this->mUser = $this->mCounter = -1; # Not loaded
+               $this->mRedirectedFrom = $this->mUserText =
+               $this->mTimestamp = $this->mComment = "";
+               $this->mCountAdjustment = 0;
+               $this->mTouched = "19700101000000";
+       }
+
+       /* static */ function newFromID( $newid )
+       {
+               global $wgOut, $wgTitle, $wgArticle;
+               $a = new Article();
+               $n = Article::nameOf( $newid );
+
+               $wgTitle = Title::newFromDBkey( $n );
+               $wgTitle->resetArticleID( $newid );
+
+               return $a;
+       }
+
+       /* static */ function nameOf( $id )
+       {
+               $sql = "SELECT cur_namespace,cur_title FROM cur WHERE " .
+                 "cur_id={$id}";
+               $res = wfQuery( $sql, "Article::nameOf" );
+               if ( 0 == wfNumRows( $res ) ) { return NULL; }
+
+               $s = wfFetchObject( $res );
+               $n = Title::makeName( $s->cur_namespace, $s->cur_title );
+               return $n;
+       }
+
+       # Note that getContent/loadContent may follow redirects if
+       # not told otherwise, and so may cause a change to wgTitle.
+
+       function getContent( $noredir = false )
+       {
+               global $action,$wgTitle; # From query string
+               wfProfileIn( "Article::getContent" );
+
+               if ( 0 == $this->getID() ) {
+                       if ( "edit" == $action ) {
+                       
+                               global $wgTitle;
+                               return ""; # was "newarticletext", now moved above the box)
+                               
+                               
+                       }
+                       wfProfileOut();
+                       return wfMsg( "noarticletext" );
+               } else {
+                       $this->loadContent( $noredir );
+                       wfProfileOut();
+                                               
+                       if(
+                               # check if we're displaying a [[User talk:x.x.x.x]] anonymous talk page
+                               ( $wgTitle->getNamespace() == Namespace::getTalk( Namespace::getUser()) ) &&
+                                 preg_match("/^\d{1,3}\.\d{1,3}.\d{1,3}\.\d{1,3}$/",$wgTitle->getText()) &&
+                                 $action=="view"
+                               ) 
+                               {
+                               return $this->mContent . "\n" .wfMsg("anontalkpagetext"); }
+                       else {
+                               return $this->mContent;
+                       }
+               }
+       }
+
+       function loadContent( $noredir = false )
+       {
+               global $wgOut, $wgTitle;
+               global $oldid, $redirect; # From query
+
+               if ( $this->mContentLoaded ) return;
+               $fname = "Article::loadContent";
+
+               # Pre-fill content with error message so that if something
+               # fails we'll have something telling us what we intended.
+
+               $t = $wgTitle->getPrefixedText();
+               if ( $oldid ) { $t .= ",oldid={$oldid}"; }
+               if ( $redirect ) { $t .= ",redirect={$redirect}"; }
+               $this->mContent = str_replace( "$1", $t, wfMsg( "missingarticle" ) );
+
+               if ( ! $oldid ) {       # Retrieve current version
+                       $id = $this->getID();
+                       if ( 0 == $id ) return;
+
+                       $sql = "SELECT " .
+                         "cur_text,cur_timestamp,cur_user,cur_counter,cur_restrictions,cur_touched " .
+                         "FROM cur WHERE cur_id={$id}";
+                       $res = wfQuery( $sql, $fname );
+                       if ( 0 == wfNumRows( $res ) ) { return; }
+
+                       $s = wfFetchObject( $res );
+
+                       # If we got a redirect, follow it (unless we've been told
+                       # not to by either the function parameter or the query
+
+                       if ( ( "no" != $redirect ) && ( false == $noredir ) &&
+                         ( preg_match( "/^#redirect/i", $s->cur_text ) ) ) {
+                               if ( preg_match( "/\\[\\[([^\\]\\|]+)[\\]\\|]/",
+                                 $s->cur_text, $m ) ) {
+                                       $rt = Title::newFromText( $m[1] );
+
+                                       # Gotta hand redirects to special pages differently:
+                                       # Fill the HTTP response "Location" header and ignore
+                                       # the rest of the page we're on.
+
+                                       if ( $rt->getInterwiki() != "" ) {
+                                               $wgOut->redirect( $rt->getFullURL() ) ;
+                                               return;
+                                       }
+                                       if ( $rt->getNamespace() == Namespace::getSpecial() ) {
+                                               $wgOut->redirect( wfLocalUrl(
+                                                 $rt->getPrefixedURL() ) );
+                                               return;
+                                       }
+                                       $rid = $rt->getArticleID();
+                                       if ( 0 != $rid ) {
+                                               $sql = "SELECT cur_text,cur_timestamp,cur_user," .
+                                                 "cur_counter,cur_touched FROM cur WHERE cur_id={$rid}";
+                                               $res = wfQuery( $sql, $fname );
+
+                                               if ( 0 != wfNumRows( $res ) ) {
+                                                       $this->mRedirectedFrom = $wgTitle->getPrefixedText();
+                                                       $wgTitle = $rt;
+                                                       $s = wfFetchObject( $res );
+                                               }
+                                       }
+                               }
+                       }
+                       $this->mContent = $s->cur_text;
+                       $this->mUser = $s->cur_user;
+                       $this->mCounter = $s->cur_counter;
+                       $this->mTimestamp = $s->cur_timestamp;
+                       $this->mTouched = $s->cur_touched;
+                       $wgTitle->mRestrictions = explode( ",", trim( $s->cur_restrictions ) );
+                       $wgTitle->mRestrictionsLoaded = true;
+                       wfFreeResult( $res );
+               } else { # oldid set, retrieve historical version
+                       $sql = "SELECT old_text,old_timestamp,old_user FROM old " .
+                         "WHERE old_id={$oldid}";
+                       $res = wfQuery( $sql, $fname );
+                       if ( 0 == wfNumRows( $res ) ) { return; }
+
+                       $s = wfFetchObject( $res );
+                       $this->mContent = $s->old_text;
+                       $this->mUser = $s->old_user;
+                       $this->mCounter = 0;
+                       $this->mTimestamp = $s->old_timestamp;
+                       wfFreeResult( $res );
+               }
+               $this->mContentLoaded = true;
+       }
+
+       function getID() { global $wgTitle; return $wgTitle->getArticleID(); }
+
+       function getCount()
+       {
+               if ( -1 == $this->mCounter ) {
+                       $id = $this->getID();
+                       $this->mCounter = wfGetSQL( "cur", "cur_counter", "cur_id={$id}" );
+               }
+               return $this->mCounter;
+       }
+
+       # Would the given text make this article a "good" article (i.e.,
+       # suitable for including in the article count)?
+
+       function isCountable( $text )
+       {
+               global $wgTitle, $wgUseCommaCount;
+
+               if ( 0 != $wgTitle->getNamespace() ) { return 0; }
+               if ( preg_match( "/^#redirect/i", $text ) ) { return 0; }
+               $token = ($wgUseCommaCount ? "," : "[[" );
+               if ( false === strstr( $text, $token ) ) { return 0; }
+               return 1;
+       }
+
+       # Load the field related to the last edit time of the article.
+       # This isn't necessary for all uses, so it's only done if needed.
+
+       /* private */ function loadLastEdit()
+       {
+               global $wgOut;
+               if ( -1 != $this->mUser ) return;
+
+               $sql = "SELECT cur_user,cur_user_text,cur_timestamp," .
+                 "cur_comment,cur_minor_edit FROM cur WHERE " .
+                 "cur_id=" . $this->getID();
+               $res = wfQuery( $sql, "Article::loadLastEdit" );
+
+               if ( wfNumRows( $res ) > 0 ) {
+                       $s = wfFetchObject( $res );
+                       $this->mUser = $s->cur_user;
+                       $this->mUserText = $s->cur_user_text;
+                       $this->mTimestamp = $s->cur_timestamp;
+                       $this->mComment = $s->cur_comment;
+                       $this->mMinorEdit = $s->cur_minor_edit;
+               }
+       }
+
+       function getTimestamp()
+       {
+               $this->loadLastEdit();
+               return $this->mTimestamp;
+       }
+
+       function getUser()
+       {
+               $this->loadLastEdit();
+               return $this->mUser;
+       }
+
+       function getUserText()
+       {
+               $this->loadLastEdit();
+               return $this->mUserText;
+       }
+
+       function getComment()
+       {
+               $this->loadLastEdit();
+               return $this->mComment;
+       }
+
+       function getMinorEdit()
+       {
+               $this->loadLastEdit();
+               return $this->mMinorEdit;
+       }
+
+       # This is the default action of the script: just view the page of
+       # the given title.
+
+       function view()
+       {
+               global $wgUser, $wgOut, $wgTitle, $wgLang;
+               global $oldid, $diff; # From query
+               global $wgLinkCache;
+               wfProfileIn( "Article::view" );
+
+               $wgOut->setArticleFlag( true );
+               $wgOut->setRobotpolicy( "index,follow" );
+
+               # If we got diff and oldid in the query, we want to see a
+               # diff page instead of the article.
+
+               if ( isset( $diff ) ) {
+                       $wgOut->setPageTitle( $wgTitle->getPrefixedText() );
+                       $de = new DifferenceEngine( $oldid, $diff );
+                       $de->showDiffPage();
+                       wfProfileOut();
+                       return;
+               }
+               $text = $this->getContent(); # May change wgTitle!
+               $wgOut->setPageTitle( $wgTitle->getPrefixedText() );
+               $wgOut->setHTMLTitle( $wgTitle->getPrefixedText() .
+                 " - " . wfMsg( "wikititlesuffix" ) );
+
+               # We're looking at an old revision
+
+               if ( $oldid ) {
+                       $this->setOldSubtitle();
+                       $wgOut->setRobotpolicy( "noindex,follow" );
+               }
+               if ( "" != $this->mRedirectedFrom ) {
+                       $sk = $wgUser->getSkin();
+                       $redir = $sk->makeKnownLink( $this->mRedirectedFrom, "",
+                         "redirect=no" );
+                       $s = str_replace( "$1", $redir, wfMsg( "redirectedfrom" ) );
+                       $wgOut->setSubtitle( $s );
+               }
+               $wgOut->checkLastModified( $this->mTouched );
+               $wgLinkCache->preFill( $wgTitle );
+               $wgOut->addWikiText( $text );
+
+               # If the article we've just shown is in the "Image" namespace,
+               # follow it with the history list and link list for the image
+               # it describes.
+
+               if ( Namespace::getImage() == $wgTitle->getNamespace() ) {
+                       $this->imageHistory();
+                       $this->imageLinks();
+               }
+               $this->viewUpdates();
+               wfProfileOut();
+       }
+
+       # This is the function that gets called for "action=edit".
+
+       function edit()
+       {
+               global $wgOut, $wgUser, $wgTitle;
+               global $wpTextbox1, $wpSummary, $wpSave, $wpPreview;
+               global $wpMinoredit, $wpEdittime, $wpTextbox2;
+
+               $fields = array( "wpTextbox1", "wpSummary", "wpTextbox2" );
+               wfCleanFormFields( $fields );
+
+               if ( ! $wgTitle->userCanEdit() ) {
+                       $this->view();
+                       return;
+               }
+               if ( $wgUser->isBlocked() ) {
+                       $this->blockedIPpage();
+                       return;
+               }
+               if ( wfReadOnly() ) {
+                       if( isset( $wpSave ) or isset( $wpPreview ) ) {
+                               $this->editForm( "preview" );
+                       } else {
+                               $wgOut->readOnlyPage();
+                       }
+                       return;
+               }
+               if ( $_SERVER['REQUEST_METHOD'] != "POST" ) unset( $wpSave );
+               if ( isset( $wpSave ) ) {
+                       $this->editForm( "save" );
+               } else if ( isset( $wpPreview ) ) {
+                       $this->editForm( "preview" );
+               } else { # First time through
+                       $this->editForm( "initial" );
+               }
+       }
+
+       # Since there is only one text field on the edit form,
+       # pressing <enter> will cause the form to be submitted, but
+       # the submit button value won't appear in the query, so we
+       # Fake it here before going back to edit().  This is kind of
+       # ugly, but it helps some old URLs to still work.
+
+       function submit()
+       {
+               global $wpSave, $wpPreview;
+               if ( ! isset( $wpPreview ) ) { $wpSave = 1; }
+
+               $this->edit();
+       }
+
+       # The edit form is self-submitting, so that when things like
+       # preview and edit conflicts occur, we get the same form back
+       # with the extra stuff added.  Only when the final submission
+       # is made and all is well do we actually save and redirect to
+       # the newly-edited page.
+
+       function editForm( $formtype )
+       {
+               global $wgOut, $wgUser, $wgTitle;
+               global $wpTextbox1, $wpSummary, $wpWatchthis;
+               global $wpSave, $wpPreview;
+               global $wpMinoredit, $wpEdittime, $wpTextbox2;
+               global $oldid, $redirect;
+               global $wgLang;
+
+               $sk = $wgUser->getSkin();
+               $isConflict = false;
+               $wpTextbox1 = rtrim ( $wpTextbox1 ) ; # To avoid text getting longer on each preview
+
+               if(!$wgTitle->getArticleID()) { # new article
+
+                       $wgOut->addWikiText(wfmsg("newarticletext"));
+
+               }
+
+               # Attempt submission here.  This will check for edit conflicts,
+               # and redundantly check for locked database, blocked IPs, etc.
+               # that edit() already checked just in case someone tries to sneak
+               # in the back door with a hand-edited submission URL.
+
+               if ( "save" == $formtype ) {
+                       if ( $wgUser->isBlocked() ) {
+                               $this->blockedIPpage();
+                               return;
+                       }
+                       if ( wfReadOnly() ) {
+                               $wgOut->readOnlyPage();
+                               return;
+                       }
+                       # If article is new, insert it.
+                       
+                       $aid = $wgTitle->getArticleID();                        
+                       if ( 0 == $aid ) {
+                               # we need to strip Windoze linebreaks because some browsers 
+                               # append them and the string comparison fails
+                               if ( ( "" == $wpTextbox1 ) ||
+                                 ( wfMsg( "newarticletext" ) == rtrim( preg_replace("/\r/","",$wpTextbox1) ) ) ) {
+                                       $wgOut->redirect(  wfLocalUrl(
+                                         $wgTitle->getPrefixedURL() ) );
+                                       return;
+                               }
+                               $this->mCountAdjustment = $this->isCountable( $wpTextbox1 );
+                               $this->insertNewArticle( $wpTextbox1, $wpSummary, $wpMinoredit, $wpWatchthis );
+                               return;
+                       }
+                       # Article exists. Check for edit conflict.
+
+                       $this->clear(); # Force reload of dates, etc.
+                       if ( $this->getTimestamp() != $wpEdittime ) { $isConflict = true; }
+                       $u = $wgUser->getID();
+
+                       # Supress edit conflict with self
+
+                       if ( ( 0 != $u ) && ( $this->getUser() == $u ) ) {
+                               $isConflict = false;
+                       }
+                       if ( ! $isConflict ) {
+                               # All's well: update the article here
+                               $this->updateArticle( $wpTextbox1, $wpSummary, $wpMinoredit, $wpWatchthis );
+                               return;
+                       }
+               }
+               # First time through: get contents, set time for conflict
+               # checking, etc.
+
+               if ( "initial" == $formtype ) {
+                       $wpEdittime = $this->getTimestamp();
+                       $wpTextbox1 = $this->getContent();
+                       $wpSummary = "";
+               }
+               $wgOut->setRobotpolicy( "noindex,nofollow" );
+               $wgOut->setArticleFlag( false );
+
+               if ( $isConflict ) {
+                       $s = str_replace( "$1", $wgTitle->getPrefixedText(),
+                         wfMsg( "editconflict" ) );
+                       $wgOut->setPageTitle( $s );
+                       $wgOut->addHTML( wfMsg( "explainconflict" ) );
+
+                       $wpTextbox2 = $wpTextbox1;
+                       $wpTextbox1 = $this->getContent();
+                       $wpEdittime = $this->getTimestamp();
+               } else {
+                       $s = str_replace( "$1", $wgTitle->getPrefixedText(),
+                         wfMsg( "editing" ) );
+                       $wgOut->setPageTitle( $s );
+                       if ( $oldid ) {
+                               $this->setOldSubtitle();
+                               $wgOut->addHTML( wfMsg( "editingold" ) );
+                       }
+               }
+
+               if( wfReadOnly() ) {
+                       $wgOut->addHTML( "<strong>" .
+                               wfMsg( "readonlywarning" ) .
+                               "</strong>" );
+               }
+               if( $wgTitle->isProtected() ) {
+                       $wgOut->addHTML( "<strong>" . wfMsg( "protectedpagewarning" ) .
+                         "</strong><br />\n" );
+               }
+
+               $kblength = (int)(strlen( $wpTextbox1 ) / 1024);
+               if( $kblength > 29 ) {
+                       $wgOut->addHTML( "<strong>" . 
+                               str_replace( '$1', $kblength , wfMsg( "longpagewarning" ) )
+                               . "</strong>" );
+               }
+               
+               $rows = $wgUser->getOption( "rows" );
+               $cols = $wgUser->getOption( "cols" );
+
+               $ew = $wgUser->getOption( "editwidth" );
+               if ( $ew ) $ew = " style=\"width:100%\"";
+               else $ew = "" ;
+
+               $q = "action=submit";
+               if ( "no" == $redirect ) { $q .= "&redirect=no"; }
+               $action = wfEscapeHTML( wfLocalUrl( $wgTitle->getPrefixedURL(), $q ) );
+
+               $summary = wfMsg( "summary" );          
+               $minor = wfMsg( "minoredit" );
+               $watchthis = wfMsg ("watchthis");
+               $save = wfMsg( "savearticle" );
+               $prev = wfMsg( "showpreview" );
+
+               $cancel = $sk->makeKnownLink( $wgTitle->getPrefixedURL(),
+                 wfMsg( "cancel" ) );
+               $edithelp = $sk->makeKnownLink( wfMsg( "edithelppage" ),
+                 wfMsg( "edithelp" ) );
+               $copywarn = str_replace( "$1", $sk->makeKnownLink(
+                 wfMsg( "copyrightpage" ) ), wfMsg( "copyrightwarning" ) );
+
+               $wpTextbox1 = wfEscapeHTML( $wpTextbox1 );
+               $wpTextbox2 = wfEscapeHTML( $wpTextbox2 );
+               $wpSummary = wfEscapeHTML( $wpSummary );
+               
+               // activate checkboxes if user wants them to be always active
+               if (!$wpPreview && $wgUser->getOption("watchdefault")) $wpWatchthis=1;
+               if (!$wpPreview && $wgUser->getOption("minordefault")) $wpMinoredit=1;          
+               
+               // activate checkbox also if user is already watching the page,
+               // require wpWatchthis to be unset so that second condition is not
+               // checked unnecessarily
+               if (!$wpWatchthis && !$wpPreview && $wgTitle->userIsWatching()) $wpWatchthis=1;
+               
+               if ( 0 != $wgUser->getID() ) {
+                       $checkboxhtml=
+                       "<input tabindex=3 type=checkbox value=1 name='wpMinoredit'".($wpMinoredit?" checked":"").">{$minor}".
+                       "<input tabindex=4 type=checkbox name='wpWatchthis'".($wpWatchthis?" checked":"").">{$watchthis}<br>";
+                       
+               } else {
+                       $checkboxhtml="";
+               }
+
+
+               if ( "preview" == $formtype) {
+               
+                       $previewhead="<h2>" . wfMsg( "preview" ) . "</h2>\n<p><large><center><font color=\"#cc0000\">" . 
+                       wfMsg( "note" ) . wfMsg( "previewnote" ) . "</font></center></large><P>\n";
+                       if ( $isConflict ) {
+                               $previewhead.="<h2>" . wfMsg( "previewconflict" ) .
+                                 "</h2>\n";
+                       }
+                       $previewtext = wfUnescapeHTML( $wpTextbox1 );
+                       
+                       if($wgUser->getOption("previewontop")) {
+                               $wgOut->addHTML($previewhead);
+                               $wgOut->addWikiText( $this->preSaveTransform( $previewtext ) ."\n\n");
+                       }
+               }
+               $wgOut->addHTML( "
+<form id=\"editform\" method=\"post\" action=\"$action\"
+enctype=\"application/x-www-form-urlencoded\">
+<textarea tabindex=1 name=\"wpTextbox1\" rows={$rows}
+cols={$cols}{$ew} wrap=\"virtual\">" .
+$wgLang->recodeForEdit( $wpTextbox1 ) .
+"
+</textarea><br>
+{$summary}: <input tabindex=2 type=text value=\"{$wpSummary}\"
+name=\"wpSummary\" maxlength=200 size=60><br>
+{$checkboxhtml}
+<input tabindex=5 type=submit value=\"{$save}\" name=\"wpSave\">
+<input tabindex=6 type=submit value=\"{$prev}\" name=\"wpPreview\">
+<em>{$cancel}</em> | <em>{$edithelp}</em>
+<br><br>{$copywarn}
+<input type=hidden value=\"{$wpEdittime}\" name=\"wpEdittime\">\n" );
+
+               if ( $isConflict ) {
+                       $wgOut->addHTML( "<h2>" . wfMsg( "yourdiff" ) . "</h2>\n" );
+                       DifferenceEngine::showDiff( $wpTextbox2, $wpTextbox1,
+                         wfMsg( "yourtext" ), wfMsg( "storedversion" ) );
+
+                       $wgOut->addHTML( "<h2>" . wfMsg( "yourtext" ) . "</h2>
+<textarea tabindex=6 name=\"wpTextbox2\" rows={$rows} cols={$cols} wrap=virtual>"
+. $wgLang->recodeForEdit( $wpTextbox2 ) .
+"
+</textarea>" );
+               }
+               $wgOut->addHTML( "</form>\n" );
+               if($formtype =="preview" && !$wgUser->getOption("previewontop")) {
+                       $wgOut->addHTML($previewhead);
+                       $wgOut->addWikiText( $this->preSaveTransform( $previewtext ) );
+               }
+
+       }
+
+       # Theoretically we could defer these whole insert and update
+       # functions for after display, but that's taking a big leap
+       # of faith, and we want to be able to report database
+       # errors at some point.
+
+       /* private */ function insertNewArticle( $text, $summary, $isminor, $watchthis )
+       {
+               global $wgOut, $wgUser, $wgTitle, $wgLinkCache;
+               $fname = "Article::insertNewArticle";
+
+               $ns = $wgTitle->getNamespace();
+               $ttl = $wgTitle->getDBkey();
+               $text = $this->preSaveTransform( $text );
+               if ( preg_match( "/^#redirect/i", $text ) ) { $redir = 1; }
+               else { $redir = 0; }
+
+               $now = wfTimestampNow();
+               $won = wfInvertTimestamp( $now );
+               $sql = "INSERT INTO cur (cur_namespace,cur_title,cur_text," .
+                 "cur_comment,cur_user,cur_timestamp,cur_minor_edit,cur_counter," .
+                 "cur_restrictions,cur_user_text,cur_is_redirect," .
+                 "cur_is_new,cur_random,cur_touched,inverse_timestamp) VALUES ({$ns},'" . wfStrencode( $ttl ) . "', '" .
+                 wfStrencode( $text ) . "', '" .
+                 wfStrencode( $summary ) . "', '" .
+                 $wgUser->getID() . "', '{$now}', " .
+                 ( $isminor ? 1 : 0 ) . ", 0, '', '" .
+                 wfStrencode( $wgUser->getName() ) . "', $redir, 1, RAND(), '{$now}', '{$won}')";
+               $res = wfQuery( $sql, $fname );
+
+               $newid = wfInsertId();
+               $wgTitle->resetArticleID( $newid );
+
+               $sql = "INSERT INTO recentchanges (rc_timestamp,rc_cur_time," .
+                 "rc_namespace,rc_title,rc_new,rc_minor,rc_cur_id,rc_user," .
+                 "rc_user_text,rc_comment,rc_this_oldid,rc_last_oldid,rc_bot) VALUES (" .
+                 "'{$now}','{$now}',{$ns},'" . wfStrencode( $ttl ) . "',1," .
+                 ( $isminor ? 1 : 0 ) . ",{$newid}," . $wgUser->getID() . ",'" .
+                 wfStrencode( $wgUser->getName() ) . "','" .
+                 wfStrencode( $summary ) . "',0,0," .
+                 ( $wgUser->isBot() ? 1 : 0 ) . ")";
+               wfQuery( $sql, $fname );
+               if ($watchthis) {               
+                       if(!$wgTitle->userIsWatching()) $this->watch(); 
+               } else {
+                       if ( $wgTitle->userIsWatching() ) {
+                               $this->unwatch();
+                       }
+               }
+               
+               $this->showArticle( $text, wfMsg( "newarticle" ) );
+       }
+
+       function updateArticle( $text, $summary, $minor, $watchthis )
+       {
+               global $wgOut, $wgUser, $wgTitle, $wgLinkCache;
+               global $wgDBtransactions;
+               $fname = "Article::updateArticle";
+
+               if ( $this->mMinorEdit ) { $me1 = 1; } else { $me1 = 0; }
+               if ( $minor ) { $me2 = 1; } else { $me2 = 0; }          
+               if ( preg_match( "/^(#redirect[^\\n]+)/i", $text, $m ) ) {
+                       $redir = 1;
+                       $text = $m[1] . "\n"; # Remove all content but redirect
+               }
+               else { $redir = 0; }
+               $this->loadLastEdit();
+
+               $text = $this->preSaveTransform( $text );
+               
+               # Update article, but only if changed.
+
+               if( $wgDBtransactions ) {
+                       $sql = "BEGIN";
+                       wfQuery( $sql );
+               }
+               $oldtext = $this->getContent( true );
+
+               if ( 0 != strcmp( $text, $oldtext ) ) {
+                       $this->mCountAdjustment = $this->isCountable( $text )
+                         - $this->isCountable( $oldtext );
+
+                       $sql = "INSERT INTO old (old_namespace,old_title,old_text," .
+                         "old_comment,old_user,old_user_text,old_timestamp," .
+                         "old_minor_edit,inverse_timestamp) VALUES (" .
+                         $wgTitle->getNamespace() . ", '" .
+                         wfStrencode( $wgTitle->getDBkey() ) . "', '" .
+                         wfStrencode( $oldtext ) . "', '" .
+                         wfStrencode( $this->getComment() ) . "', " .
+                         $this->getUser() . ", '" .
+                         wfStrencode( $this->getUserText() ) . "', '" .
+                         $this->getTimestamp() . "', " . $me1 . ", '" .
+                         wfInvertTimestamp( $this->getTimestamp() ) . "')";
+                       $res = wfQuery( $sql, $fname );
+                       $oldid = wfInsertID( $res );
+
+                       $now = wfTimestampNow();
+                       $won = wfInvertTimestamp( $now );
+                       $sql = "UPDATE cur SET cur_text='" . wfStrencode( $text ) .
+                         "',cur_comment='" .  wfStrencode( $summary ) .
+                         "',cur_minor_edit={$me2}, cur_user=" . $wgUser->getID() .
+                         ",cur_timestamp='{$now}',cur_user_text='" .
+                         wfStrencode( $wgUser->getName() ) .
+                         "',cur_is_redirect={$redir}, cur_is_new=0, cur_touched='{$now}', inverse_timestamp='{$won}' " .
+                         "WHERE cur_id=" . $this->getID();
+                       wfQuery( $sql, $fname );
+
+                       $sql = "INSERT INTO recentchanges (rc_timestamp,rc_cur_time," .
+                         "rc_namespace,rc_title,rc_new,rc_minor,rc_bot,rc_cur_id,rc_user," .
+                         "rc_user_text,rc_comment,rc_this_oldid,rc_last_oldid) VALUES (" .
+                         "'{$now}','{$now}'," . $wgTitle->getNamespace() . ",'" .
+                         wfStrencode( $wgTitle->getDBkey() ) . "',0,{$me2}," .
+                         ( $wgUser->isBot() ? 1 : 0 ) . "," .
+                         $this->getID() . "," . $wgUser->getID() . ",'" .
+                         wfStrencode( $wgUser->getName() ) . "','" .
+                         wfStrencode( $summary ) . "',0,{$oldid})";
+                       wfQuery( $sql, $fname );
+
+                       $sql = "UPDATE recentchanges SET rc_this_oldid={$oldid} " .
+                         "WHERE rc_namespace=" . $wgTitle->getNamespace() . " AND " .
+                         "rc_title='" . wfStrencode( $wgTitle->getDBkey() ) . "' AND " .
+                         "rc_timestamp='" . $this->getTimestamp() . "'";
+                       wfQuery( $sql, $fname );
+
+                       $sql = "UPDATE recentchanges SET rc_cur_time='{$now}' " .
+                         "WHERE rc_cur_id=" . $this->getID();
+                       wfQuery( $sql, $fname );
+               }
+               if( $wgDBtransactions ) {
+                       $sql = "COMMIT";
+                       wfQuery( $sql );
+               }
+               
+               if ($watchthis) { 
+                       if (!$wgTitle->userIsWatching()) $this->watch();                        
+               } else {
+                       if ( $wgTitle->userIsWatching() ) {
+                               $this->unwatch();
+                       }
+               }
+
+               $this->showArticle( $text, wfMsg( "updated" ) ); 
+       }
+
+       # After we've either updated or inserted the article, update
+       # the link tables and redirect to the new page.
+
+       function showArticle( $text, $subtitle )
+       {
+               global $wgOut, $wgTitle, $wgUser, $wgLinkCache;
+
+               $wgLinkCache = new LinkCache();
+               $wgOut->addWikiText( $text ); # Just to update links
+
+               $this->editUpdates( $text );
+               if( preg_match( "/^#redirect/i", $text ) )
+                       $r = "redirect=no";
+               else
+                       $r = "";
+               $wgOut->redirect( wfLocalUrl( $wgTitle->getPrefixedURL(), $r ) );
+       }
+
+       # If the page we've just displayed is in the "Image" namespace,
+       # we follow it with an upload history of the image and its usage.
+
+       function imageHistory()
+       {
+               global $wgUser, $wgOut, $wgLang, $wgTitle;
+               $fname = "Article::imageHistory";
+
+               $sql = "SELECT img_size,img_description,img_user," .
+                 "img_user_text,img_timestamp FROM image WHERE " .
+                 "img_name='" . wfStrencode( $wgTitle->getDBkey() ) . "'";
+               $res = wfQuery( $sql, $fname );
+
+               if ( 0 == wfNumRows( $res ) ) { return; }
+
+               $sk = $wgUser->getSkin();
+               $s = $sk->beginImageHistoryList();              
+
+               $line = wfFetchObject( $res );
+               $s .= $sk->imageHistoryLine( true, $line->img_timestamp,
+                 $wgTitle->getText(),  $line->img_user,
+                 $line->img_user_text, $line->img_size, $line->img_description );
+
+               $sql = "SELECT oi_size,oi_description,oi_user," .
+                 "oi_user_text,oi_timestamp,oi_archive_name FROM oldimage WHERE " .
+                 "oi_name='" . wfStrencode( $wgTitle->getDBkey() ) . "' " .
+                 "ORDER BY oi_timestamp DESC";
+               $res = wfQuery( $sql, $fname );
+
+               while ( $line = wfFetchObject( $res ) ) {
+                       $s .= $sk->imageHistoryLine( false, $line->oi_timestamp,
+                         $line->oi_archive_name, $line->oi_user,
+                         $line->oi_user_text, $line->oi_size, $line->oi_description );
+               }
+               $s .= $sk->endImageHistoryList();
+               $wgOut->addHTML( $s );
+       }
+
+       function imageLinks()
+       {
+               global $wgUser, $wgOut, $wgTitle;
+
+               $wgOut->addHTML( "<h2>" . wfMsg( "imagelinks" ) . "</h2>\n" );
+
+               $sql = "SELECT il_from FROM imagelinks WHERE il_to='" .
+                 wfStrencode( $wgTitle->getDBkey() ) . "'";
+               $res = wfQuery( $sql, "Article::imageLinks" );
+
+               if ( 0 == wfNumRows( $res ) ) {
+                       $wgOut->addHtml( "<p>" . wfMsg( "nolinkstoimage" ) . "\n" );
+                       return;
+               }
+               $wgOut->addHTML( "<p>" . wfMsg( "linkstoimage" ) .  "\n<ul>" );
+
+               $sk = $wgUser->getSkin();
+               while ( $s = wfFetchObject( $res ) ) {
+                       $name = $s->il_from;
+                       $link = $sk->makeKnownLink( $name, "" );
+                       $wgOut->addHTML( "<li>{$link}</li>\n" );
+               }
+               $wgOut->addHTML( "</ul>\n" );
+       }
+
+       # Add this page to my watchlist
+
+       function watch()
+       {
+               global $wgUser, $wgTitle, $wgOut, $wgLang;
+               global $wgDeferredUpdateList;
+
+               if ( 0 == $wgUser->getID() ) {
+                       $wgOut->errorpage( "watchnologin", "watchnologintext" );
+                       return;
+               }
+               if ( wfReadOnly() ) {
+                       $wgOut->readOnlyPage();
+                       return;
+               }
+               $wgUser->addWatch( $wgTitle );
+
+               $wgOut->setPagetitle( wfMsg( "addedwatch" ) );
+               $wgOut->setRobotpolicy( "noindex,follow" );
+
+               $sk = $wgUser->getSkin() ;
+               $link = $sk->makeKnownLink ( $wgTitle->getPrefixedText() ) ;
+
+               $text = str_replace( "$1", $link ,
+                 wfMsg( "addedwatchtext" ) );
+               $wgOut->addHTML( $text );
+
+               $up = new UserUpdate();
+               array_push( $wgDeferredUpdateList, $up );
+
+               $wgOut->returnToMain( false );
+       }
+
+       function unwatch()
+       {
+               global $wgUser, $wgTitle, $wgOut, $wgLang;
+               global $wgDeferredUpdateList;
+
+               if ( 0 == $wgUser->getID() ) {
+                       $wgOut->errorpage( "watchnologin", "watchnologintext" );
+                       return;
+               }
+               if ( wfReadOnly() ) {
+                       $wgOut->readOnlyPage();
+                       return;
+               }
+               $wgUser->removeWatch( $wgTitle );
+
+               $wgOut->setPagetitle( wfMsg( "removedwatch" ) );
+               $wgOut->setRobotpolicy( "noindex,follow" );
+
+               $sk = $wgUser->getSkin() ;
+               $link = $sk->makeKnownLink ( $wgTitle->getPrefixedText() ) ;
+
+               $text = str_replace( "$1", $link ,
+                 wfMsg( "removedwatchtext" ) );
+               $wgOut->addHTML( $text );
+
+               $up = new UserUpdate();
+               array_push( $wgDeferredUpdateList, $up );
+
+               $wgOut->returnToMain( false );
+       }
+
+       # This shares a lot of issues (and code) with Recent Changes
+
+       function history()
+       {
+               global $wgUser, $wgOut, $wgLang, $wgTitle, $offset, $limit;
+
+               # If page hasn't changed, client can cache this
+               
+               $wgOut->checkLastModified( $this->getTimestamp() );
+               wfProfileIn( "Article::history" );
+
+               $wgOut->setPageTitle( $wgTitle->getPRefixedText() );
+               $wgOut->setSubtitle( wfMsg( "revhistory" ) );
+               $wgOut->setArticleFlag( false );
+               $wgOut->setRobotpolicy( "noindex,nofollow" );
+
+               if( $wgTitle->getArticleID() == 0 ) {
+                       $wgOut->addHTML( wfMsg( "nohistory" ) );
+                       wfProfileOut();
+                       return;
+               }
+               
+               $offset = (int)$offset;
+               $limit = (int)$limit;
+               if( $limit == 0 ) $limit = 50;
+               $namespace = $wgTitle->getNamespace();
+               $title = $wgTitle->getText();
+               $sql = "SELECT old_id,old_user," .
+                 "old_comment,old_user_text,old_timestamp,old_minor_edit ".
+                 "FROM old USE INDEX (name_title_timestamp) " .
+                 "WHERE old_namespace={$namespace} AND " .
+                 "old_title='" . wfStrencode( $wgTitle->getDBkey() ) . "' " .
+                 "ORDER BY inverse_timestamp LIMIT $offset, $limit";
+               $res = wfQuery( $sql, "Article::history" );
+
+               $revs = wfNumRows( $res );
+               if( $wgTitle->getArticleID() == 0 ) {
+                       $wgOut->addHTML( wfMsg( "nohistory" ) );
+                       wfProfileOut();
+                       return;
+               }
+               
+               $sk = $wgUser->getSkin();
+               $numbar = wfViewPrevNext(
+                       $offset, $limit,
+                       $wgTitle->getPrefixedText(),
+                       "action=history" );
+               $s = $numbar;
+               $s .= $sk->beginHistoryList();
+
+               if($offset == 0 )
+               $s .= $sk->historyLine( $this->getTimestamp(), $this->getUser(),
+                 $this->getUserText(), $namespace,
+                 $title, 0, $this->getComment(),
+                 ( $this->getMinorEdit() > 0 ) );
+
+               $revs = wfNumRows( $res );
+               while ( $line = wfFetchObject( $res ) ) {
+                       $s .= $sk->historyLine( $line->old_timestamp, $line->old_user,
+                         $line->old_user_text, $namespace,
+                         $title, $line->old_id,
+                         $line->old_comment, ( $line->old_minor_edit > 0 ) );
+               }
+               $s .= $sk->endHistoryList();
+               $s .= $numbar;
+               $wgOut->addHTML( $s );
+               wfProfileOut();
+       }
+
+       function protect()
+       {
+               global $wgUser, $wgOut, $wgTitle;
+
+               if ( ! $wgUser->isSysop() ) {
+                       $wgOut->sysopRequired();
+                       return;
+               }
+               if ( wfReadOnly() ) {
+                       $wgOut->readOnlyPage();
+                       return;
+               }
+               $id = $wgTitle->getArticleID();
+               if ( 0 == $id ) {
+                       $wgOut->fatalEror( wfMsg( "badarticleerror" ) );
+                       return;
+               }
+        $sql = "UPDATE cur SET cur_touched='" . wfTimestampNow() . "'," .
+                 "cur_restrictions='sysop' WHERE cur_id={$id}";
+               wfQuery( $sql, "Article::protect" );
+
+               $wgOut->redirect( wfLocalUrl( $wgTitle->getPrefixedURL() ) );
+       }
+
+       function unprotect()
+       {
+               global $wgUser, $wgOut, $wgTitle;
+
+               if ( ! $wgUser->isSysop() ) {
+                       $wgOut->sysopRequired();
+                       return;
+               }
+               if ( wfReadOnly() ) {
+                       $wgOut->readOnlyPage();
+                       return;
+               }
+               $id = $wgTitle->getArticleID();
+               if ( 0 == $id ) {
+                       $wgOut->fatalEror( wfMsg( "badarticleerror" ) );
+                       return;
+               }
+               $sql = "UPDATE cur SET cur_touched='" . wfTimestampNow() . "'," .
+                 "cur_restrictions='' WHERE cur_id={$id}";
+               wfQuery( $sql, "Article::unprotect" );
+
+               $wgOut->redirect( wfLocalUrl( $wgTitle->getPrefixedURL() ) );
+       }
+
+       function delete()
+       {
+               global $wgUser, $wgOut, $wgTitle;
+               global $wpConfirm, $wpReason, $image, $oldimage;
+
+               # Anybody can delete old revisions of images; only sysops
+               # can delete articles and current images
+
+               if ( ( ! $oldimage ) && ( ! $wgUser->isSysop() ) ) {
+                       $wgOut->sysopRequired();
+                       return;
+               }
+               if ( wfReadOnly() ) {
+                       $wgOut->readOnlyPage();
+                       return;
+               }
+
+               # Better double-check that it hasn't been deleted yet!
+               $wgOut->setPagetitle( wfMsg( "confirmdelete" ) );
+               if ( $image ) {
+                       if ( "" == trim( $image ) ) {
+                               $wgOut->fatalError( wfMsg( "cannotdelete" ) );
+                               return;
+                       }
+                       $sub = str_replace( "$1", $image, wfMsg( "deletesub" ) );
+               } else {
+                       if ( ( "" == trim( $wgTitle->getText() ) )
+                         or ( $wgTitle->getArticleId() == 0 ) ) {
+                               $wgOut->fatalError( wfMsg( "cannotdelete" ) );
+                               return;
+                       }
+                       $sub = str_replace( "$1", $wgTitle->getPrefixedText(),
+                         wfMsg( "deletesub" ) );
+               }
+
+               # Likewise, deleting old images doesn't require confirmation
+               if ( $oldimage || 1 == $wpConfirm ) {
+                       $this->doDelete();
+                       return;
+               }
+
+               $wgOut->setSubtitle( $sub );
+               $wgOut->setRobotpolicy( "noindex,nofollow" );
+               $wgOut->addWikiText( wfMsg( "confirmdeletetext" ) );
+
+               $t = $wgTitle->getPrefixedURL();
+               $q = "action=delete";
+
+               if ( $image ) {
+                       $q .= "&image={$image}";
+               } else if ( $oldimage ) {
+                       $q .= "&oldimage={$oldimage}";
+               } else {
+                       $q .= "&title={$t}";
+               }
+               $formaction = wfEscapeHTML( wfLocalUrl( "", $q ) );
+               $confirm = wfMsg( "confirm" );
+               $check = wfMsg( "confirmcheck" );
+               $delcom = wfMsg( "deletecomment" );
+
+               $wgOut->addHTML( "
+<form id=\"deleteconfirm\" method=\"post\" action=\"{$formaction}\">
+<table border=0><tr><td align=right>
+{$delcom}:</td><td align=left>
+<input type=text size=20 name=\"wpReason\" value=\"{$wpReason}\">
+</td></tr><tr><td>&nbsp;</td></tr>
+<tr><td align=right>
+<input type=checkbox name=\"wpConfirm\" value='1'>
+</td><td>{$check}</td>
+</tr><tr><td>&nbsp;</td><td>
+<input type=submit name=\"wpConfirmB\" value=\"{$confirm}\">
+</td></tr></table></form>\n" );
+
+               $wgOut->returnToMain( false );
+       }
+
+       function doDelete()
+       {
+               global $wgOut, $wgTitle, $wgUser, $wgLang;
+               global $image, $oldimage, $wpReason;
+               $fname = "Article::doDelete";
+
+               if ( $image ) {
+                       $dest = wfImageDir( $image );
+                       $archive = wfImageDir( $image );
+                       if ( ! unlink( "{$dest}/{$image}" ) ) {
+                               $wgOut->fileDeleteError( "{$dest}/{$image}" );
+                               return;
+                       }
+                       $sql = "DELETE FROM image WHERE img_name='" .
+                         wfStrencode( $image ) . "'";
+                       wfQuery( $sql, $fname );
+
+                       $sql = "SELECT oi_archive_name FROM oldimage WHERE oi_name='" .
+                         wfStrencode( $image ) . "'";
+                       $res = wfQuery( $sql, $fname );
+
+                       while ( $s = wfFetchObject( $res ) ) {
+                               $this->doDeleteOldImage( $s->oi_archive_name );
+                       }       
+                       $sql = "DELETE FROM oldimage WHERE oi_name='" .
+                         wfStrencode( $image ) . "'";
+                       wfQuery( $sql, $fname );
+
+                       # Image itself is now gone, and database is cleaned.
+                       # Now we remove the image description page.
+
+                       $nt = Title::newFromText( $wgLang->getNsText( Namespace::getImage() ) . ":" . $image );
+                       $this->doDeleteArticle( $nt );
+
+                       $deleted = $image;
+               } else if ( $oldimage ) {
+                       $this->doDeleteOldImage( $oldimage );
+                       $sql = "DELETE FROM oldimage WHERE oi_archive_name='" .
+                         wfStrencode( $oldimage ) . "'";
+                       wfQuery( $sql, $fname );
+
+                       $deleted = $oldimage;
+               } else {
+                       $this->doDeleteArticle( $wgTitle );
+                       $deleted = $wgTitle->getPrefixedText();
+               }
+               $wgOut->setPagetitle( wfMsg( "actioncomplete" ) );
+               $wgOut->setRobotpolicy( "noindex,nofollow" );
+
+               $sk = $wgUser->getSkin();
+               $loglink = $sk->makeKnownLink( $wgLang->getNsText(
+                 Namespace::getWikipedia() ) .
+                 ":" . wfMsg( "dellogpage" ), wfMsg( "deletionlog" ) );
+
+               $text = str_replace( "$1" , $deleted, wfMsg( "deletedtext" ) );
+               $text = str_replace( "$2", $loglink, $text );
+
+               $wgOut->addHTML( "<p>" . $text );
+               $wgOut->returnToMain( false );
+       }
+
+       function doDeleteOldImage( $oldimage )
+       {
+               global $wgOut;
+
+               $name = substr( $oldimage, 15 );
+               $archive = wfImageArchiveDir( $name );
+               if ( ! unlink( "{$archive}/{$oldimage}" ) ) {
+                       $wgOut->fileDeleteError( "{$archive}/{$oldimage}" );
+               }
+       }
+
+       function doDeleteArticle( $title )
+       {
+               global $wgUser, $wgOut, $wgLang, $wpReason, $wgTitle, $wgDeferredUpdateList;
+
+               $fname = "Article::doDeleteArticle";
+               $ns = $title->getNamespace();
+               $t = wfStrencode( $title->getDBkey() );
+               $id = $title->getArticleID();
+
+               if ( "" == $t ) {
+                       $wgOut->fatalError( wfMsg( "cannotdelete" ) );
+                       return;
+               }
+
+               $u = new SiteStatsUpdate( 0, 1, -$this->isCountable( $this->getContent( true ) ) );
+               array_push( $wgDeferredUpdateList, $u );
+
+               # Move article and history to the "archive" table
+               $sql = "INSERT INTO archive (ar_namespace,ar_title,ar_text," .
+                 "ar_comment,ar_user,ar_user_text,ar_timestamp,ar_minor_edit," .
+                 "ar_flags) SELECT cur_namespace,cur_title,cur_text,cur_comment," .
+                 "cur_user,cur_user_text,cur_timestamp,cur_minor_edit,0 FROM cur " .
+                 "WHERE cur_namespace={$ns} AND cur_title='{$t}'";
+               wfQuery( $sql, $fname );
+
+               $sql = "INSERT INTO archive (ar_namespace,ar_title,ar_text," .
+                 "ar_comment,ar_user,ar_user_text,ar_timestamp,ar_minor_edit," .
+                 "ar_flags) SELECT old_namespace,old_title,old_text,old_comment," .
+                 "old_user,old_user_text,old_timestamp,old_minor_edit,old_flags " .
+                 "FROM old WHERE old_namespace={$ns} AND old_title='{$t}'";
+               wfQuery( $sql, $fname );
+
+               # Now that it's safely backed up, delete it
+
+               $sql = "DELETE FROM cur WHERE cur_namespace={$ns} AND " .
+                 "cur_title='{$t}'";
+               wfQuery( $sql, $fname );
+
+               $sql = "DELETE FROM old WHERE old_namespace={$ns} AND " .
+                 "old_title='{$t}'";
+               wfQuery( $sql, $fname );
+               
+               $sql = "DELETE FROM recentchanges WHERE rc_namespace={$ns} AND " .
+                 "rc_title='{$t}'";
+        wfQuery( $sql, $fname );
+
+               # Finally, clean up the link tables
+
+               if ( 0 != $id ) {
+                       $t = wfStrencode( $title->getPrefixedDBkey() );
+                       $sql = "SELECT l_from FROM links WHERE l_to={$id}";
+                       $res = wfQuery( $sql, $fname );
+
+                       $sql = "INSERT INTO brokenlinks (bl_from,bl_to) VALUES ";
+            $now = wfTimestampNow();
+                       $sql2 = "UPDATE cur SET cur_touched='{$now}' WHERE cur_id IN (";
+                       $first = true;
+
+                       while ( $s = wfFetchObject( $res ) ) {
+                               $nt = Title::newFromDBkey( $s->l_from );
+                               $lid = $nt->getArticleID();
+
+                               if ( ! $first ) { $sql .= ","; $sql2 .= ","; }
+                               $first = false;
+                               $sql .= "({$lid},'{$t}')";
+                               $sql2 .= "{$lid}";
+                       }
+                       $sql2 .= ")";
+                       if ( ! $first ) {
+                               wfQuery( $sql, $fname );
+                               wfQuery( $sql2, $fname );
+                       }
+                       wfFreeResult( $res );
+
+                       $sql = "DELETE FROM links WHERE l_to={$id}";
+                       wfQuery( $sql, $fname );
+
+                       $sql = "DELETE FROM links WHERE l_from='{$t}'";
+                       wfQuery( $sql, $fname );
+
+                       $sql = "DELETE FROM imagelinks WHERE il_from='{$t}'";
+                       wfQuery( $sql, $fname );
+
+                       $sql = "DELETE FROM brokenlinks WHERE bl_from={$id}";
+                       wfQuery( $sql, $fname );
+               }
+               
+               $log = new LogPage( wfMsg( "dellogpage" ), wfMsg( "dellogpagetext" ) );
+               $art = $title->getPrefixedText();
+               $wpReason = wfCleanQueryVar( $wpReason );
+               $log->addEntry( str_replace( "$1", $art, wfMsg( "deletedarticle" ) ), $wpReason );
+
+               # Clear the cached article id so the interface doesn't act like we exist
+               $wgTitle->resetArticleID( 0 );
+               $wgTitle->mArticleID = 0;
+       }
+
+       function revert()
+       {
+               global $wgOut;
+               global $oldimage;
+
+               if ( strlen( $oldimage ) < 16 ) {
+                       $wgOut->unexpectedValueError( "oldimage", $oldimage );
+                       return;
+               }
+               if ( wfReadOnly() ) {
+                       $wgOut->readOnlyPage();
+                       return;
+               }
+               $name = substr( $oldimage, 15 );
+
+               $dest = wfImageDir( $name );
+               $archive = wfImageArchiveDir( $name );
+               $curfile = "{$dest}/{$name}";
+
+               if ( ! is_file( $curfile ) ) {
+                       $wgOut->fileNotFoundError( $curfile );
+                       return;
+               }
+               $oldver = wfTimestampNow() . "!{$name}";
+               $size = wfGetSQL( "oldimage", "oi_size", "oi_archive_name='" .
+                 wfStrencode( $oldimage ) . "'" );
+
+               if ( ! rename( $curfile, "${archive}/{$oldver}" ) ) {
+                       $wgOut->fileRenameError( $curfile, "${archive}/{$oldver}" );
+                       return;
+               }
+               if ( ! copy( "{$archive}/{$oldimage}", $curfile ) ) {
+                       $wgOut->fileCopyError( "${archive}/{$oldimage}", $curfile );
+               }
+               wfRecordUpload( $name, $oldver, $size, wfMsg( "reverted" ) );
+
+               $wgOut->setPagetitle( wfMsg( "actioncomplete" ) );
+               $wgOut->setRobotpolicy( "noindex,nofollow" );
+               $wgOut->addHTML( wfMsg( "imagereverted" ) );
+               $wgOut->returnToMain( false );
+       }
+
+       function rollback()
+       {
+               global $wgUser, $wgTitle, $wgLang, $wgOut;
+
+               if ( ! $wgUser->isSysop() ) {
+                       $wgOut->sysopRequired();
+                       return;
+               }
+               
+               # Replace all this user's current edits with the next one down
+               $tt = wfStrencode( $wgTitle->getDBKey() );
+               $n = $wgTitle->getNamespace();
+               
+               # Get the last editor
+               $sql = "SELECT cur_id,cur_user,cur_user_text FROM cur WHERE cur_title='{$tt}' AND cur_namespace={$n}";
+               $res = wfQuery( $sql );
+               if( ($x = wfNumRows( $res )) != 1 ) {
+                       # Something wrong
+                       $wgOut->addHTML( wfMsg( "notanarticle" ) );
+                       return;
+               }
+               $s = wfFetchObject( $res );
+               $ut = wfStrencode( $s->cur_user_text );
+               $uid = $s->cur_user;
+               $pid = $s->cur_id;
+               
+               # Get the last edit not by this guy
+               $sql = "SELECT old_text,old_user,old_user_text
+               FROM old USE INDEX (name_title_timestamp)
+               WHERE old_namespace={$n} AND old_title='{$tt}'
+               AND (old_user <> {$uid} OR old_user_text <> '{$ut}')
+               ORDER BY inverse_timestamp LIMIT 1";
+               $res = wfQuery( $sql );
+               if( wfNumRows( $res ) != 1 ) {
+                       # Something wrong
+                       $wgOut->addHTML( wfMsg( "cantrollback" ) );
+                       return;
+               }
+               $s = wfFetchObject( $res );
+       
+               # Save it!
+               $newcomment = str_replace( "$1", $s->old_user_text, wfMsg( "revertpage" ) );
+               $wgOut->setPagetitle( wfMsg( "actioncomplete" ) );
+               $wgOut->setRobotpolicy( "noindex,nofollow" );
+               $wgOut->addHTML( "<h2>" . $newcomment . "</h2>\n<hr>\n" );
+               $this->updateArticle( $s->old_text, $newcomment, 1, $wgTitle->userIsWatching() );
+
+               $wgOut->returnToMain( false );
+       }
+       
+
+       # Do standard deferred updates after page view
+
+       /* private */ function viewUpdates()
+       {
+               global $wgDeferredUpdateList, $wgTitle;
+
+               if ( 0 != $this->getID() ) {
+                       $u = new ViewCountUpdate( $this->getID() );
+                       array_push( $wgDeferredUpdateList, $u );
+                       $u = new SiteStatsUpdate( 1, 0, 0 );
+                       array_push( $wgDeferredUpdateList, $u );
+
+                       $u = new UserTalkUpdate( 0, $wgTitle->getNamespace(),
+                         $wgTitle->getDBkey() );
+                       array_push( $wgDeferredUpdateList, $u );
+               }
+       }
+
+       # Do standard deferred updates after page edit.
+       # Every 1000th edit, prune the recent changes table.
+
+       /* private */ function editUpdates( $text )
+       {
+               global $wgDeferredUpdateList, $wgTitle;
+
+               wfSeedRandom();
+               if ( 0 == mt_rand( 0, 999 ) ) {
+                       $cutoff = wfUnix2Timestamp( time() - ( 7 * 86400 ) );
+                       $sql = "DELETE FROM recentchanges WHERE rc_timestamp < '{$cutoff}'";
+                       wfQuery( $sql );
+               }
+               $id = $this->getID();
+               $title = $wgTitle->getPrefixedDBkey();
+               $adj = $this->mCountAdjustment;
+
+               if ( 0 != $id ) {
+                       $u = new LinksUpdate( $id, $title );
+                       array_push( $wgDeferredUpdateList, $u );
+                       $u = new SiteStatsUpdate( 0, 1, $adj );
+                       array_push( $wgDeferredUpdateList, $u );
+                       $u = new SearchUpdate( $id, $title, $text );
+                       array_push( $wgDeferredUpdateList, $u );
+
+                       $u = new UserTalkUpdate( 1, $wgTitle->getNamespace(),
+                         $wgTitle->getDBkey() );
+                       array_push( $wgDeferredUpdateList, $u );
+               }
+       }
+
+       /* private */ function setOldSubtitle()
+       {
+               global $wgLang, $wgOut;
+
+               $td = $wgLang->timeanddate( $this->mTimestamp, true );
+               $r = str_replace( "$1", "{$td}", wfMsg( "revisionasof" ) );
+               $wgOut->setSubtitle( "({$r})" );
+       }
+
+       function blockedIPpage()
+       {
+               global $wgOut, $wgUser, $wgLang;
+
+               $wgOut->setPageTitle( wfMsg( "blockedtitle" ) );
+               $wgOut->setRobotpolicy( "noindex,nofollow" );
+               $wgOut->setArticleFlag( false );
+
+               $id = $wgUser->blockedBy();
+               $reason = $wgUser->blockedFor();
+
+               $name = User::whoIs( $id );
+               $link = "[[" . $wgLang->getNsText( Namespace::getUser() ) .
+                 ":{$name}|{$name}]]";
+
+               $text = str_replace( "$1", $link, wfMsg( "blockedtext" ) );
+               $text = str_replace( "$2", $reason, $text );
+               $wgOut->addWikiText( $text );
+               $wgOut->returnToMain( false );
+       }
+
+       # This function is called right before saving the wikitext,
+       # so we can do things like signatures and links-in-context.
+
+       function preSaveTransform( $text )
+       {
+               $s = "";
+               while ( "" != $text ) {
+                       $p = preg_split( "/<\\s*nowiki\\s*>/i", $text, 2 );
+                       $s .= $this->pstPass2( $p[0] );
+
+                       if ( ( count( $p ) < 2 ) || ( "" == $p[1] ) ) { $text = ""; }
+                       else {
+                               $q = preg_split( "/<\\/\\s*nowiki\\s*>/i", $p[1], 2 );
+                               $s .= "<nowiki>{$q[0]}</nowiki>";
+                               $text = $q[1];
+                       }
+               }
+               return rtrim( $s );
+       }
+
+       /* private */ function pstPass2( $text )
+       {
+               global $wgUser, $wgLang, $wgTitle, $wgLocaltimezone;
+
+               # Signatures
+               #
+               $n = $wgUser->getName();
+               $k = $wgUser->getOption( "nickname" );
+               if ( "" == $k ) { $k = $n; }
+               if(isset($wgLocaltimezone)) {
+                       $oldtz = getenv("TZ"); putenv("TZ=$wgLocaltimezone");
+               }
+               $d = $wgLang->timeanddate( wfTimestampNow(), false ) .
+                 " (" . date( "T" ) . ")";
+               if(isset($wgLocaltimezone)) putenv("TZ=$oldtz");
+
+               $text = preg_replace( "/~~~~/", "[[" . $wgLang->getNsText(
+                 Namespace::getUser() ) . ":$n|$k]] $d", $text );
+               $text = preg_replace( "/~~~/", "[[" . $wgLang->getNsText(
+                 Namespace::getUser() ) . ":$n|$k]]", $text );
+
+               # Context links: [[|name]] and [[name (context)|]]
+               #
+               $tc = "[&;%\\-,.\\(\\)' _0-9A-Za-z\\/:\\x80-\\xff]";
+               $np = "[&;%\\-,.' _0-9A-Za-z\\/:\\x80-\\xff]"; # No parens
+               $conpat = "/^({$np}+) \\(({$tc}+)\\)$/";
+
+               $p1 = "/\[\[({$np}+) \\(({$np}+)\\)\\|]]/";             # [[page (context)|]]
+               $p2 = "/\[\[\\|({$tc}+)]]/";                                    # [[|page]]
+               $p3 = "/\[\[([A-Za-z _]+):({$np}+)\\|]]/";              # [[namespace:page|]]
+               $p4 = "/\[\[([A-Aa-z _]+):({$np}+) \\(({$np}+)\\)\\|]]/";
+                                                                                                               # [[ns:page (cont)|]]
+               $context = "";
+               $t = $wgTitle->getText();
+               if ( preg_match( $conpat, $t, $m ) ) {
+                       $context = $m[2];
+               }
+               $text = preg_replace( $p4, "[[\\1:\\2 (\\3)|\\2]]", $text );
+               $text = preg_replace( $p1, "[[\\1 (\\2)|\\1]]", $text );
+               $text = preg_replace( $p3, "[[\\1:\\2|\\2]]", $text );
+
+               if ( "" == $context ) {
+                       $text = preg_replace( $p2, "[[\\1]]", $text );
+               } else {
+                       $text = preg_replace( $p2, "[[\\1 ({$context})|\\1]]", $text );
+               }
+               # Replace local image links with new [[image:]] style
+
+               $text = preg_replace(
+                 "/(^|[^[])http:\/\/(www.|)wikipedia.com\/upload\/" .
+                 "([a-zA-Z0-9_:.~\%\-]+)\.(png|PNG|jpg|JPG|jpeg|JPEG|gif|GIF)/",
+                 "\\1[[image:\\3.\\4]]", $text );
+               $text = preg_replace(
+                 "/(^|[^[])http:\/\/(www.|)wikipedia.com\/images\/uploads\/" .
+                 "([a-zA-Z0-9_:.~\%\-]+)\.(png|PNG|jpg|JPG|jpeg|JPEG|gif|GIF)/",
+                 "\\1[[image:\\3.\\4]]", $text );
+
+               return $text;
+       }
+}
+
+?>
diff --git a/includes/DatabaseFunctions.php b/includes/DatabaseFunctions.php
new file mode 100644 (file)
index 0000000..3d93047
--- /dev/null
@@ -0,0 +1,134 @@
+<?
+global $IP;
+include_once( "$IP/FulltextStoplist.php" );
+
+$wgLastDatabaseQuery = "";
+
+function wfGetDB( $altuser = "", $altpassword = "" )
+{
+       global $wgDBserver, $wgDBuser, $wgDBpassword;
+       global $wgDBname, $wgDBconnection, $wgEmergencyContact;
+
+       $noconn = str_replace( "$1", $wgDBserver, wfMsg( "noconnect" ) );
+       $nodb = str_replace( "$1", $wgDBname, wfMsg( "nodb" ) );
+
+       $helpme = "\n<p>If this error persists after reloading and clearing " .
+         "your browser cache, please notify the <a href=\"mailto:" .
+         $wgEmergencyContact . "\">Wikipedia developers</a>.</p>";
+
+       if ( $altuser != "" ) {
+               $wgDBconnection = mysql_connect( $wgDBserver, $altuser, $altpassword )
+                       or die( "bad sql user" );
+               mysql_select_db( $wgDBname, $wgDBconnection ) or die(
+                 htmlspecialchars(mysql_error()) );
+       }
+
+       if ( ! $wgDBconnection ) {
+               $wgDBconnection = mysql_pconnect( $wgDBserver, $wgDBuser,
+                 $wgDBpassword ) or die( $noconn .
+               "\n<p><b>" . htmlspecialchars(mysql_error()) . "</b></p>\n" . $helpme );
+               if( !mysql_select_db( $wgDBname, $wgDBconnection ) ) {
+                       wfDebug( "Persistent connection is broken?\n", true );
+                       
+                       $wgDBconnection = mysql_connect( $wgDBserver, $wgDBuser,
+                         $wgDBpassword ) or die( $noconn .
+                 "\n<p><b>" . htmlspecialchars(mysql_error()) . "</b> (tried non-p connect)</p>\n" . $helpme );
+                       mysql_select_db( $wgDBname, $wgDBconnection ) or die( $nodb .
+                         "\n<p><b>" . htmlspecialchars(mysql_error()) . "</b> (tried non-p connect)</p>\n" . $helpme );
+        }
+       }
+       # mysql_ping( $wgDBconnection );
+       return $wgDBconnection;
+}
+
+function wfQuery( $sql, $fname = "" )
+{
+       global $wgLastDatabaseQuery, $wgOut;
+##     wfProfileIn( "wfQuery" );
+       $wgLastDatabaseQuery = $sql;
+
+       $conn = wfGetDB();
+       $ret = mysql_query( $sql, $conn );
+
+       if ( "" != $fname ) {
+#              wfDebug( "{$fname}:SQL: {$sql}\n", true );
+       } else {
+#              wfDebug( "SQL: {$sql}\n", true );
+       }
+       if ( false === $ret ) {
+               $wgOut->databaseError( $fname );
+               exit;
+       }
+##     wfProfileOut();
+       return $ret;
+}
+
+function wfFreeResult( $res ) { mysql_free_result( $res ); }
+function wfFetchObject( $res ) { return mysql_fetch_object( $res ); }
+function wfNumRows( $res ) { return mysql_num_rows( $res ); }
+function wfNumFields( $res ) { return mysql_num_fields( $res ); }
+function wfFieldName( $res, $n ) { return mysql_field_name( $res, $n ); }
+function wfInsertId() { return mysql_insert_id( wfGetDB() ); }
+function wfDataSeek( $res, $row ) { return mysql_data_seek( $res, $row ); }
+function wfLastErrno() { return mysql_errno(); }
+function wfLastError() { return mysql_error(); }
+
+function wfLastDBquery()
+{
+       global $wgLastDatabaseQuery;
+       return $wgLastDatabaseQuery;
+}
+
+function wfSetSQL( $table, $var, $value, $cond )
+{
+       $sql = "UPDATE $table SET $var = '" .
+         wfStrencode( $value ) . "' WHERE ($cond)";
+       wfQuery( $sql, "wfSetSQL" );
+}
+
+function wfGetSQL( $table, $var, $cond )
+{
+       $sql = "SELECT $var FROM $table WHERE ($cond)";
+       $result = wfQuery( $sql, "wfGetSQL" );
+
+       $ret = "";
+       if ( mysql_num_rows( $result ) > 0 ) {
+               $s = mysql_fetch_object( $result );
+               $ret = $s->$var;
+               mysql_free_result( $result );
+       }
+       return $ret;
+}
+
+function wfStrencode( $s )
+{
+       return addslashes( $s );
+}
+
+# Ideally we'd be using actual time fields in the db
+function wfTimestamp2Unix( $ts ) {
+       return mktime( ( (int)substr( $ts, 8, 2) ),
+                 (int)substr( $ts, 10, 2 ), (int)substr( $ts, 12, 2 ),
+                 (int)substr( $ts, 4, 2 ), (int)substr( $ts, 6, 2 ),
+                 (int)substr( $ts, 0, 4 ) );
+}
+
+function wfUnix2Timestamp( $unixtime ) {
+       return date( "YmdHis", $unixtime );
+}
+
+function wfTimestampNow() {
+       # return NOW
+       return date( "YmdHis" );
+}
+
+# Sorting hack for MySQL 3, which doesn't use index sorts for DESC
+function wfInvertTimestamp( $ts ) {
+       return strtr(
+               $ts,
+               "0123456789",
+               "9876543210"
+       );
+}
+
+?>
diff --git a/includes/DefaultSettings.php b/includes/DefaultSettings.php
new file mode 100644 (file)
index 0000000..77be904
--- /dev/null
@@ -0,0 +1,66 @@
+<?
+# DO NOT EDIT THIS FILE!
+# To customize your installation, edit "LocalSettings.php".
+
+$wgServer           = "http://" . getenv( "SERVER_NAME" );
+$wgScriptPath      = "/wiki";
+$wgScript           = "{$wgScriptPath}/wiki.phtml";
+$wgRedirectScript   = "{$wgScriptPath}/redirect.phtml";
+$wgStyleSheetPath   = "{$wgScriptPath}/style";
+$wgStyleSheetDirectory = "{$IP}/style";
+$wgArticlePath      = "{$wgScript}?title=$1";
+$wgUploadPath       = "{$wgScriptPath}/upload";
+$wgUploadDirectory     = "{$IP}/upload";
+$wgLogo                                = "{$wgUploadPath}/wiki.png";
+$wgMathPath         = "{$wgUploadPath}/math";
+$wgMathDirectory    = "{$wgUploadDirectory}/math";
+$wgTmpDirectory     = "{$wgUploadDirectory}/tmp";
+$wgEmergencyContact = "wikiadmin@" . getenv( "SERVER_NAME" );
+
+# MySQL settings
+#
+$wgDBserver         = "127.0.0.1";
+$wgDBname           = "wikidb";
+$wgDBintlname       = "intl";
+$wgDBconnection     = "";
+$wgDBuser           = "wikiuser";
+$wgDBpassword       = "userpass";
+$wgDBsqluser           = "sqluser";
+$wgDBsqlpassword       = "sqlpass";
+$wgDBminWordLen     = 4;
+$wgDBtransactions      = false; # Set to true if using InnoDB tables
+
+# Language settings
+#
+$wgLanguageCode     = "en";
+$wgInterwikiMagic      = true; # Treat language links as magic connectors, not inline links
+$wgUseNewInterlanguage = false;
+$wgInputEncoding       = "ISO-8859-1";
+$wgOutputEncoding      = "ISO-8859-1";
+$wgEditEncoding                = "";
+$wgDocType          = "-//W3C//DTD HTML 4.01 Transitional//EN";
+$wgAmericanDates = false;      # Enable for English module to print dates
+$wgLocalInterwiki   = "w";
+
+# Miscellaneous configuration settings
+#
+$wgReadOnlyFile                = "{$wgUploadDirectory}/lock_yBgMBwiR";
+$wgDebugLogFile     = "{$wgUploadDirectory}/log_dlJbnMZb";
+$wgDebugComments       = false;
+$wgReadOnly                    = false;
+
+$wgCachePages          = true; # Allow client-side caching of pages
+$wgCookieExpiration = 2592000;
+
+$wgAllowExternalImages = true;
+$wgMiserMode = false; # Disable database-intensive features
+$wgUseTeX = false;
+$wgProfiling = false; # Enable for more detailed by-function times in debug log
+
+# Which namespaces should support subpages?
+# See Language.php for a list of namespaces.
+#
+$wgNamespacesWithSubpages = array( -1 => 0, 0 => 0, 1 => 1,
+  2 => 1, 3 => 1, 4 => 0, 5 => 1, 6 => 0, 7 => 1 );
+
+?>
diff --git a/includes/DifferenceEngine.php b/includes/DifferenceEngine.php
new file mode 100644 (file)
index 0000000..835ac74
--- /dev/null
@@ -0,0 +1,1138 @@
+<?
+# See diff.doc
+
+class DifferenceEngine {
+       /* private */ var $mOldid, $mNewid;
+       /* private */ var $mOldtitle, $mNewtitle;
+       /* private */ var $mOldtext, $mNewtext;
+
+       function DifferenceEngine( $old, $new )
+       {
+               $this->mOldid = $old;
+               $this->mNewid = $new;
+       }
+
+       function showDiffPage()
+       {
+               global $wgUser, $wgTitle, $wgOut, $wgLang;
+
+               $t = $wgTitle->getPrefixedText() . " (Diff: {$this->mOldid}, " .
+                 "{$this->mNewid})";
+               $mtext = str_replace( "$1", $t, wfMsg( "missingarticle" ) );
+
+               $wgOut->setArticleFlag( false );
+               if ( ! $this->loadText() ) {
+                       $wgOut->setPagetitle( wfMsg( "errorpagetitle" ) );
+                       $wgOut->addHTML( $mtext );
+                       return;
+               }
+               $wgOut->supressQuickbar();
+               $wgOut->setSubtitle( wfMsg( "difference" ) );
+               $wgOut->setRobotpolicy( "noindex,follow" );
+
+               DifferenceEngine::showDiff( $this->mOldtext, $this->mNewtext,
+                 $this->mOldtitle, $this->mNewtitle );
+               $wgOut->addHTML( "<hr><h2>{$this->mNewtitle}</h2>\n" );
+               $wgOut->addWikiText( $this->mNewtext );
+       }
+
+       function showDiff( $otext, $ntext, $otitle, $ntitle )
+       {
+               global $wgOut;
+
+               $ota = explode( "\n", str_replace( "\r\n", "\n",
+                 htmlspecialchars( $otext ) ) );
+               $nta = explode( "\n", str_replace( "\r\n", "\n",
+                 htmlspecialchars( $ntext ) ) );
+
+               $wgOut->addHTML( "<table width='98%' border=0
+cellpadding=0 cellspacing='4px'><tr>
+<td colspan=2 width='50%' align=center bgcolor='#cccccc'>
+<strong>{$otitle}</strong></td>
+<td colspan=2 width='50%' align=center bgcolor='#cccccc'>
+<strong>{$ntitle}</strong></td>
+</tr>\n" );
+
+               $diffs = new Diff( $ota, $nta );
+               $formatter = new TableDiffFormatter();
+               $formatter->format( $diffs );
+               $wgOut->addHTML( "</table>\n" );
+       }
+
+       # Load the text of the articles to compare.  If newid is 0, then compare
+       # the old article in oldid to the current article; if oldid is 0, then
+       # compare the current article to the immediately previous one (ignoring
+       # the value of newid).
+       #
+       function loadText()
+       {
+               global $wgTitle, $wgOut, $wgLang;
+               $fname = "DifferenceEngine::loadText";
+
+               if ( 0 == $this->mNewid || 0 == $this->mOldid ) {
+                       $wgOut->setArticleFlag( true );
+                       $this->mNewtitle = wfMsg( "currentrev" );
+                       $id = $wgTitle->getArticleID();
+
+                       $sql = "SELECT cur_text FROM cur WHERE cur_id={$id}";
+                       $res = wfQuery( $sql, $fname );
+                       if ( 0 == wfNumRows( $res ) ) { return false; }
+
+                       $s = wfFetchObject( $res );
+                       $this->mNewtext = $s->cur_text;
+               } else {
+                       $sql = "SELECT old_timestamp,old_text FROM old WHERE " .
+                         "old_id={$this->mNewid}";
+
+                       $res = wfQuery( $sql, $fname );
+                       if ( 0 == wfNumRows( $res ) ) { return false; }
+
+                       $s = wfFetchObject( $res );
+                       $this->mNewtext = $s->old_text;
+
+                       $t = $wgLang->timeanddate( $s->old_timestamp, true );
+                       $this->mNewtitle = str_replace( "$1", "{$t}",
+                         wfMsg( "revisionasof" ) );
+               }
+               if ( 0 == $this->mOldid ) {
+                       $sql = "SELECT old_timestamp,old_text FROM old USE INDEX (name_title_timestamp) WHERE " .
+                         "old_namespace=" . $wgTitle->getNamespace() . " AND " .
+                         "old_title='" . wfStrencode( $wgTitle->getDBkey() ) .
+                         "' ORDER BY inverse_timestamp LIMIT 1";
+                       $res = wfQuery( $sql, $fname );
+               } else {
+                       $sql = "SELECT old_timestamp,old_text FROM old WHERE " .
+                         "old_id={$this->mOldid}";
+                       $res = wfQuery( $sql, $fname );
+               }
+               if ( 0 == wfNumRows( $res ) ) { return false; }
+
+               $s = wfFetchObject( $res );
+               $this->mOldtext = $s->old_text;
+
+               $t = $wgLang->timeanddate( $s->old_timestamp, true );
+               $this->mOldtitle = str_replace( "$1", "{$t}",
+                 wfMsg( "revisionasof" ) );
+
+               return true;
+       }
+}
+
+// A PHP diff engine for phpwiki. (Taken from phpwiki-1.3.3)
+//
+// Copyright (C) 2000, 2001 Geoffrey T. Dairiki <dairiki@dairiki.org>
+// You may copy this code freely under the conditions of the GPL.
+//
+
+define('USE_ASSERTS', function_exists('assert'));
+
+class _DiffOp {
+    var $type;
+    var $orig;
+    var $final;
+    
+    function reverse() {
+        trigger_error("pure virtual", E_USER_ERROR);
+    }
+
+    function norig() {
+        return $this->orig ? sizeof($this->orig) : 0;
+    }
+
+    function nfinal() {
+        return $this->final ? sizeof($this->final) : 0;
+    }
+}
+
+class _DiffOp_Copy extends _DiffOp {
+    var $type = 'copy';
+    
+    function _DiffOp_Copy ($orig, $final = false) {
+        if (!is_array($final))
+            $final = $orig;
+        $this->orig = $orig;
+        $this->final = $final;
+    }
+
+    function reverse() {
+        return new _DiffOp_Copy($this->final, $this->orig);
+    }
+}
+
+class _DiffOp_Delete extends _DiffOp {
+    var $type = 'delete';
+    
+    function _DiffOp_Delete ($lines) {
+        $this->orig = $lines;
+        $this->final = false;
+    }
+
+    function reverse() {
+        return new _DiffOp_Add($this->orig);
+    }
+}
+
+class _DiffOp_Add extends _DiffOp {
+    var $type = 'add';
+    
+    function _DiffOp_Add ($lines) {
+        $this->final = $lines;
+        $this->orig = false;
+    }
+
+    function reverse() {
+        return new _DiffOp_Delete($this->final);
+    }
+}
+
+class _DiffOp_Change extends _DiffOp {
+    var $type = 'change';
+    
+    function _DiffOp_Change ($orig, $final) {
+        $this->orig = $orig;
+        $this->final = $final;
+    }
+
+    function reverse() {
+        return new _DiffOp_Change($this->final, $this->orig);
+    }
+}
+        
+      
+/**
+ * Class used internally by Diff to actually compute the diffs.
+ *
+ * The algorithm used here is mostly lifted from the perl module
+ * Algorithm::Diff (version 1.06) by Ned Konz, which is available at:
+ *   http://www.perl.com/CPAN/authors/id/N/NE/NEDKONZ/Algorithm-Diff-1.06.zip
+ *
+ * More ideas are taken from:
+ *   http://www.ics.uci.edu/~eppstein/161/960229.html
+ *
+ * Some ideas are (and a bit of code) are from from analyze.c, from GNU
+ * diffutils-2.7, which can be found at:
+ *   ftp://gnudist.gnu.org/pub/gnu/diffutils/diffutils-2.7.tar.gz
+ *
+ * Finally, some ideas (subdivision by NCHUNKS > 2, and some optimizations)
+ * are my own.
+ *
+ * @author Geoffrey T. Dairiki
+ * @access private
+ */
+class _DiffEngine
+{
+    function diff ($from_lines, $to_lines) {
+        $n_from = sizeof($from_lines);
+        $n_to = sizeof($to_lines);
+
+        $this->xchanged = $this->ychanged = array();
+        $this->xv = $this->yv = array();
+        $this->xind = $this->yind = array();
+        unset($this->seq);
+        unset($this->in_seq);
+        unset($this->lcs);
+         
+        // Skip leading common lines.
+        for ($skip = 0; $skip < $n_from && $skip < $n_to; $skip++) {
+            if ($from_lines[$skip] != $to_lines[$skip])
+                break;
+            $this->xchanged[$skip] = $this->ychanged[$skip] = false;
+        }
+        // Skip trailing common lines.
+        $xi = $n_from; $yi = $n_to;
+        for ($endskip = 0; --$xi > $skip && --$yi > $skip; $endskip++) {
+            if ($from_lines[$xi] != $to_lines[$yi])
+                break;
+            $this->xchanged[$xi] = $this->ychanged[$yi] = false;
+        }
+        
+        // Ignore lines which do not exist in both files.
+        for ($xi = $skip; $xi < $n_from - $endskip; $xi++)
+            $xhash[$from_lines[$xi]] = 1;
+        for ($yi = $skip; $yi < $n_to - $endskip; $yi++) {
+            $line = $to_lines[$yi];
+            if ( ($this->ychanged[$yi] = empty($xhash[$line])) )
+                continue;
+            $yhash[$line] = 1;
+            $this->yv[] = $line;
+            $this->yind[] = $yi;
+        }
+        for ($xi = $skip; $xi < $n_from - $endskip; $xi++) {
+            $line = $from_lines[$xi];
+            if ( ($this->xchanged[$xi] = empty($yhash[$line])) )
+                continue;
+            $this->xv[] = $line;
+            $this->xind[] = $xi;
+        }
+
+        // Find the LCS.
+        $this->_compareseq(0, sizeof($this->xv), 0, sizeof($this->yv));
+
+        // Merge edits when possible
+        $this->_shift_boundaries($from_lines, $this->xchanged, $this->ychanged);
+        $this->_shift_boundaries($to_lines, $this->ychanged, $this->xchanged);
+
+        // Compute the edit operations.
+        $edits = array();
+        $xi = $yi = 0;
+        while ($xi < $n_from || $yi < $n_to) {
+            USE_ASSERTS && assert($yi < $n_to || $this->xchanged[$xi]);
+            USE_ASSERTS && assert($xi < $n_from || $this->ychanged[$yi]);
+
+            // Skip matching "snake".
+            $copy = array();
+            while ( $xi < $n_from && $yi < $n_to
+                    && !$this->xchanged[$xi] && !$this->ychanged[$yi]) {
+                $copy[] = $from_lines[$xi++];
+                ++$yi;
+            }
+            if ($copy)
+                $edits[] = new _DiffOp_Copy($copy);
+
+            // Find deletes & adds.
+            $delete = array();
+            while ($xi < $n_from && $this->xchanged[$xi])
+                $delete[] = $from_lines[$xi++];
+
+            $add = array();
+            while ($yi < $n_to && $this->ychanged[$yi])
+                $add[] = $to_lines[$yi++];
+            
+            if ($delete && $add)
+                $edits[] = new _DiffOp_Change($delete, $add);
+            elseif ($delete)
+                $edits[] = new _DiffOp_Delete($delete);
+            elseif ($add)
+                $edits[] = new _DiffOp_Add($add);
+        }
+        return $edits;
+    }
+    
+
+    /* Divide the Largest Common Subsequence (LCS) of the sequences
+     * [XOFF, XLIM) and [YOFF, YLIM) into NCHUNKS approximately equally
+     * sized segments.
+     *
+     * Returns (LCS, PTS).  LCS is the length of the LCS. PTS is an
+     * array of NCHUNKS+1 (X, Y) indexes giving the diving points between
+     * sub sequences.  The first sub-sequence is contained in [X0, X1),
+     * [Y0, Y1), the second in [X1, X2), [Y1, Y2) and so on.  Note
+     * that (X0, Y0) == (XOFF, YOFF) and
+     * (X[NCHUNKS], Y[NCHUNKS]) == (XLIM, YLIM).
+     *
+     * This function assumes that the first lines of the specified portions
+     * of the two files do not match, and likewise that the last lines do not
+     * match.  The caller must trim matching lines from the beginning and end
+     * of the portions it is going to specify.
+     */
+    function _diag ($xoff, $xlim, $yoff, $ylim, $nchunks) {
+       $flip = false;
+       
+       if ($xlim - $xoff > $ylim - $yoff) {
+           // Things seems faster (I'm not sure I understand why)
+            // when the shortest sequence in X.
+            $flip = true;
+           list ($xoff, $xlim, $yoff, $ylim)
+               = array( $yoff, $ylim, $xoff, $xlim);
+        }
+
+       if ($flip)
+           for ($i = $ylim - 1; $i >= $yoff; $i--)
+               $ymatches[$this->xv[$i]][] = $i;
+       else
+           for ($i = $ylim - 1; $i >= $yoff; $i--)
+               $ymatches[$this->yv[$i]][] = $i;
+
+       $this->lcs = 0;
+       $this->seq[0]= $yoff - 1;
+       $this->in_seq = array();
+       $ymids[0] = array();
+    
+       $numer = $xlim - $xoff + $nchunks - 1;
+       $x = $xoff;
+       for ($chunk = 0; $chunk < $nchunks; $chunk++) {
+           if ($chunk > 0)
+               for ($i = 0; $i <= $this->lcs; $i++)
+                   $ymids[$i][$chunk-1] = $this->seq[$i];
+
+           $x1 = $xoff + (int)(($numer + ($xlim-$xoff)*$chunk) / $nchunks);
+           for ( ; $x < $x1; $x++) {
+                $line = $flip ? $this->yv[$x] : $this->xv[$x];
+                if (empty($ymatches[$line]))
+                   continue;
+               $matches = $ymatches[$line];
+                reset($matches);
+               while (list ($junk, $y) = each($matches))
+                   if (empty($this->in_seq[$y])) {
+                       $k = $this->_lcs_pos($y);
+                       USE_ASSERTS && assert($k > 0);
+                       $ymids[$k] = $ymids[$k-1];
+                       break;
+                    }
+               while (list ($junk, $y) = each($matches)) {
+                   if ($y > $this->seq[$k-1]) {
+                       USE_ASSERTS && assert($y < $this->seq[$k]);
+                       // Optimization: this is a common case:
+                       //  next match is just replacing previous match.
+                       $this->in_seq[$this->seq[$k]] = false;
+                       $this->seq[$k] = $y;
+                       $this->in_seq[$y] = 1;
+                    }
+                   else if (empty($this->in_seq[$y])) {
+                       $k = $this->_lcs_pos($y);
+                       USE_ASSERTS && assert($k > 0);
+                       $ymids[$k] = $ymids[$k-1];
+                    }
+                }
+            }
+        }
+
+       $seps[] = $flip ? array($yoff, $xoff) : array($xoff, $yoff);
+       $ymid = $ymids[$this->lcs];
+       for ($n = 0; $n < $nchunks - 1; $n++) {
+           $x1 = $xoff + (int)(($numer + ($xlim - $xoff) * $n) / $nchunks);
+           $y1 = $ymid[$n] + 1;
+           $seps[] = $flip ? array($y1, $x1) : array($x1, $y1);
+        }
+       $seps[] = $flip ? array($ylim, $xlim) : array($xlim, $ylim);
+
+       return array($this->lcs, $seps);
+    }
+
+    function _lcs_pos ($ypos) {
+       $end = $this->lcs;
+       if ($end == 0 || $ypos > $this->seq[$end]) {
+           $this->seq[++$this->lcs] = $ypos;
+           $this->in_seq[$ypos] = 1;
+           return $this->lcs;
+        }
+
+       $beg = 1;
+       while ($beg < $end) {
+           $mid = (int)(($beg + $end) / 2);
+           if ( $ypos > $this->seq[$mid] )
+               $beg = $mid + 1;
+           else
+               $end = $mid;
+        }
+
+       USE_ASSERTS && assert($ypos != $this->seq[$end]);
+
+       $this->in_seq[$this->seq[$end]] = false;
+       $this->seq[$end] = $ypos;
+       $this->in_seq[$ypos] = 1;
+       return $end;
+    }
+
+    /* Find LCS of two sequences.
+     *
+     * The results are recorded in the vectors $this->{x,y}changed[], by
+     * storing a 1 in the element for each line that is an insertion
+     * or deletion (ie. is not in the LCS).
+     *
+     * The subsequence of file 0 is [XOFF, XLIM) and likewise for file 1.
+     *
+     * Note that XLIM, YLIM are exclusive bounds.
+     * All line numbers are origin-0 and discarded lines are not counted.
+     */
+    function _compareseq ($xoff, $xlim, $yoff, $ylim) {
+       // Slide down the bottom initial diagonal.
+       while ($xoff < $xlim && $yoff < $ylim
+               && $this->xv[$xoff] == $this->yv[$yoff]) {
+           ++$xoff;
+           ++$yoff;
+        }
+
+       // Slide up the top initial diagonal.
+       while ($xlim > $xoff && $ylim > $yoff
+               && $this->xv[$xlim - 1] == $this->yv[$ylim - 1]) {
+           --$xlim;
+           --$ylim;
+        }
+
+       if ($xoff == $xlim || $yoff == $ylim)
+           $lcs = 0;
+       else {
+           // This is ad hoc but seems to work well.
+           //$nchunks = sqrt(min($xlim - $xoff, $ylim - $yoff) / 2.5);
+           //$nchunks = max(2,min(8,(int)$nchunks));
+           $nchunks = min(7, $xlim - $xoff, $ylim - $yoff) + 1;
+           list ($lcs, $seps)
+               = $this->_diag($xoff,$xlim,$yoff, $ylim,$nchunks);
+        }
+
+       if ($lcs == 0) {
+           // X and Y sequences have no common subsequence:
+           // mark all changed.
+           while ($yoff < $ylim)
+               $this->ychanged[$this->yind[$yoff++]] = 1;
+           while ($xoff < $xlim)
+               $this->xchanged[$this->xind[$xoff++]] = 1;
+        }
+       else {
+           // Use the partitions to split this problem into subproblems.
+           reset($seps);
+           $pt1 = $seps[0];
+           while ($pt2 = next($seps)) {
+               $this->_compareseq ($pt1[0], $pt2[0], $pt1[1], $pt2[1]);
+               $pt1 = $pt2;
+            }
+        }
+    }
+
+    /* Adjust inserts/deletes of identical lines to join changes
+     * as much as possible.
+     *
+     * We do something when a run of changed lines include a
+     * line at one end and has an excluded, identical line at the other.
+     * We are free to choose which identical line is included.
+     * `compareseq' usually chooses the one at the beginning,
+     * but usually it is cleaner to consider the following identical line
+     * to be the "change".
+     *
+     * This is extracted verbatim from analyze.c (GNU diffutils-2.7).
+     */
+    function _shift_boundaries ($lines, &$changed, $other_changed) {
+       $i = 0;
+       $j = 0;
+
+       USE_ASSERTS && assert('sizeof($lines) == sizeof($changed)');
+       $len = sizeof($lines);
+       $other_len = sizeof($other_changed);
+
+       while (1) {
+           /*
+            * Scan forwards to find beginning of another run of changes.
+            * Also keep track of the corresponding point in the other file.
+            *
+            * Throughout this code, $i and $j are adjusted together so that
+            * the first $i elements of $changed and the first $j elements
+            * of $other_changed both contain the same number of zeros
+            * (unchanged lines).
+            * Furthermore, $j is always kept so that $j == $other_len or
+            * $other_changed[$j] == false.
+            */
+           while ($j < $other_len && $other_changed[$j])
+               $j++;
+           
+           while ($i < $len && ! $changed[$i]) {
+               USE_ASSERTS && assert('$j < $other_len && ! $other_changed[$j]');
+               $i++; $j++;
+               while ($j < $other_len && $other_changed[$j])
+                   $j++;
+            }
+            
+           if ($i == $len)
+               break;
+
+           $start = $i;
+
+           // Find the end of this run of changes.
+           while (++$i < $len && $changed[$i])
+               continue;
+
+           do {
+               /*
+                * Record the length of this run of changes, so that
+                * we can later determine whether the run has grown.
+                */
+               $runlength = $i - $start;
+
+               /*
+                * Move the changed region back, so long as the
+                * previous unchanged line matches the last changed one.
+                * This merges with previous changed regions.
+                */
+               while ($start > 0 && $lines[$start - 1] == $lines[$i - 1]) {
+                   $changed[--$start] = 1;
+                   $changed[--$i] = false;
+                   while ($start > 0 && $changed[$start - 1])
+                       $start--;
+                   USE_ASSERTS && assert('$j > 0');
+                   while ($other_changed[--$j])
+                       continue;
+                   USE_ASSERTS && assert('$j >= 0 && !$other_changed[$j]');
+                }
+
+               /*
+                * Set CORRESPONDING to the end of the changed run, at the last
+                * point where it corresponds to a changed run in the other file.
+                * CORRESPONDING == LEN means no such point has been found.
+                */
+               $corresponding = $j < $other_len ? $i : $len;
+
+               /*
+                * Move the changed region forward, so long as the
+                * first changed line matches the following unchanged one.
+                * This merges with following changed regions.
+                * Do this second, so that if there are no merges,
+                * the changed region is moved forward as far as possible.
+                */
+               while ($i < $len && $lines[$start] == $lines[$i]) {
+                   $changed[$start++] = false;
+                   $changed[$i++] = 1;
+                   while ($i < $len && $changed[$i])
+                       $i++;
+
+                   USE_ASSERTS && assert('$j < $other_len && ! $other_changed[$j]');
+                   $j++;
+                   if ($j < $other_len && $other_changed[$j]) {
+                       $corresponding = $i;
+                       while ($j < $other_len && $other_changed[$j])
+                           $j++;
+                    }
+                }
+            } while ($runlength != $i - $start);
+
+           /*
+            * If possible, move the fully-merged run of changes
+            * back to a corresponding run in the other file.
+            */
+           while ($corresponding < $i) {
+               $changed[--$start] = 1;
+               $changed[--$i] = 0;
+               USE_ASSERTS && assert('$j > 0');
+               while ($other_changed[--$j])
+                   continue;
+               USE_ASSERTS && assert('$j >= 0 && !$other_changed[$j]');
+            }
+        }
+    }
+}
+
+/**
+ * Class representing a 'diff' between two sequences of strings.
+ */
+class Diff 
+{
+    var $edits;
+
+    /**
+     * Constructor.
+     * Computes diff between sequences of strings.
+     *
+     * @param $from_lines array An array of strings.
+     *        (Typically these are lines from a file.)
+     * @param $to_lines array An array of strings.
+     */
+    function Diff($from_lines, $to_lines) {
+        $eng = new _DiffEngine;
+        $this->edits = $eng->diff($from_lines, $to_lines);
+        //$this->_check($from_lines, $to_lines);
+    }
+
+    /**
+     * Compute reversed Diff.
+     *
+     * SYNOPSIS:
+     *
+     *  $diff = new Diff($lines1, $lines2);
+     *  $rev = $diff->reverse();
+     * @return object A Diff object representing the inverse of the
+     *                original diff.
+     */
+    function reverse () {
+       $rev = $this;
+        $rev->edits = array();
+        foreach ($this->edits as $edit) {
+            $rev->edits[] = $edit->reverse();
+        }
+       return $rev;
+    }
+
+    /**
+     * Check for empty diff.
+     *
+     * @return bool True iff two sequences were identical.
+     */
+    function isEmpty () {
+        foreach ($this->edits as $edit) {
+            if ($edit->type != 'copy')
+                return false;
+        }
+        return true;
+    }
+  
+    /**
+     * Compute the length of the Longest Common Subsequence (LCS).
+     *
+     * This is mostly for diagnostic purposed.
+     *
+     * @return int The length of the LCS.
+     */
+    function lcs () {
+       $lcs = 0;
+        foreach ($this->edits as $edit) {
+            if ($edit->type == 'copy')
+                $lcs += sizeof($edit->orig);
+        }
+       return $lcs;
+    }
+
+    /**
+     * Get the original set of lines.
+     *
+     * This reconstructs the $from_lines parameter passed to the
+     * constructor.
+     *
+     * @return array The original sequence of strings.
+     */
+    function orig() {
+        $lines = array();
+        
+        foreach ($this->edits as $edit) {
+            if ($edit->orig)
+                array_splice($lines, sizeof($lines), 0, $edit->orig);
+        }
+        return $lines;
+    }
+
+    /**
+     * Get the final set of lines.
+     *
+     * This reconstructs the $to_lines parameter passed to the
+     * constructor.
+     *
+     * @return array The sequence of strings.
+     */
+    function final() {
+        $lines = array();
+        
+        foreach ($this->edits as $edit) {
+            if ($edit->final)
+                array_splice($lines, sizeof($lines), 0, $edit->final);
+        }
+        return $lines;
+    }
+
+    /**
+     * Check a Diff for validity. 
+     *
+     * This is here only for debugging purposes.
+     */
+    function _check ($from_lines, $to_lines) {
+        if (serialize($from_lines) != serialize($this->orig()))
+            trigger_error("Reconstructed original doesn't match", E_USER_ERROR);
+        if (serialize($to_lines) != serialize($this->final()))
+            trigger_error("Reconstructed final doesn't match", E_USER_ERROR);
+
+        $rev = $this->reverse();
+        if (serialize($to_lines) != serialize($rev->orig()))
+            trigger_error("Reversed original doesn't match", E_USER_ERROR);
+        if (serialize($from_lines) != serialize($rev->final()))
+            trigger_error("Reversed final doesn't match", E_USER_ERROR);
+
+
+        $prevtype = 'none';
+        foreach ($this->edits as $edit) {
+            if ( $prevtype == $edit->type )
+                trigger_error("Edit sequence is non-optimal", E_USER_ERROR);
+            $prevtype = $edit->type;
+        }
+
+        $lcs = $this->lcs();
+        trigger_error("Diff okay: LCS = $lcs", E_USER_NOTICE);
+    }
+}
+            
+/**
+ * FIXME: bad name.
+ */
+class MappedDiff
+extends Diff
+{
+    /**
+     * Constructor.
+     *
+     * Computes diff between sequences of strings.
+     *
+     * This can be used to compute things like
+     * case-insensitve diffs, or diffs which ignore
+     * changes in white-space.
+     *
+     * @param $from_lines array An array of strings.
+     *  (Typically these are lines from a file.)
+     *
+     * @param $to_lines array An array of strings.
+     *
+     * @param $mapped_from_lines array This array should
+     *  have the same size number of elements as $from_lines.
+     *  The elements in $mapped_from_lines and
+     *  $mapped_to_lines are what is actually compared
+     *  when computing the diff.
+     *
+     * @param $mapped_to_lines array This array should
+     *  have the same number of elements as $to_lines.
+     */
+    function MappedDiff($from_lines, $to_lines,
+                        $mapped_from_lines, $mapped_to_lines) {
+
+        assert(sizeof($from_lines) == sizeof($mapped_from_lines));
+        assert(sizeof($to_lines) == sizeof($mapped_to_lines));
+        
+        $this->Diff($mapped_from_lines, $mapped_to_lines);
+
+        $xi = $yi = 0;
+        for ($i = 0; $i < sizeof($this->edits); $i++) {
+            $orig = &$this->edits[$i]->orig;
+            if (is_array($orig)) {
+                $orig = array_slice($from_lines, $xi, sizeof($orig));
+                $xi += sizeof($orig);
+            }
+            
+            $final = &$this->edits[$i]->final;
+            if (is_array($final)) {
+                $final = array_slice($to_lines, $yi, sizeof($final));
+                $yi += sizeof($final);
+            }
+        }
+    }
+}
+
+/**
+ * A class to format Diffs
+ *
+ * This class formats the diff in classic diff format.
+ * It is intended that this class be customized via inheritance,
+ * to obtain fancier outputs.
+ */
+class DiffFormatter
+{
+    /**
+     * Number of leading context "lines" to preserve.
+     *
+     * This should be left at zero for this class, but subclasses
+     * may want to set this to other values.
+     */
+    var $leading_context_lines = 0;
+
+    /**
+     * Number of trailing context "lines" to preserve.
+     *
+     * This should be left at zero for this class, but subclasses
+     * may want to set this to other values.
+     */
+    var $trailing_context_lines = 0;
+
+    /**
+     * Format a diff.
+     *
+     * @param $diff object A Diff object.
+     * @return string The formatted output.
+     */
+    function format($diff) {
+
+        $xi = $yi = 1;
+        $block = false;
+        $context = array();
+
+        $nlead = $this->leading_context_lines;
+        $ntrail = $this->trailing_context_lines;
+
+        $this->_start_diff();
+
+        foreach ($diff->edits as $edit) {
+            if ($edit->type == 'copy') {
+                if (is_array($block)) {
+                    if (sizeof($edit->orig) <= $nlead + $ntrail) {
+                        $block[] = $edit;
+                    }
+                    else{
+                        if ($ntrail) {
+                            $context = array_slice($edit->orig, 0, $ntrail);
+                            $block[] = new _DiffOp_Copy($context);
+                        }
+                        $this->_block($x0, $ntrail + $xi - $x0,
+                                      $y0, $ntrail + $yi - $y0,
+                                      $block);
+                        $block = false;
+                    }
+                }
+                $context = $edit->orig;
+            }
+            else {
+                if (! is_array($block)) {
+                    $context = array_slice($context, sizeof($context) - $nlead);
+                    $x0 = $xi - sizeof($context);
+                    $y0 = $yi - sizeof($context);
+                    $block = array();
+                    if ($context)
+                        $block[] = new _DiffOp_Copy($context);
+                }
+                $block[] = $edit;
+            }
+
+            if ($edit->orig)
+                $xi += sizeof($edit->orig);
+            if ($edit->final)
+                $yi += sizeof($edit->final);
+        }
+
+        if (is_array($block))
+            $this->_block($x0, $xi - $x0,
+                          $y0, $yi - $y0,
+                          $block);
+
+        return $this->_end_diff();
+    }
+
+    function _block($xbeg, $xlen, $ybeg, $ylen, &$edits) {
+        $this->_start_block($this->_block_header($xbeg, $xlen, $ybeg, $ylen));
+        foreach ($edits as $edit) {
+            if ($edit->type == 'copy')
+                $this->_context($edit->orig);
+            elseif ($edit->type == 'add')
+                $this->_added($edit->final);
+            elseif ($edit->type == 'delete')
+                $this->_deleted($edit->orig);
+            elseif ($edit->type == 'change')
+                $this->_changed($edit->orig, $edit->final);
+            else
+                trigger_error("Unknown edit type", E_USER_ERROR);
+        }
+        $this->_end_block();
+    }
+
+    function _start_diff() {
+        ob_start();
+    }
+
+    function _end_diff() {
+        $val = ob_get_contents();
+        ob_end_clean();
+        return $val;
+    }
+
+    function _block_header($xbeg, $xlen, $ybeg, $ylen) {
+        if ($xlen > 1)
+            $xbeg .= "," . ($xbeg + $xlen - 1);
+        if ($ylen > 1)
+            $ybeg .= "," . ($ybeg + $ylen - 1);
+
+        return $xbeg . ($xlen ? ($ylen ? 'c' : 'd') : 'a') . $ybeg;
+    }
+    
+    function _start_block($header) {
+        echo $header;
+    }
+    
+    function _end_block() {
+    }
+
+    function _lines($lines, $prefix = ' ') {
+        foreach ($lines as $line)
+            echo "$prefix $line\n";
+    }
+    
+    function _context($lines) {
+        $this->_lines($lines);
+    }
+
+    function _added($lines) {
+        $this->_lines($lines, ">");
+    }
+    function _deleted($lines) {
+        $this->_lines($lines, "<");
+    }
+
+    function _changed($orig, $final) {
+        $this->_deleted($orig);
+        echo "---\n";
+        $this->_added($final);
+    }
+}
+
+
+/**
+ *  Additions by Axel Boldt follow, partly taken from diff.php, phpwiki-1.3.3
+ * 
+ */
+
+define('NBSP', "\xA0");         // iso-8859-x non-breaking space.
+
+class _HWLDF_WordAccumulator {
+    function _HWLDF_WordAccumulator () {
+        $this->_lines = array();
+        $this->_line = '';
+        $this->_group = '';
+        $this->_tag = '';
+    }
+
+    function _flushGroup ($new_tag) {
+        if ($this->_group !== '') {
+         if ($this->_tag == 'mark') 
+            $this->_line .= "<font color=\"red\">$this->_group</font>";
+         else
+           $this->_line .= $this->_group;
+       }
+        $this->_group = '';
+        $this->_tag = $new_tag;
+    }
+    
+    function _flushLine ($new_tag) {
+        $this->_flushGroup($new_tag);
+        if ($this->_line != '')
+            $this->_lines[] = $this->_line;
+        $this->_line = '';
+    }
+                
+    function addWords ($words, $tag = '') {
+        if ($tag != $this->_tag)
+            $this->_flushGroup($tag);
+
+        foreach ($words as $word) {
+            // new-line should only come as first char of word.
+            if ($word == '')
+                continue;
+            if ($word[0] == "\n") {
+                $this->_group .= NBSP;
+                $this->_flushLine($tag);
+                $word = substr($word, 1);
+            }
+            assert(!strstr($word, "\n"));
+            $this->_group .= $word;
+        }
+    }
+
+    function getLines() {
+        $this->_flushLine('~done');
+        return $this->_lines;
+    }
+}
+
+class WordLevelDiff extends MappedDiff
+{
+    function WordLevelDiff ($orig_lines, $final_lines) {
+        list ($orig_words, $orig_stripped) = $this->_split($orig_lines);
+        list ($final_words, $final_stripped) = $this->_split($final_lines);
+
+        
+        $this->MappedDiff($orig_words, $final_words,
+                          $orig_stripped, $final_stripped);
+    }
+
+    function _split($lines) {
+        // FIXME: fix POSIX char class.
+#        if (!preg_match_all('/ ( [^\S\n]+ | [[:alnum:]]+ | . ) (?: (?!< \n) [^\S\n])? /xs',
+        if (!preg_match_all('/ ( [^\S\n]+ | [0-9_A-Za-z\x80-\xff]+ | . ) (?: (?!< \n) [^\S\n])? /xs',
+                            implode("\n", $lines),
+                            $m)) {
+            return array(array(''), array(''));
+        }
+        return array($m[0], $m[1]);
+    }
+
+    function orig () {
+        $orig = new _HWLDF_WordAccumulator;
+        
+        foreach ($this->edits as $edit) {
+            if ($edit->type == 'copy')
+                $orig->addWords($edit->orig);
+            elseif ($edit->orig)
+                $orig->addWords($edit->orig, 'mark');
+        }
+        return $orig->getLines();
+    }
+
+    function final () {
+        $final = new _HWLDF_WordAccumulator;
+        
+        foreach ($this->edits as $edit) {
+            if ($edit->type == 'copy')
+                $final->addWords($edit->final);
+            elseif ($edit->final)
+                $final->addWords($edit->final, 'mark');
+        }
+        return $final->getLines();
+    }
+}
+
+/**
+ *  Wikipedia Table style diff formatter.
+ * 
+ */
+class TableDiffFormatter extends DiffFormatter
+{
+       function TableDiffFormatter() {
+               $this->leading_context_lines = 2;
+               $this->trailing_context_lines = 2;
+       }
+    
+       function _block_header( $xbeg, $xlen, $ybeg, $ylen ) {
+               $l1 = str_replace( "$1", $xbeg, wfMsg( "lineno" ) );
+               $l2 = str_replace( "$1", $ybeg, wfMsg( "lineno" ) );
+
+               $r = "<tr><td colspan=2 align=left><strong>{$l1}</strong></td>\n" .
+                 "<td colspan=2 align=left><strong>{$l2}</strong></td></tr>\n";
+               return $r;
+       }
+
+       function _start_block( $header ) {
+               global $wgOut;
+               $wgOut->addHTML( $header );
+       }
+
+       function _end_block() {
+       }
+
+       function _lines( $lines, $prefix=' ', $color="white" ) {
+       }
+
+       function addedLine( $line ) {
+               return "<td>+</td><td bgcolor='#ccffcc'>" .
+                 "<small>{$line}</small></td>";
+       }
+
+       function deletedLine( $line ) {
+               return "<td>-</td><td bgcolor='#ffffaa'>" .
+                 "<small>{$line}</small></td>";
+       }
+
+       function emptyLine() {
+               return "<td colspan=2>&nbsp;</td>";
+       }
+
+       function contextLine( $line ) {
+               return "<td> </td><td bgcolor='white'><small>{$line}</small></td>";
+       }
+    
+    function _added($lines) {
+               global $wgOut;
+               foreach ($lines as $line) {
+                       $wgOut->addHTML( "<tr>" . $this->emptyLine() .
+                         $this->addedLine( $line ) . "</tr>\n" );
+               }
+       }
+
+       function _deleted($lines) {
+               global $wgOut;
+               foreach ($lines as $line) {
+                       $wgOut->addHTML( "<tr>" . $this->deletedLine( $line ) .
+                         $this->emptyLine() . "</tr>\n" );
+               }
+       }
+
+       function _context( $lines ) {
+               global $wgOut;
+               foreach ($lines as $line) {
+                       $wgOut->addHTML( "<tr>" . $this->contextLine( $line ) .
+                         $this->contextLine( $line ) . "</tr>\n" );
+               }
+       }
+
+       function _changed( $orig, $final ) {
+               global $wgOut;
+        $diff = new WordLevelDiff( $orig, $final );
+               $del = $diff->orig();
+               $add = $diff->final();
+
+               while ( $line = array_shift( $del ) ) {
+                       $aline = array_shift( $add );
+                       $wgOut->addHTML( "<tr>" . $this->deletedLine( $line ) .
+                         $this->addedLine( $aline ) . "</tr>\n" );
+               }
+               $this->_added( $add ); # If any leftovers
+    }
+}
+
+?>
diff --git a/includes/FulltextStoplist.php b/includes/FulltextStoplist.php
new file mode 100644 (file)
index 0000000..ce0756f
--- /dev/null
@@ -0,0 +1,592 @@
+<?
+
+# This is the MySQL fulltext search stoplist, copied from the
+# source file "myisam/ft_static.c" in the MySQL source distribution.
+# If you use a new version of MySQL, this might have to be changed.
+
+/* private */ $wgFulltextStoplist = array(
+
+  "a",
+  "a's",
+  "able",
+  "about",
+  "above",
+  "according",
+  "accordingly",
+  "across",
+  "actually",
+  "after",
+  "afterwards",
+  "again",
+  "against",
+  "ain't",
+  "all",
+  "allow",
+  "allows",
+  "almost",
+  "alone",
+  "along",
+  "already",
+  "also",
+  "although",
+  "always",
+  "am",
+  "among",
+  "amongst",
+  "an",
+  "and",
+  "another",
+  "any",
+  "anybody",
+  "anyhow",
+  "anyone",
+  "anything",
+  "anyway",
+  "anyways",
+  "anywhere",
+  "apart",
+  "appear",
+  "appreciate",
+  "appropriate",
+  "are",
+  "aren't",
+  "around",
+  "as",
+  "aside",
+  "ask",
+  "asking",
+  "associated",
+  "at",
+  "available",
+  "away",
+  "awfully",
+  "b",
+  "be",
+  "became",
+  "because",
+  "become",
+  "becomes",
+  "becoming",
+  "been",
+  "before",
+  "beforehand",
+  "behind",
+  "being",
+  "believe",
+  "below",
+  "beside",
+  "besides",
+  "best",
+  "better",
+  "between",
+  "beyond",
+  "both",
+  "brief",
+  "but",
+  "by",
+  "c",
+  "c'mon",
+  "c's",
+  "came",
+  "can",
+  "can't",
+  "cannot",
+  "cant",
+  "cause",
+  "causes",
+  "certain",
+  "certainly",
+  "changes",
+  "clearly",
+  "co",
+  "com",
+  "come",
+  "comes",
+  "concerning",
+  "consequently",
+  "consider",
+  "considering",
+  "contain",
+  "containing",
+  "contains",
+  "corresponding",
+  "could",
+  "couldn't",
+  "course",
+  "currently",
+  "d",
+  "definitely",
+  "described",
+  "despite",
+  "did",
+  "didn't",
+  "different",
+  "do",
+  "does",
+  "doesn't",
+  "doing",
+  "don't",
+  "done",
+  "down",
+  "downwards",
+  "during",
+  "e",
+  "each",
+  "edu",
+  "eg",
+  "eight",
+  "either",
+  "else",
+  "elsewhere",
+  "enough",
+  "entirely",
+  "especially",
+  "et",
+  "etc",
+  "even",
+  "ever",
+  "every",
+  "everybody",
+  "everyone",
+  "everything",
+  "everywhere",
+  "ex",
+  "exactly",
+  "example",
+  "except",
+  "f",
+  "far",
+  "few",
+  "fifth",
+  "first",
+  "five",
+  "followed",
+  "following",
+  "follows",
+  "for",
+  "former",
+  "formerly",
+  "forth",
+  "four",
+  "from",
+  "further",
+  "furthermore",
+  "g",
+  "get",
+  "gets",
+  "getting",
+  "given",
+  "gives",
+  "go",
+  "goes",
+  "going",
+  "gone",
+  "got",
+  "gotten",
+  "greetings",
+  "h",
+  "had",
+  "hadn't",
+  "happens",
+  "hardly",
+  "has",
+  "hasn't",
+  "have",
+  "haven't",
+  "having",
+  "he",
+  "he's",
+  "hello",
+  "help",
+  "hence",
+  "her",
+  "here",
+  "here's",
+  "hereafter",
+  "hereby",
+  "herein",
+  "hereupon",
+  "hers",
+  "herself",
+  "hi",
+  "him",
+  "himself",
+  "his",
+  "hither",
+  "hopefully",
+  "how",
+  "howbeit",
+  "however",
+  "i",
+  "i'd",
+  "i'll",
+  "i'm",
+  "i've",
+  "ie",
+  "if",
+  "ignored",
+  "immediate",
+  "in",
+  "inasmuch",
+  "inc",
+  "indeed",
+  "indicate",
+  "indicated",
+  "indicates",
+  "inner",
+  "insofar",
+  "instead",
+  "into",
+  "inward",
+  "is",
+  "isn't",
+  "it",
+  "it'd",
+  "it'll",
+  "it's",
+  "its",
+  "itself",
+  "j",
+  "just",
+  "k",
+  "keep",
+  "keeps",
+  "kept",
+  "know",
+  "knows",
+  "known",
+  "l",
+  "last",
+  "lately",
+  "later",
+  "latter",
+  "latterly",
+  "least",
+  "less",
+  "lest",
+  "let",
+  "let's",
+  "like",
+  "liked",
+  "likely",
+  "little",
+  "look",
+  "looking",
+  "looks",
+  "ltd",
+  "m",
+  "mainly",
+  "many",
+  "may",
+  "maybe",
+  "me",
+  "mean",
+  "meanwhile",
+  "merely",
+  "might",
+  "more",
+  "moreover",
+  "most",
+  "mostly",
+  "much",
+  "must",
+  "my",
+  "myself",
+  "n",
+  "name",
+  "namely",
+  "nd",
+  "near",
+  "nearly",
+  "necessary",
+  "need",
+  "needs",
+  "neither",
+  "never",
+  "nevertheless",
+  "new",
+  "next",
+  "nine",
+  "no",
+  "nobody",
+  "non",
+  "none",
+  "noone",
+  "nor",
+  "normally",
+  "not",
+  "nothing",
+  "novel",
+  "now",
+  "nowhere",
+  "o",
+  "obviously",
+  "of",
+  "off",
+  "often",
+  "oh",
+  "ok",
+  "okay",
+  "old",
+  "on",
+  "once",
+  "one",
+  "ones",
+  "only",
+  "onto",
+  "or",
+  "other",
+  "others",
+  "otherwise",
+  "ought",
+  "our",
+  "ours",
+  "ourselves",
+  "out",
+  "outside",
+  "over",
+  "overall",
+  "own",
+  "p",
+  "particular",
+  "particularly",
+  "per",
+  "perhaps",
+  "placed",
+  "please",
+  "plus",
+  "possible",
+  "presumably",
+  "probably",
+  "provides",
+  "q",
+  "que",
+  "quite",
+  "qv",
+  "r",
+  "rather",
+  "rd",
+  "re",
+  "really",
+  "reasonably",
+  "regarding",
+  "regardless",
+  "regards",
+  "relatively",
+  "respectively",
+  "right",
+  "s",
+  "said",
+  "same",
+  "saw",
+  "say",
+  "saying",
+  "says",
+  "second",
+  "secondly",
+  "see",
+  "seeing",
+  "seem",
+  "seemed",
+  "seeming",
+  "seems",
+  "seen",
+  "self",
+  "selves",
+  "sensible",
+  "sent",
+  "serious",
+  "seriously",
+  "seven",
+  "several",
+  "shall",
+  "she",
+  "should",
+  "shouldn't",
+  "since",
+  "six",
+  "so",
+  "some",
+  "somebody",
+  "somehow",
+  "someone",
+  "something",
+  "sometime",
+  "sometimes",
+  "somewhat",
+  "somewhere",
+  "soon",
+  "sorry",
+  "specified",
+  "specify",
+  "specifying",
+  "still",
+  "sub",
+  "such",
+  "sup",
+  "sure",
+  "t",
+  "t's",
+  "take",
+  "taken",
+  "tell",
+  "tends",
+  "th",
+  "than",
+  "thank",
+  "thanks",
+  "thanx",
+  "that",
+  "that's",
+  "thats",
+  "the",
+  "their",
+  "theirs",
+  "them",
+  "themselves",
+  "then",
+  "thence",
+  "there",
+  "there's",
+  "thereafter",
+  "thereby",
+  "therefore",
+  "therein",
+  "theres",
+  "thereupon",
+  "these",
+  "they",
+  "they'd",
+  "they'll",
+  "they're",
+  "they've",
+  "think",
+  "third",
+  "this",
+  "thorough",
+  "thoroughly",
+  "those",
+  "though",
+  "three",
+  "through",
+  "throughout",
+  "thru",
+  "thus",
+  "to",
+  "together",
+  "too",
+  "took",
+  "toward",
+  "towards",
+  "tried",
+  "tries",
+  "truly",
+  "try",
+  "trying",
+  "twice",
+  "two",
+  "u",
+  "un",
+  "under",
+  "unfortunately",
+  "unless",
+  "unlikely",
+  "until",
+  "unto",
+  "up",
+  "upon",
+  "us",
+  "use",
+  "used",
+  "useful",
+  "uses",
+  "using",
+  "usually",
+  "v",
+  "value",
+  "various",
+  "very",
+  "via",
+  "viz",
+  "vs",
+  "w",
+  "want",
+  "wants",
+  "was",
+  "wasn't",
+  "way",
+  "we",
+  "we'd",
+  "we'll",
+  "we're",
+  "we've",
+  "welcome",
+  "well",
+  "went",
+  "were",
+  "weren't",
+  "what",
+  "what's",
+  "whatever",
+  "when",
+  "whence",
+  "whenever",
+  "where",
+  "where's",
+  "whereafter",
+  "whereas",
+  "whereby",
+  "wherein",
+  "whereupon",
+  "wherever",
+  "whether",
+  "which",
+  "while",
+  "whither",
+  "who",
+  "who's",
+  "whoever",
+  "whole",
+  "whom",
+  "whose",
+  "why",
+  "will",
+  "willing",
+  "wish",
+  "with",
+  "within",
+  "without",
+  "won't",
+  "wonder",
+  "would",
+  "would",
+  "wouldn't",
+  "x",
+  "y",
+  "yes",
+  "yet",
+  "you",
+  "you'd",
+  "you'll",
+  "you're",
+  "you've",
+  "your",
+  "yours",
+  "yourself",
+  "yourselves",
+  "z",
+  "zero" );
+
+class FulltextStoplist {
+
+       /* static */ function inList( $word )
+       {
+               global $wgFulltextStoplist;
+
+               $w = strtolower( $word );
+               $w = preg_replace( "/[^a-z']+/", "", $w );
+               return in_array( $w, $wgFulltextStoplist );
+       }
+}
+
+?>
diff --git a/includes/GlobalFunctions.php b/includes/GlobalFunctions.php
new file mode 100644 (file)
index 0000000..a60007b
--- /dev/null
@@ -0,0 +1,494 @@
+<?
+# Global functions used everywhere
+
+$wgNumberOfArticles = -1; # Unset
+$wgTotalViews = -1;
+$wgTotalEdits = -1;
+
+global $IP;
+include_once( "$IP/DatabaseFunctions.php" );
+include_once( "$IP/UpdateClasses.php" );
+include_once( "$IP/LogPage.php" );
+
+# PHP 4.1+ has array_key_exists, PHP 4.0.6 has key_exists instead, and earlier
+# versions of PHP have neither. So we roll our own. Note that this
+# function will return false even for keys that exist but whose associated 
+# value is NULL.
+#
+if ( phpversion() == "4.0.6" ) {
+       function array_key_exists( $k, $a ) {
+               return key_exists( $k, $a );
+       }
+} else if (phpversion() < "4.1") {
+       function array_key_exists( $k, $a ) {
+               return isset($a[$k]);
+       }
+}
+
+$wgRandomSeeded = false;
+
+function wfSeedRandom()
+{
+       global $wgRandomSeeded;
+
+       if ( ! $wgRandomSeeded ) {
+               mt_srand( (double)microtime() * 1000000 );
+               $wgRandomSeeded = true;
+       }
+}
+
+function wfLocalUrl( $a, $q = "" )
+{
+       global $wgServer, $wgScript, $wgArticlePath;
+
+       $a = str_replace( " ", "_", $a );
+       #$a = wfUrlencode( $a ); # This stuff is _already_ URL-encoded.
+
+       if ( "" == $a ) {
+               if( "" == $q ) {
+                       $a = $wgServer . $wgScript;
+               } else {
+                       $a = "{$wgServer}{$wgScript}?{$q}";
+               }       
+       } else if ( "" == $q ) {
+               $a = str_replace( "$1", $a, $wgArticlePath );
+       } else {
+               $a = "{$wgServer}{$wgScript}?title={$a}&{$q}";  
+       }
+       return $a;
+}
+
+function wfLocalUrlE( $a, $q = "" )
+{
+       return wfEscapeHTML( wfLocalUrl( $a, $q ) );
+}
+
+function wfImageUrl( $img )
+{
+       global $wgUploadPath;
+
+       $nt = Title::newFromText( $img );
+       $name = $nt->getDBkey();
+       $hash = md5( $name );
+
+       $url = "{$wgUploadPath}/" . $hash{0} . "/" .
+         substr( $hash, 0, 2 ) . "/{$name}";
+       return wfUrlencode( $url );
+}
+
+function wfImageArchiveUrl( $name )
+{
+       global $wgUploadPath;
+
+       $hash = md5( substr( $name, 15) );
+       $url = "{$wgUploadPath}/archive/" . $hash{0} . "/" .
+         substr( $hash, 0, 2 ) . "/{$name}";
+       return $url;
+}
+
+function wfUrlencode ( $s )
+{
+       $ulink = urlencode( $s );
+       $ulink = preg_replace( "/%3[Aa]/", ":", $ulink );
+       $ulink = preg_replace( "/%2[Ff]/", "/", $ulink );
+       return $ulink;
+}
+
+function wfUtf8Sequence($codepoint) {
+       if($codepoint <     0x80) return chr($codepoint);
+       if($codepoint <    0x800) return chr($codepoint >>  6 & 0x3f | 0xc0) .
+                                     chr($codepoint       & 0x3f | 0x80);
+    if($codepoint <  0x10000) return chr($codepoint >> 12 & 0x0f | 0xe0) .
+                                     chr($codepoint >>  6 & 0x3f | 0x80) .
+                                     chr($codepoint       & 0x3f | 0x80);
+       if($codepoint < 0x100000) return chr($codepoint >> 18 & 0x07 | 0xf0) . # Double-check this
+                                        chr($codepoint >> 12 & 0x3f | 0x80) .
+                                     chr($codepoint >>  6 & 0x3f | 0x80) .
+                                     chr($codepoint       & 0x3f | 0x80);
+       # Doesn't yet handle outside the BMP
+       return "&#$codepoint;";
+}
+
+function wfMungeToUtf8($string) {
+       global $wgInputEncoding; # This is debatable
+       #$string = iconv($wgInputEncoding, "UTF-8", $string);
+       $string = preg_replace ( '/&#([0-9]+);/e', 'wfUtf8Sequence($1)', $string );
+       $string = preg_replace ( '/&#x([0-9a-f]+);/ie', 'wfUtf8Sequence(0x$1)', $string );
+       # Should also do named entities here
+       return $string;
+}
+
+function wfDebug( $text, $logonly = false )
+{
+       global $wgOut, $wgDebugLogFile;
+
+       if ( ! $logonly ) {
+               $wgOut->debug( $text );
+       }
+       if ( "" != $wgDebugLogFile ) {
+               error_log( $text, 3, $wgDebugLogFile );
+       }
+}
+
+if( !isset( $wgProfiling ) )
+       $wgProfiling = false;
+$wgProfileStack = array();
+$wgProfileWorkStack = array();
+
+if( $wgProfiling ) {
+       function wfProfileIn( $functionname )
+       {
+               global $wgProfileStack, $wgProfileWorkStack;
+               array_push( $wgProfileWorkStack, "$functionname " .
+                       count( $wgProfileWorkStack ) . " " . microtime() );
+       }
+
+       function wfProfileOut() {
+               global $wgProfileStack, $wgProfileWorkStack;
+               $bit = array_pop( $wgProfileWorkStack );
+               $bit .= " " . microtime();
+               array_push( $wgProfileStack, $bit );
+       }
+} else {
+       function wfProfileIn( $functionname ) { }
+       function wfProfileOut( ) { }
+}
+
+function wfReadOnly()
+{
+       global $wgReadOnlyFile;
+
+       if ( "" == $wgReadOnlyFile ) { return false; }
+       return is_file( $wgReadOnlyFile );
+}
+
+$wgReplacementKeys = array( "$1", "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9" );
+function wfMsg( $key )
+{
+       global $wgLang, $wgReplacementKeys;
+       $ret = $wgLang->getMessage( $key );
+       
+       if( func_num_args() > 1 ) {
+               $reps = func_get_args();
+               array_shift( $reps );
+               $ret = str_replace( $wgReplacementKeys, $reps, $ret );
+       }
+
+       if ( "" == $ret ) {
+               user_error( "Couldn't find text for message \"{$key}\"." );
+       }
+       return $ret;
+}
+
+function wfCleanFormFields( $fields )
+{
+       global $HTTP_POST_VARS;
+       global $wgInputEncoding, $wgOutputEncoding, $wgEditEncoding, $wgLang;
+
+       if ( get_magic_quotes_gpc() ) {
+               foreach ( $fields as $fname ) {
+                       if ( isset( $HTTP_POST_VARS[$fname] ) ) {
+                               $HTTP_POST_VARS[$fname] = stripslashes(
+                                 $HTTP_POST_VARS[$fname] );
+                       }
+                       global ${$fname};
+                       if ( isset( ${$fname} ) ) {
+                               ${$fname} = stripslashes( ${$fname} );
+                       }
+               }
+       }
+       $enc = $wgOutputEncoding;
+       if( $wgEditEncoding != "") $enc = $wgEditEncoding;
+       if ( $enc != $wgInputEncoding ) {
+               foreach ( $fields as $fname ) {
+                       if ( isset( $HTTP_POST_VARS[$fname] ) ) {
+                               $HTTP_POST_VARS[$fname] = $wgLang->iconv(
+                                 $wgOutputEncoding, $wgInputEncoding,
+                                 $HTTP_POST_VARS[$fname] );
+                       }
+                       global ${$fname};
+                       if ( isset( ${$fname} ) ) {
+                               ${$fname} = $wgLang->iconv(
+                                 $enc, $wgInputEncoding, ${$fname} );
+                       }
+               }
+       }
+}
+
+function wfMungeQuotes( $in )
+{
+       $out = str_replace( "%", "%25", $in );
+       $out = str_replace( "'", "%27", $out );
+       $out = str_replace( "\"", "%22", $out );
+       return $out;
+}
+
+function wfDemungeQuotes( $in )
+{
+       $out = str_replace( "%22", "\"", $in );
+       $out = str_replace( "%27", "'", $out );
+       $out = str_replace( "%25", "%", $out );
+       return $out;
+}
+
+function wfCleanQueryVar( $var )
+{
+       global $wgLang;
+       if ( get_magic_quotes_gpc() ) {
+               $var = stripslashes( $var );
+       }
+       return $wgLang->recodeInput( $var );
+}
+
+function wfSpecialPage()
+{
+       global $wgUser, $wgOut, $wgTitle, $wgLang;
+
+       $validSP = $wgLang->getValidSpecialPages();
+       $sysopSP = $wgLang->getSysopSpecialPages();
+       $devSP = $wgLang->getDeveloperSpecialPages();
+
+       $wgOut->setArticleFlag( false );
+       $wgOut->setRobotpolicy( "noindex,follow" );
+
+       $t = $wgTitle->getDBkey();
+       if ( array_key_exists( $t, $validSP ) ||
+         ( $wgUser->isSysop() && array_key_exists( $t, $sysopSP ) ) ||
+         ( $wgUser->isDeveloper() && array_key_exists( $t, $devSP ) ) ) {
+               $wgOut->setPageTitle( wfMsg( strtolower( $wgTitle->getText() ) ) );
+
+               $inc = "Special" . $t . ".php";
+               include_once( $inc );
+               $call = "wfSpecial" . $t;
+               $call();
+       } else if ( array_key_exists( $t, $sysopSP ) ) {
+               $wgOut->sysopRequired();
+       } else if ( array_key_exists( $t, $devSP ) ) {
+               $wgOut->developerRequired();
+       } else {
+               $wgOut->errorpage( "nosuchspecialpage", "nospecialpagetext" );
+       }
+}
+
+function wfSearch( $s )
+{
+       $se = new SearchEngine( wfCleanQueryVar( $s ) );
+       $se->showResults();
+}
+
+function wfGo( $s )
+{ # pick the nearest match
+       $se = new SearchEngine( wfCleanQueryVar( $s ) );
+       $se->goResult();
+}
+
+function wfNumberOfArticles()
+{
+       global $wgNumberOfArticles;
+
+       wfLoadSiteStats();
+       return $wgNumberOfArticles;
+}
+
+/* private */ function wfLoadSiteStats()
+{
+       global $wgNumberOfArticles, $wgTotalViews, $wgTotalEdits;
+       if ( -1 != $wgNumberOfArticles ) return;
+
+       $sql = "SELECT ss_total_views, ss_total_edits, ss_good_articles " .
+         "FROM site_stats WHERE ss_row_id=1";
+       $res = wfQuery( $sql, "wfLoadSiteStats" );
+
+       if ( 0 == wfNumRows( $res ) ) { return; }
+       else {
+               $s = wfFetchObject( $res );
+               $wgTotalViews = $s->ss_total_views;
+               $wgTotalEdits = $s->ss_total_edits;
+               $wgNumberOfArticles = $s->ss_good_articles;
+       }
+}
+
+function wfEscapeHTML( $in )
+{
+       return str_replace(
+               array( "&", "\"", ">", "<" ),
+               array( "&amp;", "&quot;", "&gt;", "&lt;" ),
+               $in );
+}
+
+function wfEscapeHTMLTagsOnly( $in ) {
+       return str_replace(
+               array( "\"", ">", "<" ),
+               array( "&quot;", "&gt;", "&lt;" ),
+               $in );
+}
+
+function wfUnescapeHTML( $in )
+{
+       $in = str_replace( "&lt;", "<", $in );
+       $in = str_replace( "&gt;", ">", $in );
+       $in = str_replace( "&quot;", "\"", $in );
+       $in = str_replace( "&amp;", "&", $in );
+       return $in;
+}
+
+function wfImageDir( $fname )
+{
+       global $wgUploadDirectory;
+
+       $hash = md5( $fname );
+       $oldumask = umask(0);
+       $dest = $wgUploadDirectory . "/" . $hash{0};
+       if ( ! is_dir( $dest ) ) { mkdir( $dest, 0777 ); }
+       $dest .= "/" . substr( $hash, 0, 2 );
+       if ( ! is_dir( $dest ) ) { mkdir( $dest, 0777 ); }
+       
+       umask( $oldumask );
+       return $dest;
+}
+
+function wfImageArchiveDir( $fname )
+{
+       global $wgUploadDirectory;
+
+       $hash = md5( $fname );
+       $oldumask = umask(0);
+       $archive = "{$wgUploadDirectory}/archive";
+       if ( ! is_dir( $archive ) ) { mkdir( $archive, 0777 ); }
+       $archive .= "/" . $hash{0};
+       if ( ! is_dir( $archive ) ) { mkdir( $archive, 0777 ); }
+       $archive .= "/" . substr( $hash, 0, 2 );
+       if ( ! is_dir( $archive ) ) { mkdir( $archive, 0777 ); }
+
+       umask( $oldumask );
+       return $archive;
+}
+
+function wfRecordUpload( $name, $oldver, $size, $desc )
+{
+       global $wgUser, $wgLang, $wgTitle, $wgOut, $wgDeferredUpdateList;
+       $fname = "wfRecordUpload";
+
+       $sql = "SELECT img_name,img_size,img_timestamp,img_description,img_user," .
+         "img_user_text FROM image WHERE img_name='" . wfStrencode( $name ) . "'";
+       $res = wfQuery( $sql, $fname );
+
+       if ( 0 == wfNumRows( $res ) ) {
+               $sql = "INSERT INTO image (img_name,img_size,img_timestamp," .
+                 "img_description,img_user,img_user_text) VALUES ('" .
+                 wfStrencode( $name ) . "',{$size},'" . date( "YmdHis" ) . "','" .
+                 wfStrencode( $desc ) . "', '" . $wgUser->getID() .
+                 "', '" . wfStrencode( $wgUser->getName() ) . "')";
+               wfQuery( $sql, $fname );
+
+               $sql = "SELECT cur_id,cur_text FROM cur WHERE cur_namespace=" .
+                 Namespace::getImage() . " AND cur_title='" .
+                 wfStrencode( $name ) . "'";
+               $res = wfQuery( $sql, $fname );
+               if ( 0 == wfNumRows( $res ) ) {
+                       $now = wfTimestampNow();
+                       $won = wfInvertTimestamp( $now );
+            $common =
+                         Namespace::getImage() . ",'" .
+                         wfStrencode( $name ) . "','" .
+                         wfStrencode( $desc ) . "','" . $wgUser->getID() . "','" .
+                         wfStrencode( $wgUser->getName() ) . "','" . $now .
+                         "',1";
+                       $sql = "INSERT INTO cur (cur_namespace,cur_title," .
+                         "cur_comment,cur_user,cur_user_text,cur_timestamp,cur_is_new," .
+                         "cur_text,inverse_timestamp) VALUES (" .
+                         $common .
+                         ",'" . wfStrencode( $desc ) . "','{$won}')";
+                       wfQuery( $sql, $fname );
+                       $id = wfInsertId() or 0; # We should throw an error instead
+                       $sql = "INSERT INTO recentchanges (rc_namespace,rc_title,
+                               rc_comment,rc_user,rc_user_text,rc_timestamp,rc_new,
+                               rc_cur_id,rc_cur_time) VALUES ({$common},{$id},'{$now}')";
+            wfQuery( $sql, $fname );
+                       $u = new SearchUpdate( $id, $name, $desc );
+                       $u->doUpdate();
+               }
+       } else {
+               $s = wfFetchObject( $res );
+
+               $sql = "INSERT INTO oldimage (oi_name,oi_archive_name,oi_size," .
+                 "oi_timestamp,oi_description,oi_user,oi_user_text) VALUES ('" .
+                 wfStrencode( $s->img_name ) . "','" .
+                 wfStrencode( $oldver ) .
+                 "',{$s->img_size},'{$s->img_timestamp}','" .
+                 wfStrencode( $s->img_description ) . "','" .
+                 wfStrencode( $s->img_user ) . "','" .
+                 wfStrencode( $s->img_user_text) . "')";
+               wfQuery( $sql, $fname );
+
+               $sql = "UPDATE image SET img_size={$size}," .
+                 "img_timestamp='" . date( "YmdHis" ) . "',img_user='" .
+                 $wgUser->getID() . "',img_user_text='" .
+                 wfStrencode( $wgUser->getName() ) . "', img_description='" .
+                 wfStrencode( $desc ) . "' WHERE img_name='" .
+                 wfStrencode( $name ) . "'";
+               wfQuery( $sql, $fname );
+       }
+
+       $log = new LogPage( wfMsg( "uploadlogpage" ), wfMsg( "uploadlogpagetext" ) );
+       $da = str_replace( "$1", "[[:" . $wgLang->getNsText(
+         Namespace::getImage() ) . ":{$name}|{$name}]]",
+         wfMsg( "uploadedimage" ) );
+       $ta = str_replace( "$1", $name, wfMsg( "uploadedimage" ) );
+       $log->addEntry( $da, $desc, $ta );
+}
+
+
+/* Some generic result counters, pulled out of SearchEngine */
+
+function wfShowingResults( $offset, $limit )
+{
+       $top = str_replace( "$1", $limit, wfMsg( "showingresults" ) );
+       $top = str_replace( "$2", $offset+1, $top );
+       return $top;
+}
+
+function wfViewPrevNext( $offset, $limit, $link, $query = "" )
+{
+       global $wgUser;
+       $prev = str_replace( "$1", $limit, wfMsg( "prevn" ) );
+       $next = str_replace( "$1", $limit, wfMsg( "nextn" ) );
+
+       $sk = $wgUser->getSkin();
+       if ( 0 != $offset ) {
+               $po = $offset - $limit;
+               if ( $po < 0 ) { $po = 0; }
+               $q = "limit={$limit}&offset={$po}";
+               if ( "" != $query ) { $q .= "&{$query}"; }
+               $plink = "<a href=\"" . wfLocalUrlE( $link, $q ) . "\">{$prev}</a>";
+       } else { $plink = $prev; }
+
+       $no = $offset + $limit;
+       $q = "limit={$limit}&offset={$no}";
+       if ( "" != $query ) { $q .= "&{$query}"; }
+
+       $nlink = "<a href=\"" . wfLocalUrlE( $link, $q ) . "\">{$next}</a>";
+       $nums = wfNumLink( $offset, 20, $link , $query ) . " | " .
+         wfNumLink( $offset, 50, $link, $query ) . " | " .
+         wfNumLink( $offset, 100, $link, $query ) . " | " .
+         wfNumLink( $offset, 250, $link, $query ) . " | " .
+         wfNumLink( $offset, 500, $link, $query );
+
+       $sl = str_replace( "$1", $plink, wfMsg( "viewprevnext" ) );
+       $sl = str_replace( "$2", $nlink, $sl );
+       $sl = str_replace( "$3", $nums, $sl );
+       return $sl;
+}
+
+function wfNumLink( $offset, $limit, $link, $query = "" )
+{
+       global $wgUser;
+       if ( "" == $query ) { $q = ""; }
+       else { $q = "{$query}&"; }
+       $q .= "limit={$limit}&offset={$offset}";
+
+       $s = "<a href=\"" . wfLocalUrlE( $link, $q ) . "\">{$limit}</a>";
+       return $s;
+}
+
+?>
diff --git a/includes/Interwiki.php b/includes/Interwiki.php
new file mode 100644 (file)
index 0000000..417159e
--- /dev/null
@@ -0,0 +1,256 @@
+<?
+# Note -- this file is generated by maintenance/fetchInterwiki.pl
+# Edit and rerun that script rather than modifying this directly.
+
+/* private */ $wgValidInterwikis = array(
+       # General interwiki links from the InterMap
+       "AbbeNormal" => "http://www.ourpla.net/cgi-bin/pikie.cgi?$1",
+       "AcadWiki" => "http://xarch.tu-graz.ac.at/autocad/wiki/$1",
+       "Acronym" => "http://www.acronymfinder.com/af-query.asp?String=exact&Acronym=$1",
+       "Advogato" => "http://www.advogato.org/$1",
+       "AIWiki" => "http://www.ifi.unizh.ch/ailab/aiwiki/aiw.cgi?$1",
+       "ALife" => "http://news.alife.org/wiki/index.php?$1",
+       "AndStuff" => "http://andstuff.org/wiki.php?$1",
+       "Annotation" => "http://bayle.stanford.edu/crit/nph-med.cgi/$1",
+       "AnnotationWiki" => "http://www.seedwiki.com/page.cfm?wikiid=368&doc=$1",
+       "AwarenessWiki" => "http://taoriver.net/aware/$1",
+       "BenefitsWiki" => "http://www.benefitslink.com/cgi-bin/wiki.cgi?$1",
+       "BridgesWiki" => "http://c2.com/w2/bridges/$1",
+       "C2find" => "http://c2.com/cgi/wiki?FindPage&value=$1",
+       "Cache" => "http://www.google.com/search?q=cache:$1",
+       "CLiki" => "http://ww.telent.net/cliki/$1",
+       "CmWiki" => "http://www.ourpla.net/cgi-bin/wiki.pl?$1",
+       "CreationMatters" => "http://www.ourpla.net/cgi-bin/wiki.pl?$1",
+       "DejaNews" => "http://www.deja.com/=dnc/getdoc.xp?AN=$1",
+       "DeWikiPedia" => "http://www.wikipedia.de/wiki.cgi?$1",
+       "Dictionary" => "http://www.dict.org/bin/Dict?Database=*&Form=Dict1&Strategy=*&Query=$1",
+       "DiveIntoOsx" => "http://diveintoosx.org/$1",
+       "DocBook" => "http://docbook.org/wiki/moin.cgi/$1",
+       "DolphinWiki" => "http://www.object-arts.com/wiki/html/Dolphin/$1",
+       "EfnetCeeWiki" => "http://purl.net/wiki/c/$1",
+       "EfnetCppWiki" => "http://purl.net/wiki/cpp/$1",
+       "EfnetPythonWiki" => "http://purl.net/wiki/python/$1",
+       "EfnetXmlWiki" => "http://purl.net/wiki/xml/$1",
+       "EljWiki" => "http://elj.sourceforge.net/phpwiki/index.php/$1",
+       "EmacsWiki" => "http://www.emacswiki.org/cgi-bin/wiki.pl?$1",
+       "FinalEmpire" => "http://final-empire.sourceforge.net/cgi-bin/wiki.pl?$1",
+       "Foldoc" => "http://www.foldoc.org/foldoc/foldoc.cgi?$1",
+       "FoxWiki" => "http://fox.wikis.com/wc.dll?Wiki~$1",
+       "FreeBSDman" => "http://www.FreeBSD.org/cgi/man.cgi?apropos=1&query=$1",
+       "Google" => "http://www.google.com/search?q=$1",
+       "GoogleGroups" => "http://groups.google.com/groups?q=$1",
+       "GreenCheese" => "http://www.greencheese.org/$1",
+       "HammondWiki" => "http://www.dairiki.org/HammondWiki/index.php3?$1",
+       "Haribeau" => "http://wiki.haribeau.de/cgi-bin/wiki.pl?$1",
+       "IAWiki" => "http://www.IAwiki.net/$1",
+       "IMDB" => "http://us.imdb.com/Title?$1",
+       "JargonFile" => "http://sunir.org/apps/meta.pl?wiki=JargonFile&redirect=$1",
+       "JiniWiki" => "http://www.cdegroot.com/cgi-bin/jini?$1",
+       "JspWiki" => "http://www.ecyrd.com/JSPWiki/Wiki.jsp?page=$1",
+       "KmWiki" => "http://www.voght.com/cgi-bin/pywiki?$1",
+       "KnowHow" => "http://www2.iro.umontreal.ca/~paquetse/cgi-bin/wiki.cgi?$1",
+       "LanifexWiki" => "http://opt.lanifex.com/cgi-bin/wiki.pl?$1",
+       "LegoWiki" => "http://www.object-arts.com/wiki/html/Lego-Robotics/$1",
+       "LinuxWiki" => "http://www.linuxwiki.de/$1",
+       "LugKR" => "http://lug-kr.sourceforge.net/cgi-bin/lugwiki.pl?$1",
+       "MathSongsWiki" => "http://SeedWiki.com/page.cfm?wikiid=237&doc=$1",
+       "MbTest" => "http://www.usemod.com/cgi-bin/mbtest.pl?$1",
+       "MeatBall" => "http://www.usemod.com/cgi-bin/mb.pl?$1",
+       "MetaWiki" => "http://sunir.org/apps/meta.pl?$1",
+       "MetaWikiPedia" => "http://meta.wikipedia.com/wiki/$1",
+       "MoinMoin" => "http://purl.net/wiki/moin/$1",
+       "MuWeb" => "http://www.dunstable.com/scripts/MuWebWeb?$1",
+       "NetVillage" => "http://www.netbros.com/?$1",
+       "OpenWiki" => "http://openwiki.com/?$1",
+       "OrgPatterns" => "http://www.bell-labs.com/cgi-user/OrgPatterns/OrgPatterns?$1",
+       "PangalacticOrg" => "http://www.pangalactic.org/Wiki/$1",
+       "PersonalTelco" => "http://www.personaltelco.net/index.cgi/$1",
+       "PhpWiki" => "http://phpwiki.sourceforge.net/phpwiki/index.php?$1",
+       "Pikie" => "http://pikie.darktech.org/cgi/pikie?$1",
+       "PPR" => "http://c2.com/cgi/wiki?$1",
+       "PurlNet" => "http://purl.oclc.org/NET/$1",
+       "PythonInfo" => "http://www.python.org/cgi-bin/moinmoin/$1",
+       "PythonWiki" => "http://www.pythonwiki.de/$1",
+       "PyWiki" => "http://www.voght.com/cgi-bin/pywiki?$1",
+       "SeaPig" => "http://www.seapig.org/ $1",
+       "SeattleWireless" => "http://seattlewireless.net/?$1",
+       "SenseisLibrary" => "http://senseis.xmp.net/?$1",
+       "Shakti" => "http://cgi.algonet.se/htbin/cgiwrap/pgd/ShaktiWiki/$1",
+       "SourceForge" => "http://sourceforge.net/$1",
+       "Squeak" => "http://minnow.cc.gatech.edu/squeak/$1",
+       "StrikiWiki" => "http://ch.twi.tudelft.nl/~mostert/striki/teststriki.pl?$1",
+       "SVGWiki" => "http://www.protocol7.com/svg-wiki/default.asp?$1",
+       "Tavi" => "http://tavi.sourceforge.net/index.php?$1",
+       "TmNet" => "http://www.technomanifestos.net/?$1",
+       "TMwiki" => "http://www.EasyTopicMaps.com/?page=$1",
+       "TWiki" => "http://twiki.org/cgi-bin/view/$1",
+       "TwistedWiki" => "http://purl.net/wiki/twisted/$1",
+       "Unreal" => "http://wiki.beyondunreal.com/wiki/$1",
+       "UseMod" => "http://www.usemod.com/cgi-bin/wiki.pl?$1",
+       "VisualWorks" => "http://wiki.cs.uiuc.edu/VisualWorks/$1",
+       "WebDevWikiNL" => "http://www.promo-it.nl/WebDevWiki/index.php?page=$1",
+       "WebSeitzWiki" => "http://webseitz.fluxent.com/wiki/$1",
+       "Why" => "http://clublet.com/c/c/why?$1",
+       "Wiki" => "http://c2.com/cgi/wiki?$1",
+       "WikiPedia" => "http://www.wikipedia.com/wiki/$1",
+       "WikiWorld" => "http://WikiWorld.com/wiki/index.php/$1",
+       "YpsiEyeball" => "http://sknkwrks.dyndns.org:1957/writewiki/wiki.pl?$1",
+       "ZWiki" => "http://www.zwiki.org/$1",
+
+       # Some custom additions:
+       "ReVo"  =>      "http://purl.org/NET/voko/revo/art/$1.html",
+         # eg [[ReVo:cerami]], [[ReVo:astero]] - note X-sensitive!
+       "EcheI" =>      "http://www.ikso.net/cgi-bin/wiki.pl?$1",
+       "E\xc4\x89eI" =>        "http://www.ikso.net/cgi-bin/wiki.pl?$1",
+       "UnuMondo"      =>      "http://unumondo.com/cgi-bin/wiki.pl?$1", # X-sensitive!
+       "JEFO"  =>      "http://esperanto.jeunes.free.fr/vikio/index.php?$1",
+       "PMEG"  =>      "http://www.bertilow.com/pmeg/$1.php",
+               # ekz [[PMEG:gramatiko/kunligaj vortetoj/au]]
+       "EnciclopediaLibre" => "http://enciclopedia.us.es/wiki.phtml?title=$1",
+
+       # Wikipedia-specific stuff:
+       # Special cases
+       "w"             => "http://www.wikipedia.org/wiki/$1",
+       "m"             => "http://meta.wikipedia.org/wiki/$1",
+       "meta"          => "http://meta.wikipedia.org/wiki/$1",
+       "sep11"         => "http://sep11.wikipedia.org/wiki/$1",
+       "simple"=> "http://simple.wikipedia.com/wiki.cgi?$1",
+       "wiktionary"    => "http://wiktionary.wikipedia.org/wiki/$1",
+
+       # ISO 639 2-letter language codes
+       "aa"    => "http://aa.wikipedia.com/wiki.cgi?$1",
+       "ab"    => "http://ab.wikipedia.com/wiki.cgi?$1",
+       "af"    => "http://af.wikipedia.com/wiki.cgi?$1",
+       "am"    => "http://am.wikipedia.com/wiki.cgi?$1",
+       "ar"    => "http://ar.wikipedia.com/wiki.cgi?$1",
+       "as"    => "http://as.wikipedia.com/wiki.cgi?$1",
+       "ay"    => "http://ay.wikipedia.com/wiki.cgi?$1",
+       "az"    => "http://az.wikipedia.com/wiki.cgi?$1",
+       "ba"    => "http://ba.wikipedia.com/wiki.cgi?$1",
+       "be"    => "http://be.wikipedia.com/wiki.cgi?$1",
+       "bh"    => "http://bh.wikipedia.com/wiki.cgi?$1",
+       "bi"    => "http://bi.wikipedia.com/wiki.cgi?$1",
+       "bn"    => "http://bn.wikipedia.com/wiki.cgi?$1",
+       "bs"    => "http://bs.wikipedia.org/wiki/$1",
+       "bo"    => "http://bo.wikipedia.com/wiki.cgi?$1",
+       "ca"    => "http://ca.wikipedia.com/wiki.cgi?$1",
+       "co"    => "http://co.wikipedia.com/wiki.cgi?$1",
+       "cs"    => "http://cs.wikipedia.org/wiki/$1",
+       "cy"    => "http://cy.wikipedia.com/wiki.cgi?$1",
+       "da"    => "http://da.wikipedia.org/wiki/$1",
+       "de"    => "http://de.wikipedia.org/wiki/$1",
+       "dk"    => "http://da.wikipedia.org/wiki/$1",
+       "dz"    => "http://dz.wikipedia.com/wiki.cgi?$1",
+       "el"    => "http://el.wikipedia.org/wiki/$1",
+       "en"    => "http://www.wikipedia.org/wiki/$1",    # May in future be renamed to en.wikipedia.org; should work as alternate
+       "eo"    => "http://eo.wikipedia.org/wiki/$1",
+       "es"    => "http://es.wikipedia.org/wiki/$1",
+       "et"    => "http://et.wikipedia.com/wiki.cgi?$1",
+       "eu"    => "http://eu.wikipedia.com/wiki.cgi?$1",
+       "fa"    => "http://fa.wikipedia.com/wiki.cgi?$1",
+       "fi"    => "http://fi.wikipedia.com/wiki.cgi?$1",
+       "fj"    => "http://fj.wikipedia.com/wiki.cgi?$1",
+       "fo"    => "http://fo.wikipedia.com/wiki.cgi?$1",
+       "fr"    => "http://fr.wikipedia.org/wiki/$1",
+       "fy"    => "http://fy.wikipedia.com/wiki.cgi?$1",
+       "ga"    => "http://ga.wikipedia.com/wiki.cgi?$1",
+       "gl"    => "http://gl.wikipedia.com/wiki.cgi?$1",
+       "gn"    => "http://gn.wikipedia.com/wiki.cgi?$1",
+       "gu"    => "http://gu.wikipedia.com/wiki.cgi?$1",
+       "ha"    => "http://ha.wikipedia.com/wiki.cgi?$1",
+       "he"    => "http://he.wikipedia.com/wiki.cgi?$1",
+       "hi"    => "http://hi.wikipedia.com/wiki.cgi?$1",
+       "hr"    => "http://hr.wikipedia.org/wiki/$1",
+       "hu"    => "http://hu.wikipedia.com/wiki.cgi?$1",
+       "hy"    => "http://hy.wikipedia.com/wiki.cgi?$1",
+       "ia"    => "http://ia.wikipedia.com/wiki.cgi?$1",
+       "id"    => "http://id.wikipedia.com/wiki.cgi?$1",
+       "ik"    => "http://ik.wikipedia.com/wiki.cgi?$1",
+       "is"    => "http://is.wikipedia.com/wiki.cgi?$1",
+       "it"    => "http://it.wikipedia.com/wiki.cgi?$1",
+       "iu"    => "http://iu.wikipedia.com/wiki.cgi?$1",
+       "ja"    => "http://ja.wikipedia.org/wiki/$1",
+       "jv"    => "http://jv.wikipedia.com/wiki.cgi?$1",
+       "ka"    => "http://ka.wikipedia.com/wiki.cgi?$1",
+       "kk"    => "http://kk.wikipedia.com/wiki.cgi?$1",
+       "kl"    => "http://kl.wikipedia.com/wiki.cgi?$1",
+       "km"    => "http://km.wikipedia.com/wiki.cgi?$1",
+       "kn"    => "http://kn.wikipedia.com/wiki.cgi?$1",
+       "ko"    => "http://ko.wikipedia.org/wiki/$1",
+       "ks"    => "http://ks.wikipedia.com/wiki.cgi?$1",
+       "ku"    => "http://ku.wikipedia.com/wiki.cgi?$1",
+       "ky"    => "http://ky.wikipedia.com/wiki.cgi?$1",
+       "la"    => "http://la.wikipedia.com/wiki.cgi?$1",
+       "lo"    => "http://lo.wikipedia.com/wiki.cgi?$1",
+       "lv"    => "http://lv.wikipedia.com/wiki.cgi?$1",
+       "mg"    => "http://mg.wikipedia.com/wiki.cgi?$1",
+       "mi"    => "http://mi.wikipedia.com/wiki.cgi?$1",
+       "mk"    => "http://mk.wikipedia.com/wiki.cgi?$1",
+       "ml"    => "http://ml.wikipedia.org/wiki/$1",
+       "mn"    => "http://mn.wikipedia.com/wiki.cgi?$1",
+       "mo"    => "http://mo.wikipedia.com/wiki.cgi?$1",
+       "mr"    => "http://mr.wikipedia.com/wiki.cgi?$1",
+       "ms"    => "http://ms.wikipedia.org/wiki/$1",
+       "my"    => "http://my.wikipedia.com/wiki.cgi?$1",
+       "na"    => "http://na.wikipedia.com/wiki.cgi?$1",
+       "ne"    => "http://ne.wikipedia.com/wiki.cgi?$1",
+       "nl"    => "http://nl.wikipedia.org/wiki/$1",
+       "no"    => "http://no.wikipedia.com/wiki.cgi?$1",
+       "oc"    => "http://oc.wikipedia.com/wiki.cgi?$1",
+       "om"    => "http://om.wikipedia.com/wiki.cgi?$1",
+       "or"    => "http://or.wikipedia.com/wiki.cgi?$1",
+       "pa"    => "http://pa.wikipedia.com/wiki.cgi?$1",
+       "pl"    => "http://pl.wikipedia.org/wiki/$1",
+       "ps"    => "http://ps.wikipedia.com/wiki.cgi?$1",
+       "pt"    => "http://pt.wikipedia.com/wiki.cgi?$1",
+       "qu"    => "http://qu.wikipedia.com/wiki.cgi?$1",
+       "rm"    => "http://rm.wikipedia.com/wiki.cgi?$1",
+       "rn"    => "http://rn.wikipedia.com/wiki.cgi?$1",
+       "ro"    => "http://ro.wikipedia.com/wiki.cgi?$1",
+       "ru"    => "http://ru.wikipedia.org/wiki/$1",
+       "rw"    => "http://rw.wikipedia.com/wiki.cgi?$1",
+       "sa"    => "http://sa.wikipedia.com/wiki.cgi?$1",
+       "sd"    => "http://sd.wikipedia.com/wiki.cgi?$1",
+       "sg"    => "http://sg.wikipedia.com/wiki.cgi?$1",
+       "sh"    => "http://sh.wikipedia.org/wiki/$1",
+       "si"    => "http://si.wikipedia.com/wiki.cgi?$1",
+       "sk"    => "http://sk.wikipedia.com/wiki.cgi?$1",
+       "sl"    => "http://sl.wikipedia.com/wiki.cgi?$1",
+       "sm"    => "http://sm.wikipedia.com/wiki.cgi?$1",
+       "sn"    => "http://sn.wikipedia.com/wiki.cgi?$1",
+       "so"    => "http://so.wikipedia.com/wiki.cgi?$1",
+       "sq"    => "http://sq.wikipedia.com/wiki.cgi?$1",
+       "sr"    => "http://sr.wikipedia.org/wiki/$1",
+       "ss"    => "http://ss.wikipedia.com/wiki.cgi?$1",
+       "st"    => "http://st.wikipedia.com/wiki.cgi?$1",
+       "su"    => "http://su.wikipedia.com/wiki.cgi?$1",
+       "sv"    => "http://sv.wikipedia.org/wiki/$1",
+       "sw"    => "http://sw.wikipedia.com/wiki.cgi?$1",
+       "ta"    => "http://ta.wikipedia.com/wiki.cgi?$1",
+       "te"    => "http://te.wikipedia.com/wiki.cgi?$1",
+       "tg"    => "http://tg.wikipedia.com/wiki.cgi?$1",
+       "th"    => "http://th.wikipedia.com/wiki.cgi?$1",
+       "ti"    => "http://ti.wikipedia.com/wiki.cgi?$1",
+       "tk"    => "http://tk.wikipedia.com/wiki.cgi?$1",
+       "tl"    => "http://tl.wikipedia.com/wiki.cgi?$1",
+       "tn"    => "http://tn.wikipedia.com/wiki.cgi?$1",
+       "to"    => "http://to.wikipedia.com/wiki.cgi?$1",
+       "tr"    => "http://tr.wikipedia.org/wiki/$1",
+       "ts"    => "http://ts.wikipedia.com/wiki.cgi?$1",
+       "tt"    => "http://tt.wikipedia.com/wiki.cgi?$1",
+       "tw"    => "http://tw.wikipedia.com/wiki.cgi?$1",
+       "ug"    => "http://ug.wikipedia.com/wiki.cgi?$1",
+       "uk"    => "http://uk.wikipedia.com/wiki.cgi?$1",
+       "ur"    => "http://ur.wikipedia.com/wiki.cgi?$1",
+       "uz"    => "http://uz.wikipedia.com/wiki.cgi?$1",
+       "vi"    => "http://vi.wikipedia.com/wiki.cgi?$1",
+       "vo"    => "http://vo.wikipedia.com/wiki.cgi?$1",
+       "wo"    => "http://wo.wikipedia.com/wiki.cgi?$1",
+       "xh"    => "http://xh.wikipedia.com/wiki.cgi?$1",
+       "yi"    => "http://yi.wikipedia.com/wiki.cgi?$1",
+       "yo"    => "http://yo.wikipedia.com/wiki.cgi?$1",
+       "za"    => "http://za.wikipedia.com/wiki.cgi?$1",
+       "zh"    => "http://zh.wikipedia.org/wiki/$1",
+       "zu"    => "http://zu.wikipedia.com/wiki.cgi?$1"
+);
+?>
diff --git a/includes/LinkCache.php b/includes/LinkCache.php
new file mode 100644 (file)
index 0000000..af85052
--- /dev/null
@@ -0,0 +1,109 @@
+<?
+# Cache for article titles and ids linked from one source
+
+class LinkCache {
+
+       /* private */ var $mGoodLinks, $mBadLinks, $mActive;
+       /* private */ var $mImageLinks;
+
+       function LinkCache()
+       {
+               $this->mActive = true;
+               $this->mGoodLinks = array();
+               $this->mBadLinks = array();
+               $this->mImageLinks = array();
+       }
+
+       function getGoodLinkID( $title )
+       {
+               if ( array_key_exists( $title, $this->mGoodLinks ) ) {
+                       return $this->mGoodLinks[$title];
+               } else {
+                       return 0;
+               }
+       }
+
+       function isBadLink( $title )
+       {
+               return in_array( $title, $this->mBadLinks );
+       }
+
+       function addGoodLink( $id, $title )
+       {
+               if ( $this->mActive ) {
+                       $this->mGoodLinks[$title] = $id;
+               }
+       }
+
+       function addBadLink( $title )
+       {
+               if ( $this->mActive && ( ! $this->isBadLink( $title ) ) ) {
+                       array_push( $this->mBadLinks, $title );
+               }
+       }
+
+       function addImageLink( $title )
+       {
+               if ( $this->mActive ) { $this->mImageLinks[$title] = 1; }
+       }
+
+       function clearBadLink( $title )
+       {
+               $index = array_search( $title, $this->mBadLinks );
+               if ( isset( $index ) ) {
+                       unset( $this->mBadLinks[$index] );
+               }
+       }
+
+       function suspend() { $this->mActive = false; }
+       function resume() { $this->mActive = true; }
+       function getGoodLinks() { return $this->mGoodLinks; }
+       function getBadLinks() { return $this->mBadLinks; }
+       function getImageLinks() { return $this->mImageLinks; }
+
+       function addLink( $title )
+       {
+               if ( $this->isBadLink( $title ) ) { return 0; }
+               $id = $this->getGoodLinkID( $title );
+               if ( 0 != $id ) { return $id; }
+
+               $nt = Title::newFromDBkey( $title );
+               $ns = $nt->getNamespace();
+               $t = $nt->getDBkey();
+
+               if ( "" == $t ) { return 0; }
+               $sql = "SELECT HIGH_PRIORITY cur_id FROM cur WHERE cur_namespace=" .
+                 "{$ns} AND cur_title='" . wfStrencode( $t ) . "'";
+               $res = wfQuery( $sql, "LinkCache::addLink" );
+
+               if ( 0 == wfNumRows( $res ) ) {
+                       $id = 0;
+               } else {
+                       $s = wfFetchObject( $res );
+                       $id = $s->cur_id;
+               }
+               if ( 0 == $id ) { $this->addBadLink( $title ); }
+               else { $this->addGoodLink( $id, $title ); }
+               return $id;
+       }
+
+       function preFill( $fromtitle )
+       {
+               wfProfileIn( "LinkCache::preFill" );
+               # Note -- $fromtitle is a Title *object*
+               $dbkeyfrom = wfStrencode( $fromtitle->getPrefixedDBKey() );
+               $sql = "SELECT HIGH_PRIORITY cur_id,cur_namespace,cur_title
+                       FROM cur,links
+                       WHERE cur_id=l_to AND l_from='{$dbkeyfrom}'";
+               $res = wfQuery( $sql, "LinkCache::preFill" );
+               while( $s = wfFetchObject( $res ) ) {
+                       $this->addGoodLink( $s->cur_id,
+                               Title::makeName( $s->cur_namespace, $s->cur_title )
+                               );
+               }
+               wfProfileOut();
+       }
+
+}
+
+?>
diff --git a/includes/LinksUpdate.php b/includes/LinksUpdate.php
new file mode 100644 (file)
index 0000000..bf181ad
--- /dev/null
@@ -0,0 +1,110 @@
+<?
+# See deferred.doc
+
+class LinksUpdate {
+
+       /* private */ var $mId, $mTitle;
+
+       function LinksUpdate( $id, $title )
+       {
+               $this->mId = $id;
+               $this->mTitle = $title;
+       }
+
+       function doUpdate()
+       {
+               global $wgLinkCache, $wgDBtransactions;
+               $fname = "LinksUpdate::doUpdate";
+               wfProfileIn( $fname );
+               $t = wfStrencode( $this->mTitle );
+
+               if( $wgDBtransactions ) {
+                       $sql = "BEGIN";
+                       wfQuery( $sql, $fname );
+               }
+               
+               $sql = "DELETE FROM links WHERE l_from='{$t}'";
+               wfQuery( $sql, $fname );
+
+               $a = $wgLinkCache->getGoodLinks();
+               $sql = "";
+               if ( 0 != count( $a ) ) {
+                       $sql = "INSERT INTO links (l_from,l_to) VALUES ";
+                       $first = true;
+                       foreach( $a as $lt => $lid ) {
+                               if ( ! $first ) { $sql .= ","; }
+                               $first = false;
+
+                               $sql .= "('{$t}',{$lid})";
+                       }
+               }
+               if ( "" != $sql ) { wfQuery( $sql, $fname ); }
+
+               $sql = "DELETE FROM brokenlinks WHERE bl_from={$this->mId}";
+               wfQuery( $sql, $fname );
+
+               $a = $wgLinkCache->getBadLinks();
+               $sql = "";
+               if ( 0 != count ( $a ) ) {
+                       $sql = "INSERT INTO brokenlinks (bl_from,bl_to) VALUES ";
+                       $first = true;
+                       foreach( $a as $blt ) {
+                               $blt = wfStrencode( $blt );
+                               if ( ! $first ) { $sql .= ","; }
+                               $first = false;
+
+                               $sql .= "({$this->mId},'{$blt}')";
+                       }
+               }
+               if ( "" != $sql ) { wfQuery( $sql, $fname ); }
+
+               $sql = "DELETE FROM imagelinks WHERE il_from='{$t}'";
+               wfQuery( $sql, $fname );
+
+               $a = $wgLinkCache->getImageLinks();
+               $sql = "";
+               if ( 0 != count ( $a ) ) {
+                       $sql = "INSERT INTO imagelinks (il_from,il_to) VALUES ";
+                       $first = true;
+                       foreach( $a as $iname => $val ) {
+                               $iname = wfStrencode( $iname );
+                               if ( ! $first ) { $sql .= ","; }
+                               $first = false;
+
+                               $sql .= "('{$t}','{$iname}')";
+                       }
+               }
+               if ( "" != $sql ) { wfQuery( $sql, $fname ); }
+
+               $sql = "SELECT bl_from FROM brokenlinks WHERE bl_to='{$t}'";
+               $res = wfQuery( $sql, $fname );
+               if ( 0 == wfNumRows( $res ) ) { return; }
+
+               $sql = "INSERT INTO links (l_from,l_to) VALUES ";
+               $now = wfTimestampNow();
+               $sql2 = "UPDATE cur SET cur_touched='{$now}' WHERE cur_id IN (";
+               $first = true;
+               while ( $row = wfFetchObject( $res ) ) {
+                       if ( ! $first ) { $sql .= ","; $sql2 .= ","; }
+                       $first = false;
+                       $nl = wfStrencode( Article::nameOf( $row->bl_from ) );
+
+                       $sql .= "('{$nl}',{$this->mId})";
+                       $sql2 .= $row->bl_from;
+               }
+               $sql2 .= ")";
+               wfQuery( $sql, $fname );
+               wfQuery( $sql2, $fname );
+
+               $sql = "DELETE FROM brokenlinks WHERE bl_to='{$t}'";
+               wfQuery( $sql, $fname );
+
+               if( $wgDBtransactions ) {
+                       $sql = "COMMIT";
+                       wfQuery( $sql, $fname );
+               }
+               wfProfileOut();
+       }
+}
+
+?>
diff --git a/includes/LogPage.php b/includes/LogPage.php
new file mode 100644 (file)
index 0000000..eca14cb
--- /dev/null
@@ -0,0 +1,118 @@
+<?
+# Class to simplify the use of log pages
+
+class LogPage {
+       /* private */ var $mTitle, $mContent, $mContentLoaded, $mId, $mComment;
+       var $mUpdateRecentChanges ;
+
+       function LogPage( $title, $defaulttext = "<ul>\n</ul>"  )
+       {
+               # For now, assume title is correct dbkey
+               # and log pages always go in Wikipedia namespace
+               $this->mTitle = $title;
+               $this->mId = 0;
+               $this->mUpdateRecentChanges = true ;
+               $this->mContentLoaded = false;
+               $this->getContent( $defaulttext );
+       }
+
+       function getContent( $defaulttext = "<ul>\n</ul>" )
+       {
+               $sql = "SELECT cur_id,cur_text FROM cur " .
+                       "WHERE cur_namespace=" . Namespace::getWikipedia() . " AND " .
+                       "cur_title='" . wfStrencode($this->mTitle ) . "'";
+               $res = wfQuery( $sql, "LogPage::getContent" );
+
+               if( wfNumRows( $res ) > 0 ) {
+                       $s = wfFetchObject( $res );
+                       $this->mId = $s->cur_id;
+                       $this->mContent = $s->cur_text;
+               } else {
+                       $this->mId = 0;
+                       $this->mContent = $defaulttext;
+               }
+               $this->mContentLoaded = true; # Well, sort of
+               
+               return $this->mContent;
+       }
+
+       function saveContent()
+       {
+               global $wgUser;
+               $fname = "LogPage::saveContent";
+               $uid = $wgUser->getID();
+               $ut = wfStrencode( $wgUser->getName() );
+
+               if( !$this->mContentLoaded ) return false;
+               $now = date( "YmdHis" );
+               $won = wfInvertTimestamp( $now );
+               if($this->mId == 0) {
+                       $sql = "INSERT INTO cur (cur_timestamp,cur_user,cur_user_text,
+                               cur_namespace,cur_title,cur_text,cur_comment,cur_restrictions,inverse_timestamp)
+                               VALUES ('{$now}', {$uid}, '{$ut}', " .
+                               Namespace::getWikipedia() . ", '" .
+                               wfStrencode( $this->mTitle ) . "', '" .
+                               wfStrencode( $this->mContent ) . "', '" .
+                               wfStrencode( $this->mComment ) . "', 'sysop', '{$won}')";
+                       wfQuery( $sql, $fname );
+                       $this->mId = wfInsertId();
+               } else {
+                       $sql = "UPDATE cur SET cur_timestamp='{$now}', " .
+                         "cur_user={$uid}, cur_user_text='{$ut}', " .
+                         "cur_text='" . wfStrencode( $this->mContent ) . "', " .
+                         "cur_comment='" . wfStrencode( $this->mComment ) . "', " .
+                         "cur_restrictions='sysop', inverse_timestamp='{$won}' " .
+                         "WHERE cur_id={$this->mId}";
+                       wfQuery( $sql, $fname );
+               }
+               
+               # And update recentchanges
+               if ( $this->mUpdateRecentChanges ) {
+                       $sql = "INSERT INTO recentchanges (rc_timestamp,rc_cur_time,
+                       rc_user,rc_user_text,rc_namespace,rc_title,rc_comment,
+                       rc_cur_id) VALUES ('{$now}','{$now}',{$uid},'{$ut}',4,'" .
+                               wfStrencode( $this->mTitle ) . "','" .
+                               wfStrencode( $this->mComment ) . "',{$this->mId})";
+                       wfQuery( $sql, $fname );
+                       }
+               return true;
+       }
+
+       function addEntry( $action, $comment, $textaction = "" )
+       {
+               global $wgLang, $wgUser;
+               $this->getContent();
+
+               $ut = $wgUser->getName();
+               $uid = $wgUser->getID();
+               if( $uid ) {
+                       $ul = "[[" .
+                         $wgLang->getNsText( Namespace::getUser() ) .
+                         ":{$ut}|{$ut}]]";
+               } else {
+                       $ul = $ut;
+               }
+               $d = $wgLang->timeanddate( date( "YmdHis" ), false );
+
+               preg_match( "/^(.*?)<ul>(.*)$/sD", $this->mContent, $m );
+
+               if($textaction)
+                       $this->mComment = $textaction;
+               else
+                       $this->mComment = $action;
+               
+               if ( "" == $comment ) {
+                       $inline = "";
+               } else {
+                       $inline = " <em>({$comment})</em>";
+                       $this->mComment .= ": {$comment}";
+               }
+               $this->mContent = "{$m[1]}<ul><li>{$d} {$ul} {$action}{$inline}</li>\n{$m[2]}";
+               
+               # TODO: automatic log rotation...
+               
+               return $this->saveContent();
+       }
+}
+
+?>
diff --git a/includes/Namespace.php b/includes/Namespace.php
new file mode 100644 (file)
index 0000000..03b351f
--- /dev/null
@@ -0,0 +1,49 @@
+<?
+# This is a utility class with only static functions
+# for dealing with namespaces that encodes all the
+# "magic" behaviors of them based on index.  The textual
+# names of the namespaces are handled by Language.php.
+
+class Namespace {
+
+       function getSpecial() { return -1; }
+       function getUser() { return 2; }
+       function getWikipedia() { return 4; }
+       function getImage() { return 6; }
+
+       function isMovable( $index )
+       {
+               if ( $index < 0 || $index > 5 ) { return false; }
+               return true;
+       }
+
+       function isTalk( $index )
+       {
+               if ( 1 == $index || 3 == $index || 5 == $index || 7 == $index ) {
+                       return true;
+               }
+               return false;
+       }
+
+       # Get the talk namespace corresponding to the given index
+       #
+       function getTalk( $index )
+       {
+               if ( Namespace::isTalk( $index ) ) {
+                       return $index;
+               } else {
+                       return $index + 1;
+               }
+       }
+
+       function getSubject( $index )
+       {
+               if ( Namespace::isTalk( $index ) ) {
+                       return $index - 1;
+               } else {
+                       return $index;
+               }
+       }
+}
+
+?>
diff --git a/includes/OutputPage.php b/includes/OutputPage.php
new file mode 100644 (file)
index 0000000..b1c97a1
--- /dev/null
@@ -0,0 +1,1295 @@
+<?
+# See design.doc
+
+function linkToMathImage ( $tex, $outputhash )
+{
+    global $wgMathPath;
+    return "<img src=\"".$wgMathPath."/".$outputhash.".png\" alt=\"".wfEscapeHTML($tex)."\">";
+}
+
+function renderMath( $tex )
+{
+    global $wgUser, $wgMathDirectory, $wgTmpDirectory, $wgInputEncoding;
+    $mf   = wfMsg( "math_failure" );
+    $munk = wfMsg( "math_unknown_error" );
+
+    $fname = "renderMath";
+
+    $math = $wgUser->getOption("math");
+    if ($math == 3)
+       return ('$ '.wfEscapeHTML($tex).' $');
+
+    $md5 = md5($tex);
+    $md5_sql = mysql_escape_string(pack("H32", $md5));
+    if ($math == 0)
+       $sql = "SELECT math_outputhash FROM math WHERE math_inputhash = '".$md5_sql."'";
+    else
+       $sql = "SELECT math_outputhash,math_html_conservativeness,math_html FROM math WHERE math_inputhash = '".$md5_sql."'";
+
+    $res = wfQuery( $sql, $fname );
+    if ( wfNumRows( $res ) == 0 )
+    {
+       $cmd = "./math/texvc ".escapeshellarg($wgTmpDirectory)." ".
+                     escapeshellarg($wgMathDirectory)." ".escapeshellarg($tex)." ".escapeshellarg($wgInputEncoding);
+       $contents = `$cmd`;
+
+       if (strlen($contents) == 0)
+           return "<b>".$mf." (".$munk."): ".wfEscapeHTML($tex)."</b>";
+       $retval = substr ($contents, 0, 1);
+       if (($retval == "C") || ($retval == "M") || ($retval == "L")) {
+           if ($retval == "C")
+               $conservativeness = 2;
+           else if ($retval == "M")
+               $conservativeness = 1;
+           else
+               $conservativeness = 0;
+           $outdata = substr ($contents, 33);
+
+           $i = strpos($outdata, "\000");
+
+           $outhtml = substr($outdata, 0, $i);
+           $mathml = substr($outdata, $i+1);
+
+           $sql_html = "'".mysql_escape_string($outhtml)."'";
+           $sql_mathml = "'".mysql_escape_string($mathml)."'";
+       } else if (($retval == "c") || ($retval == "m") || ($retval == "l"))  {
+           $outhtml = substr ($contents, 33);
+           if ($retval == "c")
+               $conservativeness = 2;
+           else if ($retval == "m")
+               $conservativeness = 1;
+           else
+               $conservativeness = 0;
+           $sql_html = "'".mysql_escape_string($outhtml)."'";
+           $mathml = '';
+           $sql_mathml = 'NULL';
+       } else if ($retval == "X") {
+           $outhtml = '';
+           $mathml = substr ($contents, 33);
+           $sql_html = 'NULL';
+           $sql_mathml = "'".mysql_escape_string($mathml)."'";
+           $conservativeness = 0;
+       } else if ($retval == "+") {
+           $outhtml = '';
+           $mathml = '';
+           $sql_html = 'NULL';
+           $sql_mathml = 'NULL';
+           $conservativeness = 0;
+       } else {
+           if ($retval == "E")
+               $errmsg = wfMsg( "math_lexing_error" );
+           else if ($retval == "S")
+               $errmsg = wfMsg( "math_syntax_error" );
+           else if ($retval == "F")
+               $errmsg = wfMsg( "math_unknown_function" );
+           else
+               $errmsg = $munk;
+           return "<h3>".$mf." (".$errmsg.substr($contents, 1)."): ".wfEscapeHTML($tex)."</h3>";
+       }
+
+       $outmd5 = substr ($contents, 1, 32);
+       if (!preg_match("/^[a-f0-9]{32}$/", $outmd5))
+           return "<b>".$mf." (".$munk."): ".wfEscapeHTML($tex)."</b>";
+
+       $outmd5_sql = mysql_escape_string(pack("H32", $outmd5));
+
+       $sql = "INSERT INTO math VALUES ('".$md5_sql."', '".$outmd5_sql."', ".$conservativeness.", ".$sql_html.", ".$sql_mathml.")";
+       
+       $res = wfQuery( $sql, $fname );
+       # we don't really care if it fails
+
+       if (($math == 0) || ($rpage->math_html == '') || (($math == 1) && ($conservativeness != 2)) || (($math == 4) && ($conservativeness == 0)))
+           return linkToMathImage($tex, $outmd5);
+       else
+           return $outhtml;
+    } else {
+       $rpage = wfFetchObject ( $res );
+       $outputhash = unpack( "H32md5", $rpage->math_outputhash . "                " );
+       $outputhash = $outputhash ['md5'];
+       
+       if (($math == 0) || ($rpage->math_html == '') || (($math == 1) && ($rpage->math_html_conservativeness != 2)) || (($math == 4) && ($rpage->math_html_conservativeness == 0)))
+           return linkToMathImage ( $tex, $outputhash );
+       else
+           return $rpage->math_html;
+    }
+}
+
+class OutputPage {
+       var $mHeaders, $mCookies, $mMetatags, $mKeywords;
+       var $mLinktags, $mPagetitle, $mBodytext, $mDebugtext;
+       var $mHTMLtitle, $mRobotpolicy, $mIsarticle, $mPrintable;
+       var $mSubtitle, $mRedirect, $mAutonumber, $mHeadtext;
+       var $mLastModified;
+
+       var $mDTopen, $mLastSection; # Used for processing DL, PRE
+       var $mLanguageLinks, $mSupressQuickbar;
+
+       function OutputPage()
+       {
+               $this->mHeaders = $this->mCookies = $this->mMetatags =
+               $this->mKeywords = $this->mLinktags = array();
+               $this->mHTMLtitle = $this->mPagetitle = $this->mBodytext =
+               $this->mLastSection = $this->mRedirect = $this->mLastModified =
+               $this->mSubtitle = $this->mDebugtext = $this->mRobotpolicy = "";
+               $this->mIsarticle = $this->mPrintable = true;
+               $this->mSupressQuickbar = $this->mDTopen = $this->mPrintable = false;
+               $this->mLanguageLinks = array();
+               $this->mAutonumber = 0;
+       }
+
+       function addHeader( $name, $val ) { array_push( $this->mHeaders, "$name: $val" ) ; }
+       function addCookie( $name, $val ) { array_push( $this->mCookies, array( $name, $val ) ); }
+       function redirect( $url ) { $this->mRedirect = $url; }
+
+       # To add an http-equiv meta tag, precede the name with "http:"
+       function addMeta( $name, $val ) { array_push( $this->mMetatags, array( $name, $val ) ); }
+       function addKeyword( $text ) { array_push( $this->mKeywords, $text ); }
+       function addLink( $rel, $rev, $target ) { array_push( $this->mLinktags, array( $rel, $rev, $target ) ); }
+
+       function checkLastModified ( $timestamp )
+       {
+               global $wgLang, $wgCachePages, $wgUser;
+               if( !$wgCachePages ) return;
+               if( preg_match( '/MSIE ([1-4]|5\.0)/', $_SERVER["HTTP_USER_AGENT"] ) ) {
+                       # IE 5.0 has probs with our caching
+                       return;
+               }
+
+               if( $_SERVER["HTTP_IF_MODIFIED_SINCE"] != "" ) {
+                       $ismodsince = wfUnix2Timestamp( strtotime( $_SERVER["HTTP_IF_MODIFIED_SINCE"] ) );
+                       $lastmod = gmdate( "D, j M Y H:i:s", wfTimestamp2Unix(
+                               max( $timestamp, $wgUser->mTouched ) ) ) . " GMT";
+               
+                       if( ($ismodsince >= $timestamp ) and $wgUser->validateCache( $ismodsince ) ) {
+                               # Make sure you're in a place you can leave when you call us!
+                               header( "HTTP/1.0 304 Not Modified" );
+                               header( "Expires: Mon, 15 Jan 2001 00:00:00 GMT" ); # Cachers always validate the page!
+                               header( "Cache-Control: private, must-revalidate, max-age=0" );
+                               header( "Last-Modified: {$lastmod}" );                  
+                               #wfDebug( "CACHED client: $ismodsince ; user: $wgUser->mTouched ; page: $timestamp\n", false );
+                               exit;
+                       } else {
+                               #wfDebug( "READY  client: $ismodsince ; user: $wgUser->mTouched ; page: $timestamp\n", false );
+                               $this->mLastModified = $lastmod;
+                       }
+               }
+       }
+
+       function setRobotpolicy( $str ) { $this->mRobotpolicy = $str; }
+       function setHTMLtitle( $name ) { $this->mHTMLtitle = $name; }
+       function setPageTitle( $name ) { $this->mPagetitle = $name; }
+       function getPageTitle() { return $this->mPagetitle; }
+       function setSubtitle( $str ) { $this->mSubtitle = $str; }
+       function getSubtitle() { return $this->mSubtitle; }
+       function setArticleFlag( $v ) { $this->mIsarticle = $v; }
+       function isArticle() { return $this->mIsarticle; }
+       function setPrintable() { $this->mPrintable = true; }
+       function isPrintable() { return $this->mPrintable; }
+
+       function getLanguageLinks() {
+               global $wgUseNewInterlanguage, $wgTitle, $wgLanguageCode;
+               global $wgDBconnection, $wgDBname, $wgDBintlname;
+
+               if ( ! $wgUseNewInterlanguage )
+                       return $this->mLanguageLinks; 
+               
+               mysql_select_db( $wgDBintlname, $wgDBconnection ) or die(
+                         htmlspecialchars(mysql_error()) );
+
+               $list = array();
+               $sql = "SELECT * FROM ilinks WHERE lang_from=\"" .
+                 "{$wgLanguageCode}\" AND title_from=\"" . $wgTitle->getDBkey() . "\"";
+               $res = mysql_query( $sql, $wgDBconnection );
+
+               while ( $q = mysql_fetch_object ( $res ) ) {
+                       $list[] = $q->lang_to . ":" . $q->title_to;
+               }
+               mysql_free_result( $res );
+               mysql_select_db( $wgDBname, $wgDBconnection ) or die(
+                 htmlspecialchars(mysql_error()) );
+
+               return $list;
+       }
+
+       function supressQuickbar() { $this->mSupressQuickbar = true; }
+       function isQuickbarSupressed() { return $this->mSupressQuickbar; }
+
+       function addHTML( $text ) { $this->mBodytext .= $text; }
+       function addHeadtext( $text ) { $this->mHeadtext .= $text; }
+       function debug( $text ) { $this->mDebugtext .= $text; }
+
+       # First pass--just handle <nowiki> sections, pass the rest off
+       # to doWikiPass2() which does all the real work.
+       #
+
+       function addWikiText( $text, $linestart = true )
+       {
+               global $wgUseTeX;
+               wfProfileIn( "OutputPage::addWikiText" );
+               $unique  = "3iyZiyA7iMwg5rhxP0Dcc9oTnj8qD1jm1Sfv4";
+               $unique2 = "4LIQ9nXtiYFPCSfitVwDw7EYwQlL4GeeQ7qSO";
+               $unique3 = "fPaA8gDfdLBqzj68Yjg9Hil3qEF8JGO0uszIp";
+               $nwlist = array();
+               $nwsecs = 0;
+               $mathlist = array();
+               $mathsecs = 0;
+               $prelist = array ();
+               $presecs = 0;
+               $stripped = "";
+               $stripped2 = "";
+               $stripped3 = "";
+
+               while ( "" != $text ) {
+                       $p = preg_split( "/<\\s*nowiki\\s*>/i", $text, 2 );
+                       $stripped .= $p[0];
+                       if ( ( count( $p ) < 2 ) || ( "" == $p[1] ) ) { $text = ""; }
+                       else {
+                               $q = preg_split( "/<\\/\\s*nowiki\\s*>/i", $p[1], 2 );
+                               ++$nwsecs;
+                               $nwlist[$nwsecs] = wfEscapeHTMLTagsOnly($q[0]);
+                               $stripped .= $unique;
+                               $text = $q[1];
+                       }
+               }
+
+               if( $wgUseTeX ) {
+                       while ( "" != $stripped ) {
+                               $p = preg_split( "/<\\s*math\\s*>/i", $stripped, 2 );
+                               $stripped2 .= $p[0];
+                               if ( ( count( $p ) < 2 ) || ( "" == $p[1] ) ) { $stripped = ""; }
+                               else {
+                                       $q = preg_split( "/<\\/\\s*math\\s*>/i", $p[1], 2 );
+                                       ++$mathsecs;
+                                       $mathlist[$mathsecs] = renderMath($q[0]);
+                                       $stripped2 .= $unique2;
+                                       $stripped = $q[1];
+                               }
+                       }
+               } else {
+                       $stripped2 = $stripped;
+               }
+
+               while ( "" != $stripped2 ) {
+                       $p = preg_split( "/<\\s*pre\\s*>/i", $stripped2, 2 );
+                       $stripped3 .= $p[0];
+                       if ( ( count( $p ) < 2 ) || ( "" == $p[1] ) ) { $stripped2 = ""; }
+                       else {
+                               $q = preg_split( "/<\\/\\s*pre\\s*>/i", $p[1], 2 );
+                               ++$presecs;
+                               $prelist[$presecs] = "<pre>". wfEscapeHTMLTagsOnly($q[0]). "</pre>";
+                               $stripped3 .= $unique3;
+                               $stripped2 = $q[1];
+                       }
+               }
+
+               $text = $this->doWikiPass2( $stripped3, $linestart );
+
+               for ( $i = 1; $i <= $presecs; ++$i ) {
+                       $text = preg_replace( "/{$unique3}/", str_replace( '$', '\$', $prelist[$i] ), $text, 1 );
+               }
+
+               for ( $i = 1; $i <= $mathsecs; ++$i ) {
+                       $text = preg_replace( "/{$unique2}/", str_replace( '$', '\$', $mathlist[$i] ), $text, 1 );
+               }
+
+               for ( $i = 1; $i <= $nwsecs; ++$i ) {
+                       $text = preg_replace( "/{$unique}/", str_replace( '$', '\$', $nwlist[$i] ), $text, 1 );
+               }
+               $this->addHTML( $text );
+               wfProfileOut();
+       }
+
+       # Finally, all the text has been munged and accumulated into
+       # the object, let's actually output it:
+       #
+       function output()
+       {
+               global $wgUser, $wgLang, $wgDebugComments, $wgCookieExpiration;
+               global $wgInputEncoding, $wgOutputEncoding, $wgLanguageCode;
+               wfProfileIn( "OutputPage::output" );
+               $sk = $wgUser->getSkin();
+
+               wfProfileIn( "OutputPage::output-headers" );
+               if( $this->mLastModified != "" ) {
+                       header( "Cache-Control: private, must-revalidate, max-age=0" );
+                       header( "Last-modified: {$this->mLastModified}" );
+               } else {
+                       header( "Cache-Control: no-cache" ); # Experimental - see below
+                       header( "Pragma: no-cache" );
+                       header( "Last-modified: " . gmdate( "D, j M Y H:i:s" ) . " GMT" );
+               }
+               header( "Expires: Mon, 15 Jan 2001 00:00:00 GMT" ); # Cachers always validate the page!
+
+               header( "Content-type: text/html; charset={$wgOutputEncoding}" );
+               header( "Content-language: {$wgLanguageCode}" );
+               
+               if ( "" != $this->mRedirect ) {
+                       header( "Location: {$this->mRedirect}" );
+                       wfProfileOut();
+                       return;
+               }
+
+               $exp = time() + $wgCookieExpiration;
+               foreach( $this->mCookies as $name => $val ) {
+                       setcookie( $name, $val, $exp, "/" );
+               }
+               wfProfileOut();
+
+               wfProfileIn( "OutputPage::output-middle" );
+               $sk->initPage();
+               $this->out( $this->headElement() );
+
+               $this->out( "\n<body" );
+               $ops = $sk->getBodyOptions();
+               foreach ( $ops as $name => $val ) {
+                       $this->out( " $name='$val'" );
+               }
+               $this->out( ">\n" );
+               if ( $wgDebugComments ) {
+                       $this->out( "<!-- Wiki debugging output:\n" .
+                         $this->mDebugtext . "-->\n" );
+               }
+               $this->out( $sk->beforeContent() );
+               wfProfileOut();
+               
+               wfProfileIn( "OutputPage::output-bodytext" );
+               $this->out( $this->mBodytext );
+               wfProfileOut();
+               wfProfileIn( "OutputPage::output-after" );
+               $this->out( $sk->afterContent() );
+               wfProfileOut();
+
+               wfProfileOut(); # A hack - we can't report after here
+               $this->out( $this->reportTime() );
+
+               $this->out( "\n</body></html>" );
+               flush();
+       }
+
+       function out( $ins )
+       {
+               global $wgInputEncoding, $wgOutputEncoding, $wgLang;
+               if ( 0 == strcmp( $wgInputEncoding, $wgOutputEncoding ) ) {
+                       $outs = $ins;
+               } else {
+                       $outs = $wgLang->iconv( $wgInputEncoding, $wgOutputEncoding, $ins );
+                       if ( false === $outs ) { $outs = $ins; }
+               }
+               print $outs;
+       }
+
+       function setEncodings()
+       {
+               global $HTTP_SERVER_VARS, $wgInputEncoding, $wgOutputEncoding;
+               global $wgUser, $wgLang;
+
+               $wgInputEncoding = strtolower( $wgInputEncoding );
+               $s = $HTTP_SERVER_VARS['HTTP_ACCEPT_CHARSET'];
+               
+               if( $wgUser->getOption( 'altencoding' ) ) {
+                       $wgLang->setAltEncoding();
+                       return;
+               }
+
+               if ( "" == $s ) {
+                       $wgOutputEncoding = strtolower( $wgOutputEncoding );
+                       return;
+               }
+               $a = explode( ",", $s );
+               $best = 0.0;
+               $bestset = "*";
+
+               foreach ( $a as $s ) {
+                       if ( preg_match( "/(.*);q=(.*)/", $s, $m ) ) {
+                               $set = $m[1];
+                               $q = (float)($m[2]);
+                       } else {
+                               $set = $s;
+                               $q = 1.0;
+                       }
+                       if ( $q > $best ) {
+                               $bestset = $set;
+                               $best = $q;
+                       }
+               }
+               #if ( "*" == $bestset ) { $bestset = "iso-8859-1"; }
+               if ( "*" == $bestset ) { $bestset = $wgOutputEncoding; }
+               $wgOutputEncoding = strtolower( $bestset );
+
+# Disable for now
+#
+               $wgOutputEncoding = $wgInputEncoding;
+       }
+
+       function reportTime()
+       {
+               global $wgRequestTime, $wgDebugLogFile, $HTTP_SERVER_VARS;
+               global $wgProfiling, $wgProfileStack;
+
+               list( $usec, $sec ) = explode( " ", microtime() );
+               $now = (float)$sec + (float)$usec;
+
+               list( $usec, $sec ) = explode( " ", $wgRequestTime );
+               $start = (float)$sec + (float)$usec;
+               $elapsed = $now - $start;
+
+               if ( "" != $wgDebugLogFile ) {
+                       $prof = "";
+                       if( $wgProfiling and count( $wgProfileStack ) ) {
+                               $lasttime = $start;
+                               foreach( $wgProfileStack as $ile ) {
+                                       # "foo::bar 99 0.12345 1 0.23456 2"
+                                       if( preg_match( '/^(\S+)\s+([0-9]+)\s+([0-9\.]+)\s+([0-9\.]+)\s+([0-9\.]+)\s+([0-9\.]+)/', $ile, $m ) ) {
+                                               $thisstart = (float)$m[3] + (float)$m[4] - $start;
+                                               $thisend = (float)$m[5] + (float)$m[6] - $start;
+                                               $thiselapsed = $thisend - $thisstart;
+                                               $thispercent = $thiselapsed / $elapsed * 100.0;
+                                               
+                                               $prof .= sprintf( "\tat %04.3f in %04.3f (%2.1f%%) - %s %s\n",
+                                                       $thisstart, $thiselapsed, $thispercent,
+                                                       str_repeat( "*", $m[2] ), $m[1] );
+                                               $lasttime = $thistime;
+                                               #$prof .= "\t(^ $ile)\n";
+                                       } else {
+                                               $prof .= "\t?broken? $ile\n";
+                                       }
+                               }
+                       }
+               
+                       if( $forward = $HTTP_SERVER_VARS['HTTP_X_FORWARDED_FOR'] )
+                               $forward = " forwarded for $forward";
+                       if( $client = $HTTP_SERVER_VARS['HTTP_CLIENT_IP'] )
+                               $forward .= " client IP $client";
+                       if( $from = $HTTP_SERVER_VARS['HTTP_FROM'] )
+                               $forward .= " from $from";
+                       if( $forward )
+                               $forward = "\t(proxied via {$HTTP_SERVER_VARS['REMOTE_ADDR']}{$forward})";
+                       $log = sprintf( "%s\t%04.3f\t%s\n",
+                         date( "YmdHis" ), $elapsed,
+                         urldecode( $HTTP_SERVER_VARS['REQUEST_URI'] . $forward ) );
+                       error_log( $log . $prof, 3, $wgDebugLogFile );
+               }
+               $com = sprintf( "<!-- Time since request: %01.2f secs. -->",
+                 $elapsed );
+               return $com;
+       }
+
+       # Note: these arguments are keys into wfMsg(), not text!
+       #
+       function errorpage( $title, $msg )
+       {
+               global $wgTitle;
+
+               $this->mDebugtext .= "Original title: " .
+                 $wgTitle->getPrefixedText() . "\n";
+               $this->setHTMLTitle( wfMsg( "errorpagetitle" ) );
+               $this->setPageTitle( wfMsg( $title ) );
+               $this->setRobotpolicy( "noindex,nofollow" );
+               $this->setArticleFlag( false );
+
+               $this->mBodytext = "";
+               $this->addHTML( "<p>" . wfMsg( $msg ) . "\n" );
+               $this->returnToMain( false );
+
+               $this->output();
+               exit;
+       }
+
+       function sysopRequired()
+       {
+               global $wgUser;
+
+               $this->setHTMLTitle( wfMsg( "errorpagetitle" ) );
+               $this->setPageTitle( wfMsg( "sysoptitle" ) );
+               $this->setRobotpolicy( "noindex,nofollow" );
+               $this->setArticleFlag( false );
+               $this->mBodytext = "";
+
+               $sk = $wgUser->getSkin();
+               $ap = $sk->makeKnownLink( wfMsg( "administrators" ), "" );      
+               $text = str_replace( "$1", $ap, wfMsg( "sysoptext" ) );
+               $this->addHTML( $text );
+               $this->returnToMain();
+       }
+
+       function developerRequired()
+       {
+               global $wgUser;
+
+               $this->setHTMLTitle( wfMsg( "errorpagetitle" ) );
+               $this->setPageTitle( wfMsg( "developertitle" ) );
+               $this->setRobotpolicy( "noindex,nofollow" );
+               $this->setArticleFlag( false );
+               $this->mBodytext = "";
+
+               $sk = $wgUser->getSkin();
+               $ap = $sk->makeKnownLink( wfMsg( "administrators" ), "" );      
+               $text = str_replace( "$1", $ap, wfMsg( "developertext" ) );
+               $this->addHTML( $text );
+               $this->returnToMain();
+       }
+
+       function databaseError( $fname )
+       {
+               global $wgUser;
+
+               $this->setPageTitle( wfMsg( "databaseerror" ) );
+               $this->setRobotpolicy( "noindex,nofollow" );
+               $this->setArticleFlag( false );
+
+               $msg = str_replace( "$1", htmlspecialchars( wfLastDBquery() ), wfMsg( "dberrortext" ) );
+               $msg = str_replace( "$2", htmlspecialchars( $fname ), $msg );
+               $msg = str_replace( "$3", wfLastErrno(), $msg );
+               $msg = str_replace( "$4", htmlspecialchars( wfLastError() ), $msg );
+
+               $sk = $wgUser->getSkin();
+               $shlink = $sk->makeKnownLink( wfMsg( "searchhelppage" ),
+                 wfMsg( "searchingwikipedia" ) );
+               $msg = str_replace( "$5", $shlink, $msg );
+
+               $this->mBodytext = $msg;
+               $this->output();
+               exit();
+       }
+
+       function readOnlyPage()
+       {
+               global $wgUser, $wgReadOnlyFile;
+
+               $this->setPageTitle( wfMsg( "readonly" ) );
+               $this->setRobotpolicy( "noindex,nofollow" );
+               $this->setArticleFlag( false );
+
+               $reason = implode( "", file( $wgReadOnlyFile ) );
+               $text = str_replace( "$1", $reason, wfMsg( "readonlytext" ) );
+               $this->addHTML( $text );
+               $this->returnToMain( false );
+       }
+
+       function fatalError( $message )
+       {
+               $this->setPageTitle( wfMsg( "internalerror" ) );
+               $this->setRobotpolicy( "noindex,nofollow" );
+               $this->setArticleFlag( false );
+
+               $this->mBodytext = $message;
+               $this->output();
+               exit;
+       }
+
+       function unexpectedValueError( $name, $val )
+       {
+               $msg = str_replace( "$1", $name, wfMsg( "unexpected" ) );
+               $msg = str_replace( "$2", $val, $msg );
+               $this->fatalError( $msg );
+       }
+
+       function fileCopyError( $old, $new )
+       {
+               $msg = str_replace( "$1", $old, wfMsg( "filecopyerror" ) );
+               $msg = str_replace( "$2", $new, $msg );
+               $this->fatalError( $msg );
+       }
+
+       function fileRenameError( $old, $new )
+       {
+               $msg = str_replace( "$1", $old, wfMsg( "filerenameerror" ) );
+               $msg = str_replace( "$2", $new, $msg );
+               $this->fatalError( $msg );
+       }
+
+       function fileDeleteError( $name )
+       {
+               $msg = str_replace( "$1", $name, wfMsg( "filedeleteerror" ) );
+               $this->fatalError( $msg );
+       }
+
+       function fileNotFoundError( $name )
+       {
+               $msg = str_replace( "$1", $name, wfMsg( "filenotfound" ) );
+               $this->fatalError( $msg );
+       }
+
+       function returnToMain( $auto = true )
+       {
+               global $wgUser, $wgOut, $returnto;
+
+               $sk = $wgUser->getSkin();
+               if ( "" == $returnto ) {
+                       $returnto = wfMsg( "mainpage" );
+               }
+               $link = $sk->makeKnownLink( $returnto, "" );
+
+               $r = str_replace( "$1", $link, wfMsg( "returnto" ) );
+               if ( $auto ) {
+                       $wgOut->addMeta( "http:Refresh", "10;url=" .
+                         wfLocalUrlE( wfUrlencode( $returnto ) ) );
+               }
+               $wgOut->addHTML( "\n<p>$r\n" );
+       }
+
+       # Well, OK, it's actually about 14 passes.  But since all the
+       # hard lifting is done inside PHP's regex code, it probably
+       # wouldn't speed things up much to add a real parser.
+       #
+       function doWikiPass2( $text, $linestart )
+       {
+               global $wgUser;
+               wfProfileIn( "OutputPage::doWikiPass2" );
+
+               $text = $this->removeHTMLtags( $text );
+               $text = $this->replaceVariables( $text );
+
+               $text = preg_replace( "/(^|\n)-----*/", "\\1<hr>", $text );
+               $text = str_replace ( "<HR>", "<hr>", $text );
+
+               $text = $this->doQuotes( $text );
+               $text = $this->doHeadings( $text );
+               $text = $this->doBlockLevels( $text, $linestart );
+
+               $text = $this->replaceExternalLinks( $text );
+               $text = $this->replaceInternalLinks ( $text );
+
+               $text = $this->magicISBN( $text );
+               $text = $this->magicRFC( $text );
+               $text = $this->autoNumberHeadings( $text );
+
+               $sk = $wgUser->getSkin();
+               $text = $sk->transformContent( $text );
+
+               wfProfileOut();
+               return $text;
+       }
+
+       /* private */ function doQuotes( $text )
+       {
+               $text = preg_replace( "/'''(.+)'''/mU", "<strong>\$1</strong>", $text );
+               $text = preg_replace( "/''(.+)''/mU", "<em>\$1</em>", $text );
+               return $text;
+       }
+
+       /* private */ function doHeadings( $text )
+       {
+               for ( $i = 6; $i >= 1; --$i ) {
+                       $h = substr( "======", 0, $i );
+                       $text = preg_replace( "/^{$h}([^=]+){$h}(\\s|$)/m",
+                         "<h{$i}>\\1</h{$i}>\\2", $text );
+               }
+               return $text;
+       }
+
+       # Note: we have to do external links before the internal ones,
+       # and otherwise take great care in the order of things here, so
+       # that we don't end up interpreting some URLs twice.
+
+       /* private */ function replaceExternalLinks( $text )
+       {
+               wfProfileIn( "OutputPage::replaceExternalLinks" );
+               $text = $this->subReplaceExternalLinks( $text, "http", true );
+               $text = $this->subReplaceExternalLinks( $text, "https", true );
+               $text = $this->subReplaceExternalLinks( $text, "ftp", false );
+               $text = $this->subReplaceExternalLinks( $text, "gopher", false );
+               $text = $this->subReplaceExternalLinks( $text, "news", false );
+               $text = $this->subReplaceExternalLinks( $text, "mailto", false );
+               wfProfileOut();
+               return $text;
+       }
+
+       /* private */ function subReplaceExternalLinks( $s, $protocol, $autonumber )
+       {
+               global $wgUser, $printable;
+               global $wgAllowExternalImages;
+
+
+               $unique = "4jzAfzB8hNvf4sqyO9Edd8pSmk9rE2in0Tgw3";
+               $uc = "A-Za-z0-9_\\/~%\\-+&*#?!=()@\\x80-\\xFF";
+               
+               # this is  the list of separators that should be ignored if they 
+               # are the last character of an URL but that should be included
+               # if they occur within the URL, e.g. "go to www.foo.com, where .."
+               # in this case, the last comma should not become part of the URL,
+               # but in "www.foo.com/123,2342,32.htm" it should.
+               $sep = ",;\.:";   
+               $fnc = "A-Za-z0-9_.,~%\\-+&;#*?!=()@\\x80-\\xFF";
+               $images = "gif|png|jpg|jpeg";
+
+               # PLEASE NOTE: The curly braces { } are not part of the regex,
+               # they are interpreted as part of the string (used to tell PHP
+               # that the content of the string should be inserted there).
+               $e1 = "/(^|[^\\[])({$protocol}:)([{$uc}{$sep}]+)\\/([{$fnc}]+)\\." .
+                 "((?i){$images})([^{$uc}]|$)/";
+                 
+               $e2 = "/(^|[^\\[])({$protocol}:)(([".$uc."]|[".$sep."][".$uc."])+)([^". $uc . $sep. "]|[".$sep."]|$)/";
+               $sk = $wgUser->getSkin();
+
+               if ( $autonumber and $wgAllowExternalImages) { # Use img tags only for HTTP urls
+                       $s = preg_replace( $e1, "\\1" . $sk->makeImage( "{$unique}:\\3" .
+                         "/\\4.\\5", "\\4.\\5" ) . "\\6", $s );
+               }
+               $s = preg_replace( $e2, "\\1" . "<a href=\"{$unique}:\\3\"" .
+                 $sk->getExternalLinkAttributes( "{$unique}:\\3", wfEscapeHTML(
+                 "{$unique}:\\3" ) ) . ">" . wfEscapeHTML( "{$unique}:\\3" ) .
+                 "</a>\\5", $s );
+               $s = str_replace( $unique, $protocol, $s );
+
+               $a = explode( "[{$protocol}:", " " . $s );
+               $s = array_shift( $a );
+               $s = substr( $s, 1 );
+
+               $e1 = "/^([{$uc}"."{$sep}]+)](.*)\$/sD";
+               $e2 = "/^([{$uc}"."{$sep}]+)\\s+([^\\]]+)](.*)\$/sD";
+
+               foreach ( $a as $line ) {
+                       if ( preg_match( $e1, $line, $m ) ) {
+                               $link = "{$protocol}:{$m[1]}";
+                               $trail = $m[2];
+                               if ( $autonumber ) { $text = "[" . ++$this->mAutonumber . "]"; }
+                               else { $text = wfEscapeHTML( $link ); }
+                       } else if ( preg_match( $e2, $line, $m ) ) {
+                               $link = "{$protocol}:{$m[1]}";
+                               $text = $m[2];
+                               $trail = $m[3];                 
+                       } else {
+                               $s .= "[{$protocol}:" . $line;
+                               continue;
+                       }
+                       if ( $printable == "yes") $paren = " (<i>" . htmlspecialchars ( $link ) . "</i>)";
+                       else $paren = "";
+                       $la = $sk->getExternalLinkAttributes( $link, $text );
+                       $s .= "<a href='{$link}'{$la}>{$text}</a>{$paren}{$trail}";
+
+               }
+               return $s;
+       }
+
+       /* private */ function replaceInternalLinks( $s )
+       {
+               global $wgTitle, $wgUser, $wgLang;
+               global $wgLinkCache, $wgInterwikiMagic;
+               global $wgNamespacesWithSubpages;
+               wfProfileIn( "OutputPage::replaceInternalLinks" );
+
+               $tc = Title::legalChars() . "#";
+               $sk = $wgUser->getSkin();
+
+               $a = explode( "[[", " " . $s );
+               $s = array_shift( $a );
+               $s = substr( $s, 1 );
+
+               $e1 = "/^([{$tc}]+)\\|([^]]+)]](.*)\$/sD";
+               $e2 = "/^([{$tc}]+)]](.*)\$/sD";
+
+               foreach ( $a as $line ) {
+                       if ( preg_match( $e1, $line, $m ) ) { # page with alternate text
+                               
+                               $text = $m[2];
+                               $trail = $m[3];                         
+                       
+                       } else if ( preg_match( $e2, $line, $m ) ) { # page with normal text
+                       
+                               $text = "";
+                               $trail = $m[2];                 
+                       }
+                       
+                       else { # Invalid form; output directly
+                               $s .= "[[" . $line ;
+                               continue;
+                       }
+                       if(substr($m[1],0,1)=="/") { # subpage
+                               if(substr($m[1],-1,1)=="/") {                 # / at end means we don't want the slash to be shown
+                                       $m[1]=substr($m[1],1,strlen($m[1])-2); 
+                                       $noslash=$m[1];
+                                       
+                               } else {
+                                       $noslash=substr($m[1],1);
+                               }
+                               if($wgNamespacesWithSubpages[$wgTitle->getNamespace()]) { # subpages allowed here
+                                       $link = $wgTitle->getPrefixedText(). "/" . trim($noslash);
+                                       if(!$text) {                                            
+                                               $text= $m[1]; 
+                                       } # this might be changed for ugliness reasons
+                               } else {
+                                       $link = $noslash; # no subpage allowed, use standard link
+                               }
+                       } else { # no subpage
+                               $link = $m[1]; 
+                       }
+
+                       if ( preg_match( "/^([A-Za-z\\x80-\\xff]+):(.*)\$/", $link,  $m ) ) {
+                               $pre = strtolower( $m[1] );
+                               $suf = $m[2];
+                               if ( $wgLang->getNsIndex( $pre ) ==
+                                 Namespace::getImage() ) {
+                                       $nt = Title::newFromText( $suf );
+                                       $name = $nt->getDBkey();
+                                       if ( "" == $text ) { $text = $nt->GetText(); }
+
+                                       $wgLinkCache->addImageLink( $name );
+                                       $s .= $sk->makeImageLink( $name,
+                                         wfImageUrl( $name ), $text );
+                                       $s .= $trail;
+                               } else if ( "media" == $pre ) {
+                                       $nt = Title::newFromText( $suf );
+                                       $name = $nt->getDBkey();
+                                       if ( "" == $text ) { $text = $nt->GetText(); }
+
+                                       $wgLinkCache->addImageLink( $name );
+                                       $s .= $sk->makeMediaLink( $name,
+                                         wfImageUrl( $name ), $text );
+                                       $s .= $trail;
+                               } else {
+                                       $l = $wgLang->getLanguageName( $pre );
+                                       if ( "" == $l or !$wgInterwikiMagic or
+                                         Namespace::isTalk( $wgTitle->getNamespace() ) ) {
+                                               if ( "" == $text ) { $text = $link; }
+                                               $s .= $sk->makeLink( $link, $text, "", $trail );
+                                       } else {
+                                               array_push( $this->mLanguageLinks, "$pre:$suf" );
+                                               $s .= $trail;
+                                       }
+                               }
+#                      } else if ( 0 == strcmp( "##", substr( $link, 0, 2 ) ) ) {
+#                              $link = substr( $link, 2 );
+#                              $s .= "<a name=\"{$link}\">{$text}</a>{$trail}";
+                       } else {
+                               if ( "" == $text ) { $text = $link; }
+                               $s .= $sk->makeLink( $link, $text, "", $trail );
+                       }
+               }
+               wfProfileOut();
+               return $s;
+       }
+
+       # Some functions here used by doBlockLevels()
+       #
+       /* private */ function closeParagraph()
+       {
+               $result = "";
+               if ( 0 != strcmp( "p", $this->mLastSection ) &&
+                 0 != strcmp( "", $this->mLastSection ) ) {
+                       $result = "</" . $this->mLastSection  . ">";
+               }
+               $this->mLastSection = "";
+               return $result;
+       }
+       # getCommon() returns the length of the longest common substring
+       # of both arguments, starting at the beginning of both.
+       #
+       /* private */ function getCommon( $st1, $st2 )
+       {
+               $fl = strlen( $st1 );
+               $shorter = strlen( $st2 );
+               if ( $fl < $shorter ) { $shorter = $fl; }
+
+               for ( $i = 0; $i < $shorter; ++$i ) {
+                       if ( $st1{$i} != $st2{$i} ) { break; }
+               }
+               return $i;
+       }
+       # These next three functions open, continue, and close the list
+       # element appropriate to the prefix character passed into them.
+       #
+       /* private */ function openList( $char )
+    {
+               $result = $this->closeParagraph();
+
+               if ( "*" == $char ) { $result .= "<ul><li>"; }
+               else if ( "#" == $char ) { $result .= "<ol><li>"; }
+               else if ( ":" == $char ) { $result .= "<dl><dd>"; }
+               else if ( ";" == $char ) {
+                       $result .= "<dl><dt>";
+                       $this->mDTopen = true;
+               }
+               else { $result = "<!-- ERR 1 -->"; }
+
+               return $result;
+       }
+
+       /* private */ function nextItem( $char )
+       {
+               if ( "*" == $char || "#" == $char ) { return "</li><li>"; }
+               else if ( ":" == $char || ";" == $char ) {
+                       $close = "</dd>";
+                       if ( $this->mDTopen ) { $close = "</dt>"; }
+                       if ( ";" == $char ) {
+                               $this->mDTopen = true;
+                               return $close . "<dt>";
+                       } else {
+                               $this->mDTopen = false;
+                               return $close . "<dd>";
+                       }
+               }
+               return "<!-- ERR 2 -->";
+       }
+
+       /* private */function closeList( $char )
+       {
+               if ( "*" == $char ) { return "</li></ul>"; }
+               else if ( "#" == $char ) { return "</li></ol>"; }
+               else if ( ":" == $char ) {
+                       if ( $this->mDTopen ) {
+                               $this->mDTopen = false;
+                               return "</dt></dl>";
+                       } else {
+                               return "</dd></dl>";
+                       }
+               }
+               return "<!-- ERR 3 -->";
+       }
+
+       /* private */ function doBlockLevels( $text, $linestart )
+       {
+               wfProfileIn( "OutputPage::doBlockLevels" );
+               # Parsing through the text line by line.  The main thing
+               # happening here is handling of block-level elements p, pre,
+               # and making lists from lines starting with * # : etc.
+               #
+               $a = explode( "\n", $text );
+               $text = $lastPref = "";
+               $this->mDTopen = $inBlockElem = false;
+
+               if ( ! $linestart ) { $text .= array_shift( $a ); }
+               foreach ( $a as $t ) {
+                       if ( "" != $text ) { $text .= "\n"; }
+
+                       $oLine = $t;
+                       $opl = strlen( $lastPref );
+                       $npl = strspn( $t, "*#:;" );
+                       $pref = substr( $t, 0, $npl );
+                       $pref2 = str_replace( ";", ":", $pref );
+                       $t = substr( $t, $npl );
+
+                       if ( 0 != $npl && 0 == strcmp( $lastPref, $pref2 ) ) {
+                               $text .= $this->nextItem( substr( $pref, -1 ) );
+
+                               if ( ";" == substr( $pref, -1 ) ) {
+                                       $cpos = strpos( $t, ":" );
+                                       if ( ! ( false === $cpos ) ) {
+                                               $term = substr( $t, 0, $cpos );
+                                               $text .= $term . $this->nextItem( ":" );
+                                               $t = substr( $t, $cpos + 1 );
+                                       }
+                               }
+                       } else if (0 != $npl || 0 != $opl) {
+                               $cpl = $this->getCommon( $pref, $lastPref );
+
+                               while ( $cpl < $opl ) {
+                                       $text .= $this->closeList( $lastPref{$opl-1} );
+                                       --$opl;
+                               }
+                               if ( $npl <= $cpl && $cpl > 0 ) {
+                                       $text .= $this->nextItem( $pref{$cpl-1} );
+                               }
+                               while ( $npl > $cpl ) {
+                                       $char = substr( $pref, $cpl, 1 );
+                                       $text .= $this->openList( $char );
+
+                                       if ( ";" == $char ) {
+                                               $cpos = strpos( $t, ":" );
+                                               if ( ! ( false === $cpos ) ) {
+                                                       $term = substr( $t, 0, $cpos );
+                                                       $text .= $term . $this->nextItem( ":" );
+                                                       $t = substr( $t, $cpos + 1 );
+                                               }
+                                       }
+                                       ++$cpl;
+                               }
+                               $lastPref = $pref2;
+                       }
+                       if ( 0 == $npl ) { # No prefix--go to paragraph mode
+                               if ( preg_match(
+                                 "/(<table|<blockquote|<h1|<h2|<h3|<h4|<h5|<h6)/i", $t ) ) {
+                                       $text .= $this->closeParagraph();
+                                       $inBlockElem = true;
+                               }
+                               if ( ! $inBlockElem ) {
+                                       if ( " " == $t{0} ) {
+                                               $newSection = "pre";
+                                               # $t = wfEscapeHTML( $t );
+                                       }
+                                       else { $newSection = "p"; }
+
+                                       if ( 0 == strcmp( "", trim( $oLine ) ) ) {
+                                               $text .= $this->closeParagraph();
+                                               $text .= "<" . $newSection . ">";
+                                       } else if ( 0 != strcmp( $this->mLastSection,
+                                         $newSection ) ) {
+                                               $text .= $this->closeParagraph();
+                                               if ( 0 != strcmp( "p", $newSection ) ) {
+                                                       $text .= "<" . $newSection . ">";
+                                               }
+                                       }
+                                       $this->mLastSection = $newSection;
+                               }
+                               if ( $inBlockElem &&
+                                 preg_match( "/(<\\/table|<\\/blockquote|<\\/h1|<\\/h2|<\\/h3|<\\/h4|<\\/h5|<\\/h6)/i", $t ) ) {
+                                       $inBlockElem = false;
+                               }
+                       }
+                       $text .= $t;
+               }
+               while ( $npl ) {
+                       $text .= $this->closeList( $pref2{$npl-1} );
+                       --$npl;
+               }
+               if ( "" != $this->mLastSection ) {
+                       if ( "p" != $this->mLastSection ) {
+                               $text .= "</" . $this->mLastSection . ">";
+                       }
+                       $this->mLastSection = "";
+               }
+               wfProfileOut();
+               return $text;
+       }
+
+       /* private */ function replaceVariables( $text )
+       {
+               global $wgLang;
+               wfProfileIn( "OutputPage:replaceVariables" );
+
+               $v = date( "m" );
+               $text = str_replace( "{{CURRENTMONTH}}", $v, $text );
+               $v = $wgLang->getMonthName( date( "n" ) );
+               $text = str_replace( "{{CURRENTMONTHNAME}}", $v, $text );
+               $v = $wgLang->getMonthNameGen( date( "n" ) );
+               $text = str_replace( "{{CURRENTMONTHNAMEGEN}}", $v, $text );
+               $v = date( "j" );
+               $text = str_replace( "{{CURRENTDAY}}", $v, $text );
+               $v = $wgLang->getWeekdayName( date( "w" )+1 );
+               $text = str_replace( "{{CURRENTDAYNAME}}", $v, $text );
+               $v = date( "Y" );
+               $text = str_replace( "{{CURRENTYEAR}}", $v, $text );
+               $v = $wgLang->time( date( "YmdHis" ), false );
+               $text = str_replace( "{{CURRENTTIME}}", $v, $text );
+
+               if ( false !== strstr( $text, "{{NUMBEROFARTICLES}}" ) ) {
+                       $v = wfNumberOfArticles();
+                       $text = str_replace( "{{NUMBEROFARTICLES}}", $v, $text );
+               }
+               wfProfileOut();
+               return $text;
+       }
+
+       /* private */ function removeHTMLtags( $text )
+       {
+               wfProfileIn( "OutputPage::removeHTMLtags" );
+               $htmlpairs = array( # Tags that must be closed
+                       "b", "i", "u", "font", "big", "small", "sub", "sup", "h1",
+                       "h2", "h3", "h4", "h5", "h6", "cite", "code", "em", "s",
+                       "strike", "strong", "tt", "var", "div", "center",
+                       "blockquote", "ol", "ul", "dl", "table", "caption", "pre",
+                       "ruby", "rt" , "rb" , "rp"
+               );
+               $htmlsingle = array(
+                       "br", "p", "hr", "li", "dt", "dd"
+               );
+               $htmlnest = array( # Tags that can be nested--??
+                       "table", "tr", "td", "th", "div", "blockquote", "ol", "ul",
+                       "dl", "font", "big", "small", "sub", "sup"
+               );
+               $tabletags = array( # Can only appear inside table
+                       "td", "th", "tr"
+               );
+
+               $htmlsingle = array_merge( $tabletags, $htmlsingle );
+               $htmlelements = array_merge( $htmlsingle, $htmlpairs );
+
+               $htmlattrs = array( # Allowed attributes--no scripting, etc.
+                       "title", "align", "lang", "dir", "width", "height",
+                       "bgcolor", "clear", /* BR */ "noshade", /* HR */
+                       "cite", /* BLOCKQUOTE, Q */ "size", "face", "color",
+                       /* FONT */ "type", "start", "value", "compact",
+                       /* For various lists, mostly deprecated but safe */
+                       "summary", "width", "border", "frame", "rules",
+                       "cellspacing", "cellpadding", "valign", "char",
+                       "charoff", "colgroup", "col", "span", "abbr", "axis",
+                       "headers", "scope", "rowspan", "colspan", /* Tables */
+                       "id", "class", "name", "style" /* For CSS */
+               );
+
+               # Remove HTML comments
+               $text = preg_replace( "/<!--.*-->/sU", "", $text );
+
+               $bits = explode( "<", $text );
+               $text = array_shift( $bits );
+               $tagstack = array(); $tablestack = array();
+
+               foreach ( $bits as $x ) {
+                       $prev = error_reporting( E_ALL & ~( E_NOTICE | E_WARNING ) );
+                       preg_match( "/^(\\/?)(\\w+)([^>]*)(\\/{0,1}>)([^<]*)$/",
+                         $x, $regs );
+                       list( $qbar, $slash, $t, $params, $brace, $rest ) = $regs;
+                       error_reporting( $prev );
+
+                       $badtag = 0 ;
+                       if ( in_array( $t = strtolower( $t ), $htmlelements ) ) {
+                               # Check our stack
+                               if ( $slash ) {
+                                       # Closing a tag...
+                                       if ( ! in_array( $t, $htmlsingle ) &&
+                                         ( $ot = array_pop( $tagstack ) ) != $t ) {
+                                               array_push( $tagstack, $ot );
+                                               $badtag = 1;
+                                       } else {
+                                               if ( $t == "table" ) {
+                                                       $tagstack = array_pop( $tablestack );
+                                               }
+                                               $newparams = "";
+                                       }
+                               } else {
+                                       # Keep track for later
+                                       if ( in_array( $t, $tabletags ) &&
+                                         ! in_array( "table", $tagstack ) ) {
+                                               $badtag = 1;
+                                       } else if ( in_array( $t, $tagstack ) &&
+                                         ! in_array ( $t , $htmlnest ) ) {
+                                               $badtag = 1 ;
+                                       } else if ( ! in_array( $t, $htmlsingle ) ) {
+                                               if ( $t == "table" ) {
+                                                       array_push( $tablestack, $tagstack );
+                                                       $tagstack = array();
+                                               }
+                                               array_push( $tagstack, $t );
+                                       }
+                                       # Strip non-approved attributes from the tag
+                                       $newparams = preg_replace(
+                                         "/(\\w+)(\\s*=\\s*([^\\s\">]+|\"[^\">]*\"))?/e",
+                                         "(in_array(strtolower(\"\$1\"),\$htmlattrs)?(\"\$1\".((\"x\$3\" != \"x\")?\"=\$3\":'')):'')",
+                                         $params);
+                               }
+                               if ( ! $badtag ) {
+                                       $rest = str_replace( ">", "&gt;", $rest );
+                                       $text .= "<$slash$t$newparams$brace$rest";
+                                       continue;
+                               }
+                       }
+                       $text .= "&lt;" . str_replace( ">", "&gt;", $x);
+               }
+               # Close off any remaining tags
+               while ( $t = array_pop( $tagstack ) ) {
+                       $text .= "</$t>\n";
+                       if ( $t == "table" ) { $tagstack = array_pop( $tablestack ); }
+               }
+               wfProfileOut();
+               return $text;
+       }
+
+       /* private */ function autoNumberHeadings( $text )
+       {
+               global $wgUser;
+               if ( 1 != $wgUser->getOption( "numberheadings" ) ) {
+                       return $text;
+               }
+               $j = 0;
+               $n = -1;
+               for ( $i = 0; $i < 9; ++$i ) {
+                       if ( stristr( $text, "<h$i>" ) != false ) {
+                               ++$j;
+                               if ( $n == -1 ) $n = $i;
+                       }
+               }
+               if ( $j < 2 ) return $text;
+               $i = $n;
+               $v = array( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 );
+               $t = "";
+               while ( count( spliti( "<h", $text, 2 ) ) == 2 ) {
+                       $a = spliti( "<h", $text, 2 );
+                       $j = substr( $a[1], 0, 1 );
+                       if ( strtolower( $j ) != "r" ) {
+                               $t .= $a[0] . "<h" . $j . ">";
+                               ++$v[$j];
+                               $b = array();
+                               for ( $k = $i; $k <= $j; $k++ ) array_push( $b, $v[$k] );
+                               for ( $k = $j+1; $k < 9; $k++ ) $v[$k] = 0;
+                               $t .= implode( ".", $b ) . " ";
+                $text = substr( $a[1] , 2 ) ;
+                       } else { # <HR> tag, not a heading!
+                               $t .= $a[0] . "<hr>";
+                               $text = substr( $a[1], 2 );
+                       }
+               }
+        return $t . $text;
+       }
+
+       /* private */ function magicISBN( $text )
+       {
+               global $wgLang;
+
+               $a = split( "ISBN ", " $text" );
+               if ( count ( $a ) < 2 ) return $text;
+               $text = substr( array_shift( $a ), 1);
+        $valid = "0123456789-ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+               foreach ( $a as $x ) {
+                       $isbn = $blank = "" ;
+                       while ( " " == $x{0} ) {
+                $blank .= " ";
+                $x = substr( $x, 1 );
+                       }
+            while ( strstr( $valid, $x{0} ) != false ) {
+                               $isbn .= $x{0};
+                               $x = substr( $x, 1 );
+                       }
+            $num = str_replace( "-", "", $isbn );
+            $num = str_replace( " ", "", $num );
+
+            if ( "" == $num ) {
+                               $text .= "ISBN $blank$x";
+            } else {
+                               $text .= "<a href=\"" . wfLocalUrlE( $wgLang->specialPage(
+                                 "Booksources"), "isbn={$num}" ) . "\">ISBN $isbn</a>";
+                               $text .= $x;
+                       }
+               }
+        return $text;
+       }
+
+       /* private */ function magicRFC( $text )
+       {
+               return $text;
+       }
+
+       /* private */ function headElement()
+       {
+               global $wgDocType, $wgUser, $wgLanguageCode, $wgOutputEncoding;
+
+               $ret = "<!DOCTYPE HTML PUBLIC \"$wgDocType\">\n";
+
+               if ( "" == $this->mHTMLtitle ) {
+                       $this->mHTMLtitle = $this->mPagetitle;
+               }
+               $ret .= "<html lang=\"$wgLanguageCode\"><head><title>{$this->mHTMLtitle}</title>\n";
+               array_push( $this->mMetatags, array( "http:Content-type", "text/html; charset={$wgOutputEncoding}" ) );
+               foreach ( $this->mMetatags as $tag ) {
+                       if ( 0 == strcasecmp( "http:", substr( $tag[0], 0, 5 ) ) ) {
+                               $a = "http-equiv";
+                               $tag[0] = substr( $tag[0], 5 );
+                       } else {
+                               $a = "name";
+                       }
+                       $ret .= "<meta $a=\"{$tag[0]}\" content=\"{$tag[1]}\">\n";
+               }
+               $p = $this->mRobotpolicy;
+               if ( "" == $p ) { $p = "index,follow"; }
+               $ret .= "<meta name=\"robots\" content=\"$p\">\n";
+
+               if ( count( $this->mKeywords ) > 0 ) {
+                       $ret .= "<meta name=\"keywords\" content=\"" .
+                         implode( ",", $this->mKeywords ) . "\">\n";
+               }
+               foreach ( $this->mLinktags as $tag ) {
+                       $ret .= "<link ";
+                       if ( "" != $tag[0] ) { $ret .= "rel=\"{$tag[0]}\" "; }
+                       if ( "" != $tag[1] ) { $ret .= "rev=\"{$tag[1]}\" "; }
+                       $ret .= "href=\"{$tag[2]}\">\n";
+               }
+               $sk = $wgUser->getSkin();
+               $ret .= $sk->getHeadScripts();
+               $ret .= $sk->getUserStyles();
+
+               $ret .= "</head>\n";
+               return $ret;
+       }
+}
+
+?>
diff --git a/includes/SearchEngine.php b/includes/SearchEngine.php
new file mode 100644 (file)
index 0000000..53be8f7
--- /dev/null
@@ -0,0 +1,383 @@
+<?
+# See search.doc
+
+class SearchEngine {
+       /* private */ var $mUsertext, $mSearchterms;
+       /* private */ var $mTitlecond, $mTextcond;
+
+       var $doSearchRedirects = true;
+       var $addtoquery = array();
+       var $namespacesToSearch = array();
+       var $alternateTitle;
+
+       function SearchEngine( $text )
+       {
+               # We display the query, so let's strip it for safety
+               #
+               $lc = SearchEngine::legalSearchChars() . "()";
+               $this->mUsertext = trim( preg_replace( "/[^{$lc}]/", " ", $text ) );
+               $this->mSearchterms = array();
+       }
+
+       function queryNamespaces()
+       {
+               return "cur_namespace IN (" . implode( ",", $this->namespacesToSearch ) . ")";
+               #return "1";
+       }
+
+       function searchRedirects()
+       {
+               if ( $this->doSearchRedirects ) return "";
+               return "AND cur_is_redirect=0 ";
+       }
+
+       function powersearch()
+       {
+               global $wgUser, $wgOut, $wgLang, $wgTitle;
+               $nscb = array();
+
+               $search                 = $_REQUEST['search'];
+               $searchx                = $_REQUEST['searchx'];
+               $listredirs             = $_REQUEST['redirs'];
+               $nscb[0]                = $_REQUEST['ns0'];
+               $nscb[1]                = $_REQUEST['ns1'];
+               $nscb[2]                = $_REQUEST['ns2'];
+               $nscb[3]                = $_REQUEST['ns3'];
+               $nscb[4]                = $_REQUEST['ns4'];
+               $nscb[5]                = $_REQUEST['ns5'];
+               $nscb[6]                = $_REQUEST['ns6'];
+               $nscb[7]                = $_REQUEST['ns7'];
+
+               if ( ! isset ( $searchx ) ) {   /* First time here */
+                       $nscb[0] = $listredirs = 1;     /* All others should be unset */
+               }
+               $this->checkboxes["searchx"] = 1;
+               $ret = wfMsg("powersearchtext");
+
+               # Determine namespace checkboxes
+
+               $ns = $wgLang->getNamespaces();
+               array_shift( $ns ); /* Skip "Special" */
+
+               $r1 = "";
+               for ( $i = 0; $i < count( $ns ); ++$i ) {
+                       $checked = "";
+                       if ( $nscb[$i] == 1 ) {
+                               $checked = " checked";
+                               $this->addtoquery["ns{$i}"] = 1;
+                               array_push( $this->namespacesToSearch, $i );
+                       }
+                       $name = str_replace( "_", " ", $ns[$i] );
+                       if ( "" == $name ) { $name = "(Main)"; }
+
+                       if ( 0 != $i ) { $r1 .= " "; }
+                       $r1 .= "<input type=checkbox value=\"1\" name=\"" .
+                         "ns{$i}\"{$checked}>{$name}\n";
+               }
+               $ret = str_replace ( "$1", $r1, $ret );
+
+               # List redirects checkbox
+
+               $checked = "";
+               if ( $listredirs == 1 ) {
+                       $this->addtoquery["redirs"] = 1;
+                       $checked = " checked";
+               }
+               $r2 = "<input type=checkbox value=1 name=\"redirs\"{$checked}>\n";
+               $ret = str_replace( "$2", $r2, $ret );
+
+               # Search field
+
+               $r3 = "<input type=text name=\"search\" value=\"" .
+                       htmlspecialchars( $search ) ."\" width=80>\n";
+        $ret = str_replace( "$3", $r3, $ret );
+
+               # Searchx button
+
+               $r9 = "<input type=submit name=\"searchx\" value=\"" .
+                 wfMsg("powersearch") . "\">\n";
+               $ret = str_replace( "$9", $r9, $ret );
+
+               $ret = "<br><br>\n<form id=\"powersearch\" method=\"get\" " .
+                 "action=\"" . wfLocalUrl( "" ) . "\">\n{$ret}\n</form>\n";
+
+               if ( isset ( $searchx ) ) {
+                       if ( ! $listredirs ) { $this->doSearchRedirects = false; }
+               }
+               return $ret;
+       }
+
+       function showResults()
+       {
+               global $wgUser, $wgTitle, $wgOut, $wgLang, $wgDisableTextSearch;
+               $fname = "SearchEngine::showResults";
+
+               $offset         = $_REQUEST['offset'];
+               $limit          = $_REQUEST['limit'];
+               $search         = $_REQUEST['search'];
+
+               $powersearch = $this->powersearch(); /* Need side-effects here? */
+
+               $wgOut->setPageTitle( wfMsg( "searchresults" ) );
+               $q = str_replace( "$1", $this->mUsertext,
+                 wfMsg( "searchquery" ) );
+               $wgOut->setSubtitle( $q );
+               $wgOut->setArticleFlag( false );
+               $wgOut->setRobotpolicy( "noindex,nofollow" );
+
+               $sk = $wgUser->getSkin();
+               $text = str_replace( "$1", $sk->makeKnownLink(
+                 wfMsg( "searchhelppage" ), wfMsg( "searchingwikipedia" ) ),
+                 wfMsg( "searchresulttext" ) );
+               $wgOut->addHTML( $text );
+
+               $this->parseQuery();
+               if ( "" == $this->mTitlecond || "" == $this->mTextcond ) {
+                       $wgOut->addHTML( "<h2>" . wfMsg( "badquery" ) . "</h2>\n" .
+                         "<p>" . wfMsg( "badquerytext" ) );
+                       return;
+               }
+               if ( ! isset( $limit ) ) {
+                       $limit = $wgUser->getOption( "searchlimit" );
+                       if ( ! $limit ) { $limit = 20; }
+               }
+               if ( ! $offset ) { $offset = 0; }
+
+               $searchnamespaces = $this->queryNamespaces();
+               $redircond = $this->searchRedirects();
+
+               $sql = "SELECT cur_id,cur_namespace,cur_title," .
+                 "cur_text FROM cur,searchindex " .
+                 "WHERE cur_id=si_page AND {$this->mTitlecond} " .
+                 "AND {$searchnamespaces} {$redircond}" .
+                 "LIMIT {$offset}, {$limit}";
+               $res1 = wfQuery( $sql, $fname );
+
+               if ( $wgDisableTextSearch ) {
+                       $res2 = 0;
+               } else {
+                       $sql = "SELECT cur_id,cur_namespace,cur_title," .
+                         "cur_text FROM cur,searchindex " .
+                         "WHERE cur_id=si_page AND {$this->mTextcond} " .
+                         "AND {$searchnamespaces} {$redircond} " .
+                         "LIMIT {$offset}, {$limit}";
+                       $res2 = wfQuery( $sql, $fname );
+               }
+
+               $top = wfShowingResults( $offset, $limit );
+               $wgOut->addHTML( "<p>{$top}\n" );
+
+               # For powersearch
+
+               $a2l = "" ;
+               $akk = array_keys( $this->addtoquery ) ;
+               foreach ( $akk AS $ak ) {
+                       $a2l .= "&{$ak}={$this->addtoquery[$ak]}" ;
+               }
+
+               $sl = wfViewPrevNext( $offset, $limit, "",
+                 "search=" . wfUrlencode( $this->mUsertext ) . $a2l );
+               $wgOut->addHTML( "<br>{$sl}\n" );
+
+               $foundsome = false;
+
+               if ( 0 == wfNumRows( $res1 ) ) {
+                       $wgOut->addHTML( "<h2>" . wfMsg( "notitlematches" ) .
+                         "</h2>\n" );
+               } else {
+                       $foundsome = true;
+                       $off = $offset + 1;
+                       $wgOut->addHTML( "<h2>" . wfMsg( "titlematches" ) .
+                         "</h2>\n<ol start='{$off}'>" );
+
+                       while ( $row = wfFetchObject( $res1 ) ) {
+                               $this->showHit( $row );
+                       }
+                       wfFreeResult( $res1 );
+                       $wgOut->addHTML( "</ol>\n" );
+               }
+
+               if ( $wgDisableTextSearch ) {
+                       $wgOut->addHTML( str_replace( "$1",
+                         htmlspecialchars( $search ), wfMsg( "searchdisabled" ) ) );
+               } else {
+                       if ( 0 == wfNumRows( $res2 ) ) {
+                               $wgOut->addHTML( "<h2>" . wfMsg( "notextmatches" ) .
+                                 "</h2>\n" );
+                       } else {
+                               $foundsome = true;
+                               $off = $offset + 1;
+                               $wgOut->addHTML( "<h2>" . wfMsg( "textmatches" ) . "</h2>\n" .
+                                 "<ol start='{$off}'>" );
+                               while ( $row = wfFetchObject( $res2 ) ) {
+                                       $this->showHit( $row );
+                               }
+                               wfFreeResult( $res2 );
+                               $wgOut->addHTML( "</ol>\n" );
+                       }
+               }
+               if ( ! $foundsome ) {
+                       $wgOut->addHTML( "<p>" . wfMsg( "nonefound" ) . "\n" );
+               }
+               $wgOut->addHTML( "<p>{$sl}\n" );
+               $wgOut->addHTML( $powersearch );
+       }
+
+       function legalSearchChars()
+       {
+               $lc = "A-Za-z_'0-9\\x80-\\xFF\\-";
+               return $lc;
+       }
+
+       function parseQuery()
+       {
+               global $wgDBminWordLen, $wgLang;
+
+               $lc = SearchEngine::legalSearchChars() . "()";
+               $q = preg_replace( "/([()])/", " \\1 ", $this->mUsertext );
+               $q = preg_replace( "/\\s+/", " ", $q );
+               $w = explode( " ", strtolower( trim( $q ) ) );
+
+               $last = $cond = "";
+               foreach ( $w as $word ) {
+                       $word = $wgLang->stripForSearch( $word );
+                       if ( "and" == $word || "or" == $word || "not" == $word
+                         || "(" == $word || ")" == $word ) {
+                               $cond .= " " . strtoupper( $word );
+                               $last = "";
+                       } else if ( strlen( $word ) < $wgDBminWordLen ) {
+                               continue;
+                       } else if ( FulltextStoplist::inList( $word ) ) {
+                               continue;
+                       } else {
+                               if ( "" != $last ) { $cond .= " AND"; }
+                               $cond .= " (MATCH (##field##) AGAINST ('" .
+                                 wfStrencode( $word ). "'))";
+                               $last = $word;
+                               array_push( $this->mSearchterms, "\\b" . $word . "\\b" );
+                       }
+               }
+               if ( 0 == count( $this->mSearchterms ) ) { return; }
+
+               # To disable boolean:
+               # $cond = "MATCH (##field##) AGAINST('" . wfStrencode( $q ) . "')";
+
+               $this->mTitlecond = "(" . str_replace( "##field##",
+                 "si_title", $cond ) . " )";
+
+               $this->mTextcond = "(" . str_replace( "##field##",
+                 "si_text", $cond ) . " AND (cur_is_redirect=0) )";
+       }
+
+       function showHit( $row )
+       {
+               global $wgUser, $wgOut;
+
+               $t = Title::makeName( $row->cur_namespace, $row->cur_title );
+               $sk = $wgUser->getSkin();
+
+               $contextlines = $wgUser->getOption( "contextlines" );
+               if ( "" == $contextlines ) { $contextlines = 5; }
+               $contextchars = $wgUser->getOption( "contextchars" );
+               if ( "" == $contextchars ) { $contextchars = 50; }
+
+               $link = $sk->makeKnownLink( $t, "" );
+               $size = str_replace( "$1", strlen( $row->cur_text ), WfMsg( "nbytes" ) );
+               $wgOut->addHTML( "<li>{$link} ({$size})" );
+
+               $lines = explode( "\n", $row->cur_text );
+               $pat1 = "/(.*)(" . implode( "|", $this->mSearchterms ) . ")(.*)/i";
+               $lineno = 0;
+
+               foreach ( $lines as $line ) {
+                       if ( 0 == $contextlines ) { break; }
+                       --$contextlines;
+                       ++$lineno;
+                       if ( ! preg_match( $pat1, $line, $m ) ) { continue; }
+
+                       $pre = $m[1];
+                       if ( 0 == $contextchars ) { $pre = "..."; }
+                       else {
+                               if ( strlen( $pre ) > $contextchars ) {
+                                       $pre = "..." . substr( $pre, -$contextchars );
+                               }
+                       }
+                       $pre = wfEscapeHTML( $pre );
+
+                       if ( count( $m ) < 3 ) { $post = ""; }
+                       else { $post = $m[3]; }
+
+                       if ( 0 == $contextchars ) { $post = "..."; }
+                       else {
+                               if ( strlen( $post ) > $contextchars ) {
+                                       $post = substr( $post, 0, $contextchars ) . "...";
+                               }
+                       }
+                       $post = wfEscapeHTML( $post );
+                       $found = wfEscapeHTML( $m[2] );
+
+                       $line = "{$pre}{$found}{$post}";
+                       $pat2 = "/(" . implode( "|", $this->mSearchterms ) . ")/i";
+                       $line = preg_replace( $pat2,
+                         "<font color='red'>\\1</font>", $line );
+
+                       $wgOut->addHTML( "<br><small>{$lineno}: {$line}</small>\n" );
+               }
+               $wgOut->addHTML( "</li>\n" );
+       }
+
+       function goResult()
+       {
+               global $wgOut, $wgArticle, $wgTitle;
+               $fname = "SearchEngine::goResult";
+               
+               $search         = $_REQUEST['search'];
+
+               # First try to go to page as entered            
+               #
+               $wgArticle = new Article();
+               $wgTitle = Title::newFromText( $search );
+
+               if ( 0 != $wgArticle->getID() ) {
+                       $wgArticle->view();
+                       return;
+               }
+
+               # Now try all lower case (i.e. first letter capitalized)
+               #
+               $wgTitle = Title::newFromText( strtolower( $search ) );
+               if ( 0 != $wgArticle->getID() ) {
+                       $wgArticle->view();
+                       return;
+               }
+               
+               # Now try capitalized string
+               #
+               $wgTitle=Title::newFromText( ucwords( strtolower( $search ) ) );
+               if ( 0 != $wgArticle->getID() ) {
+                       $wgArticle->view();
+                       return;
+               }
+
+               # Try a near match
+               #
+               $this->parseQuery();                                                                            
+               $sql = "SELECT cur_id,cur_title,cur_namespace,si_page FROM cur,searchindex " .
+                 "WHERE cur_id=si_page AND {$this->mTitlecond} LIMIT 1";
+
+               if ( "" != $this->mTitlecond ) {
+                       $res = wfQuery( $sql, $fname );
+               }                               
+               if ( isset( $res ) && 0 != wfNumRows( $res ) ) {
+                       $s = wfFetchObject( $res );
+
+                       $wgTitle = Title::newFromDBkey( $s->cur_title );
+                       $wgTitle->setNamespace( $s->cur_namespace );
+                       $wgArticle->view();
+                       return;
+               }
+               $wgOut->addHTML( wfMsg("nogomatch") . "\n<p>" );
+               $this->showResults();
+       }
+}
+
diff --git a/includes/SearchUpdate.php b/includes/SearchUpdate.php
new file mode 100644 (file)
index 0000000..9e9ff2a
--- /dev/null
@@ -0,0 +1,78 @@
+<?
+# See deferred.doc
+
+class SearchUpdate {
+
+       /* private */ var $mId, $mNamespace, $mTitle, $mText;
+       /* private */ var $mTitleWords;
+
+       function SearchUpdate( $id, $title, $text = false )
+       {
+               $this->mId = $id;
+               $this->mText = $text;
+
+               $nt = Title::newFromText( $title );
+               $this->mNamespace = $nt->getNamespace();
+               $this->mTitle = $nt->getText(); # Discard namespace
+
+               $this->mTitleWords = $this->mTextWords = array();
+       }
+
+       function doUpdate()
+       {
+               global $wgDBminWordLen, $wgLang;
+               $lc = SearchEngine::legalSearchChars() . "&#;";
+               
+               if( $this->mText == false ) {
+                       # Just update the title
+                       $sql = "UPDATE LOW_PRIORITY searchindex SET si_title='" .
+                         wfStrencode( Title::indexTitle( $this->mNamespace, $this->mTitle ) ) .
+                         "' WHERE si_page={$this->mId}";
+                       wfQuery( $sql, "SearchUpdate::doUpdate" );
+                       return;
+               }
+               
+               # Language-specific strip/conversion
+               $text = $wgLang->stripForSearch( $this->mText );
+
+               $text = preg_replace( "/<\\/?\\s*[A-Za-z][A-Za-z0-9]*\\s*([^>]*?)>/",
+                 " ", strtolower( " " . $text /*$this->mText*/ . " " ) ); # Strip HTML markup
+               $text = preg_replace( "/(^|\\n)\\s*==\\s+([^\\n]+)\\s+==\\s/sD",
+                 "\\2 \\2 \\2 ", $text ); # Emphasize headings
+
+               # Strip external URLs
+               $uc = "A-Za-z0-9_\\/:.,~%\\-+&;#?!=()@\\xA0-\\xFF";
+               $protos = "http|https|ftp|mailto|news|gopher";
+               $pat = "/(^|[^\\[])({$protos}):[{$uc}]+([^{$uc}]|$)/";
+               $text = preg_replace( $pat, "\\1 \\3", $text );
+
+               $p1 = "/([^\\[])\\[({$protos}):[{$uc}]+]/";
+               $p2 = "/([^\\[])\\[({$protos}):[{$uc}]+\\s+([^\\]]+)]/";
+               $text = preg_replace( $p1, "\\1 ", $text );
+               $text = preg_replace( $p2, "\\1 \\3 ", $text );
+
+               # Internal image links
+               $pat2 = "/\\[\\[image:([{$uc}]+)\\.(gif|png|jpg|jpeg)([^{$uc}])/i";
+               $text = preg_replace( $pat2, " \\1 \\3", $text );
+
+               $text = preg_replace( "/([^{$lc}])([{$lc}]+)]]([a-z]+)/",
+                 "\\1\\2 \\2\\3", $text ); # Handle [[game]]s
+
+               # Strip all remaining non-search characters
+               $text = preg_replace( "/[^{$lc}]+/", " ", $text );
+
+               # Handle 's, s'
+               $text = preg_replace( "/([{$lc}]+)'s /", "\\1 \\1's ", $text );
+               $text = preg_replace( "/([{$lc}]+)s' /", "\\1s ", $text );
+
+               # Strip wiki '' and '''
+               $text = preg_replace( "/''[']*/", " ", $text );
+
+               $sql = "REPLACE DELAYED INTO searchindex (si_page,si_title,si_text) VALUES ({$this->mId},'" .
+                 wfStrencode( Title::indexTitle( $this->mNamespace, $this->mTitle ) ) . "','" .
+                 wfStrencode( $text ) . "')";
+               wfQuery( $sql, "SearchUpdate::doUpdate" );
+       }
+}
+
+?>
diff --git a/includes/Setup.php b/includes/Setup.php
new file mode 100644 (file)
index 0000000..7b0c646
--- /dev/null
@@ -0,0 +1,37 @@
+<?
+# The main wiki script and things like database
+# conversion and maintenance scripts all share a
+# common setup of including lots of classes and
+# setting up a few globals.
+#
+
+global $IP;
+include_once( "$IP/GlobalFunctions.php" );
+include_once( "$IP/Language.php" );
+include_once( "$IP/Namespace.php" );
+include_once( "$IP/Skin.php" );
+include_once( "$IP/OutputPage.php" );
+include_once( "$IP/DifferenceEngine.php" );
+include_once( "$IP/SearchEngine.php" );
+include_once( "$IP/User.php" );
+include_once( "$IP/LinkCache.php" );
+include_once( "$IP/Title.php" );
+include_once( "$IP/Article.php" );
+
+global $wgUser, $wgLang, $wgOut, $wgTitle;
+global $wgArticle, $wgDeferredUpdateList, $wgLinkCache;
+
+$wgOut = new OutputPage();
+$wgLangClass = "Language" . ucfirst( $wgLanguageCode );
+if( ! class_exists( $wgLangClass ) ) {
+       include_once( "$IP/Utf8Case.php" );
+       $wgLangClass = "LanguageUtf8";
+}
+$wgLang = new $wgLangClass();
+
+$wgUser = new User();
+$wgUser->loadFromSession();
+$wgDeferredUpdateList = array();
+$wgLinkCache = new LinkCache();
+
+?>
diff --git a/includes/SiteStatsUpdate.php b/includes/SiteStatsUpdate.php
new file mode 100644 (file)
index 0000000..61ca846
--- /dev/null
@@ -0,0 +1,40 @@
+<?
+# See deferred.doc
+
+class SiteStatsUpdate {
+
+       var $mViews, $mEdits, $mGood;
+
+       function SiteStatsUpdate( $views, $edits, $good )
+       {
+               $this->mViews = $views;
+               $this->mEdits = $edits;
+               $this->mGood = $good;
+       }
+
+       function doUpdate()
+       {
+               $a = array();
+
+               if ( $this->mViews < 0 ) { $m = "-1"; }
+               else if ( $this->mViews > 0 ) { $m = "+1"; }
+               else $m = "";
+               array_push( $a, "ss_total_views=(ss_total_views$m)" );
+
+               if ( $this->mEdits < 0 ) { $m = "-1"; }
+               else if ( $this->mEdits > 0 ) { $m = "+1"; }
+               else $m = "";
+               array_push( $a, "ss_total_edits=(ss_total_edits$m)" );
+
+               if ( $this->mGood < 0 ) { $m = "-1"; }
+               else if ( $this->mGood > 0 ) { $m = "+1"; }
+               else $m = "";
+               array_push( $a, "ss_good_articles=(ss_good_articles$m)" );
+
+               $sql = "UPDATE LOW_PRIORITY site_stats SET " . implode ( ",", $a ) .
+                 " WHERE ss_row_id=1";
+               wfQuery( $sql, "SiteStatsUpdate::doUpdate" );
+       }
+}
+
+?>
diff --git a/includes/Skin.php b/includes/Skin.php
new file mode 100644 (file)
index 0000000..303ad17
--- /dev/null
@@ -0,0 +1,1674 @@
+<?
+# See skin.doc
+
+# These are the INTERNAL names, which get mapped
+# directly to class names.  For display purposes, the
+# Language class has internationalized names
+#
+/* private */ $wgValidSkinNames = array(
+       "Standard", "Nostalgia", "CologneBlue"
+);
+
+class RecentChangesClass {
+       var $secureName , $displayName , $link , $namespace ;
+       var $oldid , $diffid , $timestamp , $curlink , $lastlink , $usertalklink , $versionlink ;
+       var $usercomment , $userlink ;
+       var $isminor , $isnew , $watched , $islog ;
+       } ;
+
+class Skin {
+
+       /* private */ var $lastdate, $lastline;
+
+       var $rc_cache ; # Cache for Enhanced Recent Changes
+       var $rccc ; # Recent Changes Cache Counter for visibility toggle
+
+
+       function Skin()
+       {
+       }
+
+       function getSkinNames()
+       {
+               global $wgValidSkinNames;
+               return $wgValidSkinNames;
+       }
+
+       function getStylesheet()
+       {
+               return "wikistandard.css";
+       }
+
+       function qbSetting()
+       {
+               global $wgOut, $wgUser;
+
+               if ( $wgOut->isQuickbarSupressed() ) { return 0; }
+               $q = $wgUser->getOption( "quickbar" );
+               if ( "" == $q ) { $q = 0; }
+               return $q;
+       }
+
+       function initPage()
+       {
+               global $wgOut, $wgStyleSheetPath;
+               wfProfileIn( "Skin::initPage" );
+
+               $wgOut->addLink( "shortcut icon", "", "/favicon.ico" );
+               if ( $wgOut->isPrintable() ) { $ss = "wikiprintable.css"; }
+               else { $ss = $this->getStylesheet(); }
+               $wgOut->addLink( "stylesheet", "", "{$wgStyleSheetPath}/{$ss}" );
+               wfProfileOut();
+       }
+
+       function getHeadScripts() {
+               $r = "
+<SCRIPT TYPE=\"text/javascript\">
+function toggleVisibility( _levelId, _otherId, _linkId) {
+       var thisLevel = document.getElementById( _levelId );
+       var otherLevel = document.getElementById( _otherId );
+       var linkLevel = document.getElementById( _linkId );
+       if ( thisLevel.style.display == 'none' ) {
+               thisLevel.style.display = 'block';
+               otherLevel.style.display = 'none';
+               linkLevel.style.display = 'inline';
+       } else {
+               thisLevel.style.display = 'none';
+               otherLevel.style.display = 'inline';
+               linkLevel.style.display = 'none';
+               }
+       }
+</SCRIPT>
+               " ;
+               return $r;
+       }
+
+       function getUserStyles()
+       {
+               $s = "<style type='text/css' media='screen'><!--\n";
+               $s .= $this->doGetUserStyles();
+               $s .= "//--></style>\n";
+               return $s;
+       }
+
+       function doGetUserStyles()
+       {
+               global $wgUser;
+
+               $s = "";
+               if ( 1 == $wgUser->getOption( "underline" ) ) {
+                       $s .= "a.stub, a.new, a.internal, a.external { " .
+                         "text-decoration: underline; }\n";
+               } else {
+                       $s .= "a.stub, a.new, a.internal, a.external { " .
+                         "text-decoration: none; }\n";
+               }
+               if ( 1 == $wgUser->getOption( "highlightbroken" ) ) {
+                       $s .= "a.new { color: #CC2200; }\n" .
+                         "#quickbar a.new { color: CC2200; }\n";
+               }
+               if ( 1 == $wgUser->getOption( "justify" ) ) {
+                       $s .= "#article { text-align: justify; }\n";
+               }
+               return $s;
+       }
+
+       function getBodyOptions()
+       {
+               global $wgUser, $wgTitle, $wgNamespaceBackgrounds, $wgOut, $oldid, $redirect, $diff,$action;
+
+               if ( 0 != $wgTitle->getNamespace() ) {
+                       $a = array( "bgcolor" => "#FFFFDD" );
+               }
+               else $a = array( "bgcolor" => "#FFFFFF" );
+               if($wgOut->isArticle() && $wgUser->getOption("editondblclick")
+                       && 
+                       (!$wgTitle->isProtected() || $wgUser->isSysop())
+                       
+                       ) {
+                       $n = $wgTitle->getPrefixedURL();
+                       $t = wfMsg( "editthispage" );
+                       $oid = $red = "";
+                       if ( $redirect ) { $red = "&redirect={$redirect}"; }
+                       if ( $oldid && ! isset( $diff ) ) {
+                               $oid = "&oldid={$oldid}";
+                       }
+                       $s = wfLocalUrlE($n,"action=edit{$oid}{$red}");
+                       $s = "document.location = \"" .$s ."\";";
+                       $a += array ("ondblclick" => $s);
+
+               }
+               if($action=="edit") { # set focus in edit box
+                       $a += array("onLoad"=>"document.editform.wpTextbox1.focus()");  
+               }
+               return $a;
+       }
+
+       function getExternalLinkAttributes( $link, $text )
+       {
+               global $wgUser, $wgOut, $wgLang;
+
+               $link = urldecode( $link );
+               $link = $wgLang->checkTitleEncoding( $link );
+               $link = str_replace( "_", " ", $link );
+               $link = wfEscapeHTML( $link );
+
+               if ( $wgOut->isPrintable() ) { $r = " class='printable'"; }
+               else { $r = " class='external'"; }
+
+               if ( 1 == $wgUser->getOption( "hover" ) ) {
+                       $r .= " title=\"{$link}\"";
+               }
+               return $r;
+       }
+
+       function getInternalLinkAttributes( $link, $text, $broken = false )
+       {
+               global $wgUser, $wgOut;
+
+               $link = urldecode( $link );
+               $link = str_replace( "_", " ", $link );
+               $link = wfEscapeHTML( $link );
+
+               if ( $wgOut->isPrintable() ) { $r = " class='printable'"; }
+                else if ( $broken == "stub" ) { $r = " class='stub'"; }
+               else if ( $broken == "yes" ) { $r = " class='new'"; }
+               else { $r = " class='internal'"; }
+
+               if ( 1 == $wgUser->getOption( "hover" ) ) {
+                       $r .= " title=\"{$link}\"";
+               }
+               return $r;
+       }
+
+       function getLogo()
+       {
+               global $wgLogo;
+               return $wgLogo;
+       }
+
+       # This will be called immediately after the <body> tag.  Split into
+       # two functions to make it easier to subclass.
+       #
+       function beforeContent()
+       {
+               global $wgUser, $wgOut;
+
+               if ( $wgOut->isPrintable() ) {
+                       $s = $this->pageTitle() . $this->pageSubtitle() . "\n";
+                       $s .= "\n<div class='bodytext'>";
+                       return $s;
+               }
+               return $this->doBeforeContent();
+       }
+
+       function doBeforeContent()
+       {
+               global $wgUser, $wgOut, $wgTitle;
+               wfProfileIn( "Skin::doBeforeContent" );
+
+               $s = "";
+               $qb = $this->qbSetting();
+
+               if( $langlinks = $this->otherLanguages() ) {
+                       $rows = 2;
+                       $borderhack = "";
+               } else {
+                       $rows = 1;
+                       $langlinks = false;
+                       $borderhack = "class='top'";
+               }
+
+               $s .= "\n<div id='content'>\n<div id='topbar'>" .
+                 "<table width='98%' border=0 cellspacing=0><tr>";
+
+               if ( 0 == $qb ) {
+                       $s .= "<td class='top' align=left valign=top rowspan='{$rows}'>" .
+                         $this->logoText() . "</td>";
+               } else if ( 1 == $qb || 3 == $qb ) { # Left
+                       $s .= $this->getQuickbarCompensator( $rows );
+               }
+               $s .= "<td {$borderhack} align=left valign=top>";
+
+               $s .= $this->topLinks() ;
+               $s .= "<p class='subtitle'>" . $this->pageTitleLinks();
+
+               $s .= "</td>\n<td {$borderhack} valign=top align=right nowrap>";
+               $s .= $this->nameAndLogin();
+               $s .= "\n<br>" . $this->searchForm() . "</td>";
+
+               if ( $langlinks ) {
+                       $s .= "</tr>\n<tr><td class='top' colspan=\"2\">$langlinks</td>";
+               }
+
+               if ( 2 == $qb ) { # Right
+                       $s .= $this->getQuickbarCompensator( $rows );
+               }
+               $s .= "</tr></table>\n</div>\n";
+               $s .= "\n<div id='article'>";
+
+               $s .= $this->pageTitle();
+               $s .= $this->pageSubtitle() . "\n<p>";
+               wfProfileOut();
+               return $s;
+       }
+
+       function getQuickbarCompensator( $rows = 1 )
+       {
+               return "<td width='152' rowspan='{$rows}'>&nbsp;</td>";
+       }
+
+       # This gets called immediately before the </body> tag.
+       #
+       function afterContent()
+       {
+               global $wgUser, $wgOut, $wgServer, $HTTP_SERVER_VARS;
+
+               if ( $wgOut->isPrintable() ) {
+                       $s = "\n</div>\n";
+
+                       $u = $wgServer . $HTTP_SERVER_VARS['REQUEST_URI'];
+                       $u = preg_replace( "/[?&]printable=yes/", "", $u );
+                       $rf = str_replace( "$1", $u, wfMsg( "retrievedfrom" ) );
+
+                       if ( $wgOut->isArticle() ) {
+                               $lm = "<br>" . $this->lastModified();
+                       } else { $lm = ""; }
+
+                       $s .= "<p><em>{$rf}{$lm}</em>\n";
+                       return $s;
+               }
+               return $this->doAfterContent();
+       }
+
+       function doAfterContent()
+       {
+               global $wgUser, $wgOut;
+               wfProfileIn( "Skin::doAfterContent" );
+
+               $s = "\n</div><br clear=all>\n";
+
+               $s .= "\n<div id='footer'>";
+               $s .= "<table width='98%' border=0 cellspacing=0><tr>";
+
+               $qb = $this->qbSetting();
+               if ( 1 == $qb || 3 == $qb ) { # Left
+                       $s .= $this->getQuickbarCompensator();
+               }
+               $s .= "<td class='bottom' align=left valign=top>";
+
+               $s .= $this->bottomLinks();
+               $s .= "\n<br>" . $this->mainPageLink()
+                 . " | " . $this->aboutLink()
+                 . " | " . $this->specialLink( "recentchanges" )
+                 . " | " . $this->searchForm()
+                 . "<br>" . $this->pageStats();
+
+               $s .= "</td>";
+               if ( 2 == $qb ) { # Right
+                       $s .= $this->getQuickbarCompensator();
+               }
+               $s .= "</tr></table>\n</div>\n</div>\n";
+
+               if ( 0 != $qb ) { $s .= $this->quickBar(); }
+               wfProfileOut();
+               return $s;
+       }
+
+       function pageTitleLinks()
+       {
+               global $wgOut, $wgTitle, $oldid, $action, $diff, $wgUser, $wgLang;
+
+               $s = $this->printableLink();
+
+               if ( $wgOut->isArticle() ) {
+                       if ( $wgTitle->getNamespace() == Namespace::getImage() ) {
+                               $name = $wgTitle->getDBkey();
+                               $link = wfEscapeHTML( wfImageUrl( $name ) );
+                               $style = $this->getInternalLinkAttributes( $link, $name );
+                               $s .= " | <a href=\"{$link}\"{$style}>{$name}</a>";
+                       }
+               }
+               if ( "history" == $action || isset( $diff ) || isset( $oldid ) ) {
+                       $s .= " | " . $this->makeKnownLink( $wgTitle->getPrefixedText(),
+                         wfMsg( "currentrev" ) );
+               }
+
+               if ( $wgUser->getNewtalk() ) {
+                       # do not show "You have new messages" text when we are viewing our 
+                       # own talk page 
+                       
+                       if(!(strcmp($wgTitle->getText(),$wgUser->getName()) == 0 &&
+                            $wgTitle->getNamespace()==Namespace::getTalk(Namespace::getUser()))) {
+                               $n =$wgUser->getName();
+                               $tl = $this->makeKnownLink( $wgLang->getNsText(
+                               Namespace::getTalk( Namespace::getUser() ) ) . ":{$n}",
+                               wfMsg("newmessageslink") );
+                               $s.=" | <strong>". str_replace( "$1", $tl, wfMsg("newmessages") ) . "</strong>";
+                       }
+               }
+               return $s;
+       }
+
+       function printableLink()
+       {
+               global $wgOut, $wgTitle, $oldid, $action;
+
+               if ( "history" == $action ) { $q = "action=history&"; }
+               else { $q = ""; }
+
+               $s = $this->makeKnownLink( $wgTitle->getPrefixedText(),
+                 WfMsg( "printableversion" ), "{$q}printable=yes" );
+               return $s;
+       }
+
+       function pageTitle()
+       {
+               global $wgOut, $wgTitle;
+
+               $s = "<h1 class='pagetitle'>" . $wgOut->getPageTitle() . "</h1>";
+               return $s;
+       }
+
+       function pageSubtitle()
+       {
+               global $wgOut,$wgTitle,$wgNamespacesWithSubpages;
+
+               $sub = $wgOut->getSubtitle();
+               if ( "" == $sub ) { $sub = wfMsg( "fromwikipedia" ); }
+               if($wgOut->isArticle() && $wgNamespacesWithSubpages[$wgTitle->getNamespace()]) {
+                       $ptext=$wgTitle->getPrefixedText();                     
+                       if(preg_match("/\//",$ptext)) {                         
+                               $sub.="</p><p class='subpages'>";       
+                               $links=explode("/",$ptext);
+                               $c=0;
+                               $growinglink="";
+                               foreach($links as $link) {
+                                       $c++;
+                                       if ($c<count($links)) {                                         
+                                               $growinglink.=$link;
+                                               $getlink=$this->makeLink($growinglink,$link);                                           
+                                               if(preg_match("/class='new'/i",$getlink)) { break; } # this is a hack, but it saves time
+                                               if ($c>1) { 
+                                                       $sub .= " | ";
+                                               } else  {
+                                                       $sub .="&lt; ";
+                                               }
+                                               $sub .= $getlink;
+                                               $growinglink.="/";
+                                       }
+                                       
+                               }
+                       }
+               }
+               $s = "<p class='subtitle'>{$sub}\n";            
+               return $s;
+       }
+
+       function nameAndLogin()
+       {
+               global $wgUser, $wgTitle, $wgLang;
+
+               $li = $wgLang->specialPage( "Userlogin" );
+               $lo = $wgLang->specialPage( "Userlogout" );
+
+               $s = "";
+               if ( 0 == $wgUser->getID() ) {
+                       $n = getenv( "REMOTE_ADDR" );
+                       $rt = $wgTitle->getPrefixedURL();
+                       if ( 0 == strcasecmp( urlencode( $lo ), $rt ) ) {
+                               $q = "";
+                       } else { $q = "returnto={$rt}"; }
+
+                         
+                       $tl = $this->makeKnownLink( $wgLang->getNsText(
+                         Namespace::getTalk( Namespace::getUser() ) ) . ":{$n}",
+                         $wgLang->getNsText( Namespace::getTalk( 0 ) ) );
+                         
+                       $s .= $n .  " (".$tl.")" . "\n<br>" . $this->makeKnownLink( $li,
+                         wfMsg( "login" ), $q );
+                         
+                       $tl = " ({$tl})"; 
+                       
+               } else {
+                       $n = $wgUser->getName();
+                       $rt = $wgTitle->getPrefixedURL();
+                       $tl = $this->makeKnownLink( $wgLang->getNsText(
+                         Namespace::getTalk( Namespace::getUser() ) ) . ":{$n}",
+                         $wgLang->getNsText( Namespace::getTalk( 0 ) ) );
+
+                       $tl = " ({$tl})"; 
+                       
+                       $s .= $this->makeKnownLink( $wgLang->getNsText(
+                         Namespace::getUser() ) . ":{$n}", $n ) . "{$tl}<br>" .
+                         $this->makeKnownLink( $lo, wfMsg( "logout" ),
+                         "returnto={$rt}" ) . " | " .
+                         $this->specialLink( "preferences" );
+               }
+               $s .= " | " . $this->makeKnownLink( wfMsg( "helppage" ),
+                 wfMsg( "help" ) ); 
+
+               return $s;
+       }
+
+       function searchForm()
+       {
+               global $search;
+               $s = "<form id=\"search\" class=\"inline\" method=\"get\" action=\""
+                 . wfLocalUrl( "" ) . "\">"
+                 . "<input type=text name=\"search\" size=19 value=\""
+                 . htmlspecialchars(substr($search,0,256)) . "\">\n"
+                 . "<input type=submit value=\"" . wfMsg( "search" )
+                 . "\">&nbsp;<input type=submit name=\"go\" value=\""
+                 . wfMsg ("go") . "\"></form>";                  
+
+               return $s;
+       }
+
+       function topLinks()
+       {
+               global $wgOut;
+               $sep = " |\n";
+
+               $s = $this->mainPageLink() . $sep
+                 . $this->specialLink( "recentchanges" );
+
+               if ( $wgOut->isArticle() ) {
+                       $s .=  $sep . $this->editThisPage()
+                         . $sep . $this->historyLink();
+               }
+               $s .= $sep . $this->specialPagesList();
+
+               return $s;
+       }
+
+       function bottomLinks()
+       { 
+               global $wgOut, $wgUser, $wgTitle;
+               $sep = " |\n";
+
+               $s = "";
+               if ( $wgOut->isArticle() ) {
+                       $s .= "<strong>" . $this->editThisPage() . "</strong>";
+                       if ( 0 != $wgUser->getID() ) {
+                               $s .= $sep . $this->watchThisPage();
+                       }
+                       $s .= $sep . $this->talkLink()
+                         . $sep . $this->historyLink()
+                         . $sep . $this->whatLinksHere()
+                         . $sep . $this->watchPageLinksLink();
+
+                       if ( $wgTitle->getNamespace() == Namespace::getUser()
+                           || $wgTitle->getNamespace() == Namespace::getTalk(Namespace::getUser()) )
+                           
+                       {       
+                               $id=User::idFromName($wgTitle->getText());
+                               $ip=User::isIP($wgTitle->getText());
+                               
+                               if($id || $ip) { # both anons and non-anons have contri list
+                                       $s .= $sep . $this->userContribsLink();
+                               }
+                               if ( 0 != $wgUser->getID() ) { # show only to signed in users
+                                       if($id) {       # can only email non-anons
+                                               $s .= $sep . $this->emailUserLink();
+                                       }
+                               }
+                       }
+                       if ( $wgUser->isSysop() && $wgTitle->getArticleId() ) {
+                               $s .= "\n<br>" . $this->deleteThisPage() .
+                               $sep . $this->protectThisPage() .
+                               $sep . $this->moveThisPage();
+                       }
+                       $s .= "<br>\n" . $this->otherLanguages();
+               }
+               return $s;
+       }
+
+       function pageStats()
+       {
+               global $wgOut, $wgLang, $wgArticle;
+               global $oldid, $diff;
+
+               if ( ! $wgOut->isArticle() ) { return ""; }
+               if ( isset( $oldid ) || isset( $diff ) ) { return ""; }
+               if ( 0 == $wgArticle->getID() ) { return ""; }
+
+               $count = $wgArticle->getCount();
+               $s = str_replace( "$1", $count, wfMsg( "viewcount" ) );
+
+               $s .= $this->lastModified();
+               $s .= " ".wfMsg( "gnunote" ) ;
+               return "<span id='pagestats'>{$s}</span>";
+       }
+
+       function lastModified()
+       {
+               global $wgLang, $wgArticle;
+
+               $d = $wgLang->timeanddate( $wgArticle->getTimestamp(), true );
+               $s = " " . str_replace( "$1", $d, wfMsg( "lastmodified" ) );
+               return $s;
+       }
+
+       function logoText( $align = "" )
+       {
+               if ( "" != $align ) { $a = " align='{$align}'"; }
+               else { $a = ""; }
+
+               $mp = wfMsg( "mainpage" );
+               $s = "<a href=\"" . wfLocalUrlE( $mp ) . "\"><img{$a} border=0 src=\""
+                 . $this->getLogo() . "\" alt=\"" . "[{$mp}]\"></a>";
+               return $s;
+       }
+
+       function quickBar()
+       {
+               global $wgOut, $wgTitle, $wgUser, $action, $wgLang;
+               global $wpPreview;
+               wfProfileIn( "Skin::quickBar" );
+
+               $s = "\n<div id='quickbar'>";
+               $s .= "\n" . $this->logoText() . "\n<hr>";
+
+               $sep = "\n<br>";
+               $s .= $this->mainPageLink()
+                 . $sep . $this->specialLink( "recentchanges" )
+                 . $sep . $this->specialLink( "randompage" );
+               if ($wgUser->getID()) { 
+               $s.= $sep . $this->specialLink( "watchlist" ) ; 
+               $s .= $sep .$this->makeKnownLink( $wgLang->specialPage( "Contributions" ),
+                 wfMsg( "mycontris" ), "target=" . wfUrlencode($wgUser->getName() ) );         
+               
+               }
+               // only show watchlist link if logged in
+                if ( wfMsg ( "currentevents" ) != "-" ) $s .= $sep . $this->makeKnownLink( wfMsg( "currentevents" ), "" ) ;
+                $s .= "\n<hr>";
+               $articleExists = $wgTitle->getArticleId();
+               if ( $wgOut->isArticle() || $action =="edit" || $action =="history" || $wpPreview) {
+                                               
+                       if($wgOut->isArticle()) {
+                               $s .= "<strong>" . $this->editThisPage() . "</strong>";
+                       } else { # backlink to the article in edit or history mode
+
+                               if($articleExists){ # no backlink if no article
+                                       $tns=$wgTitle->getNamespace();          
+                                       switch($tns) {
+                                               case 0:
+                                               $text = wfMsg("articlepage");
+                                               break;
+                                               case 1:
+                                               $text = wfMsg("viewtalkpage");
+                                               break;
+                                               case 2:
+                                               $text = wfMsg("userpage");                              
+                                               break;
+                                               case 3:
+                                               $text = wfMsg("viewtalkpage");
+                                               break;  
+                                               case 4: 
+                                               $text = wfMsg("wikipediapage");
+                                               break;
+                                               case 5:                         
+                                               $text = wfMsg("viewtalkpage");
+                                               break;
+                                               case 6:
+                                               $text = wfMsg("imagepage");
+                                               break;
+                                               case 7:
+                                               $text = wfMsg("viewtalkpage");
+                                               break;
+                                               default:
+                                               $text= wfMsg("articlepage");
+                                       }
+                               
+                                       $link = $wgTitle->getText();
+                                       if ($nstext = $wgLang->getNsText($tns) ) { # add namespace if necessary
+                                               $link = $nstext . ":" . $link ;
+                                       }                       
+                                       $s .= $this->makeLink($link, $text );                   
+                               } elseif( $wgTitle->getNamespace() != Namespace::getSpecial() ) {
+                                       # we just throw in a "New page" text to tell the user that he's in edit mode,
+                                       # and to avoid messing with the separator that is prepended to the next item
+                                       $s .= "<strong>" . wfMsg("newpage") . "</strong>";
+                               }
+                       
+                       }
+                       
+                       /*
+                       watching could cause problems in edit mode:
+                       if user edits article, then loads "watch this article" in background and then saves
+                       article with "Watch this article" checkbox disabled, the article is transparently
+                       unwatched. Therefore we do not show the "Watch this page" link in edit mode
+                       */                      
+                       if ( 0 != $wgUser->getID() && $articleExists) {
+                               if($action!="edit" && $action!="history" &&
+                                   $action != "submit" ) 
+                               {$s .= $sep . $this->watchThisPage(); }
+                               if ( $wgTitle->userCanEdit() ) $s .= $sep . $this->moveThisPage();
+                       }
+                       if ( $wgUser->isSysop() and $articleExists ) {
+                               $s .= $sep . $this->deleteThisPage() .
+                               $sep . $this->protectThisPage();
+                       }
+                       $s .= $sep . $this->talkLink();
+                       if ($articleExists && $action !="history") { $s .= $sep . $this->historyLink();}
+                       $s.=$sep . $this->whatLinksHere();
+                       
+                       if($wgOut->isArticle()) {
+                               $s .= $sep . $this->watchPageLinksLink();
+                       }
+
+                       if ( Namespace::getUser() == $wgTitle->getNamespace() 
+                       || $wgTitle->getNamespace() == Namespace::getTalk(Namespace::getUser())
+                       ) {
+                       
+                               $id=User::idFromName($wgTitle->getText());
+                               $ip=User::isIP($wgTitle->getText());
+                               
+                               if($id||$ip) {
+                                       $s .= $sep . $this->userContribsLink();
+                               }
+                               if ( 0 != $wgUser->getID() ) {
+                                       if($id) { # can only email real users
+                                               $s .= $sep . $this->emailUserLink(); 
+                                       }
+                               }
+                       }
+                       $s .= "\n<hr>";
+               } 
+               
+               if ( 0 != $wgUser->getID() ) {
+                       $s .= $this->specialLink( "upload" ) . $sep;
+               }
+               $s .= $this->specialLink( "specialpages" )
+                 . $sep . $this->bugReportsLink();
+
+               $s .= "\n</div>\n";
+               wfProfileOut();
+               return $s;
+       }
+
+       function specialPagesList()
+       {
+               global $wgUser, $wgOut, $wgLang, $wgServer, $wgRedirectScript;
+               $a = array();
+
+               $validSP = $wgLang->getValidSpecialPages();
+
+               foreach ( $validSP as $name => $desc ) {
+                       if ( "" == $desc ) { continue; }
+                       $a[$name] = $desc;
+               }
+               if ( $wgUser->isSysop() )
+               { 
+                       $sysopSP = $wgLang->getSysopSpecialPages();
+
+                       foreach ( $sysopSP as $name => $desc ) {
+                               if ( "" == $desc ) { continue; }
+                               $a[$name] = $desc ;
+                       }
+               }
+               if ( $wgUser->isDeveloper() )
+               { 
+                       $devSP = $wgLang->getDeveloperSpecialPages();
+
+                       foreach ( $devSP as $name => $desc ) {
+                               if ( "" == $desc ) { continue; }
+                               $a[$name] = $desc ;
+                       }
+               }
+               $go = wfMsg( "go" );
+               $sp = wfMsg( "specialpages" );
+               $spp = $wgLang->specialPage( "Specialpages" );
+
+               $s = "<form id=\"specialpages\" method=\"get\" class=\"inline\" " .
+                 "action=\"{$wgServer}{$wgRedirectScript}\">\n";
+               $s .= "<select name=\"wpDropdown\">\n";
+               $s .= "<option value=\"{$spp}\">{$sp}</option>\n";
+
+               foreach ( $a as $name => $desc ) {
+                       $p = $wgLang->specialPage( $name );
+                       $s .= "<option value=\"{$p}\">{$desc}</option>\n";
+               }
+               $s .= "</select>\n";
+               $s .= "<input type=submit value=\"{$go}\" name=redirect>\n";
+               $s .= "</form>\n";
+               return $s;
+       }
+
+       function mainPageLink()
+       {
+               $mp = wfMsg( "mainpage" );
+               $s = $this->makeKnownLink( $mp, $mp );
+               return $s;
+       }
+
+       function copyrightLink()
+       {
+               $s = $this->makeKnownLink( wfMsg( "copyrightpage" ),
+                 wfMsg( "copyrightpagename" ) );
+               return $s;
+       }
+
+       function aboutLink()
+       {
+               $s = $this->makeKnownLink( wfMsg( "aboutpage" ),
+                 wfMsg( "aboutwikipedia" ) );
+               return $s;
+       }
+
+       function editThisPage()
+       {
+               global $wgOut, $wgTitle, $oldid, $redirect, $diff;
+
+               if ( ! $wgOut->isArticle() || $diff ) {
+                       $s = wfMsg( "protectedpage" );
+               } else if ( $wgTitle->userCanEdit() ) {
+                       $n = $wgTitle->getPrefixedText();
+                       $t = wfMsg( "editthispage" );
+                       $oid = $red = "";
+
+                       if ( $redirect ) { $red = "&redirect={$redirect}"; }
+                       if ( $oldid && ! isset( $diff ) ) {
+                               $oid = "&oldid={$oldid}";
+                       }
+                       $s = $this->makeKnownLink( $n, $t, "action=edit{$oid}{$red}" );
+               } else {
+                       $s = wfMsg( "protectedpage" );
+               }
+               return $s;
+       }
+
+       function deleteThisPage()
+       {
+               global $wgUser, $wgOut, $wgTitle, $diff;
+
+               if ( $wgTitle->getArticleId() && ( ! $diff ) && $wgUser->isSysop() ) {
+                       $n = $wgTitle->getPrefixedText();
+                       $t = wfMsg( "deletethispage" );
+
+                       $s = $this->makeKnownLink( $n, $t, "action=delete" );
+               } else {
+                       $s = wfMsg( "error" );
+               }
+               return $s;
+       }
+
+       function protectThisPage()
+       {
+               global $wgUser, $wgOut, $wgTitle, $diff;
+
+               if ( $wgTitle->getArticleId() && ( ! $diff ) && $wgUser->isSysop() ) {
+                       $n = $wgTitle->getPrefixedText();
+
+                       if ( $wgTitle->isProtected() ) {
+                               $t = wfMsg( "unprotectthispage" );
+                               $q = "action=unprotect";
+                       } else {
+                               $t = wfMsg( "protectthispage" );
+                               $q = "action=protect";
+                       }
+                       $s = $this->makeKnownLink( $n, $t, $q );
+               } else {
+                       $s = wfMsg( "error" );
+               }
+               return $s;
+       }
+
+       function watchThisPage()
+       {
+               global $wgUser, $wgOut, $wgTitle, $diff;
+
+               if ( $wgOut->isArticle() && ( ! $diff ) ) {
+                       $n = $wgTitle->getPrefixedText();
+
+                       if ( $wgTitle->userIsWatching() ) {
+                               $t = wfMsg( "unwatchthispage" );
+                               $q = "action=unwatch";
+                       } else {
+                               $t = wfMsg( "watchthispage" );
+                               $q = "action=watch";
+                       }
+                       $s = $this->makeKnownLink( $n, $t, $q );
+               } else {
+                       $s = wfMsg( "notanarticle" );
+               }
+               return $s;
+       }
+
+       function moveThisPage()
+       {
+               global $wgTitle, $wgLang;
+
+               if ( $wgTitle->userCanEdit() ) {
+                       $s = $this->makeKnownLink( $wgLang->specialPage( "Movepage" ),
+                         wfMsg( "movethispage" ), "target=" . $wgTitle->getPrefixedURL() );
+               } // no message if page is protected - would be redundant
+               return $s;
+       }
+
+       function historyLink()
+       {
+               global $wgTitle;
+
+               $s = $this->makeKnownLink( $wgTitle->getPrefixedText(),
+                 wfMsg( "history" ), "action=history" );
+               return $s;
+       }
+
+       function whatLinksHere()
+       {
+               global $wgTitle, $wgLang;
+
+               $s = $this->makeKnownLink( $wgLang->specialPage( "Whatlinkshere" ),
+                 wfMsg( "whatlinkshere" ), "target=" . $wgTitle->getPrefixedURL() );
+               return $s;
+       }
+
+       function userContribsLink()
+       {
+               global $wgTitle, $wgLang;
+
+               $s = $this->makeKnownLink( $wgLang->specialPage( "Contributions" ),
+                 wfMsg( "contributions" ), "target=" . $wgTitle->getURL() );
+               return $s;
+       }
+
+       function emailUserLink()
+       {
+               global $wgTitle, $wgLang;
+
+               $s = $this->makeKnownLink( $wgLang->specialPage( "Emailuser" ),
+                 wfMsg( "emailuser" ), "target=" . $wgTitle->getURL() );
+               return $s;
+       }
+
+       function watchPageLinksLink()
+       {
+               global $wgOut, $wgTitle, $wgLang;
+
+               if ( ! $wgOut->isArticle() ) {
+                       $s = "(" . wfMsg( "notanarticle" ) . ")";
+               } else {
+                       $s = $this->makeKnownLink( $wgLang->specialPage(
+                         "Recentchangeslinked" ), wfMsg( "recentchangeslinked" ),
+                         "target=" . $wgTitle->getPrefixedURL() );
+               }
+               return $s;
+       }
+
+       function otherLanguages()
+       {
+               global $wgOut, $wgLang, $wgTitle , $wgUseNewInterlanguage ;
+
+               $a = $wgOut->getLanguageLinks();
+               if ( 0 == count( $a ) ) {
+                       if ( !$wgUseNewInterlanguage ) return "";
+                       $ns = $wgLang->getNsIndex ( $wgTitle->getNamespace () ) ;
+                       if ( $ns != 0 AND $ns != 1 ) return "" ;
+                       $pn = "Intl" ;
+                       $x = "mode=addlink&xt=".$wgTitle->getDBkey() ;
+                       return $this->makeKnownLink( $wgLang->specialPage( $pn ),
+                                 wfMsg( "intl" ) , $x );
+                       }
+
+               if ( !$wgUseNewInterlanguage ) {
+                       $s = wfMsg( "otherlanguages" ) . ": ";
+               } else {
+                       global $wgLanguageCode ;
+                       $x = "mode=zoom&xt=".$wgTitle->getDBkey() ;
+                       $x .= "&xl=".$wgLanguageCode ;
+                       $s =  $this->makeKnownLink( $wgLang->specialPage( "Intl" ),
+                                 wfMsg( "otherlanguages" ) , $x ) . ": " ;
+                       }
+
+               $first = true;
+               foreach( $a as $l ) {
+                       if ( ! $first ) { $s .= " | "; }
+                       $first = false;
+
+                       $nt = Title::newFromText( $l );
+                       $url = $nt->getFullURL();
+                       $text = $wgLang->getLanguageName( $nt->getInterwiki() );
+
+                       if ( "" == $text ) { $text = $l; }
+                       $style = $this->getExternalLinkAttributes( $l, $text );
+                       $s .= "<a href=\"{$url}\"{$style}>{$text}</a>";
+               }
+               return $s;
+       }
+
+       function bugReportsLink()
+       {
+               $s = $this->makeKnownLink( wfMsg( "bugreportspage" ),
+                 wfMsg( "bugreports" ) );
+               return $s;
+       }
+
+       function dateLink()
+       {
+               global $wgLinkCache;
+               $t1 = Title::newFromText( date( "F j" ) );
+               $t2 = Title::newFromText( date( "Y" ) );
+
+               $wgLinkCache->suspend();
+               $id = $t1->getArticleID();
+               $wgLinkCache->resume();
+
+               if ( 0 == $id ) {
+                       $s = $this->makeBrokenLink( $t1->getText() );
+               } else {
+                       $s = $this->makeKnownLink( $t1->getText() );
+               }
+               $s .= ", ";
+
+               $wgLinkCache->suspend();
+               $id = $t2->getArticleID();
+               $wgLinkCache->resume();
+
+               if ( 0 == $id ) {
+                       $s .= $this->makeBrokenLink( $t2->getText() );
+               } else {
+                       $s .= $this->makeKnownLink( $t2->getText() );
+               }
+               return $s;
+       }
+
+       function talkLink()
+       {
+               global $wgLang, $wgTitle, $wgLinkCache;
+
+               $tns = $wgTitle->getNamespace();
+               if ( -1 == $tns ) { return ""; }
+
+               $pn = $wgTitle->getText();
+               $tp = wfMsg( "talkpage" );              
+               if ( Namespace::isTalk( $tns ) ) {
+                       $lns = Namespace::getSubject( $tns );
+                       switch($tns) {
+                               case 1:
+                               $text = wfMsg("articlepage");
+                               break;
+                               case 3:
+                               $text = wfMsg("userpage");
+                               break;
+                               case 5: 
+                               $text = wfMsg("wikipediapage");
+                               break;
+                               case 7:
+                               $text = wfMsg("imagepage");
+                               break;
+                               default:
+                               $text= wfMsg("articlepage");
+                       }
+               } else {
+                       
+                       $lns = Namespace::getTalk( $tns );
+                       $text=$tp;                      
+               }
+               $n = $wgLang->getNsText( $lns );
+               if ( "" == $n ) { $link = $pn; }
+               else { $link = "{$n}:{$pn}"; }
+
+               $wgLinkCache->suspend();
+               $s = $this->makeLink( $link, $text );
+               $wgLinkCache->resume();
+
+               return $s;
+       }
+
+       # After all the page content is transformed into HTML, it makes
+       # a final pass through here for things like table backgrounds.
+       #
+       function transformContent( $text )
+       {
+               return $text;
+       }
+
+       # Note: This function MUST call getArticleID() on the link,
+       # otherwise the cache won't get updated properly.  See LINKCACHE.DOC.
+       #
+       function makeLink( $title, $text= "", $query = "", $trail = "" )
+       {
+               global $wgOut, $wgUser;
+
+               $nt = Title::newFromText( $title );
+
+               if ( $nt->isExternal() ) {
+                       $u = $nt->getFullURL();
+                       if ( "" == $text ) { $text = $nt->getPrefixedText(); }
+                       $style = $this->getExternalLinkAttributes( $link, $text );
+
+                       $inside = "";
+                       if ( "" != $trail ) {
+                               if ( preg_match( "/^([a-z]+)(.*)$$/sD", $trail, $m ) ) {
+                                       $inside = $m[1];
+                                       $trail = $m[2];
+                               }
+                       }
+                       return "<a href=\"{$u}\"{$style}>{$text}{$inside}</a>{$trail}";
+               }
+               if ( 0 == $nt->getNamespace() && "" == $nt->getText() ) {
+                       return $this->makeKnownLink( $title, $text, $query, $trail );
+               }
+               if ( ( -1 == $nt->getNamespace() ) ||
+          ( Namespace::getImage() == $nt->getNamespace() ) ) {
+                       return $this->makeKnownLink( $title, $text, $query, $trail );
+               }
+                $aid = $nt->getArticleID() ;
+                if ( 0 == $aid ) {
+                        return $this->makeBrokenLink( $title, $text, $query, $trail );
+                } else {
+                        $threshold = $wgUser->getOption("stubthreshold") ;
+                        if ( $threshold > 0 ) {
+                                $res = wfQuery ( "SELECT HIGH_PRIORITY length(cur_text) AS x, cur_namespace, cur_is_redirect FROM cur WHERE cur_id='{$aid}'" ) ;
+
+                                if ( wfNumRows( $res ) > 0 ) {
+                                        $s = wfFetchObject( $res );
+                                        $size = $s->x;
+                                        if ( $s->cur_is_redirect OR $s->cur_namespace != 0 )
+                                                $size = $threshold*2 ; # Really big
+                                        wfFreeResult( $res );
+                                } else $size = $threshold*2 ; # Really big
+                        } else $size = 1 ;
+
+                        if ( $size < $threshold )
+                                return $this->makeStubLink( $title, $text, $query, $trail );
+                        return $this->makeKnownLink( $title, $text, $query, $trail );
+                }
+        }
+
+       function makeKnownLink( $title, $text = "", $query = "", $trail = "" )
+       {
+               global $wgOut, $wgTitle;
+
+               $nt = Title::newFromText( $title );
+               $link = $nt->getPrefixedURL();
+
+               if ( "" == $link ) {
+                       $u = "";
+                       if ( "" == $text ) { $text = $nt->getFragment(); }
+               } else {
+                       $u = wfLocalUrlE( $link, $query );
+               }
+               if ( "" != $nt->getFragment() ) {
+                       $u .= "#" . wfEscapeHTML( $nt->getFragment() );
+               }
+               if ( "" == $text ) { $text = $nt->getPrefixedText(); }
+               $style = $this->getInternalLinkAttributes( $link, $text );
+
+               $inside = "";
+               if ( "" != $trail ) {
+                       if ( preg_match( wfMsg("linktrail"), $trail, $m ) ) {
+                               $inside = $m[1];
+                               $trail = $m[2];
+                       }
+               }
+               $r = "<a href=\"{$u}\"{$style}>{$text}{$inside}</a>{$trail}";
+               return $r;
+       }
+
+       function makeBrokenLink( $title, $text = "", $query = "", $trail = "" )
+       {
+               global $wgOut, $wgUser;
+
+               $nt = Title::newFromText( $title );
+               $link = $nt->getPrefixedURL();
+
+               if ( "" == $query ) { $q = "action=edit"; }
+               else { $q = "action=edit&{$query}"; }
+               $u = wfLocalUrlE( $link, $q );
+
+               if ( "" == $text ) { $text = $nt->getPrefixedText(); }
+               $style = $this->getInternalLinkAttributes( $link, $text, "yes" );
+
+               $inside = "";
+               if ( "" != $trail ) {
+                       if ( preg_match( wfMsg("linktrail"), $trail, $m ) ) {
+                               $inside = $m[1];
+                               $trail = $m[2];
+                       }
+               }
+               if ( $wgOut->isPrintable() ||
+                 ( 1 == $wgUser->getOption( "highlightbroken" ) ) ) {
+                       $s = "<a href=\"{$u}\"{$style}>{$text}{$inside}</a>{$trail}";
+               } else {
+                       $s = "{$text}{$inside}<a href=\"{$u}\"{$style}>?</a>{$trail}";
+               }
+               return $s;
+       }
+
+        function makeStubLink( $title, $text = "", $query = "", $trail = "" )
+        {
+                global $wgOut, $wgUser;
+
+                $nt = Title::newFromText( $title );
+                $link = $nt->getPrefixedURL();
+
+                $u = wfLocalUrlE( $link, $query );
+
+                if ( "" == $text ) { $text = $nt->getPrefixedText(); }
+                $style = $this->getInternalLinkAttributes( $link, $text, "stub" );
+
+                $inside = "";
+                if ( "" != $trail ) {
+                        if ( preg_match( wfMsg("linktrail"), $trail, $m ) ) {
+                                $inside = $m[1];
+                                $trail = $m[2];
+                        }
+                }
+                if ( $wgOut->isPrintable() ||
+                  ( 1 == $wgUser->getOption( "highlightbroken" ) ) ) {
+                        $s = "<a href=\"{$u}\"{$style}>{$text}{$inside}</a>{$trail}";
+                } else {
+                        $s = "{$text}{$inside}<a href=\"{$u}\"{$style}>!</a>{$trail}";
+                }
+                return $s;
+        }
+
+       function fnamePart( $url )
+       {
+               $basename = strrchr( $url, "/" );
+               if ( false === $basename ) { $basename = $url; }
+               else { $basename = substr( $basename, 1 ); }
+               return wfEscapeHTML( $basename );
+       }
+
+       function makeImage( $url, $alt = "" )
+       {
+               global $wgOut;
+
+               if ( "" == $alt ) { $alt = $this->fnamePart( $url ); }
+               $s = "<img src=\"{$url}\" alt=\"{$alt}\">";
+               return $s;
+       }
+
+       function makeImageLink( $name, $url, $alt = "" )
+       {
+               global $wgOut, $wgTitle, $wgLang;
+
+               $nt = Title::newFromText( $wgLang->getNsText(
+                 Namespace::getImage() ) . ":{$name}" );
+               $link = $nt->getPrefixedURL();
+               if ( "" == $alt ) { $alt = $name; }
+
+               $u = wfLocalUrlE( $link );
+               $s = "<a href=\"{$u}\" class='image' title=\"{$alt}\">" .
+                 "<img border=0 src=\"{$url}\" alt=\"{$alt}\"></a>";
+               return $s;
+       }
+
+       function makeMediaLink( $name, $url, $alt = "" )
+       {
+               global $wgOut, $wgTitle;
+
+               if ( "" == $alt ) { $alt = $name; }
+               $u = wfEscapeHTML( $url );
+               $s = "<a href=\"{$u}\" class='media' title=\"{$alt}\">{$alt}</a>";
+               return $s;
+       }
+
+       function specialLink( $name, $key = "" )
+       {
+               global $wgLang;
+
+               if ( "" == $key ) { $key = strtolower( $name ); }
+               $pn = $wgLang->ucfirst( $name );
+               return $this->makeKnownLink( $wgLang->specialPage( $pn ),
+                 wfMsg( $key ) );
+       }
+
+       # Called by history lists and recent changes
+       #
+
+       function beginRecentChangesList()
+       {
+               $rc_cache = array() ;
+               $rccc = 0 ;
+               $this->lastdate = "";
+               return "";
+       }
+
+       function beginHistoryList()
+       {
+               $this->lastdate = $this->lastline = "";
+               $s = "\n<p>" . wfMsg( "histlegend" ) . "\n<ul>";
+               return $s;
+       }
+
+       function beginImageHistoryList()
+       {
+               $s = "\n<h2>" . wfMsg( "imghistory" ) . "</h2>\n" .
+                 "<p>" . wfMsg( "imghistlegend" ) . "\n<ul>";
+               return $s;
+       }
+
+       function endRecentChangesList()
+       {
+               $s = $this->recentChangesBlock() ;
+               $s .= "</ul>\n";
+               return $s;
+       }
+
+       function endHistoryList()
+       {
+               $last = wfMsg( "last" );
+
+               $s = preg_replace( "/!OLDID![0-9]+!/", $last, $this->lastline );
+               $s .= "</ul>\n";
+               return $s;
+       }
+
+       function endImageHistoryList()
+       {
+               $s = "</ul>\n";
+               return $s;
+       }
+
+       function historyLine( $ts, $u, $ut, $ns, $ttl, $oid, $c, $isminor )
+       {
+               global $wgLang;
+
+               $artname = Title::makeName( $ns, $ttl );
+               $last = wfMsg( "last" );
+               $cur = wfMsg( "cur" );
+               $cr = wfMsg( "currentrev" );
+
+               if ( $oid && $this->lastline ) {
+                       $ret = preg_replace( "/!OLDID!([0-9]+)!/", $this->makeKnownLink(
+                         $artname, $last, "diff=\\1&oldid={$oid}" ), $this->lastline );
+               } else {
+                       $ret = "";
+               }
+               $dt = $wgLang->timeanddate( $ts, true );
+
+               if ( $oid ) { $q = "oldid={$oid}"; }
+               else { $q = ""; }
+               $link = $this->makeKnownLink( $artname, $dt, $q );
+
+               if ( 0 == $u ) {
+            $ul = $this->makeKnownLink( $wgLang->specialPage( "Contributions" ),
+                       $ut, "target=" . $ut );
+               } else { $ul = $this->makeLink( $wgLang->getNsText(
+                 Namespace::getUser() ) . ":{$ut}", $ut ); }
+
+               $s = "<li>";
+               if ( $oid ) {
+                       $curlink = $this->makeKnownLink( $artname, $cur,
+                         "diff=0&oldid={$oid}" );
+               } else {
+                       $curlink = $cur;
+               }
+               $s .= "({$curlink}) (!OLDID!{$oid}!) . .";
+
+               $M = wfMsg( "minoreditletter" );
+               if ( $isminor ) { $s .= " <strong>{$M}</strong>"; }
+               $s .= " {$link} . . {$ul}";
+
+               if ( "" != $c && "*" != $c ) { $s .= " <em>(" . wfEscapeHTML($c) . ")</em>"; }
+               $s .= "</li>\n";
+
+               $this->lastline = $s;
+               return $ret;
+       }
+
+       function recentChangesBlockLine ( $y ) {
+               global $wgUploadPath ;
+
+               $M = wfMsg( "minoreditletter" );
+               $N = wfMsg( "newpageletter" );
+               $r = "" ;
+               $r .= "<img src='{$wgUploadPath}/Arr_.png' width=12 height=12 border=0>" ;
+               $r .= "<tt>" ;
+               if ( $y->isnew ) $r .= $N ;
+               else $r .= "&nbsp;" ;
+               if ( $y->isminor ) $r .= $M ;
+               else $r .= "&nbsp;" ;
+               $r .= " ".$y->timestamp." " ;
+               $r .= "</tt>" ;
+               $link = $y->link ;
+               if ( $y->watched ) $link = "<strong>{$link}</strong>" ;
+               $r .= $link ;
+
+               $r .= " (" ;
+               $r .= $y->curlink ;
+               $r .= "; " ;
+               $r .= $this->makeKnownLink( $y->secureName, wfMsg( "hist" ), "action=history" );
+
+               $r .= ") . . ".$y->userlink ;
+               $r .= $y->usertalklink ;
+               if ( $y->usercomment != "" )
+                       $r .= " <em>(".wfEscapeHTML($y->usercomment).")</em>" ;
+               $r .= "<br>\n" ;
+               return $r ;
+               }
+
+       function recentChangesBlockGroup ( $y ) {
+               global $wgUploadPath ;
+
+               $r = "" ;
+               $M = wfMsg( "minoreditletter" );
+               $N = wfMsg( "newpageletter" );
+               $isnew = false ;
+               $userlinks = array () ;
+               foreach ( $y AS $x ) {
+                       $oldid = $x->diffid ;
+                       if ( $x->isnew ) $isnew = true ;
+                       $u = $x->userlink ;
+                       if ( !isset ( $userlinks[$u] ) ) $userlinks[$u] = 0 ;
+                       $userlinks[$u]++ ;
+                       }
+
+               krsort ( $userlinks ) ;
+               asort ( $userlinks ) ;
+               $users = array () ;
+               $u = array_keys ( $userlinks ) ;
+               foreach ( $u as $x ) {
+                       $z = $x ;
+                       if ( $userlinks[$x] > 1 ) $z .= " ({$userlinks[$x]}&times;)" ;
+                       array_push ( $users , $z ) ;
+                       }
+               $users = " <font size='-1'>[".implode("; ",$users)."]</font>" ;
+
+               $e = $y ;
+               $e = array_shift ( $e ) ;
+
+               # Arrow
+               $rci = "RCI{$this->rccc}" ;
+               $rcl = "RCL{$this->rccc}" ;
+               $rcm = "RCM{$this->rccc}" ;
+               $tl = "<a href='javascript:toggleVisibility(\"{$rci}\",\"{$rcm}\",\"{$rcl}\")'>" ;
+               $tl .= "<span id='{$rcm}'><img src='{$wgUploadPath}/Arr_r.png' width=12 height=12 border=0></span>" ;
+               $tl .= "<span id='{$rcl}' style='display:none'><img src='{$wgUploadPath}/Arr_d.png' width=12 height=12 border=0></span>" ;
+               $tl .= "</a>" ;
+               $r .= $tl ;
+
+               # Main line
+               $r .= "<tt>" ;
+               if ( $isnew ) $r .= $N ;
+               else $r .= "&nbsp;" ;
+               $r .= "&nbsp;" ; # Minor
+               $r .= " ".$e->timestamp." " ;
+               $r .= "</tt>" ;
+
+               $link = $e->link ;
+               if ( $e->watched ) $link = "<strong>{$link}</strong>" ;
+               $r .= $link ;
+
+               if ( !$e->islog ) {
+                       $r .= " (".count($y)." " ;
+                       if ( $isnew ) $r .= wfMsg("changes");
+                       else $r .= $this->makeKnownLink( $e->secureName , wfMsg("changes") , "diff=0&oldid=".$oldid ) ;
+                       $r .= "; " ;
+                       $r .= $this->makeKnownLink( $e->secureName, wfMsg( "history" ), "action=history" );
+                       $r .= ")" ;
+                       }
+
+               $r .= $users ;
+               $r .= "<br>\n" ;
+
+               # Sub-entries
+               $r .= "<div id='{$rci}' style='display:none'>" ;
+               foreach ( $y AS $x )
+                       {
+                       $r .= "<img src='{$wgUploadPath}/Arr_.png' width=12 height=12 border=0>";
+                       $r .= "<tt>&nbsp; &nbsp; &nbsp; &nbsp;" ;
+                       if ( $x->isnew ) $r .= $N ;
+                       else $r .= "&nbsp;" ;
+                       if ( $x->isminor ) $r .= $M ;
+                       else $r .= "&nbsp;" ;
+                       $r .= "</tt>" ;
+
+                       $o = "" ;
+                       if ( $x->oldid != 0 ) $o = "oldid=".$x->oldid ;
+                       if ( $x->islog ) $link = $x->timestamp ;
+                       else $link = $this->makeKnownLink( $x->secureName, $x->timestamp , $o ) ;
+                       $link = "<tt>{$link}</tt>" ;
+
+
+                       $r .= $link ;
+                       $r .= " (" ;
+                       $r .= $x->curlink ;
+                       $r .= "; " ;
+                       $r .= $x->lastlink ;
+                       $r .= ") . . ".$x->userlink ;
+                       $r .= $x->usertalklink ;
+                       if ( $x->usercomment != "" )
+                               $r .= " <em>(".wfEscapeHTML($x->usercomment).")</em>" ;
+                       $r .= "<br>\n" ;
+                       }
+               $r .= "</div>\n" ;
+
+               $this->rccc++ ;
+               return $r ;
+               }
+
+       function recentChangesBlock ()
+       {
+               global $wgUploadPath ;
+               if ( count ( $this->rc_cache ) == 0 ) return "" ;
+               $k = array_keys ( $this->rc_cache ) ;
+               foreach ( $k AS $x )
+                       {
+                       $y = $this->rc_cache[$x] ;
+                       if ( count ( $y ) < 2 ) {
+                               $r .= $this->recentChangesBlockLine ( array_shift ( $y ) ) ;
+                       } else {
+                               $r .= $this->recentChangesBlockGroup ( $y ) ;
+                               }
+                       }
+
+               return "<div align=left>{$r}</div>" ;
+       }
+
+       function recentChangesLine( $ts, $u, $ut, $ns, $ttl, $c, $isminor, $isnew, $watched = false, $oldid = 0 , $diffid = 0 )
+       {
+               global $wgUser ;
+               $usenew = $wgUser->getOption( "usenewrc" );
+               if ( $usenew )
+                       $r = $this->recentChangesLineNew ( $ts, $u, $ut, $ns, $ttl, $c, $isminor, $isnew, $watched , $oldid , $diffid ) ;
+               else
+                       $r = $this->recentChangesLineOld ( $ts, $u, $ut, $ns, $ttl, $c, $isminor, $isnew, $watched , $oldid , $diffid ) ;
+               return $r ;
+       }
+
+       function recentChangesLineOld( $ts, $u, $ut, $ns, $ttl, $c, $isminor, $isnew, $watched = false, $oldid = 0, $diffid = 0 )
+       {
+               global $wgTitle, $wgLang, $wgUser;
+
+               $d = $wgLang->date( $ts, true);
+               $s = "";
+               if ( $d != $this->lastdate ) {
+                       if ( "" != $this->lastdate ) { $s .= "</ul>\n"; }
+                       $s .= "<h4>{$d}</h4>\n<ul>";
+                       $this->lastdate = $d;
+               }
+               $h = $wgLang->time( $ts, true );
+               $t = Title::makeName( $ns, $ttl );
+               $clink = $this->makeKnownLink( $t , "" );
+               $nt = Title::newFromText( $t );
+
+               if ( $watched ) {
+                       $clink = "<strong>{$clink}</strong>";
+               }
+               $hlink = $this->makeKnownLink( $t, wfMsg( "hist" ), "action=history" );
+               if ( $isnew || $nt->isLog() ) {
+                       $dlink = wfMsg( "diff" );
+               } else {
+                       $dlink = $this->makeKnownLink( $t, wfMsg( "diff" ),
+                         "diff={$oldid}&oldid={$diffid}" ); # Finagle's law
+               }
+               if ( 0 == $u ) {
+               $ul = $this->makeKnownLink( $wgLang->specialPage( "Contributions" ),
+                       $ut, "target=" . $ut );                                 
+               } else { $ul = $this->makeLink( $wgLang->getNsText(
+                 Namespace::getUser() ) . ":{$ut}", $ut ); }
+                 
+               $utns=$wgLang->getNsText(Namespace::getTalk(Namespace::getUser()));
+               $talkname=$wgLang->getNsText(Namespace::getTalk(0)); # use the shorter name
+               $utl= $this->makeLink($utns . ":{$ut}", $talkname );
+               $cr = wfMsg( "currentrev" );
+
+               $s .= "<li> ({$dlink}) ({$hlink}) . .";
+               $M = wfMsg( "minoreditletter" );
+               $N = wfMsg( "newpageletter" );
+               if ( $isminor ) { $s .= " <strong>{$M}</strong>"; }
+               if ( $isnew ) { $s .= "<strong>{$N}</strong>"; }
+               $s .= " {$clink}; {$h} . . {$ul}";
+
+               $blink="";
+               if ( ( 0 == $u ) && $wgUser->isSysop() ) {
+                       $blink = $this->makeKnownLink( $wgLang->specialPage(
+                         "Blockip" ), wfMsg( "blocklink" ), "ip={$ut}" );
+                       
+               }
+               if(!$blink) { 
+                       $utl = "({$utl})";
+               } else {
+                       $utl = "({$utl} | {$blink})";
+               }
+               $s.=" {$utl}";
+
+               if ( "" != $c && "*" != $c ) {
+                       $s .= " <em>(" . wfEscapeHTML( $c ) . ")</em>";
+               }
+               $s .= "</li>\n";
+
+               return $s;
+       }
+
+       function recentChangesLineNew( $ts, $u, $ut, $ns, $ttl, $c, $isminor, $isnew, $watched = false, $oldid = 0 , $diffid = 0 )
+       {
+               global $wgTitle, $wgLang, $wgUser;
+
+               $rc = new RecentChangesClass ;
+
+               $d = $wgLang->date( $ts, true);
+               $s = "";
+               $ret = "" ;
+               if ( $d != $this->lastdate ) {
+                       $ret = $this->recentChangesBlock () ;
+                       $this->rc_cache = array() ;
+                       $ret .= "<h4>{$d}</h4>\n";
+                       $this->lastdate = $d;
+               }
+               $h = $wgLang->time( $ts, true );
+               $t = Title::makeName( $ns, $ttl );
+               $clink = $this->makeKnownLink( $t, "" ) ;
+               if ( $oldid == 0 ) $c2link = $clink ;
+               else $c2link = $this->makeKnownLink( $t, "" , "oldid={$oldid}" );
+               $nt = Title::newFromText( $t );
+
+               $rc->timestamp = $h ;
+               $rc->oldid = $oldid ;
+               $rc->diffid = $diffid ;
+               $rc->watched = $watched ;
+               $rc->isnew = $isnew ;
+               $rc->isminor = $isminor ;
+               $rc->secureName = $t ;
+               $rc->displayName = $nt ;
+               $rc->link = $clink ;
+               $rc->usercomment = $c ;
+               $rc->islog = $nt->isLog() ;
+
+               if ( ( $isnew && $oldid == 0 ) || $nt->isLog() ) {
+                       $dlink = wfMsg( "cur" );
+               } else {
+                       $dlink = $this->makeKnownLink( $t, wfMsg( "cur" ),
+                         "diff=0&oldid={$oldid}" );
+               }
+
+               if ( $diffid == 0 || $nt->isLog() ) {
+                       $plink = wfMsg( "last" );
+               } else {
+                       $plink = $this->makeKnownLink( $t, wfMsg( "last" ),
+                         "diff={$oldid}&oldid={$diffid}" );
+               }
+
+               if ( 0 == $u ) {
+               $ul = $this->makeKnownLink( $wgLang->specialPage( "Contributions" ),
+                       $ut, "target=" . $ut );
+               } else { $ul = $this->makeLink( $wgLang->getNsText(
+                 Namespace::getUser() ) . ":{$ut}", $ut ); }
+
+               $rc->userlink = $ul ;
+               $rc->lastlink = $plink ;
+               $rc->curlink = $dlink ;
+
+               $utns=$wgLang->getNsText(Namespace::getTalk(Namespace::getUser()));
+               $talkname=$wgLang->getNsText(Namespace::getTalk(0)); # use the shorter name
+               $utl= $this->makeLink($utns . ":{$ut}", $talkname );                                            
+
+               if ( ( 0 == $u ) && $wgUser->isSysop() ) {
+                       $blink = $this->makeKnownLink( $wgLang->specialPage(
+                         "Blockip" ), wfMsg( "blocklink" ), "ip={$ut}" );
+                       $rc->usertalklink= " ({$utl} | {$blink})";
+               } else {
+                       $rc->usertalklink=" ({$utl})";
+               }
+
+               if ( !isset ( $this->rc_cache[$t] ) ) $this->rc_cache[$t] = array() ;
+               array_push ( $this->rc_cache[$t] , $rc ) ;
+               return $ret;
+       }
+
+
+       function imageHistoryLine( $iscur, $ts, $img, $u, $ut, $size, $c )
+       {
+               global $wgUser, $wgLang, $wgTitle;
+
+               $dt = $wgLang->timeanddate( $ts, true );
+               $del = wfMsg( "deleteimg" );
+               $cur = wfMsg( "cur" );
+
+               if ( $iscur ) {
+                       $url = wfImageUrl( $img );
+                       $rlink = $cur;
+                       if ( $wgUser->isSysop() ) {
+                               $link = wfLocalUrlE( "", "image=" . $wgTitle->getURL() .
+                                 "&action=delete" );
+                               $style = $this->getInternalLinkAttributes( $link, $del );
+
+                               $dlink = "<a href=\"{$link}\"{$style}>{$del}</a>";
+                       } else {
+                               $dlink = $del;
+                       }
+               } else {
+                       $url = wfEscapeHTML( wfImageArchiveUrl( $img ) );
+                       if( $wgUser->getID() != 0 ) {
+                               $rlink = $this->makeKnownLink( $wgTitle->getPrefixedText(),
+                                 wfMsg( "revertimg" ), "action=revert&oldimage=" .
+                                 urlencode( $img ) );
+                               $dlink = $this->makeKnownLink( $wgTitle->getPrefixedText(),
+                                 $del, "action=delete&oldimage=" . urlencode( $img ) );
+                       } else {
+                               # Having live active links for non-logged in users
+                               # means that bots and spiders crawling our site can
+                               # inadvertently change content. Baaaad idea.
+                               $rlink = wfMsg( "revertimg" );
+                               $dlink = $del;
+                       }
+               }
+               if ( 0 == $u ) { $ul = $ut; }
+               else { $ul = $this->makeLink( $wgLang->getNsText(
+                 Namespace::getUser() ) . ":{$ut}", $ut ); }
+
+               $nb = str_replace( "$1", $size, wfMsg( "nbytes" ) );
+               $style = $this->getInternalLinkAttributes( $url, $dt );
+
+               $s = "<li> ({$dlink}) ({$rlink}) <a href=\"{$url}\"{$style}>{$dt}</a>"
+                 . " . . {$ul} ({$nb})";
+
+               if ( "" != $c && "*" != $c ) {
+                       $s .= " <em>(" . wfEscapeHTML( $c ) . ")</em>";
+               }
+               $s .= "</li>\n";
+               return $s;
+       }
+}
+
+include_once( "SkinStandard.php" );
+include_once( "SkinNostalgia.php" );
+include_once( "SkinCologneBlue.php" );
+
+?>
diff --git a/includes/SkinCologneBlue.php b/includes/SkinCologneBlue.php
new file mode 100644 (file)
index 0000000..e0b4aba
--- /dev/null
@@ -0,0 +1,216 @@
+<?
+# See skin.doc
+
+class SkinCologneBlue extends Skin {
+
+       function initPage()
+       {
+               global $wgOut, $wgStyleSheetPath;
+
+               $wgOut->addLink( "stylesheet", "",
+                 "{$wgStyleSheetPath}/cologneblue.css" );
+       }
+
+       function doBeforeContent()
+       {
+               global $wgUser, $wgOut, $wgTitle;
+
+               $s = "";
+               $qb = $this->qbSetting();
+
+               $s .= "\n<div id='content'>\n<div id='topbar'>" .
+                 "<table width='98%' border=0 cellspacing=0 cellpadding=8><tr>";
+
+               $s .= "<td class='top' align=left valign=center nowrap>";
+               $s .= "<a href=\"" . wfLocalUrlE( wfMsg( "mainpage" ) ) . "\">";
+               $s .= "<span id='sitetitle'>" . wfMsg( "sitetitle" ) . "</span></a>";
+
+               $s .= "</td><td class='top' align=right valign=bottom width='100%'>";
+               $s .= $this->sysLinks();
+               $s .= "</td></tr><tr><td valign=top>";
+
+               $s .= "<font size='-1'><span id='sitesub'>";
+               $s .= wfMsg( "sitesubtitle" ) . "</span></font>";
+               $s .= "</td><td align=right>" ;
+
+               $s .= "<font size='-1'><span id='langlinks'>" ;
+               $s .= str_replace ( "<br>" , "" , $this->otherLanguages() ) ;
+               $s .= "<br>" . $this->pageTitleLinks();
+               $s .= "</span></font>";
+
+               $s .= "</td></tr></table>\n";
+
+               $s .= "\n</div>\n<div id='article'>";
+
+               $s .= $this->pageTitle();
+               $s .= $this->pageSubtitle() . "\n<p>";
+               return $s;
+       }
+
+       function doAfterContent()
+       {
+               global $wgUser, $wgOut;
+
+               $s = "\n</div><br clear=all>\n";
+
+               $s .= "\n<div id='footer'>";
+               $s .= "<table width='98%' border=0 cellspacing=0><tr>";
+
+               $qb = $this->qbSetting();
+               if ( 1 == $qb || 3 == $qb ) { # Left
+                       $s .= $this->getQuickbarCompensator();
+               }
+               $s .= "<td class='bottom' align=center valign=top>";
+
+               $s .= $this->bottomLinks();
+               $s .= "\n<br>" . $this->makeKnownLink( wfMsg( "mainpage" ),
+                 wfMsg( "mainpage" ) ) . " | "
+                 . $this->aboutLink() . " | "
+                 . $this->searchForm( wfMsg( "qbfind" ) );
+
+               $s .= "\n<br>" . $this->pageStats();
+
+               $s .= "</td>";
+               if ( 2 == $qb ) { # Right
+                       $s .= $this->getQuickbarCompensator();
+               }
+               $s .= "</tr></table>\n</div>\n</div>\n";
+
+               if ( 0 != $qb ) { $s .= $this->quickBar(); }
+               return $s;
+       }
+       function doGetUserStyles()
+       {
+               global $wgUser, $wgOut, $wgStyleSheetPath;
+
+               $s = parent::doGetUserStyles();
+               $qb = $this->qbSetting();
+
+               if ( 2 == $qb ) { # Right
+                       $s .= "#quickbar { position: absolute; right: 4px; }\n" .
+                         "#article { margin-left: 4px; margin-right: 148px; }\n";
+               } else if ( 1 == $qb || 3 == $qb ) {
+                       $s .= "#quickbar { position: absolute; left: 4px; }\n" .
+                         "#article { margin-left: 148px; margin-right: 4px; }\n";
+               }
+               return $s;
+       }
+       function sysLinks()
+       {
+               global $wgUser;
+               $s = "" .
+                 $this->makeKnownLink( wfMsg( "mainpage" ), wfMsg( "mainpage" ) )
+                 . " | " .
+                 $this->makeKnownLink( wfMsg( "aboutpage" ), wfMsg( "about" ) )
+                 . " | " .
+                 $this->makeKnownLink( wfMsg( "helppage" ), wfMsg( "help" ) )
+                 . " | " .
+                 $this->makeKnownLink( wfMsg( "faqpage" ), wfMsg("faq") )
+                 . " | " .
+                 $this->specialLink( "specialpages" ) . " | " .
+                 $this->specialLink( $wgUser->getID() ? "userlogout" : "userlogin" ) ;
+               return $s;
+       }
+
+       function quickBar()
+       {
+               global $wgOut, $wgTitle, $wgUser, $wgLang;
+
+               $s = "\n<div id='quickbar'>";
+
+               $sep = "<br>";
+               $s .= $this->menuHead( "qbfind" );
+               $s .= $this->searchForm();
+
+               $s .= $this->menuHead( "qbbrowse" )
+                 . $this->mainPageLink()
+                 . $sep . $this->specialLink( "recentchanges" )
+                 . $sep . $this->specialLink( "randompage" ) 
+                 . $sep . $this->specialLink( "newpages" ) 
+                 . $sep . $this->specialLink( "imagelist" ) 
+                 . $sep . $this->specialLink( "statistics" ) 
+                 . $sep . $this->specialLink( "specialpages" ) 
+                 . $sep . $this->bugReportsLink() ;
+                if ( wfMsg ( "currentevents" ) != "-" ) $s .= $sep . $this->makeKnownLink( wfMsg( "currentevents" ), "" ) ;
+                $s .= "\n";
+
+               if ( $wgOut->isArticle() ) {
+                       $s .= $this->menuHead( "qbedit" );
+                       $s .= "<strong>" . $this->editThisPage() . "</strong>"
+                         . $sep . $this->makeKnownLink( wfMsg( "edithelppage" ),
+                         wfMsg( "edithelp" ) );
+
+                       if ( 0 != $wgUser->getID() ) {
+                               $s .= $sep . $this->specialLink( "upload" )
+                               . $sep . $this->moveThisPage();
+                       }
+                       if ( $wgUser->isSysop() ) {
+                               $s .= $sep . $this->deleteThisPage() .
+                               $sep . $this->protectThisPage();
+                       }
+                       $s .= $sep;
+
+                       $s .= $this->menuHead( "qbpageoptions" );
+                       $s .= $this->talkLink()
+                         . $sep . $this->printableLink();
+                       if ( 0 != $wgUser->getID() ) {
+                               $s .= $sep . $this->watchThisPage();
+                       }
+                       $s .= $sep;
+
+                       $s .= $this->menuHead( "qbpageinfo" )
+                         . $this->historyLink()
+                         . $sep . $this->whatLinksHere()
+                         . $sep . $this->watchPageLinksLink();
+
+                       if ( Namespace::getUser() == $wgTitle->getNamespace() ) {
+                               $s .= $sep . $this->userContribsLink();
+                               if ( 0 != $wgUser->getID() ) {
+                                       $s .= $sep . $this->emailUserLink();
+                               }
+                       }
+                       $s .= $sep;
+               }
+               $s .= $this->menuHead( "qbmyoptions" );
+               if ( 0 != $wgUser->getID() ) {
+                       $name = $wgUser->getName();
+                       $tl = $this->makeKnownLink( $wgLang->getNsText(
+                         Namespace::getTalk( Namespace::getUser() ) ) . ":{$name}",
+                         wfMsg( "mytalk" ) );
+                       if ( 0 != $wgUser->getNewtalk() ) { $tl .= " *"; }
+
+                       $s .= $this->makeKnownLink( $wgLang->getNsText(
+                         Namespace::getUser() ) . ":{$name}", wfMsg( "mypage" ) )
+                         . $sep . $tl
+                         . $sep . $this->specialLink( "watchlist" )
+                         . $sep . $this->specialLink( "preferences" )
+                         . $sep . $this->specialLink( "userlogout" );
+               } else {
+                       $s .= $this->specialLink( "userlogin" );
+               }
+               $s .= $sep . "\n</div>\n";
+               return $s;
+       }
+
+       function menuHead( $key )
+       {
+               $s = "\n<h6>" . wfMsg( $key ) . "</h6>";
+               return $s;
+       }
+
+       function searchForm( $label = "" )
+       {
+               global $search;
+               $s = "<form id=\"search\" method=\"get\" class=\"inline\" action=\"" .
+                 wfLocalUrlE( "" ) . "\">";
+               if ( "" != $label ) { $s .= "{$label}: "; }
+
+               $s .= "<input type=text name=\"search\" size=10 value=\""
+          . htmlspecialchars(substr($search,0,256)) . "\">"
+                 . "<input type=submit value=\"" . wfMsg( "ok" ) . "\"></form>";
+
+               return $s;
+       }
+}
+
+?>
diff --git a/includes/SkinFramed.php b/includes/SkinFramed.php
new file mode 100644 (file)
index 0000000..710ea64
--- /dev/null
@@ -0,0 +1,87 @@
+<?
+# See skin.doc
+
+class SkinFramed extends Skin {
+
+       function useBodyTag()
+       {
+               global $frame;
+               return ( "set" != $frame );
+       }
+
+       function qbSetting() { return 0; }
+       function beforeContent() { return ""; }
+       function afterContent() { return ""; }
+       function qbLogo() { return ""; }
+       function isFramed() { return true; }
+
+       function getBaseTag()
+       {
+               global $wgServer, $wgScript;
+
+               $s = "<base href=\"{$wgServer}{$wgScript}\" target=\"_top\">\n";
+               return $s;
+       }
+
+       function getTopFrame()
+       {
+               $t = $this->pageTitleLinks();
+               $t = explode ( "<br>" , $t );
+               while ( count ( $t ) < 4 ) { array_push ( $t, "" ); }
+               $t = implode ( "<br>", $t );
+
+               $s = "";
+               $s .= "<table width='100%' border=0><tr height=152>\n";
+               $s .= "<td class='top' valign=top>" . $this->logoText() . "</td>\n";
+               $s .= "<td class='top'>&nbsp;&nbsp;</td>\n";
+               $s .= "<td class='top' valign=top width='100%'>\n";
+               $s .= $this->topLinks();
+               $s .= $t;
+
+               $s .= $this->pageTitle();
+               $s .= $this->pageSubtitle();
+
+               $s .= "</td>\n<td class='top' valign=top align=right width=200 nowrap>";
+               $s .= $this->nameAndLogin();
+               $s .= "\n<br>" . $this->searchForm() . "</td>";
+               $s .= "</tr></table>";
+               return $s;
+       }
+
+       function transformContent( $text )
+       {
+               global $frame, $HTTP_SERVER_VARS;
+               global $wgOut, $wgServer, $wgScript;
+
+               $qs = $HTTP_SERVER_VARS["QUERY_STRING"];
+               $qs = wfEscapeHTML( $qs );
+
+               if ( "" == $qs ) { $qs = "?frame="; }
+               else { $qs = "?{$qs}&amp;frame="; }
+               $url = "{$wgServer}{$wgScript}{$qs}";
+
+               if ( "set" == $frame ) {
+                       $s = "<frameset rows='152,*' border=0>\n" .
+                         "<frame marginwidth=0 marginheight=0 frameborder=1 " .
+                         "src=\"{$url}top\" noresize scrolling=no>\n" .
+                         "<frameset cols='152,*' border=0>\n" .
+                         "<frame marginwidth=0 marginheight=0 frameborder=1 " .
+                         "src=\"{$url}side\">\n" .
+                         "<frame marginwidth=0 marginheight=0 frameborder=1 " .
+                         "src=\"{$url}body\">\n" .
+                         "</frameset>\n</frameset>\n";
+               } else if ( "top" == $frame ) {
+                       $s = $this->getTopFrame();
+               } else if ( "side" == $frame ) {
+                       $s = $this->quickBar();
+                       # $s = spliti( "<hr>", $s, 2 );
+                       # $s = $s[1] ;
+               } else if ( "body" == $frame ) {
+                       $s = $text;
+                       # Bottom links?
+               }
+               return $s;
+       }
+}
+
+?>
diff --git a/includes/SkinNostalgia.php b/includes/SkinNostalgia.php
new file mode 100644 (file)
index 0000000..d2e97cf
--- /dev/null
@@ -0,0 +1,78 @@
+<?
+# See skin.doc
+
+class SkinNostalgia extends Skin {
+
+       function initPage()
+       {
+               global $wgOut, $wgStyleSheetPath;
+
+               $wgOut->addLink( "stylesheet", "",
+                 "$wgStyleSheetPath/nostalgia.css" );
+       }
+
+       function doBeforeContent()
+       {
+               global $wgUser, $wgOut, $wgTitle;
+
+               $s = "\n<div id='content'>\n<div id='topbar'>";
+               $s .= $this->logoText( "right" );
+
+               $s .= $this->pageTitle();
+               $s .= $this->pageSubtitle() . "\n<p>";
+
+               $s .= $this->topLinks() . "\n<br>";
+               $s .= $this->pageTitleLinks();
+
+               if ( $wgOut->isArticle() ) {
+                       $s .= "<br>" . $this->otherLanguages();
+               }
+               $s .= "<br clear=all><hr>\n</div>\n";
+               $s .= "\n<div id='article'>";
+
+               return $s;
+       }
+
+       function topLinks()
+       {
+               global $wgOut, $wgUser;
+               $sep = " |\n";
+
+               $s = $this->mainPageLink() . $sep
+                 . $this->specialLink( "recentchanges" );
+
+               if ( $wgOut->isArticle() ) {
+                       $s .=  $sep . $this->editThisPage()
+                         . $sep . $this->historyLink();
+               }
+               if ( 0 == $wgUser->getID() ) {
+                       $s .= $sep . $this->specialLink( "userlogin" );
+               } else {
+                       $s .= $sep . $this->specialLink( "userlogout" );
+               }
+               $s .= $sep . $this->specialPagesList();
+
+               return $s;
+       }
+
+       function doAfterContent()
+       {
+               global $wgUser, $wgOut;
+
+               $s = "\n</div><br clear=all>\n";
+
+               $s .= "\n<div id='footer'><hr>";
+
+               $s .= $this->bottomLinks();
+               $s .= "\n<br>" . $this->pageStats();
+               $s .= "\n<br>" . $this->mainPageLink()
+                 . " | " . $this->aboutLink()
+                 . " | " . $this->searchForm();
+
+               $s .= "\n</div>\n</div>\n";
+
+               return $s;
+       }
+}
+
+?>
diff --git a/includes/SkinStandard.php b/includes/SkinStandard.php
new file mode 100644 (file)
index 0000000..df96a00
--- /dev/null
@@ -0,0 +1,60 @@
+<?
+# See skin.doc
+
+class SkinStandard extends Skin {
+
+       function getHeadScripts()
+       {
+               global $wgStyleSheetPath;
+
+               $s = parent::getHeadScripts();
+               if ( 3 == $this->qbSetting() ) { # Floating left
+                       $s .= "<script language='javascript' type='text/javascript' " .
+                         "src='{$wgStyleSheetPath}/sticky.js'></script>\n";
+               }
+               return $s;
+       }
+
+       function getUserStyles()
+       {
+               global $wgStyleSheetPath;
+
+               $s = parent::getUserStyles();
+               if ( 3 == $this->qbSetting() ) { # Floating left
+                       $s .= "<style type='text/css' media='screen'>\n" .
+                         "@import '{$wgStyleSheetPath}/quickbar.css';\n</style>\n";
+               }
+               return $s;
+       }
+
+       function doGetUserStyles()
+       {
+               global $wgUser, $wgOut, $wgStyleSheetPath;
+
+               $s = parent::doGetUserStyles();
+               $qb = $this->qbSetting();
+
+               if ( 2 == $qb ) { # Right
+                       $s .= "#quickbar { position: absolute; top: 4px; right: 4px; " .
+                         "border-left: 2px solid #000000; }\n" .
+                         "#article { margin-left: 4px; margin-right: 152px; }\n";
+               } else if ( 1 == $qb || 3 == $qb ) {
+                       $s .= "#quickbar { position: absolute; top: 4px; left: 4px; " .
+                         "border-right: 2px solid #000000; }\n" .
+                         "#article { margin-left: 152px; margin-right: 4px; }\n";
+               }
+               return $s;
+       }
+
+       function getBodyOptions()
+       {
+               $a = parent::getBodyOptions();
+
+               if ( 3 == $this->qbSetting() ) { # Floating left
+                       $a["onload"] = "setup(\"quickbar\")";
+               }
+               return $a;
+       }
+}
+
+?>
diff --git a/includes/SpecialAllpages.php b/includes/SpecialAllpages.php
new file mode 100644 (file)
index 0000000..a3b7aaf
--- /dev/null
@@ -0,0 +1,116 @@
+<?
+
+function wfSpecialAllpages()
+{
+       global $from, $indexMaxperpage;
+       $indexMaxperpage = 480;
+
+       if( isset( $from ) ) {
+               indexShowChunk( $from );
+       } else {
+               indexShowToplevel();
+       }
+}
+
+function indexShowToplevel()
+{
+       global $wgOut, $indexMaxperpage;
+       $fname = "indexShowToplevel";
+       # FIXME: This may be slow; we may need to cache it
+
+#      $fromwhere = "FROM cur WHERE cur_namespace=0 AND cur_is_redirect=0";
+       $fromwhere = "FROM cur WHERE cur_namespace=0";
+       $order = "ORDER BY cur_title";
+       $out = "";
+       
+       $sql = "SELECT COUNT(*) AS count $fromwhere";
+       $res = wfQuery( $sql, $fname );
+       $s = wfFetchObject( $res );
+       $count = $s->count;
+       $sections = ceil( $count / $indexMaxperpage );
+       
+       $sql = "SELECT cur_title $fromwhere $order LIMIT 1";
+       $res = wfQuery( $sql, $fname );
+       $s = wfFetchObject( $res );
+       $inpoint = $s->cur_title;
+       
+       $out .= "<table>\n";
+       # There's got to be a cleaner way to do this!
+       for( $i = 1; $i < $sections; $i++ ) {
+               $from = $i * $indexMaxperpage;
+               $sql = "SELECT cur_title $fromwhere $order LIMIT $from,2";
+               $res = wfQuery( $sql, $fname );
+       
+               $s = wfFetchObject( $res );
+               $outpoint = $s->cur_title;
+               $out .= indexShowline( $inpoint, $outpoint );
+       
+               $s = wfFetchObject( $res );
+               $inpoint = $s->cur_title;
+               
+               wfFreeResult( $res );
+       }
+       
+       $from = $i * $indexMaxperpage;
+       $sql = "SELECT cur_title $fromwhere $order LIMIT " . ($count-1) . ",1";
+       $res = wfQuery( $sql, $fname );
+       $s = wfFetchObject( $res );
+       $outpoint = $s->cur_title;
+       $out .= indexShowline( $inpoint, $outpoint );
+       $out .= "</table>\n";
+       
+       $wgOut->addHtml( $out );
+}
+
+function indexShowline( $inpoint, $outpoint )
+{
+       global $wgOut, $wgLang, $wgUser;
+       $sk = $wgUser->getSkin();
+
+       # Fixme: this is ugly
+       $out = wfMsg(
+               "alphaindexline",
+               $sk->makeKnownLink( $wgLang->specialPage( "Allpages" ),
+                       str_replace( "_", " ", $inpoint ),
+                       "from=" . wfStrencode( $inpoint ) ) . "</td><td>",
+               "</td><td align=\"left\">" .
+               str_replace( "_", " ", $outpoint )
+               );
+       return "<tr><td align=\"right\">{$out}</td></tr>\n";
+}
+
+function indexShowChunk( $from )
+{
+       global $wgOut, $wgUser, $indexMaxperpage;
+       $sk = $wgUser->getSkin();
+       
+       $out = "";
+       $sql = "SELECT cur_title
+FROM cur
+WHERE cur_namespace=0 AND cur_title >= '" . wfStrencode( $from ) . "'
+ORDER BY cur_title
+LIMIT {$indexMaxperpage}";
+       $res = wfQuery( $sql, "indexShowChunk" );
+
+       # FIXME: Dynamic column widths, backlink to main list,
+       # side links to next and previous
+       $n = 0;
+       $out = "<table border=\"0\">\n";
+       while( $s = wfFetchObject( $res ) ) {
+               $out .= "<td width=\"33%\">" .
+                       $sk->makeKnownLink( $s->cur_title ) .
+                       "</td>";
+               $n = ++$n % 3;
+               if( $n == 0 ) {
+                       $out .= "</tr>\n<tr>";
+               }
+       }
+       if( $n != 0 ) {
+               $out .= "</tr>\n";
+       }
+       $out .= "</table>";
+       #return $out;
+       $wgOut->addHtml( $out );
+}
+
+?>
diff --git a/includes/SpecialAsksql.php b/includes/SpecialAsksql.php
new file mode 100644 (file)
index 0000000..edddd06
--- /dev/null
@@ -0,0 +1,113 @@
+<?
+
+function wfSpecialAsksql()
+{
+       global $wgUser, $wgOut, $action;
+
+       if ( ! $wgUser->isSysop() ) {
+               $wgOut->sysopRequired();
+               return;
+       }
+       $fields = array( "wpSqlQuery" );
+       wfCleanFormFields( $fields );
+       $f = new SqlQueryForm();
+
+       if ( "submit" == $action ) { $f->doSubmit(); }
+       else { $f->showForm( "" ); }
+}
+
+class SqlQueryForm {
+
+       function showForm( $err )
+       {
+               global $wgOut, $wgUser, $wgLang;
+               global $wpSqlQuery;
+
+               $wgOut->setPagetitle( wfMsg( "asksql" ) );
+               $wgOut->addWikiText( wfMsg( "asksqltext" ) );
+
+               if ( "" != $err ) {
+                       $wgOut->addHTML( "<p><font color='red' size='+1'>" . htmlspecialchars($err) . "</font>\n" );
+               }
+               if ( ! $wpSqlQuery ) { $wpSqlQuery = "SELECT ... FROM ... WHERE ..."; }
+               $q = wfMsg( "sqlquery" );
+               $qb = wfMsg( "querybtn" );
+               $action = wfLocalUrlE( $wgLang->specialPage( "Asksql" ),
+                 "action=submit" );
+
+               $wgOut->addHTML( "<p>
+<form id=\"asksql\" method=\"post\" action=\"{$action}\">
+<table border=0><tr>
+<td align=right>{$q}:</td>
+<td align=left>
+<textarea name=\"wpSqlQuery\" cols=80 rows=4 wrap=\"virtual\">"
+. htmlspecialchars($wpSqlQuery) ."
+</textarea>
+</td>
+</tr><tr>
+<td>&nbsp;</td><td align=\"left\">
+<input type=submit name=\"wpQueryBtn\" value=\"{$qb}\">
+</td></tr></table>
+</form>\n" );
+
+       }
+
+       function doSubmit()
+       {
+               global $wgOut, $wgUser, $wgServer, $wgScript, $wgArticlePath;
+               global $wpSqlQuery;
+               global $wgDBsqluser, $wgDBsqlpassword;
+
+               # Use a limit, folks!
+               $wpSqlQuery = trim( $wpSqlQuery );
+               if( preg_match( "/^SELECT/i", $wpSqlQuery )
+                       and !preg_match( "/LIMIT/i", $wpSqlQuery ) ) {
+                       $wpSqlQuery .= " LIMIT 100";
+               }
+               if ( ! $wgUser->isDeveloper() ) {
+                       $connection = wfGetDB( $wgDBsqluser, $wgDBsqlpassword );
+               }
+               $res = wfQuery( $wpSqlQuery, "SpecialAsksql::doSubmit" );
+
+               $n = 0;
+               @$n = wfNumFields( $res );
+               if ( $n ) {
+                       $k = array();
+                       for ( $x = 0; $x < $n; ++$x ) {
+                               array_push( $k, wfFieldName( $res, $x ) );
+                       }
+                       $a = array();
+                       while ( $s = wfFetchObject( $res ) ) {
+                               array_push( $a, $s );
+                       }
+                       wfFreeResult( $res );
+
+                       $r = "<table border=1 bordercolor=black cellspacing=0 " .
+                         "cellpadding=2><tr>\n";
+                       foreach ( $k as $x ) $r .= "<th>" . htmlspecialchars( $x ) . "</th>";
+                       $r .= "</tr>\n";
+
+                       foreach ( $a as $y ) {
+                               $r .= "<tr>";
+                               foreach ( $k as $x ) {
+                                       $o = $y->$x ;
+                                       if ( $x == "cur_title" or $x == "old_title" ) {
+                                               $o = str_replace ( "$1" , rawurlencode( $o ) , $wgArticlePath ) ;
+                                               $o = "<a href=\"{$o}\" class='internal'>" .
+                                                 htmlspecialchars( $y->$x ) . "</a>" ;
+                                               } else {
+                                               $o = htmlspecialchars( $o );
+                                               }
+                                       $r .= "<td>" . $o . "</td>\n";
+                               }
+                               $r .= "</tr>\n";
+                       }
+                       $r .= "</table>\n";
+               }
+               $this->showForm( wfMsg( "querysuccessful" ) );
+               $wgOut->addHTML( "<hr>{$r}\n" );
+       }
+
+}
+
+?>
diff --git a/includes/SpecialBlockip.php b/includes/SpecialBlockip.php
new file mode 100644 (file)
index 0000000..bc24f4d
--- /dev/null
@@ -0,0 +1,97 @@
+<?
+
+function wfSpecialBlockip()
+{
+       global $wgUser, $wgOut, $action;
+
+       if ( ! $wgUser->isSysop() ) {
+               $wgOut->sysopRequired();
+               return;
+       }
+       $fields = array( "wpBlockAddress", "wpBlockReason" );
+       wfCleanFormFields( $fields );
+       $ipb = new IPBlockForm();
+
+       if ( "success" == $action ) { $ipb->showSuccess(); }
+       else if ( "submit" == $action ) { $ipb->doSubmit(); }
+       else { $ipb->showForm( "" ); }
+}
+
+class IPBlockForm {
+
+       function showForm( $err )
+       {
+               global $wgOut, $wgUser, $wgLang;
+               global $ip, $wpBlockAddress, $wpBlockReason;
+
+               $wgOut->setPagetitle( wfMsg( "blockip" ) );
+               $wgOut->addWikiText( wfMsg( "blockiptext" ) );
+
+               if ( ! $wpBlockAddress ) { $wpBlockAddress = $ip; }
+               $ipa = wfMsg( "ipaddress" );
+               $reason = wfMsg( "ipbreason" );
+               $ipbs = wfMsg( "ipbsubmit" );
+               $action = wfLocalUrlE( $wgLang->specialPage( "Blockip" ),
+                 "action=submit" );
+
+               if ( "" != $err ) {
+                       $wgOut->setSubtitle( wfMsg( "formerror" ) );
+                       $wgOut->addHTML( "<p><font color='red' size='+1'>{$err}</font>\n" );
+               }
+               $wgOut->addHTML( "<p>
+<form id=\"blockip\" method=\"post\" action=\"{$action}\">
+<table border=0><tr>
+<td align=\"right\">{$ipa}:</td>
+<td align=\"left\">
+<input tabindex=1 type=text size=20 name=\"wpBlockAddress\" value=\"{$wpBlockAddress}\">
+</td></tr><tr>
+<td align=\"right\">{$reason}:</td>
+<td align=\"left\">
+<input tabindex=2 type=text size=40 name=\"wpBlockReason\" value=\"{$wpBlockReason}\">
+</td></tr><tr>
+<td>&nbsp;</td><td align=\"left\">
+<input tabindex=3 type=submit name=\"wpBlock\" value=\"{$ipbs}\">
+</td></tr></table>
+</form>\n" );
+
+       }
+
+       function doSubmit()
+       {
+               global $wgOut, $wgUser, $wgLang;
+               global $ip, $wpBlockAddress, $wpBlockReason;
+               $fname = "IPBlockForm::doSubmit";
+
+               if ( ! preg_match( "/\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}/",
+                 $wpBlockAddress ) ) {
+                       $this->showForm( wfMsg( "badipaddress" ) );
+                       return;
+               }
+               if ( "" == $wpBlockReason ) {
+                       $this->showForm( wfMsg( "noblockreason" ) );
+                       return;
+               }
+               $sql = "INSERT INTO ipblocks (ipb_address, ipb_user, ipb_by, " .
+                 "ipb_reason, ipb_timestamp ) VALUES ('{$wpBlockAddress}', 0, " .
+                 $wgUser->getID() . ", '" . wfStrencode( $wpBlockReason ) . "','" .
+                 date( "YmdHis" ) . "')";
+               wfQuery( $sql, $fname );
+
+               $success = wfLocalUrl( $wgLang->specialPage( "Blockip" ),
+                 "action=success&ip={$wpBlockAddress}" );
+               $wgOut->redirect( $success );
+       }
+
+       function showSuccess()
+       {
+               global $wgOut, $wgUser;
+               global $ip;
+
+               $wgOut->setPagetitle( wfMsg( "blockip" ) );
+               $wgOut->setSubtitle( wfMsg( "blockipsuccesssub" ) );
+               $text = str_replace( "$1", $ip, wfMsg( "blockipsuccesstext" ) );
+               $wgOut->addWikiText( $text );
+       }
+}
+
+?>
diff --git a/includes/SpecialBooksources.php b/includes/SpecialBooksources.php
new file mode 100644 (file)
index 0000000..a3722cd
--- /dev/null
@@ -0,0 +1,57 @@
+<?
+
+# ISBNs in wiki pages will create links to this page, with
+# the ISBN passed in via the query string.
+
+function wfSpecialBooksources()
+{
+       $isbn = $_REQUEST["isbn"];
+
+       $bsl = new BookSourceList( $isbn );
+       $bsl->show();
+}
+
+class BookSourceList {
+
+       var $mIsbn;
+
+       function BookSourceList( $isbn )
+       {
+               $this->mIsbn = $isbn;
+       }
+
+       function show()
+       {
+               global $wgOut, $wgUser, $wgLang;
+               global $ip, $wpBlockAddress, $wpBlockReason;
+
+               $wgOut->setPagetitle( wfMsg( "booksources" ) );
+               $wgOut->addWikiText( wfMsg( "booksourcetext" ) );
+
+               # If ISBN is blank, just show a list of links to the
+               # home page of the various book sites.  Otherwise, show
+               # a list of links directly to the book.
+
+               $s = "<ul>\n";
+               $bs = $wgLang->getBookstoreList() ;
+               $bsn = array_keys ( $bs ) ;
+               foreach ( $bsn as $name ) {
+                       $adr = $bs[$name] ;
+                       if ( ! $this->mIsbn ) {
+                               $adr = explode ( ":" , $adr , 2 ) ;
+                               $adr = explode ( "/" , $adr[1] ) ;
+                               $a = "" ;
+                               while ( $a == "" ) $a = array_shift ( $adr ) ;
+                               $adr = "http://".$a ;
+                       } else {
+                               $adr = str_replace ( "$1" , $this->mIsbn , $adr ) ;
+                       }
+                       $s .= "<li><a href=\"{$adr}\">{$name}</a></li>\n" ;
+                       }
+               $s .= "</ul>\n";
+
+               $wgOut->addHTML( $s );
+       }
+}
+
+?>
diff --git a/includes/SpecialContributions.php b/includes/SpecialContributions.php
new file mode 100644 (file)
index 0000000..d9e86a7
--- /dev/null
@@ -0,0 +1,151 @@
+<?
+
+function wfSpecialContributions()
+{
+       global $wgUser, $wgOut, $wgLang, $target, $offset, $limit, $hideminor;
+       $fname = "wfSpecialContributions";
+       $sysop = $wgUser->isSysop();
+
+       if ( "" == $target ) {
+               $wgOut->errorpage( "notargettitle", "notargettext" );
+               return;
+       }
+       $offset = (int)$offset;
+       $limit = (int)$limit;
+       if( $offset < 0 ) { $offset = 0; }
+       if( $limit < 1 ) { $limit = 50; }
+
+       $target = wfCleanQueryVar( $target );
+       $nt = Title::newFromURL( $target );
+       $nt->setNamespace( Namespace::getUser() );
+
+       $sk = $wgUser->getSkin();
+       $id = User::idFromName( $nt->getText() );
+
+       if ( 0 == $id ) { $ul = $nt->getText(); }
+       else {
+               $ul = $sk->makeKnownLink( $nt->getPrefixedText(), $nt->getText() );
+       }
+       $sub = str_replace( "$1", $ul, wfMsg( "contribsub" ) );
+       $wgOut->setSubtitle( $sub );
+
+       if ( ! isset( $hideminor ) ) {
+               $hideminor = $wgUser->getOption( "hideminor" );
+       }
+       if ( $hideminor ) {
+               $cmq = "AND cur_minor_edit=0";
+               $omq = "AND old_minor_edit=0";
+       } else { $cmq = $omq = ""; }
+
+       $top = wfShowingResults( $offset, $limit );
+       $wgOut->addHTML( "<p>{$top}\n" );
+
+       $sl = wfViewPrevNext( $offset, $limit,
+         $wgLang->specialpage( "Contributions" ), "target=" . wfUrlEncode( $target ) );
+       $wgOut->addHTML( "<br>{$sl}\n" );
+       
+       # Sorting slowness on cur and especially old
+       # forces us to check RC table first
+       if ( 0 == $id ) {
+               $sql = "SELECT cur_namespace,cur_title,cur_timestamp,cur_comment FROM cur " .
+                 "WHERE cur_user_text='" . wfStrencode( $nt->getText() ) . "' {$cmq} " .
+                 "ORDER BY inverse_timestamp LIMIT {$offset}, {$limit}";
+               $res1 = wfQuery( $sql, $fname );
+
+               $sql = "SELECT old_namespace,old_title,old_timestamp,old_comment FROM old " .
+                 "WHERE old_user_text='" . wfStrencode( $nt->getText() ) . "' {$omq} " .
+                 "ORDER BY inverse_timestamp LIMIT {$offset}, {$limit}";
+               $res2 = wfQuery( $sql, $fname );
+       } else {
+               $sql = "SELECT cur_namespace,cur_title,cur_timestamp,cur_comment FROM cur " .
+                 "WHERE cur_user={$id} {$cmq} ORDER BY inverse_timestamp LIMIT {$offset}, {$limit}";
+               $res1 = wfQuery( $sql, $fname );
+
+               $sql = "SELECT old_namespace,old_title,old_timestamp,old_comment FROM old " .
+                 "WHERE old_user={$id} {$omq} ORDER BY inverse_timestamp LIMIT {$offset}, {$limit}";
+               $res2 = wfQuery( $sql, $fname );
+       }
+       $nCur = wfNumRows( $res1 );
+       $nOld = wfNumRows( $res2 );
+
+
+       if ( 0 == $nCur && 0 == $nOld && 0 == $rcrows ) {
+               $wgOut->addHTML( "\n<p>" . wfMsg( "nocontribs" ) . "</p>\n" );
+               return;
+       }
+       if ( 0 != $nCur ) { $obj1 = wfFetchObject( $res1 ); }
+       if ( 0 != $nOld ) { $obj2 = wfFetchObject( $res2 ); }
+
+       $wgOut->addHTML( "<ul>\n" );
+       while ( $limit ) {
+               if ( 0 == $nCur && 0 == $nOld ) { break; }
+
+               if ( ( 0 == $nOld ) ||
+                 ( ( 0 != $nCur ) &&
+                 ( $obj1->cur_timestamp >= $obj2->old_timestamp ) ) ) {
+                       $ns = $obj1->cur_namespace;
+                       $t = $obj1->cur_title;
+                       $ts = $obj1->cur_timestamp;
+                       $comment =$obj1->cur_comment;
+
+                       $obj1 = wfFetchObject( $res1 );
+                       $topmark = true;                        
+                       --$nCur;
+               } else {
+                       $ns = $obj2->old_namespace;
+                       $t = $obj2->old_title;
+                       $ts = $obj2->old_timestamp;
+                       $comment =$obj2->old_comment;
+
+                       $obj2 = wfFetchObject( $res2 );
+                       $topmark = false;
+                       --$nOld;
+               }
+               ucListEdit( $sk, $ns, $t, $ts, $topmark, $comment );
+
+               --$limit;
+       }
+       $wgOut->addHTML( "</ul>\n" );
+}
+
+function ucListEdit( $sk, $ns, $t, $ts, $topmark, $comment )
+{
+       global $wgLang, $wgOut, $wgUser;
+       $page = Title::makeName( $ns, $t );
+       $link = $sk->makeKnownLink( $page, "" );
+       $topmarktext = $topmark ? wfMsg ( "uctop" ) : "";
+       $sysop = $wgUser->isSysop();
+       if($sysop && $topmark ) {
+               $topmarktext .= " [". $sk->makeKnownLink( $page,
+                 wfMsg( "rollbacklink" ), "action=rollback" ) ."]";
+       }
+       if($comment) {
+       
+               $comment="<em>(". htmlspecialchars( $comment ) .")</em> ";
+       
+       }
+       $d = $wgLang->timeanddate( $ts, true );
+
+       $wgOut->addHTML( "<li>{$d} {$link} {$comment}{$topmarktext}</li>\n" );
+}
+
+function ucCountLink( $lim, $d )
+{
+       global $wgUser, $wgLang, $target;
+
+       $sk = $wgUser->getSkin();
+       $s = $sk->makeKnownLink( $wgLang->specialPage( "Contributions" ),
+         "{$lim}", "target={$target}&days={$d}&limit={$lim}" );
+       return $s;
+}
+
+function ucDaysLink( $lim, $d )
+{
+       global $wgUser, $wgLang, $target;
+
+       $sk = $wgUser->getSkin();
+       $s = $sk->makeKnownLink( $wgLang->specialPage( "Contributions" ),
+         "{$d}", "target={$target}&days={$d}&limit={$lim}" );
+       return $s;
+}
+?>
diff --git a/includes/SpecialDebug.php b/includes/SpecialDebug.php
new file mode 100644 (file)
index 0000000..f11c075
--- /dev/null
@@ -0,0 +1,13 @@
+<?
+
+function wfSpecialDebug()
+{
+       global $wgUser, $wgOut;
+
+       if ( ! $wgUser->isDeveloper() ) {
+               $wgOut->developerRequired();
+               return;
+       }
+       phpinfo();
+}
+
diff --git a/includes/SpecialEmailuser.php b/includes/SpecialEmailuser.php
new file mode 100644 (file)
index 0000000..8ae02b2
--- /dev/null
@@ -0,0 +1,135 @@
+<?
+
+function wfSpecialEmailuser()
+{
+       global $wgUser, $wgOut, $action, $target;
+
+       if ( 0 == $wgUser->getID() ||
+               ( false === strpos( $wgUser->getEmail(), "@" ) ) ) {
+               $wgOut->errorpage( "mailnologin", "mailnologintext" );
+               return;
+       }
+       $target = wfCleanQueryVar( $target );
+       if ( "" == $target ) {
+               $wgOut->errorpage( "notargettitle", "notargettext" );
+               return;
+       }
+       $nt = Title::newFromURL( $target );
+       $nu = User::newFromName( $nt->getText() );
+       $id = $nu->idForName();
+
+       if ( 0 == $id ) {
+               $wgOut->errorpage( "noemailtitle", "noemailtext" );
+               return;
+       }
+       $nu->setID( $id );
+       $address = $nu->getEmail();
+
+       if ( ( false === strpos( $address, "@" ) ) ||
+         ( 1 == $nu->getOption( "disablemail" ) ) ) {
+               $wgOut->errorpage( "noemailtitle", "noemailtext" );
+               return;
+       }
+       $fields = array( "wpSubject", "wpText" );
+       wfCleanFormFields( $fields );
+
+       $f = new EmailUserForm( $nu->getName() . " <{$address}>" );
+
+       if ( "success" == $action ) { $f->showSuccess(); }
+       else if ( "submit" == $action ) { $f->doSubmit(); }
+       else { $f->showForm( "" ); }
+}
+
+class EmailUserForm {
+
+       var $mAddress;
+
+       function EmailUserForm( $addr )
+       {
+               $this->mAddress = $addr;
+       }
+
+       function showForm( $err )
+       {
+               global $wgOut, $wgUser, $wgLang;
+               global $wpSubject, $wpText, $target;
+
+               $wgOut->setPagetitle( wfMsg( "emailpage" ) );
+               $wgOut->addWikiText( wfMsg( "emailpagetext" ) );
+
+               if ( ! $wpSubject ) { $wpSubject = "Wikipedia e-mail"; }
+
+               $emf = wfMsg( "emailfrom" );
+               $sender = $wgUser->getName();
+               $emt = wfMsg( "emailto" );
+               $rcpt = str_replace( "_", " ", urldecode( $target ) );
+               $emr = wfMsg( "emailsubject" );
+               $emm = wfMsg( "emailmessage" );
+               $ems = wfMsg( "emailsend" );
+
+               $action = wfLocalUrlE( $wgLang->specialPage( "Emailuser" ),
+                 "target={$target}&action=submit" );
+
+               if ( "" != $err ) {
+                       $wgOut->setSubtitle( wfMsg( "formerror" ) );
+                       $wgOut->addHTML( "<p><font color='red' size='+1'>{$err}</font>\n" );
+               }
+               $wgOut->addHTML( "<p>
+<form id=\"emailuser\" method=\"post\" action=\"{$action}\">
+<table border=0><tr>
+<td align=right>{$emf}:</td>
+<td align=left><strong>{$sender}</strong></td>
+</tr><tr>
+<td align=right>{$emt}:</td>
+<td align=left><strong>{$rcpt}</strong></td>
+</tr><tr>
+<td align=right>{$emr}:</td>
+<td align=left>
+<input type=text name=\"wpSubject\" value=\"{$wpSubject}\">
+</td>
+</tr><tr>
+<td align=right>{$emm}:</td>
+<td align=left>
+<textarea name=\"wpText\" rows=10 cols=60 wrap=virtual>
+{$wpText}
+</textarea>
+</td></tr><tr>
+<td>&nbsp;</td><td align=left>
+<input type=submit name=\"wpSend\" value=\"{$ems}\">
+</td></tr></table>
+</form>\n" );
+
+       }
+
+       function doSubmit()
+       {
+               global $wgOut, $wgUser, $wgLang, $wgOutputEncoding;
+               global $wpSubject, $wpText, $target;
+
+               $from = $wgUser->getName() . " <" . $wgUser->getEmail() . ">";
+               $headers =
+                       "MIME-Version: 1.0\r\n" .
+                       "Content-type: text/plain; charset={$wgOutputEncoding}\r\n" .
+                       "Content-transfer-encoding: 8bit\r\n" .
+                       "From: {$from}\r\n" .
+                       "Reply-To: {$from}\r\n" .
+                       "To: {$this->mAddress}\r\n" .
+                       "X-Mailer: Pediawiki interuser e-mailer";
+               mail( $this->mAddress, $wpSubject, $wpText, $headers );
+
+               $success = wfLocalUrl( $wgLang->specialPage( "Emailuser" ),
+                 "target={$target}&action=success" );
+               $wgOut->redirect( $success );
+       }
+
+       function showSuccess()
+       {
+               global $wgOut, $wgUser;
+
+               $wgOut->setPagetitle( wfMsg( "emailsent" ) );
+               $wgOut->addHTML( wfMsg( "emailsenttext" ) );
+
+               $wgOut->returnToMain( false );
+       }
+}
+?>
diff --git a/includes/SpecialImagelist.php b/includes/SpecialImagelist.php
new file mode 100644 (file)
index 0000000..459b362
--- /dev/null
@@ -0,0 +1,115 @@
+<?
+
+function wfSpecialImagelist()
+{
+       global $wgUser, $wgOut, $wgLang, $sort, $limit;
+       global $wpIlMatch, $wpIlSubmit;
+
+       $fields = array( 'wpIlMatch' );
+       wfCleanFormFields( $fields );
+
+       $sql = "SELECT img_size,img_name,img_user,img_user_text," .
+         "img_description,img_timestamp FROM image";
+
+       $byname = wfMsg( "byname" );
+       $bydate = wfMsg( "bydate" );
+       $bysize = wfMsg( "bysize" );
+
+       if ( "bysize" == $sort ) {
+               $sql .= " ORDER BY img_size DESC";
+               $st = $bysize;
+       } else if ( "byname" == $sort ) {
+               if ( $wpIlMatch ) {
+                       $nt = Title::newFromUrl( $wpIlMatch );
+                       $m = wfStrencode( strtolower( $nt->getDBkey() ) );
+                       $m = str_replace( "%", "\\%", $m );
+                       $m = str_replace( "_", "\\_", $m );
+                       $sql .= " WHERE LCASE(img_name) LIKE '%{$m}%'";
+               }
+               $sql .= " ORDER BY img_name";
+               $st = $byname;
+       } else {
+               $sql .= " ORDER BY img_timestamp DESC";
+               $st = $bydate;
+       }
+       if ( ! isset( $limit ) ) { $limit = 50; }
+       if ( 0 == $limit ) {
+               $lt = wfMsg( "all" );
+       } else {
+               $lt = "${limit}";
+               $sql .= " LIMIT {$limit}";
+       }
+       $wgOut->addHTML( "<p>" . wfMsg( "imglegend" ) . "\n" );
+
+       $text = str_replace( "$1", "<strong>{$lt}</strong>",
+         wfMsg( "imagelisttext" ) );
+       $text = str_replace( "$2", "<strong>{$st}</strong>", $text );
+       $wgOut->addHTML( "<p>{$text}\n<p>" );
+
+       $sk = $wgUser->getSkin();
+       $cap = wfMsg( "ilshowmatch" );
+       $sub = wfMsg( "ilsubmit" );
+       $action = wfLocalUrlE( $wgLang->specialPage( "Imagelist" ),
+         "sort=byname&limit={$limit}" );
+
+       $wgOut->addHTML( "<form id=\"imagesearch\" method=\"post\" action=\"" .
+         "{$action}\">" .
+         "{$cap}: <input type=text size=8 name=\"wpIlMatch\" value=\"\"> " .
+         "<input type=submit name=\"wpIlSubmit\" value=\"{$sub}\"></form>" );
+
+       $nums = array( 50, 100, 250, 500 );
+       $here = $wgLang->specialPage( "Imagelist" );
+
+       $fill = "";
+       $first = true;
+       foreach ( $nums as $num ) {
+               if ( ! $first ) { $fill .= " | "; }
+               $first = false;
+
+               $fill .= $sk->makeKnownLink( $here, "{$num}",
+                 "sort=bysize&limit={$num}" );
+       }
+       $text = str_replace( "$1", $fill, wfMsg( "showlast" ) );
+       $text = str_replace( "$2", $bysize, $text );
+       $wgOut->addHTML( "{$text}<br>\n" );
+
+       $fill = "";
+       $first = true;
+       foreach ( $nums as $num ) {
+               if ( ! $first ) { $fill .= " | "; }
+               $first = false;
+
+               $fill .= $sk->makeKnownLink( $here, $num,
+                 "sort=bydate&limit={$num}" );
+       }
+       $text = str_replace( "$1", $fill, wfMsg( "showlast" ) );
+       $text = str_replace( "$2", $bydate, $text );
+       $wgOut->addHTML( "{$text}<br>\n<p>" );
+
+       $res = wfQuery( $sql, "wfSpecialImagelist" );
+       while ( $s = wfFetchObject( $res ) ) {
+               $name = $s->img_name;
+               $ut = $s->img_user_text;
+               if ( 0 == $s->img_user ) { $ul = $ut; }
+               else { $ul = $sk->makeLink( $wgLang->getNsText(
+                 Namespace::getUser() ) . ":{$ut}", $ut ); }
+
+               $ilink = "<a href=\"" . wfImageUrl( $name ) .
+                 "\">{$name}</a>";
+
+               $nb = str_replace( "$1", $s->img_size, wfMsg( "nbytes" ) );
+               $l = "(" .
+                 $sk->makeKnownLink( $wgLang->getNsText(
+                 Namespace::getImage() ) . ":{$name}", wfMsg( "imgdesc" ) ) .
+                 ") {$ilink} . . {$nb} . . {$ul} . . " .
+                 $wgLang->timeanddate( $s->img_timestamp, true );
+
+               if ( "" != $s->img_description ) {
+                       $l .= " <em>({$s->img_description})</em>";
+               }
+               $wgOut->addHTML( "{$l}<br>\n" );
+       }
+       wfFreeResult( $res );
+}
+
+?>
diff --git a/includes/SpecialIntl.php b/includes/SpecialIntl.php
new file mode 100644 (file)
index 0000000..8e36605
--- /dev/null
@@ -0,0 +1,555 @@
+<?
+
+function wfSpecialIntl()
+{
+       global $wgUser, $wgOut, $wgLang, $wgTitle;
+       global $limit, $offset; # From query string
+       global $wgDBconnection ;
+       $fname = "wfSpecialIntl";
+       $s = "" ;
+
+       if ( ! $limit ) {
+               $limit = $wgUser->getOption( "rclimit" );
+               if ( ! $limit ) { $limit = 50; }
+       }
+       if ( ! $offset ) { $offset = 0; }
+
+       # Connecting to the wiki-intl database
+       $c = $wgDBconnection ;
+       if ( !mysql_select_db ( $wgDBIntlName, $c ) ) {
+               $wgOut->addHTML( htmlspecialchars(mysql_error()) );
+               return ;
+               }
+
+       global $mode ;
+       $mode = strtolower ( trim ( $mode ) ) ;
+       if ( $mode == "" ) $mode = "main" ;
+
+       if ( $mode == "main" ) $s .= intl_main ( $c ) ;
+       else if ( $mode == "addlink" ) $s .= intl_add ( $c ) ;
+       else if ( $mode == "zoom" ) $s .= intl_zoom ( $c ) ;
+       else if ( $mode == "incominglinks" ) $s .= intl_incoming ( $c ) ;
+       else if ( $mode == "outgoinglinks" ) $s .= intl_outgoing ( $c ) ;
+       else if ( $mode == "alllinks" ) $s .= intl_all ( $c ) ;
+       else if ( $mode == "delete" ) $s .= intl_delete ( $c ) ;
+       else if ( $mode == "recentchanges" ) $s .= intl_recentchanges ( $c ) ;
+
+       $si = "Special:Intl" ;
+       $sk = $wgUser->getSkin();
+       if ( $mode != "" && $mode != "main" )
+               $s .= $sk->makeKnownLink($si,"International issues main menu") ;
+
+       $wgOut->addHTML( $s );
+}
+
+function appendRecentChanges ( $message ) {
+       global $wgDBconnection , $wgUser , $wgLanguageCode , $wgLang ;
+       $user_name = $wgLang->getNSText(Namespace::getUser()).":".$wgUser->getName() ;
+       $user_lang = $wgLanguageCode ;
+       $message = str_replace ( '"' , '\"' , $message ) ;
+       $sql = "INSERT INTO recentchanges (user_name,user_lang,message) VALUES (
+               \"{$user_name}\",
+               \"{$user_lang}\",
+               \"{$message}\")" ;
+       $res = mysql_query ( $sql , $wgDBconnection ) ;
+       }
+
+function intl_recentchanges ( $c ) {
+       global $wgLang ;
+       $r = "<h2>Recent Link Changes</h2>\n" ;
+
+       $rc = array () ;
+       $sql = "SELECT * FROM recentchanges ORDER BY date DESC LIMIT 250" ;
+       $res = mysql_query ( $sql , $c ) ;
+       while ( $q = mysql_fetch_object ( $res ) ) $rc[] = $q ;
+       mysql_free_result ( $res ) ;
+
+       $r .= "<UL>\n" ;
+       foreach ( $rc AS $x ) {
+               $r .= "<li>" ;
+               $r .= getArticleLink ( $x->user_name , $x->user_lang ) ;
+               $h = $wgLang->time( $x->date, true );
+               $r .= " ({$h}) " ;
+               $r .= $x->message ;
+               $r .= "</li>\n" ;
+               }
+       $r .= "</UL>\n" ;
+
+       return $r ;
+       }
+
+function getArticleLink ( $title , $lang = "" ) {
+       global $wgLanguageCode ;
+       $cl = "external" ;
+       if ( $lang == "" ) $lang = $wgLanguageCode ;
+       if ( $lang == $wgLanguageCode ) $cl = "internal" ;
+       $nt = Title::newFromText ( $title ) ;
+       $link = "http://".$lang.".wikipedia.org/wiki/".$title ;
+       $link = "<a class='{$cl}' href=\"{$link}\">".$nt->getText()."</a>" ;
+       return $link ;
+       }
+
+function intl_main ( $c ) {
+       global $wgUser ;
+       $sk = $wgUser->getSkin();
+       $si = "Special:Intl" ;
+
+       $r = "<h2>International issues main menu</h2>" ;
+       $r .= "<UL>" ;
+       $r .= "<li>".$sk->makeKnownLink($si,"Add a link","mode=addlink")."</li>" ;
+       $r .= "<li>".$sk->makeKnownLink($si,"View incoming links","mode=incominglinks")."</li>" ;
+       $r .= "<li>".$sk->makeKnownLink($si,"View outgoing links","mode=outgoinglinks")."</li>" ;
+       $r .= "<li>".$sk->makeKnownLink($si,"View all links","mode=alllinks")."</li>" ;
+       $r .= "<li>".$sk->makeKnownLink($si,"Recent Link Changes","mode=recentchanges")."</li>" ;
+       $r .= "</UL>" ;
+       return $r ;
+       }
+
+function intl_add_doit ( $c ) {
+       global $wgUser , $wgLang , $wgLanguageCode , $doit ;
+       global $l_f , $l_t , $t_f , $t_t , $backlink ;
+       $sk = $wgUser->getSkin();
+       $si = "Special:Intl" ;
+
+       # checking for language link
+       $q = explode ( ":" , $t_t , 2 ) ;
+       $ln = $wgLang->getLanguageNames();
+       if ( count ( $q ) == 2 ) {
+               $nl_t = trim ( array_shift ( $q ) ) ;
+               $nt_t = trim ( array_shift ( $q ) ) ;
+               if ( $nl_t != "" AND isset ( $ln[$nl_t] ) ) {
+                       $l_t = $nl_t ;
+                       $t_t = $nt_t ;
+                       }
+               }
+
+       $nt = Title::newFromText ( $t_f ) ;
+       $t_f = $nt->getDBkey() ;
+       $nt = Title::newFromText ( $t_t ) ;
+       $t_t = $nt->getDBkey() ;
+       
+       $r = "<h2>Creating/updating language links</h2>" ;
+
+       # Deleting forward link
+       $sql = "DELETE FROM ilinks WHERE 
+lang_from='{$l_f}' AND
+lang_to='{$l_t}' AND
+title_from='{$t_f}'
+" ;
+       $res = mysql_query ( $sql , $c ) ;
+
+       $r .= "Executed {$sql}" ;
+       $r .= "<br>Result {$res}" ;
+       $r .= "<br>Error ".  htmlspecialchars(mysql_error()) ;
+       $r .= "<br><br>" ;
+
+       # Adding link
+       $sql = "INSERT INTO ilinks (lang_from,lang_to,title_from,title_to) VALUES
+('{$l_f}','{$l_t}','{$t_f}','{$t_t}')" ;
+       $res = mysql_query ( $sql , $c ) ;
+
+       $r .= "Executed {$sql}" ;
+       $r .= "<br>Result {$res}" ;
+       $r .= "<br>Error ".  htmlspecialchars(mysql_error()) ;
+
+       appendRecentChanges ( $ln[$l_f].":".getArticleLink($t_f,$l_f)." &rarr; ".
+                               $ln[$l_t].":".getArticleLink($t_t,$l_t) ) ;
+
+       if ( $backlink == "on" ) {
+               $backlink = "" ;
+               $x = $l_f ; $l_f = $l_t ; $l_t = $x ;
+               $x = $t_f ; $t_f = $t_t ; $t_t = $x ;
+               intl_add_doit ( $c ) ; # Ugly recursion
+               }
+
+       return $r ;
+       }
+
+function intl_add ( $c ) {
+       global $wgUser , $wgLang , $wgLanguageCode , $doit , $mode ;
+       global $xl , $xt , $yl , $yt ;
+       $r = "" ;
+       if ( isset ( $doit ) ) {
+               global $al_t , $at_t , $l_t , $t_t ;
+               for ( $x = 0 ; $x < 10 ; $x++ ) {
+                       if ( trim($at_t[$x]) != "" ) {
+                               $t_t = $at_t[$x] ;
+                               $l_t = $al_t[$x] ;
+                               $r .= "<font color=red size=+1>".
+                                       "The link ".
+                                       $l_f.":".$t_f." &harr; ".$l_t.":".$t_t.
+                                       " has been added.</font><br>" ;
+                               intl_add_doit ( $c ) ;
+                               }
+                       }
+               $yt = "" ;
+               $yl = "" ;
+               }
+
+       $sk = $wgUser->getSkin();
+       $si = "Special:Intl" ;
+
+       if ( $xl == "" ) $xl = $wgLanguageCode ;
+
+       $oxt = $xt ;
+       $oyt = $yt ;
+       $nt = Title::newFromText ( $xt ) ;
+       $xt = $nt->getPrefixedText () ;
+       $nt = Title::newFromText ( $yt ) ;
+       $yt = $nt->getPrefixedText () ;
+
+       $ll1 = $ll2 = "" ;
+       $a = $wgLang->getLanguageNames();
+       $ak = array_keys ( $a ) ;
+       foreach ( $ak AS $k ) {
+               $sel = "" ;
+               if ( $k == $xl ) $sel = " SELECTED" ;
+               $ll1 .= "<option{$sel} value='{$k}'>{$a[$k]}</option>\n" ;
+               $sel = "" ;
+               if ( $k == $yl ) $sel = " SELECTED" ;
+               $ll2 .= "<option{$sel} value='{$k}'>{$a[$k]}</option>\n" ;
+               }
+
+       $r .= "<h2>Add or update a link</h2>" ;
+
+       if ( $oxt != "" ) {
+               $zl = "See the group of articles interlinked for ".$a[$xl].":".$xt ;
+               $zl = $sk->makeKnownLink($si,$zl,"mode=zoom&xl={$xl}&xt={$oxt}")."<br>\n" ;
+               $al = getArticleLink ( $oxt , $xl ) ;
+               $r .= $zl.$al ;
+               }
+
+       $r .= "Note: You can also type the language code before the target (e.g., 'en:target'). The selection of the drop down box will then be ignored.<br>\n" ;
+
+       $r .= "<FORM method=post>\n" ;
+
+       $r .= "<li>Source \n" ;
+       $r .= "<select name=l_f>\n{$ll1}</select>\n " ;
+       $r .= "<input type=text name=t_f value=\"{$xt}\">\n" ;
+       $r .= "</li>\n" ;
+
+       for ( $x = 0 ; $x < 10 ; $x++ ) {
+               $r .= "<li>Destin. \n" ;
+               $r .= "<select name='al_t[{$x}]'>\n{$ll2}</select>\n " ;
+               $r .= "<input type=text name='at_t[{$x}]' value=\"{$yt}\">\n" ;
+               $r .= "</li>\n" ;
+               }
+
+       $r .= "<INPUT type=checkbox name=backlink checked>Add link in both directions<br>\n" ;
+
+       $r .= "<INPUT type=submit name=doit value='Do it'>\n" ;
+
+       $r .= "</FORM>\n" ;
+
+       return $r ;
+       }
+
+function eliminate_doubles ( &$list ) { # Real ugly
+       $ak = array_keys ( $list ) ;
+       foreach ( $ak AS $k1 ) {
+               if ( $list[$k1]->hidden ) continue ;
+               foreach ( $ak AS $k2 ) {
+                       if ( $k1 != $k2 &&
+                               $list[$k1]->title_from == $list[$k2]->title_to &&
+                               $list[$k1]->title_to == $list[$k2]->title_from &&
+                               $list[$k1]->lang_from == $list[$k2]->lang_to &&
+                               $list[$k1]->lang_to == $list[$k2]->lang_from ) {
+                               $list[$k1]->both = true ;
+                               $list[$k2]->hidden = true ;
+                               break ;
+                               }
+                       }
+               }
+       }
+
+function displayLinks ( $list , $opt = "" ) {
+       eliminate_doubles ( $list ) ;
+       global $wgLang , $wgUser , $mode ;
+       $si = "Special:Intl" ;
+       $sk = $wgUser->getSkin();
+       $ln = $wgLang->getLanguageNames();
+       $r = "" ;
+
+       if ( !isset ( $opt->showdel ) ) $opt->showdel = true ;
+
+       global $limit , $offset , $intlparam ;
+       if ( $intlparam != "" ) {
+               $r .= wfShowingResults( $offset, $limit );
+               $sl = wfViewPrevNext( $offset, $limit,
+                 $wgLang->specialPage( "Intl".$intlparam ) );
+               $r .= "<br>{$sl}\n" ;
+               }
+
+       $r .= "<table border=1 cellpadding=2 cellspacing=0>\n" ;
+       $r .= "<tr>\n" ;
+       $r .= "<th colspan=2>From</th>\n" ;
+       $r .= "<th>&nbsp;</th>\n" ;
+       $r .= "<th colspan=2>To</th>\n" ;
+       if ( $mode != "zoom" ) $r .= "<th>&nbsp;</th>\n" ;
+       if ( $opt->showdel ) $r .= "<th colspan=3>Delete</th>\n" ;
+       if ( $opt->display != "" ) $r .= "<th colspan=3>".$opt->display."</th>\n" ;
+       $r .= "</tr>\n" ;
+
+       foreach ( $list AS $q ) {
+               if ( $q->hidden ) continue ;
+               $zoom = "xl={$q->lang_from}&xt=".urlencode($q->title_from) ;
+               $zoom = $sk->makeKnownLink($si,"[&Sigma;]","mode=zoom&{$zoom}") ;
+               $del1 = "xl={$q->lang_from}&xt=".urlencode($q->title_from)."&yl={$q->lang_to}" ;
+               $del2 = $sk->makeKnownLink($si,"[&harr;]","mode=delete&{$del1}&back=yes") ;
+               $del1 = $sk->makeKnownLink($si,"[&rarr;]","mode=delete&{$del1}") ;
+               $del1a = "xl={$q->lang_to}&xt=".urlencode($q->title_to)."&yl={$q->lang_from}" ;
+               $del1a = $sk->makeKnownLink($si,"[&larr;]","mode=delete&{$del1a}") ;
+               $sign = "&rarr;" ;
+               if ( $q->both ) $sign = "&harr;" ;
+               else $del1a = "&nbsp;" ;
+
+               $r .= "<tr>\n" ;
+               $r .= "<td>".$ln[$q->lang_from]."</td>\n" ;
+               $r .= "<td>".getArticleLink($q->title_from,$q->lang_from)."</td>\n" ;
+               $r .= "<td> {$sign} </td>\n" ;
+               $r .= "<td>".$ln[$q->lang_to]."</td>\n" ;
+               $r .= "<td>".getArticleLink($q->title_to,$q->lang_to)."</td>\n" ;
+               if ( $mode != "zoom" ) $r .= "<td>{$zoom}</td>\n" ;
+               if ( $opt->showdel ) {
+                       $r .= "<td>{$del1}</td>\n" ;
+                       $r .= "<td>{$del1a}</td>\n" ;
+                       $r .= "<td>{$del2}</td>\n" ;
+                       }
+               if ( $opt->display != "" ) {
+                       if ( $q->display == "" ) $q->display = "&nbsp;" ;
+                       $r .= "<td>{$q->display}</td>\n" ;
+                       }
+               $r .= "</tr>\n" ;
+               }
+       $r .= "</table>\n" ;
+       if ( $intlparam != "" )
+               $r .= "{$sl}<br>\n" ;
+       return $r ;
+       }
+
+function intl_outgoing ( $c ) {
+       global $wgLanguageCode ;
+       global $limit , $offset , $intlparam ;
+       $intlparam = "&mode=outgoinglinks" ;
+       $list = array() ;
+       $r = "<h2>Outgoing links</h2>\n" ;
+       $sql = "SELECT * FROM ilinks WHERE lang_from='{$wgLanguageCode}' LIMIT {$offset}, {$limit}";
+       $res = mysql_query ( $sql , $c ) ;
+       while ( $q = mysql_fetch_object ( $res ) ) $list[] = $q ;
+       mysql_free_result ( $res ) ;
+       $r .= displayLinks ( $list ) ;
+       return $r ;
+       }
+
+function intl_incoming ( $c ) {
+       global $wgLanguageCode ;
+       global $limit , $offset , $intlparam ;
+       $intlparam = "&mode=incominglinks" ;
+       $list = array() ;
+       $r = "<h2>Incoming links</h2>\n" ;
+       $sql="SELECT * FROM ilinks WHERE lang_to='{$wgLanguageCode}' LIMIT {$offset}, {$limit}";
+       $res = mysql_query ( $sql , $c ) ;
+       while ( $q = mysql_fetch_object ( $res ) ) $list[] = $q ;
+       mysql_free_result ( $res ) ;
+       $r .= displayLinks ( $list ) ;
+       return $r ;
+       }
+
+function intl_all ( $c ) {
+       global $wgLanguageCode ;
+       global $limit , $offset , $intlparam ;
+       $intlparam = "&mode=alllinks" ;
+       $list = array() ;
+       $r = "<h2>All links</h2>\n" ;
+       $sql = "SELECT * FROM ilinks LIMIT {$offset}, {$limit}";
+       $res = mysql_query ( $sql , $c ) ;
+       while ( $q = mysql_fetch_object ( $res ) ) $list[] = $q ;
+       mysql_free_result ( $res ) ;
+       $r .= displayLinks ( $list ) ;
+       return $r ;
+       }
+
+
+function do_zoom ( &$found , &$list , $c ) {
+       $news = array () ;
+       foreach ( $found AS $x ) {
+               if ( $x->new ) {
+$sql = "SELECT * FROM ilinks WHERE 
+( lang_from='{$x->lang}' AND title_from='{$x->title}' ) OR 
+( lang_to='{$x->lang}'   AND title_to='{$x->title}' )
+" ;
+                       $res = mysql_query ( $sql , $c ) ;
+                       while ( $q = mysql_fetch_object ( $res ) ) {
+                               $i->orig = $q ;
+                               $i->lang = $q->lang_from ;
+                               $i->title = $q->title_from ;
+                               $news[] = $i ;
+
+                               $i->lang = $q->lang_to ;
+                               $i->title = $q->title_to ;
+                               $news[] = $i ;
+                               }
+                       mysql_free_result ( $res ) ;
+                       }
+               }
+       $ak = array_keys ( $found ) ;
+       foreach ( $ak AS $x ) $found[$x]->new = false ;
+
+       # Adding new ones
+       $isnewone = false ;
+       foreach ( $news AS $n ) {
+               $didfind = 0 ;
+               foreach ( $found AS $f ) {
+                       if($n->lang==$f->lang AND $n->title==$f->title) {
+                               $didfind=1;
+                               if ( $f->new ) $list[] = $n->orig ;
+                               }
+                       }
+               if ( $didfind == 0 ) {
+                       $i->lang = $n->lang ;
+                       $i->title = $n->title ;
+                       $i->new = true ;
+                       $found[] = $i ;
+                       $list[] = $n->orig ;
+                       $isnewone = true ;
+                       }
+               }
+
+       if ( $isnewone ) do_zoom ( $found , $list , $c ) ;
+       }
+
+function getMissingLinks ( $found , $list ) {
+       $a = $r = array () ;
+       foreach ( $found AS $f1 ) {
+               foreach ( $found AS $f2 ) {
+                       if ( $f1 != $f2 ) {
+                               $i->lang_from = $f1->lang ;
+                               $i->lang_to = $f2->lang ;
+                               $i->title_from = $f1->title ;
+                               $i->title_to = $f2->title ;
+                               $a[] = $i ;
+                               }
+                       }
+               }
+       foreach ( $a AS $x ) {
+               $f = false ;
+               foreach ( $list AS $l ) {
+                       if ( $x->lang_from == $l->lang_from &&
+                            $x->lang_to == $l->lang_to &&
+                            $x->title_from == $l->title_from &&
+                            $x->title_to == $l->title_to ) {
+                               $f = true ;
+                               break ;
+                               }
+                       }
+               if ( !$f ) $r[] = $x ;
+               }
+       return $r ;
+       }
+
+function intl_zoom2 ( $c ) {
+       global $doit , $ZLF , $ZLT , $ZTF , $ZTT , $ZCB ;
+       global $l_f , $l_t , $t_f , $t_t , $backlink ;
+       $r = "<h2>Adding selected language links</h2>\n" ;
+       $r .= "<OL>\n" ;
+       $ak = array_keys ( $ZCB ) ;
+       foreach ( $ak AS $cnt ) {
+               if ( $ZCB[$cnt] == "on" ) {
+                       $l_f = $ZLF[$cnt] ;
+                       $l_t = $ZLT[$cnt] ;
+                       $t_f = $ZTF[$cnt] ;
+                       $t_t = $ZTT[$cnt] ;
+                       $backlink = "on" ;
+                       intl_add_doit ( $c ) ;
+                       $r .= "<li>$l_f:$t_f &harr; $l_t:$t_t</li>\n" ;
+                       }
+               }
+       $r .= "</OL>\n" ;
+       return $r ;
+       }
+
+function intl_zoom ( $c ) {
+       global $doit ;
+       global $wgLanguageCode , $wgLang ;
+       global $xl , $xt ;
+       if ( isset ( $doit ) ) return intl_zoom2 ( $c ) ;
+       $ln = $wgLang->getLanguageNames();
+       $list = array() ;
+       $found = array () ;
+       $r = "<h2>Interlinked articles group</h2>\n" ;
+       $initial->lang = $xl ;
+       $initial->title = urldecode ( $xt ) ;
+       $initial->new = true ;
+       $found[] = $initial ;
+
+       do_zoom ( $found , $list , $c ) ;
+
+       $involved = array() ;
+       foreach ( $found AS $f )
+               $involved[] = $ln[$f->lang].":".getArticleLink ( $f->title , $f->lang ) ;
+       $r .= "Involved are ".implode ( ", " , $involved )."<br>\n" ;
+
+       $r .= displayLinks ( $list ) ;
+
+       $list2 = getMissingLinks ( $found , $list ) ;
+
+       if ( count ( $list2 ) > 0 ) {
+               $r .= "<h3>Missing links</h3>\n" ;
+               $opt->showdel = false ;
+               $opt->display = "Create" ;
+               $ak = array_keys ( $list2 ) ;
+               $cnt = 1 ;
+               foreach ( $ak AS $a ) {
+                       $b = $list2[$a] ;
+                       $z = "<input type=checkbox name='ZCB[{$cnt}]' checked>\n" ;
+                       $z.="<input type=hidden name='ZLF[{$cnt}]' value='{$b->lang_from}'>\n";
+                       $z.="<input type=hidden name='ZLT[{$cnt}]' value='{$b->lang_to}'>\n";
+                       $z.="<input type=hidden name='ZTF[{$cnt}]' value='{$b->title_from}'>\n";
+                       $z.="<input type=hidden name='ZTT[{$cnt}]' value='{$b->title_to}'>\n";
+                       $list2[$a]->display = $z ;
+                       $cnt++ ;
+                       }
+               $r .= "<FORM method=post>\n" ;
+               $r .= displayLinks ( $list2 , $opt ) ;
+               $r .= "<INPUT type=submit name=doit value='Create selected links'>\n" ;
+               $r .= " (Note: This is still buggy, I don't know why...)" ;
+               $r .= "</FORM>\n" ;
+               }
+
+       return $r ;
+       }
+
+function intl_delete ( $c ) {
+       global $wgLang ;
+       global $xt , $xl , $yl , $back ;
+       $title = urldecode ( $xt ) ;
+       $ln = $wgLang->getLanguageNames();
+
+       $sql = "DELETE FROM ilinks WHERE 
+lang_from='{$xl}' AND
+lang_to='{$yl}' AND
+title_from='{$title}'
+" ;
+       $res = mysql_query ( $sql , $c ) ;
+
+       $r = "<h2>Deletion</h2>" ;
+       $r .= "The link from ".$ln[$xl].":".$title." to ".$ln[$yl]." has been deleted.<br>" ;
+
+       appendRecentChanges ( "- ".$ln[$xl].":".getArticleLink($title,$xl)." &rarr;" ) ;
+
+       # Backlink?
+       if ( $back != "yes" ) return $r ;
+
+       $sql = "DELETE FROM ilinks WHERE 
+lang_to='{$xl}' AND
+lang_from='{$yl}' AND
+title_to='{$title}'
+" ;
+       $res = mysql_query ( $sql , $c ) ;
+
+       appendRecentChanges ( "- &rarr;".$ln[$xl].":".getArticleLink($title,$xl) ) ;
+
+       $r .= "As was the backlink.<br>" ;
+       return $r ;
+       }
+?>
diff --git a/includes/SpecialIpblocklist.php b/includes/SpecialIpblocklist.php
new file mode 100644 (file)
index 0000000..e46748f
--- /dev/null
@@ -0,0 +1,128 @@
+<?
+
+function wfSpecialIpblocklist()
+{
+       global $wgUser, $wgOut, $action, $ip;
+
+       $fields = array( "wpUnblockAddress" );
+       wfCleanFormFields( $fields );
+       $ipu = new IPUnblockForm();
+
+       if ( "success" == $action ) {
+               $msg = str_replace( "$1", $ip, wfMsg( "ipusuccess" ) );
+               $ipu->showList( $msg );
+       } else if ( "submit" == $action ) {
+               if ( ! $wgUser->isSysop() ) {
+                       $wgOut->sysopRequired();
+                       return;
+               }
+               $ipu->doSubmit();
+       } else if ( "unblock" == $action ) {
+               $ipu->showForm( "" );
+       } else {
+               $ipu->showList( "" );
+       }
+}
+
+class IPUnblockForm {
+
+       function showForm( $err )
+       {
+               global $wgOut, $wgUser, $wgLang;
+               global $ip, $wpUnblockAddress;
+
+               $wgOut->setPagetitle( wfMsg( "unblockip" ) );
+               $wgOut->addWikiText( wfMsg( "unblockiptext" ) );
+
+               if ( ! $wpUnblockAddress ) { $wpUnblockAddress = $ip; }
+               $ipa = wfMsg( "ipaddress" );
+               $ipus = wfMsg( "ipusubmit" );
+               $action = wfLocalUrlE( $wgLang->specialPage( "Ipblocklist" ),
+                 "action=submit" );
+
+               if ( "" != $err ) {
+                       $wgOut->setSubtitle( wfMsg( "formerror" ) );
+                       $wgOut->addHTML( "<p><font color='red' size='+1'>{$err}</font>\n" );
+               }
+               $wgOut->addHTML( "<p>
+<form id=\"unblockip\" method=\"post\" action=\"{$action}\">
+<table border=0><tr>
+<td align=right>{$ipa}:</td>
+<td align=left>
+<input tabindex=1 type=text size=20 name=\"wpUnblockAddress\" value=\"{$wpUnblockAddress}\">
+</td></tr><tr>
+<td>&nbsp;</td><td align=left>
+<input tabindex=2 type=submit name=\"wpBlock\" value=\"{$ipus}\">
+</td></tr></table>
+</form>\n" );
+
+       }
+
+       function doSubmit()
+       {
+               global $wgOut, $wgUser, $wgLang;
+               global $ip, $wpUnblockAddress;
+               $fname = "IPUnblockForm::doSubmit";
+
+               if ( ! preg_match( "/\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}/",
+                 $wpUnblockAddress ) ) {
+                       $this->showForm( wfMsg( "badipaddress" ) );
+                       return;
+               }
+               $sql = "DELETE FROM ipblocks WHERE ipb_address='{$wpUnblockAddress}'";
+               wfQuery( $sql, $fname );
+
+               $success = wfLocalUrl( $wgLang->specialPage( "Ipblocklist" ),
+                 "action=success&ip={$wpUnblockAddress}" );
+               $wgOut->redirect( $success );
+       }
+
+       function showList( $msg )
+       {
+               global $wgOut, $wgUser, $wgLang;
+               global $ip;
+
+               $wgOut->setPagetitle( wfMsg( "ipblocklist" ) );
+               if ( "" != $msg ) {
+                       $wgOut->setSubtitle( $msg );
+               }
+               $sql = "SELECT ipb_timestamp,ipb_address,ipb_user,ipb_by,ipb_reason " .
+                 "FROM ipblocks ORDER BY ipb_timestamp";
+               $res = wfQuery( $sql, "IPUnblockForm::showList" );
+
+               $wgOut->addHTML( "<ul>" );
+               $sk = $wgUser->getSkin();
+               while ( $row = wfFetchObject( $res ) ) {
+                       $addr = $row->ipb_address;
+                       $name = User::whoIs( $row->ipb_by );
+                       $ulink = $sk->makeKnownLink( $wgLang->getNsText( Namespace::getUser() ). ":{$name}", $name );
+                       $d = $wgLang->timeanddate( $row->ipb_timestamp, true );
+
+                       $line = str_replace( "$1", $d, wfMsg( "blocklistline" ) );
+                       $line = str_replace( "$2", $ulink, $line );
+                       $line = str_replace( "$3", $row->ipb_address, $line );
+
+                       $wgOut->addHTML( "<li>{$line}" );
+                       $clink = "<a href=\"" . wfLocalUrlE( $wgLang->specialPage(
+                         "Contributions" ), "target={$addr}" ) . "\">" .
+                         wfMsg( "contribslink" ) . "</a>";
+                       $wgOut->addHTML( " ({$clink})" );
+
+                       if ( $wgUser->isSysop() ) {
+                               $ublink = "<a href=\"" . wfLocalUrlE( $wgLang->specialPage(
+                                 "Ipblocklist" ), "action=unblock&ip={$addr}" ) . "\">" .
+                                 wfMsg( "unblocklink" ) . "</a>";
+                               $wgOut->addHTML( " ({$ublink})" );
+                       }
+                       if ( "" != $row->ipb_reason ) {
+                               $wgOut->addHTML( " <em>(" . wfEscapeHTML( $row->ipb_reason ) .
+                                 ")</em>" );
+                       }
+                       $wgOut->addHTML( "</li>\n" );
+               }
+               wfFreeResult( $res );
+               $wgOut->addHTML( "</ul>\n" );
+       }
+}
+
+?>
diff --git a/includes/SpecialListusers.php b/includes/SpecialListusers.php
new file mode 100644 (file)
index 0000000..3d9c098
--- /dev/null
@@ -0,0 +1,42 @@
+<?
+
+function wfSpecialListusers()
+{
+       global $wgUser, $wgOut, $wgLang, $offset, $limit;
+
+       if ( ! $limit ) {
+               $limit = $wgUser->getOption( "rclimit" );
+               if ( ! $limit ) { $limit = 50; }
+       }
+       if ( ! $offset ) { $offset = 0; }
+
+       $top = wfShowingResults( $offset, $limit );
+       $wgOut->addHTML( "<p>{$top}\n" );
+
+       $sl = wfViewPrevNext( $offset, $limit,
+         $wgLang->specialPage( "Listusers" ) );
+       $wgOut->addHTML( "<br>{$sl}\n<ol start=" . ( $offset + 1 ) . ">" );
+
+       $sql = "SELECT user_name,user_rights FROM user ORDER BY " .
+         "user_name LIMIT {$offset}, {$limit}";
+       $res = wfQuery( $sql, "wfSpecialListusers" );
+
+       $sk = $wgUser->getSkin();
+       while ( $s = wfFetchObject( $res ) ) {
+               $n = $s->user_name;
+               $r = $s->user_rights;
+
+               $l = $sk->makeLink( $wgLang->getNsText(
+                 Namespace::getUser() ) . ":{$n}", $n );
+
+               if ( "" != $r ) {
+                       $link = $sk->makeKnownLink( wfMsg( "administrators" ), $r );
+                       $l .= " ({$link})";
+               }
+               $wgOut->addHTML( "<li>{$l}</li>\n" );
+       }
+       wfFreeResult( $res );
+       $wgOut->addHTML( "</ol><p>{$sl}\n" );
+}
+
+?>
diff --git a/includes/SpecialLockdb.php b/includes/SpecialLockdb.php
new file mode 100644 (file)
index 0000000..efc75a0
--- /dev/null
@@ -0,0 +1,96 @@
+<?
+
+function wfSpecialLockdb()
+{
+       global $wgUser, $wgOut, $action;
+
+       if ( ! $wgUser->isDeveloper() ) {
+               $wgOut->developerRequired();
+               return;
+       }
+       $fields = array( "wpLockReason" );
+       wfCleanFormFields( $fields );
+
+       $f = new DBLockForm();
+
+       if ( "success" == $action ) { $f->showSuccess(); }
+       else if ( "submit" == $action ) { $f->doSubmit(); }
+       else { $f->showForm( "" ); }
+}
+
+class DBLockForm {
+
+       function showForm( $err )
+       {
+               global $wgOut, $wgUser, $wgLang;
+               global $wpLockConfirm;
+
+               $wgOut->setPagetitle( wfMsg( "lockdb" ) );
+               $wgOut->addWikiText( wfMsg( "lockdbtext" ) );
+
+               if ( "" != $err ) {
+                       $wgOut->setSubtitle( wfMsg( "formerror" ) );
+                       $wgOut->addHTML( "<p><font color='red' size='+1'>{$err}</font>\n" );
+               }
+               $lc = wfMsg( "lockconfirm" );
+               $lb = wfMsg( "lockbtn" );
+               $elr = wfMsg( "enterlockreason" );
+               $action = wfLocalUrlE( $wgLang->specialPage( "Lockdb" ),
+                 "action=submit" );
+
+               $wgOut->addHTML( "<p>
+<form id=\"lockdb\" method=\"post\" action=\"{$action}\">
+{$elr}:
+<textarea name=\"wpLockReason\" rows=10 cols=60 wrap=virtual>
+</textarea>
+<table border=0><tr>
+<td align=right>
+<input type=checkbox name=\"wpLockConfirm\">
+</td>
+<td align=left>{$lc}<td>
+</tr><tr>
+<td>&nbsp;</td><td align=left>
+<input type=submit name=\"wpLock\" value=\"{$lb}\">
+</td></tr></table>
+</form>\n" );
+
+       }
+
+       function doSubmit()
+       {
+               global $wgOut, $wgUser, $wgLang;
+               global $wpLockConfirm, $wpLockReason, $wgReadOnlyFile;
+
+               if ( ! $wpLockConfirm ) {
+                       $this->showForm( wfMsg( "locknoconfirm" ) );
+                       return;
+               }
+               $fp = fopen( $wgReadOnlyFile, "w" );
+
+               if ( false === $fp ) {
+                       $wgOut->fileNotFoundError( $wgReadOnlyFile );
+                       return;
+               }
+               fwrite( $fp, $wpLockReason );
+               fwrite( $fp, "\n<p>(by " . $wgUser->getName() . " at " .
+                 $wgLang->timeanddate( date( "YmdHis" ) ) . ")\n" );
+               fclose( $fp );
+
+               $success = wfLocalUrl( $wgLang->specialPage( "Lockdb" ),
+                 "action=success" );
+               $wgOut->redirect( $success );
+       }
+
+       function showSuccess()
+       {
+               global $wgOut, $wgUser;
+               global $ip;
+
+               $wgOut->setPagetitle( wfMsg( "lockdb" ) );
+               $wgOut->setSubtitle( wfMsg( "lockdbsuccesssub" ) );
+               $text = str_replace( "$1", $ip, wfMsg( "lockdbsuccesstext" ) );
+               $wgOut->addWikiText( $text );
+       }
+}
+
+?>
diff --git a/includes/SpecialLonelypages.php b/includes/SpecialLonelypages.php
new file mode 100644 (file)
index 0000000..b62b482
--- /dev/null
@@ -0,0 +1,46 @@
+<?
+
+function wfSpecialLonelypages()
+{
+       global $wgUser, $wgOut, $wgLang, $wgTitle;
+       global $limit, $offset; # From query string
+       $fname = "wfSpecialLonelypages";
+
+       global $wgMiserMode;
+       if ( $wgMiserMode ) {
+               $wgOut->addWikiText( wfMsg( "perfdisabled" ) );
+               return;
+       }
+
+       if ( ! $limit ) {
+               $limit = $wgUser->getOption( "rclimit" );
+               if ( ! $limit ) { $limit = 50; }
+       }
+       if ( ! $offset ) { $offset = 0; }
+
+       $sql = "SELECT cur_title FROM cur LEFT JOIN links ON " .
+         "cur_id=l_to WHERE l_to IS NULL AND cur_namespace=0 AND " .
+         "cur_is_redirect=0 ORDER BY cur_title LIMIT {$offset}, {$limit}";
+       $res = wfQuery( $sql, $fname );
+
+       $sk = $wgUser->getSkin();
+
+       $top = wfShowingResults( $offset, $limit );
+       $wgOut->addHTML( "<p>{$top}\n" );
+
+       $sl = wfViewPrevNext( $offset, $limit,
+         $wgLang->specialPage( "Lonelypages" ) );
+       $wgOut->addHTML( "<br>{$sl}\n" );
+
+       $s = "<ol start=" . ( $offset + 1 ) . ">";
+       while ( $obj = wfFetchObject( $res ) ) {
+               $link = $sk->makeKnownLink( $obj->cur_title, "" );
+               $s .= "<li>{$link}</li>\n";
+       }
+       wfFreeResult( $res );
+       $s .= "</ol>";
+       $wgOut->addHTML( $s );
+       $wgOut->addHTML( "<p>{$sl}\n" );
+}
+
+?>
diff --git a/includes/SpecialLongpages.php b/includes/SpecialLongpages.php
new file mode 100644 (file)
index 0000000..3807abd
--- /dev/null
@@ -0,0 +1,47 @@
+<?
+
+function wfSpecialLongpages()
+{
+       global $wgUser, $wgOut, $wgLang, $wgTitle;
+       global $limit, $offset; # From query string
+       $fname = "wfSpecialLongpages";
+
+       global $wgMiserMode;
+       if ( $wgMiserMode ) {
+               $wgOut->addWikiText( wfMsg( "perfdisabled" ) );
+               return;
+       }
+
+       if ( ! $limit ) {
+               $limit = $wgUser->getOption( "rclimit" );
+               if ( ! $limit ) { $limit = 50; }
+       }
+       if ( ! $offset ) { $offset = 0; }
+
+       $sql = "SELECT cur_title, LENGTH(cur_text) AS len FROM cur " .
+         "WHERE cur_namespace=0 AND cur_is_redirect=0 ORDER BY " .
+         "LENGTH(cur_text) DESC LIMIT {$offset}, {$limit}";
+       $res = wfQuery( $sql, $fname );
+
+       $sk = $wgUser->getSkin();
+
+       $top = wfShowingResults( $offset, $limit );
+       $wgOut->addHTML( "<p>{$top}\n" );
+
+       $sl = wfViewPrevNext( $offset, $limit,
+         $wgLang->specialPage( "Longpages" ) );
+       $wgOut->addHTML( "<br>{$sl}\n" );
+
+       $s = "<ol start=" . ( $offset + 1 ) . ">";
+       while ( $obj = wfFetchObject( $res ) ) {
+               $nb = str_replace( "$1", $obj->len, wfMsg( "nbytes" ) );
+               $link = $sk->makeKnownLink( $obj->cur_title, "" );
+               $s .= "<li>{$link} ({$nb})</li>\n";
+       }
+       wfFreeResult( $res );
+       $s .= "</ol>";
+       $wgOut->addHTML( $s );
+       $wgOut->addHTML( "<p>{$sl}\n" );
+}
+
+?>
diff --git a/includes/SpecialMaintenance.php b/includes/SpecialMaintenance.php
new file mode 100644 (file)
index 0000000..9a830e4
--- /dev/null
@@ -0,0 +1,368 @@
+<?
+
+function sns()
+       {
+       global $wgLang ;
+       $ns = $wgLang->getNamespaces() ;
+       return $ns[-1] ;
+       }
+
+function wfSpecialMaintenance ()
+       {
+       global $wgUser, $wgOut, $wgLang, $wgTitle, $subfunction, $wgLanguageCode, $submitmll;
+       global $wgMiserMode;
+       if ( $wgMiserMode ) {
+               $wgOut->addWikiText( wfMsg( "perfdisabled" ) );
+               return;
+       }
+
+       if ( $subfunction == "disambiguations" ) return wfSpecialDisambiguations() ;
+       if ( $subfunction == "doubleredirects" ) return wfSpecialDoubleRedirects() ;
+       if ( $subfunction == "brokenredirects" ) return wfSpecialBrokenRedirects() ;
+       if ( $subfunction == "selflinks" ) return wfSpecialSelfLinks() ;
+        if ( $subfunction == "mispeelings" ) return wfSpecialMispeelings() ;
+       if ( $subfunction == "missinglanguagelinks" ) return wfSpecialMissingLanguageLinks() ;
+       if ( isset ( $submitmll ) ) return wfSpecialMissingLanguageLinks() ;
+
+       $sk = $wgUser->getSkin();
+       $ns = $wgLang->getNamespaces() ;
+       $r = wfMsg("maintnancepagetext") ;
+       $r .= "<UL>\n" ;
+       $r .= "<li>".getMPL("disambiguations")."</li>\n" ;
+       $r .= "<li>".getMPL("doubleredirects")."</li>\n" ;
+       $r .= "<li>".getMPL("brokenredirects")."</li>\n" ;
+       $r .= "<li>".getMPL("selflinks")."</li>\n" ;
+        $r .= "<li>".getMPL("mispeelings")."</li>\n" ;
+
+       $r .= "<li>";
+       $l = getMPL("missinglanguagelinks");
+       $l = str_replace ( "</a>" , "" , $l ) ;
+       $l = str_replace ( "<a " , "<FORM method=post " , $l ) ;
+       $l = explode ( ">" , $l ) ;
+       $l = $l[0] ;
+       $r .= $l.">\n" ;
+       $r .= "<input type=submit name='submitmll' value='" ;
+       $r .= wfMsg("missinglanguagelinksbutton");
+       $r .= "'>\n" ;
+       $r .= "<select name=thelang>\n" ;
+       $a = $wgLang->getLanguageNames();
+       $ak = array_keys ( $a ) ;
+       foreach ( $ak AS $k ) {
+               if ( $k != $wgLanguageCode )
+                       $r .= "<option value='{$k}'>{$a[$k]}</option>\n" ;
+               }
+       $r .= "</select>\n" ;
+       $r .= "</FORM>\n</li>" ;
+
+       $r .= "</UL>\n" ;
+       $wgOut->addHTML ( $r ) ;
+       }
+
+function getMPL ( $x )
+       {
+       global $wgUser , $wgLang;
+       $sk = $wgUser->getSkin() ;
+       return $sk->makeKnownLink(sns().":Maintenance",wfMsg($x),"subfunction={$x}") ;
+       }
+
+function getMaintenancePageBacklink()
+       {
+       global $wgUser , $wgLang , $subfunction ;
+       $sk = $wgUser->getSkin() ;
+       $ns = $wgLang->getNamespaces() ;
+       $r = $sk->makeKnownLink (
+               $ns[-1].":Maintenance",
+               wfMsg("maintenancebacklink") ) ;
+       $t = wfMsg ( $subfunction ) ;
+       
+       $s = "<table width=100% border=0><tr><td>";
+       $s .= "<h2>{$t}</h2></td><td align=right>";
+       $s .= "{$r}</td></tr></table>\n" ;
+       return $s ;
+       }
+
+
+function wfSpecialDisambiguations()
+{
+       global $wgUser, $wgOut, $wgLang, $wgTitle;
+       global $limit, $offset; # From query string
+       $fname = "wfSpecialDisambiguations";
+
+       if ( ! $limit ) {
+               $limit = $wgUser->getOption( "rclimit" );
+               if ( ! $limit ) { $limit = 50; }
+       }
+       if ( ! $offset ) { $offset = 0; }
+
+       $dp = wfStrencode( wfMsg("disambiguationspage") );
+
+       $sql = "SELECT la.l_from,la.l_to,"
+               . " lb.l_from AS source,lb.l_to AS dest,"
+               . " c.cur_id, c.cur_title AS dt"
+               . " FROM links AS la, links AS lb, cur AS c, cur AS d"
+               . " WHERE la.l_from='{$dp}'"
+               . " AND la.l_to=lb.l_to"
+               . " AND la.l_from<>lb.l_from"
+               . " AND c.cur_id=lb.l_to"
+               . " AND c.cur_namespace=0"
+               . " AND d.cur_title=lb.l_from"
+               . " AND d.cur_namespace=0"
+               . " LIMIT {$offset}, {$limit}";
+
+       $res = wfQuery( $sql, $fname );
+
+       $sk = $wgUser->getSkin();
+
+       $top = "<p>".wfMsg("disambiguationstext")."</p><br>\n";
+       $top = str_replace ( "$1" , $sk->makeKnownLink ( $dp ) , $top ) ;
+       $top = getMaintenancePageBacklink().$top ;
+       $top .= wfShowingResults( $offset, $limit );
+       $wgOut->addHTML( "<p>{$top}\n" );
+
+       $sl = wfViewPrevNext( $offset, $limit, "REPLACETHIS" ) ;
+       $sl = str_replace ( "REPLACETHIS" , sns().":Maintenance&subfunction=disambiguations" , $sl ) ;
+       $wgOut->addHTML( "<br>{$sl}\n" );
+
+       $s = "<ol start=" . ( $offset + 1 ) . ">";
+       while ( $obj = wfFetchObject( $res ) ) {
+               $l1 = $sk->makeKnownLink ( $obj->source , "" , "redirect=no" ) ;
+               $l2 = $sk->makeKnownLink ( $obj->dt ) ;
+               $l3 = $sk->makeBrokenLink ( $obj->source , "(".wfMsg("qbedit").")" , "redirect=no" ) ;
+               $s .= "<li>{$l1} {$l3} => {$l2}</li>\n" ;
+       }
+       wfFreeResult( $res );
+       $s .= "</ol>";
+       $wgOut->addHTML( $s );
+       $wgOut->addHTML( "<p>{$sl}\n" );
+}
+
+function wfSpecialDoubleRedirects()
+{
+       global $wgUser, $wgOut, $wgLang, $wgTitle;
+       global $limit, $offset; # From query string
+       $fname = "wfSpecialDoubleRedirects";
+
+       if ( ! $limit ) {
+               $limit = $wgUser->getOption( "rclimit" );
+               if ( ! $limit ) { $limit = 50; }
+       }
+       if ( ! $offset ) { $offset = 0; }
+
+       $sql = "SELECT l_from,l_to,cb.cur_text AS rt,cb.cur_title AS ti FROM links,cur AS ca, cur AS cb WHERE ca.cur_is_redirect=1 AND cb.cur_is_redirect=1 AND l_to=cb.cur_id AND l_from=ca.cur_title AND ca.cur_namespace=0 LIMIT {$offset}, {$limit}" ;
+
+       $res = wfQuery( $sql, $fname );
+
+       $top = getMaintenancePageBacklink();
+       $top .= "<p>".wfMsg("doubleredirectstext")."</p><br>\n";
+       $top .= wfShowingResults( $offset, $limit );
+       $wgOut->addHTML( "<p>{$top}\n" );
+
+       $sl = wfViewPrevNext( $offset, $limit, "REPLACETHIS" ) ;
+       $sl = str_replace ( "REPLACETHIS" , sns().":Maintenance&subfunction=doubleredirects" , $sl ) ;
+       $wgOut->addHTML( "<br>{$sl}\n" );
+
+       $sk = $wgUser->getSkin();
+       $s = "<ol start=" . ( $offset + 1 ) . ">";
+       while ( $obj = wfFetchObject( $res ) ) {
+               $n = explode ( "\n" , $obj->rt ) ;
+               $n = $n[0] ;
+               $l1 = $sk->makeKnownLink ( $obj->l_from , "" , "redirect=no" ) ;
+               $l2 = $sk->makeKnownLink ( $obj->ti , "" , "redirect=no" ) ;
+               $l3 = $sk->makeBrokenLink ( $obj->l_from , "(".wfMsg("qbedit").")" , "redirect=no" ) ;
+               $s .= "<li>{$l1} {$l3} => {$l2} (\"{$n}\")</li>\n" ;
+       }
+       wfFreeResult( $res );
+       $s .= "</ol>";
+       $wgOut->addHTML( $s );
+       $wgOut->addHTML( "<p>{$sl}\n" );
+}
+
+function wfSpecialBrokenRedirects()
+{
+       global $wgUser, $wgOut, $wgLang, $wgTitle;
+       global $limit, $offset; # From query string
+       $fname = "wfSpecialBrokenRedirects";
+
+       if ( ! $limit ) {
+               $limit = $wgUser->getOption( "rclimit" );
+               if ( ! $limit ) { $limit = 50; }
+       }
+       if ( ! $offset ) { $offset = 0; }
+
+       $sql = "SELECT bl_to,cur_title FROM brokenlinks,cur WHERE cur_is_redirect=1 AND cur_namespace=0 AND bl_from=cur_id LIMIT {$offset}, {$limit}" ;
+
+       $res = wfQuery( $sql, $fname );
+
+       $top = getMaintenancePageBacklink();
+       $top .= "<p>".wfMsg("brokenredirectstext")."</p><br>\n";
+       $top .= wfShowingResults( $offset, $limit );
+       $wgOut->addHTML( "<p>{$top}\n" );
+
+       $sl = wfViewPrevNext( $offset, $limit, "REPLACETHIS" ) ;
+       $sl = str_replace ( "REPLACETHIS" , sns().":Maintenance&subfunction=brokenredirects" , $sl ) ;
+       $wgOut->addHTML( "<br>{$sl}\n" );
+
+       $sk = $wgUser->getSkin();
+       $s = "<ol start=" . ( $offset + 1 ) . ">";
+       while ( $obj = wfFetchObject( $res ) ) {
+               $l1 = $sk->makeKnownLink ( $obj->cur_title , "" , "redirect=no" ) ;
+               $l2 = $sk->makeBrokenLink ( $obj->cur_title , "(".wfMsg("qbedit").")" , "redirect=no" ) ;
+               $l3 = $sk->makeBrokenLink ( $obj->bl_to , "" , "redirect=no" ) ;
+               $s .= "<li>{$l1} {$l2} => {$l3}</li>\n" ;
+       }
+       wfFreeResult( $res );
+       $s .= "</ol>";
+       $wgOut->addHTML( $s );
+       $wgOut->addHTML( "<p>{$sl}\n" );
+}
+
+function wfSpecialSelfLinks()
+{
+       global $wgUser, $wgOut, $wgLang, $wgTitle;
+       global $limit, $offset; # From query string
+       $fname = "wfSpecialSelfLinks";
+
+       if ( ! $limit ) {
+               $limit = $wgUser->getOption( "rclimit" );
+               if ( ! $limit ) { $limit = 50; }
+       }
+       if ( ! $offset ) { $offset = 0; }
+
+       $sql = "SELECT cur_title FROM cur,links WHERE cur_is_redirect=0 AND cur_namespace=0 AND l_from=cur_title AND l_to=cur_id LIMIT {$offset}, {$limit}";
+
+       $res = wfQuery( $sql, $fname );
+
+       $top = getMaintenancePageBacklink();
+       $top .= "<p>".wfMsg("selflinkstext")."</p><br>\n";
+       $top .= wfShowingResults( $offset, $limit );
+       $wgOut->addHTML( "<p>{$top}\n" );
+
+       $sl = wfViewPrevNext( $offset, $limit, "REPLACETHIS" ) ;
+       $sl = str_replace ( "REPLACETHIS" , sns().":Maintenance&subfunction=selflinks" , $sl ) ;
+       $wgOut->addHTML( "<br>{$sl}\n" );
+
+       $sk = $wgUser->getSkin();
+       $s = "<ol start=" . ( $offset + 1 ) . ">";
+       while ( $obj = wfFetchObject( $res ) )
+               $s .= "<li>".$sk->makeKnownLink ( $obj->cur_title )."</li>\n" ;
+       wfFreeResult( $res );
+       $s .= "</ol>";
+       $wgOut->addHTML( $s );
+       $wgOut->addHTML( "<p>{$sl}\n" );
+}
+
+function wfSpecialMispeelings ()
+{
+        global $wgUser, $wgOut, $wgLang, $wgTitle;
+        global $limit, $offset; # From query string
+        $sk = $wgUser->getSkin();
+        $fname = "wfSpecialMispeelings";
+
+        if ( ! $limit ) {
+                $limit = $wgUser->getOption( "rclimit" );
+                if ( ! $limit ) { $limit = 50; }
+        }
+        if ( ! $offset ) { $offset = 0; }
+
+        # Determine page name
+        $ms = wfMsg ( "mispeelingspage" ) ;
+        $mss = str_replace ( " " , "_" , $ms ) ;
+        $msp = $wgLang->getNsText(4).":".$ms ;
+        $msl = $sk->makeKnownLink ( $msp ) ;
+
+        # Load list from database
+        $sql = "SELECT cur_text FROM cur WHERE cur_title='{$mss}' AND cur_namespace=4" ;
+        $res = wfQuery( $sql, $fname );
+        $obj = wfFetchObject ( $res ) ;
+        $l = $obj->cur_text ;
+        $l = explode ( "\n" , $l ) ;
+        $a = array () ;
+        foreach ( $l as $x )
+                if ( substr ( trim ( $x ) , 0 , 1 ) == "*" )
+                        $a[] = strtolower ( trim ( substr ( trim ( $x ) , 1 ) ) );
+        asort ( $a ) ;
+
+        $cnt = 0 ;
+        $b = array () ;
+        foreach ( $a AS $x ) {
+                if ( $cnt < $offset+$limit && $x != "" ) {
+                        $y = $x ;
+                        $x = preg_replace( '/^(\S+).*$/', '$1', $x );
+                       #$sql = "SELECT DISTINCT cur_title FROM cur WHERE cur_namespace=0 AND cur_is_redirect=0 AND (MATCH(cur_ind_text) AGAINST ('" . wfStrencode( $wgLang->stripForSearch( $x ) ) . "'))" ;
+                       $sql = "SELECT DISTINCT cur_title FROM cur,searchindex WHERE cur_id=si_page AND cur_namespace=0 AND cur_is_redirect=0 AND (MATCH(si_text) AGAINST ('" . wfStrencode( $wgLang->stripForSearch( $x ) ) . "'))" ;
+                        $res = wfQuery( $sql, $fname );
+                        while ( $obj = wfFetchObject ( $res ) ) {
+                                if ( $cnt >= $offset AND $cnt < $offset+$limit ) {
+                                        if ( $y != "" ) {
+                                                if ( count ( $b ) > 0 ) $b[] = "</OL>\n" ;
+                                                $b[] = "<H3>{$y}</H3>\n<OL start=".($cnt+1).">\n" ;
+                                                $y = "" ;
+                                                }
+                                        $b[] = "<li>".
+                                                $sk->makeKnownLink ( $obj->cur_title ).
+                                                " (".
+                                                $sk->makeBrokenLink ( $obj->cur_title , wfMsg ( "qbedit" ) ).
+                                                ")</li>\n" ;
+                                        }
+                                $cnt++ ;
+                                }
+                        }
+                }
+        $top = getMaintenancePageBacklink();
+        $top .= "<p>".str_replace("$1",$msl,wfMsg("mispeelingstext"))."</p><br>\n";
+        $top .= wfShowingResults( $offset, $limit );
+        $wgOut->addHTML( "<p>{$top}\n" );
+
+        $sl = wfViewPrevNext( $offset, $limit, "REPLACETHIS" ) ;
+        $sl = str_replace ( "REPLACETHIS" , sns().":Maintenance&subfunction=mispeelings" , $sl ) ;
+        $wgOut->addHTML( "<br>{$sl}\n" );
+
+        $s = implode ( "" , $b ) ;
+        if ( count ( $b ) > 0 ) $s .= "</ol>";
+        $wgOut->addHTML( $s );
+        $wgOut->addHTML( "<p>{$sl}\n" );
+}
+
+
+function wfSpecialMissingLanguageLinks()
+{
+       global $wgUser, $wgOut, $wgLang, $wgTitle, $thelang, $subfunction;
+       global $limit, $offset; # From query string
+       $fname = "wfSpecialMissingLanguageLinks";
+       $subfunction = "missinglanguagelinks" ;
+       if ( $thelang == "w" ) $thelang = "en" ; # Fix for international wikis
+
+       if ( ! $limit ) {
+               $limit = $wgUser->getOption( "rclimit" );
+               if ( ! $limit ) { $limit = 50; }
+       }
+       if ( ! $offset ) { $offset = 0; }
+
+       $sql = "SELECT cur_title FROM cur WHERE cur_namespace=0 AND cur_is_redirect=0 AND cur_title NOT LIKE '%/%' AND cur_text NOT LIKE '%[[{$thelang}:%' LIMIT {$offset}, {$limit}";
+
+       $res = wfQuery( $sql, $fname );
+
+
+       $mll = wfMsg("missinglanguagelinkstext");
+       $mll = str_replace ( "$1" , $wgLang->getLanguageName($thelang) , $mll ) ;
+
+       $top = getMaintenancePageBacklink();
+       $top .= "<p>$mll</p><br>";
+       $top .= wfShowingResults( $offset, $limit );
+       $wgOut->addHTML( "<p>{$top}\n" );
+
+       $sl = wfViewPrevNext( $offset, $limit, "REPLACETHIS" ) ;
+       $sl = str_replace ( "REPLACETHIS" , sns().":Maintenance&subfunction=missinglanguagelinks&thelang={$thelang}" , $sl ) ;
+       $wgOut->addHTML( "<br>{$sl}\n" );
+
+       $sk = $wgUser->getSkin();
+       $s = "<ol start=" . ( $offset + 1 ) . ">";
+       while ( $obj = wfFetchObject( $res ) )
+               $s .= "<li>".$sk->makeKnownLink ( $obj->cur_title )."</li>\n" ;
+       wfFreeResult( $res );
+       $s .= "</ol>";
+       $wgOut->addHTML( $s );
+       $wgOut->addHTML( "<p>{$sl}\n" );
+}
+
+?>
diff --git a/includes/SpecialMovepage.php b/includes/SpecialMovepage.php
new file mode 100644 (file)
index 0000000..2a67b95
--- /dev/null
@@ -0,0 +1,424 @@
+<?
+
+function wfSpecialMovepage()
+{
+       global $wgUser, $wgOut, $action, $target;
+
+       if ( 0 == $wgUser->getID() or $wgUser->isBlocked() ) {
+               $wgOut->errorpage( "movenologin", "movenologintext" );
+               return;
+       }
+       if ( wfReadOnly() ) {
+               $wgOut->readOnlyPage();
+               return;
+       }
+       $fields = array( "wpNewTitle", "wpOldTitle" );
+       wfCleanFormFields( $fields );
+
+       $f = new MovePageForm();
+
+       if ( "success" == $action ) { $f->showSuccess(); }
+       else if ( "submit" == $action ) { $f->doSubmit(); }
+       else { $f->showForm( "" ); }
+}
+
+class MovePageForm {
+
+       var $ot, $nt;           # Old, new Title objects
+       var $ons, $nns;         # Namespaces
+       var $odt, $ndt;         # Pagenames (dbkey form)
+       var $oft, $nft;         # Full page titles (DBkey form)
+       var $ofx, $nfx;         # Full page titles (Text form)
+       var $oldid, $newid;     # "cur_id" field (yes, both from "cur")
+       var $talkmoved = 0;
+       
+       function showForm( $err )
+       {
+               global $wgOut, $wgUser, $wgLang;
+               global $wpNewTitle, $wpOldTitle, $wpMovetalk, $target;
+
+               $wgOut->setPagetitle( wfMsg( "movepage" ) );
+
+               if ( ! $wpOldTitle ) {
+                       $target = wfCleanQueryVar( $target );
+                       if ( "" == $target ) {
+                               $wgOut->errorpage( "notargettitle", "notargettext" );
+                               return;
+                       }
+                       $wpOldTitle = $target;
+               }
+               $ot = Title::newFromURL( $wpOldTitle );
+               $ott = $ot->getPrefixedText();
+
+               $wgOut->addWikiText( wfMsg( "movepagetext" ) );
+               if ( ! Namespace::isTalk( $ot->getNamespace() ) )
+                       $wgOut->addWikiText( "\n\n" . wfMsg( "movepagetalktext" ) );
+
+               $ma = wfMsg( "movearticle" );
+               $newt = wfMsg( "newtitle" );
+               $mpb = wfMsg( "movepagebtn" );
+               $movetalk = wfMsg( "movetalk" );
+
+               $action = wfLocalUrlE( $wgLang->specialPage( "Movepage" ),
+                 "action=submit" );
+
+               if ( "" != $err ) {
+                       $wgOut->setSubtitle( wfMsg( "formerror" ) );
+                       $wgOut->addHTML( "<p><font color='red' size='+1'>{$err}</font>\n" );
+               }
+               $wgOut->addHTML( "<p>
+<form id=\"movepage\" method=\"post\" action=\"{$action}\">
+<table border=0><tr>
+<td align=right>{$ma}:</td>
+<td align=left><strong>{$ott}</strong></td>
+</tr><tr>
+<td align=right>{$newt}:</td>
+<td align=left>
+<input type=text size=40 name=\"wpNewTitle\" value=\"{$wpNewTitle}\">
+<input type=hidden name=\"wpOldTitle\" value=\"{$wpOldTitle}\">
+</td>
+</tr>" );
+
+               if ( ! Namespace::isTalk( $ot->getNamespace() ) ) {
+                       $wgOut->addHTML(
+"<tr>
+<td align=right>
+<input type=checkbox name=\"wpMovetalk\" checked value=\"1\">
+</td><td>{$movetalk}</td>
+</tr>" );
+               }
+               $wgOut->addHTML(
+"<tr>
+<td>&nbsp;</td><td align=left>
+<input type=submit name=\"wpMove\" value=\"{$mpb}\">
+</td></tr></table>
+</form>\n" );
+
+       }
+
+       function doSubmit()
+       {
+               global $wgOut, $wgUser, $wgLang;
+               global $wpNewTitle, $wpOldTitle, $wpMovetalk, $target;
+               global $wgDeferredUpdateList;
+               $fname = "MovePageForm::doSubmit";
+
+               $this->ot = Title::newFromText( $wpOldTitle );
+               $this->nt = Title::newFromText( $wpNewTitle );
+               $this->ons = $this->ot->getNamespace();
+               $this->nns = $this->nt->getNamespace();
+               $this->odt = wfStrencode( $this->ot->getDBkey() );
+               $this->ndt = wfStrencode( $this->nt->getDBkey() );
+               $this->oft = wfStrencode( $this->ot->getPrefixedDBkey() );
+               $this->nft = wfStrencode( $this->nt->getPrefixedDBkey() );
+               $this->ofx = $this->ot->getPrefixedText();
+               $this->nfx = $this->nt->getPrefixedText();
+
+               $this->oldid = $this->ot->getArticleID();
+               $this->newid = $this->nt->getArticleID();
+
+               if ( strlen( trim( $this->ndt ) ) < 2 ) {
+                       $this->showForm( wfMsg( "articleexists" ) );
+                       return;
+               }
+               if ( ( ! Namespace::isMovable( $this->ons ) ) ||
+                        ( "" == $this->odt ) ||
+                        ( "" != $this->ot->getInterwiki() ) ||
+                    ( ! Namespace::isMovable( $nns ) ) ||
+                        ( "" == $this->ndt ) ||
+                        ( "" != $this->nt->getInterwiki() ) ) {
+                       $this->showForm( wfMsg( "badarticleerror" ) );
+                       return;
+               }
+               # The move is allowed only if (1) the target doesn't exist, or
+               # (2) the target is a redirect to the source, and has no history
+               # (so we can undo bad moves right after they're done).
+
+               if ( 0 != $this->newid ) { # Target exists; check for validity
+                       if ( ! $this->isValidTarget() ) {
+                               $this->showForm( wfMsg( "articleexists" ) );
+                               return;
+                       }
+                       $this->moveOverExistingRedirect();
+               } else { # Target didn't exist, do normal move.
+                       $this->moveToNewTitle();
+               }
+
+               $this->updateWatchlists();
+
+               $u = new SearchUpdate( $this->oldid, $this->nt->getPrefixedDBkey() );
+               $u->doUpdate();
+               $u = new SearchUpdate( $this->newid, $this->ot->getPrefixedDBkey(), "" );
+               $u->doUpdate();
+
+               # Move talk page if (1) the checkbox says to, (2) the source
+               # and target namespaces are identical, (3) the namespaces are not
+               # themselves talk namespaces, and of course (4) it exists.
+
+               if ( ( 1 == $wpMovetalk ) &&
+                        ( ! Namespace::isTalk( $this->ons ) ) &&
+                        ( $this->ons == $this->nns ) ) {
+
+                       $this->ons = $this->nns = Namespace::getTalk( $this->ons );
+
+                       $this->ot = Title::newFromText( Title::makeName(
+                         $this->ons, $wpOldTitle ) );
+                       $this->nt = Title::newFromText( Title::makeName(
+                         $this->nns, $wpNewTitle ) );
+
+                       # odt, ndt, ofx, nfx remain the same
+
+                       $this->oft = wfStrencode( $this->ot->getPrefixedDBkey() );
+                       $this->nft = wfStrencode( $this->nt->getPrefixedDBkey() );
+
+                       $this->oldid = $this->ot->getArticleID();
+                       $this->newid = $this->nt->getArticleID();
+
+                       if ( 0 != $this->oldid ) {
+                               if ( 0 != $this->newid ) {
+                                       if ( $this->isValidTarget() ) {
+                                               $this->moveOverExistingRedirect();
+                                               $this->talkmoved = 1;
+                                       } else {
+                                               $this->talkmoved = 'invalid';
+                                       }
+                               } else {
+                                       $this->moveToNewTitle();
+                                       $this->talkmoved = 1;
+                               }
+                               $u = new SearchUpdate( $this->oldid, $this->nt->getPrefixedDBkey() );
+                               $u->doUpdate();
+                               $u = new SearchUpdate( $this->newid, $this->ot->getPrefixedDBkey(), "" );
+                               $u->doUpdate();
+                       }
+               }
+               $success = wfLocalUrl( $wgLang->specialPage( "Movepage" ),
+                 "action=success&oldtitle=" . wfUrlencode( $this->ofx ) .
+                 "&newtitle=" . wfUrlencode( $this->nfx ) .
+                 "&talkmoved={$this->talkmoved}" );
+
+               $wgOut->redirect( $success );
+       }
+
+       function showSuccess()
+       {
+               global $wgOut, $wgUser;
+               global $newtitle, $oldtitle, $talkmoved;
+
+               $wgOut->setPagetitle( wfMsg( "movepage" ) );
+               $wgOut->setSubtitle( wfMsg( "pagemovedsub" ) );
+
+               $fields = array( "oldtitle", "newtitle" );
+               wfCleanFormFields( $fields );
+
+               $text = str_replace( "$1", $oldtitle, wfMsg( "pagemovedtext" ) );
+               $text = str_replace( "$2", $newtitle, $text );
+               $wgOut->addWikiText( $text );
+
+               if ( 1 == $talkmoved ) {
+                       $wgOut->addHTML( "\n<p>" . wfMsg( "talkpagemoved" ) );
+               } elseif( 'invalid' == $talkmoved ) {
+                       $wgOut->addHTML( "\n<p><strong>" . wfMsg( "talkexists" ) . "</strong>" );
+               } else {
+                       $ot = Title::newFromURL( $oldtitle );
+                       if ( ! Namespace::isTalk( $ot->getNamespace() ) ) {
+                               $wgOut->addHTML( "\n<p>" . wfMsg( "talkpagenotmoved" ) );
+                       }
+               }
+       }
+
+       # Is the the existing target title valid?
+
+       function isValidTarget()
+       {
+               $fname = "MovePageForm::isValidTarget";
+
+               $sql = "SELECT cur_is_redirect,cur_text FROM cur " .
+                 "WHERE cur_id={$this->newid}";
+               $res = wfQuery( $sql, $fname );
+               $obj = wfFetchObject( $res );
+
+               if ( 0 == $obj->cur_is_redirect ) { return false; }
+
+               if ( preg_match( "/\\[\\[\\s*([^\\]]*)]]/", $obj->cur_text, $m ) ) {
+                       $rt = Title::newFromText( $m[1] );
+                       if ( 0 != strcmp( wfStrencode( $rt->getPrefixedDBkey() ),
+                         $this->oft ) ) {
+                               return false;
+                       }
+               }
+               $sql = "SELECT old_id FROM old WHERE old_namespace={$this->nns} " .
+                 "AND old_title='{$this->ndt}'";
+               $res = wfQuery( $sql, $fname );
+               if ( 0 != wfNumRows( $res ) ) { return false; }
+
+               return true;
+       }
+
+       # Move page to title which is presently a redirect to the source
+       # page.  Handling link tables here is tricky.
+
+       function moveOverExistingRedirect()
+       {
+               global $wgUser;
+               $fname = "MovePageForm::moveOverExistingRedirect";
+               $mt = wfMsg( "movedto" );
+
+        $now = wfTimestampNow();
+               $sql = "UPDATE cur SET cur_touched='{$now}'," .
+                 "cur_namespace={$this->nns},cur_title='{$this->ndt}' " .
+                 "WHERE cur_id={$this->oldid}";
+               wfQuery( $sql, $fname );
+
+               $sql = "UPDATE cur SET cur_touched='{$now}'," .
+                 "cur_namespace={$this->ons},cur_title='{$this->odt}'," .
+                 "cur_text='#REDIRECT [[{$this->nft}]]\n',cur_comment='" .
+                 "{$mt} \\\"{$this->nft}\\\"',cur_user='" .  $wgUser->getID() .
+                 "',cur_minor_edit=0,cur_counter=0,cur_restrictions=''," .
+                 "cur_user_text='" . wfStrencode( $wgUser->getName() ) . "'," .
+                 "cur_is_redirect=1,cur_is_new=0 WHERE cur_id={$this->newid}";
+               wfQuery( $sql, $fname );
+
+               $sql = "UPDATE old SET " .
+                 "old_namespace={$this->nns},old_title='{$this->ndt}' WHERE " .
+                 "old_namespace={$this->ons} AND old_title='{$this->odt}'";
+               wfQuery( $sql, $fname );
+               
+               $sql = "UPDATE recentchanges SET ".
+                       "rc_namespace={$this->nns}, rc_title='{$this->ndt}' WHERE ".
+                       "rc_cur_id={$this->oldid}";
+        wfQuery( $sql, $fname );
+
+               $sql = "INSERT INTO recentchanges (rc_namespace,rc_title,
+                       rc_comment,rc_user,rc_user_text,rc_timestamp,
+                       rc_cur_time,rc_cur_id,rc_new)
+                       VALUES ({$this->ons},'{$this->odt}'," .
+                 "'{$mt} \\\"{$this->nft}\\\"','" .
+                 $wgUser->getID() . "','" . wfStrencode( $wgUser->getName() ) .
+          "','{$now}','{$now}',{$this->newid},1)";
+        wfQuery( $sql, $fname );
+
+               # The only link from here should be the old redirect
+
+               $sql = "DELETE FROM links WHERE l_from='{$this->nft}'";
+               wfQuery( $sql, $fname );
+
+               $sql = "UPDATE links SET l_from='{$this->nft}' WHERE l_from='{$this->oft}'";
+               wfQuery( $sql, $fname );
+
+               # Swap links.  Using MAXINT as a temp; if there's ever an article
+               # with id 4294967295, this will fail, but I think that's pretty safe
+
+               $sql = "UPDATE links SET l_to=4294967295 WHERE l_to={$this->oldid}";
+               wfQuery( $sql, $fname );
+
+               $sql = "UPDATE links SET l_to={$this->oldid} WHERE l_to={$this->newid}";
+               wfQuery( $sql, $fname );
+
+               $sql = "UPDATE links SET l_to={$this->newid} WHERE l_to=4294967295";
+               wfQuery( $sql, $fname );
+
+               # Note: the insert below must be after the updates above!
+
+               $sql = "INSERT INTO links (l_from,l_to) VALUES ('{$this->oft}',{$this->oldid})";
+               wfQuery( $sql, $fname );
+
+               $sql = "UPDATE imagelinks SET il_from='{$this->nft}' WHERE il_from='{$this->oft}'";
+               wfQuery( $sql, $fname );
+       }
+
+       # Move page to non-existing title.
+
+       function moveToNewTitle()
+       {
+               global $wgUser;
+               $fname = "MovePageForm::moveToNewTitle";
+               $mt = wfMsg( "movedto" );
+
+               $sql = "UPDATE cur SET cur_touched='{$now}'," .
+                 "cur_namespace={$this->nns},cur_title='{$this->ndt}' " .
+                 "WHERE cur_id={$this->oldid}";
+               wfQuery( $sql, $fname );
+
+               $now = wfTimestampNow();
+               $won = wfInvertTimestamp( $now );
+               $common = "{$this->ons},'{$this->odt}'," .
+                 "'{$mt} \\\"{$this->nft}\\\"','" .
+                 $wgUser->getID() . "','" . wfStrencode( $wgUser->getName() ) .
+          "','{$now}'";
+               $sql = "INSERT INTO cur (cur_namespace,cur_title," .
+                 "cur_comment,cur_user,cur_user_text,cur_timestamp,inverse_timestamp," .
+                 "cur_touched,cur_text,cur_is_redirect,cur_is_new) " .
+                 "VALUES ({$common},'{$won}','{$now}','#REDIRECT [[{$this->nft}]]\n',1,1)";
+               wfQuery( $sql, $fname );
+               $this->newid = wfInsertId();
+
+               $sql = "UPDATE old SET " .
+                 "old_namespace={$this->nns},old_title='{$this->ndt}' WHERE " .
+                 "old_namespace={$this->ons} AND old_title='{$this->odt}'";
+               wfQuery( $sql, $fname );
+
+        $sql = "UPDATE recentchanges SET ".
+                       "rc_namespace={$this->nns}, rc_title='{$this->ndt}' WHERE ".
+                       "rc_namespace={$this->ons} AND rc_title='{$this->odt}'";
+        wfQuery( $sql, $fname );
+
+               $sql = "INSERT INTO recentchanges (rc_namespace,rc_title,
+                       rc_comment,rc_user,rc_user_text,rc_timestamp,
+                       rc_cur_time,rc_cur_id,rc_new)
+                       VALUES ({$common},'{$now}',{$this->newid},1)";
+        wfQuery( $sql, $fname );
+
+               $sql = "UPDATE links SET l_from='{$this->nft}' WHERE l_from='{$this->oft}'";
+               wfQuery( $sql, $fname );
+
+               $sql = "UPDATE links SET l_to={$this->newid} WHERE l_to={$this->oldid}";
+               wfQuery( $sql, $fname );
+
+               $sql = "INSERT INTO links (l_from,l_to) VALUES ('{$this->oft}',{$this->oldid})";
+               wfQuery( $sql, $fname );
+
+               # Non-existent target may have had broken links to it; these must
+               # now be removed and made into good links.
+
+               $sql = "SELECT bl_from FROM brokenlinks WHERE bl_to='{$this->nft}'";
+               $res = wfQuery( $sql, $fname );
+
+               while ( $rec = wfFetchObject( $res ) ) {
+                       $lid = $rec->bl_from;
+                       $lt = wfStrencode( Article::nameOf( $lid ) );
+                       $sql = "INSERT INTO links (l_from,l_to) VALUES ('{$lt}',$this->oldid)";
+                       wfQuery( $sql, $fname );
+               }
+               $sql = "DELETE FROM brokenlinks WHERE bl_to='{$this->nft}'";
+               wfQuery( $sql, $fname );
+
+               $sql = "UPDATE imagelinks SET il_from='{$this->nft}' WHERE il_from='{$this->oft}'";
+               wfQuery( $sql, $fname );
+       }
+
+       function updateWatchlists()
+       {
+               $oldnamespace = $this->ons & ~1;
+               $newnamespace = $this->nns & ~1;
+               $oldtitle = $this->odt;
+               $newtitle = $this->ndt;
+
+               if( $oldnamespace == $newnamespace and $oldtitle == $newtitle )
+                       return;
+
+               $sql = "SELECT wl_user FROM watchlist
+                       WHERE wl_namespace={$oldnamespace} AND wl_title='{$oldtitle}'";
+               $res = wfQuery( $sql, $fname );
+               if( $s = wfFetchObject( $res ) ) {
+                       $sql = "REPLACE INTO watchlist (wl_user,wl_namespace,wl_title)
+                               VALUES ({$s->wl_user},{$newnamespace},'{$newtitle}')";
+                       while( $s = wfFetchObject( $res ) ) {
+                               $sql .= ",({$s->wl_user},{$newnamespace},'{$newtitle}')";
+                       }
+                       wfQuery( $sql, $fname );
+               }
+       }
+
+}
+?>
diff --git a/includes/SpecialNeglectedpages.php b/includes/SpecialNeglectedpages.php
new file mode 100644 (file)
index 0000000..42d4006
--- /dev/null
@@ -0,0 +1,13 @@
+<?
+# Suggestion from mailing list: lists pages in order
+# least recently reviewed.
+#
+
+function wfSpecialNeglectedpages()
+{
+       global $wgUser, $wgOut;
+
+       $wgOut->addHTML( "<p>(TODO: neglected pages)" );
+}
+
+?>
diff --git a/includes/SpecialNewpages.php b/includes/SpecialNewpages.php
new file mode 100644 (file)
index 0000000..47e09d6
--- /dev/null
@@ -0,0 +1,54 @@
+<?
+
+function wfSpecialNewpages()
+{
+       global $wgUser, $wgOut, $wgLang, $wgTitle;
+       global $limit, $offset; # From query string
+       $fname = "wfSpecialNewpages";
+
+       if ( ! $limit ) {
+               $limit = $wgUser->getOption( "rclimit" );
+               if ( ! $limit ) { $limit = 50; }
+       }
+       if ( ! $offset ) { $offset = 0; }
+
+#      $sql = "SELECT cur_title,cur_user,cur_user_text,cur_comment," .
+#        "cur_timestamp FROM cur " .
+#        "WHERE cur_is_new=1 AND cur_namespace=0 AND cur_is_redirect=0 " .
+#        " ORDER BY cur_timestamp DESC LIMIT {$offset}, {$limit}";
+       $sql = "SELECT rc_title AS cur_title,rc_user AS cur_user,rc_user_text AS cur_user_text,cur_comment," .
+         "rc_timestamp AS cur_timestamp FROM recentchanges,cur " .
+         "WHERE rc_cur_id=cur_id AND rc_new=1 AND rc_namespace=0 AND cur_text NOT LIKE '#REDIRECT%' " .
+         " ORDER BY rc_timestamp DESC LIMIT {$offset}, {$limit}";
+       $res = wfQuery( $sql, $fname );
+
+       $top = wfShowingResults( $offset, $limit );
+       $wgOut->addHTML( "<p>{$top}\n" );
+
+       $sl = wfViewPrevNext( $offset, $limit,
+         $wgLang->specialPage( "Newpages" ) );
+       $wgOut->addHTML( "<br>{$sl}\n" );
+
+       $sk = $wgUser->getSkin();
+       $s = "<ol start=" . ( $offset + 1 ) . ">";
+       while ( $obj = wfFetchObject( $res ) ) {
+               $u = $obj->cur_user;
+               $ut = $obj->cur_user_text;
+               $c = wfEscapeHTML( $obj->cur_comment );
+               if ( 0 == $u ) { $ul = $ut; }
+               else { $ul = $sk->makeLink( $wgLang->getNsText(2).":{$ut}", $ut ); }
+
+               $d = $wgLang->timeanddate( $obj->cur_timestamp, true );
+               $link = $sk->makeKnownLink( $obj->cur_title, "" );
+               $s .= "<li>{$d} {$link} . . {$ul}";
+
+               if ( "" != $c && "*" != $c ) { $s .= " <em>({$c})</em>"; }
+               $s .= "</li>\n";
+       }
+       wfFreeResult( $res );
+       $s .= "</ol>";
+       $wgOut->addHTML( $s );
+       $wgOut->addHTML( "<p>{$sl}\n" );
+}
+
+?>
diff --git a/includes/SpecialPopularpages.php b/includes/SpecialPopularpages.php
new file mode 100644 (file)
index 0000000..387ecbe
--- /dev/null
@@ -0,0 +1,47 @@
+<?
+
+function wfSpecialPopularpages()
+{
+       global $wgUser, $wgOut, $wgLang, $wgTitle;
+       global $limit, $offset; # From query string
+       $fname = "wfSpecialPopularpages";
+
+       global $wgMiserMode;
+       if ( $wgMiserMode ) {
+               $wgOut->addWikiText( wfMsg( "perfdisabled" ) );
+               return;
+       }
+
+       if ( ! $limit ) {
+               $limit = $wgUser->getOption( "rclimit" );
+               if ( ! $limit ) { $limit = 50; }
+       }
+       if ( ! $offset ) { $offset = 0; }
+
+       $sql = "SELECT DISTINCT cur_title, cur_counter FROM cur " .
+         "WHERE cur_namespace=0 AND cur_is_redirect=0 ORDER BY " .
+         "cur_counter DESC LIMIT {$offset}, {$limit}";
+       $res = wfQuery( $sql, $fname );
+
+       $sk = $wgUser->getSkin();
+
+       $top = wfShowingResults( $offset, $limit );
+       $wgOut->addHTML( "<p>{$top}\n" );
+
+       $sl = wfViewPrevNext( $offset, $limit,
+         $wgLang->specialPage( "Popularpages" ) );
+       $wgOut->addHTML( "<br>{$sl}\n" );
+
+       $s = "<ol start=" . ( $offset + 1 ) . ">";
+       while ( $obj = wfFetchObject( $res ) ) {
+               $nv = str_replace( "$1", $obj->cur_counter, wfMsg( "nviews" ) );
+               $link = $sk->makeKnownLink( $obj->cur_title, "" );
+               $s .= "<li>{$link} ({$nv})</li>\n";
+       }
+       wfFreeResult( $res );
+       $s .= "</ol>";
+       $wgOut->addHTML( $s );
+       $wgOut->addHTML( "<p>{$sl}\n" );
+}
+
+?>
diff --git a/includes/SpecialPreferences.php b/includes/SpecialPreferences.php
new file mode 100644 (file)
index 0000000..fb0dfac
--- /dev/null
@@ -0,0 +1,260 @@
+<?
+function wfSpecialPreferences()
+{
+       global $wgUser, $wgOut, $action;
+       global $wpSaveprefs, $wpReset;
+
+       $fields = array( "wpOldpass", "wpNewpass", "wpRetype",
+         "wpEmail", "wpNick" );
+       wfCleanFormFields( $fields );
+
+       if ( 0 == $wgUser->getID() ) {
+               $wgOut->errorpage( "prefsnologin", "prefsnologintext" );
+               return;
+       }
+       if ( wfReadOnly() ) {
+               $wgOut->readOnlyPage();
+               return;
+       }
+       if ( isset( $wpReset ) ) {
+               resetPrefs();
+               mainPrefsForm( WfMsg( "prefsreset" ) );
+       } else if ( "submit" == $action || isset( $wpSaveprefs ) ) {
+               savePreferences();
+       } else {
+               resetPrefs();
+               mainPrefsForm( "" );
+       }
+}
+
+/* private */ function savePreferences()
+{
+       global $wgUser, $wgLang, $wgDeferredUpdateList;
+       global $wpQuickbar, $wpOldpass, $wpNewpass, $wpRetype;
+       global $wpSkin, $wpMath, $wpEmail, $wpEmailFlag, $wpNick, $wpSearch, $wpRecent;
+       global $wpSearchLines, $wpSearchChars, $wpStubs;
+       global $wpRows, $wpCols, $wpHourDiff, $HTTP_POST_VARS;
+
+       if ( "" != $wpNewpass ) {
+               if ( $wpNewpass != $wpRetype ) {
+                       mainPrefsForm( wfMsg( "badretype" ) );                  
+                       return;
+               }
+               $ep = User::encryptPassword( $wpOldpass );
+               if ( $ep != $wgUser->getPassword() ) {
+                       if ( $ep != $wgUser->getNewpassword() ) {
+                               mainPrefsForm( wfMsg( "wrongpassword" ) );
+                               return;
+                       }
+               }
+               $wgUser->setPassword( $wpNewpass );
+       }
+       $wgUser->setEmail( $wpEmail );
+       $wgUser->setOption( "nickname", $wpNick );
+       $wgUser->setOption( "quickbar", $wpQuickbar );
+       $wgUser->setOption( "skin", $wpSkin );
+       $wgUser->setOption( "math", $wpMath );
+       $wgUser->setOption( "searchlimit", $wpSearch );
+       $wgUser->setOption( "contextlines", $wpSearchLines );
+       $wgUser->setOption( "contextchars", $wpSearchChars );
+       $wgUser->setOption( "rclimit", $wpRecent );
+       $wgUser->setOption( "rows", $wpRows );
+       $wgUser->setOption( "cols", $wpCols );
+       $wgUser->setOption( "stubthreshold", $wpStubs );
+       $wgUser->setOption( "timecorrection", $wpHourDiff );
+
+       if ( $wpEmailFlag ) { $wgUser->setOption( "disablemail", 1 ); }
+       else { $wgUser->setOption( "disablemail", 0 ); }
+
+       $togs = $wgLang->getUserToggles();
+       foreach ( $togs as $tname => $ttext ) {
+               if ( array_key_exists( "wpOp$tname", $HTTP_POST_VARS ) ) {
+                       $wgUser->setOption( $tname, 1 );
+               } else {
+                       $wgUser->setOption( $tname, 0 );
+               }
+       }
+       $wgUser->setCookies();
+       $up = new UserUpdate();
+       array_push( $wgDeferredUpdateList, $up );
+       mainPrefsForm( wfMsg( "savedprefs" ) );
+}
+
+/* private */ function resetPrefs()
+{
+       global $wgUser, $wgLang;
+       global $wpQuickbar, $wpOldpass, $wpNewpass, $wpRetype, $wpStubs;
+       global $wpRows, $wpCols, $wpSkin, $wpMath, $wpEmail, $wpEmailFlag, $wpNick;
+       global $wpSearch, $wpRecent, $HTTP_POST_VARS;
+       global $wpHourDiff, $wpSearchLines, $wpSearchChars;
+
+       $wpOldpass = $wpNewpass = $wpRetype = "";
+       $wpEmail = $wgUser->getEmail();
+       if ( 1 == $wgUser->getOption( "disablemail" ) ) { $wpEmailFlag = 1; }
+       else { $wpEmailFlag = 0; }
+       $wpNick = $wgUser->getOption( "nickname" );
+
+       $wpQuickbar = $wgUser->getOption( "quickbar" );
+       $wpSkin = $wgUser->getOption( "skin" );
+       $wpMath = $wgUser->getOption( "math" );
+       $wpRows = $wgUser->getOption( "rows" );
+       $wpCols = $wgUser->getOption( "cols" );
+       $wpStubs = $wgUser->getOption( "stubthreshold" );
+       $wpHourDiff = $wgUser->getOption( "timecorrection" );
+       $wpSearch = $wgUser->getOption( "searchlimit" );
+       $wpSearchLines = $wgUser->getOption( "contextlines" );
+       $wpSearchChars = $wgUser->getOption( "contextchars" );
+       $wpRecent = $wgUser->getOption( "rclimit" );
+
+       $togs = $wgLang->getUserToggles();
+       foreach ( $togs as $tname => $ttext ) {
+               $HTTP_POST_VARS["wpOp$tname"] = $wgUser->getOption( $tname );
+       }
+}
+
+/* private */ function mainPrefsForm( $err )
+{
+       global $wgUser, $wgOut, $wgLang;
+       global $wpQuickbar, $wpOldpass, $wpNewpass, $wpRetype;
+       global $wpSkin, $wpMath, $wpEmail, $wpEmailFlag, $wpNick, $wpSearch, $wpRecent;
+       global $wpRows, $wpCols, $wpSaveprefs, $wpReset, $wpHourDiff;
+       global $wpSearchLines, $wpSearchChars, $wpStubs;
+
+       $wgOut->setPageTitle( wfMsg( "preferences" ) );
+       $wgOut->setArticleFlag( false );
+       $wgOut->setRobotpolicy( "noindex,nofollow" );
+
+       if ( "" != $err ) {
+               $wgOut->addHTML( "<font size='+1' color='red'>$err</font>\n<p>" );
+       }
+       $uname = $wgUser->getName();
+       $uid = $wgUser->getID();
+
+       $wgOut->addHTML( "<p>" . str_replace( array("$1","$2"), array($uname,$uid),
+               wfMsg( "prefslogintext" ) ) . "\n" );
+
+       $qbs = $wgLang->getQuickbarSettings();
+       $skins = $wgLang->getSkinNames();
+       $mathopts = $wgLang->getMathNames();
+       $togs = $wgLang->getUserToggles();
+
+       $action = wfLocalUrlE( $wgLang->specialPage( "Preferences" ),
+         "action=submit" );
+       $qb = wfMsg( "qbsettings" );
+       $cp = wfMsg( "changepassword" );
+       $sk = wfMsg( "skin" );
+       $math = wfMsg( "math" );
+       $opw = wfMsg( "oldpassword" );
+       $npw = wfMsg( "newpassword" );
+       $rpw = wfMsg( "retypenew" );
+       $svp = wfMsg( "saveprefs" );
+       $rsp = wfMsg( "resetprefs" );
+       $tbs = wfMsg( "textboxsize" );
+       $tbr = wfMsg( "rows" );
+       $tbc = wfMsg( "columns" );
+       $ltz = wfMsg( "localtime" );
+       $tzt = wfMsg( "timezonetext" );
+       $tzo = wfMsg( "timezoneoffset" );
+       $yem = wfMsg( "youremail" );
+       $emf = wfMsg( "emailflag" );
+       $ynn = wfMsg( "yournick" );
+        $stt = wfMsg ( "stubthreshold" ) ;
+       $srh = wfMsg( "searchresultshead" );
+       $rpp = wfMsg( "resultsperpage" );
+       $scl = wfMsg( "contextlines" );
+       $scc = wfMsg( "contextchars" );
+       $rcc = wfMsg( "recentchangescount" );
+
+       $wgOut->addHTML( "<form id=\"preferences\" action=\"$action\"
+method=\"post\"><table border=\"1\"><tr><td valign=top nowrap><b>$qb:</b><br>\n" );
+
+       # Quickbar setting
+       #
+       for ( $i = 0; $i < count( $qbs ); ++$i ) {
+               if ( $i == $wpQuickbar ) { $checked = " checked"; }
+               else { $checked = ""; }
+               $wgOut->addHTML( "<input type=radio name=\"wpQuickbar\"
+value=\"$i\"$checked> {$qbs[$i]}<br>\n" );
+       }
+
+       # Fields for changing password
+       #
+       $wpOldpass = wfEscapeHTML( $wpOldpass );
+       $wpNewpass = wfEscapeHTML( $wpNewpass );
+       $wpRetype = wfEscapeHTML( $wpRetype );
+
+       $wgOut->addHTML( "</td><td vaign=top nowrap><b>$cp:</b><br>
+$opw: <input type=password name=\"wpOldpass\" value=\"$wpOldpass\" size=20><br>
+$npw: <input type=password name=\"wpNewpass\" value=\"$wpNewpass\" size=20><br>
+$rpw: <input type=password name=\"wpRetype\" value=\"$wpRetype\" size=20><br>
+</td></tr>\n" );
+
+       # Skin setting
+       #
+       $wgOut->addHTML( "<tr><td valign=top nowrap><b>$sk:</b><br>\n" );
+       for ( $i = 0; $i < count( $skins ); ++$i ) {
+               if ( $i == $wpSkin ) { $checked = " checked"; }
+               else { $checked = ""; }
+               $wgOut->addHTML( "<input type=radio name=\"wpSkin\"
+value=\"$i\"$checked> {$skins[$i]}<br>\n" );
+       }
+
+       # Various checkbox options
+       #
+       $wgOut->addHTML( "</td><td rowspan=2 valign=top nowrap>\n" );
+       foreach ( $togs as $tname => $ttext ) {
+               if ( 1 == $wgUser->getOption( $tname ) ) {
+                       $checked = " checked";
+               } else {
+                       $checked = "";
+               }
+               $wgOut->addHTML( "<input type=checkbox value=\"1\" "
+                 . "name=\"wpOp$tname\"$checked>$ttext<br>\n" );
+       }
+       $wgOut->addHTML( "</td>" );
+
+       # Math setting
+       #
+       $wgOut->addHTML( "<tr><td valign=top nowrap><b>$math:</b><br>\n" );
+       for ( $i = 0; $i < count( $mathopts ); ++$i ) {
+               if ( $i == $wpMath ) { $checked = " checked"; }
+               else { $checked = ""; }
+               $wgOut->addHTML( "<input type=radio name=\"wpMath\"
+value=\"$i\"$checked> {$mathopts[$i]}<br>\n" );
+       }
+
+       $wgOut->addHTML( "</td></tr><tr>" );
+
+       # Textbox rows, cols
+       #
+       $wgOut->addHTML( "<td valign=top nowrap><b>$tbs:</b><br>
+$tbr: <input type=text name=\"wpRows\" value=\"{$wpRows}\" size=6><br>
+$tbc: <input type=text name=\"wpCols\" value=\"{$wpCols}\" size=6><br><br>
+<b>$ltz</b><br>
+$tzo*: <input type=text name=\"wpHourDiff\" value=\"{$wpHourDiff}\" size=6>
+</td>" );
+
+       # Email, etc.
+       #
+       $wpEmail = wfEscapeHTML( $wpEmail );
+       $wpNick = wfEscapeHTML( $wpNick );
+       if ( $wpEmailFlag ) { $emfc = "checked"; }
+       else { $emfc = ""; }
+
+       $wgOut->addHTML( "<td valign=top nowrap>
+$yem: <input type=text name=\"wpEmail\" value=\"{$wpEmail}\" size=20><br>
+<input type=checkbox $emfc value=\"1\" name=\"wpEmailFlag\"> $emf<br>
+$ynn: <input type=text name=\"wpNick\" value=\"{$wpNick}\" size=12><br>
+$rcc: <input type=text name=\"wpRecent\" value=\"$wpRecent\" size=6><br>
+$stt: <input type=text name=\"wpStubs\" value=\"$wpStubs\" size=6><br>
+<strong>{$srh}:</strong><br>
+$rpp: <input type=text name=\"wpSearch\" value=\"$wpSearch\" size=6><br>
+$scl: <input type=text name=\"wpSearchLines\" value=\"$wpSearchLines\" size=6><br>
+$scc: <input type=text name=\"wpSearchChars\" value=\"$wpSearchChars\" size=6></td>
+</tr><tr>
+<td align=center><input type=submit name=\"wpSaveprefs\" value=\"$svp\"></td>
+<td align=center><input type=submit name=\"wpReset\" value=\"$rsp\"></td>
+</tr></table>* {$tzt} </form>\n" );
+}
+
+?>
diff --git a/includes/SpecialRandompage.php b/includes/SpecialRandompage.php
new file mode 100644 (file)
index 0000000..b3110f6
--- /dev/null
@@ -0,0 +1,29 @@
+<?
+
+function wfSpecialRandompage()
+{
+       global $wgOut, $wgTitle, $wgArticle, $force;
+       $fname = "wfSpecialRandompage";
+
+       wfSeedRandom();
+       $sqlget = "SELECT cur_id,cur_title
+               FROM cur USE INDEX (cur_random)
+               WHERE cur_namespace=0 AND cur_is_redirect=0
+               AND cur_random>RAND()
+               ORDER BY cur_random
+               LIMIT 1";
+       $res = wfQuery( $sqlget, $fname );
+       if( $s = wfFetchObject( $res ) ) {
+               $sql = "UPDATE cur SET cur_random=RAND() WHERE cur_id={$s->cur_id}";
+               wfQuery( $sql, $fname );
+               $rt = wfUrlEncode( $s->cur_title );
+       } else {
+               # No articles?!
+               $rt = "";
+       }
+
+       $wgOut->reportTime(); # for logfile
+       $wgOut->redirect( wfLocalUrl( $rt ) );
+}
+
+?>
diff --git a/includes/SpecialRecentchanges.php b/includes/SpecialRecentchanges.php
new file mode 100644 (file)
index 0000000..1412193
--- /dev/null
@@ -0,0 +1,172 @@
+<?
+
+function wfSpecialRecentchanges()
+{
+       global $wgUser, $wgOut, $wgLang, $wgTitle;
+       global $days, $limit, $hideminor, $from, $hidebots; # From query string
+       $fname = "wfSpecialRecentchanges";
+
+       $sql = "SELECT MAX(rc_timestamp) AS lastmod FROM recentchanges";
+       $res = wfQuery( $sql, $fname );
+       $s = wfFetchObject( $res );
+       $wgOut->checkLastModified( $s->lastmod );
+
+       $rctext = wfMsg( "recentchangestext" );
+       $sql = "SELECT cur_text FROM cur WHERE cur_namespace=4 AND cur_title='Recentchanges'";
+       $res = wfQuery( $sql, $fname );
+       if( ( $s = wfFetchObject( $res ) ) and ( $s->cur_text != "" ) ) {
+               $rctext = $s->cur_text;
+       }
+       $wgOut->addWikiText( $rctext );
+
+       if ( ! $days ) {
+               $days = $wgUser->getOption( "rcdays" );
+               if ( ! $days ) { $days = 3; }
+       }
+       if ( ! $limit ) {
+               $limit = $wgUser->getOption( "rclimit" );
+               if ( ! $limit ) { $limit = 100; }
+       }
+       $cutoff = date( "YmdHis", time() - ( $days * 86400 ) );
+       if(preg_match('/^[0-9]{14}$/', $from) and $from > $cutoff) {
+               $cutoff = $from;
+       } else {
+               unset($from);
+       }
+
+       $sk = $wgUser->getSkin();
+
+       if ( ! isset( $hideminor ) ) {
+               $hideminor = $wgUser->getOption( "hideminor" );
+       }
+       if ( $hideminor ) {
+               $hidem = "AND rc_minor=0";
+               $mlink = $sk->makeKnownLink( $wgLang->specialPage( "Recentchanges" ),
+                 WfMsg( "show" ), "days={$days}&limit={$limit}&hideminor=0" );
+       } else {
+               $hidem = "";
+               $mlink = $sk->makeKnownLink( $wgLang->specialPage( "Recentchanges" ),
+                 WfMsg( "hide" ), "days={$days}&limit={$limit}&hideminor=1" );
+       }
+       
+       if ( !isset( $hidebots ) ) {
+               $hidebots = 1;
+       }
+       if( $hidebots ) {
+               $hidem .= " AND rc_bot=0";
+       }
+
+       $uid = $wgUser->getID();
+       $sql2 = "SELECT rc_cur_id,rc_namespace,rc_title,rc_user,rc_new," .
+         "rc_comment,rc_user_text,rc_timestamp,rc_minor,rc_this_oldid,rc_last_oldid,rc_bot" . ($uid ? ",wl_user" : "") . " FROM recentchanges " .
+         ($uid ? "LEFT OUTER JOIN watchlist ON wl_user={$uid} AND wl_title=rc_title AND wl_namespace=rc_namespace & 65534 " : "") .
+         "WHERE rc_timestamp > '{$cutoff}' {$hidem} " .
+         "ORDER BY rc_timestamp DESC LIMIT {$limit}";
+       $res = wfQuery( $sql2, $fname );
+
+       if(isset($from)) {
+               $note = str_replace( "$1", $limit, wfMsg( "rcnotefrom" ) );
+               $note = str_replace( "$2", $wgLang->timeanddate( $from, true ), $note );
+       } else {
+               $note = str_replace( "$1", $limit, wfMsg( "rcnote" ) );
+               $note = str_replace( "$2", $days, $note );
+       }
+       $wgOut->addHTML( "\n<hr>\n{$note}\n<br>" );
+
+       $note = rcDayLimitLinks( $days, $limit );
+
+       $now = date( "YmdHis" );
+       $note .= "<br>\n" . str_replace( "$1",
+         $sk->makeKnownLink( $wgLang->specialPage( "Recentchanges" ),
+         $wgLang->timeanddate( $now, true ), "from=$now" ),
+         wfMsg( "rclistfrom" ) );
+
+       $wgOut->addHTML( "{$note}\n" );
+
+       $count1 = wfNumRows( $res );
+       $obj1 = wfFetchObject( $res );
+
+       $s = $sk->beginRecentChangesList();
+       while ( $limit ) {
+               if ( ( 0 == $count1 ) ) { break; }
+
+                       $ts = $obj1->rc_timestamp;
+                       $u = $obj1->rc_user;
+                       $ut = $obj1->rc_user_text;
+                       $ns = $obj1->rc_namespace;
+                       $ttl = $obj1->rc_title;
+                       $com = $obj1->rc_comment;
+                       $me = ( $obj1->rc_minor > 0 );
+                       $new = ( $obj1->rc_new > 0 );
+                       $watched = ($obj1->wl_user > 0);
+                       $oldid = $obj1->rc_this_oldid ;
+                       $diffid = $obj1->rc_last_oldid ;
+
+                       $obj1 = wfFetchObject( $res );
+                       --$count1;
+               if ( ! ( $hideminor && $me ) ) {
+                       $s .= $sk->recentChangesLine( $ts, $u, $ut, $ns, $ttl,
+                         $com, $me, $new, $watched, $oldid , $diffid );
+                       --$limit;
+               }
+       }
+       $s .= $sk->endRecentChangesList();
+
+       wfFreeResult( $res );
+       $wgOut->addHTML( $s );
+}
+
+function rcCountLink( $lim, $d, $page="Recentchanges", $more="" )
+{
+       global $wgUser, $wgLang;
+       $sk = $wgUser->getSkin();
+       $s = $sk->makeKnownLink( $wgLang->specialPage( $page ),
+         ($lim ? "{$lim}" : wfMsg( "all" ) ), "{$more}" .
+         ($d ? "days={$d}&" : "") . "limit={$lim}" );
+       return $s;
+}
+
+function rcDaysLink( $lim, $d, $page="Recentchanges", $more="" )
+{
+       global $wgUser, $wgLang;
+       $sk = $wgUser->getSkin();
+       $s = $sk->makeKnownLink( $wgLang->specialPage( $page ),
+         ($d ? "{$d}" : wfMsg( "all" ) ), "{$more}days={$d}" .
+         ($lim ? "&limit={$lim}" : "") );
+       return $s;
+}
+
+function rcDayLimitLinks( $days, $limit, $page="Recentchanges", $more="", $doall = false )
+{
+       if ($more != "") $more .= "&";
+       $cl = rcCountLink( 50, $days, $page, $more ) . " | " .
+         rcCountLink( 100, $days, $page, $more  ) . " | " .
+         rcCountLink( 250, $days, $page, $more  ) . " | " .
+         rcCountLink( 500, $days, $page, $more  ) .
+         ( $doall ? ( " | " . rcCountLink( 0, $days, $page, $more ) ) : "" );
+       $dl = rcDaysLink( $limit, 1, $page, $more  ) . " | " .
+         rcDaysLink( $limit, 3, $page, $more  ) . " | " .
+         rcDaysLink( $limit, 7, $page, $more  ) . " | " .
+         rcDaysLink( $limit, 14, $page, $more  ) . " | " .
+         rcDaysLink( $limit, 30, $page, $more  ) .
+         ( $doall ? ( " | " . rcDaysLink( $limit, 0, $page, $more ) ) : "" );
+       $note = str_replace( "$1", $cl, wfMsg( "rclinks" ) );
+       $note = str_replace( "$2", $dl, $note );
+       $note = str_replace( "$3", $mlink, $note );
+       return $note;
+}
+
+function rcLimitLinks( $page="Recentchanges", $more="", $doall = false )
+{
+       if ($more != "") $more .= "&";
+       $cl = rcCountLink( 50, 0, $page, $more ) . " | " .
+         rcCountLink( 100, 0, $page, $more  ) . " | " .
+         rcCountLink( 250, 0, $page, $more  ) . " | " .
+         rcCountLink( 500, 0, $page, $more  ) .
+         ( $doall ? ( " | " . rcCountLink( 0, $days, $page, $more ) ) : "" );
+       $note = str_replace( "$1", $cl, wfMsg( "rclinks" ) );
+       $note = str_replace( "$3", $mlink, $note );
+       return $note;
+}
+
+?>
diff --git a/includes/SpecialRecentchangeslinked.php b/includes/SpecialRecentchangeslinked.php
new file mode 100644 (file)
index 0000000..6625173
--- /dev/null
@@ -0,0 +1,89 @@
+<?
+global $IP;
+include_once( "$IP/SpecialRecentchanges.php" );
+
+function wfSpecialRecentchangeslinked()
+{
+       global $wgUser, $wgOut, $wgLang, $wgTitle;
+       global $days, $limit, $target, $hideminor; # From query string
+       $fname = "wfSpecialRecentchangeslinked";
+
+       $wgOut->setPagetitle( wfMsg( "recentchanges" ) );
+       $sk = $wgUser->getSkin();
+
+       if ( "" == $target ) {
+               $wgOut->errorpage( "notargettitle", "notargettext" );
+               return;
+       }
+       $nt = Title::newFromURL( $target );
+       $sub = str_replace( "$1", $nt->getPrefixedText(), wfMsg( "rclsub" ) );
+       $wgOut->setSubtitle( $sub );
+
+       if ( ! $days ) {
+               $days = $wgUser->getOption( "rcdays" );
+               if ( ! $days ) { $days = 7; }
+       }
+       if ( ! $limit ) {
+               $limit = $wgUser->getOption( "rclimit" );
+               if ( ! $limit ) { $limit = 100; }
+       }
+       $cutoff = date( "YmdHis", time() - ( $days * 86400 ) );
+
+       if ( ! isset( $hideminor ) ) {
+               $hideminor = $wgUser->getOption( "hideminor" );
+       }
+       if ( $hideminor ) {
+               $mlink = $sk->makeKnownLink( $wgLang->specialPage( "Recentchangeslinked" ),
+                 WfMsg( "show" ), "target=" . wfEscapeHTML( $nt->getPrefixedURL() ) .
+                 "&days={$days}&limit={$limit}&hideminor=0" );
+       } else {
+               $mlink = $sk->makeKnownLink( $wgLang->specialPage( "Recentchangeslinked" ),
+                 WfMsg( "hide" ), "target=" . wfEscapeHTML( $nt->getPrefixedURL() ) .
+                 "&days={$days}&limit={$limit}&hideminor=1" );
+       }
+       if ( $hideminor ) {
+               $cmq = "AND cur_minor_edit=0";
+       } else { $cmq = ""; }
+
+       $sql = "SELECT cur_id,cur_namespace,cur_title,cur_user,cur_comment," .
+         "cur_user_text,cur_timestamp,cur_minor_edit,cur_is_new FROM links, cur " .
+         "WHERE cur_timestamp > '{$cutoff}' {$cmq} AND l_to=cur_id AND l_from='" .
+      wfStrencode( $nt->getPrefixedDBkey() ) . "' GROUP BY cur_id " .
+         "ORDER BY inverse_timestamp LIMIT {$limit}";
+       $res = wfQuery( $sql, $fname );
+
+       $note = str_replace( "$1", $limit, wfMsg( "rcnote" ) );
+       $note = str_replace( "$2", $days, $note );
+       $wgOut->addHTML( "<hr>\n{$note}\n<br>" );
+
+       $tu = "target=" . $nt->getPrefixedURL();
+       $note = rcDayLimitlinks( $days, $limit, "Recentchangeslinked", $tu );
+       $wgOut->addHTML( "{$note}\n" );
+
+       $s = $sk->beginRecentChangesList();
+       $count = wfNumRows( $res );
+
+       while ( $limit ) {
+               if ( 0 == $count ) { break; }
+               $obj = wfFetchObject( $res );
+               --$count;
+
+               $ts = $obj->cur_timestamp;
+               $u = $obj->cur_user;
+               $ut = $obj->cur_user_text;
+               $ns = $obj->cur_namespace;
+               $ttl = $obj->cur_title;
+               $com = $obj->cur_comment;
+               $me = ( $obj->cur_minor_edit > 0 );
+               $new = ( $obj->cur_is_new > 0 );
+
+               $s .= $sk->recentChangesLine( $ts, $u, $ut, $ns, $ttl, $com, $me, $new );
+               --$limit;
+       }
+       $s .= $sk->endRecentChangesList();
+
+       wfFreeResult( $res );
+       $wgOut->addHTML( $s );
+}
+
+?>
diff --git a/includes/SpecialShortpages.php b/includes/SpecialShortpages.php
new file mode 100644 (file)
index 0000000..57efef4
--- /dev/null
@@ -0,0 +1,46 @@
+<?
+
+function wfSpecialShortpages()
+{
+       global $wgUser, $wgOut, $wgLang, $wgTitle;
+       global $limit, $offset; # From query string
+       $fname = "wfSpecialShortpages";
+
+       global $wgMiserMode;
+       if ( $wgMiserMode ) {
+               $wgOut->addWikiText( wfMsg( "perfdisabled" ) );
+               return;
+       }
+
+       if ( ! $limit ) {
+               $limit = $wgUser->getOption( "rclimit" );
+               if ( ! $limit ) { $limit = 50; }
+       }
+       if ( ! $offset ) { $offset = 0; }
+
+       $sql = "SELECT cur_title, LENGTH(cur_text) AS len FROM cur " .
+         "WHERE cur_namespace=0 AND cur_is_redirect=0 ORDER BY " .
+         "LENGTH(cur_text) LIMIT {$offset}, {$limit}";
+       $res = wfQuery( $sql, $fname );
+
+       $top = wfShowingResults( $offset, $limit );
+       $wgOut->addHTML( "<p>{$top}\n" );
+
+       $sl = wfViewPrevNext( $offset, $limit,
+         $wgLang->specialPage( "Shortpages" ) );
+       $wgOut->addHTML( "<br>{$sl}\n" );
+
+       $sk = $wgUser->getSkin();
+       $s = "<ol start=" . ( $offset + 1 ) . ">";
+       while ( $obj = wfFetchObject( $res ) ) {
+               $nb = str_replace( "$1", $obj->len, wfMsg( "nbytes" ) );
+               $link = $sk->makeKnownLink( $obj->cur_title, "" );
+               $s .= "<li>{$link} ({$nb})</li>\n";
+       }
+       wfFreeResult( $res );
+       $s .= "</ol>";
+       $wgOut->addHTML( $s );
+       $wgOut->addHTML( "<p>{$sl}\n" );
+}
+
+?>
diff --git a/includes/SpecialSpecialpages.php b/includes/SpecialSpecialpages.php
new file mode 100644 (file)
index 0000000..0488a27
--- /dev/null
@@ -0,0 +1,46 @@
+<?
+
+function wfSpecialSpecialpages()
+{
+       global $wgUser, $wgOut, $wgLang;
+
+       $wgOut->setRobotpolicy( "index,nofollow" );
+
+       $sk = $wgUser->getSkin();
+       $validSP = $wgLang->getValidSpecialPages();
+       $wgOut->addHTML( "<h2>" . wfMsg( "spheading" ) . "</h2>\n<ul>" );
+
+       foreach ( $validSP as $name => $desc ) {
+               if ( "" == $desc ) { continue; }
+               $link = $sk->makeKnownLink( $wgLang->specialPage( $name ), $desc );
+               $wgOut->addHTML( "<li>{$link}</li>\n" );
+       }
+       $wgOut->addHTML( "</ul>\n" );
+
+       if ( $wgUser->isSysop() ) {
+               $sysopSP = $wgLang->getSysopSpecialPages();
+               $wgOut->addHTML( "<h2>" . wfMsg( "sysopspheading" ) . "</h2>\n<ul>" );
+
+               foreach ( $sysopSP as $name => $desc ) {
+                       if ( "" == $desc ) { continue; }
+                       $link = $sk->makeKnownLink( $wgLang->specialPage( $name ), $desc );
+                       $wgOut->addHTML( "<li>{$link}</li>\n" );
+               }
+               $wgOut->addHTML( "</ul>\n" );
+       }
+
+       if ( $wgUser->isDeveloper() ) {
+               $devSP = $wgLang->getDeveloperSpecialPages();
+               $wgOut->addHTML( "<h2>" . wfMsg( "developerspheading" ) .
+                 "</h2>\n<ul>" );
+
+               foreach ( $devSP as $name => $desc ) {
+                       if ( "" == $desc ) { continue; }
+                       $link = $sk->makeKnownLink( $wgLang->specialPage( $name ), $desc );
+                       $wgOut->addHTML( "<li>{$link}</li>\n" );
+               }
+               $wgOut->addHTML( "</ul>\n" );
+       }
+}
+
+?>
diff --git a/includes/SpecialStatistics.php b/includes/SpecialStatistics.php
new file mode 100644 (file)
index 0000000..cbbbb64
--- /dev/null
@@ -0,0 +1,53 @@
+<?
+
+function wfSpecialStatistics()
+{
+       global $wgUser, $wgOut;
+       $fname = "wfSpecialStatistics";
+
+       $wgOut->addHTML( "<h2>" . wfMsg( "sitestats" ) . "</h2>\n" );
+
+       $sql = "SELECT COUNT(cur_id) AS total FROM cur";
+       $res = wfQuery( $sql, $fname );
+       $row = wfFetchObject( $res );
+       $total = $row->total;
+
+       $sql = "SELECT ss_total_views, ss_total_edits, ss_good_articles " .
+         "FROM site_stats WHERE ss_row_id=1";
+       $res = wfQuery( $sql, $fname );
+       $row = wfFetchObject( $res );
+       $views = $row->ss_total_views;
+       $edits = $row->ss_total_edits;
+       $good = $row->ss_good_articles;
+
+       $text = str_replace( "$1", $total, wfMsg( "sitestatstext" ) );
+       $text = str_replace( "$2", $good, $text );
+       $text = str_replace( "$3", $views, $text );
+       $text = str_replace( "$4", $edits, $text );
+       $text = str_replace( "$5", sprintf( "%.2f", $edits / $total ), $text );
+       $text = str_replace( "$6", sprintf( "%.2f", $views / $edits ), $text );
+
+       $wgOut->addHTML( $text );
+       $wgOut->addHTML( "<h2>" . wfMsg( "userstats" ) . "</h2>\n" );
+
+       $sql = "SELECT COUNT(user_id) AS total FROM user";
+       $res = wfQuery( $sql, $fname );
+       $row = wfFetchObject( $res );
+       $total = $row->total;
+
+       $sql = "SELECT COUNT(user_id) AS total FROM user " .
+         "WHERE user_rights <> ''";
+       $res = wfQuery( $sql, $fname );
+       $row = wfFetchObject( $res );
+       $admins = $row->total;
+
+       $sk = $wgUser->getSkin();
+       $ap = $sk->makeKnownLink( wfMsg( "administrators" ), "" );
+
+       $text = str_replace( "$1", $total, wfMsg( "userstatstext" ) );
+       $text = str_replace( "$2", $admins, $text );
+       $text = str_replace( "$3", $ap, $text );
+       $wgOut->addHTML( $text );
+}
+
+?>
diff --git a/includes/SpecialUndelete.php b/includes/SpecialUndelete.php
new file mode 100644 (file)
index 0000000..8f786c7
--- /dev/null
@@ -0,0 +1,161 @@
+<?
+
+function wfSpecialUndelete( )
+{
+    global $wgLang, $wgUser, $wgOut, $action, $target, $timestamp, $restore;
+    
+    if( isset($target ) ) {
+       $t = Title::newFromURL( $target );
+       $title = $t->mDbkeyform;
+       $namespace = $t->mNamespace;
+       if( isset( $timestamp ) ) {
+               return doUndeleteShowRevision( $namespace, $title, $timestamp );
+       }
+       if( isset( $action ) and isset( $restore) and $action == "submit" ) {
+               return doUndeleteArticle( $namespace, $title );
+       }
+       return doUndeleteShowHistory( $namespace, $title );
+    }
+    
+    # List undeletable articles    
+    $sql = "SELECT ar_namespace,ar_title, COUNT(*) AS count FROM archive GROUP BY ar_namespace,ar_title ORDER BY ar_title";
+    $res = wfQuery( $sql );
+    
+       $wgOut->setPagetitle( wfMsg( "undeletepage" ) );
+       $wgOut->addWikiText( wfMsg( "undeletepagetext" ) );
+
+    $special = $wgLang->getNsText( Namespace::getSpecial() );
+    $sk = $wgUser->getSkin();
+    $wgOut->addHTML( "<ul>\n" );
+    while ($row = wfFetchObject( $res )) {
+       $n = ($row->ar_namespace ? 
+               ($wgLang->getNsText( $row->ar_namespace ) . ":") : "").
+               $row->ar_title;
+
+       $wgOut->addHTML( "<li>" .
+         $sk->makeKnownLink( $wgLang->specialPage( "Undelete" ),
+          $n, "target=" . urlencode($n) ) . " " .
+         str_replace( '$1', $row->count, wfMsg( "undeleterevisions" )) );
+    }
+    $wgOut->addHTML( "</ul>\n" );
+    
+    return $ret;    
+}
+
+/* private */ function doUndeleteShowRevision( $namespace, $title, $timestamp ) {
+    global $wgLang, $wgUser, $wgOut, $action, $target, $timestamp, $restore;
+    
+    if(!preg_match("/[0-9]{14}/",$timestamp)) return 0;
+    
+    $sql = "SELECT ar_text FROM archive WHERE ar_namespace={$namespace} AND ar_title=\"{$title}\" AND ar_timestamp={$timestamp}";
+    $ret = wfQuery( $sql );
+    $row = wfFetchObject( $ret );
+    
+    $wgOut->setPagetitle( wfMsg( "undeletepage" ) );
+    $wgOut->addWikiText( "(" . str_replace("$1",
+      $wgLang->date($timestamp, true), wfMsg( "undeleterevision" ))
+      . ")\n<hr>\n" . $row->ar_text );
+    
+       return 0;
+}
+
+/* private */ function doUndeleteShowHistory( $namespace, $title ) {
+    global $wgLang, $wgUser, $wgOut, $action, $target, $timestamp, $restore;
+    
+    $sk = $wgUser->getSkin();
+    $wgOut->setPagetitle( wfMsg( "undeletepage" ) );
+    $wgOut->addWikiText( wfMsg( "undeletehistory" ) . "\n<hr>\n" . $row->ar_text );
+
+       $action = wfLocalUrlE( $wgLang->specialPage( "Undelete" ), "action=submit" );
+       $wgOut->addHTML("<p>
+<form id=\"undelete\" method=\"post\" action=\"{$action}\">
+<input type=hidden name=\"target\" value=\"{$target}\">
+<input type=submit name=\"restore\" value=\"".wfMsg("undeletebtn")."\">
+</form>");
+
+    $log = wfGetSQL("cur", "cur_text", "cur_namespace=4 AND cur_title=\"".wfMsg("dellogpage")."\"" );
+    if(preg_match("/^(.*".
+       preg_quote( ($namespace ? ($wgLang->getNsText($namespace) . ":") : "")
+       . str_replace("_", " ", $title), "/" ).".*)$/m", $log, $m)) {
+       $wgOut->addWikiText( $m[1] );
+    }
+    
+    $sql = "SELECT ar_minor_edit,ar_timestamp,ar_user,ar_user_text,ar_comment
+      FROM archive WHERE ar_namespace={$namespace} AND ar_title=\"{$title}\"
+      ORDER BY ar_timestamp DESC";
+    $ret = wfQuery( $sql );
+    
+    $special = $wgLang->getNsText( Namespace::getSpecial() );
+    $wgOut->addHTML("<ul>");
+    while( $row = wfFetchObject( $ret ) ) {
+        $wgOut->addHTML( "<li>" .
+         $sk->makeKnownLink( $wgLang->specialPage( "Undelete" ),
+          $wgLang->timeanddate( $row->ar_timestamp, true ),
+          "target=" . urlencode($target) . "&timestamp={$row->ar_timestamp}" ) . " " .
+         ". . {$row->ar_user_text}" .
+          " <i>(" . htmlspecialchars($row->ar_comment) . "</i>)\n");
+
+    }
+    $wgOut->addHTML("</ul>");
+    
+       return 0;
+}
+       
+/* private */ function doUndeleteArticle( $namespace, $title )
+       {
+               global $wgUser, $wgOut, $wgLang, $target;
+
+               $fname = "doUndeleteArticle";
+
+               if ( "" == $title ) {
+                       $wgOut->fatalError( wfMsg( "cannotundelete" ) );
+                       return;
+               }
+               $t = addslashes($title);
+
+               # Move article and history from the "archive" table
+               $sql = "SELECT COUNT(*) AS count FROM cur WHERE cur_namespace={$namespace} AND cur_title='{$t}'";
+               $res = wfQuery( $sql );
+               $row = wfFetchObject( $res );
+               if( $row->count == 0) {
+                       # Have to create new article...
+                       $max = wfGetSQL( "archive", "MAX(ar_timestamp)", "ar_namespace={$namespace} AND ar_title='{$t}'" );
+               $sql = "INSERT INTO cur (cur_namespace,cur_title,cur_text," .
+                         "cur_comment,cur_user,cur_user_text,cur_timestamp,inverse_timestamp,cur_minor_edit,cur_random)" .
+                         "SELECT ar_namespace,ar_title,ar_text,ar_comment," .
+                         "ar_user,ar_user_text,ar_timestamp,99999999999999-ar_timestamp,ar_minor_edit,RAND() FROM archive " .
+                         "WHERE ar_namespace={$namespace} AND ar_title='{$t}' AND ar_timestamp={$max}";
+                       wfQuery( $sql, $fname );
+               $newid = wfInsertId();
+                       $oldones = "AND ar_timestamp<{$max}";
+               } else {
+                       # If already exists, put history entirely into old table
+                       $oldones = "";
+                       $newid = 0;
+               }
+               
+               $sql = "INSERT INTO old (old_namespace,old_title,old_text," .
+                 "old_comment,old_user,old_user_text,old_timestamp,inverse_timestamp,old_minor_edit," .
+                 "old_flags) SELECT ar_namespace,ar_title,ar_text,ar_comment," .
+                 "ar_user,ar_user_text,ar_timestamp,99999999999999-ar_timestamp,ar_minor_edit,ar_flags " .
+                 "FROM archive WHERE ar_namespace={$namespace} AND ar_title='{$t}' {$oldones}";
+               wfQuery( $sql, $fname );
+
+        # Finally, clean up the link tables
+        if( $newid ) {
+               $to = Title::newFromDBKey( $target );
+                       $to->resetArticleID( $newid );
+               }
+
+               # Now that it's safely stored, take it out of the archive
+               $sql = "DELETE FROM archive WHERE ar_namespace={$namespace} AND " .
+                 "ar_title='{$t}'";
+               wfQuery( $sql, $fname );
+
+               
+        # Touch the log?
+        
+        $wgOut->addWikiText(str_replace("$1", $target, wfMsg("undeletedtext")));
+               return 0;
+       }
+?>
diff --git a/includes/SpecialUnlockdb.php b/includes/SpecialUnlockdb.php
new file mode 100644 (file)
index 0000000..7baee94
--- /dev/null
@@ -0,0 +1,82 @@
+<?
+
+function wfSpecialUnlockdb()
+{
+       global $wgUser, $wgOut, $action;
+
+       if ( ! $wgUser->isDeveloper() ) {
+               $wgOut->developerRequired();
+               return;
+       }
+       $f = new DBUnlockForm();
+
+       if ( "success" == $action ) { $f->showSuccess(); }
+       else if ( "submit" == $action ) { $f->doSubmit(); }
+       else { $f->showForm( "" ); }
+}
+
+class DBUnlockForm {
+
+       function showForm( $err )
+       {
+               global $wgOut, $wgUser, $wgLang;
+               global $wpLockConfirm;
+
+               $wgOut->setPagetitle( wfMsg( "unlockdb" ) );
+               $wgOut->addWikiText( wfMsg( "unlockdbtext" ) );
+
+               if ( "" != $err ) {
+                       $wgOut->setSubtitle( wfMsg( "formerror" ) );
+                       $wgOut->addHTML( "<p><font color='red' size='+1'>{$err}</font>\n" );
+               }
+               $lc = wfMsg( "unlockconfirm" );
+               $lb = wfMsg( "unlockbtn" );
+               $action = wfLocalUrlE( $wgLang->specialPage( "Unlockdb" ),
+                 "action=submit" );
+
+               $wgOut->addHTML( "<p>
+<form id=\"unlockdb\" method=\"post\" action=\"{$action}\">
+<table border=0><tr>
+<td align=right>
+<input type=checkbox name=\"wpLockConfirm\">
+</td>
+<td align=\"left\">{$lc}<td>
+</tr><tr>
+<td>&nbsp;</td><td align=left>
+<input type=submit name=\"wpLock\" value=\"{$lb}\">
+</td></tr></table>
+</form>\n" );
+
+       }
+
+       function doSubmit()
+       {
+               global $wgOut, $wgUser, $wgLang;
+               global $wpLockConfirm, $wgReadOnlyFile;
+
+               if ( ! $wpLockConfirm ) {
+                       $this->showForm( wfMsg( "locknoconfirm" ) );
+                       return;
+               }
+               if ( ! unlink( $wgReadOnlyFile ) ) {
+                       $wgOut->fileDeleteError( $wgReadOnlyFile );
+                       return;
+               }
+               $success = wfLocalUrl( $wgLang->specialPage( "Unlockdb" ),
+                 "action=success" );
+               $wgOut->redirect( $success );
+       }
+
+       function showSuccess()
+       {
+               global $wgOut, $wgUser;
+               global $ip;
+
+               $wgOut->setPagetitle( wfMsg( "unlockdb" ) );
+               $wgOut->setSubtitle( wfMsg( "unlockdbsuccesssub" ) );
+               $text = str_replace( "$1", $ip, wfMsg( "unlockdbsuccesstext" ) );
+               $wgOut->addWikiText( $text );
+       }
+}
+
+?>
diff --git a/includes/SpecialUnusedimages.php b/includes/SpecialUnusedimages.php
new file mode 100644 (file)
index 0000000..9157073
--- /dev/null
@@ -0,0 +1,56 @@
+<?
+
+function wfSpecialUnusedimages()
+{
+       global $wgUser, $wgOut, $wgLang, $wgTitle;
+       global $limit, $offset; # From query string
+       $fname = "wfSpecialUnusedimages";
+
+       if ( ! $limit ) {
+               $limit = $wgUser->getOption( "rclimit" );
+               if ( ! $limit ) { $limit = 50; }
+       }
+       if ( ! $offset ) { $offset = 0; }
+
+       $sql = "SELECT img_name,img_user,img_user_text,img_timestamp,img_description " .
+         "FROM image LEFT JOIN imagelinks ON img_name=il_to WHERE il_to IS NULL " .
+         "ORDER BY img_timestamp LIMIT {$offset}, {$limit}";
+       $res = wfQuery( $sql, $fname );
+
+       $sk = $wgUser->getSkin();
+
+       $wgOut->addHTML( wfMsg( "unusedimagestext" ) );
+       $top = wfShowingResults( $offset, $limit );
+       $wgOut->addHTML( "<p>{$top}\n" );
+
+       $sl = wfViewPrevNext( $offset, $limit,
+         $wgLang->specialPage( "Unusedimages" ) );
+       $wgOut->addHTML( "<br>{$sl}\n" );
+
+       $ins = $wgLang->getNsText ( 6 ) ;
+       $s = "<ol start=" . ( $offset + 1 ) . ">";
+       while ( $obj = wfFetchObject( $res ) ) {
+               $name = $obj->img_name;
+               $dlink = $sk->makeKnownLink( "{$ins}:{$name}", wfMsg( "imgdesc" ) );
+               $ilink = "<a href=\"" . wfImageUrl( $name ) . "\">{$name}</a>";
+
+               $d = $wgLang->timeanddate( $obj->img_timestamp, true );
+               $u = $obj->img_user;
+               $ut = $obj->img_user_text;
+               $c = $obj->img_description;
+
+               if ( 0 == $u ) { $ul = $ut; }
+               else { $ul = $sk->makeLink( $wgLang->getNsText(2).":{$ut}", $ut ); }
+
+               $s .= "<li>({$dlink}) {$ilink} . . {$d} . . {$ul}";
+
+               if ( "" != $c && "*" != $c ) { $s .= " <em>({$c})</em>"; }
+               $s .= "</li>\n";
+       }
+       wfFreeResult( $res );
+       $s .= "</ol>";
+       $wgOut->addHTML( $s );
+       $wgOut->addHTML( "<p>{$sl}\n" );
+}
+
+?>
diff --git a/includes/SpecialUpload.php b/includes/SpecialUpload.php
new file mode 100644 (file)
index 0000000..fc7093f
--- /dev/null
@@ -0,0 +1,245 @@
+<?
+
+function wfSpecialUpload()
+{
+       global $wgUser, $wgOut, $wpUpload, $wpReUpload, $action;
+
+       $fields = array( "wpUploadFile", "wpUploadDescription" );
+       wfCleanFormFields( $fields );
+
+       if ( 0 == $wgUser->getID() ) {
+               $wgOut->errorpage( "uploadnologin", "uploadnologintext" );
+               return;
+       }
+       if ( wfReadOnly() ) {
+               $wgOut->readOnlyPage();
+               return;
+       }
+       if ( isset( $wpReUpload) ) {
+               unsaveUploadedFile();
+               mainUploadForm( "" );
+       } else if ( "submit" == $action || isset( $wpUpload ) ) {
+               processUpload();
+       } else {
+               mainUploadForm( "" );
+       }
+}
+
+function processUpload()
+{
+       global $wgUser, $wgOut, $wgLang, $wpUploadAffirm, $wpUploadFile;
+       global $wpUploadDescription, $wpIgnoreWarning;
+       global $HTTP_POST_FILES, $wgUploadDirectory;
+       global $wpUploadSaveName, $wpUploadTempName, $wpUploadSize;
+       global $wgSavedFile, $wgUploadOldVersion, $wpUploadOldVersion;
+
+       if ( 1 != $wpUploadAffirm ) {
+               mainUploadForm( WfMsg( "noaffirmation" ) );
+               return;
+       }
+       if ( ! $wpUploadTempName ) {
+               $wpUploadTempName = $HTTP_POST_FILES['wpUploadFile']['tmp_name'];
+       }
+       if ( ! $wpUploadSize ) {
+               $wpUploadSize = $HTTP_POST_FILES['wpUploadFile']['size'];
+       }
+       $prev = error_reporting( E_ALL & ~( E_NOTICE | E_WARNING ) );
+       $oname = wfCleanQueryVar( $HTTP_POST_FILES['wpUploadFile']['name'] );
+       if ( $wpUploadSaveName != "" ) $wpUploadSaveName = wfCleanQueryVar( $wpUploadSaveName );
+       error_reporting( $prev );
+
+       if ( "" != $oname ) {
+               $basename = strrchr( $oname, "/" );
+               if ( false === $basename ) { $basename = $oname; }
+               else ( $basename = substr( $basename, 1 ) );
+
+               $ext = strrchr( $basename, "." );
+               if ( false === $ext ) { $ext = ""; }
+               else { $ext = substr( $ext, 1 ); }
+
+               if ( "" == $ext ) { $xl = 0; } else { $xl = strlen( $ext ) + 1; }
+               $partname = substr( $basename, 0, strlen( $basename ) - $xl );
+
+               if ( strlen( $partname ) < 3 ) {
+                       mainUploadForm( WfMsg( "minlength" ) );
+                       return;
+               }
+               $nt = Title::newFromText( $basename );
+               $wpUploadSaveName = $nt->getDBkey();
+
+               saveUploadedFile();
+               if ( ( ! $wpIgnoreWarning ) &&
+                 ( 0 != strcmp( ucfirst( $basename ), $wpUploadSaveName ) ) ) {
+                       $warn = str_replace( "$1", $wpUploadSaveName,
+                         wfMsg( "badfilename" ) );
+                       return uploadWarning( $warn );
+               }
+               $extensions = array( "png", "jpg", "jpeg", "ogg" ); 
+               if ( ( ! $wpIgnoreWarning ) &&
+                 ( ! in_array( strtolower( $ext ), $extensions ) ) ) {
+                       $warn = str_replace( "$1", $ext, wfMsg( "badfiletype" ) );
+                       return uploadWarning( $warn );
+               }
+               if ( ( ! $wpIgnoreWarning ) && ( $wpUploadSize > 150000 ) ) {
+                       return uploadWarning( WfMsg( "largefile" ) );
+               }
+       }
+       if ( isset( $wpUploadOldVersion ) ) {
+               $wgUploadOldVersion = $wpUploadOldVersion;
+       }
+       wfRecordUpload( $wpUploadSaveName, $wgUploadOldVersion,
+         $wpUploadSize, $wpUploadDescription );
+
+       $sk = $wgUser->getSkin();
+       $ilink = $sk->makeMediaLink( $wpUploadSaveName, wfImageUrl(
+         $wpUploadSaveName ) );
+       $dname = $wgLang->getNsText( Namespace::getImage() ) . ":{$wpUploadSaveName}";
+       $dlink = $sk->makeKnownLink( $dname, $dname );
+
+       $wgOut->addHTML( "<h2>" . wfMsg( "successfulupload" ) . "</h2>\n" );
+       $text = str_replace( "$1", $ilink, wfMsg( "fileuploaded" ) );
+       $text = str_replace( "$2", $dlink, $text );
+       $wgOut->addHTML( "<p>{$text}\n" );
+       $wgOut->returnToMain( false );
+}
+
+function saveUploadedFile()
+{
+       global $wpUploadSaveName, $wpUploadTempName;
+       global $wgSavedFile, $wgUploadOldVersion;
+       global $wgUploadDirectory, $wgOut;
+
+       $dest = wfImageDir( $wpUploadSaveName );
+       $archive = wfImageArchiveDir( $wpUploadSaveName );
+       $wgSavedFile = "{$dest}/{$wpUploadSaveName}";
+
+       if ( is_file( $wgSavedFile ) ) {
+               $wgUploadOldVersion = date( "YmdHis" ) . "!{$wpUploadSaveName}";
+
+               if ( ! rename( $wgSavedFile, "${archive}/{$wgUploadOldVersion}" ) ) { 
+                       $wgOut->fileRenameError( $wgSavedFile,
+                         "${archive}/{$wgUploadOldVersion}" );
+                       return;
+               }
+       } else {
+               $wgUploadOldVersion = "";
+       }
+       if ( ! move_uploaded_file( $wpUploadTempName, $wgSavedFile ) ) {
+               $wgOut->fileCopyError( $wpUploadTempName, $wgSavedFile );
+       }
+       chmod( $wgSavedFile, 0644 );
+}
+
+function unsaveUploadedFile()
+{
+       global $wgSavedFile, $wgUploadOldVersion;
+       global $wpSavedFile, $wpUploadOldVersion;
+       global $wgUploadDirectory, $wgOut;
+
+       $wgSavedFile = $wpSavedFile;
+       $wgUploadOldVersion = $wpUploadOldVersion;
+
+       if ( ! unlink( $wgSavedFile ) ) {
+               $wgOut->fileDeleteError( $wgSavedFile );
+               return;
+       }
+       if ( "" != $wgUploadOldVersion ) {
+               $hash = md5( substr( $wgUploadOldVersion, 15 ) );
+               $archive = "{$wgUploadDirectory}/archive/" . $hash{0} .
+               "/" . substr( $hash, 0, 2 );
+
+               if ( ! rename( "{$archive}/{$wgUploadOldVersion}", $wgSavedFile ) ) {
+                       $wgOut->fileRenameError( "{$archive}/{$wgUploadOldVersion}",
+                         $wgSavedFile );
+               }
+       }
+}
+
+function uploadWarning( $warning )
+{
+       global $wgOut, $wgUser, $wgLang, $wgUploadDirectory;
+       global $wpUpload, $wpReUpload, $wpUploadAffirm, $wpUploadFile;
+       global $wpUploadDescription, $wpIgnoreWarning;
+       global $wpUploadSaveName, $wpUploadTempName, $wpUploadSize;
+       global $wgSavedFile, $wgUploadOldVersion;
+       global $wpSavedFile, $wpUploadOldVersion;
+
+       $sub = wfMsg( "uploadwarning" );
+       $wgOut->addHTML( "<h2>{$sub}</h2>\n" );
+       $wgOut->addHTML( "<h4><font color=red>{$warning}</font></h4>\n" );
+
+       $save = wfMsg( "savefile" );
+       $reupload = wfMsg( "reupload" );
+       $iw = wfMsg( "ignorewarning" );
+       $reup = wfMsg( "reuploaddesc" );
+       $action = wfLocalUrlE( $wgLang->specialPage( "Upload" ),
+         "action=submit" );
+
+       $wgOut->addHTML( "
+<form id=\"uploadwarning\" method=\"post\" enctype=\"multipart/form-data\"
+action=\"{$action}\">
+<input type=hidden name=\"wpUploadAffirm\" value=\"1\">
+<input type=hidden name=\"wpIgnoreWarning\" value=\"1\">
+<input type=hidden name=\"wpUploadDescription\" value=\"" . htmlspecialchars( $wpUploadDescription ) . "\">
+<input type=hidden name=\"wpUploadSaveName\" value=\"" . htmlspecialchars( $wpUploadSaveName ) . "\">
+<input type=hidden name=\"wpUploadTempName\" value=\"" . htmlspecialchars( $wpUploadTempName ) . "\">
+<input type=hidden name=\"wpUploadSize\" value=\"" . htmlspecialchars( $wpUploadSize ) . "\">
+<input type=hidden name=\"wpSavedFile\" value=\"" . htmlspecialchars( $wgSavedFile ) . "\">
+<input type=hidden name=\"wpUploadOldVersion\" value=\"" . htmlspecialchars( $wgUploadOldVersion) . "\">
+<table border=0><tr>
+<tr><td align=right>
+<input tabindex=2 type=submit name=\"wpUpload\" value=\"{$save}\">
+</td><td align=left>{$iw}</td></tr>
+<tr><td align=right>
+<input tabindex=2 type=submit name=\"wpReUpload\" value=\"{$reupload}\">
+</td><td align=left>{$reup}</td></tr></table></form>\n" );
+}
+
+function mainUploadForm( $msg )
+{
+       global $wgOut, $wgUser, $wgLang, $wgUploadDirectory;
+       global $wpUpload, $wpUploadAffirm, $wpUploadFile;
+       global $wpUploadDescription, $wpIgnoreWarning;
+
+       if ( "" != $msg ) {
+               $sub = wfMsg( "uploaderror" );
+               $wgOut->addHTML( "<h2>{$sub}</h2>\n" .
+                 "<h4><font color=red>{$msg}</font></h4>\n" );
+       } else {
+               $sub = wfMsg( "uploadfile" );
+               $wgOut->addHTML( "<h2>{$sub}</h2>\n" );
+       }
+       $wgOut->addHTML( "<p>" . wfMsg( "uploadtext" ) );
+       $sk = $wgUser->getSkin();
+
+       $fn = wfMsg( "filename" );
+       $fd = wfMsg( "filedesc" );
+       $ulb = wfMsg( "uploadbtn" );
+
+       $clink = $sk->makeKnownLink( wfMsg( "copyrightpage" ),
+         wfMsg( "copyrightpagename" ) );
+       $ca = str_replace( "$1", $clink, wfMsg( "affirmation" ) );
+       $iw = wfMsg( "ignorewarning" );
+
+       $action = wfLocalUrl( $wgLang->specialPage( "Upload" ) );
+       $wgOut->addHTML( "
+<form id=\"upload\" method=\"post\" enctype=\"multipart/form-data\"
+action=\"{$action}\">
+<table border=0><tr>
+<td align=right>{$fn}:</td><td align=left>
+<input tabindex=1 type=file name=\"wpUploadFile\" value=\""
+  . htmlspecialchars( $wpUploadFile ) . "\" size=40>
+</td></tr><tr>
+<td align=right>{$fd}:</td><td align=left>
+<input tabindex=2 type=text name=\"wpUploadDescription\" value=\""
+  . htmlspecialchars( $wpUploadDescription ) . "\" size=40>
+</td></tr><tr>
+<td align=right>
+<input tabindex=3 type=checkbox name=\"wpUploadAffirm\" value=\"1\">
+</td><td align=left>{$ca}</td></tr>
+<tr><td>&nbsp;</td><td align=left>
+<input tabindex=5 type=submit name=\"wpUpload\" value=\"{$ulb}\">
+</td></tr></table></form>\n" );
+}
+
+?>
diff --git a/includes/SpecialUserlogin.php b/includes/SpecialUserlogin.php
new file mode 100644 (file)
index 0000000..ed16443
--- /dev/null
@@ -0,0 +1,248 @@
+<?
+
+function wfSpecialUserlogin()
+{
+       global $wpCreateaccount, $wpLoginattempt, $wpMailmypassword;
+       global $action;
+
+       $fields = array( "wpName", "wpPassword", "wpName",
+         "wpPassword", "wpRetype", "wpEmail" );
+       wfCleanFormFields( $fields );
+
+       if ( isset( $wpCreateaccount ) ) {
+               addNewAccount();
+       } else if ( isset( $wpMailmypassword ) ) {
+               mailPassword();
+       } else if ( "submit" == $action || isset( $wpLoginattempt ) ) {
+               processLogin();
+       } else {
+               mainLoginForm( "" );
+       }
+}
+
+/* private */ function addNewAccount()
+{
+       global $wgUser, $wgOut, $wpPassword, $wpRetype, $wpName, $wpRemember;
+       global $wpEmail, $wgDeferredUpdateList;
+
+       if ( 0 != strcmp( $wpPassword, $wpRetype ) ) {
+               mainLoginForm( wfMsg( "badretype" ) );
+               return;
+       }
+       $wpName = trim( $wpName );
+       if ( ( "" == $wpName ) ||
+         preg_match( "/^\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}$/", $wpName ) ) {
+               mainLoginForm( wfMsg( "noname" ) );
+               return;
+       }
+       if ( wfReadOnly() ) {
+               $wgOut->readOnlyPage();
+               return;
+       }
+       $u = User::newFromName( $wpName );
+
+       if ( 0 != $u->idForName() ) {
+               mainLoginForm( wfMsg( "userexists" ) );
+               return;
+       }
+       $u->addToDatabase();
+       $u->setPassword( $wpPassword );
+       $u->setEmail( $wpEmail );
+       if ( 1 == $wpRemember ) { $r = 1; }
+       else { $r = 0; }
+       $u->setOption( "rememberpassword", $r );
+
+       $wgUser = $u;
+       $m = str_replace( "$1", $wgUser->getName(), wfMsg( "welcomecreation" ) );
+       successfulLogin( $m );
+}
+
+/* private */ function processLogin()
+{
+       global $wgUser, $wpName, $wpPassword, $wpRemember;
+       global $returnto;
+
+       if ( "" == $wpName ) {
+               mainLoginForm( wfMsg( "noname" ) );
+               return;
+       }
+       $u = User::newFromName( $wpName );
+       $id = $u->idForName();
+       if ( 0 == $id ) {
+               $m = str_replace( "$1", $u->getName(), wfMsg( "nosuchuser" ) );
+               mainLoginForm( $m );
+               return;
+       }
+       $u->setId( $id );
+       $u->loadFromDatabase();
+       $ep = User::encryptPassword( $wpPassword );
+       if ( 0 != strcmp( $ep, $u->getPassword() ) ) {
+               if ( 0 != strcmp( $ep, $u->getNewpassword() ) ) {
+                       mainLoginForm( wfMsg( "wrongpassword" ) );
+                       return;
+               }
+       }
+       # We've verified now, update the real record
+       #
+       if ( 1 == $wpRemember ) { $r = 1; }
+       else { $r = 0; }
+       $u->setOption( "rememberpassword", $r );
+
+       $wgUser = $u;
+       $m = str_replace( "$1", $wgUser->getName(), wfMsg( "loginsuccess" ) );
+       successfulLogin( $m );
+}
+
+/* private */ function mailPassword()
+{
+       global $wgUser, $wpName, $wgDeferredUpdateList, $wgOutputEncoding;
+
+       if ( "" == $wpName ) {
+               mainLoginForm( wfMsg( "noname" ) );
+               return;
+       }
+       $u = User::newFromName( $wpName );
+       $id = $u->idForName();
+       if ( 0 == $id ) {
+               $m = str_replace( "$1", $u->getName(), wfMsg( "nosuchuser" ) );
+               mainLoginForm( $m );
+               return;
+       }
+       $u->setId( $id );
+       $u->loadFromDatabase();
+
+       if ( "" == $u->getEmail() ) {
+               $m = str_replace( "$1", $u->getName(), wfMsg( "noemail" ) );
+               mainLoginForm( $m );
+               return;
+       }
+       $np = User::randomPassword();
+       $u->setNewpassword( $np );
+       setcookie( "wcUserPassword", "", time() - 3600 );
+       $u->saveSettings();
+
+       $ip = getenv( "REMOTE_ADDR" );
+       if ( "" == $ip ) { $ip = "(Unknown)"; }
+
+       $m = str_replace( "$1", $ip, wfMsg( "passwordremindertext" ) );
+       $m = str_replace( "$2", $u->getName(), $m );
+       $m = str_replace( "$3", $np, $m );
+
+       #FIXME: Generilize the email addresses for 3rd party sites...
+       mail( $u->getEmail(), wfMsg( "passwordremindertitle" ), $m,
+         "MIME-Version: 1.0\r\n" .
+         "Content-type: text/plain; charset={$wgOutputEncoding}\r\n" .
+         "Content-transfer-encoding: 8bit\r\n" .
+         "From: Wikipedia Mail <apache@www.wikipedia.org>\r\n" .
+         "Reply-To: webmaster@www.wikipedia.org" );
+       $m = str_replace( "$1", $u->getName(), wfMsg( "passwordsent" ) );
+       mainLoginForm( $m );
+}
+
+/* private */ function successfulLogin( $msg )
+{
+       global $wgUser, $wgOut, $returnto;
+       global $wgDeferredUpdateList;
+
+       $wgUser->setCookies();
+       $up = new UserUpdate();
+       array_push( $wgDeferredUpdateList, $up );
+
+       $wgOut->setPageTitle( wfMsg( "loginsuccesstitle" ) );
+       $wgOut->setRobotpolicy( "noindex,nofollow" );
+       $wgOut->setArticleFlag( false );
+       $wgOut->addHTML( $msg . "\n<p>" );
+       $wgOut->returnToMain();
+}
+
+/* private */ function mainLoginForm( $err )
+{
+       global $wgUser, $wgOut, $wgLang, $returnto;
+       global $wpName, $wpPassword, $wpRetype, $wpRemember;
+       global $wpEmail, $HTTP_COOKIE_VARS;
+
+       $le = wfMsg( "loginerror" );
+       $yn = wfMsg( "yourname" );
+       $yp = wfMsg( "yourpassword" );
+       $ypa = wfMsg( "yourpasswordagain" );
+       $rmp = wfMsg( "remembermypassword" );
+       $ayn = wfMsg( "areyounew" );
+       $nuo = wfMsg( "newusersonly" );
+       $li = wfMsg( "login" );
+       $ca = wfMsg( "createaccount" );
+       $ye = wfMsg( "youremail" );
+       $efl = wfMsg( "emailforlost" );
+       $mmp = wfMsg( "mailmypassword" );
+
+       $name = $wpName;
+       if ( "" == $name ) {
+               if ( 0 != $wgUser->getID() ) {
+                       $name = $wgUser->getName();
+               } else {
+                       $name = $HTTP_COOKIE_VARS["wcUserName"];
+               }
+       }
+       $pwd = $wpPassword;
+
+       $wgOut->setPageTitle( wfMsg( "userlogin" ) );
+       $wgOut->setRobotpolicy( "noindex,nofollow" );
+       $wgOut->setArticleFlag( false );
+
+       if ( "" == $err ) {
+               $wgOut->addHTML( "<h2>$li:</h2>\n" );
+       } else {
+               $wgOut->addHTML( "<h2>$le:</h2>\n<font size='+1' color='red'>$err</font>\n" );
+       }
+       if ( 1 == $wgUser->getOption( "rememberpassword" ) ) {
+               $checked = " checked";
+       } else {
+               $checked = "";
+       }
+       $q = "action=submit";
+       if ( "" != $returnto ) { $q .= "&returnto=" . wfUrlencode($returnto); }
+       $action = wfLocalUrlE( $wgLang->specialPage( "Userlogin" ), $q );
+
+       $wpName = wfEscapeHTML( $wpName );
+       $wpPassword = wfEscapeHTML( $wpPassword );
+       $wpRetype = wfEscapeHTML( $wpRetype );
+       $wpEmail = wfEscapeHTML( $wpEmail );
+
+       $wgOut->addHTML( "
+<form id=\"userlogin\" method=\"post\" action=\"{$action}\">
+<table border=0><tr>
+<td align=right>$yn:</td>
+<td colspan=2 align=left>
+<input tabindex=1 type=text name=\"wpName\" value=\"{$name}\" size=20>
+</td></tr><tr>
+<td align=right>$yp:</td>
+<td align=left>
+<input tabindex=2 type=password name=\"wpPassword\" value=\"{$pwd}\" size=20>
+</td>
+<td align=left>
+<input tabindex=3 type=submit name=\"wpLoginattempt\" value=\"{$li}\">
+</td></tr>
+<tr><td colspan=3>&nbsp;</td></tr><tr>
+<td align=right>$ypa:</td>
+<td align=left>
+<input tabindex=4 type=password name=\"wpRetype\" value=\"{$wpRetype}\" size=20>
+</td><td>$nuo</td></tr>
+<tr>
+<td align=right>$ye:</td>
+<td align=left>
+<input tabindex=5 type=text name=\"wpEmail\" value=\"{$wpEmail}\" size=20>
+</td><td align=left>
+<input tabindex=6 type=submit name=\"wpCreateaccount\" value=\"{$ca}\">
+</td></tr>
+<tr>
+<td colspan=3 align=left>
+<input tabindex=7 type=checkbox name=\"wpRemember\" value=\"1\"$checked>$rmp
+</td></tr>
+<tr><td colspan=3>&nbsp;</td></tr><tr>
+<td colspan=3 align=left>
+<p>$efl<br>
+<input tabindex=8 type=submit name=\"wpMailmypassword\" value=\"{$mmp}\">
+</td></tr></table>
+</form>\n" );
+}
+
+?>
diff --git a/includes/SpecialUserlogout.php b/includes/SpecialUserlogout.php
new file mode 100644 (file)
index 0000000..0943351
--- /dev/null
@@ -0,0 +1,13 @@
+<?
+
+function wfSpecialUserlogout()
+{
+       global $wgUser, $wgOut, $returnto;
+
+       $wgUser->logout();
+       $wgOut->setRobotpolicy( "noindex,nofollow" );
+       $wgOut->addHTML( wfMsg( "logouttext" ) . "\n<p>" );
+       $wgOut->returnToMain();
+}
+
+?>
diff --git a/includes/SpecialVote.php b/includes/SpecialVote.php
new file mode 100644 (file)
index 0000000..de0f8ff
--- /dev/null
@@ -0,0 +1,10 @@
+<?
+
+function wfSpecialVote()
+{
+       global $wgUser, $wgOut;
+
+       $wgOut->addHTML( "<p>(TODO: Vote)" );
+}
+
+?>
diff --git a/includes/SpecialWantedpages.php b/includes/SpecialWantedpages.php
new file mode 100644 (file)
index 0000000..3f84ce3
--- /dev/null
@@ -0,0 +1,74 @@
+<?
+global $IP;
+include_once ( "$IP/LogPage.php" ) ;
+
+function wfSpecialWantedpages()
+{
+       global $wgUser, $wgOut, $wgLang, $wgTitle;
+       global $limit, $offset; # From query string
+       $fname = "wfSpecialWantedpages";
+
+       # Cache
+       $vsp = $wgLang->getValidSpecialPages() ;
+       $mw = $vsp["Wantedpages"] ;
+       $mw = str_replace ( " " , "_" , $mw ) ; # DBKEY
+       $log = new LogPage ( $mw ) ;
+       $log->mUpdateRecentChanges = false ;
+
+       $wgOut->setRobotpolicy( "noindex,nofollow" );
+       global $wgMiserMode;
+       if ( $wgMiserMode ) {
+               $s = "=== " . wfMsg( "perfdisabled" ) . " ===\n" ;
+               $s .= $log->getContent() ;
+               $wgOut->addWikiText ( $s ) ;
+               return;
+       }
+
+       if ( ! $limit ) {
+               $limit = $wgUser->getOption( "rclimit" );
+               if ( ! $limit ) { $limit = 50; }
+       }
+       if ( ! $offset ) { $offset = 0; }
+
+       $cache = "" ; # To be saved, eventually
+
+       $sql = "SELECT bl_to, COUNT( DISTINCT bl_from ) as nlinks " .
+         "FROM brokenlinks GROUP BY bl_to HAVING nlinks > 1 " .
+         "ORDER BY nlinks DESC LIMIT {$offset}, {$limit}";
+       $res = wfQuery( $sql, $fname );
+
+       $sk = $wgUser->getSkin();
+
+       $top = wfShowingResults( $offset, $limit );
+       $wgOut->addHTML( "<p>{$top}\n" );
+
+       $sl = wfViewPrevNext( $offset, $limit,
+         $wgLang->specialpage( "Wantedpages" ) );
+       $wgOut->addHTML( "<br>{$sl}\n" );
+
+       $s = "<ol start=" . ( $offset + 1 ) . ">";
+       while ( $obj = wfFetchObject( $res ) ) {
+               $nt = Title::newFromDBkey( $obj->bl_to );
+
+               $plink = $sk->makeBrokenLink( $nt->getPrefixedText(), "" );
+               $nl = str_replace( "$1", $obj->nlinks, wfMsg( "nlinks" ) );
+               $nlink = $sk->makeKnownLink( $wgLang->specialPage(
+                 "Whatlinkshere" ), $nl, "target=" . $nt->getPrefixedURL() );
+
+               $cache .= "* [[".$nt->getPrefixedText()."]] ({$nl})\n" ;
+
+               $s .= "<li>{$plink} ({$nlink})</li>\n";
+       }
+       wfFreeResult( $res );
+       $s .= "</ol>";
+       $wgOut->addHTML( $s );
+       $wgOut->addHTML( "<p>{$sl}\n" );
+
+       # Saving cache
+       if ( $offset > 0 OR $limit < 50 ) return ; #Not suitable
+       $log->mContent = $cache ;
+       $log->mContentLoaded = true ;
+       $log->saveContent() ;
+}
+
+?>
diff --git a/includes/SpecialWatchlist.php b/includes/SpecialWatchlist.php
new file mode 100644 (file)
index 0000000..e9df9ef
--- /dev/null
@@ -0,0 +1,90 @@
+<?
+global $IP;
+include_once( "$IP/SpecialRecentchanges.php" );
+
+function wfSpecialWatchlist()
+{
+       global $wgUser, $wgOut, $wgLang, $wgTitle;
+       global $days, $limit, $target; # From query string
+       $fname = "wfSpecialWatchlist";
+
+       $wgOut->setPagetitle( wfMsg( "watchlist" ) );
+       $sub = str_replace( "$1", $wgUser->getName(), wfMsg( "watchlistsub" ) );
+       $wgOut->setSubtitle( $sub );
+       $wgOut->setRobotpolicy( "index,follow" );
+
+       if ( ! isset( $days ) ) {
+               $days = $wgUser->getOption( "rcdays" );
+               if ( ! $days ) { $days = 3; }
+       }
+       if ( ! isset( $limit ) ) {
+               $limit = $wgUser->getOption( "rclimit" );
+               if ( ! $limit ) { $limit = 100; }
+       }
+       if ( $days == 0 ) {
+               $docutoff = '';
+       } else {
+               $docutoff = "cur_timestamp > '" .
+                 date( "YmdHis", time() - ( $days * 86400 ) )
+                 . "' AND";
+       }
+       if ( $limit == 0 ) {
+               $dolimit = "";
+       } else {
+               $dolimit = "LIMIT $limit";
+       }
+       
+       $uid = $wgUser->getID();
+       if( $uid == 0 ) {
+               $wgOut->addHTML( wfMsg( "nowatchlist" ) );
+               return;
+       }
+
+#      $sql = "SELECT DISTINCT
+#  cur_id,cur_namespace,cur_title,cur_comment,
+#  cur_user,cur_user_text,cur_timestamp,cur_minor_edit,cur_is_new
+#  FROM cur,watchlist
+#  WHERE wl_user={$uid} AND wl_namespace=cur_namespace & (~1) AND wl_title=cur_title
+#  ORDER BY cur_timestamp DESC {$dolimit}";
+       $sql = "SELECT DISTINCT
+  cur_id,cur_namespace,cur_title,cur_comment,
+  cur_user,cur_user_text,cur_timestamp,cur_minor_edit,cur_is_new
+  FROM cur,watchlist
+  WHERE wl_user={$uid} AND wl_title=cur_title
+        AND (cur_namespace=wl_namespace OR cur_namespace=wl_namespace+1)
+  ORDER BY inverse_timestamp {$dolimit}";
+       $res = wfQuery( $sql, $fname );
+       if ( wfNumRows( $res ) == 0 ) {
+               $wgOut->addHTML( wfMsg( "nowatchlist" ) );
+               return;
+       }
+
+       $note = str_replace( "$1", $limit, wfMsg( "rcnote" ) );
+       $note = str_replace( "$2", $days, $note );
+       $wgOut->addHTML( "\n<hr>\n{$note}\n<br>" );
+       $note = rcDayLimitlinks( $days, $limit, "Watchlist", "", true );
+       $wgOut->addHTML( "{$note}\n" );
+
+       $sk = $wgUser->getSkin();
+       $s = $sk->beginRecentChangesList();
+
+       while ( $obj = wfFetchObject( $res ) ) {
+               $ts = $obj->cur_timestamp;
+               $u = $obj->cur_user;
+               $ut = $obj->cur_user_text;
+               $ns = $obj->cur_namespace;
+               $ttl = $obj->cur_title;
+               $com = $obj->cur_comment;
+               $me = ( $obj->cur_minor_edit > 0 );
+               $new = ( $obj->cur_is_new  > 0 );
+               $watched = true;
+
+               $s .= $sk->recentChangesLine( $ts, $u, $ut, $ns, $ttl, $com, $me, $new, $watched );
+       }
+       $s .= $sk->endRecentChangesList();
+
+       wfFreeResult( $res );
+       $wgOut->addHTML( $s );
+}
+
+?>
diff --git a/includes/SpecialWhatlinkshere.php b/includes/SpecialWhatlinkshere.php
new file mode 100644 (file)
index 0000000..f9d2a26
--- /dev/null
@@ -0,0 +1,101 @@
+<?
+
+function wfSpecialWhatlinkshere()
+{
+       global $wgUser, $wgOut, $target;
+       $fname = "wfSpecialWhatlinkshere";
+
+       if ( "" == $target ) {
+               $wgOut->errorpage( "notargettitle", "notargettext" );
+               return;
+       }
+       $nt = Title::newFromURL( wfCleanQueryVar( $target ) );
+       $wgOut->setPagetitle( $nt->getPrefixedText() );
+       $wgOut->setSubtitle( wfMsg( "linklistsub" ) );
+
+       $id = $nt->getArticleID();
+       $sk = $wgUser->getSkin();
+       $isredir = " (" . wfMsg( "isredirect" ) . ")\n";
+
+       if ( 0 == $id ) {
+               $sql = "SELECT DISTINCT bl_from FROM brokenlinks WHERE bl_to='" .
+                 wfStrencode( $nt->getPrefixedDBkey() ) . "' LIMIT 500";
+               $res = wfQuery( $sql, $fname );
+
+               if ( 0 == wfNumRows( $res ) ) {
+                       $wgOut->addHTML( wfMsg( "nolinkshere" ) );
+               } else {
+                       $wgOut->addHTML( wfMsg( "linkshere" ) );
+                       $wgOut->addHTML( "\n<ul>" );
+
+                       while ( $row = wfFetchObject( $res ) ) {
+                               $lid = $row->bl_from;
+                               $sql = "SELECT cur_namespace,cur_title,cur_is_redirect " .
+                                 "FROM cur WHERE cur_id={$lid}";
+                               $res2 = wfQuery( $sql, $fname );
+                               $s = wfFetchObject( $res2 );
+
+                               $n = Title::makeName( $s->cur_namespace, $s->cur_title );
+                               $link = $sk->makeKnownLink( $n, "", "redirect=no" );
+                               $wgOut->addHTML( "<li>{$link}" );
+
+                               if ( 1 == $s->cur_is_redirect ) {
+                                       $wgOut->addHTML( $isredir );
+                                       wfShowIndirectLinks( 1, $lid );
+                               }
+                               $wgOut->addHTML( "</li>\n" );
+                       }
+                       $wgOut->addHTML( "</ul>\n" );
+                       wfFreeResult( $res );
+               }
+       } else {
+               wfShowIndirectLinks( 0, $id );
+       }
+}
+
+function wfShowIndirectLinks( $level, $lid )
+{
+       global $wgOut, $wgUser;
+       $fname = "wfShowIndirectLinks";
+
+       $sql = "SELECT DISTINCT l_from FROM links WHERE l_to={$lid} LIMIT 500";
+       $res = wfQuery( $sql, $fname );
+
+       if ( 0 == wfNumRows( $res ) ) {
+               if ( 0 == $level ) {
+                       $wgOut->addHTML( wfMsg( "nolinkshere" ) );
+               }
+               return;
+       }
+       if ( 0 == $level ) {
+               $wgOut->addHTML( wfMsg( "linkshere" ) );
+       }
+       $sk = $wgUser->getSkin();
+       $isredir = " (" . wfMsg( "isredirect" ) . ")\n";
+
+       $wgOut->addHTML( "<ul>" );
+       while ( $row = wfFetchObject( $res ) ) {
+               $nt = Title::newFromDBkey( $row->l_from );
+               $ns = $nt->getNamespace();
+               $t = wfStrencode( $nt->getDBkey() );
+
+               $link = $sk->makeKnownLink( $row->l_from, "", "redirect=no" );
+               $wgOut->addHTML( "<li>{$link}" );
+
+               $sql = "SELECT cur_id,cur_is_redirect FROM cur " .
+                 "WHERE cur_namespace={$ns} AND cur_title='{$t}'";
+               $res2 = wfQuery( $sql, $fname );
+               $s = wfFetchObject( $res2 );
+
+               if ( 1 == $s->cur_is_redirect ) {
+                       $wgOut->addHTML( $isredir );
+                       if ( $level < 2 ) {
+                               wfShowIndirectLinks( $level + 1, $s->cur_id );
+                       }
+               }
+               $wgOut->addHTML( "</il>\n" );
+       }
+       $wgOut->addHTML( "</ul>\n" );
+}
+
+?>
diff --git a/includes/Title.php b/includes/Title.php
new file mode 100644 (file)
index 0000000..9c0f6d2
--- /dev/null
@@ -0,0 +1,370 @@
+<?
+# See title.doc
+global $IP;
+include_once( "$IP/Interwiki.php" );
+
+class Title {
+       /* private */ var $mTextform, $mUrlform, $mDbkeyform;
+       /* private */ var $mNamespace, $mInterwiki, $mFragment;
+       /* private */ var $mArticleID, $mRestrictions, $mRestrictionsLoaded;
+
+       /* private */ function Title()
+       {
+               $this->mInterwiki = $this->mUrlform =
+               $this->mTextform = $this->mDbkeyform = "";
+               $this->mArticleID = -1;
+               $this->mNamespace = 0;
+               $this->mRestrictionsLoaded = false;
+               $this->mRestrictions = array();
+       }
+
+       # Static factory methods
+       #
+       function newFromDBkey( $key )
+       {
+               $t = new Title();
+               $t->mDbkeyform = $key;
+               $t->secureAndSplit();
+               return $t;
+       }
+
+       function newFromText( $text )
+       {
+               # Note - mixing latin1 named entities and unicode numbered
+               # ones will result in a bad link.
+               $trans = get_html_translation_table( HTML_ENTITIES );
+               $trans = array_flip( $trans );
+               $text = strtr( $text, $trans );
+               
+               $text = wfMungeToUtf8( $text );
+               
+               $text = urldecode( $text );
+
+               $t = new Title();
+               $t->mDbkeyform = str_replace( " ", "_", $text );
+               $t->secureAndSplit();
+               return $t;
+       }
+
+       function newFromURL( $url )
+       {
+               global $wgLang, $wgServer, $HTTP_SERVER_VARS;
+               
+               $t = new Title();
+               $s = urldecode( $url ); # This is technically wrong, as anything
+                                                               # we've gotten is already decoded by PHP.
+                                                               # Kept for backwards compatibility with
+                                                               # buggy URLs we had for a while...
+               
+               # For links that came from outside, check for alternate/legacy
+               # character encoding.
+               if( strncmp($wgServer, $HTTP_SERVER_VARS["HTTP_REFERER"], strlen( $wgServer ) ) )
+                       $s = $wgLang->checkTitleEncoding( $s );
+               
+               $t->mDbkeyform = str_replace( " ", "_", $s );
+               $t->secureAndSplit();
+               return $t;
+       }
+
+       function legalChars()
+       {
+               return "-,.()' &;%!?_0-9A-Za-z\\/:\\x80-\\xFF";
+       }
+
+       function getInterwikiLink( $key )
+       {
+               global $wgValidInterwikis;
+
+               if ( array_key_exists( $key, $wgValidInterwikis ) ) {
+                       return $wgValidInterwikis[$key];
+               } else return "";
+       }
+
+       function getText() { return $this->mTextform; }
+       function getURL() { return $this->mUrlform; }
+       function getDBkey() { return $this->mDbkeyform; }
+       function getNamespace() { return $this->mNamespace; }
+       function setNamespace( $n ) { $this->mNamespace = $n; }
+       function getInterwiki() { return $this->mInterwiki; }
+       function getFragment() { return $this->mFragment; }
+
+       /* static */ function indexTitle( $ns, $title )
+       {
+               global $wgDBminWordLen, $wgLang;
+
+               $lc = SearchEngine::legalSearchChars() . "&#;";
+               $t = $wgLang->stripForSearch( $title );
+               $t = preg_replace( "/[^{$lc}]+/", " ", $t );
+               $t = strtolower( $t );
+
+               # Handle 's, s'
+               $t = preg_replace( "/([{$lc}]+)'s( |$)/", "\\1 \\1's ", $t );
+               $t = preg_replace( "/([{$lc}]+)s'( |$)/", "\\1s ", $t );
+
+               $t = preg_replace( "/\\s+/", " ", $t );
+
+               if ( $ns == Namespace::getImage() ) {
+                       $t = preg_replace( "/ (png|gif|jpg|jpeg|ogg)$/", "", $t );
+               }
+               return trim( $t );
+       }
+
+       function getIndexTitle()
+       {
+               return Title::indexTitle( $this->mNamespace, $this->mTextform );
+       }
+
+       /* static */ function makeName( $ns, $title )
+       {
+               global $wgLang;
+
+               $n = $wgLang->getNsText( $ns );
+               if ( "" == $n ) { return $title; }
+               else { return "{$n}:{$title}"; }
+       }
+
+       function getPrefixedDBkey()
+       {
+               $s = $this->prefix( $this->mDbkeyform );
+               $s = str_replace( " ", "_", $s );
+               return $s;
+       }
+
+       function getPrefixedText()
+       {
+               $s = $this->prefix( $this->mTextform );
+               $s = str_replace( "_", " ", $s );
+               return $s;
+       }
+
+       function getPrefixedURL()
+       {
+               $s = $this->prefix( $this->mDbkeyform );
+               $s = str_replace( " ", "_", $s );
+
+               $s = urlencode ( $s ) ;
+               # Cleaning up URL to make it look nice -- is this safe?
+               $s = preg_replace( "/%3[Aa]/", ":", $s );
+               $s = preg_replace( "/%2[Ff]/", "/", $s );
+               $s = str_replace( "%28", "(", $s );
+               $s = str_replace( "%29", ")", $s );
+               return $s;
+       }
+
+       function getFullURL()
+       {
+               global $wgLang, $wgArticlePath, $wgValidInterwikis;
+
+               if ( "" == $this->mInterwiki ) {
+                       $p = $wgArticlePath;
+               } else {
+                       $p = $wgValidInterwikis[$this->mInterwiki];
+               }
+               $n = $wgLang->getNsText( $this->mNamespace );
+               if ( "" != $n ) { $n .= ":"; }
+               $u = str_replace( "$1", $n . $this->mUrlform, $p );
+               if ( "" != $this->mFragment ) {
+                       $u .= "#" . $this->mFragment;
+               }
+               return $u;
+       }
+
+       function getEditURL()
+       {
+               global $wgServer, $wgScript;
+
+               if ( "" != $this->mInterwiki ) { return ""; }
+               $s = wfLocalUrl( $this->getPrefixedURL(), "action=edit" );
+
+               return $s;
+       }
+
+       function isExternal() { return ( "" != $this->mInterwiki ); }
+
+       function isProtected()
+       {
+               if ( -1 == $this->mNamespace ) { return true; }
+               $a = $this->getRestrictions();
+               if ( in_array( "sysop", $a ) ) { return true; }
+               return false;
+       }
+
+       function isLog()
+       {
+               if ( $this->mNamespace != Namespace::getWikipedia() ) {
+                       return false;
+               }
+               if ( ( 0 == strcmp( wfMsg( "uploadlogpage" ), $this->mDbkeyform ) ) ||
+                 ( 0 == strcmp( wfMsg( "dellogpage" ), $this->mDbkeyform ) ) ) {
+                       return true;
+               }
+               return false;
+       }
+
+       function userIsWatching()
+       {
+               global $wgUser;
+
+               if ( -1 == $this->mNamespace ) { return false; }
+               if ( 0 == $wgUser->getID() ) { return false; }
+
+               return $wgUser->isWatched( $this );
+       }
+
+       function userCanEdit()
+       {
+               global $wgUser;
+
+               if ( -1 == $this->mNamespace ) { return false; }
+               # if ( 0 == $this->getArticleID() ) { return false; }
+               if ( $this->mDbkeyform == "_" ) { return false; }
+
+               $ur = $wgUser->getRights();
+               foreach ( $this->getRestrictions() as $r ) {
+                       if ( "" != $r && ( ! in_array( $r, $ur ) ) ) {
+                               return false;
+                       }
+               }
+               return true;
+       }
+
+       function getRestrictions()
+       {
+               $id = $this->getArticleID();
+               if ( 0 == $id ) { return array(); }
+
+               if ( ! $this->mRestrictionsLoaded ) {
+                       $res = wfGetSQL( "cur", "cur_restrictions", "cur_id=$id" );
+                       $this->mRestrictions = explode( ",", trim( $res ) );
+                       $this->mRestrictionsLoaded = true;
+               }
+               return $this->mRestrictions;
+       }
+
+       function getArticleID()
+       {
+               global $wgLinkCache;
+
+               if ( -1 != $this->mArticleID ) { return $this->mArticleID; }
+               $this->mArticleID = $wgLinkCache->addLink(
+                 $this->getPrefixedDBkey() );
+               return $this->mArticleID;
+       }
+
+       function resetArticleID( $newid )
+       {
+               global $wgLinkCache;
+               $wgLinkCache->clearBadLink( $this->getPrefixedDBkey() );
+
+               if ( 0 == $newid ) { $this->mArticleID = -1; }
+               else { $this->mArticleID = $newid; }
+               $this->mRestrictionsLoaded = false;
+               $this->mRestrictions = array();
+       }
+
+       /* private */ function prefix( $name )
+       {
+               global $wgLang;
+
+               $p = "";
+               if ( "" != $this->mInterwiki ) {
+                       $p = $this->mInterwiki . ":";
+               }
+               if ( 0 != $this->mNamespace ) {
+                       $p .= $wgLang->getNsText( $this->mNamespace ) . ":";
+               }
+               return $p . $name;
+       }
+
+       # Assumes that mDbkeyform has been set, and is urldecoded
+    # and uses undersocres, but not otherwise munged.  This function
+    # removes illegal characters, splits off the winterwiki and
+    # namespace prefixes, sets the other forms, and canonicalizes
+    # everything.  This one function is really at the core of
+       # Wiki--don't mess with it unless you're really sure you know
+       # what you're doing.
+       #
+       /* private */ function secureAndSplit()
+       {
+               global $wgLang, $wgValidInterwikis, $wgLocalInterwiki;
+
+               $validNamespaces = $wgLang->getNamespaces();
+               unset( $validNamespaces[0] );
+
+               $this->mInterwiki = $this->mFragment = "";
+               $this->mNamespace = 0;
+
+               $t = preg_replace( "/[\\s_]+/", "_", $this->mDbkeyform );
+               if ( "_" == $t{0} ) { $t = substr( $t, 1 ); }
+               $l = strlen( $t );
+               if ( $l && ( "_" == $t{$l-1} ) ) { $t = substr( $t, 0, $l-1 ); }
+               if ( "" == $t ) { $t = "_"; }
+
+               $this->mDbkeyform = $t;
+               $done = false;
+
+               $imgpre = ":" . $wgLang->getNsText( Namespace::getImage() ) . ":";
+               if ( 0 == strncasecmp( $imgpre, $t, strlen( $imgpre ) ) ) {
+                       $t = substr( $t, 1 );
+               }
+               if ( ":" == $t{0} ) {
+                       $r = substr( $t, 1 );
+               } else {
+                       if ( preg_match( "/^([A-Za-z0-9_\\x80-\\xff]+):(.*)$/", $t, $m ) ) {
+                               #$p = strtolower( $m[1] );
+                               $p = $m[1];
+                               if ( array_key_exists( $p, $wgValidInterwikis ) ) {
+                                       $t = $m[2];
+                                       $this->mInterwiki = $p;
+
+                                       if ( preg_match( "/^([A-Za-z0-9_\\x80-\\xff]+):(.*)$/",
+                                         $t, $m ) ) {
+                                               $p = strtolower( $m[1] );
+                                       } else {
+                                               $done = true;
+                                       }
+                                       if($this->mInterwiki != $wgLocalInterwiki)
+                                               $done = true;
+                               }
+                               if ( ! $done ) {
+                                       if ( $ns = $wgLang->getNsIndex( str_replace( " ", "_", $p ))) {
+                                               $t = $m[2];
+                                               $this->mNamespace = $ns;
+                                       }
+                               #       foreach ( $validNamespaces as $ns ) {
+                               #               if ( 0 == strcasecmp( $p, $ns ) ) {
+                               #                       $t = $m[2];
+                               #                       $this->mNamespace = $wgLang->getNsIndex(
+                               #                         str_replace( " ", "_", $p ) );
+                               #                       break;
+                               #               }
+                               #       }
+                               }
+                       }
+                       $r = $t;
+               }
+               if ( 0 == strcmp( $this->mInterwiki, $wgLocalInterwiki ) ) {
+                       $this->mInterwiki = "";
+               }
+               # We already know that some pages won't be in the database!
+               #
+               if ( "" != $this->mInterwiki || -1 == $this->mNamespace ) {
+                       $this->mArticleID = 0;
+               }
+               $f = strstr( $r, "#" );
+               if ( false !== $f ) {
+                       $this->mFragment = substr( $f, 1 );
+                       $r = substr( $r, 0, strlen( $r ) - strlen( $f ) );
+               }
+               # Strip illegal characters.
+               #
+               $tc = Title::legalChars();
+               $t = preg_replace( "/[^{$tc}]/", "", $r );
+
+               if( $this->mInterwiki == "") $t = $wgLang->ucfirst( $t );
+               $this->mDbkeyform = $t;
+               $this->mUrlform = wfUrlencode( $t );
+               $this->mTextform = str_replace( "_", " ", $t );
+       }
+}
+?>
diff --git a/includes/UpdateClasses.php b/includes/UpdateClasses.php
new file mode 100644 (file)
index 0000000..ed80289
--- /dev/null
@@ -0,0 +1,11 @@
+<?
+# See deferred.doc
+global $IP;
+include_once( "$IP/UserUpdate.php" );
+include_once( "$IP/ViewCountUpdate.php" );
+include_once( "$IP/SiteStatsUpdate.php" );
+include_once( "$IP/LinksUpdate.php" );
+include_once( "$IP/SearchUpdate.php" );
+include_once( "$IP/UserTalkUpdate.php" );
+
+?>
diff --git a/includes/User.php b/includes/User.php
new file mode 100644 (file)
index 0000000..127fe34
--- /dev/null
@@ -0,0 +1,530 @@
+<?
+# See user.doc
+
+class User {
+       /* private */ var $mId, $mName, $mPassword, $mEmail, $mNewtalk;
+       /* private */ var $mRights, $mOptions;
+       /* private */ var $mDataLoaded, $mNewpassword;
+       /* private */ var $mSkin;
+       /* private */ var $mBlockedby, $mBlockreason;
+       /* private */ var $mTouched;
+
+       function User()
+       {
+               $this->loadDefaults();
+       }
+
+       # Static factory method
+       #
+       function newFromName( $name )
+       {
+               $u = new User();
+
+               # Clean up name according to title rules
+
+               $t = Title::newFromText( $name );
+               $u->setName( $t->getText() );
+               return $u;
+       }
+
+       /* static */ function whoIs( $id )
+       {
+               return wfGetSQL( "user", "user_name", "user_id=$id" );
+       }
+
+       /* static */ function idFromName( $name )
+       {
+               $nt = Title::newFromText( $name );
+               $sql = "SELECT user_id FROM user WHERE user_name='" .
+                 wfStrencode( $nt->getText() ) . "'";
+               $res = wfQuery( $sql, "User::idFromName" );
+
+               if ( 0 == wfNumRows( $res ) ) { return 0; }
+               else {
+                       $s = wfFetchObject( $res );
+                       return $s->user_id;
+               }
+       }
+       
+       # does the string match an anonymous user IP address?
+       /* static */ function isIP( $name ) {
+               return preg_match("/^\d{1,3}\.\d{1,3}.\d{1,3}\.\d{1,3}$/",$name);
+       
+       }
+       
+       
+
+       /* static */ function randomPassword()
+       {
+               $pwchars = "ABCDEFGHJKLMNPQRSTUVWXYZabcdefghjkmnpqrstuvwxyz";
+               $l = strlen( $pwchars ) - 1;
+
+               wfSeedRandom();
+               $np = $pwchars{mt_rand( 0, $l )} . $pwchars{mt_rand( 0, $l )} .
+                 $pwchars{mt_rand( 0, $l )} . chr( mt_rand(48, 57) ) .
+                 $pwchars{mt_rand( 0, $l )} . $pwchars{mt_rand( 0, $l )} .
+                 $pwchars{mt_rand( 0, $l )};
+               return $np;
+       }
+
+       function loadDefaults()
+       {
+               global $wgLang ;
+
+               $this->mId = $this->mNewtalk = 0;
+               $this->mName = getenv( "REMOTE_ADDR" );
+               $this->mEmail = "";
+               $this->mPassword = $this->mNewpassword = "";
+               $this->mRights = array();
+               $defOpt = $wgLang->getDefaultUserOptions() ;
+               foreach ( $defOpt as $oname => $val ) {
+                       $this->mOptions[$oname] = $val;
+               }
+               unset( $this->mSkin );
+               $this->mDataLoaded = false;
+               $this->mBlockedby = -1; # Unset
+               $this->mTouched = '0'; # Allow any pages to be cached
+       }
+
+       /* private */ function getBlockedStatus()
+       {
+               if ( -1 != $this->mBlockedby ) { return; }
+
+               $remaddr = getenv( "REMOTE_ADDR" );
+               if ( 0 == $this->mId ) {
+                       $sql = "SELECT ipb_by,ipb_reason FROM ipblocks WHERE " .
+                         "ipb_address='$remaddr'";
+               } else {
+                       $sql = "SELECT ipb_by,ipb_reason FROM ipblocks WHERE " .
+                         "(ipb_address='$remaddr' OR ipb_user={$this->mId})";
+               }
+               $res = wfQuery( $sql, "User::getBlockedStatus" );
+               if ( 0 == wfNumRows( $res ) ) {
+                       $this->mBlockedby = 0;
+                       return;
+               }
+               $s = wfFetchObject( $res );
+               $this->mBlockedby = $s->ipb_by;
+               $this->mBlockreason = $s->ipb_reason;
+       }
+
+       function isBlocked()
+       {
+               $this->getBlockedStatus();
+               if ( 0 == $this->mBlockedby ) { return false; }
+               return true;
+       }
+
+       function blockedBy() {
+               $this->getBlockedStatus();
+               return $this->mBlockedby;
+       }
+
+       function blockedFor() {
+               $this->getBlockedStatus();
+               return $this->mBlockreason;
+       }
+
+       function loadFromSession()
+       {
+               global $HTTP_COOKIE_VARS, $wsUserID, $wsUserName, $wsUserPassword;
+
+               if ( isset( $wsUserID ) ) {
+                       if ( 0 != $wsUserID ) {
+                               $sId = $wsUserID;
+                       } else {
+                               $this->mId = 0;
+                               return;
+                       }
+               } else if ( isset( $HTTP_COOKIE_VARS["wcUserID"] ) ) {
+                       $sId = $HTTP_COOKIE_VARS["wcUserID"];
+                       $wsUserID = $sId;
+               } else {
+                       $this->mId = 0;
+                       return;
+               }
+               if ( isset( $wsUserName ) ) {
+                       $sName = $wsUserName;
+               } else if ( isset( $HTTP_COOKIE_VARS["wcUserName"] ) ) {
+                       $sName = $HTTP_COOKIE_VARS["wcUserName"];
+                       $wsUserName = $sName;
+               } else {
+                       $this->mId = 0;
+                       return;
+               }
+               if ( isset( $wsUserPassword ) ) {
+                       $sPass = $wsUserPassword;
+               } else if ( isset( $HTTP_COOKIE_VARS["wcUserPassword"] ) ) {
+                       $sPass = $HTTP_COOKIE_VARS["wcUserPassword"];
+                       $wsUserPassword = $sPass;
+               } else {
+                       $this->mId = 0;
+                       return;
+               }
+               $this->mId = $sId;
+               $this->loadFromDatabase();
+
+               if ( ( $sName == $this->mName ) &&
+                 ( ( $sPass == $this->mPassword ) ||
+                 ( $sPass == $this->mNewpassword ) ) ) {
+                       return;
+               }
+               $this->loadDefaults(); # Can't log in from session
+       }
+
+       function loadFromDatabase()
+       {
+               if ( $this->mDataLoaded ) { return; }           
+               # check in separate table if there are changes to the talk page
+               $this->mNewtalk=0; # reset talk page status
+               if($this->mId) {                
+                       $sql = "SELECT 1 FROM user_newtalk WHERE user_id={$this->mId}";                                                                 
+                       $res = wfQuery ($sql,  "User::loadFromDatabase" );
+
+                       if (wfNumRows($res)>0) {                                
+                               $this->mNewtalk= 1;
+                       }
+                       wfFreeResult( $res );
+               } else {
+                       $sql = "SELECT 1 FROM user_newtalk WHERE user_ip='{$this->mName}'";                     
+                       $res = wfQuery ($sql,  "User::loadFromDatabase" );
+                       
+                       if (wfNumRows($res)>0) {                                
+                               $this->mNewtalk= 1;
+                       }
+                       wfFreeResult( $res );
+               }
+               if(!$this->mId) {
+                       $this->mDataLoaded = true;
+                       return;
+               } # the following stuff is for non-anonymous users only
+               
+               $sql = "SELECT user_name,user_password,user_newpassword,user_email," .
+                 "user_options,user_rights,user_touched FROM user WHERE user_id=" .
+                 "{$this->mId}";
+               $res = wfQuery( $sql, "User::loadFromDatabase" );
+
+               if ( wfNumRows( $res ) > 0 ) {
+                       $s = wfFetchObject( $res );
+                       $this->mName = $s->user_name;
+                       $this->mEmail = $s->user_email;
+                       $this->mPassword = $s->user_password;
+                       $this->mNewpassword = $s->user_newpassword;
+                       $this->decodeOptions( $s->user_options );
+                       $this->mRights = explode( ",", strtolower( $s->user_rights ) );
+                       $this->mTouched = $s->user_touched;
+               }                               
+               
+               wfFreeResult( $res );
+               $this->mDataLoaded = true;
+       }
+
+       function getID() { return $this->mId; }
+       function setID( $v ) {
+               $this->mId = $v;
+               $this->mDataLoaded = false;
+       }
+
+       function getName() {
+               $this->loadFromDatabase();
+               return $this->mName;
+       }
+
+       function setName( $str )
+       {
+               $this->loadFromDatabase();
+               $this->mName = $str;
+       }
+
+       function getNewtalk()
+       {
+               $this->loadFromDatabase();
+               return ( 0 != $this->mNewtalk );
+       }
+
+       function setNewtalk( $val )
+       {
+               $this->loadFromDatabase();
+               $this->mNewtalk = $val;
+               $this->invalidateCache();
+       }
+       
+       function invalidateCache() {
+               $this->loadFromDatabase();
+               $this->mTouched = wfTimestampNow();
+               # Don't forget to save the options after this or
+               # it won't take effect!
+       }
+       
+       function validateCache( $timestamp ) {
+               $this->loadFromDatabase();
+               return ($timestamp >= $this->mTouched);
+       }
+       
+       function getPassword()
+       {
+               $this->loadFromDatabase();
+               return $this->mPassword;
+       }
+
+       function getNewpassword()
+       {
+               $this->loadFromDatabase();
+               return $this->mNewpassword;
+       }
+
+       /* static */ function encryptPassword( $p )
+       {
+               $np = md5( $p );
+               return $np;
+       }
+
+       function setPassword( $str )
+       {
+               $this->loadFromDatabase();
+               $this->mPassword = User::encryptPassword( $str );
+               $this->mNewpassword = "";
+       }
+
+       function setNewpassword( $str )
+       {
+               $this->loadFromDatabase();
+               $this->mNewpassword = User::encryptPassword( $str );
+       }
+
+       function getEmail()
+       {
+               $this->loadFromDatabase();
+               return $this->mEmail;
+       }
+
+       function setEmail( $str )
+       {
+               $this->loadFromDatabase();
+               $this->mEmail = $str;
+       }
+
+       function getOption( $oname )
+       {
+               $this->loadFromDatabase();
+               if ( array_key_exists( $oname, $this->mOptions ) ) {
+                       return $this->mOptions[$oname];
+               } else {
+                       return "";
+               }
+       }
+
+       function setOption( $oname, $val )
+       {
+               $this->loadFromDatabase();
+               $this->mOptions[$oname] = $val;
+               $this->invalidateCache();
+       }
+
+       function getRights()
+       {
+               $this->loadFromDatabase();
+               return $this->mRights;
+       }
+
+       function isSysop()
+       {
+               $this->loadFromDatabase();
+               if ( 0 == $this->mId ) { return false; }
+
+               return in_array( "sysop", $this->mRights );
+       }
+
+       function isDeveloper()
+       {
+               $this->loadFromDatabase();
+               if ( 0 == $this->mId ) { return false; }
+
+               return in_array( "developer", $this->mRights );
+       }
+       
+       function isBot()
+       {
+               $this->loadFromDatabase();
+               if ( 0 == $this->mId ) { return false; }
+               
+               return in_array( "bot", $this->mRights );
+       }
+               
+       function &getSkin()
+       {
+               if ( ! isset( $this->mSkin ) ) {
+                       $skinNames = Skin::getSkinNames();
+                       $s = $this->getOption( "skin" );
+                       if ( "" == $s ) { $s = 0; }
+
+                       if ( $s >= count( $skinNames ) ) { $sn = "SkinStandard"; }
+                       else $sn = "Skin" . $skinNames[$s];
+                       $this->mSkin = new $sn;
+               }
+               return $this->mSkin;
+       }
+
+       function isWatched( $title )
+       {
+               # Note - $title should be a Title _object_
+               # Pages and their talk pages are considered equivalent for watching;
+               # remember that talk namespaces are numbered as page namespace+1.
+               if( $this->mId ) {
+                       $sql = "SELECT 1 FROM watchlist
+                         WHERE wl_user={$this->mId} AND
+                         wl_namespace = " . ($title->getNamespace() & ~1) . " AND
+                         wl_title='" . wfStrencode( $title->getDBkey() ) . "'";
+                       $res = wfQuery( $sql );
+                       return (wfNumRows( $res ) > 0);
+               } else {
+                       return false;
+               }
+       }
+
+       function addWatch( $title )
+       {
+               if( $this->mId ) {
+                       # REPLACE instead of INSERT because occasionally someone
+                       # accidentally reloads a watch-add operation.
+                       $sql = "REPLACE INTO watchlist (wl_user, wl_namespace,wl_title)
+                         VALUES ({$this->mId}," . (($title->getNamespace() | 1) - 1) .
+                         ",'" . wfStrencode( $title->getDBkey() ) . "')";
+                       wfQuery( $sql );
+                       $this->invalidateCache();
+               }
+       }
+
+       function removeWatch( $title )
+       {
+               if( $this->mId ) {
+                       $sql = "DELETE FROM watchlist WHERE wl_user={$this->mId} AND
+                         wl_namespace=" . (($title->getNamespace() | 1) - 1) .
+                         " AND wl_title='" . wfStrencode( $title->getDBkey() ) . "'";
+                       wfQuery( $sql );
+            $this->invalidateCache();
+               }
+       }
+
+
+       /* private */ function encodeOptions()
+       {
+               $a = array();
+               foreach ( $this->mOptions as $oname => $oval ) {
+                       array_push( $a, "{$oname}={$oval}" );
+               }
+               $s = implode( "\n", $a );
+               return wfStrencode( $s );
+       }
+
+       /* private */ function decodeOptions( $str )
+       {
+               $a = explode( "\n", $str );
+               foreach ( $a as $s ) {
+                       if ( preg_match( "/^(.[^=]*)=(.*)$/", $s, $m ) ) {
+                               $this->mOptions[$m[1]] = $m[2];
+                       }
+               }
+       }
+
+       function setCookies()
+       {
+               global $wsUserID, $wsUserName, $wsUserPassword;
+               global $wgCookieExpiration;
+               if ( 0 == $this->mId ) return;
+               $this->loadFromDatabase();
+               $exp = time() + $wgCookieExpiration;
+
+               $wsUserID = $this->mId;
+               setcookie( "wcUserID", $this->mId, $exp, "/" );
+
+               $wsUserName = $this->mName;
+               setcookie( "wcUserName", $this->mName, $exp, "/" );
+
+               $wsUserPassword = $this->mPassword;
+               if ( 1 == $this->getOption( "rememberpassword" ) ) {
+                       setcookie( "wcUserPassword", $this->mPassword, $exp, "/" );
+               } else {
+                       setcookie( "wcUserPassword", "", time() - 3600 );
+               }
+       }
+
+       function logout()
+       {
+               global $wsUserID;
+               $this->mId = 0;
+
+               $wsUserID = 0;
+
+               setcookie( "wcUserID", "", time() - 3600 );
+               setcookie( "wcUserPassword", "", time() - 3600 );
+       }
+
+       function saveSettings()
+       {
+               global $wgUser;
+       
+               if(!$this->mNewtalk) {
+               
+                       if($this->mId) {
+                               $sql="DELETE FROM user_newtalk WHERE user_id={$this->mId}";
+                               wfQuery ($sql,"User::saveSettings");
+                       } else {
+                       
+                               
+                               $sql="DELETE FROM user_newtalk WHERE user_ip='{$this->mName}'";
+                               wfQuery ($sql,"User::saveSettings");
+                               
+                       }
+               }
+
+               if ( 0 == $this->mId ) { return; }                                      
+
+               $sql = "UPDATE user SET " .
+                 "user_name= '" . wfStrencode( $this->mName ) . "', " .
+                 "user_password= '" . wfStrencode( $this->mPassword ) . "', " .
+                 "user_newpassword= '" . wfStrencode( $this->mNewpassword ) . "', " .
+                 "user_email= '" . wfStrencode( $this->mEmail ) . "', " .
+                 "user_options= '" . $this->encodeOptions() . "', " .
+                 "user_rights= '" . wfStrencode( implode( ",", $this->mRights ) ) . "', " .
+                 "user_touched= '" . wfStrencode( $this->mTouched ) .
+                 "' WHERE user_id={$this->mId}";
+               wfQuery( $sql, "User::saveSettings" );
+       }
+
+       # Checks if a user with the given name exists
+       #
+       function idForName()
+       {
+               $gotid = 0;
+               $s = trim( $this->mName );
+               if ( 0 == strcmp( "", $s ) ) return 0;
+
+               $sql = "SELECT user_id FROM user WHERE user_name='" .
+                 wfStrencode( $s ) . "'";
+               $res = wfQuery( $sql, "User::idForName" );
+               if ( 0 == wfNumRows( $res ) ) { return 0; }
+
+               $s = wfFetchObject( $res );
+               if ( "" == $s ) return 0;
+
+               $gotid = $s->user_id;
+               wfFreeResult( $res );
+               return $gotid;
+       }
+
+       function addToDatabase()
+       {
+               $sql = "INSERT INTO user (user_name,user_password,user_newpassword," .
+                 "user_email, user_rights, user_options) " .
+                 " VALUES ('" . wfStrencode( $this->mName ) . "', '" .
+                 wfStrencode( $this->mPassword ) . "', '" .
+                 wfStrencode( $this->mNewpassword ) . "', '" .
+                 wfStrencode( $this->mEmail ) . "', '" .
+                 wfStrencode( implode( ",", $this->mRights ) ) . "', '" .
+                 $this->encodeOptions() . "')";
+               wfQuery( $sql, "User::addToDatabase" );
+               $this->mId = $this->idForName();
+       }
+}
+?>
diff --git a/includes/UserTalkUpdate.php b/includes/UserTalkUpdate.php
new file mode 100644 (file)
index 0000000..011a7ba
--- /dev/null
@@ -0,0 +1,63 @@
+<?
+# See deferred.doc
+
+class UserTalkUpdate {
+
+       /* private */ var $mAction, $mNamespace, $mTitle;
+
+       function UserTalkUpdate( $action, $ns, $title )
+       {
+               $this->mAction = $action;
+               $this->mNamespace = $ns;
+               $this->mTitle = str_replace( "_", " ", $title );
+       }
+
+       function doUpdate()
+       {
+       
+               global $wgUser, $wgLang;
+               $fname = "UserTalkUpdate::doUpdate";
+
+               # If namespace isn't User_talk:, do nothing.
+
+               if ( $this->mNamespace != Namespace::getTalk(
+                 Namespace::getUser() ) ) {
+                       return;
+               }
+               # If the user talk page is our own, clear the flag
+               # whether we are reading it or writing it.
+               if ( 0 == strcmp( $this->mTitle, $wgUser->getName() ) ) {
+                       
+                       $wgUser->setNewtalk( 0 );                       
+                       $wgUser->saveSettings();
+
+               } else {
+                       # Not ours.  If writing, mark it as modified.
+
+                       if ( 1 == $this->mAction ) {
+                               $user = new User();                             
+                               $user->setID(User::idFromName($this->mTitle));
+                               if ($id=$user->getID()) {                                                                       
+                                       $sql = "INSERT INTO user_newtalk (user_id) values ({$id})";
+                                       
+                               } else { #anon
+                                       
+                                       if(preg_match("/^\d{1,3}\.\d{1,3}.\d{1,3}\.\d{1,3}$/",$this->mTitle)) { #real anon (user:xxx.xxx.xxx.xxx)
+                                       
+                                               $sql = "INSERT INTO user_newtalk (user_id,user_ip) values (0,\"{$this->mTitle}\")";             
+                                               
+                                       }                                       
+                               
+                               }
+                               
+                               if($sql && !$user->getNewtalk()) { # only insert if real user and it's not already there
+                                       wfQuery( $sql, $fname );
+                               }
+                       }
+               }
+               
+       
+       }
+}
+
+?>
diff --git a/includes/UserUpdate.php b/includes/UserUpdate.php
new file mode 100644 (file)
index 0000000..1d28cf3
--- /dev/null
@@ -0,0 +1,15 @@
+<?
+# See deferred.doc
+
+class UserUpdate {
+
+       function UserUpdate() { }
+
+       function doUpdate()
+       {
+               global $wgUser;
+               $wgUser->saveSettings();
+       }
+}
+
+?>
diff --git a/includes/Utf8Case.php b/includes/Utf8Case.php
new file mode 100644 (file)
index 0000000..1f0208e
--- /dev/null
@@ -0,0 +1,1520 @@
+<?
+$wgInputEncoding    = "utf-8";
+$wgOutputEncoding      = "utf-8";
+
+# Simple 1:1 upper/lowercase switching arrays for utf-8 text
+# Won't get context-sensitive things yet
+
+# Hack for bugs in ucfirst() and company
+
+$wikiUpperChars = array(
+       "a" => "A",
+       "b" => "B",
+       "c" => "C",
+       "d" => "D",
+       "e" => "E",
+       "f" => "F",
+       "g" => "G",
+       "h" => "H",
+       "i" => "I",
+       "j" => "J",
+       "k" => "K",
+       "l" => "L",
+       "m" => "M",
+       "n" => "N",
+       "o" => "O",
+       "p" => "P",
+       "q" => "Q",
+       "r" => "R",
+       "s" => "S",
+       "t" => "T",
+       "u" => "U",
+       "v" => "V",
+       "w" => "W",
+       "x" => "X",
+       "y" => "Y",
+       "z" => "Z",
+       "\xc2\xb5" => "\xce\x9c",
+       "\xc3\xa0" => "\xc3\x80",
+       "\xc3\xa1" => "\xc3\x81",
+       "\xc3\xa2" => "\xc3\x82",
+       "\xc3\xa3" => "\xc3\x83",
+       "\xc3\xa4" => "\xc3\x84",
+       "\xc3\xa5" => "\xc3\x85",
+       "\xc3\xa6" => "\xc3\x86",
+       "\xc3\xa7" => "\xc3\x87",
+       "\xc3\xa8" => "\xc3\x88",
+       "\xc3\xa9" => "\xc3\x89",
+       "\xc3\xaa" => "\xc3\x8a",
+       "\xc3\xab" => "\xc3\x8b",
+       "\xc3\xac" => "\xc3\x8c",
+       "\xc3\xad" => "\xc3\x8d",
+       "\xc3\xae" => "\xc3\x8e",
+       "\xc3\xaf" => "\xc3\x8f",
+       "\xc3\xb0" => "\xc3\x90",
+       "\xc3\xb1" => "\xc3\x91",
+       "\xc3\xb2" => "\xc3\x92",
+       "\xc3\xb3" => "\xc3\x93",
+       "\xc3\xb4" => "\xc3\x94",
+       "\xc3\xb5" => "\xc3\x95",
+       "\xc3\xb6" => "\xc3\x96",
+       "\xc3\xb8" => "\xc3\x98",
+       "\xc3\xb9" => "\xc3\x99",
+       "\xc3\xba" => "\xc3\x9a",
+       "\xc3\xbb" => "\xc3\x9b",
+       "\xc3\xbc" => "\xc3\x9c",
+       "\xc3\xbd" => "\xc3\x9d",
+       "\xc3\xbe" => "\xc3\x9e",
+       "\xc3\xbf" => "\xc5\xb8",
+       "\xc4\x81" => "\xc4\x80",
+       "\xc4\x83" => "\xc4\x82",
+       "\xc4\x85" => "\xc4\x84",
+       "\xc4\x87" => "\xc4\x86",
+       "\xc4\x89" => "\xc4\x88",
+       "\xc4\x8b" => "\xc4\x8a",
+       "\xc4\x8d" => "\xc4\x8c",
+       "\xc4\x8f" => "\xc4\x8e",
+       "\xc4\x91" => "\xc4\x90",
+       "\xc4\x93" => "\xc4\x92",
+       "\xc4\x95" => "\xc4\x94",
+       "\xc4\x97" => "\xc4\x96",
+       "\xc4\x99" => "\xc4\x98",
+       "\xc4\x9b" => "\xc4\x9a",
+       "\xc4\x9d" => "\xc4\x9c",
+       "\xc4\x9f" => "\xc4\x9e",
+       "\xc4\xa1" => "\xc4\xa0",
+       "\xc4\xa3" => "\xc4\xa2",
+       "\xc4\xa5" => "\xc4\xa4",
+       "\xc4\xa7" => "\xc4\xa6",
+       "\xc4\xa9" => "\xc4\xa8",
+       "\xc4\xab" => "\xc4\xaa",
+       "\xc4\xad" => "\xc4\xac",
+       "\xc4\xaf" => "\xc4\xae",
+       "\xc4\xb1" => "I",
+       "\xc4\xb3" => "\xc4\xb2",
+       "\xc4\xb5" => "\xc4\xb4",
+       "\xc4\xb7" => "\xc4\xb6",
+       "\xc4\xba" => "\xc4\xb9",
+       "\xc4\xbc" => "\xc4\xbb",
+       "\xc4\xbe" => "\xc4\xbd",
+       "\xc5\x80" => "\xc4\xbf",
+       "\xc5\x82" => "\xc5\x81",
+       "\xc5\x84" => "\xc5\x83",
+       "\xc5\x86" => "\xc5\x85",
+       "\xc5\x88" => "\xc5\x87",
+       "\xc5\x8b" => "\xc5\x8a",
+       "\xc5\x8d" => "\xc5\x8c",
+       "\xc5\x8f" => "\xc5\x8e",
+       "\xc5\x91" => "\xc5\x90",
+       "\xc5\x93" => "\xc5\x92",
+       "\xc5\x95" => "\xc5\x94",
+       "\xc5\x97" => "\xc5\x96",
+       "\xc5\x99" => "\xc5\x98",
+       "\xc5\x9b" => "\xc5\x9a",
+       "\xc5\x9d" => "\xc5\x9c",
+       "\xc5\x9f" => "\xc5\x9e",
+       "\xc5\xa1" => "\xc5\xa0",
+       "\xc5\xa3" => "\xc5\xa2",
+       "\xc5\xa5" => "\xc5\xa4",
+       "\xc5\xa7" => "\xc5\xa6",
+       "\xc5\xa9" => "\xc5\xa8",
+       "\xc5\xab" => "\xc5\xaa",
+       "\xc5\xad" => "\xc5\xac",
+       "\xc5\xaf" => "\xc5\xae",
+       "\xc5\xb1" => "\xc5\xb0",
+       "\xc5\xb3" => "\xc5\xb2",
+       "\xc5\xb5" => "\xc5\xb4",
+       "\xc5\xb7" => "\xc5\xb6",
+       "\xc5\xba" => "\xc5\xb9",
+       "\xc5\xbc" => "\xc5\xbb",
+       "\xc5\xbe" => "\xc5\xbd",
+       "\xc5\xbf" => "S",
+       "\xc6\x83" => "\xc6\x82",
+       "\xc6\x85" => "\xc6\x84",
+       "\xc6\x88" => "\xc6\x87",
+       "\xc6\x8c" => "\xc6\x8b",
+       "\xc6\x92" => "\xc6\x91",
+       "\xc6\x95" => "\xc7\xb6",
+       "\xc6\x99" => "\xc6\x98",
+       "\xc6\xa1" => "\xc6\xa0",
+       "\xc6\xa3" => "\xc6\xa2",
+       "\xc6\xa5" => "\xc6\xa4",
+       "\xc6\xa8" => "\xc6\xa7",
+       "\xc6\xad" => "\xc6\xac",
+       "\xc6\xb0" => "\xc6\xaf",
+       "\xc6\xb4" => "\xc6\xb3",
+       "\xc6\xb6" => "\xc6\xb5",
+       "\xc6\xb9" => "\xc6\xb8",
+       "\xc6\xbd" => "\xc6\xbc",
+       "\xc6\xbf" => "\xc7\xb7",
+       "\xc7\x85" => "\xc7\x84",
+       "\xc7\x86" => "\xc7\x84",
+       "\xc7\x88" => "\xc7\x87",
+       "\xc7\x89" => "\xc7\x87",
+       "\xc7\x8b" => "\xc7\x8a",
+       "\xc7\x8c" => "\xc7\x8a",
+       "\xc7\x8e" => "\xc7\x8d",
+       "\xc7\x90" => "\xc7\x8f",
+       "\xc7\x92" => "\xc7\x91",
+       "\xc7\x94" => "\xc7\x93",
+       "\xc7\x96" => "\xc7\x95",
+       "\xc7\x98" => "\xc7\x97",
+       "\xc7\x9a" => "\xc7\x99",
+       "\xc7\x9c" => "\xc7\x9b",
+       "\xc7\x9d" => "\xc6\x8e",
+       "\xc7\x9f" => "\xc7\x9e",
+       "\xc7\xa1" => "\xc7\xa0",
+       "\xc7\xa3" => "\xc7\xa2",
+       "\xc7\xa5" => "\xc7\xa4",
+       "\xc7\xa7" => "\xc7\xa6",
+       "\xc7\xa9" => "\xc7\xa8",
+       "\xc7\xab" => "\xc7\xaa",
+       "\xc7\xad" => "\xc7\xac",
+       "\xc7\xaf" => "\xc7\xae",
+       "\xc7\xb2" => "\xc7\xb1",
+       "\xc7\xb3" => "\xc7\xb1",
+       "\xc7\xb5" => "\xc7\xb4",
+       "\xc7\xb9" => "\xc7\xb8",
+       "\xc7\xbb" => "\xc7\xba",
+       "\xc7\xbd" => "\xc7\xbc",
+       "\xc7\xbf" => "\xc7\xbe",
+       "\xc8\x81" => "\xc8\x80",
+       "\xc8\x83" => "\xc8\x82",
+       "\xc8\x85" => "\xc8\x84",
+       "\xc8\x87" => "\xc8\x86",
+       "\xc8\x89" => "\xc8\x88",
+       "\xc8\x8b" => "\xc8\x8a",
+       "\xc8\x8d" => "\xc8\x8c",
+       "\xc8\x8f" => "\xc8\x8e",
+       "\xc8\x91" => "\xc8\x90",
+       "\xc8\x93" => "\xc8\x92",
+       "\xc8\x95" => "\xc8\x94",
+       "\xc8\x97" => "\xc8\x96",
+       "\xc8\x99" => "\xc8\x98",
+       "\xc8\x9b" => "\xc8\x9a",
+       "\xc8\x9d" => "\xc8\x9c",
+       "\xc8\x9f" => "\xc8\x9e",
+       "\xc8\xa3" => "\xc8\xa2",
+       "\xc8\xa5" => "\xc8\xa4",
+       "\xc8\xa7" => "\xc8\xa6",
+       "\xc8\xa9" => "\xc8\xa8",
+       "\xc8\xab" => "\xc8\xaa",
+       "\xc8\xad" => "\xc8\xac",
+       "\xc8\xaf" => "\xc8\xae",
+       "\xc8\xb1" => "\xc8\xb0",
+       "\xc8\xb3" => "\xc8\xb2",
+       "\xc9\x93" => "\xc6\x81",
+       "\xc9\x94" => "\xc6\x86",
+       "\xc9\x96" => "\xc6\x89",
+       "\xc9\x97" => "\xc6\x8a",
+       "\xc9\x99" => "\xc6\x8f",
+       "\xc9\x9b" => "\xc6\x90",
+       "\xc9\xa0" => "\xc6\x93",
+       "\xc9\xa3" => "\xc6\x94",
+       "\xc9\xa8" => "\xc6\x97",
+       "\xc9\xa9" => "\xc6\x96",
+       "\xc9\xaf" => "\xc6\x9c",
+       "\xc9\xb2" => "\xc6\x9d",
+       "\xc9\xb5" => "\xc6\x9f",
+       "\xca\x80" => "\xc6\xa6",
+       "\xca\x83" => "\xc6\xa9",
+       "\xca\x88" => "\xc6\xae",
+       "\xca\x8a" => "\xc6\xb1",
+       "\xca\x8b" => "\xc6\xb2",
+       "\xca\x92" => "\xc6\xb7",
+       "\xcd\x85" => "\xce\x99",
+       "\xce\xac" => "\xce\x86",
+       "\xce\xad" => "\xce\x88",
+       "\xce\xae" => "\xce\x89",
+       "\xce\xaf" => "\xce\x8a",
+       "\xce\xb1" => "\xce\x91",
+       "\xce\xb2" => "\xce\x92",
+       "\xce\xb3" => "\xce\x93",
+       "\xce\xb4" => "\xce\x94",
+       "\xce\xb5" => "\xce\x95",
+       "\xce\xb6" => "\xce\x96",
+       "\xce\xb7" => "\xce\x97",
+       "\xce\xb8" => "\xce\x98",
+       "\xce\xb9" => "\xce\x99",
+       "\xce\xba" => "\xce\x9a",
+       "\xce\xbb" => "\xce\x9b",
+       "\xce\xbc" => "\xce\x9c",
+       "\xce\xbd" => "\xce\x9d",
+       "\xce\xbe" => "\xce\x9e",
+       "\xce\xbf" => "\xce\x9f",
+       "\xcf\x80" => "\xce\xa0",
+       "\xcf\x81" => "\xce\xa1",
+       "\xcf\x82" => "\xce\xa3",
+       "\xcf\x83" => "\xce\xa3",
+       "\xcf\x84" => "\xce\xa4",
+       "\xcf\x85" => "\xce\xa5",
+       "\xcf\x86" => "\xce\xa6",
+       "\xcf\x87" => "\xce\xa7",
+       "\xcf\x88" => "\xce\xa8",
+       "\xcf\x89" => "\xce\xa9",
+       "\xcf\x8a" => "\xce\xaa",
+       "\xcf\x8b" => "\xce\xab",
+       "\xcf\x8c" => "\xce\x8c",
+       "\xcf\x8d" => "\xce\x8e",
+       "\xcf\x8e" => "\xce\x8f",
+       "\xcf\x90" => "\xce\x92",
+       "\xcf\x91" => "\xce\x98",
+       "\xcf\x95" => "\xce\xa6",
+       "\xcf\x96" => "\xce\xa0",
+       "\xcf\x9b" => "\xcf\x9a",
+       "\xcf\x9d" => "\xcf\x9c",
+       "\xcf\x9f" => "\xcf\x9e",
+       "\xcf\xa1" => "\xcf\xa0",
+       "\xcf\xa3" => "\xcf\xa2",
+       "\xcf\xa5" => "\xcf\xa4",
+       "\xcf\xa7" => "\xcf\xa6",
+       "\xcf\xa9" => "\xcf\xa8",
+       "\xcf\xab" => "\xcf\xaa",
+       "\xcf\xad" => "\xcf\xac",
+       "\xcf\xaf" => "\xcf\xae",
+       "\xcf\xb0" => "\xce\x9a",
+       "\xcf\xb1" => "\xce\xa1",
+       "\xcf\xb2" => "\xce\xa3",
+       "\xcf\xb5" => "\xce\x95",
+       "\xd0\xb0" => "\xd0\x90",
+       "\xd0\xb1" => "\xd0\x91",
+       "\xd0\xb2" => "\xd0\x92",
+       "\xd0\xb3" => "\xd0\x93",
+       "\xd0\xb4" => "\xd0\x94",
+       "\xd0\xb5" => "\xd0\x95",
+       "\xd0\xb6" => "\xd0\x96",
+       "\xd0\xb7" => "\xd0\x97",
+       "\xd0\xb8" => "\xd0\x98",
+       "\xd0\xb9" => "\xd0\x99",
+       "\xd0\xba" => "\xd0\x9a",
+       "\xd0\xbb" => "\xd0\x9b",
+       "\xd0\xbc" => "\xd0\x9c",
+       "\xd0\xbd" => "\xd0\x9d",
+       "\xd0\xbe" => "\xd0\x9e",
+       "\xd0\xbf" => "\xd0\x9f",
+       "\xd1\x80" => "\xd0\xa0",
+       "\xd1\x81" => "\xd0\xa1",
+       "\xd1\x82" => "\xd0\xa2",
+       "\xd1\x83" => "\xd0\xa3",
+       "\xd1\x84" => "\xd0\xa4",
+       "\xd1\x85" => "\xd0\xa5",
+       "\xd1\x86" => "\xd0\xa6",
+       "\xd1\x87" => "\xd0\xa7",
+       "\xd1\x88" => "\xd0\xa8",
+       "\xd1\x89" => "\xd0\xa9",
+       "\xd1\x8a" => "\xd0\xaa",
+       "\xd1\x8b" => "\xd0\xab",
+       "\xd1\x8c" => "\xd0\xac",
+       "\xd1\x8d" => "\xd0\xad",
+       "\xd1\x8e" => "\xd0\xae",
+       "\xd1\x8f" => "\xd0\xaf",
+       "\xd1\x90" => "\xd0\x80",
+       "\xd1\x91" => "\xd0\x81",
+       "\xd1\x92" => "\xd0\x82",
+       "\xd1\x93" => "\xd0\x83",
+       "\xd1\x94" => "\xd0\x84",
+       "\xd1\x95" => "\xd0\x85",
+       "\xd1\x96" => "\xd0\x86",
+       "\xd1\x97" => "\xd0\x87",
+       "\xd1\x98" => "\xd0\x88",
+       "\xd1\x99" => "\xd0\x89",
+       "\xd1\x9a" => "\xd0\x8a",
+       "\xd1\x9b" => "\xd0\x8b",
+       "\xd1\x9c" => "\xd0\x8c",
+       "\xd1\x9d" => "\xd0\x8d",
+       "\xd1\x9e" => "\xd0\x8e",
+       "\xd1\x9f" => "\xd0\x8f",
+       "\xd1\xa1" => "\xd1\xa0",
+       "\xd1\xa3" => "\xd1\xa2",
+       "\xd1\xa5" => "\xd1\xa4",
+       "\xd1\xa7" => "\xd1\xa6",
+       "\xd1\xa9" => "\xd1\xa8",
+       "\xd1\xab" => "\xd1\xaa",
+       "\xd1\xad" => "\xd1\xac",
+       "\xd1\xaf" => "\xd1\xae",
+       "\xd1\xb1" => "\xd1\xb0",
+       "\xd1\xb3" => "\xd1\xb2",
+       "\xd1\xb5" => "\xd1\xb4",
+       "\xd1\xb7" => "\xd1\xb6",
+       "\xd1\xb9" => "\xd1\xb8",
+       "\xd1\xbb" => "\xd1\xba",
+       "\xd1\xbd" => "\xd1\xbc",
+       "\xd1\xbf" => "\xd1\xbe",
+       "\xd2\x81" => "\xd2\x80",
+       "\xd2\x8d" => "\xd2\x8c",
+       "\xd2\x8f" => "\xd2\x8e",
+       "\xd2\x91" => "\xd2\x90",
+       "\xd2\x93" => "\xd2\x92",
+       "\xd2\x95" => "\xd2\x94",
+       "\xd2\x97" => "\xd2\x96",
+       "\xd2\x99" => "\xd2\x98",
+       "\xd2\x9b" => "\xd2\x9a",
+       "\xd2\x9d" => "\xd2\x9c",
+       "\xd2\x9f" => "\xd2\x9e",
+       "\xd2\xa1" => "\xd2\xa0",
+       "\xd2\xa3" => "\xd2\xa2",
+       "\xd2\xa5" => "\xd2\xa4",
+       "\xd2\xa7" => "\xd2\xa6",
+       "\xd2\xa9" => "\xd2\xa8",
+       "\xd2\xab" => "\xd2\xaa",
+       "\xd2\xad" => "\xd2\xac",
+       "\xd2\xaf" => "\xd2\xae",
+       "\xd2\xb1" => "\xd2\xb0",
+       "\xd2\xb3" => "\xd2\xb2",
+       "\xd2\xb5" => "\xd2\xb4",
+       "\xd2\xb7" => "\xd2\xb6",
+       "\xd2\xb9" => "\xd2\xb8",
+       "\xd2\xbb" => "\xd2\xba",
+       "\xd2\xbd" => "\xd2\xbc",
+       "\xd2\xbf" => "\xd2\xbe",
+       "\xd3\x82" => "\xd3\x81",
+       "\xd3\x84" => "\xd3\x83",
+       "\xd3\x88" => "\xd3\x87",
+       "\xd3\x8c" => "\xd3\x8b",
+       "\xd3\x91" => "\xd3\x90",
+       "\xd3\x93" => "\xd3\x92",
+       "\xd3\x95" => "\xd3\x94",
+       "\xd3\x97" => "\xd3\x96",
+       "\xd3\x99" => "\xd3\x98",
+       "\xd3\x9b" => "\xd3\x9a",
+       "\xd3\x9d" => "\xd3\x9c",
+       "\xd3\x9f" => "\xd3\x9e",
+       "\xd3\xa1" => "\xd3\xa0",
+       "\xd3\xa3" => "\xd3\xa2",
+       "\xd3\xa5" => "\xd3\xa4",
+       "\xd3\xa7" => "\xd3\xa6",
+       "\xd3\xa9" => "\xd3\xa8",
+       "\xd3\xab" => "\xd3\xaa",
+       "\xd3\xad" => "\xd3\xac",
+       "\xd3\xaf" => "\xd3\xae",
+       "\xd3\xb1" => "\xd3\xb0",
+       "\xd3\xb3" => "\xd3\xb2",
+       "\xd3\xb5" => "\xd3\xb4",
+       "\xd3\xb9" => "\xd3\xb8",
+       "\xd5\xa1" => "\xd4\xb1",
+       "\xd5\xa2" => "\xd4\xb2",
+       "\xd5\xa3" => "\xd4\xb3",
+       "\xd5\xa4" => "\xd4\xb4",
+       "\xd5\xa5" => "\xd4\xb5",
+       "\xd5\xa6" => "\xd4\xb6",
+       "\xd5\xa7" => "\xd4\xb7",
+       "\xd5\xa8" => "\xd4\xb8",
+       "\xd5\xa9" => "\xd4\xb9",
+       "\xd5\xaa" => "\xd4\xba",
+       "\xd5\xab" => "\xd4\xbb",
+       "\xd5\xac" => "\xd4\xbc",
+       "\xd5\xad" => "\xd4\xbd",
+       "\xd5\xae" => "\xd4\xbe",
+       "\xd5\xaf" => "\xd4\xbf",
+       "\xd5\xb0" => "\xd5\x80",
+       "\xd5\xb1" => "\xd5\x81",
+       "\xd5\xb2" => "\xd5\x82",
+       "\xd5\xb3" => "\xd5\x83",
+       "\xd5\xb4" => "\xd5\x84",
+       "\xd5\xb5" => "\xd5\x85",
+       "\xd5\xb6" => "\xd5\x86",
+       "\xd5\xb7" => "\xd5\x87",
+       "\xd5\xb8" => "\xd5\x88",
+       "\xd5\xb9" => "\xd5\x89",
+       "\xd5\xba" => "\xd5\x8a",
+       "\xd5\xbb" => "\xd5\x8b",
+       "\xd5\xbc" => "\xd5\x8c",
+       "\xd5\xbd" => "\xd5\x8d",
+       "\xd5\xbe" => "\xd5\x8e",
+       "\xd5\xbf" => "\xd5\x8f",
+       "\xd6\x80" => "\xd5\x90",
+       "\xd6\x81" => "\xd5\x91",
+       "\xd6\x82" => "\xd5\x92",
+       "\xd6\x83" => "\xd5\x93",
+       "\xd6\x84" => "\xd5\x94",
+       "\xd6\x85" => "\xd5\x95",
+       "\xd6\x86" => "\xd5\x96",
+       "\xe1\xb8\x81" => "\xe1\xb8\x80",
+       "\xe1\xb8\x83" => "\xe1\xb8\x82",
+       "\xe1\xb8\x85" => "\xe1\xb8\x84",
+       "\xe1\xb8\x87" => "\xe1\xb8\x86",
+       "\xe1\xb8\x89" => "\xe1\xb8\x88",
+       "\xe1\xb8\x8b" => "\xe1\xb8\x8a",
+       "\xe1\xb8\x8d" => "\xe1\xb8\x8c",
+       "\xe1\xb8\x8f" => "\xe1\xb8\x8e",
+       "\xe1\xb8\x91" => "\xe1\xb8\x90",
+       "\xe1\xb8\x93" => "\xe1\xb8\x92",
+       "\xe1\xb8\x95" => "\xe1\xb8\x94",
+       "\xe1\xb8\x97" => "\xe1\xb8\x96",
+       "\xe1\xb8\x99" => "\xe1\xb8\x98",
+       "\xe1\xb8\x9b" => "\xe1\xb8\x9a",
+       "\xe1\xb8\x9d" => "\xe1\xb8\x9c",
+       "\xe1\xb8\x9f" => "\xe1\xb8\x9e",
+       "\xe1\xb8\xa1" => "\xe1\xb8\xa0",
+       "\xe1\xb8\xa3" => "\xe1\xb8\xa2",
+       "\xe1\xb8\xa5" => "\xe1\xb8\xa4",
+       "\xe1\xb8\xa7" => "\xe1\xb8\xa6",
+       "\xe1\xb8\xa9" => "\xe1\xb8\xa8",
+       "\xe1\xb8\xab" => "\xe1\xb8\xaa",
+       "\xe1\xb8\xad" => "\xe1\xb8\xac",
+       "\xe1\xb8\xaf" => "\xe1\xb8\xae",
+       "\xe1\xb8\xb1" => "\xe1\xb8\xb0",
+       "\xe1\xb8\xb3" => "\xe1\xb8\xb2",
+       "\xe1\xb8\xb5" => "\xe1\xb8\xb4",
+       "\xe1\xb8\xb7" => "\xe1\xb8\xb6",
+       "\xe1\xb8\xb9" => "\xe1\xb8\xb8",
+       "\xe1\xb8\xbb" => "\xe1\xb8\xba",
+       "\xe1\xb8\xbd" => "\xe1\xb8\xbc",
+       "\xe1\xb8\xbf" => "\xe1\xb8\xbe",
+       "\xe1\xb9\x81" => "\xe1\xb9\x80",
+       "\xe1\xb9\x83" => "\xe1\xb9\x82",
+       "\xe1\xb9\x85" => "\xe1\xb9\x84",
+       "\xe1\xb9\x87" => "\xe1\xb9\x86",
+       "\xe1\xb9\x89" => "\xe1\xb9\x88",
+       "\xe1\xb9\x8b" => "\xe1\xb9\x8a",
+       "\xe1\xb9\x8d" => "\xe1\xb9\x8c",
+       "\xe1\xb9\x8f" => "\xe1\xb9\x8e",
+       "\xe1\xb9\x91" => "\xe1\xb9\x90",
+       "\xe1\xb9\x93" => "\xe1\xb9\x92",
+       "\xe1\xb9\x95" => "\xe1\xb9\x94",
+       "\xe1\xb9\x97" => "\xe1\xb9\x96",
+       "\xe1\xb9\x99" => "\xe1\xb9\x98",
+       "\xe1\xb9\x9b" => "\xe1\xb9\x9a",
+       "\xe1\xb9\x9d" => "\xe1\xb9\x9c",
+       "\xe1\xb9\x9f" => "\xe1\xb9\x9e",
+       "\xe1\xb9\xa1" => "\xe1\xb9\xa0",
+       "\xe1\xb9\xa3" => "\xe1\xb9\xa2",
+       "\xe1\xb9\xa5" => "\xe1\xb9\xa4",
+       "\xe1\xb9\xa7" => "\xe1\xb9\xa6",
+       "\xe1\xb9\xa9" => "\xe1\xb9\xa8",
+       "\xe1\xb9\xab" => "\xe1\xb9\xaa",
+       "\xe1\xb9\xad" => "\xe1\xb9\xac",
+       "\xe1\xb9\xaf" => "\xe1\xb9\xae",
+       "\xe1\xb9\xb1" => "\xe1\xb9\xb0",
+       "\xe1\xb9\xb3" => "\xe1\xb9\xb2",
+       "\xe1\xb9\xb5" => "\xe1\xb9\xb4",
+       "\xe1\xb9\xb7" => "\xe1\xb9\xb6",
+       "\xe1\xb9\xb9" => "\xe1\xb9\xb8",
+       "\xe1\xb9\xbb" => "\xe1\xb9\xba",
+       "\xe1\xb9\xbd" => "\xe1\xb9\xbc",
+       "\xe1\xb9\xbf" => "\xe1\xb9\xbe",
+       "\xe1\xba\x81" => "\xe1\xba\x80",
+       "\xe1\xba\x83" => "\xe1\xba\x82",
+       "\xe1\xba\x85" => "\xe1\xba\x84",
+       "\xe1\xba\x87" => "\xe1\xba\x86",
+       "\xe1\xba\x89" => "\xe1\xba\x88",
+       "\xe1\xba\x8b" => "\xe1\xba\x8a",
+       "\xe1\xba\x8d" => "\xe1\xba\x8c",
+       "\xe1\xba\x8f" => "\xe1\xba\x8e",
+       "\xe1\xba\x91" => "\xe1\xba\x90",
+       "\xe1\xba\x93" => "\xe1\xba\x92",
+       "\xe1\xba\x95" => "\xe1\xba\x94",
+       "\xe1\xba\x9b" => "\xe1\xb9\xa0",
+       "\xe1\xba\xa1" => "\xe1\xba\xa0",
+       "\xe1\xba\xa3" => "\xe1\xba\xa2",
+       "\xe1\xba\xa5" => "\xe1\xba\xa4",
+       "\xe1\xba\xa7" => "\xe1\xba\xa6",
+       "\xe1\xba\xa9" => "\xe1\xba\xa8",
+       "\xe1\xba\xab" => "\xe1\xba\xaa",
+       "\xe1\xba\xad" => "\xe1\xba\xac",
+       "\xe1\xba\xaf" => "\xe1\xba\xae",
+       "\xe1\xba\xb1" => "\xe1\xba\xb0",
+       "\xe1\xba\xb3" => "\xe1\xba\xb2",
+       "\xe1\xba\xb5" => "\xe1\xba\xb4",
+       "\xe1\xba\xb7" => "\xe1\xba\xb6",
+       "\xe1\xba\xb9" => "\xe1\xba\xb8",
+       "\xe1\xba\xbb" => "\xe1\xba\xba",
+       "\xe1\xba\xbd" => "\xe1\xba\xbc",
+       "\xe1\xba\xbf" => "\xe1\xba\xbe",
+       "\xe1\xbb\x81" => "\xe1\xbb\x80",
+       "\xe1\xbb\x83" => "\xe1\xbb\x82",
+       "\xe1\xbb\x85" => "\xe1\xbb\x84",
+       "\xe1\xbb\x87" => "\xe1\xbb\x86",
+       "\xe1\xbb\x89" => "\xe1\xbb\x88",
+       "\xe1\xbb\x8b" => "\xe1\xbb\x8a",
+       "\xe1\xbb\x8d" => "\xe1\xbb\x8c",
+       "\xe1\xbb\x8f" => "\xe1\xbb\x8e",
+       "\xe1\xbb\x91" => "\xe1\xbb\x90",
+       "\xe1\xbb\x93" => "\xe1\xbb\x92",
+       "\xe1\xbb\x95" => "\xe1\xbb\x94",
+       "\xe1\xbb\x97" => "\xe1\xbb\x96",
+       "\xe1\xbb\x99" => "\xe1\xbb\x98",
+       "\xe1\xbb\x9b" => "\xe1\xbb\x9a",
+       "\xe1\xbb\x9d" => "\xe1\xbb\x9c",
+       "\xe1\xbb\x9f" => "\xe1\xbb\x9e",
+       "\xe1\xbb\xa1" => "\xe1\xbb\xa0",
+       "\xe1\xbb\xa3" => "\xe1\xbb\xa2",
+       "\xe1\xbb\xa5" => "\xe1\xbb\xa4",
+       "\xe1\xbb\xa7" => "\xe1\xbb\xa6",
+       "\xe1\xbb\xa9" => "\xe1\xbb\xa8",
+       "\xe1\xbb\xab" => "\xe1\xbb\xaa",
+       "\xe1\xbb\xad" => "\xe1\xbb\xac",
+       "\xe1\xbb\xaf" => "\xe1\xbb\xae",
+       "\xe1\xbb\xb1" => "\xe1\xbb\xb0",
+       "\xe1\xbb\xb3" => "\xe1\xbb\xb2",
+       "\xe1\xbb\xb5" => "\xe1\xbb\xb4",
+       "\xe1\xbb\xb7" => "\xe1\xbb\xb6",
+       "\xe1\xbb\xb9" => "\xe1\xbb\xb8",
+       "\xe1\xbc\x80" => "\xe1\xbc\x88",
+       "\xe1\xbc\x81" => "\xe1\xbc\x89",
+       "\xe1\xbc\x82" => "\xe1\xbc\x8a",
+       "\xe1\xbc\x83" => "\xe1\xbc\x8b",
+       "\xe1\xbc\x84" => "\xe1\xbc\x8c",
+       "\xe1\xbc\x85" => "\xe1\xbc\x8d",
+       "\xe1\xbc\x86" => "\xe1\xbc\x8e",
+       "\xe1\xbc\x87" => "\xe1\xbc\x8f",
+       "\xe1\xbc\x90" => "\xe1\xbc\x98",
+       "\xe1\xbc\x91" => "\xe1\xbc\x99",
+       "\xe1\xbc\x92" => "\xe1\xbc\x9a",
+       "\xe1\xbc\x93" => "\xe1\xbc\x9b",
+       "\xe1\xbc\x94" => "\xe1\xbc\x9c",
+       "\xe1\xbc\x95" => "\xe1\xbc\x9d",
+       "\xe1\xbc\xa0" => "\xe1\xbc\xa8",
+       "\xe1\xbc\xa1" => "\xe1\xbc\xa9",
+       "\xe1\xbc\xa2" => "\xe1\xbc\xaa",
+       "\xe1\xbc\xa3" => "\xe1\xbc\xab",
+       "\xe1\xbc\xa4" => "\xe1\xbc\xac",
+       "\xe1\xbc\xa5" => "\xe1\xbc\xad",
+       "\xe1\xbc\xa6" => "\xe1\xbc\xae",
+       "\xe1\xbc\xa7" => "\xe1\xbc\xaf",
+       "\xe1\xbc\xb0" => "\xe1\xbc\xb8",
+       "\xe1\xbc\xb1" => "\xe1\xbc\xb9",
+       "\xe1\xbc\xb2" => "\xe1\xbc\xba",
+       "\xe1\xbc\xb3" => "\xe1\xbc\xbb",
+       "\xe1\xbc\xb4" => "\xe1\xbc\xbc",
+       "\xe1\xbc\xb5" => "\xe1\xbc\xbd",
+       "\xe1\xbc\xb6" => "\xe1\xbc\xbe",
+       "\xe1\xbc\xb7" => "\xe1\xbc\xbf",
+       "\xe1\xbd\x80" => "\xe1\xbd\x88",
+       "\xe1\xbd\x81" => "\xe1\xbd\x89",
+       "\xe1\xbd\x82" => "\xe1\xbd\x8a",
+       "\xe1\xbd\x83" => "\xe1\xbd\x8b",
+       "\xe1\xbd\x84" => "\xe1\xbd\x8c",
+       "\xe1\xbd\x85" => "\xe1\xbd\x8d",
+       "\xe1\xbd\x91" => "\xe1\xbd\x99",
+       "\xe1\xbd\x93" => "\xe1\xbd\x9b",
+       "\xe1\xbd\x95" => "\xe1\xbd\x9d",
+       "\xe1\xbd\x97" => "\xe1\xbd\x9f",
+       "\xe1\xbd\xa0" => "\xe1\xbd\xa8",
+       "\xe1\xbd\xa1" => "\xe1\xbd\xa9",
+       "\xe1\xbd\xa2" => "\xe1\xbd\xaa",
+       "\xe1\xbd\xa3" => "\xe1\xbd\xab",
+       "\xe1\xbd\xa4" => "\xe1\xbd\xac",
+       "\xe1\xbd\xa5" => "\xe1\xbd\xad",
+       "\xe1\xbd\xa6" => "\xe1\xbd\xae",
+       "\xe1\xbd\xa7" => "\xe1\xbd\xaf",
+       "\xe1\xbd\xb0" => "\xe1\xbe\xba",
+       "\xe1\xbd\xb1" => "\xe1\xbe\xbb",
+       "\xe1\xbd\xb2" => "\xe1\xbf\x88",
+       "\xe1\xbd\xb3" => "\xe1\xbf\x89",
+       "\xe1\xbd\xb4" => "\xe1\xbf\x8a",
+       "\xe1\xbd\xb5" => "\xe1\xbf\x8b",
+       "\xe1\xbd\xb6" => "\xe1\xbf\x9a",
+       "\xe1\xbd\xb7" => "\xe1\xbf\x9b",
+       "\xe1\xbd\xb8" => "\xe1\xbf\xb8",
+       "\xe1\xbd\xb9" => "\xe1\xbf\xb9",
+       "\xe1\xbd\xba" => "\xe1\xbf\xaa",
+       "\xe1\xbd\xbb" => "\xe1\xbf\xab",
+       "\xe1\xbd\xbc" => "\xe1\xbf\xba",
+       "\xe1\xbd\xbd" => "\xe1\xbf\xbb",
+       "\xe1\xbe\x80" => "\xe1\xbe\x88",
+       "\xe1\xbe\x81" => "\xe1\xbe\x89",
+       "\xe1\xbe\x82" => "\xe1\xbe\x8a",
+       "\xe1\xbe\x83" => "\xe1\xbe\x8b",
+       "\xe1\xbe\x84" => "\xe1\xbe\x8c",
+       "\xe1\xbe\x85" => "\xe1\xbe\x8d",
+       "\xe1\xbe\x86" => "\xe1\xbe\x8e",
+       "\xe1\xbe\x87" => "\xe1\xbe\x8f",
+       "\xe1\xbe\x90" => "\xe1\xbe\x98",
+       "\xe1\xbe\x91" => "\xe1\xbe\x99",
+       "\xe1\xbe\x92" => "\xe1\xbe\x9a",
+       "\xe1\xbe\x93" => "\xe1\xbe\x9b",
+       "\xe1\xbe\x94" => "\xe1\xbe\x9c",
+       "\xe1\xbe\x95" => "\xe1\xbe\x9d",
+       "\xe1\xbe\x96" => "\xe1\xbe\x9e",
+       "\xe1\xbe\x97" => "\xe1\xbe\x9f",
+       "\xe1\xbe\xa0" => "\xe1\xbe\xa8",
+       "\xe1\xbe\xa1" => "\xe1\xbe\xa9",
+       "\xe1\xbe\xa2" => "\xe1\xbe\xaa",
+       "\xe1\xbe\xa3" => "\xe1\xbe\xab",
+       "\xe1\xbe\xa4" => "\xe1\xbe\xac",
+       "\xe1\xbe\xa5" => "\xe1\xbe\xad",
+       "\xe1\xbe\xa6" => "\xe1\xbe\xae",
+       "\xe1\xbe\xa7" => "\xe1\xbe\xaf",
+       "\xe1\xbe\xb0" => "\xe1\xbe\xb8",
+       "\xe1\xbe\xb1" => "\xe1\xbe\xb9",
+       "\xe1\xbe\xb3" => "\xe1\xbe\xbc",
+       "\xe1\xbe\xbe" => "\xce\x99",
+       "\xe1\xbf\x83" => "\xe1\xbf\x8c",
+       "\xe1\xbf\x90" => "\xe1\xbf\x98",
+       "\xe1\xbf\x91" => "\xe1\xbf\x99",
+       "\xe1\xbf\xa0" => "\xe1\xbf\xa8",
+       "\xe1\xbf\xa1" => "\xe1\xbf\xa9",
+       "\xe1\xbf\xa5" => "\xe1\xbf\xac",
+       "\xe1\xbf\xb3" => "\xe1\xbf\xbc",
+       "\xe2\x85\xb0" => "\xe2\x85\xa0",
+       "\xe2\x85\xb1" => "\xe2\x85\xa1",
+       "\xe2\x85\xb2" => "\xe2\x85\xa2",
+       "\xe2\x85\xb3" => "\xe2\x85\xa3",
+       "\xe2\x85\xb4" => "\xe2\x85\xa4",
+       "\xe2\x85\xb5" => "\xe2\x85\xa5",
+       "\xe2\x85\xb6" => "\xe2\x85\xa6",
+       "\xe2\x85\xb7" => "\xe2\x85\xa7",
+       "\xe2\x85\xb8" => "\xe2\x85\xa8",
+       "\xe2\x85\xb9" => "\xe2\x85\xa9",
+       "\xe2\x85\xba" => "\xe2\x85\xaa",
+       "\xe2\x85\xbb" => "\xe2\x85\xab",
+       "\xe2\x85\xbc" => "\xe2\x85\xac",
+       "\xe2\x85\xbd" => "\xe2\x85\xad",
+       "\xe2\x85\xbe" => "\xe2\x85\xae",
+       "\xe2\x85\xbf" => "\xe2\x85\xaf",
+       "\xe2\x93\x90" => "\xe2\x92\xb6",
+       "\xe2\x93\x91" => "\xe2\x92\xb7",
+       "\xe2\x93\x92" => "\xe2\x92\xb8",
+       "\xe2\x93\x93" => "\xe2\x92\xb9",
+       "\xe2\x93\x94" => "\xe2\x92\xba",
+       "\xe2\x93\x95" => "\xe2\x92\xbb",
+       "\xe2\x93\x96" => "\xe2\x92\xbc",
+       "\xe2\x93\x97" => "\xe2\x92\xbd",
+       "\xe2\x93\x98" => "\xe2\x92\xbe",
+       "\xe2\x93\x99" => "\xe2\x92\xbf",
+       "\xe2\x93\x9a" => "\xe2\x93\x80",
+       "\xe2\x93\x9b" => "\xe2\x93\x81",
+       "\xe2\x93\x9c" => "\xe2\x93\x82",
+       "\xe2\x93\x9d" => "\xe2\x93\x83",
+       "\xe2\x93\x9e" => "\xe2\x93\x84",
+       "\xe2\x93\x9f" => "\xe2\x93\x85",
+       "\xe2\x93\xa0" => "\xe2\x93\x86",
+       "\xe2\x93\xa1" => "\xe2\x93\x87",
+       "\xe2\x93\xa2" => "\xe2\x93\x88",
+       "\xe2\x93\xa3" => "\xe2\x93\x89",
+       "\xe2\x93\xa4" => "\xe2\x93\x8a",
+       "\xe2\x93\xa5" => "\xe2\x93\x8b",
+       "\xe2\x93\xa6" => "\xe2\x93\x8c",
+       "\xe2\x93\xa7" => "\xe2\x93\x8d",
+       "\xe2\x93\xa8" => "\xe2\x93\x8e",
+       "\xe2\x93\xa9" => "\xe2\x93\x8f",
+       "\xef\xbd\x81" => "\xef\xbc\xa1",
+       "\xef\xbd\x82" => "\xef\xbc\xa2",
+       "\xef\xbd\x83" => "\xef\xbc\xa3",
+       "\xef\xbd\x84" => "\xef\xbc\xa4",
+       "\xef\xbd\x85" => "\xef\xbc\xa5",
+       "\xef\xbd\x86" => "\xef\xbc\xa6",
+       "\xef\xbd\x87" => "\xef\xbc\xa7",
+       "\xef\xbd\x88" => "\xef\xbc\xa8",
+       "\xef\xbd\x89" => "\xef\xbc\xa9",
+       "\xef\xbd\x8a" => "\xef\xbc\xaa",
+       "\xef\xbd\x8b" => "\xef\xbc\xab",
+       "\xef\xbd\x8c" => "\xef\xbc\xac",
+       "\xef\xbd\x8d" => "\xef\xbc\xad",
+       "\xef\xbd\x8e" => "\xef\xbc\xae",
+       "\xef\xbd\x8f" => "\xef\xbc\xaf",
+       "\xef\xbd\x90" => "\xef\xbc\xb0",
+       "\xef\xbd\x91" => "\xef\xbc\xb1",
+       "\xef\xbd\x92" => "\xef\xbc\xb2",
+       "\xef\xbd\x93" => "\xef\xbc\xb3",
+       "\xef\xbd\x94" => "\xef\xbc\xb4",
+       "\xef\xbd\x95" => "\xef\xbc\xb5",
+       "\xef\xbd\x96" => "\xef\xbc\xb6",
+       "\xef\xbd\x97" => "\xef\xbc\xb7",
+       "\xef\xbd\x98" => "\xef\xbc\xb8",
+       "\xef\xbd\x99" => "\xef\xbc\xb9",
+       "\xef\xbd\x9a" => "\xef\xbc\xba",
+       "\xf0\x90\x90\xa8" => "\xf0\x90\x90\x80",
+       "\xf0\x90\x90\xa9" => "\xf0\x90\x90\x81",
+       "\xf0\x90\x90\xaa" => "\xf0\x90\x90\x82",
+       "\xf0\x90\x90\xab" => "\xf0\x90\x90\x83",
+       "\xf0\x90\x90\xac" => "\xf0\x90\x90\x84",
+       "\xf0\x90\x90\xad" => "\xf0\x90\x90\x85",
+       "\xf0\x90\x90\xae" => "\xf0\x90\x90\x86",
+       "\xf0\x90\x90\xaf" => "\xf0\x90\x90\x87",
+       "\xf0\x90\x90\xb0" => "\xf0\x90\x90\x88",
+       "\xf0\x90\x90\xb1" => "\xf0\x90\x90\x89",
+       "\xf0\x90\x90\xb2" => "\xf0\x90\x90\x8a",
+       "\xf0\x90\x90\xb3" => "\xf0\x90\x90\x8b",
+       "\xf0\x90\x90\xb4" => "\xf0\x90\x90\x8c",
+       "\xf0\x90\x90\xb5" => "\xf0\x90\x90\x8d",
+       "\xf0\x90\x90\xb6" => "\xf0\x90\x90\x8e",
+       "\xf0\x90\x90\xb7" => "\xf0\x90\x90\x8f",
+       "\xf0\x90\x90\xb8" => "\xf0\x90\x90\x90",
+       "\xf0\x90\x90\xb9" => "\xf0\x90\x90\x91",
+       "\xf0\x90\x90\xba" => "\xf0\x90\x90\x92",
+       "\xf0\x90\x90\xbb" => "\xf0\x90\x90\x93",
+       "\xf0\x90\x90\xbc" => "\xf0\x90\x90\x94",
+       "\xf0\x90\x90\xbd" => "\xf0\x90\x90\x95",
+       "\xf0\x90\x90\xbe" => "\xf0\x90\x90\x96",
+       "\xf0\x90\x90\xbf" => "\xf0\x90\x90\x97",
+       "\xf0\x90\x91\x80" => "\xf0\x90\x90\x98",
+       "\xf0\x90\x91\x81" => "\xf0\x90\x90\x99",
+       "\xf0\x90\x91\x82" => "\xf0\x90\x90\x9a",
+       "\xf0\x90\x91\x83" => "\xf0\x90\x90\x9b",
+       "\xf0\x90\x91\x84" => "\xf0\x90\x90\x9c",
+       "\xf0\x90\x91\x85" => "\xf0\x90\x90\x9d",
+       "\xf0\x90\x91\x86" => "\xf0\x90\x90\x9e",
+       "\xf0\x90\x91\x87" => "\xf0\x90\x90\x9f",
+       "\xf0\x90\x91\x88" => "\xf0\x90\x90\xa0",
+       "\xf0\x90\x91\x89" => "\xf0\x90\x90\xa1",
+       "\xf0\x90\x91\x8a" => "\xf0\x90\x90\xa2",
+       "\xf0\x90\x91\x8b" => "\xf0\x90\x90\xa3",
+       "\xf0\x90\x91\x8c" => "\xf0\x90\x90\xa4",
+       "\xf0\x90\x91\x8d" => "\xf0\x90\x90\xa5"
+);
+
+$wikiLowerChars = array (
+       "A" => "a",
+       "B" => "b",
+       "C" => "c",
+       "D" => "d",
+       "E" => "e",
+       "F" => "f",
+       "G" => "g",
+       "H" => "h",
+       "I" => "i",
+       "J" => "j",
+       "K" => "k",
+       "L" => "l",
+       "M" => "m",
+       "N" => "n",
+       "O" => "o",
+       "P" => "p",
+       "Q" => "q",
+       "R" => "r",
+       "S" => "s",
+       "T" => "t",
+       "U" => "u",
+       "V" => "v",
+       "W" => "w",
+       "X" => "x",
+       "Y" => "y",
+       "Z" => "z",
+       "\xc3\x80" => "\xc3\xa0",
+       "\xc3\x81" => "\xc3\xa1",
+       "\xc3\x82" => "\xc3\xa2",
+       "\xc3\x83" => "\xc3\xa3",
+       "\xc3\x84" => "\xc3\xa4",
+       "\xc3\x85" => "\xc3\xa5",
+       "\xc3\x86" => "\xc3\xa6",
+       "\xc3\x87" => "\xc3\xa7",
+       "\xc3\x88" => "\xc3\xa8",
+       "\xc3\x89" => "\xc3\xa9",
+       "\xc3\x8a" => "\xc3\xaa",
+       "\xc3\x8b" => "\xc3\xab",
+       "\xc3\x8c" => "\xc3\xac",
+       "\xc3\x8d" => "\xc3\xad",
+       "\xc3\x8e" => "\xc3\xae",
+       "\xc3\x8f" => "\xc3\xaf",
+       "\xc3\x90" => "\xc3\xb0",
+       "\xc3\x91" => "\xc3\xb1",
+       "\xc3\x92" => "\xc3\xb2",
+       "\xc3\x93" => "\xc3\xb3",
+       "\xc3\x94" => "\xc3\xb4",
+       "\xc3\x95" => "\xc3\xb5",
+       "\xc3\x96" => "\xc3\xb6",
+       "\xc3\x98" => "\xc3\xb8",
+       "\xc3\x99" => "\xc3\xb9",
+       "\xc3\x9a" => "\xc3\xba",
+       "\xc3\x9b" => "\xc3\xbb",
+       "\xc3\x9c" => "\xc3\xbc",
+       "\xc3\x9d" => "\xc3\xbd",
+       "\xc3\x9e" => "\xc3\xbe",
+       "\xc4\x80" => "\xc4\x81",
+       "\xc4\x82" => "\xc4\x83",
+       "\xc4\x84" => "\xc4\x85",
+       "\xc4\x86" => "\xc4\x87",
+       "\xc4\x88" => "\xc4\x89",
+       "\xc4\x8a" => "\xc4\x8b",
+       "\xc4\x8c" => "\xc4\x8d",
+       "\xc4\x8e" => "\xc4\x8f",
+       "\xc4\x90" => "\xc4\x91",
+       "\xc4\x92" => "\xc4\x93",
+       "\xc4\x94" => "\xc4\x95",
+       "\xc4\x96" => "\xc4\x97",
+       "\xc4\x98" => "\xc4\x99",
+       "\xc4\x9a" => "\xc4\x9b",
+       "\xc4\x9c" => "\xc4\x9d",
+       "\xc4\x9e" => "\xc4\x9f",
+       "\xc4\xa0" => "\xc4\xa1",
+       "\xc4\xa2" => "\xc4\xa3",
+       "\xc4\xa4" => "\xc4\xa5",
+       "\xc4\xa6" => "\xc4\xa7",
+       "\xc4\xa8" => "\xc4\xa9",
+       "\xc4\xaa" => "\xc4\xab",
+       "\xc4\xac" => "\xc4\xad",
+       "\xc4\xae" => "\xc4\xaf",
+       "\xc4\xb0" => "i",
+       "\xc4\xb2" => "\xc4\xb3",
+       "\xc4\xb4" => "\xc4\xb5",
+       "\xc4\xb6" => "\xc4\xb7",
+       "\xc4\xb9" => "\xc4\xba",
+       "\xc4\xbb" => "\xc4\xbc",
+       "\xc4\xbd" => "\xc4\xbe",
+       "\xc4\xbf" => "\xc5\x80",
+       "\xc5\x81" => "\xc5\x82",
+       "\xc5\x83" => "\xc5\x84",
+       "\xc5\x85" => "\xc5\x86",
+       "\xc5\x87" => "\xc5\x88",
+       "\xc5\x8a" => "\xc5\x8b",
+       "\xc5\x8c" => "\xc5\x8d",
+       "\xc5\x8e" => "\xc5\x8f",
+       "\xc5\x90" => "\xc5\x91",
+       "\xc5\x92" => "\xc5\x93",
+       "\xc5\x94" => "\xc5\x95",
+       "\xc5\x96" => "\xc5\x97",
+       "\xc5\x98" => "\xc5\x99",
+       "\xc5\x9a" => "\xc5\x9b",
+       "\xc5\x9c" => "\xc5\x9d",
+       "\xc5\x9e" => "\xc5\x9f",
+       "\xc5\xa0" => "\xc5\xa1",
+       "\xc5\xa2" => "\xc5\xa3",
+       "\xc5\xa4" => "\xc5\xa5",
+       "\xc5\xa6" => "\xc5\xa7",
+       "\xc5\xa8" => "\xc5\xa9",
+       "\xc5\xaa" => "\xc5\xab",
+       "\xc5\xac" => "\xc5\xad",
+       "\xc5\xae" => "\xc5\xaf",
+       "\xc5\xb0" => "\xc5\xb1",
+       "\xc5\xb2" => "\xc5\xb3",
+       "\xc5\xb4" => "\xc5\xb5",
+       "\xc5\xb6" => "\xc5\xb7",
+       "\xc5\xb8" => "\xc3\xbf",
+       "\xc5\xb9" => "\xc5\xba",
+       "\xc5\xbb" => "\xc5\xbc",
+       "\xc5\xbd" => "\xc5\xbe",
+       "\xc6\x81" => "\xc9\x93",
+       "\xc6\x82" => "\xc6\x83",
+       "\xc6\x84" => "\xc6\x85",
+       "\xc6\x86" => "\xc9\x94",
+       "\xc6\x87" => "\xc6\x88",
+       "\xc6\x89" => "\xc9\x96",
+       "\xc6\x8a" => "\xc9\x97",
+       "\xc6\x8b" => "\xc6\x8c",
+       "\xc6\x8e" => "\xc7\x9d",
+       "\xc6\x8f" => "\xc9\x99",
+       "\xc6\x90" => "\xc9\x9b",
+       "\xc6\x91" => "\xc6\x92",
+       "\xc6\x93" => "\xc9\xa0",
+       "\xc6\x94" => "\xc9\xa3",
+       "\xc6\x96" => "\xc9\xa9",
+       "\xc6\x97" => "\xc9\xa8",
+       "\xc6\x98" => "\xc6\x99",
+       "\xc6\x9c" => "\xc9\xaf",
+       "\xc6\x9d" => "\xc9\xb2",
+       "\xc6\x9f" => "\xc9\xb5",
+       "\xc6\xa0" => "\xc6\xa1",
+       "\xc6\xa2" => "\xc6\xa3",
+       "\xc6\xa4" => "\xc6\xa5",
+       "\xc6\xa6" => "\xca\x80",
+       "\xc6\xa7" => "\xc6\xa8",
+       "\xc6\xa9" => "\xca\x83",
+       "\xc6\xac" => "\xc6\xad",
+       "\xc6\xae" => "\xca\x88",
+       "\xc6\xaf" => "\xc6\xb0",
+       "\xc6\xb1" => "\xca\x8a",
+       "\xc6\xb2" => "\xca\x8b",
+       "\xc6\xb3" => "\xc6\xb4",
+       "\xc6\xb5" => "\xc6\xb6",
+       "\xc6\xb7" => "\xca\x92",
+       "\xc6\xb8" => "\xc6\xb9",
+       "\xc6\xbc" => "\xc6\xbd",
+       "\xc7\x84" => "\xc7\x86",
+       "\xc7\x85" => "\xc7\x86",
+       "\xc7\x87" => "\xc7\x89",
+       "\xc7\x88" => "\xc7\x89",
+       "\xc7\x8a" => "\xc7\x8c",
+       "\xc7\x8b" => "\xc7\x8c",
+       "\xc7\x8d" => "\xc7\x8e",
+       "\xc7\x8f" => "\xc7\x90",
+       "\xc7\x91" => "\xc7\x92",
+       "\xc7\x93" => "\xc7\x94",
+       "\xc7\x95" => "\xc7\x96",
+       "\xc7\x97" => "\xc7\x98",
+       "\xc7\x99" => "\xc7\x9a",
+       "\xc7\x9b" => "\xc7\x9c",
+       "\xc7\x9e" => "\xc7\x9f",
+       "\xc7\xa0" => "\xc7\xa1",
+       "\xc7\xa2" => "\xc7\xa3",
+       "\xc7\xa4" => "\xc7\xa5",
+       "\xc7\xa6" => "\xc7\xa7",
+       "\xc7\xa8" => "\xc7\xa9",
+       "\xc7\xaa" => "\xc7\xab",
+       "\xc7\xac" => "\xc7\xad",
+       "\xc7\xae" => "\xc7\xaf",
+       "\xc7\xb1" => "\xc7\xb3",
+       "\xc7\xb2" => "\xc7\xb3",
+       "\xc7\xb4" => "\xc7\xb5",
+       "\xc7\xb6" => "\xc6\x95",
+       "\xc7\xb7" => "\xc6\xbf",
+       "\xc7\xb8" => "\xc7\xb9",
+       "\xc7\xba" => "\xc7\xbb",
+       "\xc7\xbc" => "\xc7\xbd",
+       "\xc7\xbe" => "\xc7\xbf",
+       "\xc8\x80" => "\xc8\x81",
+       "\xc8\x82" => "\xc8\x83",
+       "\xc8\x84" => "\xc8\x85",
+       "\xc8\x86" => "\xc8\x87",
+       "\xc8\x88" => "\xc8\x89",
+       "\xc8\x8a" => "\xc8\x8b",
+       "\xc8\x8c" => "\xc8\x8d",
+       "\xc8\x8e" => "\xc8\x8f",
+       "\xc8\x90" => "\xc8\x91",
+       "\xc8\x92" => "\xc8\x93",
+       "\xc8\x94" => "\xc8\x95",
+       "\xc8\x96" => "\xc8\x97",
+       "\xc8\x98" => "\xc8\x99",
+       "\xc8\x9a" => "\xc8\x9b",
+       "\xc8\x9c" => "\xc8\x9d",
+       "\xc8\x9e" => "\xc8\x9f",
+       "\xc8\xa2" => "\xc8\xa3",
+       "\xc8\xa4" => "\xc8\xa5",
+       "\xc8\xa6" => "\xc8\xa7",
+       "\xc8\xa8" => "\xc8\xa9",
+       "\xc8\xaa" => "\xc8\xab",
+       "\xc8\xac" => "\xc8\xad",
+       "\xc8\xae" => "\xc8\xaf",
+       "\xc8\xb0" => "\xc8\xb1",
+       "\xc8\xb2" => "\xc8\xb3",
+       "\xce\x86" => "\xce\xac",
+       "\xce\x88" => "\xce\xad",
+       "\xce\x89" => "\xce\xae",
+       "\xce\x8a" => "\xce\xaf",
+       "\xce\x8c" => "\xcf\x8c",
+       "\xce\x8e" => "\xcf\x8d",
+       "\xce\x8f" => "\xcf\x8e",
+       "\xce\x91" => "\xce\xb1",
+       "\xce\x92" => "\xce\xb2",
+       "\xce\x93" => "\xce\xb3",
+       "\xce\x94" => "\xce\xb4",
+       "\xce\x95" => "\xce\xb5",
+       "\xce\x96" => "\xce\xb6",
+       "\xce\x97" => "\xce\xb7",
+       "\xce\x98" => "\xce\xb8",
+       "\xce\x99" => "\xce\xb9",
+       "\xce\x9a" => "\xce\xba",
+       "\xce\x9b" => "\xce\xbb",
+       "\xce\x9c" => "\xce\xbc",
+       "\xce\x9d" => "\xce\xbd",
+       "\xce\x9e" => "\xce\xbe",
+       "\xce\x9f" => "\xce\xbf",
+       "\xce\xa0" => "\xcf\x80",
+       "\xce\xa1" => "\xcf\x81",
+       "\xce\xa3" => "\xcf\x83",
+       "\xce\xa4" => "\xcf\x84",
+       "\xce\xa5" => "\xcf\x85",
+       "\xce\xa6" => "\xcf\x86",
+       "\xce\xa7" => "\xcf\x87",
+       "\xce\xa8" => "\xcf\x88",
+       "\xce\xa9" => "\xcf\x89",
+       "\xce\xaa" => "\xcf\x8a",
+       "\xce\xab" => "\xcf\x8b",
+       "\xcf\x9a" => "\xcf\x9b",
+       "\xcf\x9c" => "\xcf\x9d",
+       "\xcf\x9e" => "\xcf\x9f",
+       "\xcf\xa0" => "\xcf\xa1",
+       "\xcf\xa2" => "\xcf\xa3",
+       "\xcf\xa4" => "\xcf\xa5",
+       "\xcf\xa6" => "\xcf\xa7",
+       "\xcf\xa8" => "\xcf\xa9",
+       "\xcf\xaa" => "\xcf\xab",
+       "\xcf\xac" => "\xcf\xad",
+       "\xcf\xae" => "\xcf\xaf",
+       "\xcf\xb4" => "\xce\xb8",
+       "\xd0\x80" => "\xd1\x90",
+       "\xd0\x81" => "\xd1\x91",
+       "\xd0\x82" => "\xd1\x92",
+       "\xd0\x83" => "\xd1\x93",
+       "\xd0\x84" => "\xd1\x94",
+       "\xd0\x85" => "\xd1\x95",
+       "\xd0\x86" => "\xd1\x96",
+       "\xd0\x87" => "\xd1\x97",
+       "\xd0\x88" => "\xd1\x98",
+       "\xd0\x89" => "\xd1\x99",
+       "\xd0\x8a" => "\xd1\x9a",
+       "\xd0\x8b" => "\xd1\x9b",
+       "\xd0\x8c" => "\xd1\x9c",
+       "\xd0\x8d" => "\xd1\x9d",
+       "\xd0\x8e" => "\xd1\x9e",
+       "\xd0\x8f" => "\xd1\x9f",
+       "\xd0\x90" => "\xd0\xb0",
+       "\xd0\x91" => "\xd0\xb1",
+       "\xd0\x92" => "\xd0\xb2",
+       "\xd0\x93" => "\xd0\xb3",
+       "\xd0\x94" => "\xd0\xb4",
+       "\xd0\x95" => "\xd0\xb5",
+       "\xd0\x96" => "\xd0\xb6",
+       "\xd0\x97" => "\xd0\xb7",
+       "\xd0\x98" => "\xd0\xb8",
+       "\xd0\x99" => "\xd0\xb9",
+       "\xd0\x9a" => "\xd0\xba",
+       "\xd0\x9b" => "\xd0\xbb",
+       "\xd0\x9c" => "\xd0\xbc",
+       "\xd0\x9d" => "\xd0\xbd",
+       "\xd0\x9e" => "\xd0\xbe",
+       "\xd0\x9f" => "\xd0\xbf",
+       "\xd0\xa0" => "\xd1\x80",
+       "\xd0\xa1" => "\xd1\x81",
+       "\xd0\xa2" => "\xd1\x82",
+       "\xd0\xa3" => "\xd1\x83",
+       "\xd0\xa4" => "\xd1\x84",
+       "\xd0\xa5" => "\xd1\x85",
+       "\xd0\xa6" => "\xd1\x86",
+       "\xd0\xa7" => "\xd1\x87",
+       "\xd0\xa8" => "\xd1\x88",
+       "\xd0\xa9" => "\xd1\x89",
+       "\xd0\xaa" => "\xd1\x8a",
+       "\xd0\xab" => "\xd1\x8b",
+       "\xd0\xac" => "\xd1\x8c",
+       "\xd0\xad" => "\xd1\x8d",
+       "\xd0\xae" => "\xd1\x8e",
+       "\xd0\xaf" => "\xd1\x8f",
+       "\xd1\xa0" => "\xd1\xa1",
+       "\xd1\xa2" => "\xd1\xa3",
+       "\xd1\xa4" => "\xd1\xa5",
+       "\xd1\xa6" => "\xd1\xa7",
+       "\xd1\xa8" => "\xd1\xa9",
+       "\xd1\xaa" => "\xd1\xab",
+       "\xd1\xac" => "\xd1\xad",
+       "\xd1\xae" => "\xd1\xaf",
+       "\xd1\xb0" => "\xd1\xb1",
+       "\xd1\xb2" => "\xd1\xb3",
+       "\xd1\xb4" => "\xd1\xb5",
+       "\xd1\xb6" => "\xd1\xb7",
+       "\xd1\xb8" => "\xd1\xb9",
+       "\xd1\xba" => "\xd1\xbb",
+       "\xd1\xbc" => "\xd1\xbd",
+       "\xd1\xbe" => "\xd1\xbf",
+       "\xd2\x80" => "\xd2\x81",
+       "\xd2\x8c" => "\xd2\x8d",
+       "\xd2\x8e" => "\xd2\x8f",
+       "\xd2\x90" => "\xd2\x91",
+       "\xd2\x92" => "\xd2\x93",
+       "\xd2\x94" => "\xd2\x95",
+       "\xd2\x96" => "\xd2\x97",
+       "\xd2\x98" => "\xd2\x99",
+       "\xd2\x9a" => "\xd2\x9b",
+       "\xd2\x9c" => "\xd2\x9d",
+       "\xd2\x9e" => "\xd2\x9f",
+       "\xd2\xa0" => "\xd2\xa1",
+       "\xd2\xa2" => "\xd2\xa3",
+       "\xd2\xa4" => "\xd2\xa5",
+       "\xd2\xa6" => "\xd2\xa7",
+       "\xd2\xa8" => "\xd2\xa9",
+       "\xd2\xaa" => "\xd2\xab",
+       "\xd2\xac" => "\xd2\xad",
+       "\xd2\xae" => "\xd2\xaf",
+       "\xd2\xb0" => "\xd2\xb1",
+       "\xd2\xb2" => "\xd2\xb3",
+       "\xd2\xb4" => "\xd2\xb5",
+       "\xd2\xb6" => "\xd2\xb7",
+       "\xd2\xb8" => "\xd2\xb9",
+       "\xd2\xba" => "\xd2\xbb",
+       "\xd2\xbc" => "\xd2\xbd",
+       "\xd2\xbe" => "\xd2\xbf",
+       "\xd3\x81" => "\xd3\x82",
+       "\xd3\x83" => "\xd3\x84",
+       "\xd3\x87" => "\xd3\x88",
+       "\xd3\x8b" => "\xd3\x8c",
+       "\xd3\x90" => "\xd3\x91",
+       "\xd3\x92" => "\xd3\x93",
+       "\xd3\x94" => "\xd3\x95",
+       "\xd3\x96" => "\xd3\x97",
+       "\xd3\x98" => "\xd3\x99",
+       "\xd3\x9a" => "\xd3\x9b",
+       "\xd3\x9c" => "\xd3\x9d",
+       "\xd3\x9e" => "\xd3\x9f",
+       "\xd3\xa0" => "\xd3\xa1",
+       "\xd3\xa2" => "\xd3\xa3",
+       "\xd3\xa4" => "\xd3\xa5",
+       "\xd3\xa6" => "\xd3\xa7",
+       "\xd3\xa8" => "\xd3\xa9",
+       "\xd3\xaa" => "\xd3\xab",
+       "\xd3\xac" => "\xd3\xad",
+       "\xd3\xae" => "\xd3\xaf",
+       "\xd3\xb0" => "\xd3\xb1",
+       "\xd3\xb2" => "\xd3\xb3",
+       "\xd3\xb4" => "\xd3\xb5",
+       "\xd3\xb8" => "\xd3\xb9",
+       "\xd4\xb1" => "\xd5\xa1",
+       "\xd4\xb2" => "\xd5\xa2",
+       "\xd4\xb3" => "\xd5\xa3",
+       "\xd4\xb4" => "\xd5\xa4",
+       "\xd4\xb5" => "\xd5\xa5",
+       "\xd4\xb6" => "\xd5\xa6",
+       "\xd4\xb7" => "\xd5\xa7",
+       "\xd4\xb8" => "\xd5\xa8",
+       "\xd4\xb9" => "\xd5\xa9",
+       "\xd4\xba" => "\xd5\xaa",
+       "\xd4\xbb" => "\xd5\xab",
+       "\xd4\xbc" => "\xd5\xac",
+       "\xd4\xbd" => "\xd5\xad",
+       "\xd4\xbe" => "\xd5\xae",
+       "\xd4\xbf" => "\xd5\xaf",
+       "\xd5\x80" => "\xd5\xb0",
+       "\xd5\x81" => "\xd5\xb1",
+       "\xd5\x82" => "\xd5\xb2",
+       "\xd5\x83" => "\xd5\xb3",
+       "\xd5\x84" => "\xd5\xb4",
+       "\xd5\x85" => "\xd5\xb5",
+       "\xd5\x86" => "\xd5\xb6",
+       "\xd5\x87" => "\xd5\xb7",
+       "\xd5\x88" => "\xd5\xb8",
+       "\xd5\x89" => "\xd5\xb9",
+       "\xd5\x8a" => "\xd5\xba",
+       "\xd5\x8b" => "\xd5\xbb",
+       "\xd5\x8c" => "\xd5\xbc",
+       "\xd5\x8d" => "\xd5\xbd",
+       "\xd5\x8e" => "\xd5\xbe",
+       "\xd5\x8f" => "\xd5\xbf",
+       "\xd5\x90" => "\xd6\x80",
+       "\xd5\x91" => "\xd6\x81",
+       "\xd5\x92" => "\xd6\x82",
+       "\xd5\x93" => "\xd6\x83",
+       "\xd5\x94" => "\xd6\x84",
+       "\xd5\x95" => "\xd6\x85",
+       "\xd5\x96" => "\xd6\x86",
+       "\xe1\xb8\x80" => "\xe1\xb8\x81",
+       "\xe1\xb8\x82" => "\xe1\xb8\x83",
+       "\xe1\xb8\x84" => "\xe1\xb8\x85",
+       "\xe1\xb8\x86" => "\xe1\xb8\x87",
+       "\xe1\xb8\x88" => "\xe1\xb8\x89",
+       "\xe1\xb8\x8a" => "\xe1\xb8\x8b",
+       "\xe1\xb8\x8c" => "\xe1\xb8\x8d",
+       "\xe1\xb8\x8e" => "\xe1\xb8\x8f",
+       "\xe1\xb8\x90" => "\xe1\xb8\x91",
+       "\xe1\xb8\x92" => "\xe1\xb8\x93",
+       "\xe1\xb8\x94" => "\xe1\xb8\x95",
+       "\xe1\xb8\x96" => "\xe1\xb8\x97",
+       "\xe1\xb8\x98" => "\xe1\xb8\x99",
+       "\xe1\xb8\x9a" => "\xe1\xb8\x9b",
+       "\xe1\xb8\x9c" => "\xe1\xb8\x9d",
+       "\xe1\xb8\x9e" => "\xe1\xb8\x9f",
+       "\xe1\xb8\xa0" => "\xe1\xb8\xa1",
+       "\xe1\xb8\xa2" => "\xe1\xb8\xa3",
+       "\xe1\xb8\xa4" => "\xe1\xb8\xa5",
+       "\xe1\xb8\xa6" => "\xe1\xb8\xa7",
+       "\xe1\xb8\xa8" => "\xe1\xb8\xa9",
+       "\xe1\xb8\xaa" => "\xe1\xb8\xab",
+       "\xe1\xb8\xac" => "\xe1\xb8\xad",
+       "\xe1\xb8\xae" => "\xe1\xb8\xaf",
+       "\xe1\xb8\xb0" => "\xe1\xb8\xb1",
+       "\xe1\xb8\xb2" => "\xe1\xb8\xb3",
+       "\xe1\xb8\xb4" => "\xe1\xb8\xb5",
+       "\xe1\xb8\xb6" => "\xe1\xb8\xb7",
+       "\xe1\xb8\xb8" => "\xe1\xb8\xb9",
+       "\xe1\xb8\xba" => "\xe1\xb8\xbb",
+       "\xe1\xb8\xbc" => "\xe1\xb8\xbd",
+       "\xe1\xb8\xbe" => "\xe1\xb8\xbf",
+       "\xe1\xb9\x80" => "\xe1\xb9\x81",
+       "\xe1\xb9\x82" => "\xe1\xb9\x83",
+       "\xe1\xb9\x84" => "\xe1\xb9\x85",
+       "\xe1\xb9\x86" => "\xe1\xb9\x87",
+       "\xe1\xb9\x88" => "\xe1\xb9\x89",
+       "\xe1\xb9\x8a" => "\xe1\xb9\x8b",
+       "\xe1\xb9\x8c" => "\xe1\xb9\x8d",
+       "\xe1\xb9\x8e" => "\xe1\xb9\x8f",
+       "\xe1\xb9\x90" => "\xe1\xb9\x91",
+       "\xe1\xb9\x92" => "\xe1\xb9\x93",
+       "\xe1\xb9\x94" => "\xe1\xb9\x95",
+       "\xe1\xb9\x96" => "\xe1\xb9\x97",
+       "\xe1\xb9\x98" => "\xe1\xb9\x99",
+       "\xe1\xb9\x9a" => "\xe1\xb9\x9b",
+       "\xe1\xb9\x9c" => "\xe1\xb9\x9d",
+       "\xe1\xb9\x9e" => "\xe1\xb9\x9f",
+       "\xe1\xb9\xa0" => "\xe1\xb9\xa1",
+       "\xe1\xb9\xa2" => "\xe1\xb9\xa3",
+       "\xe1\xb9\xa4" => "\xe1\xb9\xa5",
+       "\xe1\xb9\xa6" => "\xe1\xb9\xa7",
+       "\xe1\xb9\xa8" => "\xe1\xb9\xa9",
+       "\xe1\xb9\xaa" => "\xe1\xb9\xab",
+       "\xe1\xb9\xac" => "\xe1\xb9\xad",
+       "\xe1\xb9\xae" => "\xe1\xb9\xaf",
+       "\xe1\xb9\xb0" => "\xe1\xb9\xb1",
+       "\xe1\xb9\xb2" => "\xe1\xb9\xb3",
+       "\xe1\xb9\xb4" => "\xe1\xb9\xb5",
+       "\xe1\xb9\xb6" => "\xe1\xb9\xb7",
+       "\xe1\xb9\xb8" => "\xe1\xb9\xb9",
+       "\xe1\xb9\xba" => "\xe1\xb9\xbb",
+       "\xe1\xb9\xbc" => "\xe1\xb9\xbd",
+       "\xe1\xb9\xbe" => "\xe1\xb9\xbf",
+       "\xe1\xba\x80" => "\xe1\xba\x81",
+       "\xe1\xba\x82" => "\xe1\xba\x83",
+       "\xe1\xba\x84" => "\xe1\xba\x85",
+       "\xe1\xba\x86" => "\xe1\xba\x87",
+       "\xe1\xba\x88" => "\xe1\xba\x89",
+       "\xe1\xba\x8a" => "\xe1\xba\x8b",
+       "\xe1\xba\x8c" => "\xe1\xba\x8d",
+       "\xe1\xba\x8e" => "\xe1\xba\x8f",
+       "\xe1\xba\x90" => "\xe1\xba\x91",
+       "\xe1\xba\x92" => "\xe1\xba\x93",
+       "\xe1\xba\x94" => "\xe1\xba\x95",
+       "\xe1\xba\xa0" => "\xe1\xba\xa1",
+       "\xe1\xba\xa2" => "\xe1\xba\xa3",
+       "\xe1\xba\xa4" => "\xe1\xba\xa5",
+       "\xe1\xba\xa6" => "\xe1\xba\xa7",
+       "\xe1\xba\xa8" => "\xe1\xba\xa9",
+       "\xe1\xba\xaa" => "\xe1\xba\xab",
+       "\xe1\xba\xac" => "\xe1\xba\xad",
+       "\xe1\xba\xae" => "\xe1\xba\xaf",
+       "\xe1\xba\xb0" => "\xe1\xba\xb1",
+       "\xe1\xba\xb2" => "\xe1\xba\xb3",
+       "\xe1\xba\xb4" => "\xe1\xba\xb5",
+       "\xe1\xba\xb6" => "\xe1\xba\xb7",
+       "\xe1\xba\xb8" => "\xe1\xba\xb9",
+       "\xe1\xba\xba" => "\xe1\xba\xbb",
+       "\xe1\xba\xbc" => "\xe1\xba\xbd",
+       "\xe1\xba\xbe" => "\xe1\xba\xbf",
+       "\xe1\xbb\x80" => "\xe1\xbb\x81",
+       "\xe1\xbb\x82" => "\xe1\xbb\x83",
+       "\xe1\xbb\x84" => "\xe1\xbb\x85",
+       "\xe1\xbb\x86" => "\xe1\xbb\x87",
+       "\xe1\xbb\x88" => "\xe1\xbb\x89",
+       "\xe1\xbb\x8a" => "\xe1\xbb\x8b",
+       "\xe1\xbb\x8c" => "\xe1\xbb\x8d",
+       "\xe1\xbb\x8e" => "\xe1\xbb\x8f",
+       "\xe1\xbb\x90" => "\xe1\xbb\x91",
+       "\xe1\xbb\x92" => "\xe1\xbb\x93",
+       "\xe1\xbb\x94" => "\xe1\xbb\x95",
+       "\xe1\xbb\x96" => "\xe1\xbb\x97",
+       "\xe1\xbb\x98" => "\xe1\xbb\x99",
+       "\xe1\xbb\x9a" => "\xe1\xbb\x9b",
+       "\xe1\xbb\x9c" => "\xe1\xbb\x9d",
+       "\xe1\xbb\x9e" => "\xe1\xbb\x9f",
+       "\xe1\xbb\xa0" => "\xe1\xbb\xa1",
+       "\xe1\xbb\xa2" => "\xe1\xbb\xa3",
+       "\xe1\xbb\xa4" => "\xe1\xbb\xa5",
+       "\xe1\xbb\xa6" => "\xe1\xbb\xa7",
+       "\xe1\xbb\xa8" => "\xe1\xbb\xa9",
+       "\xe1\xbb\xaa" => "\xe1\xbb\xab",
+       "\xe1\xbb\xac" => "\xe1\xbb\xad",
+       "\xe1\xbb\xae" => "\xe1\xbb\xaf",
+       "\xe1\xbb\xb0" => "\xe1\xbb\xb1",
+       "\xe1\xbb\xb2" => "\xe1\xbb\xb3",
+       "\xe1\xbb\xb4" => "\xe1\xbb\xb5",
+       "\xe1\xbb\xb6" => "\xe1\xbb\xb7",
+       "\xe1\xbb\xb8" => "\xe1\xbb\xb9",
+       "\xe1\xbc\x88" => "\xe1\xbc\x80",
+       "\xe1\xbc\x89" => "\xe1\xbc\x81",
+       "\xe1\xbc\x8a" => "\xe1\xbc\x82",
+       "\xe1\xbc\x8b" => "\xe1\xbc\x83",
+       "\xe1\xbc\x8c" => "\xe1\xbc\x84",
+       "\xe1\xbc\x8d" => "\xe1\xbc\x85",
+       "\xe1\xbc\x8e" => "\xe1\xbc\x86",
+       "\xe1\xbc\x8f" => "\xe1\xbc\x87",
+       "\xe1\xbc\x98" => "\xe1\xbc\x90",
+       "\xe1\xbc\x99" => "\xe1\xbc\x91",
+       "\xe1\xbc\x9a" => "\xe1\xbc\x92",
+       "\xe1\xbc\x9b" => "\xe1\xbc\x93",
+       "\xe1\xbc\x9c" => "\xe1\xbc\x94",
+       "\xe1\xbc\x9d" => "\xe1\xbc\x95",
+       "\xe1\xbc\xa8" => "\xe1\xbc\xa0",
+       "\xe1\xbc\xa9" => "\xe1\xbc\xa1",
+       "\xe1\xbc\xaa" => "\xe1\xbc\xa2",
+       "\xe1\xbc\xab" => "\xe1\xbc\xa3",
+       "\xe1\xbc\xac" => "\xe1\xbc\xa4",
+       "\xe1\xbc\xad" => "\xe1\xbc\xa5",
+       "\xe1\xbc\xae" => "\xe1\xbc\xa6",
+       "\xe1\xbc\xaf" => "\xe1\xbc\xa7",
+       "\xe1\xbc\xb8" => "\xe1\xbc\xb0",
+       "\xe1\xbc\xb9" => "\xe1\xbc\xb1",
+       "\xe1\xbc\xba" => "\xe1\xbc\xb2",
+       "\xe1\xbc\xbb" => "\xe1\xbc\xb3",
+       "\xe1\xbc\xbc" => "\xe1\xbc\xb4",
+       "\xe1\xbc\xbd" => "\xe1\xbc\xb5",
+       "\xe1\xbc\xbe" => "\xe1\xbc\xb6",
+       "\xe1\xbc\xbf" => "\xe1\xbc\xb7",
+       "\xe1\xbd\x88" => "\xe1\xbd\x80",
+       "\xe1\xbd\x89" => "\xe1\xbd\x81",
+       "\xe1\xbd\x8a" => "\xe1\xbd\x82",
+       "\xe1\xbd\x8b" => "\xe1\xbd\x83",
+       "\xe1\xbd\x8c" => "\xe1\xbd\x84",
+       "\xe1\xbd\x8d" => "\xe1\xbd\x85",
+       "\xe1\xbd\x99" => "\xe1\xbd\x91",
+       "\xe1\xbd\x9b" => "\xe1\xbd\x93",
+       "\xe1\xbd\x9d" => "\xe1\xbd\x95",
+       "\xe1\xbd\x9f" => "\xe1\xbd\x97",
+       "\xe1\xbd\xa8" => "\xe1\xbd\xa0",
+       "\xe1\xbd\xa9" => "\xe1\xbd\xa1",
+       "\xe1\xbd\xaa" => "\xe1\xbd\xa2",
+       "\xe1\xbd\xab" => "\xe1\xbd\xa3",
+       "\xe1\xbd\xac" => "\xe1\xbd\xa4",
+       "\xe1\xbd\xad" => "\xe1\xbd\xa5",
+       "\xe1\xbd\xae" => "\xe1\xbd\xa6",
+       "\xe1\xbd\xaf" => "\xe1\xbd\xa7",
+       "\xe1\xbe\x88" => "\xe1\xbe\x80",
+       "\xe1\xbe\x89" => "\xe1\xbe\x81",
+       "\xe1\xbe\x8a" => "\xe1\xbe\x82",
+       "\xe1\xbe\x8b" => "\xe1\xbe\x83",
+       "\xe1\xbe\x8c" => "\xe1\xbe\x84",
+       "\xe1\xbe\x8d" => "\xe1\xbe\x85",
+       "\xe1\xbe\x8e" => "\xe1\xbe\x86",
+       "\xe1\xbe\x8f" => "\xe1\xbe\x87",
+       "\xe1\xbe\x98" => "\xe1\xbe\x90",
+       "\xe1\xbe\x99" => "\xe1\xbe\x91",
+       "\xe1\xbe\x9a" => "\xe1\xbe\x92",
+       "\xe1\xbe\x9b" => "\xe1\xbe\x93",
+       "\xe1\xbe\x9c" => "\xe1\xbe\x94",
+       "\xe1\xbe\x9d" => "\xe1\xbe\x95",
+       "\xe1\xbe\x9e" => "\xe1\xbe\x96",
+       "\xe1\xbe\x9f" => "\xe1\xbe\x97",
+       "\xe1\xbe\xa8" => "\xe1\xbe\xa0",
+       "\xe1\xbe\xa9" => "\xe1\xbe\xa1",
+       "\xe1\xbe\xaa" => "\xe1\xbe\xa2",
+       "\xe1\xbe\xab" => "\xe1\xbe\xa3",
+       "\xe1\xbe\xac" => "\xe1\xbe\xa4",
+       "\xe1\xbe\xad" => "\xe1\xbe\xa5",
+       "\xe1\xbe\xae" => "\xe1\xbe\xa6",
+       "\xe1\xbe\xaf" => "\xe1\xbe\xa7",
+       "\xe1\xbe\xb8" => "\xe1\xbe\xb0",
+       "\xe1\xbe\xb9" => "\xe1\xbe\xb1",
+       "\xe1\xbe\xba" => "\xe1\xbd\xb0",
+       "\xe1\xbe\xbb" => "\xe1\xbd\xb1",
+       "\xe1\xbe\xbc" => "\xe1\xbe\xb3",
+       "\xe1\xbf\x88" => "\xe1\xbd\xb2",
+       "\xe1\xbf\x89" => "\xe1\xbd\xb3",
+       "\xe1\xbf\x8a" => "\xe1\xbd\xb4",
+       "\xe1\xbf\x8b" => "\xe1\xbd\xb5",
+       "\xe1\xbf\x8c" => "\xe1\xbf\x83",
+       "\xe1\xbf\x98" => "\xe1\xbf\x90",
+       "\xe1\xbf\x99" => "\xe1\xbf\x91",
+       "\xe1\xbf\x9a" => "\xe1\xbd\xb6",
+       "\xe1\xbf\x9b" => "\xe1\xbd\xb7",
+       "\xe1\xbf\xa8" => "\xe1\xbf\xa0",
+       "\xe1\xbf\xa9" => "\xe1\xbf\xa1",
+       "\xe1\xbf\xaa" => "\xe1\xbd\xba",
+       "\xe1\xbf\xab" => "\xe1\xbd\xbb",
+       "\xe1\xbf\xac" => "\xe1\xbf\xa5",
+       "\xe1\xbf\xb8" => "\xe1\xbd\xb8",
+       "\xe1\xbf\xb9" => "\xe1\xbd\xb9",
+       "\xe1\xbf\xba" => "\xe1\xbd\xbc",
+       "\xe1\xbf\xbb" => "\xe1\xbd\xbd",
+       "\xe1\xbf\xbc" => "\xe1\xbf\xb3",
+       "\xe2\x84\xa6" => "\xcf\x89",
+       "\xe2\x84\xaa" => "k",
+       "\xe2\x84\xab" => "\xc3\xa5",
+       "\xe2\x85\xa0" => "\xe2\x85\xb0",
+       "\xe2\x85\xa1" => "\xe2\x85\xb1",
+       "\xe2\x85\xa2" => "\xe2\x85\xb2",
+       "\xe2\x85\xa3" => "\xe2\x85\xb3",
+       "\xe2\x85\xa4" => "\xe2\x85\xb4",
+       "\xe2\x85\xa5" => "\xe2\x85\xb5",
+       "\xe2\x85\xa6" => "\xe2\x85\xb6",
+       "\xe2\x85\xa7" => "\xe2\x85\xb7",
+       "\xe2\x85\xa8" => "\xe2\x85\xb8",
+       "\xe2\x85\xa9" => "\xe2\x85\xb9",
+       "\xe2\x85\xaa" => "\xe2\x85\xba",
+       "\xe2\x85\xab" => "\xe2\x85\xbb",
+       "\xe2\x85\xac" => "\xe2\x85\xbc",
+       "\xe2\x85\xad" => "\xe2\x85\xbd",
+       "\xe2\x85\xae" => "\xe2\x85\xbe",
+       "\xe2\x85\xaf" => "\xe2\x85\xbf",
+       "\xe2\x92\xb6" => "\xe2\x93\x90",
+       "\xe2\x92\xb7" => "\xe2\x93\x91",
+       "\xe2\x92\xb8" => "\xe2\x93\x92",
+       "\xe2\x92\xb9" => "\xe2\x93\x93",
+       "\xe2\x92\xba" => "\xe2\x93\x94",
+       "\xe2\x92\xbb" => "\xe2\x93\x95",
+       "\xe2\x92\xbc" => "\xe2\x93\x96",
+       "\xe2\x92\xbd" => "\xe2\x93\x97",
+       "\xe2\x92\xbe" => "\xe2\x93\x98",
+       "\xe2\x92\xbf" => "\xe2\x93\x99",
+       "\xe2\x93\x80" => "\xe2\x93\x9a",
+       "\xe2\x93\x81" => "\xe2\x93\x9b",
+       "\xe2\x93\x82" => "\xe2\x93\x9c",
+       "\xe2\x93\x83" => "\xe2\x93\x9d",
+       "\xe2\x93\x84" => "\xe2\x93\x9e",
+       "\xe2\x93\x85" => "\xe2\x93\x9f",
+       "\xe2\x93\x86" => "\xe2\x93\xa0",
+       "\xe2\x93\x87" => "\xe2\x93\xa1",
+       "\xe2\x93\x88" => "\xe2\x93\xa2",
+       "\xe2\x93\x89" => "\xe2\x93\xa3",
+       "\xe2\x93\x8a" => "\xe2\x93\xa4",
+       "\xe2\x93\x8b" => "\xe2\x93\xa5",
+       "\xe2\x93\x8c" => "\xe2\x93\xa6",
+       "\xe2\x93\x8d" => "\xe2\x93\xa7",
+       "\xe2\x93\x8e" => "\xe2\x93\xa8",
+       "\xe2\x93\x8f" => "\xe2\x93\xa9",
+       "\xef\xbc\xa1" => "\xef\xbd\x81",
+       "\xef\xbc\xa2" => "\xef\xbd\x82",
+       "\xef\xbc\xa3" => "\xef\xbd\x83",
+       "\xef\xbc\xa4" => "\xef\xbd\x84",
+       "\xef\xbc\xa5" => "\xef\xbd\x85",
+       "\xef\xbc\xa6" => "\xef\xbd\x86",
+       "\xef\xbc\xa7" => "\xef\xbd\x87",
+       "\xef\xbc\xa8" => "\xef\xbd\x88",
+       "\xef\xbc\xa9" => "\xef\xbd\x89",
+       "\xef\xbc\xaa" => "\xef\xbd\x8a",
+       "\xef\xbc\xab" => "\xef\xbd\x8b",
+       "\xef\xbc\xac" => "\xef\xbd\x8c",
+       "\xef\xbc\xad" => "\xef\xbd\x8d",
+       "\xef\xbc\xae" => "\xef\xbd\x8e",
+       "\xef\xbc\xaf" => "\xef\xbd\x8f",
+       "\xef\xbc\xb0" => "\xef\xbd\x90",
+       "\xef\xbc\xb1" => "\xef\xbd\x91",
+       "\xef\xbc\xb2" => "\xef\xbd\x92",
+       "\xef\xbc\xb3" => "\xef\xbd\x93",
+       "\xef\xbc\xb4" => "\xef\xbd\x94",
+       "\xef\xbc\xb5" => "\xef\xbd\x95",
+       "\xef\xbc\xb6" => "\xef\xbd\x96",
+       "\xef\xbc\xb7" => "\xef\xbd\x97",
+       "\xef\xbc\xb8" => "\xef\xbd\x98",
+       "\xef\xbc\xb9" => "\xef\xbd\x99",
+       "\xef\xbc\xba" => "\xef\xbd\x9a",
+       "\xf0\x90\x90\x80" => "\xf0\x90\x90\xa8",
+       "\xf0\x90\x90\x81" => "\xf0\x90\x90\xa9",
+       "\xf0\x90\x90\x82" => "\xf0\x90\x90\xaa",
+       "\xf0\x90\x90\x83" => "\xf0\x90\x90\xab",
+       "\xf0\x90\x90\x84" => "\xf0\x90\x90\xac",
+       "\xf0\x90\x90\x85" => "\xf0\x90\x90\xad",
+       "\xf0\x90\x90\x86" => "\xf0\x90\x90\xae",
+       "\xf0\x90\x90\x87" => "\xf0\x90\x90\xaf",
+       "\xf0\x90\x90\x88" => "\xf0\x90\x90\xb0",
+       "\xf0\x90\x90\x89" => "\xf0\x90\x90\xb1",
+       "\xf0\x90\x90\x8a" => "\xf0\x90\x90\xb2",
+       "\xf0\x90\x90\x8b" => "\xf0\x90\x90\xb3",
+       "\xf0\x90\x90\x8c" => "\xf0\x90\x90\xb4",
+       "\xf0\x90\x90\x8d" => "\xf0\x90\x90\xb5",
+       "\xf0\x90\x90\x8e" => "\xf0\x90\x90\xb6",
+       "\xf0\x90\x90\x8f" => "\xf0\x90\x90\xb7",
+       "\xf0\x90\x90\x90" => "\xf0\x90\x90\xb8",
+       "\xf0\x90\x90\x91" => "\xf0\x90\x90\xb9",
+       "\xf0\x90\x90\x92" => "\xf0\x90\x90\xba",
+       "\xf0\x90\x90\x93" => "\xf0\x90\x90\xbb",
+       "\xf0\x90\x90\x94" => "\xf0\x90\x90\xbc",
+       "\xf0\x90\x90\x95" => "\xf0\x90\x90\xbd",
+       "\xf0\x90\x90\x96" => "\xf0\x90\x90\xbe",
+       "\xf0\x90\x90\x97" => "\xf0\x90\x90\xbf",
+       "\xf0\x90\x90\x98" => "\xf0\x90\x91\x80",
+       "\xf0\x90\x90\x99" => "\xf0\x90\x91\x81",
+       "\xf0\x90\x90\x9a" => "\xf0\x90\x91\x82",
+       "\xf0\x90\x90\x9b" => "\xf0\x90\x91\x83",
+       "\xf0\x90\x90\x9c" => "\xf0\x90\x91\x84",
+       "\xf0\x90\x90\x9d" => "\xf0\x90\x91\x85",
+       "\xf0\x90\x90\x9e" => "\xf0\x90\x91\x86",
+       "\xf0\x90\x90\x9f" => "\xf0\x90\x91\x87",
+       "\xf0\x90\x90\xa0" => "\xf0\x90\x91\x88",
+       "\xf0\x90\x90\xa1" => "\xf0\x90\x91\x89",
+       "\xf0\x90\x90\xa2" => "\xf0\x90\x91\x8a",
+       "\xf0\x90\x90\xa3" => "\xf0\x90\x91\x8b",
+       "\xf0\x90\x90\xa4" => "\xf0\x90\x91\x8c",
+       "\xf0\x90\x90\xa5" => "\xf0\x90\x91\x8d"
+);
+
+# Base stuff useful to all UTF-8 based language files
+class LanguageUtf8 extends Language {
+
+    function ucfirst( $string ) {
+               # For most languages, this is a wrapper for ucfirst()
+               # But that doesn't work right in a UTF-8 locale
+               global $wikiUpperChars, $wikiLowerChars;
+        return preg_replace (
+               "/^([\\x00-\\x7f]|[\\xc0-\\xff][\\x80-\\xbf]*)/e",
+               "strtr ( \"\$1\" , \$wikiUpperChars )",
+               $string );
+       }
+       
+       function stripForSearch( $string ) {
+               # MySQL fulltext index doesn't grok utf-8, so we
+               # need to fold cases and convert to hex
+               global $wikiLowerChars;
+               return preg_replace(
+                 "/([\\xc0-\\xff][\\x80-\\xbf]*)/e",
+                 "'U8' . bin2hex( strtr( \"\$1\", \$wikiLowerChars ) )",
+                 $string );
+       }
+}
+
+?>
\ No newline at end of file
diff --git a/includes/ViewCountUpdate.php b/includes/ViewCountUpdate.php
new file mode 100644 (file)
index 0000000..676ce80
--- /dev/null
@@ -0,0 +1,21 @@
+<?
+# See deferred.doc
+
+class ViewCountUpdate {
+
+       var $mPageID;
+
+       function ViewCountUpdate( $pageid )
+       {
+               $this->mPageID = $pageid;
+       }
+
+       function doUpdate()
+       {
+               $sql = "UPDATE LOW_PRIORITY cur SET cur_counter=(1+cur_counter)," .
+                 "cur_timestamp=cur_timestamp WHERE cur_id={$this->mPageID}";
+               $res = wfQuery( $sql, "ViewCountUpdate::doUpdate" );
+       }
+}
+
+?>
diff --git a/install.php b/install.php
new file mode 100644 (file)
index 0000000..e4f5a60
--- /dev/null
@@ -0,0 +1,259 @@
+<?
+
+# Install software and create new empty database.
+#
+
+if ( ! ( is_readable( "./LocalSettings.php" )
+  && is_readable( "./AdminSettings.php" ) ) ) {
+       print "You must first create the files LocalSettings.php\n" .
+         "and AdminSettings.php based on the samples in the top\n" .
+         "source directory before running this install script.\n";
+       exit();
+}
+
+$DP = "./includes";
+include_once( "./LocalSettings.php" );
+include_once( "./AdminSettings.php" );
+
+if ( $wgUseTeX && ( ! is_executable( "./math/texvc" ) ) ) {
+       print "To use math functions, you must first compile texvc by\n" .
+         "running \"make\" in the math directory.\n";
+       exit();
+}
+
+umask( 000 );
+set_time_limit( 0 );
+
+#
+# Make the necessary directories
+#
+$dirs = array( $IP, $wgUploadDirectory, $wgStyleSheetDirectory, $wgTmpDirectory );
+foreach ( $dirs as $d ) { makedirectory( $d ); }
+
+#
+# Copy files into installation directories
+#
+print "Copying files...\n";
+
+copyfile( ".", "LocalSettings.php", $IP );
+copyfile( ".", "wiki.phtml", $IP );
+copyfile( ".", "redirect.phtml", $IP );
+copyfile( ".", "texvc.phtml", $IP );
+
+$handle = opendir( "./includes" );
+while ( false !== ( $f = readdir( $handle ) ) ) {
+       if ( "." == $f{0} ) continue;
+       copyfile( "./includes", $f, $IP );
+}
+
+$handle = opendir( "./stylesheets" );
+while ( false !== ( $f = readdir( $handle ) ) ) {
+       if ( "." == $f{0} ) continue;
+       copyfile( "./stylesheets", $f, $wgStyleSheetDirectory );
+}
+
+copyfile( "./images", "wiki.png", $wgUploadDirectory );
+copyfile( "./languages", "Language.php", $IP );
+copyfile( "./languages", "Language" . ucfirst( $wgLanguageCode ) . ".php", $IP );
+
+$fp = fopen( $wgDebugLogFile, "w" );
+if ( false === $fp ) {
+       print "Could not create log file \"{$wgDebugLogFile}\".\n";
+       exit();
+}
+$d = date( "Y-m-d H:i:s" );
+fwrite( $fp, "Wiki debug log file created {$d}\n\n" );
+fclose( $fp );
+
+if ( $wgUseTeX ) {
+       makedirectory( "{$IP}/math" );
+       makedirectory( $wgMathDirectory );
+       copyfile( "./math", "texvc", "{$IP}/math", 0775 );
+       copyfile( "./math", "texvc_test", "{$IP}/math", 0775 );
+       copyfile( "./math", "texvc_tex", "{$IP}/math", 0775 );
+}
+
+#
+# Make and initialize database
+#
+print "\n* * *\nWarning! This script will completely erase the\n" .
+  "existing database \"{$wgDBname}\" and all its contents.\n" .
+  "Are you sure you want to do this? (yes/no) ";
+
+$response = readconsole();
+if ( ! ( "Y" == $response{0} || "y" == $response{0} ) ) { exit(); }
+
+print "\nYou should have already created a root password for the database.\n" .
+  "Enter the root password here: ";
+
+$rootpw = readconsole();
+
+$rconn = mysql_connect( $wgDBserver, "root", $rootpw );
+if ( false === $rconn ) {
+       print "Could not connect to database on \"{$wgDBserver}\" as root.\n";
+       exit();
+}
+
+# Include rest of code to get things like internationalized messages.
+#
+include_once( "{$IP}/Setup.php" );
+$wgTitle = Title::newFromText( "Installation script" );
+
+# Now do the actual database creation
+#
+print "Creating database...\n";
+dbsource( $rconn, "./maintenance/database.sql" );
+
+mysql_select_db( $wgDBname, $rconn );
+dbsource( $rconn, "./maintenance/tables.sql" );
+dbsource( $rconn, "./maintenance/users.sql" );
+dbsource( $rconn, "./maintenance/initialdata.sql" );
+
+populatedata(); # Needs internationalized messages
+
+print "Adding indexes...\n";
+dbsource( $rconn, "./maintenance/indexes.sql" );
+
+print "Done.\nBrowse \"{$wgServer}{$wgScript}\" to test,\n" .
+  "or \"run WikiSuite -b -o\" in test suite.\n";
+exit();
+
+#
+# Functions used above:
+#
+function makedirectory( $d ) {
+       global $installOwner, $installGroup;
+
+       if ( is_dir( $d ) ) {
+               print "Directory \"{$d}\" exists.\n";
+       } else {
+               if ( mkdir( $d, 0777 ) ) {
+                       if ( isset( $installOwner ) ) { chown( $d, $installOwner ); }
+                       if ( isset( $installGroup ) ) { chgrp( $d, $installGroup ); }
+                       print "Directory \"{$d}\" created.\n";
+               } else {
+                       print "Could not create directory \"{$d}\".\n";
+                       exit();
+               }
+       }
+}
+
+function copyfile( $sdir, $name, $ddir, $perms = 0644 ) {
+       global $installOwner, $installGroup;
+
+       $d = "{$ddir}/{$name}";
+       if ( copy( "{$sdir}/{$name}", $d ) ) {
+               if ( isset( $installOwner ) ) { chown( $d, $installOwner ); }
+               if ( isset( $installGroup ) ) { chgrp( $d, $installGroup ); }
+               chmod( $d, $perms );
+               # print "Copied \"{$name}\" to \"{$ddir}\".\n";
+       } else {
+               print "Failed to copy file \"{$name}\" to \"{$ddir}\".\n";
+               exit();
+       }
+}
+
+function readconsole() {
+       $fp = fopen( "php://stdin", "r" );
+       $resp = trim( fgets( $fp ) );
+       fclose( $fp );
+       return $resp;
+}
+
+#
+# Read and execute SQL commands from a file
+#
+function dbsource( $conn, $fname ) {
+       $fp = fopen( $fname, "r" );
+       if ( false === $fp ) {
+               print "Could not open \"{$fname}\".\n";
+               exit();
+       }
+
+       $cmd = "";
+       $done = false;
+
+       while ( ! feof( $fp ) ) {
+               $line = trim( fgets( $fp ) );
+               $sl = strlen( $line ) - 1;
+
+               if ( $sl < 0 ) { continue; }
+               if ( "-" == $line{0} && "-" == $line{1} ) { continue; }
+
+               if ( ";" == $line{$sl} ) {
+                       $done = true;
+                       $line = substr( $line, 0, $sl );
+               }
+
+               if ( "" != $cmd ) { $cmd .= " "; }
+               $cmd .= $line;
+
+               if ( $done ) {
+                       $cmd = replacevars( $cmd );
+                       $res = mysql_query( $cmd, $conn );
+
+                       if ( false === $res ) {
+                               print "Query \"{$cmd}\" failed.\n";
+                               exit();
+                       }
+
+                       $cmd = "";
+                       $done = false;
+               }
+       }
+       fclose( $fp );
+}
+
+function replacevars( $ins ) {
+       $varnames = array(
+               "wgDBserver", "wgDBname", "wgDBintlname", "wgDBuser",
+               "wgDBpassword", "wgDBsqluser", "wgDBsqlpassword",
+               "wgDBadminuser", "wgDBadminpassword"
+       );
+
+       foreach ( $varnames as $var ) {
+               global $$var;
+               $ins = str_replace( '{$' . $var . '}', $$var, $ins );
+       }
+       return $ins;
+}
+
+function populatedata() {
+       global $wgDBadminpassword;
+       $fname = "Installation script: populatedata()";
+
+       $sql = "DELETE FROM site_stats";
+       wfQuery( $sql, $fname );
+
+       $sql = "INSERT INTO site_stats (ss_row_id,ss_total_views," .
+               "ss_total_edits,ss_good_articles) VALUES (1,0,0,0)";
+       wfQuery( $sql, $fname );
+
+       $sql = "DELETE FROM user";
+       wfQuery( $sql, $fname );
+
+       $sql = "INSERT INTO user (user_name, user_password, user_rights)" .
+         "VALUES ('WikiSysop','" . User::encryptPassword( $wgDBadminpassword ) .
+         "','sysop'),('WikiDeveloper','" . User::encryptPassword(
+         $wgDBadminpassword ) . "','sysop,developer')";
+       wfQuery( $sql, $fname );
+       
+       $wns = Namespace::getWikipedia();
+       $ulp = addslashes( wfMsg( "uploadlogpage" ) );
+       $dlp = addslashes( wfMsg( "dellogpage" ) );
+
+       $sql = "DELETE FROM cur";
+       wfQuery( $sql, $fname );
+
+       $sql = "INSERT INTO cur (cur_namespace,cur_title,cur_text," .
+         "cur_restrictions) VALUES ({$wns},'{$ulp}','" .
+         wfStrencode( wfMsg( "uploadlogpagetext" ) ) . "','sysop')";
+       wfQuery( $sql );
+
+       $sql = "INSERT INTO cur (cur_namespace,cur_title,cur_text," .
+         "cur_restrictions) VALUES ({$wns},'{$dlp}','" .
+         wfStrencode( wfMsg( "dellogpagetext" ) ) . "','sysop')";
+       wfQuery( $sql );
+}
+
+?>
diff --git a/languages/Language.php b/languages/Language.php
new file mode 100644 (file)
index 0000000..c089551
--- /dev/null
@@ -0,0 +1,1308 @@
+<?
+
+# NOTE: To turn off "Current Events" in the sidebar,
+# set "currentevents" => "-"
+
+# The names of the namespaces can be set here, but the numbers
+# are magical, so don't change or move them!  The Namespace class
+# encapsulates some of the magic-ness.
+#
+/* private */ $wgNamespaceNamesEn = array(
+       -1      => "Special",
+       0       => "",
+       1       => "Talk",
+       2       => "User",
+       3       => "User_talk",
+       4       => "Wikipedia",
+       5       => "Wikipedia_talk",
+       6       => "Image",
+       7       => "Image_talk"
+);
+
+/* private */ $wgDefaultUserOptionsEn = array(
+       "quickbar" => 1, "underline" => 1, "hover" => 1,
+       "cols" => 80, "rows" => 25, "searchlimit" => 20,
+       "contextlines" => 5, "contextchars" => 50,
+       "skin" => 0, "math" => 1, "rcdays" => 7, "rclimit" => 50,
+       "highlightbroken" => 1, "stubthreshold" => 0
+);
+
+/* private */ $wgQuickbarSettingsEn = array(
+       "None", "Fixed left", "Fixed right", "Floating left"
+);
+
+/* private */ $wgSkinNamesEn = array(
+       "Standard", "Nostalgia", "Cologne Blue"
+);
+
+/* private */ $wgMathNamesEn = array(
+       "Always render PNG",
+       "HTML if very simple or else PNG",
+       "HTML if possible or else PNG",
+       "Leave it as TeX (for text browsers)",
+       "Recommended for modern browsers"
+);
+
+/* private */ $wgUserTogglesEn = array(
+       "hover"         => "Show hoverbox over wiki links",
+       "underline" => "Underline links",
+       "highlightbroken" => "Format broken links <a href=\"\" class=\"new\">like
+this</a> (alternative: like this<a href=\"\" class=\"internal\">?</a>).",
+       "justify"       => "Justify paragraphs",
+       "hideminor" => "Hide minor edits in recent changes",
+       "usenewrc" => "Enhanced recent changes (not for all browsers)",
+       "numberheadings" => "Auto-number headings",
+       "rememberpassword" => "Remember password across sessions",
+       "editwidth" => "Edit box has full width",
+       "editondblclick" => "Edit pages on double click (JavaScript)",
+       "watchdefault" => "Watch new and modified articles",
+       "minordefault" => "Mark all edits minor by default",
+       "previewontop" => "Show preview before edit box and not after it"
+);
+
+/* private */ $wgBookstoreListEn = array(
+       "AddALL" => "http://www.addall.com/New/Partner.cgi?query=$1&type=ISBN",
+       "PriceSCAN" => "http://www.pricescan.com/books/bookDetail.asp?isbn=$1",
+       "Barnes & Noble" => "http://shop.barnesandnoble.com/bookSearch/isbnInquiry.asp?isbn=$1",
+       "Amazon.com" => "http://www.amazon.com/exec/obidos/ISBN=$1"
+);
+
+/* private */ $wgLanguageNamesEn = array(
+       "aa"    => "Afar",
+       "ab"    => "Abkhazian",
+       "af"    => "Afrikaans",
+       "am"    => "Amharic",
+       "ar" => "&#8238;&#1575;&#1604;&#1593;&#1585;&#1576;&#1610;&#1577;&#8236; (Araby)",
+       "as"    => "Assamese",
+       "ay"    => "Aymara",
+       "az"    => "Azerbaijani",
+       "ba"    => "Bashkir",
+       "be" => "&#1041;&#1077;&#1083;&#1072;&#1088;&#1091;&#1089;&#1082;&#1080;",
+       "bh"    => "Bihara",
+       "bi"    => "Bislama",
+       "bn"    => "Bengali",
+       "bo"    => "Tibetan",
+       "br" => "Brezhoneg",
+       "bs" => "Bosnian",
+       "ca" => "Catal&#224;",
+       "ch" => "Chamoru",
+       "co"    => "Corsican",
+       "cs" => "&#268;esk&#225;",
+       "cy" => "Cymraeg",
+       "da" => "Dansk", # Note two different subdomains.
+       "dk" => "Dansk", # 'da' is correct for the language.
+       "de" => "Deutsch",
+       "dz"    => "Bhutani",
+       "el" => "&#917;&#955;&#955;&#951;&#957;&#953;&#954;&#940; (Ellenika)",
+       "en"    => "English",
+       "eo"    => "Esperanto",
+       "es" => "Espa&#241;ol",
+       "et" => "Eesti",
+       "eu" => "Euskara",
+       "fa" => "&#8238;&#1601;&#1585;&#1587;&#1609;&#8236; (Farsi)",
+       "fi" => "Suomi",
+       "fj"    => "Fijian",
+       "fo"    => "Faeroese",
+       "fr" => "Fran&#231;ais",
+       "fy" => "Frysk",
+       "ga" => "Gaelige",
+       "gl"    => "Galician",
+       "gn"    => "Guarani",
+       "gu" => "&#2711;&#2753;&#2716;&#2736;&#2750;&#2724;&#2752; (Gujarati)",
+       "ha"    => "Hausa",
+       "he" => "&#1506;&#1489;&#1512;&#1497;&#1514; (Ivrit)",
+       "hi" => "&#2361;&#2367;&#2344;&#2381;&#2342;&#2368; (Hindi)",
+       "hr" => "Hrvatski",
+       "hu" => "Magyar",
+       "hy"    => "Armenian",
+       "ia"    => "Interlingua",
+       "id"    => "Indonesia",
+       "ik"    => "Inupiak",
+       "is" => "&#205;slenska",
+       "it" => "Italiano",
+       "iu"    => "Inuktitut",
+       "ja" => "&#26085;&#26412;&#35486; (Nihongo)",
+       "jv"    => "Javanese",
+       "ka" => "&#4325;&#4304;&#4320;&#4311;&#4309;&#4308;&#4314;&#4312; (Kartuli)",
+       "kk"    => "Kazakh",
+       "kl"    => "Greenlandic",
+       "km"    => "Cambodian",
+       "kn"    => "Kannada",
+       "ko" => "&#54620;&#44397;&#50612; (Hangukeo)",
+       "ks"    => "Kashmiri",
+       "kw" => "Kernewek",
+       "ky"    => "Kirghiz",
+       "la" => "Latina",
+       "ln"    => "Lingala",
+       "lo"    => "Laotian",
+       "lt" => "Lietuvi&#371;",
+       "lv"    => "Latvian",
+       "mg" => "Malagasy",
+       "mi"    => "Maori",
+       "mk"    => "Macedonian",
+       "ml"    => "Malayalam",
+       "mn"    => "Mongolian",
+       "mo"    => "Moldavian",
+       "mr"    => "Marathi",
+       "ms" => "Bahasa Melayu",
+       "my"    => "Burmese",
+       "na"    => "Nauru",
+       "ne" => "&#2344;&#2375;&#2346;&#2366;&#2354;&#2368; (Nepali)",
+       "nl" => "Nederlands",
+       "no" => "Norsk",
+       "oc"    => "Occitan",
+       "om"    => "Oromo",
+       "or"    => "Oriya",
+       "pa"    => "Punjabi",
+       "pl" => "Polski",
+       "ps"    => "Pashto",
+       "pt" => "Portugu&#234;s",
+       "qu"    => "Quechua",
+       "rm"    => "Rhaeto-Romance",
+       "rn"    => "Kirundi",
+       "ro" => "Rom&#226;n&#259;",
+       "ru" => "&#1056;&#1091;&#1089;&#1089;&#1082;&#1080;&#1081; (Russkij)",
+       "rw"    => "Kinyarwanda",
+       "sa" => "&#2360;&#2306;&#2360;&#2381;&#2325;&#2371;&#2340; (Samskrta)",
+       "sd"    => "Sindhi",
+       "sg"    => "Sangro",
+       "sh"    => "Serbocroatian",
+       "si"    => "Sinhalese",
+       "simple" => "Simple English",
+       "sk"    => "Slovak",
+       "sl"    => "Slovensko",
+       "sm"    => "Samoan",
+       "sn"    => "Shona",
+       "so" => "Soomaali",
+       "sq" => "Shqiptare",
+       "sr" => "Srpski",
+       "ss"    => "Siswati",
+       "st"    => "Sesotho",
+       "su"    => "Sudanese",
+       "sv" => "Svenska",
+       "sw" => "Kiswahili",
+       "ta"    => "Tamil",
+       "te"    => "Telugu",
+       "tg"    => "Tajik",
+       "th"    => "Thai",
+       "ti"    => "Tigrinya",
+       "tk"    => "Turkmen",
+       "tl"    => "Tagalog",
+       "tn"    => "Setswana",
+       "to"    => "Tonga",
+       "tr" => "T&#252;rk&#231;e",
+       "ts"    => "Tsonga",
+       "tt"    => "Tatar",
+       "tw"    => "Twi",
+       "ug"    => "Uighur",
+       "uk" => "&#1059;&#1082;&#1088;&#1072;&#1111;&#1085;&#1089;&#1100;&#1082;&#1072; (Ukrayins`ka)",
+       "ur"    => "Urdu",
+       "uz"    => "Uzbek",
+       "vi"    => "Vietnamese",
+       "vo" => "Volap&#252;k",
+       "wo"    => "Wolof",
+       "xh" => "isiXhosa",
+       "yi"    => "Yiddish",
+       "yo"    => "Yoruba",
+       "za"    => "Zhuang",
+       "zh" => "&#20013;&#25991; (Zhongwen)",
+       "zu"    => "Zulu"
+);
+
+/* private */ $wgWeekdayNamesEn = array(
+       "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
+       "Friday", "Saturday"
+);
+
+/* private */ $wgMonthNamesEn = array(
+       "January", "February", "March", "April", "May", "June",
+       "July", "August", "September", "October", "November",
+       "December"
+);
+
+/* private */ $wgMonthAbbreviationsEn = array(
+       "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug",
+       "Sep", "Oct", "Nov", "Dec"
+);
+
+# All special pages have to be listed here: a description of ""
+# will make them not show up on the "Special Pages" page, which
+# is the right thing for some of them (such as the "targeted" ones).
+#
+/* private */ $wgValidSpecialPagesEn = array(
+       "Userlogin"             => "",
+       "Userlogout"    => "",
+       "Preferences"   => "Set my user preferences",
+       "Watchlist"             => "My watchlist",
+       "Recentchanges" => "Recently updated pages",
+       "Upload"                => "Upload image files",
+       "Imagelist"             => "Image list",
+       "Listusers"             => "Registered users",
+       "Statistics"    => "Site statistics",
+       "Randompage"    => "Random article",
+
+       "Lonelypages"   => "Orphaned articles",
+       "Unusedimages"  => "Orphaned images",
+       "Popularpages"  => "Popular articles",
+       "Wantedpages"   => "Most wanted articles",
+       "Shortpages"    => "Short articles",
+       "Longpages"             => "Long articles",
+       "Newpages"              => "Newly created articles",
+       "Intl"          => "Interlanguage links",
+       "Allpages"              => "All pages by title",
+
+       "Ipblocklist"   => "Blocked IP addresses",
+       "Maintenance" => "Maintenance page",
+       "Specialpages"  => "",
+       "Contributions" => "",
+       "Emailuser"             => "",
+       "Whatlinkshere" => "",
+       "Recentchangeslinked" => "",
+       "Movepage"              => "",
+       "Booksources"   => "External book sources"
+);
+
+/* private */ $wgSysopSpecialPagesEn = array(
+       "Blockip"               => "Block an IP address",
+       "Asksql"                => "Query the database",
+       "Undelete"              => "Restore deleted pages"
+);
+
+/* private */ $wgDeveloperSpecialPagesEn = array(
+       "Lockdb"                => "Make database read-only",
+       "Unlockdb"              => "Restore DB write access",
+       "Debug"                 => "Debugging information"
+);
+
+/* private */ $wgAllMessagesEn = array(
+
+# Bits of text used by many pages:
+#
+"linktrail"            => "/^([a-z]+)(.*)\$/sD",
+"mainpage"             => "Main Page",
+"about"                        => "About",
+"aboutwikipedia" => "About Wikipedia",
+"aboutpage"            => "Wikipedia:About",
+"help"                 => "Help",
+"helppage"             => "Wikipedia:Help",
+"wikititlesuffix" => "Wikipedia",
+"bugreports"   => "Bug reports",
+"bugreportspage" => "Wikipedia:Bug_reports",
+"faq"                  => "FAQ",
+"faqpage"              => "Wikipedia:FAQ",
+"edithelp"             => "Editing help",
+"edithelppage" => "Wikipedia:How_does_one_edit_a_page",
+"cancel"               => "Cancel",
+"qbfind"               => "Find",
+"qbbrowse"             => "Browse",
+"qbedit"               => "Edit",
+"qbpageoptions" => "Page options",
+"qbpageinfo"   => "Page info",
+"qbmyoptions"  => "My options",
+"mypage"               => "My page",
+"mytalk"               => "My talk",
+"currentevents" => "Current events",
+"errorpagetitle" => "Error",
+"returnto"             => "Return to $1.",
+"fromwikipedia"        => "From Wikipedia, the free encyclopedia.",
+"whatlinkshere"        => "Pages that link here",
+"help"                 => "Help",
+"search"               => "Search",
+"go"           => "Go",
+"history"              => "Older versions",
+"printableversion" => "Printable version",
+"editthispage" => "Edit this page",
+"deletethispage" => "Delete this page",
+"protectthispage" => "Protect this page",
+"unprotectthispage" => "Unprotect this page",
+"newpage" => "New page",
+"talkpage"             => "Discuss this page",
+"articlepage"  => "View article",
+"subjectpage"  => "View subject", # For compatibility
+"userpage" => "View user page",
+"wikipediapage" => "View meta page",
+"imagepage" =>         "View image page",
+"viewtalkpage" => "View discussion",
+"otherlanguages" => "Other languages",
+"redirectedfrom" => "(Redirected from $1)",
+"lastmodified" => "It was last modified $1.",
+"viewcount"            => "This page has been accessed $1 times.",
+"gnunote" => "All text is available under the terms of the <a class=internal href='/wiki/GNU_FDL'>GNU Free Documentation License</a>.",
+"printsubtitle" => "(From http://www.wikipedia.org)",
+"protectedpage" => "Protected page",
+"administrators" => "Wikipedia:Administrators",
+"sysoptitle"   => "Sysop access required",
+"sysoptext"            => "The action you have requested can only be
+performed by users with \"sysop\" status.
+See $1.",
+"developertitle" => "Developer access required",
+"developertext"        => "The action you have requested can only be
+performed by users with \"developer\" status.
+See $1.",
+"nbytes"               => "$1 bytes",
+"go"                   => "Go",
+"ok"                   => "OK",
+"sitetitle"            => "Wikipedia",
+"sitesubtitle" => "The Free Encyclopedia",
+"retrievedfrom" => "Retrieved from \"$1\"",
+"newmessages" => "You have $1.",
+"newmessageslink" => "new messages",
+
+# Main script and global functions
+#
+"nosuchaction" => "No such action",
+"nosuchactiontext" => "The action specified by the URL is not
+recognized by the Wikipedia software",
+"nosuchspecialpage" => "No such special page",
+"nospecialpagetext" => "You have requested a special page that is not
+recognized by the Wikipedia software.",
+
+# General errors
+#
+"error"                        => "Error",
+"databaseerror" => "Database error",
+"dberrortext"  => "A database query syntax error has occurred.
+This could be because of an illegal search query (see $5),
+or it may indicate a bug in the software.
+The last attempted database query was:
+<blockquote><tt>$1</tt></blockquote>
+from within function \"<tt>$2</tt>\".
+MySQL returned error \"<tt>$3: $4</tt>\".",
+"noconnect"            => "Could not connect to DB on $1",
+"nodb"                 => "Could not select database $1",
+"readonly"             => "Database locked",
+"enterlockreason" => "Enter a reason for the lock, including an estimate
+of when the lock will be released",
+"readonlytext" => "The Wikipedia database is currently locked to new
+entries and other modifications, probably for routine database maintenance,
+after which it will be back to normal.
+The administrator who locked it offered this explanation:
+<p>$1",
+"missingarticle" => "The database did not find the text of a page
+that it should have found, named \"$1\".
+
+<p>This is usually caused by following an outdated diff or history link to a
+page that has been deleted.
+
+<p>If this is not the case, you may have found a bug in the software.
+Please report this to an administrator, making note of the URL.",
+"internalerror" => "Internal error",
+"filecopyerror" => "Could not copy file \"$1\" to \"$2\".",
+"filerenameerror" => "Could not rename file \"$1\" to \"$2\".",
+"filedeleteerror" => "Could not delete file \"$1\".",
+"filenotfound" => "Could not find file \"$1\".",
+"unexpected"   => "Unexpected value: \"$1\"=\"$2\".",
+"formerror"            => "Error: could not submit form",      
+"badarticleerror" => "This action cannot be performed on this page.",
+"cannotdelete" => "Could not delete the page or image specified. (It may have already been deleted by someone else.)",
+"badtitle"             => "Bad title",
+"badtitletext" => "The requested page title was invalid, empty, or
+an incorrectly linked inter-language or inter-wiki title.",
+"perfdisabled" => "Sorry! This feature has been temporarily disabled
+because it slows the database down to the point that no one can use
+the wiki. Which is bad. It will be rewritten for efficiency in the near
+future (possibly by you! we're open source after all)",
+
+# Login and logout pages
+#
+"logouttitle"  => "User logout",
+"logouttext"   => "You are now logged out.
+You can continue to use Wikipedia anonymously, or you can log in
+again as the same or as a different user.\n",
+
+"welcomecreation" => "<h2>Welcome, $1!</h2><p>Your account has been created.
+Don't forget to personalize your wikipedia preferences.",
+
+"loginpagetitle" => "User login",
+"yourname"             => "Your user name",
+"yourpassword" => "Your password",
+"yourpasswordagain" => "Retype password",
+"newusersonly" => " (new users only)",
+"remembermypassword" => "Remember my password across sessions.",
+"loginproblem" => "<b>There has been a problem with your login.</b><br>Try again!",
+"alreadyloggedin" => "<font color=red><b>User $1, you are already logged in!</b></font><br>\n",
+
+"areyounew"            => "If you are new to Wikipedia and want to get a user account,
+enter a user name, then type and re-type a password.
+Your e-mail address is optional; if you lose your password you can request
+that it be to the address you give.<br>\n",
+
+"login"                        => "Log in",
+"userlogin"            => "Log in",
+"logout"               => "Log out",
+"userlogout"   => "Log out",
+"createaccount"        => "Create new account",
+"badretype"            => "The passwords you entered do not match.",
+"userexists"   => "The user name you entered is already in use. Please choosea different name.",
+"youremail"            => "Your e-mail*",
+"yournick"             => "Your nickname (for signatures)",
+"emailforlost" => "* Entering an email address is optional.  But it enables people to
+contact you through the website without you having to reveal your 
+email address to them, and it also helps you if you forget your   
+password.",
+"loginerror"   => "Login error",
+"noname"               => "You have not specified a valid user name.",
+"loginsuccesstitle" => "Login successful",
+"loginsuccess" => "You are now logged in to Wikipedia as \"$1\".",
+"nosuchuser"   => "There is no user by the name \"$1\".
+Check your spelling, or use the form below to create a new user account.",
+"wrongpassword"        => "The password you entered is incorrect. Please try again.",
+"mailmypassword" => "Mail me a new password",
+"passwordremindertitle" => "Password reminder from Wikipedia",
+"passwordremindertext" => "Someone (probably you, from IP address $1)
+requested that we send you a new Wikipedia login password.
+The password for user \"$2\" is now \"$3\".
+You should log in and change your password now.",
+"noemail"              => "There is no e-mail address recorded for user \"$1\".",
+"passwordsent" => "A new password has been sent to the e-mail address
+registered for \"$1\".
+Please log in again after you receive it.",
+
+# Edit pages
+#
+"summary"              => "Summary",
+"minoredit"            => "This is a minor edit",
+"watchthis"            => "Watch this article",
+"savearticle"  => "Save page",
+"preview"              => "Preview",
+"showpreview"  => "Show preview",
+"blockedtitle" => "User is blocked",
+"blockedtext"  => "Your user name or IP address has been blocked by $1.
+The reason given is this:<br>''$2''<p>You may contact $1 or one of the other
+[[Wikipedia:administrators|administrators]] to discuss the block.",
+"newarticle"   => "(New)",
+"newarticletext" =>
+"You've followed a link to a page that doesn't exist yet.
+To create the page, start typing in the box below 
+(see the [[Wikipedia:Help|help page]] for more info).
+If you are here by mistake, just click your browser's '''back''' button.",
+"anontalkpagetext" => "---- ''This is the discussion page for an anonymous user who has not created an account yet or who does not use it. We therefore have to use the numerical [[IP address]] to identify him/her. Such an IP address can be shared by several users. If you are an anonymous user and feel that irrelevant comments have been directed at you, please [[Special:Userlogin|create an account or log in]] to avoid future confusion with other anonymous users.'' ",
+"noarticletext" => "(There is currently no text in this page)",
+"updated"              => "(Updated)",
+"note"                 => "<strong>Note:</strong> ",
+"previewnote"  => "Remember that this is only a preview, and has not yet been saved!",
+"previewconflict" => "This preview reflects the text in the upper
+text editing area as it will appear if you choose to save.",
+"editing"              => "Editing $1",
+"editconflict" => "Edit conflict: $1",
+"explainconflict" => "Someone else has changed this page since you
+started editing it.
+The upper text area contains the page text as it currently exists.
+Your changes are shown in the lower text area.
+You will have to merge your changes into the existing text.
+<b>Only</b> the text in the upper text area will be saved when you
+press \"Save page\".\n<p>",
+"yourtext"             => "Your text",
+"storedversion" => "Stored version",
+"editingold"   => "<strong>WARNING: You are editing an out-of-date
+revision of this page.
+If you save it, any changes made since this revision will be lost.</strong>\n",
+"yourdiff"             => "Differences",
+"copyrightwarning" => "Please note that all contributions to Wikipedia are
+considered to be released under the GNU Free Documentation License
+(see $1 for details).
+If you don't want your writing to be edited mercilessly and redistributed
+at will, then don't submit it here.<br>
+You are also promising us that you wrote this yourself, or copied it from a
+public domain or similar free resource.
+<strong>DO NOT SUBMIT COPYRIGHTED WORK WITHOUT PERMISSION!</strong>",
+"longpagewarning" => "WARNING: This page is $1 kilobytes long; some
+browsers may have problems editing pages approaching or longer than 32kb.
+Please consider breaking the page into smaller sections.",
+"readonlywarning" => "WARNING: The database has been locked for maintenance,
+so you will not be able to save your edits right now. You may wish to cut-n-paste
+the text into a text file and save it for later.",
+"protectedpagewarning" => "WARNING:  This page has been locked so that only
+users with sysop priveledges can edit it. Be sure you are following the
+<a href='/wiki/Wikipedia:Protected_page_guidelines'>protected page
+guidelines</a>.",
+
+# History pages
+#
+"revhistory"   => "Revision history",
+"nohistory"            => "There is no edit history for this page.",
+"revnotfound"  => "Revision not found",
+"revnotfoundtext" => "The old revision of the page you asked for could not be found.
+Please check the URL you used to access this page.\n",
+"loadhist"             => "Loading page history",
+"currentrev"   => "Current revision",
+"revisionasof" => "Revision as of $1",
+"cur"                  => "cur",
+"next"                 => "next",
+"last"                 => "last",
+"orig"                 => "orig",
+"histlegend"   => "Legend: (cur) = difference with current version,
+(last) = difference with preceding version, M = minor edit",
+
+# Diffs
+#
+"difference"   => "(Difference between revisions)",
+"loadingrev"   => "loading revision for diff",
+"lineno"               => "Line $1:",
+"editcurrent"  => "Edit the current version of this page",
+
+# Search results
+#
+"searchresults" => "Search results",
+"searchhelppage" => "Wikipedia:Searching",
+"searchingwikipedia" => "Searching Wikipedia",
+"searchresulttext" => "For more information about searching Wikipedia, see $1.",
+"searchquery"  => "For query \"$1\"",
+"badquery"             => "Badly formed search query",
+"badquerytext" => "We could not process your query.
+This is probably because you have attempted to search for a
+word fewer than three letters long, which is not yet supported.
+It could also be that you have mistyped the expression, for
+example \"fish and and scales\".
+Please try another query.",
+"matchtotals"  => "The query \"$1\" matched $2 article titles
+and the text of $3 articles.",
+"nogomatch" => "No page with this exact title exists, trying full text search.",
+"titlematches" => "Article title matches",
+"notitlematches" => "No article title matches",
+"textmatches"  => "Article text matches",
+"notextmatches"        => "No article text matches",
+"prevn"                        => "previous $1",
+"nextn"                        => "next $1",
+"viewprevnext" => "View ($1) ($2) ($3).",
+"showingresults" => "Showing below <b>$1</b> results starting with #<b>$2</b>.",
+"nonefound"            => "<strong>Note</strong>: unsuccessful searches are
+often caused by searching for common words like \"have\" and \"from\",
+which are not indexed, or by specifying more than one search term (only pages
+containing all of the search terms will appear in the result).",
+"powersearch" => "Search",
+"powersearchtext" => "
+Search in namespaces :<br>
+$1<br>
+$2 List redirects &nbsp; Search for $3 $9",
+
+
+# Preferences page
+#
+"preferences"  => "Preferences",
+"prefsnologin" => "Not logged in",
+"prefsnologintext"     => "You must be <a href=\"" .
+  wfLocalUrl( "Special:Userlogin" ) . "\">logged in</a>
+to set user preferences.",
+"prefslogintext" => "You are logged in as \"$1\".
+Your internal ID number is $2.",
+"prefsreset"   => "Preferences have been reset from storage.",
+"qbsettings"   => "Quickbar settings", 
+"changepassword" => "Change password",
+"skin"                 => "Skin",
+"math"                 => "Rendering math",
+"math_failure"         => "Failed to parse",
+"math_unknown_error"   => "unknown error",
+"math_unknown_function"        => "unknown function ",
+"math_lexing_error"    => "lexing error",
+"math_syntax_error"    => "syntax error",
+"saveprefs"            => "Save preferences",
+"resetprefs"   => "Reset preferences",
+"oldpassword"  => "Old password",
+"newpassword"  => "New password",
+"retypenew"            => "Retype new password",
+"textboxsize"  => "Textbox dimensions",
+"rows"                 => "Rows",
+"columns"              => "Columns",
+"searchresultshead" => "Search result settings",
+"resultsperpage" => "Hits to show per page",
+"contextlines" => "Lines to show per hit",
+"contextchars" => "Characters of context per line",
+"stubthreshold" => "Threshold for stub display",
+"recentchangescount" => "Number of titles in recent changes",
+"savedprefs"   => "Your preferences have been saved.",
+"timezonetext" => "Enter number of hours your local time differs
+from server time (UTC).",
+"localtime"    => "Local time",
+"timezoneoffset" => "Offset",
+"emailflag"            => "Disable e-mail from other users",
+
+# Recent changes
+#
+"changes" => "changes",
+"recentchanges" => "Recent changes",
+"recentchangestext" => "Track the most recent changes to Wikipedia on this page.
+[[Wikipedia:Welcome,_newcomers|Welcome, newcomers]]!
+Please have a look at these pages: [[wikipedia:FAQ|Wikipedia FAQ]],
+[[Wikipedia:Policies and guidelines|Wikipedia policy]]
+(especially [[wikipedia:Naming conventions|naming conventions]],
+[[wikipedia:Neutral point of view|neutral point of view]]),
+and [[wikipedia:Most common Wikipedia faux pas|most common Wikipedia faux pas]].
+
+If you want to see Wikipedia succeed, it's very important that you don't add
+material restricted by others' [[wikipedia:Copyrights|copyrights]].
+The legal liability could really hurt the project, so please don't do it.
+See also the [http://meta.wikipedia.org/wiki/Special:Recentchanges recent meta discussion].",
+"rcloaderr"            => "Loading recent changes",
+"rcnote"               => "Below are the last <strong>$1</strong> changes in last <strong>$2</strong> days.",
+"rcnotefrom"   => "Below are the changes since <b>$2</b> (up to <b>$1</b> shown).",
+"rclistfrom"   => "Show new changes starting from $1",
+# "rclinks"            => "Show last $1 changes in last $2 hours / last $3 days",
+"rclinks"              => "Show last $1 changes in last $2 days.",
+"rchide"               => "in $4 form; $1 minor edits; $2 secondary namespaces; $3 multiple edits.",
+"diff"                 => "diff",
+"hist"                 => "hist",
+"hide"                 => "hide",
+"show"                 => "show",
+"tableform"            => "table",
+"listform"             => "list",
+"nchanges"             => "$1 changes",
+"minoreditletter" => "M",
+"newpageletter" => "N",
+
+# Upload
+#
+"upload"               => "Upload file",
+"uploadbtn"            => "Upload file",
+"uploadlink"   => "Upload images",
+"reupload"             => "Re-upload",
+"reuploaddesc" => "Return to the upload form.",
+"uploadnologin" => "Not logged in",
+"uploadnologintext"    => "You must be <a href=\"" .
+  wfLocalUrl( "Special:Userlogin" ) . "\">logged in</a>
+to upload files.",
+"uploadfile"   => "Upload file",
+"uploaderror"  => "Upload error",
+"uploadtext"   => "<strong>STOP!</strong> Before you upload here,
+make sure to read and follow Wikipedia's <a href=\"" .
+wfLocalUrlE( "Wikipedia:Image_use_policy" ) . "\">image use policy</a>.
+<p>To view or search previously uploaded images,
+go to the <a href=\"" . wfLocalUrlE( "Special:Imagelist" ) .
+"\">list of uploaded images</a>.
+Uploads and deletions are logged on the <a href=\"" .
+wfLocalUrlE( "Wikipedia:Upload_log" ) . "\">upload log</a>.
+<p>Use the form below to upload new image files for use in
+illustrating your articles.
+On most browsers, you will see a \"Browse...\" button, which will
+bring up your operating system's standard file open dialog.
+Choosing a file will fill the name of that file into the text
+field next to the button.
+You must also check the box affirming that you are not
+violating any copyrights by uploading the file.
+Press the \"Upload\" button to finish the upload.
+This may take some time if you have a slow internet connection.
+<p>The preferred formats are JPEG for photographic images, PNG
+for drawings and other iconic images, and OGG for sounds.
+Please name your files descriptively to avoid confusion.
+To include the image in an article, use a link in the form
+<b>[[image:file.jpg]]</b> or <b>[[image:file.png|alt text]]</b>
+or <b>[[media:file.ogg]]</b> for sounds.
+<p>Please note that as with Wikipedia pages, others may edit or
+delete your uploads if they think it serves the encyclopedia, and
+you may be blocked from uploading if you abuse the system.",
+"uploadlog"            => "upload log",
+"uploadlogpage" => "Upload_log",
+"uploadlogpagetext" => "Below is a list of the most recent file uploads.
+All times shown are server time (UTC).
+<ul>
+</ul>
+",
+"filename"             => "Filename",
+"filedesc"             => "Summary",
+"affirmation"  => "I affirm that the copyright holder of this file
+agrees to license it under the terms of the $1.",
+"copyrightpage" => "Wikipedia:Copyrights",
+"copyrightpagename" => "Wikipedia copyright",
+"uploadedfiles"        => "Uploaded files",
+"noaffirmation" => "You must affirm that your upload does not violate
+any copyrights.",
+"ignorewarning"        => "Ignore warning and save file anyway.",
+"minlength"            => "Image names must be at least three letters.",
+"badfilename"  => "Image name has been changed to \"$1\".",
+"badfiletype"  => "\".$1\" is not a recommended image file format.",
+"largefile"            => "It is recommended that images not exceed 100k in size.",
+"successfulupload" => "Successful upload",
+"fileuploaded" => "File \"$1\" uploaded successfully.
+Please follow this link: ($2) to the description page and fill
+in information about the file, such as where it came from, when it was
+created and by whom, and anything else you may know about it.",
+"uploadwarning" => "Upload warning",
+"savefile"             => "Save file",
+"uploadedimage" => "uploaded \"$1\"",
+
+# Image list
+#
+"imagelist"            => "Image list",
+"imagelisttext"        => "Below is a list of $1 images sorted $2.",
+"getimagelist" => "fetching image list",
+"ilshowmatch"  => "Show all images with names matching",
+"ilsubmit"             => "Search",
+"showlast"             => "Show last $1 images sorted $2.",
+"all"                  => "all",
+"byname"               => "by name",
+"bydate"               => "by date",
+"bysize"               => "by size",
+"imgdelete"            => "del",
+"imgdesc"              => "desc",
+"imglegend"            => "Legend: (desc) = show/edit image description.",
+"imghistory"   => "Image history",
+"revertimg"            => "rev",
+"deleteimg"            => "del",
+"imghistlegend" => "Legend: (cur) = this is the current image, (del) = delete
+this old version, (rev) = revert to this old version.
+<br><i>Click on date to see image uploaded on that date</i>.",
+"imagelinks"   => "Image links",
+"linkstoimage" => "The following pages link to this image:",
+"nolinkstoimage" => "There are no pages that link to this image.",
+
+# Statistics
+#
+"statistics"   => "Statistics",
+"sitestats"            => "Site statistics",
+"userstats"            => "User statistics",
+"sitestatstext" => "There are <b>$1</b> total pages in the database.
+This includes \"talk\" pages, pages about Wikipedia, minimal \"stub\"
+pages, redirects, and others that probably don't qualify as articles.
+Excluding those, there are <b>$2</b> pages that are probably legitimate
+articles.<p>
+There have been a total of <b>$3</b> page views, and <b>$4</b> page edits
+since the software was upgraded (July 20, 2002).
+That comes to <b>$5</b> average edits per page, and <b>$6</b> views per edit.",
+"userstatstext" => "There are <b>$1</b> registered users.
+<b>$2</b> of these are administrators (see $3).",
+
+# Maintenance Page
+#
+"maintenance"          => "Maintenance page",
+"maintnancepagetext"   => "This page includes several handy tools for everyday maintenance. Some of these functions tend to stress the database, so please do not hit reload after every item you fixed ;-)",
+"maintenancebacklink"  => "Back to Maintenance Page",
+"disambiguations"      => "Disambiguation pages",
+"disambiguationspage"  => "Wikipedia:Links_to_disambiguating_pages",
+"disambiguationstext"  => "The following articles link to a <i>disambiguation page</i>. They should link to the appropriate topic instead.<br>A page is treated as dismbiguation if it is linked from $1.<br>Links from other namespaces are <i>not</i> listed here.",
+"doubleredirects"      => "Double Redirects",
+"doubleredirectstext"  => "<b>Attention:</b> This list may contain false positives. That usually means there is additional text with links below the first #REDIRECT.<br>\nEach row contains links to the first and second redirect, as well as the first line of the second redirect text, usually giving the \"real\" taget article, which the first redirect should point to.",
+"brokenredirects"      => "Broken Redirects",
+"brokenredirectstext"  => "The following redirects link to a non-existing article.",
+"selflinks"            => "Pages with Self Links",
+"selflinkstext"                => "The following pages contain a link to themselves, which they should not.",
+"mispeelings"           => "Pages with misspellings",
+"mispeelingstext"               => "The following pages contain a common misspelling, which are listed on $1. The correct spelling might be given (like this).",
+"mispeelingspage"       => "List of common misspellings",
+"missinglanguagelinks"  => "Missing Language Links",
+"missinglanguagelinksbutton"    => "Find missing language links for",
+"missinglanguagelinkstext"      => "These articles do <i>not</i> link to their counterpart in $1. Redirects and subpages are <i>not</i> shown.",
+
+
+# Miscellaneous special pages
+#
+"orphans"              => "Orphaned pages",
+"lonelypages"  => "Orphaned pages",
+"unusedimages" => "Unused images",
+"popularpages" => "Popular pages",
+"nviews"               => "$1 views",
+"wantedpages"  => "Wanted pages",
+"nlinks"               => "$1 links",
+"allpages"             => "All pages",
+"randompage"   => "Random page",
+"shortpages"   => "Short pages",
+"longpages"            => "Long pages",
+"listusers"            => "User list",
+"specialpages" => "Special pages",
+"spheading"            => "Special pages",
+"sysopspheading" => "Special pages for sysop use",
+"developerspheading" => "Special pages for developer use",
+"protectpage"  => "Protect page",
+"recentchangeslinked" => "Related changes",
+"rclsub"               => "(to pages linked from \"$1\")",
+"debug"                        => "Debug",
+"newpages"             => "New pages",
+"intl"         => "Interlanguage links",
+"movethispage" => "Move this page",
+"unusedimagestext" => "<p>Please note that other web sites
+such as the international Wikipedias may link to an image with
+a direct URL, and so may still be listed here despite being
+in active use.",
+"booksources"  => "Book sources",
+"booksourcetext" => "Below is a list of links to other sites that
+sell new and used books, and may also have further information
+about books you are looking for.
+Wikipedia is not affiliated with any of these businesses, and
+this list should not be construed as an endorsement.",
+"alphaindexline" => "$1 to $2",
+
+# Email this user
+#
+"mailnologin"  => "No send address",
+"mailnologintext" => "You must be <a href=\"" .
+  wfLocalUrl( "Special:Userlogin" ) . "\">logged in</a>
+and have a valid e-mail address in your <a href=\"" .
+  wfLocalUrl( "Special:Preferences" ) . "\">preferences</a>
+to send e-mail to other users.",
+"emailuser"            => "E-mail this user",
+"emailpage"            => "E-mail user",
+"emailpagetext"        => "If this user has entered a valid e-mail address in
+his or her user preferences, the form below will send a single message.
+The e-mail address you entered in your user preferences will appear
+as the \"From\" address of the mail, so the recipient will be able
+to reply.",
+"noemailtitle" => "No e-mail address",
+"noemailtext"  => "This user has not specified a valid e-mail address,
+or has chosen not to receive e-mail from other users.",
+"emailfrom"            => "From",
+"emailto"              => "To",
+"emailsubject" => "Subject",
+"emailmessage" => "Message",
+"emailsend"            => "Send",
+"emailsent"            => "E-mail sent",
+"emailsenttext" => "Your e-mail message has been sent.",
+
+# Watchlist
+#
+"watchlist"            => "My watchlist",
+"watchlistsub" => "(for user \"$1\")",
+"nowatchlist"  => "You have no items on your watchlist.",
+"watchnologin" => "Not logged in",
+"watchnologintext"     => "You must be <a href=\"" .
+  wfLocalUrl( "Special:Userlogin" ) . "\">logged in</a>
+to modify your watchlist.",
+"addedwatch"   => "Added to watchlist",
+"addedwatchtext" => "The page \"$1\" has been added to your <a href=\"" .
+  wfLocalUrl( "Special:Watchlist" ) . "\">watchlist</a>.
+Future changes to this page and its associated Talk page will be listed there,
+and the page will appear <b>bolded</b> in the <a href=\"" .
+  wfLocalUrl( "Special:Recentchanges" ) . "\">list of recent changes</a> to
+make it easier to pick out.</p>
+
+<p>If you want to remove the page from your watchlist later, click \"Stop watching\" in the sidebar.",
+"removedwatch" => "Removed from watchlist",
+"removedwatchtext" => "The page \"$1\" has been removed from your watchlist.",
+"watchthispage"        => "Watch this page",
+"unwatchthispage" => "Stop watching",
+"notanarticle" => "Not an article",
+
+# Delete/protect/revert
+#
+"deletepage"   => "Delete page",
+"confirm"              => "Confirm",
+"confirmdelete" => "Confirm delete",
+"deletesub"            => "(Deleting \"$1\")",
+"confirmdeletetext" => "You are about to permanently delete a page
+or image along with all of its history from the database.
+Please confirm that you intend to do this, that you understand the
+consequences, and that you are doing this in accordance with
+[[Wikipedia:Policy]].",
+"confirmcheck" => "Yes, I really want to delete this.",
+"actioncomplete" => "Action complete",
+"deletedtext"  => "\"$1\" has been deleted.
+See $2 for a record of recent deletions.",
+"deletedarticle" => "deleted \"$1\"",
+"dellogpage"   => "Deletion_log",
+"dellogpagetext" => "Below is a list of the most recent deletions.
+All times shown are server time (UTC).
+<ul>
+</ul>
+",
+"deletionlog"  => "deletion log",
+"reverted"             => "Reverted to earlier revision",
+"deletecomment"        => "Reason for deletion",
+"imagereverted" => "Revert to earlier version was successful.",
+"rollback"             => "Roll back edits",
+"rollbacklink" => "rollback",
+"cantrollback" => "Can't revert edit; last contributor is only author of this article.",
+"revertpage"   => "Reverted to last edit by $1",
+
+# Undelete
+"undelete" => "Restore deleted page",
+"undeletepage" => "View and restore deleted pages",
+"undeletepagetext" => "The following pages have been deleted but are still in the archive and
+can be restored. The archive may be periodically cleaned out.",
+"undeletearticle" => "Restore deleted article",
+"undeleterevisions" => "$1 revisions archived",
+"undeletehistory" => "If you restore the page, all revisions will be restored to the history.
+If a new page with the same name has been created since the deletion, the restored
+revisions will appear in the prior history, and the current revision of the live page
+will not be automatically replaced.",
+"undeleterevision" => "Deleted revision as of $1",
+"undeletebtn" => "Restore!",
+"undeletedarticle" => "restored \"$1\"",
+"undeletedtext"   => "The article [[$1]] has been successfully restored.
+See [[Wikipedia:Deletion_log]] for a record of recent deletions and restorations.",
+
+# Contributions
+#
+"contributions"        => "User contributions",
+"mycontris" => "My contributions",
+"contribsub"   => "For $1",
+"nocontribs"   => "No changes were found matching these criteria.",
+"ucnote"               => "Below are this user's last <b>$1</b> changes in the last <b>$2</b> days.",
+"uclinks"              => "View the last $1 changes; view the last $2 days.",
+"uctop"                => " (top)" ,
+
+# What links here
+#
+"whatlinkshere"        => "What links here",
+"notargettitle" => "No target",
+"notargettext" => "You have not specified a target page or user
+to perform this function on.",
+"linklistsub"  => "(List of links)",
+"linkshere"            => "The following pages link to here:",
+"nolinkshere"  => "No pages link to here.",
+"isredirect"   => "redirect page",
+
+# Block/unblock IP
+#
+"blockip"              => "Block IP address",
+"blockiptext"  => "Use the form below to block write access
+from a specific IP address.
+This should be done only only to prevent vandalism, and in
+accordance with [[Wikipedia:Policy|Wikipedia policy]].
+Fill in a specific reason below (for example, citing particular
+pages that were vandalized).",
+"ipaddress"            => "IP Address",
+"ipbreason"            => "Reason",
+"ipbsubmit"            => "Block this address",
+"badipaddress" => "The IP address is badly formed.",
+"noblockreason" => "You must supply a reason for the block.",
+"blockipsuccesssub" => "Block succeeded",
+"blockipsuccesstext" => "The IP address \"$1\" has been blocked.
+<br>See [[Special:Ipblocklist|IP block list]] to review blocks.",
+"unblockip"            => "Unblock IP address",
+"unblockiptext"        => "Use the form below to restore write access
+to a previously blocked IP address.",
+"ipusubmit"            => "Unblock this address",
+"ipusuccess"   => "IP address \"$1\" unblocked",
+"ipblocklist"  => "List of blocked IP addresses",
+"blocklistline"        => "$1, $2 blocked $3",
+"blocklink"            => "block",
+"unblocklink"  => "unblock",
+"contribslink" => "contribs",
+
+# Developer tools
+#
+"lockdb"               => "Lock database",
+"unlockdb"             => "Unlock database",
+"lockdbtext"   => "Locking the database will suspend the ability of all
+users to edit pages, change their preferences, edit their watchlists, and
+other things requiring changes in the database.
+Please confirm that this is what you intend to do, and that you will
+unlock the database when your maintenance is done.",
+"unlockdbtext" => "Unlocking the database will restore the ability of all
+users to edit pages, change their preferences, edit their watchlists, and
+other things requiring changes in the database.
+Please confirm that this is what you intend to do.",
+"lockconfirm"  => "Yes, I really want to lock the database.",
+"unlockconfirm"        => "Yes, I really want to unlock the database.",
+"lockbtn"              => "Lock database",
+"unlockbtn"            => "Unlock database",
+"locknoconfirm" => "You did not check the confirmation box.",
+"lockdbsuccesssub" => "Database lock succeeded",
+"unlockdbsuccesssub" => "Database lock removed",
+"lockdbsuccesstext" => "The Wikipedia database has been locked.
+<br>Remember to remove the lock after your maintenance is complete.",
+"unlockdbsuccesstext" => "The Wikipedia database has been unlocked.",
+
+# SQL query
+#
+"asksql"               => "SQL query",
+"asksqltext"   => "Use the form below to make a direct query of the
+Wikipedia database.
+Use single quotes ('like this') to delimit string literals.
+This can often add considerable load to the server, so please use
+this function sparingly.",
+"sqlquery"             => "Enter query",
+"querybtn"             => "Submit query",
+"selectonly"   => "Queries other than \"SELECT\" are restricted to
+Wikipedia developers.",
+"querysuccessful" => "Query successful",
+
+# Move page
+#
+"movepage"             => "Move page",
+"movepagetext" => "Using the form below will rename a page, moving all
+of its history to the new name.
+The old title will become a redirect page to the new title.
+Links to the old page title will not be changed; be sure to
+[[Special:Maintenance|check]] for double or broken redirects.
+You are responsible for making sure that links continue to
+point where they are supposed to go.
+
+Note that the page will '''not''' be moved if there is already
+a page at the new title, unless it is empty or a redirect and has no
+past edit history. This means that you can rename a page back to where
+it was just renamed from if you make a mistake, and you cannot overwrite
+an existing page.
+
+<b>WARNING!</b>
+This can be a drastic and unexpected change for a popular page;
+please be sure you understand the consequences of this before
+proceeding.",
+"movepagetalktext" => "The associated talk page, if any, will be automatically moved along with it '''unless:'''
+*You are moving the page across namespaces,
+*A non-empty talk page already exists under the new name, or
+*You uncheck the box below.
+
+In those cases, you will have to move or merge the page manually if desired.",
+"movearticle"  => "Move page",
+"movenologin"  => "Not logged in",
+"movenologintext" => "You must be a registered user and <a href=\"" .
+  wfLocalUrl( "Special:Userlogin" ) . "\">logged in</a>
+to move a page.",
+"newtitle"             => "To new title",
+"movepagebtn"  => "Move page",
+"pagemovedsub" => "Move succeeded",
+"pagemovedtext" => "Page \"[[$1]]\" moved to \"[[$2]]\".",
+"articleexists" => "A page of that name already exists, or the
+name you have chosen is not valid.
+Please choose another name.",
+"talkexists"   => "The page itself was moved successfully, but the
+talk page could not be moved because one already exists at the new
+title. Please merge them manually.",
+"movedto"              => "moved to",
+"movetalk"             => "Move \"talk\" page as well, if applicable.",
+"talkpagemoved" => "The corresponding talk page was also moved.",
+"talkpagenotmoved" => "The corresponding talk page was <strong>not</strong> moved.",
+
+);
+
+class Language {
+
+       function getDefaultUserOptions () {
+               global $wgDefaultUserOptionsEn ;
+               return $wgDefaultUserOptionsEn ;
+               }
+
+       function getBookstoreList () {
+               global $wgBookstoreListEn ;
+               return $wgBookstoreListEn ;
+       }
+
+       function getNamespaces() {
+               global $wgNamespaceNamesEn;
+               return $wgNamespaceNamesEn;
+       }
+
+       function getNsText( $index ) {
+               global $wgNamespaceNamesEn;
+               return $wgNamespaceNamesEn[$index];
+       }
+
+       function getNsIndex( $text ) {
+               global $wgNamespaceNamesEn;
+
+               foreach ( $wgNamespaceNamesEn as $i => $n ) {
+                       if ( 0 == strcasecmp( $n, $text ) ) { return $i; }
+               }
+               return false;
+       }
+
+       function specialPage( $name ) {
+               return $this->getNsText( Namespace::getSpecial() ) . ":" . $name;
+       }
+
+       function getQuickbarSettings() {
+               global $wgQuickbarSettingsEn;
+               return $wgQuickbarSettingsEn;
+       }
+
+       function getSkinNames() {
+               global $wgSkinNamesEn;
+               return $wgSkinNamesEn;
+       }
+
+       function getMathNames() {
+               global $wgMathNamesEn;
+               return $wgMathNamesEn;
+       }
+
+       function getUserToggles() {
+               global $wgUserTogglesEn;
+               return $wgUserTogglesEn;
+       }
+
+       function getLanguageNames() {
+               global $wgLanguageNamesEn;
+               return $wgLanguageNamesEn;
+       }
+
+       function getLanguageName( $code ) {
+               global $wgLanguageNamesEn;
+               if ( ! array_key_exists( $code, $wgLanguageNamesEn ) ) {
+                       return "";
+               }
+               return $wgLanguageNamesEn[$code];
+       }
+
+       function getMonthName( $key )
+       {
+               global $wgMonthNamesEn;
+               return $wgMonthNamesEn[$key-1];
+       }
+
+       /* by default we just return base form */
+       function getMonthNameGen( $key )
+       {
+               global $wgMonthNamesEn;
+               return $wgMonthNamesEn[$key-1];
+       }
+
+       function getMonthAbbreviation( $key )
+       {
+               global $wgMonthAbbreviationsEn;
+               return $wgMonthAbbreviationsEn[$key-1];
+       }
+
+       function getWeekdayName( $key )
+       {
+               global $wgWeekdayNamesEn;
+               return $wgWeekdayNamesEn[$key-1];
+       }
+
+       function userAdjust( $ts )
+       {
+               global $wgUser, $wgLocalTZoffset;
+
+               $diff = $wgUser->getOption( "timecorrection" );
+               if ( ! is_numeric( $diff ) ) {
+                       $diff = isset( $wgLocalTZoffset ) ? $wgLocalTZoffset : 0;
+               }
+               if ( 0 == $diff ) { return $ts; }
+
+               $t = mktime( ( (int)substr( $ts, 8, 2) ) + $diff,
+                 (int)substr( $ts, 10, 2 ), (int)substr( $ts, 12, 2 ),
+                 (int)substr( $ts, 4, 2 ), (int)substr( $ts, 6, 2 ),
+                 (int)substr( $ts, 0, 4 ) );
+               return date( "YmdHis", $t );
+       }
+       function date( $ts, $adj = false )
+       {
+               global $wgAmericanDates;
+               if ( $adj ) { $ts = $this->userAdjust( $ts ); }
+
+               if( $wgAmericanDates ) {
+                       $d = $this->getMonthAbbreviation( substr( $ts, 4, 2 ) ) .
+                         " " . (0 + substr( $ts, 6, 2 )) . ", " .
+                         substr( $ts, 0, 4 );
+               } else {
+                       $d = (0 + substr( $ts, 6, 2 )) . " " .
+                         $this->getMonthAbbreviation( substr( $ts, 4, 2 ) ) . " " .
+                         substr( $ts, 0, 4 );
+               }
+               return $d;
+       }
+
+       function time( $ts, $adj = false )
+       {
+               if ( $adj ) { $ts = $this->userAdjust( $ts ); }
+
+               $t = substr( $ts, 8, 2 ) . ":" . substr( $ts, 10, 2 );
+               return $t;
+       }
+
+       function timeanddate( $ts, $adj = false )
+       {
+               return $this->time( $ts, $adj ) . " " . $this->date( $ts, $adj );
+       }
+
+       function rfc1123( $ts )
+       {
+               return date( "D, d M Y H:i:s T", $ts );
+       }
+
+       function getValidSpecialPages()
+       {
+               global $wgValidSpecialPagesEn;
+               return $wgValidSpecialPagesEn;
+       }
+
+       function getSysopSpecialPages()
+       {
+               global $wgSysopSpecialPagesEn;
+               return $wgSysopSpecialPagesEn;
+       }
+
+       function getDeveloperSpecialPages()
+       {
+               global $wgDeveloperSpecialPagesEn;
+               return $wgDeveloperSpecialPagesEn;
+       }
+
+       function getMessage( $key )
+       {
+               global $wgAllMessagesEn;
+               return $wgAllMessagesEn[$key];
+       }
+       
+       function iconv( $in, $out, $string ) {
+               # For most languages, this is a wrapper for iconv
+               return iconv( $in, $out, $string );
+       }
+       
+       function ucfirst( $string ) {
+               # For most languages, this is a wrapper for ucfirst()
+               return ucfirst( $string );
+       }
+       
+       function checkTitleEncoding( $s ) {
+        global $wgInputEncoding;
+               
+        # Check for UTF-8 URLs; Internet Explorer produces these if you
+               # type non-ASCII chars in the URL bar or follow unescaped links.
+        $ishigh = preg_match( '/[\x80-\xff]/', $s);
+               $isutf = ($ishigh ? preg_match( '/^([\x00-\x7f]|[\xc0-\xdf][\x80-\xbf]|' .
+                '[\xe0-\xef][\x80-\xbf]{2}|[\xf0-\xf7][\x80-\xbf]{3})+$/', $s ) : true );
+
+               if( ($wgInputEncoding != "utf-8") and $ishigh and $isutf )
+                       return iconv( "UTF-8", $wgInputEncoding, $s );
+               
+               if( ($wgInputEncoding == "utf-8") and $ishigh and !$isutf )
+                       return utf8_encode( $s );
+               
+               # Other languages can safely leave this function, or replace
+               # it with one to detect and convert another legacy encoding.
+               return $s;
+       }
+       
+       function stripForSearch( $in ) {
+               # Some languages have special punctuation to strip out
+               # or characters which need to be converted for MySQL's
+               # indexing to grok it correctly. Make such changes here.
+               return $in;
+       }
+
+
+       function setAltEncoding() {
+               # Some languages may have an alternate char encoding option
+               # (Esperanto X-coding, Japanese furigana conversion, etc)
+               # If 'altencoding' is checked in user prefs, this gives a
+               # chance to swap out the default encoding settings.
+               #global $wgInputEncoding, $wgOutputEncoding, $wgEditEncoding;
+       }
+
+       function recodeForEdit( $s ) {
+               # For some languages we'll want to explicitly specify
+               # which characters make it into the edit box raw
+               # or are converted in some way or another.
+               # Note that if wgOutputEncoding is different from
+               # wgInputEncoding, this text will be further converted
+               # to wgOutputEncoding.
+               global $wgInputEncoding, $wgEditEncoding;
+               if( $wgEditEncoding == "" or
+                 $wgEditEncoding == $wgInputEncoding ) {
+                       return $s;
+               } else {
+                       return $this->iconv( $wgInputEncoding, $wgEditEncoding, $s );
+               }
+       }
+
+       function recodeInput( $s ) {
+               # Take the previous into account.
+               global $wgInputEncoding, $wgOutputEncoding, $wgEditEncoding;
+               if($wgEditEncoding != "") {
+                       $enc = $wgEditEncoding;
+               } else {
+                       $enc = $wgOutputEncoding;
+               }
+               if( $enc == $wgInputEncoding ) {
+                       return $s;
+               } else {
+                       return $this->iconv( $enc, $wgInputEncoding, $s );
+               }
+       }
+
+}
+
+global $IP;
+@include_once( "$IP/Language" . ucfirst( $wgLanguageCode ) . ".php" );
+
+?>
diff --git a/languages/LanguageCs.php b/languages/LanguageCs.php
new file mode 100644 (file)
index 0000000..ed26641
--- /dev/null
@@ -0,0 +1,1002 @@
+<?
+
+# See language.doc
+
+# The names of the namespaces can be set here, but the numbers
+# are magical, so don't change or move them!  The Namespace class
+# encapsulates some of the magic-ness.
+#
+/* private */ $wgNamespaceNamesCs = array(
+       -1      => "Speciální", # FIXME Is it safe to change this?
+       0       => "",
+       1       => "Diskuse", # neb diskutuj?
+       2       => "Wikipediista",
+       3       => "Wikipediista_diskuse",
+       4       => "Wikipedie",
+       5       => "Wikipedie_diskuse",
+       6       => "Soubor", #FIXME: Check the magic for Image: and Media:
+       7       => "Soubor_diskuse"
+);
+
+# Zdědit apriorní preference: wgDefaultUserOptionsEn
+
+/* private */ $wgQuickbarSettingsCs = array(
+       "Žádný", "Leží vlevo", "Leží vpravo", "Visí vlevo"
+);
+
+/* private */ $wgSkinNamesCs = array(
+       "Standard", "Nostalgie", "Kolínská modř"
+);
+
+/* private */ $wgUserTogglesCs = array(
+       "hover"         => "Ukázat odkazovou adresu (hoverbox) nad wikiovými odkazy",
+       "underline" => "Podtrhnout odkazy",
+       "highlightbroken" => "Začervenit odkazy na neexistující stránky",
+       "justify"       => "Zarámovat řádky",
+       "hideminor" => "Ukrýt malé redakční úpravy <i>Poslední změny</i>",
+       "numberheadings" => "Automaticky spočítat sekce",
+       "rememberpassword" => "Pamatovat si mé heslo od návštěvy k návětěvě",
+       "editwidth" => "Redakční okno roztáhnout na celou šíři.",
+       "editondblclick" => "Redigovat dvojím kliknutím (JavaScript)",
+       "watchdefault" => "Náhled na nové a modifikované články",
+       "minordefault" => "Mark all edits minor by default" #TRADUKU MIN
+);
+
+# Se eble, trovu Chehxajn libroservojn traserceblaj lau ISBN
+# $wgBookstoreListCs = ..
+
+# Tie, kie eble, uzu la memnomo de la lingvo
+# These need to be replaced
+/* private */ $wgLanguageNamesCs = array(
+       "ab"    => "Abcházština",
+       "aa"    => "Afarština",
+    "af"    => "Afrikánština",
+    "ay"    => "Ajmarština",
+    "tw"    => "Akanština",
+       "sq"    => "Albánština",
+       "am"    => "Amharština",
+    "en"    => "Angličtina",
+       "w"     => "Angličtina", # FIXME - Cu guste en la listo?
+       "simple" => "Zjednodušená angličtina",
+       "ar"    => "Arabština",
+       "hy"    => "Arménština",
+       "as"    => "Ásámština",
+       "az"    => "Ázerbájdžánština",
+       "ba"    => "Baškirština",
+       "be"    => "Běloruština",
+       "bn"    => "Bengálština",
+       "bh"    => "Bihárština", #FIXME - Bogpura, Majtila, Magaha
+    "my"    => "Birmětina",
+       "bi"    => "Bislamština",
+    "rn"    => "Burunda",
+    "ts"    => "Konžština",
+    "tn"    => "Cvanština",
+       "zh"    => "Čínština",
+       "cs"    => "Čeština",
+       "da"    => "Dánština", # Nepre uzu "da" por la lingvo
+       "dk"    => "Dánština",
+    "dz"    => "Zonque",
+    "ik"    => "Eskymáčtina", #FIXME - Cu?
+       "eo"    => "Esperanto",
+       "et"    => "Estonština",
+    "eu"    => "Baskitština",
+       "fo"    => "Faerština",
+       "fj"    => "Fidžijština",
+    "tl"    => "Filipínština",
+       "fi"    => "Finština", # FIXME - Cu suoma?
+       "fr"    => "Francouzština",
+       "fy"    => "Fríština",
+       "gl"    => "Galicijština",
+       "de"    => "Němčina",
+       "el"    => "Řečtina",
+       "kl"    => "Grónština", # FIXME Cu?
+       "gu"    => "Gudžarátština",
+    "gn"    => "Gvaraní",
+    "za"    => "Guang",
+       "ha"    => "Hauština",
+       "he"    => "Hebreština",
+       "hi"    => "Hindština", #FIXME Cu?
+    "es"    => "Španěltina",
+       "hu"    => "Maďarština",
+       "id"    => "Indonéština",
+       "ia"    => "Interlingua", #FIXME - Cu interlingua?
+       "iu"    => "Eskymáčtina", #FIXME - Cu?
+    "ga"    => "Irština",
+    "is"    => "Islandština",
+       "it"    => "Italština",
+       "ja"    => "Japonština",
+       "jv"    => "Javánština", #FIXME - Cu kodo "jw"?
+    "yi"    => "Jidiš",
+       "yo"    => "Jorubština",
+       "kn"    => "Kanárština",
+    "ka"    => "Kartvelština, Gruzínština",
+       "ks"    => "Kašmírština",
+    "ca"    => "Katalánština",
+       "kk"    => "Kazachština",
+    "qu"    => "Kečujština",
+    "cy"    => "Velština",
+    "ky"    => "Kirgizština",
+    "km"    => "Kmérština",
+    "ko"    => "Korejština",
+       "co"    => "Korsičtina",
+       "hr"    => "Chorvatština",
+    "xh"    => "Xhoština",
+       "la"    => "Latina",
+       "lv"    => "Lotyština",
+    "lo"    => "Laoština",
+       "ln"    => "Lingala",
+       "lt"    => "Litevština",
+       "mk"    => "Makedonština",
+       "mg"    => "Malgaština",
+       "ms"    => "Malajština",
+       "ml"    => "Malajálamština",
+       "mi"    => "Maorština",
+       "mr"    => "Maráthština",
+       "mo"    => "Moldavština", # " =ro rumana"
+       "mn"    => "Mongolština",
+       "na"    => "Nauru",
+    "nl"    => "Nizozemština",
+       "ne"    => "Nepálština",
+       "no"    => "Norština",
+       "oc"    => "Okcitánština",
+       "or"    => "Orijo",
+       "om"    => "Oroma",
+    "pa"    => "Pandábština",
+       "ps"    => "Paštština",
+       "fa"    => "Perština",
+       "pl"    => "Polština",
+       "pt"    => "Portugalština",
+       "rm"    => "Románština",
+    "rw"    => "Rwandština",
+       "ro"    => "Rumunština",
+       "ru"    => "Ruština",
+       "sm"    => "Samoánština",
+       "sg"    => "Sangoština",
+       "sa"    => "Sanskrt",
+       "sr"    => "Srbština",
+       "sh"    => "Srbocharvátština",
+       "st"    => "Sotština",
+       "sn"    => "Sona",
+       "sd"    => "Sindhština",
+       "si"    => "Sinhalština",
+       "ss"    => "Svazijština",
+       "sk"    => "Slovenština",
+       "sl"    => "Slovinština",
+       "so"    => "Somálština",
+       "su"    => "Sundánština",
+       "sw"    => "Svahilština",
+       "sv"    => "Švédština",
+       "tg"    => "Tadžičtina",
+    "th"    => "Thajština",
+       "ta"    => "Tamilština",
+       "tt"    => "Tatarština",
+       "te"    => "Telugua",
+       "bo"    => "Tibetština",
+       "ti"    => "Tigriňňa",
+       "to"    => "Tonžtina",
+       "tr"    => "Turečtina",
+       "tk"    => "Turkmenština",
+       "ug"    => "Ujgurština",
+       "uk"    => "Ukrajinština",
+       "ur"    => "Urdština",
+       "uz"    => "Uzbečtina",
+       "vi"    => "Vietnamština",
+       "vo"    => "Volapük",
+       "wo"    => "Volofština",
+       "zu"    => "Zulština"
+);
+
+# Note capitalization; also some uses may require addition of final -n
+/* private */ $wgWeekdayNamesCs = array(
+       "neděle", "pondělí", "úterý", "středa" , "čtvrtek",
+       "pátek", "sobota"
+);
+
+# Double-check capitalization
+/* private */ $wgMonthNamesCs = array(
+       "leden", "únor", "březen", "duben", "květen", "červen",
+       "červenec", "srpen", "září", "říjen", "listopad",
+       "prosinec"
+);
+
+# Hmm
+/* private */ $wgMonthAbbreviationsCs = array(
+       "Led", "Úno", "Bře", "Dub", "Kvě", "Čer", "Črv", "Srp",
+       "Zář", "Říj", "Lis", "Pro"
+);
+
+# All special pages have to be listed here: a description of ""
+# will make them not show up on the "Special Pages" page, which
+# is the right thing for some of them (such as the "targeted" ones).
+#
+# *Neměnit jména v levém sloupci, jsou to interní jména programových funkcí. Pravý sloupec  obsahuje několik mezer, které mají tak zůstat, aby se tyto funkce nezařadily do seznamu speciálních stránek.
+/* private */ $wgValidSpecialPagesCs = array(
+       "Userlogin"             => "",
+       "Userlogout"    => "",
+       "Preferences"   => "Změnit moje uživatelské preference", 
+       "Watchlist"             => "Moje preference", # Seznam stránek, které si uživatel vybral jako oblíbené
+       "Recentchanges" => "Poslední změny stránek",
+       "Upload"                => "Načti obrázky a soubory",
+       "Imagelist"             => "Načtené soubory",
+       "Listusers"             => "Zapsaní uživatelé",
+       "Statistics"    => "Statistika stránek",
+       "Randompage"    => "Náhodná stránka",
+
+       "Lonelypages"   => "Sirotčí stránky",
+       "Unusedimages"  => "Sirotčí obrázky",
+       "Popularpages"  => "Nejvíce navštěvované stránky",
+       "Wantedpages"   => "Nejvíce žádané stránky",
+       "Shortpages"    => "Krátké články",
+       "Longpages"             => "Dlouhé stránky",
+       "Newpages"              => "Nově vytvořené stránky",
+       "Allpages"              => "Každá stránka podle titulu",
+
+       "Ipblocklist"   => "Blokované adresy IP",
+    "Maintenance" => "Opravy a údržba", # angle "Maintenance page"
+       "Specialpages"  => "",
+       "Contributions" => "",
+    "Emailuser"     => "",
+       "Whatlinkshere" => "",
+       "Recentchangeslinked" => "",
+       "Movepage"              => "",
+       "Booksources"   => "Vnější knihovny"
+);
+
+/* private */ $wgSysopSpecialPagesCs = array(
+       "Blockip"               => "Zablokuj adresu IP",
+       "Asksql"                => "Objednávka z databáze",
+       "Undelete"              => "Obnov odstraněnou stránku"
+);
+
+# FIXME
+/* private */ $wgDeveloperSpecialPagesCs = array(
+       "Lockdb"                => "Odemknout data",
+       "Unlockdb"              => "Povolit změnu dat",
+       "Debug"                 => "Ukaž informace servere"
+);
+
+/* private */ $wgAllMessagesCs = array(
+
+# Části textu používané různými stránkami:
+#
+# Písmena, která se mají objevit jako část odkazu ve formě "[[jazyk]]y" atd:
+"linktrail"     => "/^([a-z]+)(.*)$/sD",
+"mainpage"             => "Hlavní strana",
+"about"                        => "Úvod",
+"aboutwikipedia" => "O Wikipedii", #FIXME
+"aboutpage"            => "Wikipedie:Úvod",
+"help"                 => "Nápověda",
+"helppage"             => "Wikipedie:Nápověda",
+"wikititlesuffix" => "Wikipedie",
+"bugreports"   => "Oznam mouchy",
+"bugreportspage" => "Wikipedie:Oznam_mouchy",
+"faq"                  => "Časté otázky",
+"faqpage"              => "Wikipedie:Časté otázky",
+"edithelp"             => "Pomoc při redigování",
+"edithelppage" => "Wikipedie:Jak_redigovat_stránku", #FIXME: Kontroluj
+"cancel"               => "Rezignuj",
+"qbfind"               => "Hledej",
+"qbbrowse"             => "Listování", # FIXME
+"qbedit"               => "Redigování", #FIXME
+"qbpageoptions" => "Parametra stránky", #FIXME
+"qbpageinfo"   => "Info stránky", #FIXME
+"qbmyoptions"  => "Osobní údaje", #FIXME
+"mypage"               => "Moje stránka", #FIXME
+"mytalk"        => "Moje diskuse",
+"currentevents" => "Aktuality", #FIXME - Novinky? Aktuální novinky? Aktuální události?
+"errorpagetitle" => "Chyba", #FIXME - Arero? ;)
+"returnto"             => "Vrať se na $1.",
+"fromwikipedia"        => "Z Wikipedie, otevřené encyklopedie.",
+"whatlinkshere"        => "Sem odkazy", #FIXME: cu ligantaj?
+"help"                 => "Nápověda",
+"search"               => "Hledej",
+"history"              => "Historie", #FIXME
+"printableversion" => "Verze k tisku", # FIXME: cu printebla?
+"editthispage" => "Rediguj stránku",
+"deletethispage" => "Odstraň stránku",
+"protectthispage" => "Chraň stránku", #FIXME: Cu 'gardu'
+"unprotectthispage" => "Neochraňuj stránku", #FIXME: cu 'malgardu', 'ne plu', ktp?
+"talkpage"             => "Diskusní stránka",
+"subjectpage"  => "Stránka námětu", #FIXME: ?
+"otherlanguages" => "Jiné jazyky",
+"redirectedfrom" => "(Přesměrováno z $1)",
+"lastmodified" => "Stránka byla naposledy redigována $1.",
+"viewcount"            => "Stránka se ukázala $1-krát.",
+"printsubtitle" => "(Z http://cs.wikipedia.org)",
+"protectedpage" => "Chráněná stránka", #FIXME: cu "gardita" ktp?
+"administrators" => "Wikipedie:Správci", # FIXME?
+"sysoptitle"   => "Účet správce nutný",
+"sysoptext"            => "Žádaný úkon je proveditelný pouze  \"správci\".
+Čtěte prosím $1.", #FIXME
+"developertitle" => "Účet správce nutný",
+"developertext"        => "Žádaný úkonLa je proveditelný pouze programátory projekty, aby se zabránilo poškození dat.
+Čtěte prosím $1.",
+"nbytes"               => "$1 bajty",
+"go"                   => "Do toho!", #FIXME
+"ok"                   => "OK", #FIXME
+"sitetitle"            => "Wikipedie", # Wikipedia
+"sitesubtitle" => "Wikipedie: Otevřená Encyklopedie",
+"retrievedfrom" => "Citováno z \"$1\"", #FIXME: Ukazuje se po tisku strany
+
+# Main script and global functions
+#
+"nosuchaction" => "Žádný podobný úkon", 
+"nosuchactiontext" => "Úkon ('action') specifikovaný pomocí nepodporuje programové vybavení Wikipedie",
+"nosuchspecialpage" => "Žádná taková speciální stránka",
+"nospecialpagetext" => "Žádal jsi speciální stránku podporovanou Wikipedií",
+
+# General errors
+#
+"error"         => "Chyba",
+"databaseerror" => "Databázová chyba",
+"dberrortext"  => "Syntaktická chyba se stala při dotazu na databázi. Možná ji způsobila nedovolená otázka. (viz $1), nebo to indikuje chybu v programovém vybavení. Jako poslední jste volil(a) otázku:
+<blockquote><tt>$1</tt></blockquote>
+z funkce \"<tt>$2</tt>\". 
+MySQL vrátil chybu  \"<tt>$3: $4</tt>\".",
+"noconnect"            => "Nebylo možné se připojit k databázi $1",
+"nodb"                 => "Nebylo možné vybrat databázi $1",
+#"readonly"            => "Data uzamčena pouze ke čtení" => "Vysvětlete prosím, jak se uzamykají data, a očekávaný čas odemykání.",
+"readonlytext" => "Data Wikipedie jsou nyní uzavřena pro nové doplňky a změny, pravděpodobně kvůli pravidelné údržbě dat. Zkuste se připojit znovu po malé době. Uzamykatel zanechal následující zprávu:
+<p>$1\n",
+"missingarticle" => "Databázo nenašla text článku, který měla najít, nazvaný \"$1\".
+Toto není chyba databáze, ale patrně chyba v programu. Oznamte to správci systému a upozorněte na URL.",
+"internalerror" => "Vnitřní chyba",
+"filecopyerror" => "Nebylo možné zkopírovat soubor  \"$1\" na \"$2\".",
+"filerenameerror" => "Nebylo možné přejmenovat soubor \"$1\" na \"$2\".",
+"filedeleteerror" => "Nebylo možné odstranit soubor \"$1\".",
+"filenotfound" => "Nebylo možné najít soubor \"$1\".",
+"unexpected"   => "Neočekávaná hodnota: \"$1\"=\"$2\".",
+"formerror"            => "Chyba: nebylo možné dotat formulář",    
+"badarticleerror" => "Tento úkon nelze použít u tohoto článku.",
+"cannotdelete"  => "Nebylo možné odstranit zvolenou stránku ani soubor.",
+"badtitle"             => "Neplatný titul",
+"badtitletext" => "Požadovaný titul stránky byl neplatný, prázdný nebo nesprávně adresovaný na jinojazyčný titul nebo jiný článek Wikipedie.",
+
+# Login and logout pages
+#
+"logouttitle"  => "Na shledanou!",
+"logouttext"   => "Skončil jste svou seanci.
+Můžete pracovat ve Wikipedii anonymně, nebo se přihlásit znovu jako stejný nebo jiný uživatel..\n", #FIXME
+
+"welcomecreation" => "<h2>Vítejte, $1!</h2> Váš účet je vytvořen.
+<font color=\"red\">Nezapomeňte uvést své preference ve Wikipedii!</font>",
+
+"loginpagetitle" => "Přihlaste se", #FIXME
+"yourname"             => "Název vašeho účtu", #FIXME buď heslo nebo jméno uživatele nebo název účtu atd.?
+"yourpassword" => "Vaše heslo",
+"yourpasswordagain" => "Napište heslo znovu",
+"newusersonly" => " (pouze noví uživatelé)",
+"remembermypassword" => "Pamatuj si mé heslo od seance k seanci.",
+"loginproblem" => "<b>Nastal problém při vašem přihlášení.</b><br>Zkuste to znovu!",
+"alreadyloggedin" => "<font color=\"red\"><b>Uživateli $1, již jste přihlášen!</b></font><br>\n",
+
+"areyounew"            => "Pokud jste nový u Wikipedie a chcete získat uživatelský účet, napište své přihlašovací jméno, heslo, a znovu heslo zopakujte. Podle uvážení můžete vložit svou e-mailovou adresu, abychom vám mohli poslat nové heslo, kdybyste současné zapomněl.
+<br>\n",
+
+"login"                        => "Přihlašte se", #FIXME, what exactly do the following go to?
+"userlogin"            => "Přihlašte se",
+"logout"               => "Na shledanou",
+"userlogout"   => "Na shledanou",
+"createaccount"        => "Vytvořte nový účet",
+"badretype"            => "Vámi napsaná hesla nesouhlasí.",
+"userexists"   => "Uživatel se stejným jménem je už registrován. Zvolte jiné jméno.",
+"youremail"            => "Vaše e-mailová adresa",
+"yournick"             => "Zdrobnělina vašho jména (pro podpisy)", #FIXME - cu kasbude to přezdívka, literární jméno atd.?
+"emailforlost" => "Pokud zapomenete své heslo, můžeme vám zaslat nové na vaši mailovou adresu.",
+"loginerror"   => "Chyba při přihlašování", #FIXME
+"noname"               => "Je nutné úvést jméno svého účtu.",
+"loginsuccesstitle" => "Přihlášení uspělo",
+"loginsuccess" => "Nyní jste přihlášen ve Wikipedii jako uživatel \"$1\".",
+"nosuchuser"   => "Žádný uživatel nemá jméno \"$1\".
+Zkontrolujte prosím správnost zápisu nebo vytvořte účet dle níže uvedeného formuláře.",
+"wrongpassword"        => "Heslo vámi uvedené nesouhlasí. Zkuste to znovu.",
+"mailmypassword" => "Zašlete mi mailem nové heslo",
+"passwordremindertitle" => "Připomenutí ztraceného hesla z Wikipedie", #FIXME
+"passwordremindertext" => "Někdo (patrně vy, z IP-adresy $1) žádal, abychom vám poslali nové heslo pro přihlášení do Wikipedie. Heslo pro uživatele  \"$2\" je nyní \"$3\".
+Doporučujeme, abyste se nyní přihlásil a raději změnil heslo.", #FIXME
+"noemail"              => "E-mailová adresa není zaregistrována pro uživatele \"$1\".",
+#"passwordsent"        => "Oni sendis novan pasvorton al la retpostadreso"Bylo zasláno nové helo pro uživatele \"$1\". Po obdržení nového hesla se znovu
+#přihlaste.",
+
+# Edit pages
+#
+"summary"              => "Resumé",
+"minoredit"            => "Tato změna je malá redakční úpravu.",
+"savearticle"  => "Uchovej změny",
+"preview"              => "Náhled",
+"showpreview"  => "Ukaž náhled", #FIXME eh?
+"blockedtitle" => "Uživatel odblokován", #FIXME cu 'Konto forbarita'?
+"blockedtext"  => "Váš účet nebo IP-adresa byly odblokovány osobou ,
+která popsala příčinu takto:<br><p>Máte právo se spojit se správcem systému a prodiskutovat odblokování.", #FIXME - sistemestro?
+"newarticle"   => "(Nový)",
+"newarticletext" => "Vložte sem text nového článku.", #FIXME?
+"noarticletext" => "(Článek zatím neobsahuje text)", #FIXME
+"updated"              => "(Změna zaregistrována)", #FIXME: ?
+"note"                 => "<strong>Noto:</strong> ", #FIXME: Where does this come from?
+"previewnote"  => "Pamatujte, že toto je pouze náhled, ne uložení!",
+"previewconflict" => "Tento náhled ukazuje výše uvedený text, jak bude vypadat po uložení stránky.", #FIXME
+"editing"              => "Redakce stránky $1",
+"editconflict" => "Redakční konflikt: ",
+"explainconflict" => "Někdo změnil stránku poté, co jste ji napsal(a). Výše vidíte aktuální text článku. Vaše změny jsou uvedeny dole. Musíte sloučit své změny se stávajícím článkem.
+<b>Poue</b> výše uvedený text zůstane uchováná po kliknutí na  \"Uložit\".\n<p>" , #FIXME - double-check that this makes sense
+"yourtext"             => "Váš text",
+"storedversion" => "Registrovaná verze",
+"editingold"   => "<strong>VAROVÁNÍ: nyní redigujete starou verzi tohoto článku. Když ji uložíte, všechny změny provedené po zmíněné revizi se ztratí.</strong>\n",
+"yourdiff"             => "Rozdíly",
+"copyrightwarning" => "Pamatujte, že každý příspěvek pro Wikipedii je považován jako zveřejněný dle <i>GNU Free Documentation License</i> (viz ). Pokud chcete, aby váš příspěvek nebyl redigován a rozšiřován, ne klikejte na \"Uložit\". Zároveň tím přísaháte, že příspěvek je vaším dílem nebo jste ho opsal(a) ze zdroje, na který se nevztahuje copyright.. <strong>NE POUŹÍVEJTE BEZ DOVOLENÍ DÍLA VÁZANÁ COPYRIGHTem!</strong>",
+
+
+# History pages
+#
+"revhistory"   => "Historie redakcí",
+"nohistory"            => "O této stránce neexistuje historie redakcí.", #FIXME
+"revnotfound"  => "Revize nenalezena", #fixme
+"revnotfoundtext" => "Nelze najít starou revizi, kterou hledáte. Zkuste prosím zkontrolovat URL hledané stránky.\b",
+"loadhist"             => "Načítání stránky historie redakcí", #FIXME Apparently not used
+"currentrev"   => "Aktuální revize", #FIXME cu "plej lasta"?
+"revisionasof" => "Jak zaregistrováno na ",
+"cur"                  => "teď",
+"next"                 => "násl",
+"last"                 => "předch",
+"orig"                 => "orig",
+"histlegend"   => "Vysvětlení: (teď) = viz rozdíly oproti nynější verzi,
+(předch) = rozdíly oproti předchozí verzi, M = malá redakční změna",
+
+# Diffs
+#
+"difference"   => "(Rozdíly mezi revizemi)",
+"loadingrev"   => "načíst revize pro rozdíly", #FIXME Apparently not used
+"lineno"               => "Linie :",
+"editcurrent"  => "Zrediguj současnou verzi stránky",
+
+# Search results
+#
+"searchresults" => "Výsledek hledání",
+"searchhelppage" => "Wikipedie:Hledání",
+"searchingwikipedia" => "Hledání ve Wikipedii",
+"searchresulttext" => "Nápovědu, jak účinně hledat ve Wikipedii, čtěte na  .",
+"searchquery"  => "Zadání pro vyhledávání \"$1\"",
+"badquery"             => "Zkreslené zadání pro vyhledávání",
+"badquerytext" => "Via sercmendo ne estis Vaše zadání pro vyhledávání není splnitelné. Může to být tím, že hledáte slovo kratší než tři písmena, nebo jste zadání napsal nesprávně".
+#", ekzemple \"fisoj kaj kaj skaloj\"".   # FIXME ? eblas
+". Bonvolu reserci per alia mendo.",
+"maZkuste zadat nové zadání"        => "Zadání \"$1\" poskytlo články podle názvu a články dle obsahu.",
+"titlematches" => "Nalezeno dle názvů",
+"notitlematches" => "Nic nebylo nalezeno dle názvu",
+"textmatches"  => "Nalezeno podle obsahu",
+"notextmatches"        => "Nic nebylo nalezeno podle obsahu",
+"prevn"                        => "$1 předchozí",
+"nextn"                        => "$1 následující",
+"viewprevnext" => "Ukaž ($1) ($2) ($3).",
+"showingresults" => "Ukazuje <b></b> nalezené od <b></b>-a.",
+"nonefound"            => "<strong>Poznámka</strong>: neúspěšné hledání zaviňuje často zadání slov, které nejsou v indexu, nebo mnoha slov najednou (jen stránky, které obsahují všechna zadaná slova, se objeví ve výsledku).",
+"powersearch" => "Sercu",
+#"powersearchtext" => "Hledej"
+#Sercu en sekcioj: :<br>
+#<br>
+# Kun alidirektiloj &nbsp; Sercu  ",
+
+# Preferences page
+#
+"preferences"  => "Preference",
+"prefsnologin" => "Dosud nepřihlášen!",
+"prefsnologintext"     => "Určite <a href=\"" .
+  wfLocalUrl( "Special:Userlogin" ) . "\">se přihlaste</a>
+dříve než je možno měnit priority.",
+"prefslogintext" => "Přihlásil jste se \"$1\".
+Vaše interní identifikační číslo je  .",
+"prefsreset"   => "Priority odstraněny z registru.", #FIXME: Hmm...
+"qbsettings"   => "Priority na liště nástrojů", 
+"changepassword" => "Změňte heslo",
+"skin"                 => "Etos",
+"saveprefs"            => "Uložit priority",
+"resetprefs"   => "Obnovit předchozí priority",
+"oldpassword"  => "Staré hesle",
+"newpassword"  => "Nové heslo",
+"retypenew"            => "Napište znovu nové heslo",
+"textboxsize"  => "Velikost redakčního okna",
+"rows"                 => "Linie",
+"columns"              => "Sloupce",
+"searchresultshead" => "Sladění výsledku hledání",
+"resultsperpage" => "Ukázat nalezené po",
+"contextlines" => "Ukázat linie ze stránek po",
+"contextchars" => "Ukázat písmena z linií až po",
+"recentchangescount" => "Ukázat množství názvů v Posledních Změnách",
+"savedprefs"   => "Vaše priority jsou zaregistrovány.",
+"timezonetext" => "Označte, o kolik se vaše časové pásmo liší od serveru (UTC).
+Například, pro Střední Evropu Časové pásmo, označte \"1\" v zimě nebo \"2\" v létě.",
+"localtime"    => "Místní časové pásmo",
+"timezoneoffset" => "Rozdíl", #FIXME (?)
+"emailflag"     => "Přijměte mailovou poštu od jiných wikipediistů",
+
+# Recent changes
+#
+"recentchanges" => "Poslední změny",
+"recentchangestext" => "Sledujte poslední změny ve Wikipedii na této stránce.
+[[Vítejte, nováčci]]!
+Přečtěte prosím tuto stránku: [[wikipedie:Časté otázky|Časté otázky]],
+[[wikipedie:Drobné rady|Drobné rady]]
+(zvláště [[wikipedie:Názvy titulů|Názvy titulů]]
+a [[wikipedie:Neutrální hledisko|Neutrální hledisko]]),
+a [[wikipedie:Časté chyby|Časté chyby ve Wikipedii]].
+
+Pokud chcete, aby Wikipedie uspěla, je velice důležité, abyste nevkládali články vázané na  [[copyright]] někoho jiného. Zákonná odpovědnost by skutečně mohla ohrozit celý projekt, proto to prosím nedělejte.
+
+Také se podívejte na 
+[http://meta.wikipedia.org/wiki/Special:Recentchanges poslední diskusi o Wikipedii]
+(plurlingve)",
+"rcloaderr"            => "Načti poslední změny",
+"rcnote"               => "Poslední <b></b> změny během posledních<b></b> dní.",
+"rclinks"              => "Ukázat poslední změny; ukázat změny během posledních dní.",
+"diff"                 => "rozdíl",
+"hist"                 => "historie",
+"hide"                 => "skrýt",
+"show"                 => "ukázat",
+"tableform"            => "tabulka",
+"listform"             => "seznam",
+"nchanges"             => "změny",
+
+"minoreditletter" => "M",
+"newpageletter" => "N",
+
+# Upload
+#
+"upload"               => "Načti",
+"uploadbtn"            => "Načti soubor",
+"uploadlink"   => "Načti obrázek", # Cu neuzata?
+"reupload"             => "Načti znovu",
+"reuploaddesc" => "Vrať se k načtení.",
+"uploadnologin" => "Nepřihlášený",
+"uploadnologintext"    => "Musíte mít účet a <a href=\"" .
+  wfLocalUrl( "Speciala:Userlogin" ) . "\">přihlaste se</a>
+pro načtení souboru.",
+"uploadfile"   => "Načti soubor",
+"uploaderror"  => "Při načítání došlo k chybě",
+"uploadtext"   => "Pro prohlížení a hledání již načtených souborů, jděte na  <a href=\"" . wfLocalUrl( "Special:Imagelist" ) .
+"\">seznam načteného</a>.
+Každé načtení a odstranění je registrováno u  <a href=\"" .
+wfLocalUrl( "Wikipedie:Načtení_log" ) ."\">Načtení_log</a>.</p>
+
+
+<p>Použij tento formulář pro načtení nového obrázku nebo jiných souborů jako ilustrací ke svým článkům. U běžných prohlížečů se dole objeví buton \"Procházet...\" apod; tím se otevřou adresáře tvého pevného disku, kde si vybereš svůj soubor, jehož název vyplní pole vedle butonu; musíš také potvrdit prohlášení, že neporušuješ ničí copyright. Vlastní načtení provedeš kliknutím na buton \"Načti\". Může to trvat i delší dobu, pokud je soubor velký a počítač pomalý.</p>
+
+<p>Wikipedie upřednostňuje formát JPEG pro fotografie,
+PNG pro grafiku, diagramy, apod.; a OGG pro zvukové nahrávky.
+Pojmenuj svůj soubor informativním způsobem, aby se vyloučila nedorozumění.
+Pro vložení obrázku do článku napiš odkaz ve formě
+<b>[[obrázek:soubor.jpg]]</b> nebo <b>[[image:obraz.png|text pro prohlížeče bez grafiky]]</b>,
+nebo <b>[[soubor:soubor.ogg]]</b> por sounds.</p>
+
+<p>Všimni si, že články ve Wikipedii mohou redigovat i ostatní wikipediisté. Mohou přidávat, nahrazovat, i odstraňovat, pokud to prospěje encyklopedii. Pokud někdo bude zlomyslně poškozovat soubory jiných autorů,
+může mu být zablokován přístup k redigování.</p>",
+"uploadlog"            => "kniha nahrávek ",
+"uploadlogpage" => "kniha_nahrávek ",
+"uploadlogpagetext" => "Přehled naposledy načtených souborů. Všechny časové údaje se ukazují podle časového pásma UTC.
+<ul>
+</ul>
+",
+"filename"             => "Soubor",
+"filedesc"             => "Popis",
+"affirmation"  => "Potvrzuji, že zákonný vlastník copyrightu na tento soubor souhlasí se zveřejněním podle $1.",
+"copyrightpage" => "Wikipedie:Copyright",
+"copyrightpagename" => "povolenka GFDL používaná ve Wikipedii ",
+"uploadedfiles"        => "Načtené soubory ",
+"noaffirmation" => "Bezpodmínečně musíte potvrdit, že váš příspěvek neporušuje zákony o copyrightu.",
+"ignorewarning"        => "Ignoruj varování a ulož soubor.",
+"minlength"            => "Jméno souboru se musí skládat nejméně ze tří písmen.",
+"badfilename"  => "Jméno souboru bylo změněno na \"$1\".",
+"badfiletype"  => "\".$1\" jedná se o nedoporučený typ souboru.",
+"largefile"            => "Doporučuje se, aby soubor nepřesahoval 100 kbytů.",
+"successfulupload" => "Načtení úspěšně provedeno!",
+"fileuploaded" => "Úspěšně jsi načetl soubor \"$1\".
+Věnuj pozornost následujícímu odkazu: ($2) na stránku popisu a napiš pár informací o souboru. Např. odkud pochází, kdy a kdo ho vytvořil či cokoliv dalšího, co o něm víš..",
+"uploadwarning" => "Varování",
+"savefile"             => "Ulož soubor $1",
+"uploadedimage" => "načetl \"$1\"",
+
+# Image list
+#
+"imagelist"            => "Seznam načtených souborů ",
+"imagelisttext"        => "Seznam souborů, seřazených dle .",
+"getimagelist" => "získává seznam souborů ",
+"ilshowmatch"  => "Ukaž soubory, jejich jména vyhovují",
+"ilsubmit"             => "Hledej",
+"showlast"             => "Ukaž poslední soubor dle .",
+"all"                  => "všichni",
+"byname"               => "jméno",
+"bydate"               => "datum",
+"bysize"               => "velikost",
+"imgdelete"            => "odstranit",
+"imgdesc"              => "pri",
+"imglegend"            => "(pri) = ukaž/zrediguj popis souboru.",
+"imghistory"   => "Historie načtených souborů",
+"revertimg"            => "res",
+"deleteimg"            => "for",
+"imghistlegend" => "(nun) = toto je současná verze souboru, (for) = odstranit tuto starou verzi, (res) = obnovit starou verzi.
+<br><i>Click on date to see image uploaded on that date</i>.",
+"imagelinks"   => "Odkazy k souboru ",
+"linkstoimage" => "K souboru odkazují tyto stránky:",
+"nolinkstoimage" => "Žádná stránka neodkazuje na tento soubor.",
+
+# Statistics
+#
+"statistics"   => "Statistika",
+"sitestats"            => "O síti ",
+"userstats"            => "O uživatelích ",
+"sitestatstext" => "V naší sbírce souborů se nachází celkem <b></b> stránek.
+Toto číslo obsahuje \"diskusní stránky\", stránky o Wikipedii, droboučké
+\"podčlánky\", přesměrování, a další, které nejsou články v pravém slova smyslu. Pomineme-li je, zbývá <b></b> skutečných článků.</p>
+
+<p>Bylo navštíveno celkem <b></b> stránek, a zredigováno celkem <b></b> stránek od zavedení tohoto programu Wikipedie (Listopad 2002).
+To je v průměru jedna stránka na <b></b> návštěv, a na <b></b> redakcí.",
+"userstatstext" => "Zapsalo se <b></b> uživatelů. Z nich, <b></b> jsou spoluvedoucí 
+(viz ).",
+
+# Maintenance Page
+#
+"maintenance"          => "Nástroje pro opravy a údržbu",
+"maintnancepagetext"   => "Zde jsou různé nástroje pro opravy a všeobecnou údržbu dat. Některé funkce mohou otřást databází, nenačítejte proto po každé drobné opravě!",
+"maintenancebacklink"  => "Návrat k nástrojům",
+"disambiguations"      => "Špatně odkázané oddělovače ",
+"disambiguationspage"  => "Wikipedie:Oddělovače",
+"disambiguationstext"  => "Tyto stránky odkazují na <i>stránkový oddělovač</i>. Měly by místo toho odkazovat na správný subjekt.<br>Bereme do úvahy stránky, které odkazují na oddělovač.<br>Odkazy na sekci nečlánkových souborů <i>ne</i> se zapisují zde.",
+"doubleredirects"      => "Dvojité přesměrování",
+"doubleredirectstext"  => "<b>Pozor:</b> Může se stát, že tento seznam bude obsahovat falešné pozitivy. Všeobecně to znamená, že existuje další text s odkazy po #REDIERCT.<br>
+Každý řádek ukazuje odkaz k prvnímu a druhému přesměrování, plus první řádek textu druhého přesměrování, který všeobecně ukazuje \"skutečný\" hlavní článek, na který odkazuje první přesměrování.",
+"brokenredirects"      => "Přerušené přesměrování",
+"brokenredirectstext"  => "Tato přesměrování se vztahují na neexistující články.",
+"selflinks"            => "Stránky samoodkazující",
+"selflinkstext"                => "Tyto stránky obsahují neužitečný odkaz samy na sebe.",
+"mispeelings"           => "Stránky se špatnou výslovností",
+"mispeelingstext"               => "Tyto stránky obsahují jednu z nesprávných výslovností uvedených v . Správná výslovnost se ukáže (takto).",
+"mispeelingspage"       => "Seznam častých chyb výslovnosti",
+"missinglanguagelinks"  => "Chybějící mezijazykové odkazy",
+"missinglanguagelinksbutton"    => "Ukaž chybějící mezijazykové odkazy pro",
+"missinglanguagelinkstext"      => "Tyto články <i>ne</i> odkazují na svůj ekvivalent v jazyce . Přesměrování a podstránky se <i>ne</i> ukazují.",
+# Miscellaneous special pages
+#
+"orphans"              => "Sirotci",
+"lonelypages"  => "Sirotci",
+"unusedimages" => "Nepoužívané obrázky a soubory",
+"popularpages" => "Nejvíce navštěvované stránky",
+"nviews"               => " jednou",
+"wantedpages"  => "Žádoucí stránky ",
+"nlinks"               => " odkazy",
+"allpages"             => "Celý komplex stran",
+"randompage"   => "Náhodná stránka",
+"shortpages"   => "Drobné stránky",
+"longpages"            => "Dlouhé stránky",
+"listusers"            => "Uživatelé",
+"specialpages" => "Speciální stránky",
+"spheading"            => "Speciální stránky",
+"sysopspheading" => "Speciální stránky pro spoluadministrátory",
+"developerspheading" => "Speciální stránky pro programátory",
+"protectpage"  => "Ochrana stránky",
+"recentchangeslinked" => "Ukaž odkazy",
+"rclsub"               => "(ke stráncej odkazy z \"$1\")",
+"debug"                        => "Proti mouchám",
+"newpages"             => "Nové stránky",
+"movethispage" => "Přemístit stránku",
+"unusedimagestext" => "<p>Ostatní WWW-stránky, např. jinojazyčné Wikipedie, mohou udělat přímé odkazy pomocí URL, ty se nezapočítávají do tohoto seznamu.",
+"booksources"  => "Knižní služby",
+"booksourcetext" => "Odkazy na jiné WWW-stránky, které prodávají knihy a/nebo informují o knize, na níž je odkaz. Wikipedie není na tyto prodejny obchodně vázána, takže odkazy nelze chápat jako doporučení nebo reklamu.", 
+
+# Email this user
+#
+"mailnologin"  => "Žádná adresa k zaslání",
+"mailnologintext" => "Určitě uveď <a href=\"" .
+  wfLocalUrl( "Speciala:Userlogin" ) . "\">jméno</a>
+a měj platnou e-mailovou adresu ve svých <a href=\"" .
+  wfLocalUrl( "Speciala:Preferences" ) . "\">preferencích</a>
+abys mohl mailovat jiným wikipediistům.",
+"emailuser"            => "Pošli mail",
+"emailpage"            => "Pošli mail",
+"emailpagetext"        => "Pokud wikipediista-adresát uvedl platnou e-mailovou adresu v preferencích, můžeš mu poslat zprávu tímto formulářem. 
+Mailová adresa tebou uvedená v preferencích se objeví jako \"Od\"-adresa
+pošty, aby adresát mohl odpovědět.",
+"noemailtitle" => "Žádná mailová adresa ",
+"noemailtext"  => "Tento wikipediista buď nedal platnou adresu nebo zvolil režim nepřijímat zprávy od jiných wikipediistů.",
+"emailfrom"            => "Od",
+"emailto"              => "Komu",
+"emailsubject" => "Předmět",
+"emailmessage" => "Zpráva",
+"emailsend"            => "Odeslat",
+"emailsent"            => "Odeslaná pošta",
+"emailsenttext" => "Tvá pošta byla odeslána.",
+
+
+
+# Watchlist
+#
+"watchlist"            => "Oblíbené stránky",
+"watchlistsub" => "(uživatele \"$1\")",
+"nowatchlist"  => "Zatím jsi neuvedl žádné oblíbené stránky.",
+"watchnologin" => "Neuvedeno jméno",
+"watchnologintext"     => "Nutno uvést <a href=\"" .
+  wfLocalUrl( "Speciala:Userlogin" ) . "\">jméno</a>
+pro aktivaci tvých oblíbených stránek.",
+"addedwatch"   => "Přidáno k oblíbeným",
+"addedwatchtext" => "Stránka \"$1\" je přidána k tvým <a href=\"" .
+  wfLocalUrl( "Speciala:Watchlist" ) . "\">oblíbeným</a>.
+Budoucí změny této stránky se objeví <b>tučně</b> v  <a href=\"" .
+  wfLocalUrl( "Speciala:Recentchanges" ) . "\">seznamu Poslední Změny </a>,
+a bude počítány v seznamu tvých Oblíbených.
+
+<p>Pokud později budeš chtít odstranit stránku ze seznamu Oblíbených, klikni na \"Ignoruj stránku \" v liště nástrojů.",
+"removedwatch" => "Vytaženo z Oblíbených",
+"removedwatchtext" => "Stránka \"$1\" vytažena z tvých Oblíbených.",
+"watchthispage"        => "Věnovat pozornost této stránce",
+"unwatchthispage" => "Ignorovat tuto stránku",
+"notanarticle" => "Toto není článek",
+
+# Delete/protect/revert
+#
+"deletepage"   => "Odstranit stránku",
+"confirm"              => "Potvrdit",
+"confirmdelete" => "Potvrdit odstranění",
+"deletesub"            => "(Odstraňuje se \"$1\")",
+"confirmdeletetext" => "Odstraníš článek nebo soubor a smažeš celou jeho historii z databáze.<br>
+Potvrď prosím, že to opravdu chceš, že si uvědomuješ důsledky a že dodržuješ [[Wikipedie:Pravidla o odstraňování]].",
+"confirmcheck" => "Ano, jsem naprosto jist, že chci toto odstranit.",
+"actioncomplete" => "Provedeno",
+"deletedtext"  => "\"$1\" je odstraněno.
+Pohleď na záznam posledních odstranění.",
+"deletedarticle" => "odstraněno \"$1\"",
+"dellogpage"   => "Kniha_odstraněných_souborů",
+"dellogpagetext" => "Zde je seznam posledních odstranění z databáze.
+Všechny časové údaje uvedeny podle časového pásma serveru. (UTC)
+<ul>
+</ul>
+",
+"deletionlog"  => "kniha odstranění",
+"reverted"             => "Obnovení předchozí verze",
+"deletecomment"        => "Důvod odstranění",
+"imagereverted" => "Obnovení předchozí verze úspěšně provedeno.",
+
+# Undelete
+"undelete" => "Obnov odstraněnou stránku",
+"undeletepage" => "Ukaž a obnov odstraněnou stránku",
+"undeletepagetext" => "Tyto stránky jsou odstraněny, avšak dosud archivovány, je možno je obnovit. Archiv se vyprazdňuje pravidelně.",
+"undeletearticle" => "Obnovit odstraněný článek",
+"undeleterevisions" => " revize archivovány",
+"undeletehistory" => "Pokud stránku obnovíš, všechny revize budou v historii obnoveny. Pokud byla vytvořena nová stránka se stejným jménem jako odstraněná, obnovené revize se zapíší na starší místo v historii a nová stránka nebude nahrazena.",
+"undeleterevision" => "Odstraněná revize z ", # ( uveden čas)
+"undeletebtn" => "Obnovit!",
+"undeletedarticle" => "obnoveno \"$1\"",
+"undeletedtext"   => "Článek [[]] je úspěšně obnoven.
+Pohleď do [[Wikipedie:Kniha odstranění]] pro záznam posledních odstranění a obnovení.",
+
+# Contributions
+#
+"contributions"        => "Příspěvky wikipediisty",
+"contribsub"   => "Od ",
+"nocontribs"   => "Nenalezeny žádné redakce podle těchto kritérií.",
+"ucnote"               => "Zde jsou <b></b> poslední redakce tohoto wikipediisty během <b></b> posledních dní.",
+"uclinks"              => "Ukaž poslední redakce; ukaž poslední dny.",
+
+# What links here
+#
+"whatlinkshere"        => "Přihlašovaní sem",
+"notargettitle" => "Bez cílové stránky",
+"notargettext" => "Neupřesnil jsi, kterou stránku nebo kterého uživatele zamýšlíš.",
+"linklistsub"  => "(Seznam odkazů)",
+"linkshere"            => "Tyto stránky odkazují sem:",
+"nolinkshere"  => "Žádná stránka sem neodkazuje.",
+"isredirect"   => "přesměrovač",
+
+# Block/unblock IP
+#
+"blockip"              => "Zablokuj adresu IP",
+"blockiptext"  => "Tímto formulářem můžeš zablokovat adresu IP a zbavit ji práva přispívat do wikie. To lze učinit ''pouze'' v případě vandalizmu, a při dodržení [[Wikipedie:Pravidla pro zablokování|pravidel pro zablokování]].
+Níže objasni přesný důvod (např. uveď stránku, která se stala terčem vandalského útoku).",
+"ipaddress"            => "Adresa IP",
+"ipbreason"            => "Důvod",
+"ipbsubmit"            => "Zablokuj adresu",
+"badipaddress" => "Adresa IP je překroucena.",
+"noblockreason" => "Nutno uvést důvod zablokování.",
+"blockipsuccesssub" => "Úspěšné zablokování",
+"blockipsuccesstext" => "Adresa IP \"$1\" je zablokována.
+<br>Viz [[Special:Ipblocklist|seznam zablokování IP]].",
+"unblockip"            => "Zrušit blokování adresy IP",
+"unblockiptext"        => "Tímto formulářem možno obnovit právo blokované adresy IP opět přispívat do wikipedie.",
+"ipusubmit"            => "Zrušit blokování adresy",
+"ipusuccess"   => "Adresa IP \"$1\" byla uvolněna z blokování",
+"ipblocklist"  => "Seznam blokovaných adres IP",
+"blocklistline"        => "Dne ,  zablokováno ",
+"blocklink"            => "zablokuj",
+"unblocklink"  => "uvolni",
+"contribslink" => "příspěvky",
+
+# Developer tools
+#
+"lockdb"               => "Uzamčít databázi",
+"unlockdb"             => "Odemčít databázi",
+"lockdbtext"   => "Pokud uzamčeš databázi, znemožníš odstatním provádět redakce, volit preference, oblíbené a jiné věci. Potvrď, že to opravdu chceš udělat a že odemčeš databázi hned po opravách.",
+"unlockdbtext" => " Pokud odemčeš databázi, umožníš odstatním provádět redakce, volit preference, oblíbené a jiné věci. Potvrď, že to opravdu chceš udělat.",
+"lockconfirm"  => "Ano, opravdu chci uzamknout databázi.",
+"unlockconfirm"        => "Ano, opravdu chci odemknout databázi.",
+"lockbtn"              => "Zamknout databázi",
+"unlockbtn"            => "Odemknout databázi",
+"locknoconfirm" => "Ne potvrdil jsi.",
+"lockdbsuccesssub" => "Databáze uzamknuta",
+"unlockdbsuccesssub" => "Databáze odemknuta",
+"lockdbsuccesstext" => "Databáze wikipedie je uzamknuta.
+<br>Nezapomeň ji odemknout po opravách.",
+"unlockdbsuccesstext" => "Databáze wikipedie je odemknuta.",
+
+# SQL query
+#
+"asksql"               => "Žádost o informace SQL",
+"asksqltext"   => "Tímto formulářem můžeš přímo požádat databázi o informaci SQL.
+Toto může velmi otřást serverem, proto používěj málo a opatrně.",
+"sqlquery"             => "Napiš žádost o informaci",
+"querybtn"             => "Žádej!",
+"selectonly"   => "Žádosti o informace kromě \"SELECT\" jsou omzeny pouze na programátory wikipedie.",
+"querysuccessful" => "Žádost o inforaci byla úspěšná",
+
+# Move page
+#
+"movepage"             => "Přesuň stránku",
+"movepagetext" => "Touto formulí můžeš změnit název stránky a přenést i seznam její historie na nový název. Původní název se stane přesměrovačem na nový název.
+Odkazy na předchozí název <i>ne</i>budou změněny.
+<b>VAROVÁNÍ!</b>
+Může to být drastická a nečekaná změna pro oblíbené stránky. Ujisti se, že si uvědomuješ důsledky, než změnu provedeš.",
+"movearticle"  => "Přesuň stránku",
+"movenologin"  => "Neuvedeno přihlašovací jméno",
+"movenologintext" => "Musíš být přihlášeným uživatelem a <a href=\"" .
+  wfLocalUrl( "Speciala:Userlogin" ) . "\">uveď přihlašovací jméno</a>
+abys mohl stránku přesunout.",
+"newtitle"             => "Na nový název",
+"movepagebtn"  => "Přesuň stránku",
+"pagemovedsub" => "Úspěšně přesunuto",
+"pagemovedtext" => "Stránka \"[[$1]]\" přesunuta na \"[[$2]]\".",
+"articleexists" => "Takto nazvaná stránky již existuje nebo tebou zvolený název je neplatný. Zvol jiný název.",
+"movedto"              => "přesunuto na",
+"movetalk"             => "Přesuň také \"diskusní\" stránku, pokud existuje.",
+"talkpagemoved" => "Diskusní stránka také přesunuta.",
+"talkpagenotmoved" => "Diskusní stránka <strong>není</strong> přesunuta."
+
+);
+
+global $IP;
+include_once("$IP/Utf8Case.php");
+
+class LanguageCs extends LanguageUtf8 {
+
+    function getNamespaces() {
+               global $wgNamespaceNamesCs;
+               return $wgNamespaceNamesCs;
+       }
+
+       function getNsText( $index ) {
+               global $wgNamespaceNamesCs;
+               return $wgNamespaceNamesCs[$index];
+       }
+
+       function getNsIndex( $text ) {
+               global $wgNamespaceNamesCs;
+
+               foreach ( $wgNamespaceNamesCs as $i => $n ) {
+                       if ( 0 == strcasecmp( $n, $text ) ) { return $i; }
+               }
+               if( 0 == strcasecmp( "Special", $text ) ) return -1;
+               if( 0 == strcasecmp( "Wikipedia", $text ) ) return 4;
+               return false;
+       }
+
+       function getQuickbarSettings() {
+               global $wgQuickbarSettingsCs;
+               return $wgQuickbarSettingsCs;
+       }
+
+       function getSkinNames() {
+               global $wgSkinNamesCs;
+               return $wgSkinNamesCs;
+       }
+
+       function getUserToggles() {
+               global $wgUserTogglesCs;
+               return $wgUserTogglesCs;
+       }
+
+       function getLanguageName( $code ) {
+               global $wgLanguageNamesCs;
+               if ( ! array_key_exists( $code, $wgLanguageNamesCs ) ) {
+                       return "";
+               }
+               return $wgLanguageNamesCs[$code];
+       }
+
+       function getMonthName( $key )
+       {
+               global $wgMonthNamesCs;
+               return $wgMonthNamesCs[$key-1];
+       }
+
+       function getMonthAbbreviation( $key )
+       {
+               global $wgMonthAbbreviationsCs;
+               return $wgMonthAbbreviationsCs[$key-1];
+       }
+
+       function getWeekdayName( $key )
+       {
+               global $wgWeekdayNamesCs;
+               return $wgWeekdayNamesCs[$key-1];
+       }
+
+       # Zdědit userAdjust()
+       # Datové a časové funkce možno upřesnit podle jazyka
+       function date( $ts, $adj = false )
+       {
+               if ( $adj ) { $ts = $this->userAdjust( $ts ); }
+
+               $d = (0 + substr( $ts, 6, 2 )) . ". " .
+               $this->getMonthAbbreviation( substr( $ts, 4, 2 ) ) .
+                 " " . 
+                 substr( $ts, 0, 4 );
+               return $d;
+       }
+
+       function time( $ts, $adj = false )
+       {
+               if ( $adj ) { $ts = $this->userAdjust( $ts ); }
+
+               $t = substr( $ts, 8, 2 ) . ":" . substr( $ts, 10, 2 );
+               return $t;
+       }
+
+       function timeanddate( $ts, $adj = false )
+       {
+               return $this->time( $ts, $adj ) . ", " . $this->date( $ts, $adj );
+       }
+
+       # Heredu rfs1123()
+
+       function getValidSpecialPages()
+       {
+               global $wgValidSpecialPagesCs;
+               return $wgValidSpecialPagesCs;
+       }
+
+       function getSysopSpecialPages()
+       {
+               global $wgSysopSpecialPagesCs;
+               return $wgSysopSpecialPagesCs;
+       }
+
+       function getDeveloperSpecialPages()
+       {
+               global $wgDeveloperSpecialPagesCs;
+               return $wgDeveloperSpecialPagesCs;
+       }
+
+       function getMessage( $key )
+       {
+               global $wgAllMessagesCs;
+               if(array_key_exists($key, $wgAllMessagesCs))
+                       return $wgAllMessagesCs[$key];
+               else
+                       return Language::getMessage($key);
+       }
+
+       # Heredu iconv(), ucfirst(), ktp
+
+       function checkTitleEncoding( $s ) {
+               global $wgInputEncoding;
+
+               # Check for non-UTF-8 URLs; assume they are WinLatin2
+               $ishigh = preg_match( '/[\x80-\xff]/', $s);
+               $isutf = ($ishigh ? preg_match( '/^([\x00-\x7f]|[\xc0-\xdf][\x80-\xbf]|' .
+               '[\xe0-\xef][\x80-\xbf]{2}|[\xf0-\xf7][\x80-\xbf]{3})+$/', $s ) : true );
+
+               if( $ishigh and !$isutf )
+                       return iconv( "cp1250", "utf-8", $s );
+
+               return $s;
+       }
+
+}
+
+?>
diff --git a/languages/LanguageDa.php b/languages/LanguageDa.php
new file mode 100644 (file)
index 0000000..607a3a8
--- /dev/null
@@ -0,0 +1,1260 @@
+<?
+
+# NOTE: To turn off "Current Events" in the sidebar,
+# set "currentevents" => "-"
+
+# The names of the namespaces can be set here, but the numbers
+# are magical, so don't change or move them!  The Namespace class
+# encapsulates some of the magic-ness.
+#
+/* private */ $wgNamespaceNamesDa = array(
+       -1      => "Speciel",
+       0       => "",
+       1       => "Diskussion",
+       2       => "Bruger",
+       3       => "Bruger_diskussion",
+       4       => "Wikipedia",
+       5       => "Wikipedia_diskussion",
+       6       => "Billede",
+       7       => "Billede_diskussion"
+);
+
+/* private */ $wgDefaultUserOptionsDa = array(
+       "quickbar" => 1, "underline" => 1, "hover" => 1,
+       "cols" => 80, "rows" => 25, "searchlimit" => 20,
+       "contextlines" => 5, "contextchars" => 50,
+       "skin" => 0, "math" => 1, "rcdays" => 7, "rclimit" => 50,
+       "highlightbroken" => 1, "stubthreshold" => 0
+);
+
+/* private */ $wgQuickbarSettingsDa = array(
+       "Ingen", "Fast venstre", "Fast højre", "Flydende venstre"
+);
+
+/* private */ $wgSkinNamesDa = array(
+       "Standard", "Nostalgi", "Cologne Blå"
+);
+
+/* private */ $wgMathNamesDa = array(
+       "Vis altid som PNG",
+       "HTML hvis meget simpel ellers PNG",
+       "HTML hvis muligt ellers PNG",
+       "Lad være som TeX (for tekst browsere)",
+    "Anbefalet til moderne browsere"
+);
+
+/* private */ $wgUserTogglesDa = array(
+       "hover"         => "Vis svævende tekst over wiki links",
+       "underline" => "Understreg links",
+       "highlightbroken" => "Røde links til tomme sider",
+       "justify"       => "Justér paragraffer",
+       "hideminor" => "Gem små redigeringer i sidste ændringer",
+       "usenewrc" => "Udvidet seneste ændringer (ikke for alle browsere)",
+       "numberheadings" => "Automatisk nummerering af overskrifter",
+       "rememberpassword" => "Husk password til næste besøg",
+       "editwidth" => "Redigeringsboksen har fuld bredde",
+       "editondblclick" => "Rediger sider med dobbeltklik (JavaScript)",
+       "watchdefault" => "Overvåg nye og ændrede artikler",
+       "minordefault" => "Marker som standard alle ændringer som mindre",
+       "previewontop" => "Vis forhåndsvisning før redigeringsboksen"
+       
+);
+
+/* private */ $wgBookstoreListDa = array(
+       "Bibliotek.dk" => "http://bibliotek.dk/vis.php?base=dfa&origin=kommando&field1=ccl&term1=is=$1&element=L&start=1&step=10",
+       "Bogguide.dk" => "http://www.bogguide.dk/find_boeger_bog.asp?ISBN=$1",
+       "AddALL" => "http://www.addall.com/New/Partner.cgi?query=$1&type=ISBN",
+       "PriceSCAN" => "http://www.pricescan.com/books/bookDetail.asp?isbn=$1",
+       "Barnes & Noble" => "http://shop.barnesandnoble.com/bookSearch/isbnInquiry.asp?isbn=$1",
+       "Amazon.com" => "http://www.amazon.com/exec/obidos/ISBN=$1"
+);
+
+/* Note: native names of languages are preferred where known to maximize
+   ease of navigation -- people should be able to recognize their own
+   languages! */
+/* private */ $wgLanguageNamesDa = array(
+    "aa"    => "Afar",
+    "ab"    => "Abkhazian",
+       "af"    => "Afrikaans",
+       "am"    => "Amharisk",
+       "ar" => "&#8238;&#1575;&#1604;&#1593;&#1585;&#1576;&#1610;&#1577;&#8236; (Araby)",
+       "as"    => "Assamesisk",
+       "ay"    => "Aymará",
+       "az"    => "Aserbajdsjansk",
+       "ba"    => "Bajkirsk",
+       "be" => "&#1041;&#1077;&#1083;&#1072;&#1088;&#1091;&#1089;&#1082;&#1080;",
+       "bh"    => "Bihara",
+       "bi"    => "Bislama",
+       "bn"    => "Bengalsk",
+       "bo"    => "Tibetansk",
+       "br" => "Brezhoneg",
+       "bs" => "Bosnisk",
+       "ca" => "Catal&#224;",
+       "ch" => "Chamoru",
+       "co"    => "Korsikansk",
+       "cs" => "&#268;esk&#225;",
+       "cy" => "Cymraeg",
+       "da" => "Dansk", # Note two different subdomains. 
+    "dk" => "Dansk", # 'da' is correct for the language.
+       "de" => "Deutsch",
+       "dz"    => "Bhutansk",
+       "el" => "&#917;&#955;&#955;&#951;&#957;&#953;&#954;&#940; (Ellenika)",
+       "en" => "English",
+       "eo" => "Esperanto",
+       "es" => "Espa&#241;ol",
+       "et" => "Eesti",
+       "eu" => "Euskara",
+       "fa" => "&#8238;&#1601;&#1585;&#1587;&#1609;&#8236;(Farsi)",
+       "fi" => "Suomi",
+       "fj"    => "Fijian",
+       "fo"    => "Færøsk",
+       "fr" => "Fran&#231;ais",
+       "fy"    => "Frisisk",
+       "ga"    => "Irsk",
+       "gl"    => "Galicisk",
+       "gn"    => "Guarani",
+       "gu" => "&#2711;&#2753;&#2716;&#2736;&#2750;&#2724;&#2752; (Gujarati)",
+       "ha"    => "Hausa",
+       "he" => "&#1506;&#1489;&#1512;&#1497;&#1514; (Ivrit)",
+       "hi" => "&#2361;&#2367;&#2344;&#2381;&#2342;&#2368; (Hindi)",
+       "hr" => "Hrvatski",
+       "hu" => "Magyar",
+       "hy"    => "Armensk",
+       "ia" => "Interlingua",
+       "id" => "Indonesia",
+       "ik"    => "Inupiaq",
+       "is" => "&#205;slenska",
+       "it" => "Italiano",
+       "iu"    => "Inuktitut",
+       "ja" => "&#26085;&#26412;&#35486; (Nihongo)",
+       "jv"    => "Javanesisk",
+       "ka" => "&#4325;&#4304;&#4320;&#4311;&#4309;&#4308;&#4314;&#4312; (Kartuli)",
+       "kk"    => "Kasakhisk",
+       "kl"    => "Grønlandsk",
+       "km"    => "Cambodjansk",
+       "kn"    => "Kannaresisk",
+       "ko" => "&#54620;&#44397;&#50612; (Hangukeo)",
+       "ks"    => "Kashmiri",
+       "kw" => "Kernewek",
+       "ky"    => "Kirgisisk",
+       "la" => "Latina",
+       "ln"    => "Lingala",
+       "lo"    => "Laotisk",
+       "lt" => "Lietuvi&#371;",
+       "lv"    => "Lettisk",
+       "mg" => "Malagasy",
+       "mi"    => "Maori",
+       "mk"    => "Makedonisk",
+       "ml"    => "Maltesisk",
+       "mn"    => "Mongolsk",
+       "mo"    => "Moldovisk",
+       "mr"    => "Marathi",
+       "ms" => "Bahasa Melayu",
+       "my"    => "Burmesisk",
+       "na"    => "Nauru",
+       "ne" => "&#2344;&#2375;&#2346;&#2366;&#2354;&#2368; (Nepali)",
+       "nl" => "Nederlands",
+       "no" => "Norsk",
+       "oc"    => "Occitansk",
+       "om"    => "Oromo",
+       "or"    => "Orija",
+       "pa"    => "Panjabi",
+       "pl" => "Polski",
+       "ps"    => "Pashto",
+       "pt" => "Portugu&#234;s",
+       "qu"    => "Kechua",
+       "rm"    => "Rhætoromansk",
+       "rn"    => "Rundi",
+       "ro" => "Rom&#226;n&#259;",
+       "ru" => "&#1056;&#1091;&#1089;&#1089;&#1082;&#1080;&#1081; (Russkij)",
+       "rw"    => "Kinyarwanda",
+       "sa" => "&#2360;&#2306;&#2360;&#2381;&#2325;&#2371;&#2340; (Samskrta)",
+       "sd"    => "Sindhi",
+       "sg"    => "Sango",
+       "sh"    => "Kroatisk",
+       "si"    => "Singalesisk",
+       "simple" => "Simple English",
+       "sk"    => "Slovakisk",
+       "sl"    => "Slovensko",
+       "sm"    => "Samoansk",
+       "sn"    => "Shona",
+       "so" => "Soomaali",
+       "sq" => "Shqiptare",
+       "sr" => "Srpski",
+       "ss"    => "Swati",
+       "st"    => "Sotho",
+       "su"    => "Sudanesisk",
+       "sv" => "Svenska",
+       "sw" => "Kiswahili",
+       "ta"    => "Tamilsk",
+       "te"    => "Telugu",
+       "tg"    => "Tajik",
+       "th"    => "Thai",
+       "ti"    => "Tigrinja",
+       "tk"    => "Turkmensk",
+       "tl"    => "Tagalog",
+       "tn"    => "Tswana",
+       "to"    => "Tonga",
+       "tr" => "T&#252;rk&#231;e",
+       "ts"    => "Tsonga",
+       "tt"    => "Tatarisk",
+       "tw"    => "Twi",
+       "ug"    => "Uigurisk",
+       "uk" => "&#1059;&#1082;&#1088;&#1072;&#1111;&#1085;&#1089;&#1100;&#1082;&#1072; (Ukrayins`ka)",
+       "ur"    => "Urdu",
+       "uz"    => "Uzbekisk",
+       "vi"    => "Vietnamesisk",
+       "vo" => "Volap&#252;k",
+       "wo"    => "Wolof",
+       "xh" => "isiXhosa",
+       "yi"    => "Jiddisch",
+       "yo"    => "Yoruba",
+       "za"    => "Zhuang",
+       "zh" => "&#20013;&#25991; (Zhongwen)",
+       "zu"    => "Zulu"
+);
+
+/* private */ $wgWeekdayNamesDa = array(
+       "Søndag", "Mandag", "Tirsdag", "Onsdag", "Torsdag",
+       "Fredag", "Lørdag"
+);
+
+/* private */ $wgMonthNamesDa = array(
+       "januar", "februar", "marts", "april", "maj", "juni",
+       "juli", "august", "september", "oktober", "november",
+       "december"
+);
+
+/* private */ $wgMonthAbbreviationsDa = array(
+       "Jan", "Feb", "Mar", "Apr", "Maj", "Jun", "Jul", "Aug",
+       "Sep", "Okt", "Nov", "Dec"
+);
+
+# All special pages have to be listed here: a description of ""
+# will make them not show up on the "Special Pages" page, which
+# is the right thing for some of them (such as the "targeted" ones).
+#
+/* private */ $wgValidSpecialPagesDa = array(
+       "Userlogin"     => "",
+       "Userlogout"    => "",
+       "Preferences"   => "Mine brugerindstillinger",
+       "Watchlist"     => "Min overvågningsliste",
+       "Recentchanges" => "Seneste ændringer",
+       "Upload"        => "Upload filer",
+       "Imagelist"     => "Billedliste",
+       "Listusers"     => "Registrerede brugere",
+       "Statistics"    => "Statistik om siden",
+       "Randompage"    => "Tilfældig artikel",
+
+       "Lonelypages"   => "Forældreløse artikler",
+       "Unusedimages"  => "Forældreløse filer",
+       "Popularpages"  => "Populære artikler",
+       "Wantedpages"   => "Mest ønskede artikler",
+       "Shortpages"    => "Korte artikler",
+       "Longpages"     => "Lange artikler",
+       "Newpages"      => "De nyeste artikler",
+       "Intl"          => "Sproglinks",
+       "Allpages"      => "Alle sider efter titel",
+
+       "Ipblocklist"   => "Blokerede IP adresser",
+       "Maintenance"   => "Vedligeholdelsesside",
+       "Specialpages"  => "",
+       "Contributions" => "",
+       "Emailuser"             => "",
+       "Whatlinkshere" => "",
+       "Recentchangeslinked" => "",
+       "Movepage"              => "",
+       "Booksources"   => "Eksterne bogkilder"
+);
+
+/* private */ $wgSysopSpecialPagesDa = array(
+       "Blockip"               => "Bloker en IP adresse",
+       "Asksql"                => "Lav en query i databasen",
+       "Undelete"              => "Se og gendan slettede sider"
+);
+
+/* private */ $wgDeveloperSpecialPagesDa = array(
+       "Lockdb"                => "Skrivebeskyt databasen",
+       "Unlockdb"              => "Gendan skriveadgangen til databasen",
+       "Debug"                 => "Debug information"
+);
+
+/* private */ $wgAllMessagesDa = array(
+
+# Bits of text used by many pages:
+#
+"linktrail"            => "/^([a-z|æ|ø|å]+)(.*)\$/sD",
+"mainpage"             => "Forside",
+"about"                        => "Om",
+"aboutwikipedia" => "Om Wikipedia",
+"aboutpage"            => "Wikipedia:Om",
+"help"                 => "Hjælp",
+"helppage"             => "Wikipedia:Hjælp",
+"wikititlesuffix" => "Wikipedia",
+"bugreports"   => "Fejlrapporter",
+"bugreportspage" => "Wikipedia:Fejlrapporter",
+"faq"                  => "OSS",
+"faqpage"              => "Wikipedia:OSS",
+"edithelp"             => "Hjælp til redigering",
+"edithelppage" => "Wikipedia:Hvordan_redigerer_jeg_en_side",
+"cancel"               => "Afbryd",
+"qbfind"               => "Find",
+"qbbrowse"             => "Gennemse",
+"qbedit"               => "Rediger",
+"qbpageoptions" => "Indstillinger for side",
+"qbpageinfo"   => "Information om side",
+"qbmyoptions"  => "Mine indstillinger",
+"mypage"               => "Min side",
+"mytalk"               => "Min diskussion",
+"currentevents" => "Aktuelle begivenheder",
+"errorpagetitle" => "Fejl",
+"returnto"             => "Tilbage til $1.",
+"fromwikipedia"        => "Fra Wikipedia, den frie encyklopædi.",
+"whatlinkshere"        => "Sider med et link hertil",
+"help"                 => "Hjælp",
+"search"               => "Søg",
+"go"           => "Udfør",
+"history"              => "Historie",
+"printableversion" => "Printervenlig version",
+"editthispage" => "Rediger side",
+"deletethispage" => "Slet side",
+"protectthispage" => "Beskyt side",
+"unprotectthispage" => "Fjern beskyttelse af side",
+"newpage" => "Ny side",
+"talkpage"             => "Diskussionssiden",
+"articlepage"  => "Se artiklen",
+"subjectpage"  => "Se emnesiden",
+"userpage" => "Se brugersiden",
+"wikipediapage" => "Se metasiden",
+"imagepage" =>         "Se billedsiden",
+"viewtalkpage" => "Se diskussion",
+"otherlanguages" => "Andre sprog",
+"redirectedfrom" => "(Omdirigeret fra $1)",
+"lastmodified" => "Sidst ændret den $1.",
+"viewcount"            => "Siden er vist ialt $1 gange.",
+"gnunote" => "Denne side er udgivet under <a class=internal href='/wiki/GNU_FDL'>GNU FDL</a>.",
+"printsubtitle" => "(Fra http://da.wikipedia.org)",
+"protectedpage" => "Beskyttet side",
+"administrators" => "Wikipedia:Administratorer",
+"sysoptitle"   => "Sysop adgang påkrævet",
+"sysoptext"            => "Den funktion du har bedt om kan kun
+udføres af brugere med \"sysop\" status. Se $1.",
+"developertitle" => "Developer adgang påkrævet",
+"developertext"        => "Den funktion du har bedt om kan kun
+udføres af brugere med \"developer\" status. Se $1.",
+"nbytes"               => "$1 bytes",
+"go"                   => "Udfør",
+"ok"                   => "OK",
+"sitetitle"            => "Wikipedia",
+"sitesubtitle" => "Den frie encyklopædi",
+"retrievedfrom" => "Hentet fra \"$1\"",
+"newmessages" => "Du har $1.",
+"newmessageslink" => "nye beskeder",
+
+# Main script and global functions
+#
+"nosuchaction" => "Funktionen findes ikke",
+"nosuchactiontext" => "Den funktion der er specificeret i URL'en kan ikke
+genkendes af Wikipedia softwaren",
+"nosuchspecialpage" => "Sådan en speciel side findes ikke",
+"nospecialpagetext" => "Du har bedt om en speciel side der ikke
+kan genkendes af Wikipedia softwaren.",
+
+# General errors
+#
+"error"                        => "Fejl",
+"databaseerror" => "Database fejl",
+"dberrortext"  => "Der er sket en database query syntax fejl.
+Dette kan være på grund af en illegal søge query (se $5),
+eller det kan betyde en fejl i softwaren.
+Den sidst forsøgte database query var:
+<blockquote><tt>$1</tt></blockquote>
+fra funktionen \"<tt>$2</tt>\".
+MySQL returnerede fejlen \"<tt>$3: $4</tt>\".",
+"noconnect"            => "Kunne ikke forbinde til databasen på $1",
+"nodb"                 => "Kunne ikke vælge databasen $1",
+"readonly"             => "Databasen er skrivebeskyttet",
+"enterlockreason" => "Skriv en begrundelse for skrivebeskyttelsen, inklusive 
+et estimat på hvornår skrivebeskyttelsen vil blive ophævet igen",
+"readonlytext" => "Wikipedia databasen er for øjeblikket skrivebeskyttet for 
+nye sider og andre modifikationer, sandsynligvis for rutinemæssig database 
+vedligeholdelse, hvorefter den vil returnere til normal.
+Den administrator der skrivebeskyttede den har denne forklaring:
+<p>$1",
+"missingarticle" => "Databasen fandt ikke teksten på en side
+som den skulle have fundet, med navnet \"$1\".
+Dette er ikke en database fejl, men sandsynligvis en fejl i softwaren.
+Send venligst en rapport om dette til en administrator, 
+hvor du også nævner URL'en.",
+"internalerror" => "Intern fejl",
+"filecopyerror" => "Kunne ikke kopiere filen \"$1\" til \"$2\".",
+"filerenameerror" => "Kunne ikke omdøbe filen \"$1\" til \"$2\".",
+"filedeleteerror" => "Kunne ikke slette filen \"$1\".",
+"filenotfound" => "Kunne ikke finde filen \"$1\".",
+"unexpected"   => "Uventet værdi: \"$1\"=\"$2\".",
+"formerror"            => "Fejl: kunne ikke afsende form",
+"badarticleerror" => "Denne funktion kan ikke udføres på denne side.",
+"cannotdelete" => "Kunne ikke slette siden eller filen der blev 
+specificeret.",
+"badtitle"             => "Forkert titel",
+"badtitletext" => "Den ønskede sides titel var ulovlig, tom eller siden
+er forkert linket fra en Wikipedia på et andet sprog.",
+"perfdisabled" => "Desværre! Denne funktion er midlertidigt afbrudt, 
+fordi den belaster databasen meget hårdt, i en sådan grad at siden 
+bliver meget langsom. Funktionen bliver forhåbentlig omskrevet i den 
+nærmeste fremtid (måske af dig, vi er jo open source!!).",
+
+# Login and logout pages
+#
+"logouttitle"  => "Bruger log af",
+"logouttext"   => "Du er nu logget af.
+Du kan fortsætte med at bruge Wikipedia anonymt, eller du kan logge på
+igen som den samme eller en anden bruger.\n",
+
+"welcomecreation" => "<h2>Velkommen, $1!</h2><p>Din konto er blevet 
+oprettet. Glem ikke at personliggøre dine Wikipedia indstillinger.",
+
+"loginpagetitle" => "Bruger log på",
+"yourname"             => "Dit brugernavn",
+"yourpassword" => "Dit password",
+"yourpasswordagain" => "Gentag password",
+"newusersonly" => " (kun nye brugere)",
+"remembermypassword" => "Husk mit password til næste gang.",
+"loginproblem" => "<b>Der har været et problem med at logge dig 
+på.</b><br>Prøv igen!",
+"alreadyloggedin" => "<font color=red><b>Bruger $1, du er allerede logget 
+på!</b></font><br>\n",
+"areyounew"            => "Hvis du er ny på Wikipedia og gerne vil have en 
+bruger konto, så indtast et brugernavn, derefter indtaster du et 
+password og gentager samme password. Din e-mail adresse er valgfri; 
+hvis du mister dit password kan du bede om
+at få det sendt til den adresse du har oplyst.<br>\n",
+
+"login"                        => "Log på",
+"userlogin"            => "Log på",
+"logout"               => "Log af",
+"userlogout"   => "Log af",
+"createaccount"        => "Opret en ny konto",
+"badretype"            => "De passwords du indtastede er ikke ens.",
+"userexists"   => "Det brugernavn du har valgt er allerede i brug. Vælg 
+venligst et andet brugernavn.",
+"youremail"            => "Din e-mail *",
+"yournick"             => "Dit øgenavn (til signaturer)",
+"emailforlost" => "* Det er valgfrit om du vil oplyse din e-mail adresse. 
+Men det gør andre brugere i stand til at sende dig en e-mail, uden at 
+du behøves offentliggøre din e-mail adresse, og det gør at du kan få et 
+nyt password sendt til din e-mail adresse.",
+"loginerror"   => "Fejl med at logge på",
+"noname"               => "Du har ikke specificeret et gyldigt brugernavn.",
+"loginsuccesstitle" => "Logget på med success",
+"loginsuccess" => "Du er nu logget på Wikipedia som \"$1\".",
+"nosuchuser"   => "Der er ingen bruger med navnet \"$1\".
+Tjek stavemåden igen, eller brug formen herunder til at lave en ny bruger 
+konto.",
+"wrongpassword"        => "Det password du indtastede var forkert. Prøv igen.",
+"mailmypassword" => "Send mig et nyt password med e-mail",
+"passwordremindertitle" => "Nyt password fra Wikipedia",
+"passwordremindertext" => "Nogen (sandsynligvis dig, fra IP adressen $1)
+har bedt om at vi sender dig et nyt password til at logge på Wikipedia.
+Det nye password for bruger \"$2\" er nu \"$3\".
+Du bør logge på nu og ændre dit password.",
+"noemail"              => "Der er ikke oplyst nogen e-mail adresse for bruger \"$1\".",
+"passwordsent" => "Et nyt password er sendt til e-mail adressen
+der er registreret for \"$1\".
+Du bør logge på og ændre dit password straks efter du har modtaget det.",
+
+# Edit pages
+#
+"summary"              => "Beskrivelse",
+"minoredit"            => "Dette er en mindre ændring.",
+"watchthis"            => "Overvåg denne artikel",
+"savearticle"  => "Gem side",
+"preview"              => "Forhåndsvisning",
+"showpreview"  => "Forhåndsvisning",
+"blockedtitle" => "Brugeren er blokeret",
+"blockedtext"  => "Dit brugernavn eller din IP adresse er blevet blokeret af 
+$1. Begrundelsen der er blevet givet er denne:<br>$2<p>Du kan kontakte 
+administratoren for at diskutere blokeringen.",
+"newarticle"   => "(Ny)",
+"newarticletext" => "Der er på nuværende tidspunkt ingen tekst på denne side.<br>
+Du kan begynde en artikel ved at skrive i boksen herunder. 
+(se [[Wikipedia:Hjælp|hjælpen]] for yderligere information).<br>
+Hvis det ikke var din mening, så tryk på '''Tilbage''' eller '''Back''' knappen.",
+"anontalkpagetext" => "---- ''Dette er en diskussionsside for anonyme brugere der 
+ikke har oprettet en konto endnu eller ikke bruger den. Vi er derfor nødt til at 
+bruge den nummeriske [[IP adresse]] til at identificere ham eller hende.
+En IP adresse kan være delt mellem flere brugere. Hvis du er en anonym bruger 
+og syntes at du har fået irrelevante kommentarer på sådan en side, så vær 
+venlig og [[Speciel:Userlogin|logge på]] så vi undgår fremtidige 
+forvekslinger med andre anonyme brugere.'' ",
+"noarticletext" => "(Der er på nuværende tidspunkt ingen tekst på denne 
+side)",
+"updated"              => "(Opdateret)",
+"note"                 => "<strong>Note:</strong> ",
+"previewnote"  => "Husk at dette er kun en forhåndsvisning, og siden er ikke 
+gemt endnu!",
+"previewconflict" => "Denne forhåndsvisning er resultatet af den 
+redigerbare tekst ovenfor,
+sådan vil det komme til at se ud hvis du vælger at gemme teksten.",
+"editing"              => "Redigerer $1",
+"editconflict" => "Redigeringskonflikt: $1",
+"explainconflict" => "Nogen har ændret denne side efter du
+startede på at redigerer den.
+Den øverste tekst boks indeholder den nuværende tekst.
+Dine ændringer er vist i den nederste tekst boks.
+Du er nødt til at sammenflette dine ændringer med den eksisterende tekst.
+<b>Kun</b> teksten i den øverste tekst boks vil blive gemt når du
+trykker \"Gem side\".\n<p>",
+"yourtext"             => "Din tekst",
+"storedversion" => "Den gemte version",
+"editingold"   => "<strong>ADVARSEL: Du redigerer en gammel version
+af denne side
+Hvis du gemmer den, vil alle ændringer lavet siden denne revision være 
+overskrevet.</strong>\n",
+"yourdiff"             => "Forskelle",
+"copyrightwarning" => "Læg mærke til at alle bidrag til Wikipedia er
+at betragte som udgivet under GNU Free Documentation License
+(se $1 for detaljer).
+Hvis du ikke vil have din tekst redigeret uden nåde og kopieret efter
+forgodtbefindene, så skal du ikke lægge det her.<br>
+Du lover os også at du skrev teksten selv, eller kopierede fra en
+public domain eller lignende fri resurce.
+<strong>LÆG ALDRIG MATERIALE HER SOM ER BESKYTTET AF ANDRES OPHAVSRET UDEN 
+DERES TILLADELSE!</strong>",
+"longpagewarning" => "ADVARSEL: Denne side er $1 kilobytes lang; nogle
+browsere kan have problemer med at redigerer sider der nærmer sig eller 
+er længere end 32kb. Overvej om ikke siden kan splittes op i mindre dele.",
+
+# History pages
+#
+"revhistory"   => "Versionshistorie",
+"nohistory"            => "Der er ingen versionshistorie for denne side.",
+"revnotfound"  => "Versionen er ikke fundet",
+"revnotfoundtext" => "Den gamle version af den side du spurgte efter kan 
+ikke findes. Tjek den URL du brugte til at få adgang til denne side.\n",
+"loadhist"             => "Læser sidens historie",
+"currentrev"   => "Nuværende version",
+"revisionasof" => "Versionen fra $1",
+"cur"                  => "nuværende",
+"next"                 => "næste",
+"last"                 => "forrige",
+"orig"                 => "originale",
+"histlegend"   => "Forklaring: (nuværende) = forskel til den nuværende 
+version, (forrige) = forskel til den forrige version, M = mindre ændring",
+
+# Diffs
+#
+"difference"   => "(Forskelle mellem versioner)",
+"loadingrev"   => "læser version til at se forskelle",
+"lineno"               => "Linje $1:",
+"editcurrent"  => "Rediger den nuværende version af denne side",
+
+# Search results
+#
+"searchresults" => "Søge resultater",
+"searchhelppage" => "Wikipedia:Søgning",
+"searchingwikipedia" => "Søgning på Wikipedia",
+"searchresulttext" => "For mere information om søgning på Wikipedia, se 
+$1.",
+"searchquery"  => "For query \"$1\"",
+"badquery"             => "Forkert udformet søge forespørgsel",
+"badquerytext" => "Vi kunne ikke udføre din forespørgsel.
+Det er sandsynligvis fordi du har forsøgt at søge efter et ord med
+færre end tre bogstaver, hvilket ikke understøttes endnu.
+Det kan også være du har skrevet forkert, for
+eksempel \"fisk og og skaldyr\".
+Prøv en anden forespørgsel.",
+"matchtotals"  => "Forespørgslen \"$1\" matchede $2 artikel titler
+og teksten i $3 artikler.",
+"nogomatch" => "Ingen sider med præcis denne titel eksisterer, prøver 
+fuldtekstsøgning istedet for. ",
+"titlematches" => "Artikel titler der matchede forespørgslen",
+"notitlematches" => "Ingen artikel titler matchede forespørgslen",
+"textmatches"  => "Artikel tekster der matchede forespørgslen",
+"notextmatches"        => "Ingen artikel tekster matchede forespørgslen",
+"prevn"                        => "forrige $1",
+"nextn"                        => "næste $1",
+"viewprevnext" => "Vis ($1) ($2) ($3).",
+"showingresults" => "Nedenfor vises <b>$1</b> resultater startende med 
+nummer <b>$2</b>.",
+"nonefound"            => "<strong>Note</strong>: søgning uden success er tit
+forårsaget af at man søger efter almindelige ord som \"har\" og \"fra\",
+som ikke er indekseret, eller ved at specificere mere end et søgeord (kun 
+sider der indeholder alle søgeordene vil blive fundet).",
+"powersearch" => "Søg",
+"powersearchtext" => "
+Søg i navnerum :<br>
+$1<br>
+$2 List omdirigeringer &nbsp; Søg efter $3 $9",
+
+
+# Preferences page
+#
+"preferences"  => "Indstillinger",
+"prefsnologin" => "Ikke logget på",
+"prefsnologintext"     => "Du skal være <a href=\"" .
+  wfLocalUrl( "Speciel:Userlogin" ) . "\">logget på</a>
+for at ændre bruger indstillinger.",
+"prefslogintext" => "Du logget på som \"$1\".
+Dit interne ID nummer er $2.",
+"prefsreset"   => "Indstillingerne er blevet gendannet fra lageret.",
+"qbsettings"   => "Indstillinger for hurtigmenu",
+"changepassword" => "Skift password",
+"skin"                 => "Udseende",
+"math"                 => "Vise matematik",
+"math_failure"         => "Fejl i matematikken",
+"math_unknown_error"   => "ukendt fejl",
+"math_unknown_function"        => "ukendt funktion ",
+"math_lexing_error"    => "lexer fejl",
+"math_syntax_error"    => "syntax fejl",
+"saveprefs"            => "Gem indstillinger",
+"resetprefs"   => "Gendan indstillinger",
+"oldpassword"  => "Gammelt password",
+"newpassword"  => "Nyt password",
+"retypenew"            => "Gentag nyt password",
+"textboxsize"  => "Tekstboks dimensioner",
+"rows"                 => "Rækker",
+"columns"              => "Kolonner",
+"searchresultshead" => "Søge resultat indstillinger",
+"resultsperpage" => "Resultater pr. side",
+"contextlines" => "Linjer pr. resultat",
+"contextchars" => "Karakterer pr. linje i resultatet",
+"stubthreshold" => "Grænse for visning af stubs",
+"recentchangescount" => "Antallet af titler på \"seneste ændringer\" 
+siden",
+"savedprefs"   => "Dine indstillinger er blevet gemt.",
+"timezonetext" => "Indtast antal timer din lokale tid er forskellig
+fra server (UTC) tiden. Der bliver automatisk tilpasset til dansk tid, 
+ellers skulle man for eksempel for Dansk vintertid, indtaste \"1\" 
+(og \"2\" når vi er på sommertid).",
+"localtime"    => "Lokal tid",
+"timezoneoffset" => "Forskel",
+"emailflag"    => "Fravælg muligheden for at få e-mail fra andre brugere",
+
+# Recent changes
+#
+"changes" => "ændringer",
+"recentchanges" => "Seneste ændringer",
+"recentchangestext" => "Se de senest ændrede sider i Wikipedia på denne 
+side.
+
+[[Wikipedia:Velkommen nybegynder|Velkommen nybegynder]]!
+Kig venligst på disse sider: [[Wikipedia:Hjælp|Hjælp]], 
+[[Wikipedia:OSS|Ofte Stillede Spørgsmål]] og 
+[[Wikipedia:Mest almindelige begynderfejl på Wikipedia|mest almindelige begynderfejl på Wikipedia]].
+
+Det er meget vigtigt for Wikipedias success, at du ikke lægger materiale på 
+Wikipedia som andre har ophavsret til. De retslige konsekvenser kan blive 
+meget kostbare og besværlige
+for projektet, så lad venligst være med det.
+
+Se også seneste ændringer for andre sprog: 
+[http://meta.wikipedia.org/wiki/Special:Recentchanges meta], 
+[http://de.wikipedia.org/wiki/Spezial:Recentchanges de], 
+[http://www.wikipedia.org/wiki/Special:Recentchanges en], 
+[http://eo.wikipedia.org/wiki/Speciala:Recentchanges eo], 
+[http://es.wikipedia.org/wiki/Especial:Recentchanges es], 
+[http://et.wikipedia.com/wiki.cgi?Recent_Changes et], 
+[http://fr.wikipedia.org/wiki/Special:Recentchanges fr], 
+[http://it.wikipedia.com/wiki.cgi?RecentChanges it], 
+[http://la.wikipedia.com/wiki.cgi?Recent_Changes la], 
+[http://nl.wikipedia.org/wiki/Speciaal:Recentchanges nl], 
+[http://no.wikipedia.com/wiki.cgi?Recent_Changes no], 
+[http://pl.wikipedia.org/wiki/Specjalna:Recentchanges pl], 
+[http://pt.wikipedia.com/wiki.cgi?RecentChanges pt], 
+[http://ru.wikipedia.org/wiki/Special:Recentchanges ru] og 
+[http://sv.wikipedia.org/wiki/Special:Recentchanges sv].",
+"rcloaderr"            => "Læser seneste ændrede sider",
+"rcnote"               => "Nedenfor er de seneste <strong>$1</strong> ændringer i de 
+sidste <strong>$2</strong> dage.",
+"rcnotefrom"   => "Nedenfor er ændringerne fra <b>$2</b> indtil <b>$1</b> vist.",
+"rclistfrom"   => "Vis nye ændringer startende fra $1",
+# "rclinks"            => "Vis seneste $1 ændringer i de sidste $2 timer / sidste $3 dage",
+"rclinks"              => "Vis seneste $1 ændringer i de sidste $2 dage.",
+"rchide"               => "i $4 form; $1 mindre ændringer; $2 andre navnerum; $3 mere end en redigering.",
+"diff"                 => "forskel",
+"hist"                 => "historie",
+"hide"                 => "gem",
+"show"                 => "vis",
+"tableform"            => "tabel",
+"listform"             => "liste",
+"nchanges"             => "$1 ændringer",
+"minoreditletter" => "M",
+"newpageletter" => "N",
+
+# Upload
+#
+"upload"               => "Upload",
+"uploadbtn"            => "Upload fil",
+"uploadlink"   => "Upload fil",
+"reupload"             => "Gen-upload",
+"reuploaddesc" => "Tilbage til upload formen.",
+"uploadnologin" => "Ikke logget på",
+"uploadnologintext"    => "Du skal være <a href=\"" .
+  wfLocalUrl( "Speciel:Userlogin" ) . "\">logget på</a>
+for at kunne uploade filer.",
+"uploadfile"   => "Upload fil",
+"uploaderror"  => "Upload fejl",
+"uploadtext"   => "<strong>STOP!</strong> Før du uploader her,
+så vær sikker på du har læst og følger Wikipedias <a href=\"" .
+wfLocalUrlE( "Wikipedia:Politik om brug af billeder" ) . "\">politik om brug 
+af billeder</a>.
+<p>For at se eller søge i tidligere uploadede billeder,
+gå til <a href=\"" . wfLocalUrlE( "Speciel:Imagelist" ) .
+"\">listen af uploadede billeder</a>.
+Uploads og sletninger er logget i <a href=\"" .
+wfLocalUrlE( "Wikipedia:Upload_log" ) . "\">upload log</a>.
+<p>Brug formularen herunder til at uploade nye billeder til at bruge
+som illustration i dine artikler.
+På de fleste browsere vil du se en \"Browse...\" knap eller en 
+\"Gennemse...\" knap, som vil
+bringe dig til operativsystemets standard fil åben dialog.
+Når du vælger en fil vil navnet på filen dukke op i tekst feltet
+ved siden af knappen.
+Du skal også verificerer at du ikke er ved at bryde nogens ophavsret.
+Det gør du ved at sætte et mærke i check boksen.
+Tryk på \"Upload\" knappen for at afslutte din upload.
+Dette kan godt tage lidt tid hvis du har en langsom internet forbindelse.
+<p>De foretrukne formater er JPEG til fotografiske billeder, PNG
+til tegninger og andre små billeder, og OGG til lyd.
+Sørg for at navngive din fil med et beskrivende navn, for at undgå 
+forvirring om indholdet.
+For at bruge billedet i en artikel, så brug et link af denne slags
+<b>[[billede:fil.jpg]]</b> eller <b>[[billede:fil.png|alternativ tekst]]</b>
+eller <b>[[media:fil.ogg]]</b> for lyd.
+<p>Læg mærke til at præcis som med Wikipedia sider, så kan og må andre gerne 
+redigerer eller
+slette dine uploadede filer hvis de mener det hjælper encyklopædien, og
+du kan blive blokeret fra at uploade hvis du misbruger systemet.",
+"uploadlog"            => "upload log",
+"uploadlogpage" => "Upload_log",
+"uploadlogpagetext" => "Herunder er der en liste af de seneste 
+uploadede filer. Alle de viste tider er server (UTC) tider.
+<ul>
+</ul>
+",
+"filename"             => "Filnavn",
+"filedesc"             => "Beskrivelse",
+"affirmation"  => "Jeg bekræfter at ophavsretshaveren til denne fil
+er enig i at filen udgives under betingelserne for $1.",
+"copyrightpage" => "Wikipedia:Ophavsret",
+"copyrightpagename" => "Wikipedia ophavsret",
+"uploadedfiles"        => "Uploadede filer",
+"noaffirmation" => "Du skal bekræfte at du ikke bryder nogens ophavsret
+ved at uploade denne fil.",
+"ignorewarning"        => "Ignorer advarslen og gem filen alligevel.",
+"minlength"            => "Navnet på filen skal være på mindst tre bogstaver.",
+"badfilename"  => "Navnet på filen er blevet ændret til \"$1\".",
+"badfiletype"  => "\".$1\" er ikke et af de anbefalede fil formater.",
+"largefile"            => "Det anbefales at filer ikke fylder mere end 100kb.",
+"successfulupload" => "Upload gennemført med success",
+"fileuploaded" => "Filen \"$1\" er uploadeded med success.
+Følg dette link: ($2) til siden med beskrivelse og udfyld
+information omkring filen, såsom hvor den kom fra, hvornår den er lavet
+og af hvem, og andre ting du ved om filen.",
+"uploadwarning" => "Upload advarsel",
+"savefile"             => "Gem fil",
+"uploadedimage" => "uploadede \"$1\"",
+
+# Image list
+#
+"imagelist"            => "Billedliste",
+"imagelisttext"        => "Herunder er en liste med $1 billeder sorteret $2.",
+"getimagelist" => "henter billedliste",
+"ilshowmatch"  => "Vis alle billeder med navne der matcher",
+"ilsubmit"             => "Søg",
+"showlast"             => "Vis de sidste $1 billeder sorteret $2.",
+"all"                  => "alle",
+"byname"               => "efter navn",
+"bydate"               => "efter dato",
+"bysize"               => "efter størrelse",
+"imgdelete"            => "slet",
+"imgdesc"              => "beskrivelse",
+"imglegend"            => "Legend: (beskrivelse) = vis/rediger billede beskrivelse.",
+"imghistory"   => "Billedhistorie",
+"revertimg"            => "gendan",
+"deleteimg"            => "slet",
+"imghistlegend" => "Legend: (nuværende) = dette er det nuværende billede, 
+(slet) = slet denne gamle version, (gendan) = gendan en gammel version.
+<br><i>Klik på en dato for at se billedet som er uploaded den dag</i>.",
+"imagelinks"   => "Billede links",
+"linkstoimage" => "De følgende sider linker til dette billede:",
+"nolinkstoimage" => "Der er ingen sider der linker til dette billede.",
+
+# Statistics
+#
+"statistics"   => "Statistik",
+"sitestats"            => "Side statistik",
+"userstats"            => "Bruger statistik",
+"sitestatstext" => "Der er ialt <b>$1</b> sider i databasen.
+Dette inkluderer \"diskussion\" sider, sider om Wikipedia, minimale \"stub\"
+sider, omdirigeringssider, og andre der sikkert ikke kan kvalificeres som 
+artikler.
+Hvis man ekskludere disse, så er der <b>$2</b> sider som sandsynligvis er 
+rigtige artikler.<p>
+Der har ialt været <b>$3</b> viste sider, og <b>$4</b> redigeringer af sider
+siden softwaren blev opdateret (25. september 2002).
+Det vil sige der har været <b>$5</b> gennemsnitlige redigeringer per side, 
+og <b>$6</b> visninger per redigering.",
+"userstatstext" => "Der er  <b>$1</b> registrerede brugere.
+<b>$2</b> af disse er administratorer (se $3).",
+
+# Maintenance Page
+#
+"maintenance"          => "Vedligeholdelsesside",
+"maintnancepagetext"   => "På denne side er der forskellige smarte 
+værktøjer til at vedligeholde Wikipedia. Nogle af disse funktioner er ret 
+hårde for databasen (de tager lang tid), så lad være med at refreshe siden 
+hver gang du har rettet en enkelt ting ;-)",
+"maintenancebacklink"  => "Tilbage til vedligeholdelsessiden",
+"disambiguations"      => "Sider med tvetydige titler",
+"disambiguationspage"  => "Wikipedia:Links_til_sider_med_tvetydige_titler",
+"disambiguationstext"  => "De følgende artikler linker til 
+<i>sider med tvetydige titler</i>. De skulle linke til en ikke-tvetydig 
+titel i stedet for.<br>En side bliver behandlet som tvetydig hvis den er
+linket fra $1.<br>Links fra andre navnerum er <i>ikke</i> listet her.",
+"doubleredirects"      => "Dobbelte omdirigeringer",
+"doubleredirectstext"  => "<b>Bemærk:</b> Denne liste kan indeholde forkerte 
+resultater. Det er som regel fordi siden indeholder ekstra tekst under den
+første #REDIRECT.<br>\nHver linje indeholder links til den første og den 
+anden omdirigering, og den første linje fra den anden omdirigeringstekst, 
+det giver som regel den \"rigtige\" mål artikel, som den første omdirigering 
+skulle have peget på.",
+"brokenredirects"      => "Dårlige omdirigeringer",
+"brokenredirectstext"  => "De følgende omdirigeringer peger på en side der 
+ikke eksisterer.",
+"selflinks"            => "Sider der linker til sig selv",
+"selflinkstext"                => "De følgende sider indeholder links til sig selv, 
+men det burde de ikke.",
+"mispeelings"           => "Sider med stavefejl",
+"mispeelingstext"               => "De følgende sider indeholder en af de 
+almindelig stavefejl, som er listet på $1. Den korrekte stavemåde kan 
+angives i paranteser efter den fejlagtige stavemåde (sådan her).",
+"mispeelingspage"       => "Liste af almindelige stavefejl",
+"missinglanguagelinks"  => "Manglende sprog links",
+"missinglanguagelinksbutton"    => "Find manglende sprog links for",
+"missinglanguagelinkstext"      => "Disse artikler har <i>ikke</i> noget 
+link til den samme artikel i $1. Omdirigeringer og underartikler er 
+<i>ikke</i> vist.",
+
+
+# Miscellaneous special pages
+#
+"orphans"              => "Forældreløse sider",
+"lonelypages"  => "Forældreløse sider",
+"unusedimages" => "Ubrugte billeder",
+"popularpages" => "Populære sider",
+"nviews"               => "$1 visninger",
+"wantedpages"  => "Ønskede sider",
+"nlinks"               => "$1 links",
+"allpages"             => "Alle sider",
+"randompage"   => "Tilfældig artikel",
+"shortpages"   => "Korte sider",
+"longpages"            => "Lange sider",
+"listusers"            => "Brugerliste",
+"specialpages" => "Specielle sider",
+"spheading"            => "Specielle sider",
+"sysopspheading" => "Specielle sider til sysop brug",
+"developerspheading" => "Specielle sider til developer brug",
+"protectpage"  => "Beskyt side",
+"recentchangeslinked" => "Relaterede ændringer",
+"rclsub"               => "(til sider linket fra \"$1\")",
+"debug"                        => "Debug",
+"newpages"             => "Nye sider",
+"intl"         => "Sproglinks",
+"movethispage" => "Flyt side",
+"unusedimagestext" => "<p>Læg mærke til at andre web sider
+såsom de andre internationale Wikipediaer måske linker til et billede med
+en direkte URL, så det kan stadig være listet her selvom det er
+i aktivt brug.",
+"booksources"  => "Bogkilder",
+"booksourcetext" => "Herunder er en liste af links til steder der
+udlåner og/eller sælger nye og brugte bøger, og som måske også har 
+yderligere information om bøger du leder efter.
+Wikipedia er ikke associeret med nogen af disse steder,
+og denne liste skal ikke ses som en anbefaling af disse.",
+"alphaindexline" => "$1 til $2",
+
+# Email this user
+#
+"mailnologin"  => "Ingen sende adresse",
+"mailnologintext" => "Du skal være <a href=\"" .
+  wfLocalUrl( "Speciel:Userlogin" ) . "\">logget på</a>
+og have en gyldig e-mail adresse sat i dine <a href=\"" .
+  wfLocalUrl( "Speciel:Preferences" ) . "\">indstillinger</a>
+for at sende e-mail til andre brugere.",
+"emailuser"            => "E-mail til denne bruger",
+"emailpage"            => "E-mail bruger",
+"emailpagetext"        => "Hvis denne bruger har sat en gyldig e-mail adresse i
+sine bruger indstillinger, så vil formularen herunder sende en enkelt 
+besked.
+Den e-mail adresse du har sat i dine bruger indstillinger vil dukke op
+i \"Fra\" feltet på denne mail, så modtageren er i stand til at svare.",
+"noemailtitle" => "Ingen e-mail adresse",
+"noemailtext"  => "Denne bruger har ikke sat en gyldig e-mail adresse,
+eller har valgt ikke at modtage e-mail fra andre brugere.",
+"emailfrom"            => "Fra",
+"emailto"              => "Til",
+"emailsubject" => "Emne",
+"emailmessage" => "Besked",
+"emailsend"            => "Send",
+"emailsent"            => "E-mail sendt",
+"emailsenttext" => "Din e-mail besked er blevet sendt.",
+
+# Watchlist
+#
+"watchlist"            => "Overvågningsliste",
+"watchlistsub" => "(for bruger \"$1\")",
+"nowatchlist"  => "Du har ingenting i din overvågningsliste.",
+"watchnologin" => "Ikke logget på",
+"watchnologintext"     => "Du skal være <a href=\"" .
+  wfLocalUrl( "Speciel:Userlogin" ) . "\">logget på</a>
+for at kunne ændre din overvågningsliste.",
+"addedwatch"   => "Tilføjet til din overvågningsliste",
+"addedwatchtext" => "Siden \"$1\" er blevet tilføjet til din <a href=\"" .
+  wfLocalUrl( "Speciel:Watchlist" ) . "\">overvågningsliste</a>.
+Fremtidige ændringer til denne side og den tilhørende diskussion side vil 
+blive listet her, og siden vil fremstå <b>fremhævet</b> i <a href=\"" .
+  wfLocalUrl( "Speciel:Recentchanges" ) . "\">listen med de seneste 
+ændringer</a> for at gøre det lettere at finde den.</p>
+
+<p>Hvis du senere vil fjerne siden fra din overvågningsliste, så klik 
+\"Fjern overvågning\" ude i siden.",
+"removedwatch" => "Fjernet fra overvågningsliste",
+"removedwatchtext" => "Siden \"$1\" er blevet fjernet fra din 
+overvågningsliste.",
+"watchthispage"        => "Overvåg side",
+"unwatchthispage" => "Fjern overvågning",
+"notanarticle" => "Ikke en artikel",
+
+# Delete/protect/revert
+#
+"deletepage"   => "Slet side",
+"confirm"              => "Bekræft",
+"confirmdelete" => "Bekræft sletning",
+"deletesub"            => "(Sletter \"$1\")",
+"confirmdeletetext" => "Du er ved permanent at slette en side
+eller et billede sammen med hele den tilhørende historie fra databasen.
+Bekræft venligst at du virkelig vil gøre dette, at du forstår
+konsekvenserne, og at du gør dette i overensstemmelse med
+[[Wikipedia:Politik]].",
+"confirmcheck" => "Ja, jeg vil virkelig slette den her.",
+"actioncomplete" => "Gennemført",
+"deletedtext"  => "\"$1\" er slettet.
+Se $2 for en fortegnelse over de nyeste sletninger.",
+"deletedarticle" => "slettet \"$1\"",
+"dellogpage"   => "Sletningslog",
+"dellogpagetext" => "Herunder er en liste over de nyeste sletninger.
+Alle tider er server (UTC) tider.
+<ul>
+</ul>
+",
+"deletionlog"  => "sletningslog",
+"reverted"             => "Gendannet en tidligere version",
+"deletecomment"        => "Begrundelse for sletning",
+"imagereverted" => "Gendannelse af en tidligere version gennemført med 
+success.",
+"rollback"             => "Fjern redigeringer",
+"rollbacklink" => "fjern redigering",
+"cantrollback" => "Kan ikke fjerne redigering; den sidste bruger er den eneste forfatter.",
+"revertpage"   => "Fjernet den seneste redigering lavet af $1",
+
+# Undelete
+"undelete" => "Gendan en slettet side",
+"undeletepage" => "Se og gendan slettede sider",
+"undeletepagetext" => "De følgende sider er slettede, men de findes 
+stadig i arkivet og kan gendannes. Arkivet blivet periodevis slettet.",
+"undeletearticle" => "Gendan slettet artikel",
+"undeleterevisions" => "$1 revisioner arkiveret",
+"undeletehistory" => "Hvis du gendanner siden, vil alle de historiske 
+revisioner også blive gendannet. Hvis en ny side med det samme navn 
+er oprettet siden den blev slettet, så vil de gendannede revisioner 
+dukke op i den tidligere historie, og den nyeste revision vil forblive 
+på siden.",
+"undeleterevision" => "Slettet version fra $1",
+"undeletebtn" => "Gendan!",
+"undeletedarticle" => "gendannet \"$1\"",
+"undeletedtext"   => "Artiklen [[$1]] er blevet gendannet med success.
+Se [[Wikipedia:Sletningslog]] for en fortegnelse over nylige 
+sletninger og gendannelser.",
+
+# Contributions
+#
+"contributions"        => "Bruger bidrag",
+"mycontris" => "Mine bidrag",
+"contribsub"   => "For $1",
+"nocontribs"   => "Ingen ændringer er fundet som matcher disse kriterier.",
+"ucnote"       => "Herunder er denne brugers sidste <b>$1</b> ændringer i de 
+sidste <b>$2</b> dage.",
+"uclinks"      => "Vis de sidste $1 ændringer; vis de sidste $2 dage.",
+"uctop"                => " (top)" ,
+
+# What links here
+#
+"whatlinkshere"        => "Hvad linker hertil",
+"notargettitle" => "Intet mål",
+"notargettext" => "Du har ikke specificeret en mål side eller bruger
+at udføre denne funktion på.",
+"linklistsub"  => "(Liste af links)",
+"linkshere"    => "De følgende sider linker hertil:",
+"nolinkshere"  => "Ingen sider linker hertil.",
+"isredirect"   => "omdirigeringsside",
+
+# Block/unblock IP
+#
+"blockip"              => "Bloker IP adresse",
+"blockiptext"  => "Brug formularen herunder til at blokere for skriveadgangen
+fra en specifik IP adresse.
+Dette må kun gøres for at forhindre vandalisme, og i
+overensstemmelse med [[Wikipedia:Politik|Wikipedia politik]].
+Udfyld en speciel begrundelse herunder (for eksempel med et citat fra
+sider der har været udsat for vandalisme).",
+"ipaddress"            => "IP Adresse",
+"ipbreason"            => "Begrundelse",
+"ipbsubmit"            => "Bloker denne adresse",
+"badipaddress" => "IP adressen er udformet forkert.",
+"noblockreason" => "Du skal angive en begrundelse for denne blokering.",
+"blockipsuccesssub" => "Blokering udført med success",
+"blockipsuccesstext" => "IP adressen \"$1\" er blevet blokeret.
+<br>Se [[Speciel:Ipblocklist|IP blokeringslisten]] for alle blokeringer.",
+"unblockip"            => "Ophæv blokeringen af IP adresse",
+"unblockiptext"        => "Brug formularen herunder for at gendanne skriveadgangen
+for en tidligere blokeret IP adresse.",
+"ipusubmit"            => "Ophæv blokeringen af denne adresse",
+"ipusuccess"   => "IP adressen \"$1\" har fået ophævet blokeringen",
+"ipblocklist"  => "Liste af blokerede IP adresser",
+"blocklistline"        => "$1, $2 blokerede $3",
+"blocklink"            => "bloker",
+"unblocklink"  => "ophæv blokering",
+"contribslink" => "bidrag",
+
+# Developer tools
+#
+"lockdb"               => "Lås database",
+"unlockdb"             => "Lås database op",
+"lockdbtext"   => "At låse databasen vil afbryde alle brugere fra at kunne
+redigerer sider, ændre deres indstillinger, redigerer deres 
+overvågningsliste, og
+andre ting der kræver ændringer i databasen.
+Bekræft venligst at du har til hensigt at gøre dette, og at du vil
+låse databasen op når din vedligeholdelse er overstået.",
+"unlockdbtext" => "At låse databasen op vil vil gøre at alle brugere igen 
+kan
+redigerer sider, ændre deres indstillinger, redigerer deres 
+overvågningsliste, og
+andre ting der kræver ændringer i databasen.
+Bekræft venligst at du har til hensigt at gøre dette.",
+"lockconfirm"  => "Ja, jeg vil virkelig låse databasen.",
+"unlockconfirm"        => "Ja, jeg vil virkelig låse databasen op.",
+"lockbtn"              => "Lås databasen",
+"unlockbtn"            => "Lås databasen op",
+"locknoconfirm" => "Du har ikke bekræftet handlingen.",
+"lockdbsuccesssub" => "Databasen er nu låst",
+"unlockdbsuccesssub" => "Databasen er nu låst op",
+"lockdbsuccesstext" => "Wikipedia databasen er låst.
+<br>Husk at fjerne låsen når du er færdig med din vedligeholdelse.",
+"unlockdbsuccesstext" => "Wikipedia databasen er låst op.",
+
+# SQL query
+#
+"asksql"               => "SQL forespørgsel",
+"asksqltext"   => "Brug formularen herunder til at lave direkte forespørgsler 
+i Wikipedia databasen.
+Brug enkelte anførselstegn ('sådan her') for at adskille strenge.
+Dette kan ofte belaste serveren kraftigt, så brug venligst denne funktion
+med omtanke.",
+"sqlquery"             => "Indtast forespørgsel",
+"querybtn"             => "Afsend forespørgsel",
+"selectonly"   => "Forespørgsler andre end \"SELECT\" er forbeholdt 
+Wikipedia udviklere.",
+"querysuccessful" => "Forespørgsel gennemført med success",
+
+# Move page
+#
+"movepage"             => "Flyt side",
+"movepagetext" => "Når du bruger formularen herunder vil du få omdøbt en 
+side, flyttet hele sidens historie til det nye navn.
+Den gamle titel vil blive en omdirigeringsside til den nye titel.
+Links til den gamle titel vil ikke blive ændret. Sørg for at 
+[[Speciel:Maintenance|tjekke]] for dobbelte eller dårlige omdirigeringer. 
+Du er ansvarlig for, at alle links stadig peger på der hvor det er 
+meningen de skal pege.
+
+Bemærk at siden '''ikke''' kan flyttes hvis der allerede er en side 
+med den nye titel, medmindre den side er tom eller er en omdirigering 
+uden nogen historie. Det betyder at du kan flytte en side tilbage hvor 
+den kom fra, hvis du kommer til at lave en fejl.
+
+<b>ADVARSEL!</b>
+Dette kan være en drastisk og uventet ændring for en populær side;
+vær sikker på at du forstår konsekvenserne af dette før du
+fortsætter.",
+"movepagetalktext" => "Den tilhørende diskussionsside, hvis der er en, 
+vil automatisk blive flyttet med siden '''medmindre:'''
+*Du flytter siden til et andet navnerum,
+*En ikke-tom diskussionsside allerede eksisterer under det nye navn, eller
+*Du fjerner markeringen i boksen nedenunder.
+
+I disse tilfælde er du nødt til at flytte eller sammenflette siden manuelt.",
+"movearticle"  => "Flyt side",
+"movenologin"  => "Ikke logget på",
+"movenologintext" => "Du skal være registreret bruger og være <a href=\"" .
+  wfLocalUrl( "Speciel:Userlogin" ) . "\">logget på</a>
+for at flytte en side.",
+"newtitle"             => "Til ny titel",
+"movepagebtn"  => "Flyt side",
+"pagemovedsub" => "Flytning gennemført",
+"pagemovedtext" => "Siden \"[[$1]]\" er flyttet til \"[[$2]]\".",
+"articleexists" => "En side med det navn eksisterer allerede, eller det
+navn du har valgt er ikke gyldigt. Vælg et andet navn.",
+"talkexists"   => "Siden blev flyttet korrekt, men den tilhørende 
+diskussionsside kunne ikke flyttes, fordi der allerede eksisterer en 
+med den nye titel. Du er nødt til at flette dem sammen manuelt.",
+"movedto"              => "flyttet til",
+"movetalk"             => "Flyt også \"diskussion\" siden, hvis den eksistere.",
+"talkpagemoved" => "Den tilhørende diskussion side blev også flyttet.",
+"talkpagenotmoved" => "Den tilhørende diskussion side blev 
+<strong>ikke</strong> flyttet.",
+
+);
+
+class LanguageDa extends Language {
+
+       function getDefaultUserOptions () {
+               global $wgDefaultUserOptionsDa ;
+               return $wgDefaultUserOptionsDa ;
+               }
+
+       function getBookstoreList () {
+               global $wgBookstoreListDa ;
+               return $wgBookstoreListDa ;
+       }
+
+       function getNamespaces() {
+               global $wgNamespaceNamesDa;
+               return $wgNamespaceNamesDa;
+       }
+
+       function getNsText( $index ) {
+               global $wgNamespaceNamesDa;
+               return $wgNamespaceNamesDa[$index];
+       }
+
+       function getNsIndex( $text ) {
+               global $wgNamespaceNamesDa;
+
+               foreach ( $wgNamespaceNamesDa as $i => $n ) {
+                       if ( 0 == strcasecmp( $n, $text ) ) { return $i; }
+               }
+               return false;
+       }
+
+       function specialPage( $name ) {
+               return $this->getNsText( Namespace::getSpecial() ) . ":" . $name;
+       }
+
+       function getQuickbarSettings() {
+               global $wgQuickbarSettingsDa;
+               return $wgQuickbarSettingsDa;
+       }
+
+       function getSkinNames() {
+               global $wgSkinNamesDa;
+               return $wgSkinNamesDa;
+       }
+
+       function getMathNames() {
+               global $wgMathNamesDa;
+               return $wgMathNamesDa;
+       }
+
+       function getUserToggles() {
+               global $wgUserTogglesDa;
+               return $wgUserTogglesDa;
+       }
+
+       function getLanguageNames() {
+               global $wgLanguageNamesDa;
+               return $wgLanguageNamesDa;
+       }
+
+       function getLanguageName( $code ) {
+               global $wgLanguageNamesDa;
+               if ( ! array_key_exists( $code, $wgLanguageNamesDa ) ) {
+                       return "";
+               }
+               return $wgLanguageNamesDa[$code];
+       }
+
+       function getMonthName( $key )
+       {
+               global $wgMonthNamesDa;
+               return $wgMonthNamesDa[$key-1];
+       }
+
+       function getMonthAbbreviation( $key )
+       {
+               global $wgMonthAbbreviationsDa;
+               return $wgMonthAbbreviationsDa[$key-1];
+       }
+
+       function getWeekdayName( $key )
+       {
+               global $wgWeekdayNamesDa;
+               return $wgWeekdayNamesDa[$key-1];
+       }
+
+       # Inherit userAdjust()
+
+       function date( $ts, $adj = false )
+       {
+               if ( $adj ) { $ts = $this->userAdjust( $ts ); }
+
+               $d = (0 + substr( $ts, 6, 2 )) . ". " .
+                 $this->getMonthAbbreviation( substr( $ts, 4, 2 ) ) . " " .
+                 substr( $ts, 0, 4 );
+               return $d;
+       }
+
+       function time( $ts, $adj = false )
+       {
+               if ( $adj ) { $ts = $this->userAdjust( $ts ); }
+
+               $t = substr( $ts, 8, 2 ) . ":" . substr( $ts, 10, 2 );
+               return $t;
+       }
+
+       function timeanddate( $ts, $adj = false )
+       {
+               return $this->date( $ts, $adj ) . " kl." . $this->time( $ts, $adj );
+       }
+
+       function getValidSpecialPages()
+       {
+               global $wgValidSpecialPagesDa;
+               return $wgValidSpecialPagesDa;
+       }
+
+       function getSysopSpecialPages()
+       {
+               global $wgSysopSpecialPagesDa;
+               return $wgSysopSpecialPagesDa;
+       }
+
+       function getDeveloperSpecialPages()
+       {
+               global $wgDeveloperSpecialPagesDa;
+               return $wgDeveloperSpecialPagesDa;
+       }
+
+       function getMessage( $key )
+       {
+            global $wgAllMessagesDa, $wgAllMessagesEn;
+            $m = $wgAllMessagesDa[$key];
+
+            if ( "" == $m ) { return $wgAllMessagesEn[$key]; }
+            else return $m;
+       }
+}
+
+?>
diff --git a/languages/LanguageDe.php b/languages/LanguageDe.php
new file mode 100644 (file)
index 0000000..1d0bc1a
--- /dev/null
@@ -0,0 +1,932 @@
+<?
+# See Language.php for notes.
+
+/* private */ $wgNamespaceNamesDe = array(
+       -1      => "Spezial",
+       0       => "",
+       1       => "Diskussion",
+       2       => "Benutzer",
+       3       => "Benutzer_Diskussion",
+       4       => "Wikipedia",
+       5       => "Wikipedia_Diskussion",
+       6       => "Bild",
+       7       => "Bild_Diskussion"
+);
+
+/* private */ $wgDefaultUserOptionsDe = array(
+       "quickbar" => 1, "underline" => 1, "hover" => 1,
+       "cols" => 80, "rows" => 25, "searchlimit" => 20,
+       "contextlines" => 5, "contextchars" => 50,
+       "skin" => 0, "math" => 1, "rcdays" => 3, "rclimit" => 50,
+       "highlightbroken" => 1, "stubthreshold" => 0
+);
+
+/* private */ $wgQuickbarSettingsDe = array(
+       "Keine", "Links, fest", "Rechts, fest", "Links, schwebend"
+);
+
+/* private */ $wgSkinNamesDe = array(
+       "Standard", "Nostalgia", "Cologne Blue"
+);
+
+/* private */ $wgMathNamesDe = array(
+       "Immer als PNG",
+       "Einfaches TeX als HTML, sonst PNG",
+       "HTML wenn möglich, sonst PNG",
+       "Als TeX belassen (für Textbrowser)"
+);
+
+
+/* private */ $wgUserTogglesDe = array(
+       "hover" => "Hinweis über interne Verweise",
+       "underline" => "Verweise unterstreichen",
+       "highlightbroken" => "Verweise auf leere Themen hervorheben",
+       "justify"       => "Text als Blocksatz",
+       "hideminor" => "Keine kleinen Änderungen in Letzte Änderungen anzeigen",
+       "usenewrc" => "Erweiterte letzte Änderungen (nicht für alle Browser geeignet)",
+       "numberheadings" => "Überschriften automatisch numerieren",
+       "rememberpassword" => "Passwort merken",
+       "editwidth" => "Text-Eingabefeld mit voller Breite",
+       "editondblclick" => "Seiten mit Doppelklick bearbeiten (JavaScript)",
+       "watchdefault" => "Neue und geänderte Seiten beobachten",
+       "minordefault" => "Alle Änderungen als geringfügig markieren",
+       "previewontop" => "Vorschau vor dem Editierfenster anzeigen"
+);
+
+/* private */ $wgLanguageNamesDe = array(
+       "af" => "Afrikaans",
+       "ar" => "&#1575;&#1604;&#1593;&#1585;&#1576;&#1610;&#1617;&#1577; (Araby)",
+       "ca" => "Català",
+       "cs" => "&#268;esky",
+       "cy" => "Cymraeg",
+       "da" => "Dansk",
+       "dk" => "Dansk",
+       "el" => "&#917;&#955;&#955;&#951;&#957;&#953;&#954;&#940; (Ellinika)",
+       "en" => "English",
+       "simple" => "Einfaches Englisch",
+       "eo" => "Esperanto",
+       "es" => "Español",
+       "et" => "Esti",
+       "eu" => "Euskara",
+       "fi" => "Suomi",
+       "fr" => "Français",
+       "fy" => "Frysk",
+       "ga" => "Gaeilge",
+       "he" => "&#1506;&#1489;&#1512;&#1497;&#1514; (Ivrit)",
+       "hr" => "Hrvatski",
+       "hu" => "Magyar",
+       "ia" => "Interlingua",
+       "id" => "Indonesia",
+       "is" => "Íslenska",
+       "it" => "Italiano",
+       "ja" => "&#26085;&#26412;&#35486; (Nihongo)",
+       "ko" => "&#54620;&#44397;&#50612; (Hangul)",
+       "la" => "Latina",
+       "lt" => "Lietuvi&#371;",
+       "nl" => "Nederlands",
+       "no" => "Norsk",
+       "pl" => "Polski",
+       "pt" => "Português",
+       "ro" => "Român&#259;",
+       "ru" => "&#1056;&#1091;&#1089;&#1089;&#1082;&#1080;&#1081; (Russkij)",
+       "sh" => "Serbocroatisch",
+       "sl" => "Slovensko",
+       "sv" => "Svenska",
+       "sw" => "Kiswahili",
+       "tr" => "Türkçe",
+       "uk" => "&#1059;&#1082;&#1088;&#1072;&#1111;&#1085;&#1089;&#1100;&#1082;&#1072; (Ukrayins`ka)",
+       "zh" => "&#20013;&#25991; (Zhongwen)",
+);
+
+/* private */ $wgBookstoreListDe = array(
+       "Verzeichnis lieferbarer B&uuml;cher" => "http://www.buchhandel.de/sixcms/list.php?page=buchhandel_profisuche_frameset&suchfeld=isbn&suchwert=$1&x=0&y=0",
+       "abebooks.de" => "http://www.abebooks.de/servlet/BookSearchPL?ph=2&isbn=$1",
+       "Amazon.de" => "http://www.amazon.de/exec/obidos/ISBN=$1",
+       "Lehmanns Fachbuchhandlung" => "http://www.lob.de/cgi-bin/work/suche?flag=new&stich1=$1",
+);
+
+/* private */ $wgWeekdayNamesDe = array(
+       "Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag",
+       "Freitag", "Samstag"
+);
+
+/* private */ $wgMonthNamesDe = array(
+       "Januar", "Februar", "März", "April", "Mai", "Juni",
+       "Juli", "August", "September", "Oktober", "November",
+       "Dezember"
+);
+
+/* private */ $wgMonthAbbreviationsDe = array(
+       "Jan", "Feb", "Mär", "Apr", "Mai", "Jun", "Jul", "Aug",
+       "Sep", "Okt", "Nov", "Dez"
+);
+
+/* private */ $wgValidSpecialPagesDe = array(
+       "Userlogin"             => "",
+       "Userlogout"    => "",
+       "Preferences"   => "Meine Benutzereinstellungen",
+       "Watchlist"             => "Meine Beobachtungsliste",
+       "Recentchanges" => "Zeige Letzte Änderungen",
+       "Upload"                => "Dateien hochladen",
+       "Imagelist"             => "Zeige hochgeladene Dateien",
+       "Listusers"             => "Zeige registrierte Benutzer",
+       "Statistics"    => "Zeige Seitenstatistik",
+       "Randompage"    => "Zufälliger Artikel",
+
+       "Lonelypages"   => "Zeige verwaiste Artikel",
+       "Unusedimages"  => "Zeige verwaiste Dateien",
+       "Popularpages"  => "Zeige beliebte Artikel",
+       "Wantedpages"   => "Zeige gewünschte Artikel",
+       "Shortpages"    => "Zeige kurze Artikel",
+       "Longpages"             => "Zeige lange Artikel",
+       "Newpages"              => "Zeige neue Artikel",
+       "Allpages"              => "Zeige alle Artikel (alphabetisch)",
+
+       "Ipblocklist"   => "Zeige blockierte IP-Addressen",
+       "Maintenance" => "Wartungsseite",
+       "Specialpages"  => "",
+       "Contributions" => "",
+       "Movepage"              => "",
+       "Emailuser"     => "",
+       "Whatlinkshere" => "",
+       "Recentchangeslinked" => "",
+       "Booksources"   => "Externe Buchhandlungen"
+);
+
+/* private */ $wgSysopSpecialPagesDe = array(
+       "Blockip"               => "Blockiere eine IP-Addresse",
+       "Asksql"                => "Datenbank-Abfrage",
+       "Undelete"              => "Gelöschte Seiten anzeigen und wiederherstellen"
+);
+
+/* private */ $wgDeveloperSpecialPagesDe = array(
+       "Lockdb"                => "Datenbank auf 'nur lesen' stellen",
+       "Unlockdb"              => "Datenbank Schreibzugriff wieder herstellen",
+       "Debug"                 => "Zeige debugging information"
+);
+
+/* private */ $wgAllMessagesDe = array(
+
+# Bits of text used by many pages:
+#
+"linktrail"            => "/^([ä|ö|ü|ß|a-z]+)(.*)\$/sD",
+"mainpage"             => "Hauptseite",
+"about"                        => "Über",
+"aboutwikipedia" => "Über Wikipedia",
+"aboutpage"            => "Wikipedia:Über_Wikipedia",
+"help"                 => "Hilfe",
+"helppage"             => "Wikipedia:Hilfe",
+"bugreports"   => "Fehlerliste",
+"bugreportspage" => "Wikipedia:Beobachtete_Fehler",
+"faq"                  => "FAQ",
+"faqpage"              => "Wikipedia:Häufig_gestellte_Fragen",
+"edithelp"             => "Editierhilfe",
+"edithelppage" => "Wikipedia:Wie_man_eine_Seite_bearbeitet",
+"cancel"               => "Abbruch",
+"qbfind"               => "Finden",
+"qbbrowse"             => "Blättern",
+"qbedit"               => "Ändern",
+"qbpageoptions" => "Seitenoptionen",
+"qbpageinfo"   => "Seitendaten",
+"qbmyoptions"  => "Einstellungen",
+"mypage"               => "Meine Seite",
+"mytalk"               => "Meine Diskussion",
+"currentevents" => "-",
+"errorpagetitle" => "Fehler",
+"returnto"             => "Zurück zu $1.",
+"fromwikipedia"        => "aus Wikipedia, der freien Enzyklopädie",
+"whatlinkshere"        => "Was zeigt hierhin",
+"help"                 => "Hilfe",
+"search"               => "Suche",
+"history"              => "Versionen",
+"printableversion" => "Druckversion",
+"editthispage" => "Seite bearbeiten",
+"deletethispage" => "Artikel löschen",
+"protectthispage" => "Artikel schützen",
+"unprotectthispage" => "Schutz aufheben",
+"newpage" => "Neue Seite",
+"talkpage"             => "Diskussion",
+"articlepage"  => "Artikel",
+"wikipediapage" => "Wikipedia-Text",
+"userpage" => "Benutzerseite",
+"imagepage" => "Bildseite",
+"viewtalkpage" => "Diskussion",
+"otherlanguages" => "Andere Sprachen",
+"redirectedfrom" => "(Weitergeleitet von $1)",
+"lastmodified" => "Diese Seite wurde zuletzt geändert um $1.",
+"viewcount"            => "Diese Seite wurde bisher $1 mal abgerufen.",
+"gnunote" => "Diese Seite ist unter der <a class=internal href='/wiki/GNU_FDL'>GNU FDL</a> verfügbar.",
+"printsubtitle" => "(Von http://de.wikipedia.com)",
+"protectedpage" => "Geschützte Seite",
+"administrators" => "Wikipedia:Administratoren",
+"sysoptitle"   => "Sysop-Zugang notwendig",
+"sysoptext"            => "Dieser Vorgang kann aus Sicherheitsgründen nur von Benutzern mit \"Sysop\"-Status durchgeführt werden. Siehe auch $1.",
+"developertitle" => "Entwickler-Zugang notwendig",
+"developertext"        => "Dieser Vorgang kann aus Sicherheitsgründen nur von Benutzern mit \"Entwickler\"-Status durchgeführt werden. Siehe auch $1.",
+"nbytes"               => "$1 Byte",
+"go"                   => "Los",
+"ok"                   => "OK",
+"sitetitle"            => "Wikipedia",
+"sitesubtitle" => "Die freie Enzyklopädie",
+"retrievedfrom" => "Von \"$1\"",
+
+# Main script and global functions
+#
+"nosuchaction" => "Diese Aktion gibt es nicht",
+"nosuchactiontext" => "Diese Aktion wird von der Wikipedia-Software nicht unterstützt",
+"nosuchspecialpage" => "Diese Spezialseite gibt es nicht",
+"nospecialpagetext" => "Diese Spezialseite wird von der Wikipedia-Software nicht unterstützt",
+
+# General errors
+#
+"databaseerror" => "Fehler in der Datenbank",
+"dberrortext"  => "Es gab einen Syntaxfehler in der Datenbankabfrage.
+Das könnte eine illegale Suchanfrage sein (siehe $5),
+oder ein Softwarefehler.
+Die letzte Datenbankabfrage lautete:
+<blockquote><tt>$1</tt></blockquote>
+aus der Funktion \"<tt>$2</tt>\".
+MySQL meldete den Fehler \"<tt>$3: $4</tt>\".",
+"noconnect"            => "Konnte keine Verbindung zur Datenbank auf $1 herstellen",
+"nodb"                 => "Konnte Datenbank $1 nicht auswählen",
+"readonly"             => "Datenbank ist geperrt",
+"readonlytext" => "Die Datenbank der Wikipedia ist vorrübergehend gesperrt, z.B. für Wartungsarbeiten. Bitte versuchen Sie es später noch einmal\n",
+"missingarticle" => "Der Text für den Artikel \"$1\" wurde nicht in der Datenbank gefunden. Das ist wahrscheinlich ein Fehler in der Software. Bitte melden Sie dies einem Administrator, und geben sie den Artikelnamen an.",
+"internalerror" => "Interner Fehler",
+"filecopyerror" => "Konnte Datei \"$1\" nicht nach \"$2\" kopieren.",
+"filerenameerror" => "Konnte Datei \"$1\" nicht nach \"$2\" umbenennen.",
+"filedeleteerror" => "Konnte Datei \"$1\" nicht löschen.",
+"filenotfound" => "Konnte Datei \"$1\" nicht finden.",
+"unexpected"   => "Unerwarteter Wert: \"$1\"=\"$2\".",
+"formerror"            => "Fehler: Konnte Formular nicht verarbeiten", 
+"badarticleerror" => "Diese Aktion kann auf diesen Artikel nicht angewendet werden.",
+"cannotdelete" => "Kann spezifizierte Seite oder Artikel nicht löschen. (Wurde möglicherweise schon von jemand anderem gelöscht.)",
+"badtitle"             => "Ungültiger Titel",
+"badtitletext" => "Der Titel der angeforderten Seite war ungültig, leer, oder ein ungültiger Sprachlink von einer anderen Wikipedia.",
+"perfdisabled" => "Diese Funktion wurde wegen Überlastung des Servers vorrübergehend deaktiviert. Versuchen Sie es bitte zwischen 02:00 und 14:00 UTC noch einmal<br>(Aktuelle Serverzeit : ".date("H:i:s")." UTC).",
+
+
+# Login and logout pages
+#
+"logouttitle"  => "Benutzer-Abmeldung",
+"logouttext"   => "Sie sind nun abgemeldet.
+Sie können Wikipedia jetzt anonym weiterbenutzen, oder sich unter dem selben oder einem anderen Benutzernamen wieder anmelden.\n",
+
+"welcomecreation" => "<h2>Willkommen, $1!</h2><p>Ihr Benutzerkonto wurde eingerichtet.
+Vergessen Sie nicht, Ihre Wikipedia-Einstellungen anzupassen.",
+
+"loginpagetitle" => "Benutzer-Anmeldung",
+"yourname"             => "Ihr Benutzername",
+"yourpassword" => "Ihr Passwort",
+"yourpasswordagain" => "Passwort wiederholen",
+"newusersonly" => " (nur für neue Mitglieder)",
+"remembermypassword" => "Mein Passwort merken.",
+"loginproblem" => "<b>Es gab ein Problem mit Ihrer Anmeldung.</b><br>Bitte versuchen Sie es nochmal!",
+"alreadyloggedin" => "<font color=red><b>Benutzer $1, Sie sind bereits angemeldet!</b></font><br>\n",
+
+"areyounew"            => "Wenn Sie neu bei Wikipedia sind und ein Benutzerkonto möchten,
+geben Sie bitte ihren Benutzernamen und ihr Passwort ein und wiederholen sie das Passwort.
+Ihre E-Mail-Addresse brauchen Sie nicht anzugeben, aber falls Sie Ihr Passwort vergessen sollten, können Sie sich ein neues zuschicken lassen.<br>\n",
+
+"login"                        => "Anmelden",
+"userlogin"            => "Anmelden",
+"logout"               => "Abmelden",
+"userlogout"   => "Abmelden",
+"createaccount"        => "Neues Benutzerkonto anlegen",
+"badretype"            => "Die beiden Passwörter stimmen nicht überein.",
+"userexists"   => "Dieser Benutzername ist schon vergeben. Bitte wählen Sie einen anderen.",
+"youremail"            => "Ihre E-Mail",
+"yournick"             => "Ihr \"Spitzname\" (zum \"Unterschreiben\")",
+"emailforlost" => "Falls Sie Ihr Passwort vergessen, kann Ihnen ein neues an Ihre E-Mail-Addresse gesendet werden.",
+"loginerror"   => "Fehler bei der Anmeldung",
+"noname"               => "Sie müssen einen Benutzernamen angeben.",
+"loginsuccesstitle" => "Anmeldung erfolgreich",
+"loginsuccess" => "Sie sind jetzt als \"$1\" bei Wikipedia angemeldet.",
+"nosuchuser"   => "Der Benutzername \"$1\" existiert nicht.
+Überprüfen Sie die Schreibweise, oder melden Sie sich als neuer Benutzer an.",
+"wrongpassword"        => "Das Passwort ist falsch. Bitte versuchen Sie es erneut.",
+"mailmypassword" => "Ein neues Passwort schicken",
+"passwordremindertitle" => "Wikipedia Passwort",
+"passwordremindertext" => "Jemand (IP-Addresse $1)
+hat um ein neues Passwort für die Anmeldung bei Wikipedia gebeten.
+Das Passwort für Benutzer \"$2\" lautet nun \"$3\".
+Sie sollten sich jetzt anmelden und Ihr Passwort ändern.",
+"noemail"              => "Benutzer \"$1\" hat keine E-Mail-Addresse angegeben.",
+"passwordsent" => "Ein neues Passwort wurde an die E-Mail-Addresse von Benutzer \"$1\" gesendet.
+Bitte melden Si sich an, sobald Sie es erhalten.",
+
+# Edit pages
+#
+"summary"              => "Zusammenfassung",
+"minoredit"            => "Nur Kleinigkeiten wurden verändert.",
+"watchthis" => "Diesen Artikel beobachten",
+"savearticle"  => "Artikel speichern",
+"preview"              => "Vorschau",
+"showpreview"  => "Vorschau zeigen",
+"blockedtitle" => "Benutzer ist blockiert",
+"blockedtext"  => "Ihr Benutzername oder Ihre IP-Addresse wurde von $1 blockiert.
+Als Grund wurde angegeben:<br>$2<p>Bitte kontaktieren Sie den Administrator, um über die Blockierung zu sprechen.",
+"newarticle"   => "(Neu)",
+"newarticletext" => "Hier den Text des neuen Artikels eintragen.\nBitte nur in ganzen Sätzen schreiben und keine urheberrechtsgeschützten Texte anderer kopieren.",
+"anontalkpagetext" => "---- ''Dies ist Die Diskussions-Seite eines nicht angemeldeten Benutzers. Wir müssen hier die numerische [[IP-Adresse]] zur Identifizierung verwenden. Eine solche Adresse kann nacheinander von mehreren Benutzer verwendet werden. Wenn Sie ein anonymer Benutzer sind und denken, dass irrelevante Kommentare an Sie gerichtet wurden, [[Spezial:Userlogin|melden Sie sich bitte an]], um zukünftige Verwirrung zu vermeiden. ''",
+"noarticletext" => "(Dieser Artikel enthält momentan keinen Text)",
+"updated"              => "(Geändert)",
+"note"                 => "<strong>Hinweis:</strong> ",
+"previewnote"  => "Dies ist nur eine Vorschau, der Artikel wurde noch nicht gespeichert!",
+"previewconflict" => "Diese Vorschau gibt den Inhalt des oberen Textfeldes wieder; so wird der Artikel aussehen, wenn Sie jetzt speichern.",
+"editing"              => "Bearbeiten von $1",
+"editconflict" => "Bearbeitungs-Konflikt: $1",
+"explainconflict" => "Jemand anders hat diesen Artikel geändert, nachdem Sie angefangen haben, ihn zu bearbeiten.
+Das obere Textfeld enthält den aktuellen Artikel.
+Das untere Textfeld enthält Ihre Änderungen.
+Bitte fügen Sie Ihre Änderungen in das obere Textfeld ein.
+<b>Nur</b> der Inhalt des oberen Textfeldes wird gespeichert, wenn Sie auf \"Speichern\" klicken!\n<p>",
+"yourtext"             => "Ihr Text",
+"storedversion" => "Gespeicherte Version",
+"editingold"   => "<strong>ACHTUNG: Sie bearbeiten eine alte Version dieses Artikels.
+Wenn Sie speichern, werden alle neueren Versionen überschrieben.</strong>\n",
+"yourdiff"             => "Unterschiede",
+"copyrightwarning" => "
+<b>Bitte <font size='+1'>kopieren Sie keine Webseiten</font>, die nicht Ihre eigenen sind, benutzen Sie <fonz size='+1'>keine urheberrechtlich geschützten Werke</font> ohne Erlaubnis des Copyright-Inhabers!</b>
+<p>Sie geben uns hiermit ihre Zusage, daß Sie den Text <strong>selbst verfasst</strong> haben, daß der Text Allgemeingut (<strong>public domain</strong>) ist, oder daß de <strong>Copyright-Inhaber</strong> seine <strong>Zustimmung</strong> gegeben hat. Falls dieser Text bereits woanders veröffentlicht wurde, weisen Sie bitte auf der 'Diskussion:'-Seite darauf hin.
+<p><i>Bitte beachten Sie, dass alle Beiträge zur Wikipedia automatisch unter der \"GNU Freie Dokumentationslizenz\" stehen. Falls Sie nicht möchten, dass Ihre Arbeit hier von anderen verändert und verbreitet wird, dann drücken Sie nicht auf \"Speichern\".</i>",
+
+# History pages
+#
+"revhistory"   => "Frühere Versionen",
+"nohistory"            => "Es gibt keine früheren Versionen von diesem Artikel.",
+"revnotfound"  => "Keine früheren Versionen gefunden",
+"revnotfoundtext" => "Die Version dieses Artikels, nach der Sie suchen, konnte nicht gefunden werden. Bitte überprüfen Sie die URL dieser Seite.\n",
+"loadhist"             => "Lade Liste mit früheren Versionen",
+"currentrev"   => "Aktuelle Version",
+"revisionasof" => "Version vom $1",
+"cur"                  => "Aktuell",
+"next"                 => "Nächste",
+"last"                 => "Letzte",
+"orig"                 => "Original",
+"histlegend"   => "Legende:
+(Aktuell) = Unterschied zur aktuellen Version,
+(Letzte) = Unterschied zur vorherigen Version,
+M = Kleine Änderung",
+
+# Diffs
+#
+"difference"   => "(Unterschied zwischen Versionen)",
+"loadingrev"   => "lage Versionen zur Unterscheidung",
+"lineno"               => "Zeile $1:",
+"editcurrent"  => "Die aktuelle Version dieses Artikels bearbeiten",
+
+# Search results
+#
+"searchresults" => "Suchergebnisse",
+"searchhelppage" => "Wikipedia:Suche",
+"searchingwikipedia" => "Wikipedia durchsuchen",
+"searchresulttext" => "Für mehr Information über Wikipedia, siehe $1.",
+"searchquery"  => "Für die Suchanfrage \"$1\"",
+"badquery"             => "Falsche Suchanfrage",
+"badquerytext" => "Wir konnten Ihre Suchanfrage nicht verarbeiten.
+Vermutlich haben Sie versucht, ein Wort zu suchen, das kürzer als zwei Buchstaben ist.
+Dies funktioniert im Moment noch nicht.
+Möglicherweise haben Sie auch die Anfrage falsch formuliert, z.B.
+\"Lohn und und Steuern\".
+Bitte versuchen Sie eine anders formulierte Anfrage.",
+"matchtotals"  => "Die Anfrage \"$1\" stimmt mit $2 Artikelüberschriften
+und dem Text von $3 Artikeln überein.",
+"nogomatch" => "Es existiert kein Artikel mit diesem Namen. Bitte versuchen Sie die Volltextsuche. ",
+"titlematches" => "Übereinstimmungen mit Überschriften",
+"notitlematches" => "Keine Übereinstimmungen",
+"textmatches"  => "Übereinstimmungen mit Texten",
+"notextmatches"        => "Keine Übereinstimmungen",
+"prevn"                        => "letzte $1",
+"nextn"                        => "nächste $1",
+"viewprevnext" => "Zeige ($1) ($2) ($3).",
+"showingresults" => "Hier sind <b>$1</b> Ergebnisse, beginnend mit #<b>$2</b>.",
+"nonefound"            => "<strong>Hinweis</strong>:
+Erfolglose Suchanfragen werden häufig verursacht durch den Versuch, nach 'gewöhnlichen' Worten zu suchen; diese sind nicht indiziert.",
+"powersearch" => "Suche",
+"powersearchtext" => "
+Suche in Namensräumen :<br>
+$1<br>
+$2 Zeige auch REDIRECTs &nbsp; Suche nach $3 $9",
+
+
+
+# Preferences page
+#
+"preferences"  => "Einstellungen",
+"prefsnologin" => "Nicht angemeldet",
+"prefsnologintext"     => "Sie müssen <a href=\"" .
+  wfLocalUrl( "Spezial:Userlogin" ) . "\">angemeldet</a>
+sein, um Ihre Einstellungen zu ändern.",
+"prefslogintext" => "Sie sind angemeldet als \"$1\".
+Ihre interne ID-Nummer ist $2.",
+"prefsreset"   => "Einstellungen wuden auf Standard zurückgesetzt.",
+"qbsettings"   => "Seitenleiste", 
+"changepassword" => "Passwort ändern",
+"skin"                 => "Skin",
+"math"                 => "TeX darstellen",
+"math_failure"         => "Parser-Fehler",
+"math_unknown_error"   => "Unbekannter Fehler",
+"math_unknown_function"        => "Unbekannte Funktion ",
+"math_lexing_error"    => "'Lexing'-Fehler",
+"math_syntax_error"    => "Syntaxfehler",
+"saveprefs"            => "Einstellungen speichern",
+"resetprefs"   => "Einstellungen zurücksetzen",
+"oldpassword"  => "Altes Passwort",
+"newpassword"  => "Neues Passwort",
+"retypenew"            => "Neues Passwort (nochmal)",
+"textboxsize"  => "Textfeld-Grösse",
+"rows"                 => "Zeilen",
+"columns"              => "Spalten",
+"searchresultshead" => "Suchergebnisse",
+"resultsperpage" => "Treffer pro Seite",
+"contextlines" => "Zeilen pro Treffer",
+"contextchars" => "Zeichen pro Zeile",
+"stubthreshold" => "Kurze Artikel markieren bis",
+"recentchangescount" => "Anzahl \"Letzte Änderungen\"",
+"savedprefs"   => "Ihre Einstellungen wurden gespeichert.",
+"timezonetext" => "Geben Sie die Anzahl der Stunden ein, die zwischen Ihrer Zeitzone und UTC liegen.",
+"localtime"    => "Ortszeit",
+"timezoneoffset" => "Unterschied",
+"emailflag"            => "Keine E-Mail von anderen Benutzern erhalten",
+
+# Recent changes
+#
+"changes" => "Änderungen",
+"recentchanges" => "Letzte Änderungen",
+"recentchangestext" => "
+Diese Seite wird beim Laden automatisch aktualisiert. Angezeigt werden Seiten, die zuletzt bearbeitet wurden, sowie die Zeit und der Name des Autors.<br>
+Falls Sie neu bei Wikipedia sind, lesen Sie bitte die [[Wikipedia:Willkommen|Willkommensseite der Wikipedia]] und [[Wikipedia:Erste Schritte|Erste Schritte]].<br>
+Wenn Sie möchten, dass Wikipedia zu einem Erfolg wird, dann fügen Sie bitte keine Texte hinzu, die dem [[Wikipedia:Urheberrechte beachten|Urheberrecht]] anderer unterliegen. Dies könnte dem Projekt sonst schweren Schaden zufügen.
+Beachten Sie auch die letzten Änderungen auf [[m:Special:Recentchanges|Metawikipedia]]",
+"rcloaderr"            => "Lade Letzte Änderungen",
+"rcnote"               => "Hier sind die letzten <b>$1</b> Änderungen der letzten <b>$2</b> Tage. (<b>N</b> - Neuer Artikel; <b>M</b> - kleine Änderung)",
+"rcnotefrom"   => "Dies sind die Änderungen seit <b>$2</b> (bis zu <b>$1</b> gezeigt).",
+"rclistfrom"   => "Zeige neue Änderungen seit $1",
+"rclinks"              => "Zeige die letzten $1 Änderungen; zeige die letzten $2 Tage.",
+"diff"                 => "Unterschied",
+"hist"                 => "Versionen",
+"hide"                 => "Verbergen",
+"show"                 => "Anzeigen",
+"tableform"            => "Tabelle",
+"listform"             => "Liste",
+"nchanges"             => "$1 Änderungen",
+"minoreditletter" => "M",
+"newpageletter" => "N",
+
+
+# Upload
+#
+"upload"               => "Hochladen",
+"uploadbtn"            => "Dateien hochladen",
+"uploadlink"           => "Bilder hochladen",
+"reupload"             => "Erneut hochladen",
+"reuploaddesc" => "Zurück zur Hochladen-Seite.",
+"uploadnologin" => "Nicht angemeldet",
+"uploadnologintext"    => "Sie müssen <a href=\"" .
+  wfLocalUrl( "Spezial:Userlogin" ) . "\">angemeldet sein</a>
+um Dateien hochladen zu können.",
+"uploadfile"   => "Datei hochladen",
+"uploaderror"  => "Fehler beim Hochladen",
+"uploadtext"   => "
+Um hochgeladene Bilder zu suchen und anzusehen,
+gehen Sie zu der <a href=\"" . wfLocalUrl( "Spezial:Imagelist" ) .
+"\">Liste hochgeladener Bilder</a>.
+<p>Benutzen Sie das Formular, um neue Bilder hochzuladen und
+sie in Artikeln zu verwenden.
+In den meisten Browsern werden Sie ein \"Durchsuchen\"-Feld sehen,
+das einen Standard-Dateidialog öffnet.
+Suchen Sie sich eine Datei aus. Die Datei wird dann im Textfeld angezeigt.
+Bestätigen Sie dann die Copyright-Vereinbarung.
+Schließlich drücken Sie den \"Hochladen\"-Knopf.
+Dies kann eine Weile dauern, besonders bei einer langsamen Internet-Verbindung.
+<p>Für Photos wird das JPEG-Format, für Zeichnungen und Symbole das PNG-Format bevorzugt.
+Um ein Bild in einem Artikel zu verwenden, schreiben Sie an Stelle des Bildes
+<b>[[bild:datei.jpg]]</b> oder <b>[[bild:datei.jpg|Beschreibung]]</b>.
+<p>Bitte beachten Sie, dass, genau wie bei den Artikeln, andere Benutzer Ihre Dateien löschen oder verändern können.",
+"uploadlog"            => "Datei-Logbuch",
+"uploadlogpage" => "Datei-Logbuch",
+"uploadlogpagetext" => "Hier ist die Liste der letzten hochgeladenen Dateien.
+Alle Zeiten sind UTC.
+<ul>
+</ul>
+",
+"uploadlogtext" => "Hochgeladene und gelöschte Dateien werden im $1 verzeichnet.",
+"filename"             => "Dateiname",
+"filedesc"             => "Beschreibung",
+"affirmation"  => "Hiermit bestätige ich, dass ich das Copyright dieser Datei habe, und diese hiermit unter $1 veröffentliche, bzw. dass die Datei 'Public Domain' ist.",
+"copyrightpage" => "Wikipedia:Copyright",
+"copyrightpagename" => "Wikipedia copyright",
+"uploadedfiles"        => "Hochgeladene Dateien",
+"noaffirmation" => "Sie müssen bestätigen, dass das Hochladen der Datei keine Copyright-Verletzung darstellt.",
+"ignorewarning"        => "Warnung ignorieren und Datei trotzdem speichern.",
+"minlength"            => "Bilddateien müssen mindestens drei Buchstaben haben.",
+"badfilename"  => "Der Bildname wurde in \"$1\" geändert.",
+"badfiletype"  => "\".$1\" ist kein empfohlenes Dateiformat.",
+"largefile"            => "Bitte keine Bilder über 100 KByte hochladen.",
+"successfulupload" => "Erfolgreich hochgeladen",
+"fileuploaded" => "Die Datei \"$1\" wurde erfolgreich hochgeladen.",
+"uploadwarning" => "Warnung",
+"savefile"             => "Datei speichern",
+"uploadedimage" => "\"$1\" hochgeladen",
+
+# Image list
+#
+"imagelist"            => "Bilderliste",
+"imagelisttext"        => "Hier ist eine Liste von $1 Bildern, sortiert $2.",
+"getimagelist" => "Lade Bilderliste",
+"ilshowmatch"  => "Zeige alle Bilder mit Namen",
+"ilsubmit"             => "Suche",
+"showlast"             => "Zeige die letzten $1 Bilder, sortiert nach $2.",
+"all"                  => "alle",
+"byname"               => "nach Name",
+"bydate"               => "nach Datum",
+"bysize"               => "nach Grösse",
+"imgdelete"            => "Löschen",
+"imgdesc"              => "Beschreibung",
+"imglegend"            => "Legende: (Beschreibung) = Zeige/Bearbeite Bildbeschreibung.",
+"imghistory"   => "Bild-Versionen",
+"revertimg"            => "Zurücksetzen",
+"deleteimg"            => "Löschen",
+"imghistlegend" => "Legende: (cur) = Dies ist das aktuelle Bild, (Löschen) = lösche
+diese alte Version, (Zurücksetzen) = verwende wieder diese alte Version.",
+"imagelinks"   => "Bildverweise",
+"linkstoimage" => "Die folgenden Artikel benutzen dieses Bild:",
+"nolinkstoimage" => "Kein Artikel benutzt dieses Bild.",
+
+# Statistics
+#
+"statistics"   => "Statistik",
+"sitestats"            => "Seitenstatistik",
+"userstats"            => "Benutzerstatistik",
+"sitestatstext" => "Es gibt insgesamt <b>$1</b> Seiten in der Datenbank.
+Das schliesst \"Diskussion\"-Seiten, Seiten über Wikipedia, extrem kurze Artikel, Weiterleitungen und andere Seiten ein, die nicht als Artikel gelten können.
+Diese ausgenommen, gibt es <b>$2</b> Seiten, die als Artikel gelten können.<p>
+Es wurden insgesamt <b>$3</b>&times; Seiten aufgerufen, und <b>$4</b>&times; Seiten bearbeitet.
+Daraus ergeben sich <b>$5</b> Bearbeitungen pro Seite, und <b>$6</b> Betrachtungen pro Bearbeitung.",
+"userstatstext" => "Es gibt <b>$1</b> registrierte Benutzer.
+Davon haben <b>$2</b> Administrator-Rechte (siehe $3).",
+
+# Maintenance Page
+#
+"maintenance"          => "Wartungsseite",
+"maintnancepagetext"   => "Diese Seite enthält mehrere praktische Funktionen zur täglichen Wartung von Wikipedia. Einige dieser Funktionen können die Datenbank stark beanspruchen, also bitte nicht nach jeder Änderung neu laden ;-)",
+"maintenancebacklink"  => "Zurück zur Wartungsseite",
+"disambiguations"      => "Begriffsklärungsseiten",
+"disambiguationspage"  => "Wikipedia:Begriffsklärung",
+"disambiguationstext"  => "Die folgenden Artikel verweisen auf eine <i>Seite zur Begriffsklärung</i>. Sie sollten statt dessen auf die eigentlich gemeinte Seite verweisen.<br>Eine Seite wird als Begriffsklärungsseite behandelt, wenn $1 auf sie verweist.<br>Verweise aus Namensräumen werden hier <i>nicht</i> aufgelistet.",
+"doubleredirects"      => "Doppelte Redirects",
+"doubleredirectstext"  => "<b>Achtung:</b> Diese Liste kann \"falsche Positive\" enthalten. Das ist dann der Fall, wenn ein Redirect außer dem Redirect-Verweis noch weiteren Text mit anderen Verweisen enthält. Letztere sollten dann entfernt werden.",
+"brokenredirects"      => "Kaputte Redirects",
+"brokenredirectstext"  => "Die folgenden Redirects leiten zu einem nicht existierenden Artikel weiter",
+"selflinks"            => "Seiten, die auf sich selbst verweisen",
+"selflinkstext"                => "Die folgenden Artikel verweisen auf sich selbst, was sie nicht sollten.",
+"mispeelings"           => "Seiten mit falsch geschriebenen Worten",
+"mispeelingstext"       => "Die folgenden Seiten enthalten falsch geschriebene Worte, wie sie auf $1 definiert sind. In Klammern angegebene Worte geben die korrekte Schreibweise wieder.",
+"mispeelingspage"       => "Liste von Tippfehlern",
+"missinglanguagelinks"  => "Fehlende Sprachverweise",
+"missinglanguagelinksbutton"    => "Zeige fehlende Sprachverweise nach",
+"missinglanguagelinkstext"      => "Diese Artikel haben <i>keinen</i> Verweis zu ihrem Gegenstück in $1. Redirects und Unterseiten werden <i>nicht</i> angezeigt.",
+
+
+# Miscellaneous special pages
+#
+"orphans"              => "Verwaiste Seiten",
+"lonelypages"  => "Verwaiste Seiten",
+"unusedimages" => "Verwaiste Bilder",
+"popularpages" => "Beliebte Seiten",
+"nviews"               => "$1 Abfragen",
+"wantedpages"  => "Gewünschte Seiten",
+"nlinks"               => "$1 Verweise",
+"allpages"             => "Alle Artikel",
+"randompage"   => "Zufälliger Artikel",
+"shortpages"   => "Kurze Artikel",
+"longpages"            => "Lange Artikel",
+"listusers"            => "Benutzerverzeichnis",
+"specialpages" => "Spezialseiten",
+"spheading"            => "Spezialseiten",
+"sysopspheading" => "Spezialseiten für Sysops",
+"developerspheading" => "Spezialseiten für Entwickler",
+"protectpage"  => "Artikel schützen",
+"recentchangeslinked" => "Verlinkte Seiten",
+"rclsub"               => "(auf Artikel von \"$1\")",
+"debug"                        => "Debug",
+"newpages"             => "Neue Artikel",
+"movethispage" => "Artikel verschieben",
+"unusedimagestext" => "<p>Bitte beachten Sie, dass andere Wikipedias, die noch die alte Software verwenden, möglicherweise einige dieser Bilder benutzen.",
+"booksources"  => "Buchhandlungen",
+"booksourcetext" => "Dies ist eine Liste mit Links zu Internetseiten, die neue und gebrauchte Bücher verkaufen. Dort kann es auch weitere Informationen über die Bücher geben, die Sie interessieren. Wikipedia ist mit keinem dieser Anbieter geschäftlich verbunden.",
+
+# Email this user
+#
+"mailnologin"  => "Sie sind nicht angemeldet.",
+"mailnologintext" => "Sie müssen <a href=\"" .
+  wfLocalUrl( "Spezial:Userlogin" ) . "\">angemeldet sein</a>
+und eine gültige E-Mail-Addresse haben, um anderen Benutzern E-Mail zu schicken.",
+"emailuser"            => "E-Mail an diesen Benutzer",
+"emailpage"            => "E-Mail an Benutzer",
+"emailpagetext"        => "Wenn dieser Benutzer eine gültige E-Mail-Addresse angegeben hat, können Sie ihm mit dem untenstehenden Formular eine E-Mail senden. Als Absender wird die E-Mail-Addresse aus Ihren Einstellungen eingetragen, damit der Benutzer Ihnen antworten kann.",
+"noemailtitle" => "Keine E-Mail-Addresse",
+"noemailtext"  => "Dieser Benutzer hat keine gültige E-Mail-Addresse angegeben, oder möchte keine E-Mail von anderen Benutzern empfangen.",
+"emailfrom"            => "Von",
+"emailto"              => "An",
+"emailsubject" => "Betreff",
+"emailmessage" => "Nachricht",
+"emailsend"            => "Senden",
+"emailsent"            => "E-Mail verschickt",
+"emailsenttext" => "Ihre E-Mail wurde verschickt.",
+
+
+# Beobachtungsliste
+#
+"watchlist"            => "Beobachtungsliste",
+"watchlistsub" => "(für Benutzer \"$1\")",
+"nowatchlist"  => "Sie haben keine Einträge auf Ihrer Beobachtungsliste.",
+"watchnologin" => "Sie sind nicht angemeldet",
+"watchnologintext"     => "Sie müssen <a href=\"" .
+  wfLocalUrl( "Spezial:Userlogin" ) . "\">angemeldet</a>
+sein, um Ihre Beobachtungsliste zu bearbeiten.",
+"addedwatch"   => "Zur Beobachtungsliste hinzugefügt",
+"addedwatchtext" => "Der Artikel \"$1\" wurde zu Ihrer Beobachtungsliste hinzugefügt.",
+"removedwatch" => "Von der Beobachtungsliste entfernt",
+"removedwatchtext" => "Der Artikel \"$1\" wurde von Ihrer Beobachtungsliste entfernt.",
+"watchthispage"        => "Seite beobachten",
+"unwatchthispage" => "Nicht mehr beobachten",
+"notanarticle" => "Kein Artikel",
+
+# Delete/protect/revert
+#
+"deletepage"   => "Seite löschen",
+"confirm"              => "Bestätigen",
+"confirmdelete" => "Löschung bestätigen",
+"deletesub"            => "(Lösche \"$1\")",
+"confirmdeletetext" => "Sie sind dabei, einen Artikel oder ein Bild und alle älteren Versionen permanent aus der Datenbank zu löschen.
+Bitte bestätigen Sie Ihre Absicht, dies zu tun, dass Sie sich der Konsequenzen bewusst sind, und dass Sie in Übereinstimmung mit [[Wikipedia:Leitlinien|den Wikipedia Leitlinien]] handeln.",
+"confirmcheck" => "Ja, ich möchte den Löschvorgang fortsetzen.",
+"actioncomplete" => "Aktion beendet",
+"deletedtext"  => "\"$1\" wurde gelöscht.
+Im $2 finden Sie eine Liste der letzten Löschungen.",
+"deletedarticle" => "\"$1\" gelöscht",
+"dellogpage"   => "Lösch-Logbuch",
+"dellogpagetext" => "Hier ist eine Liste der letzten Löschungen (UTC).
+<ul>
+</ul>
+",
+"deletionlog"  => "Lösch-Logbuch",
+"reverted"             => "Auf eine alte Version zurückgesetzt",
+"deletecomment"        => "Grund der Löschung",
+"imagereverted" => "Auf eine alte version zurückgesetzt.",
+
+# Undelete
+"undelete" => "Gelöschte Seite wiederherstellen",
+"undeletepage" => "Gelöschte Seiten anzeigen und wiederherstellen",
+"undeletepagetext" => "Die folgenden Seiten wurden gelöscht, sind aber immer noch
+gespeichert und können wiederhergestellt werden.",
+"undeletearticle" => "Gelöschten Artikel wiederherstellen",
+"undeleterevisions" => "$1 Versionen archiviert",
+"undeletehistory" => "Wenn Sie diese Seite wiederherstellen, werden auch alle alten
+Versionen wiederhergestellt. Wenn seit der Löschung ein neuer Artikel gleichen
+Namens erstellt wurde, werden die wiederhergestellten Versionen als alte Versionen
+dieses Artikels erscheinen.",
+"undeleterevision" => "Gelöschte Version vom $1",
+"undeletebtn" => "Wiederherstellen!",
+"undeletedarticle" => "\"$1\" wiederhergestellt",
+"undeletedtext"   => "Der Artikel [[$1]] wurde erfolgreich wiederhergestellt.",
+
+# Contributions
+#
+"contributions"        => "Benutzerbeiträge",
+"mycontris" => "Meine Beiträge",
+"contribsub"   => "Für $1",
+"nocontribs"   => "Es wurden keine Änderungen für diese Kriterien gefunden.",
+"ucnote"               => "Dies sind die letzten <b>$1</b> Beiträge des Benutzers in den letzten <b>$2</b> Tagen.",
+"uclinks"              => "Zeige die letzten $1 Beiträge; zeige die letzten $2 Tage.",
+"uctop"                => " (top)" ,
+
+# What links here
+#
+"whatlinkshere"        => "Was zeigt hierhin",
+"notargettitle" => "Kein Artikel angegeben",
+"notargettext" => "Sie haben nicht angegeben, auf welche Seite Sie diese Funktion anwenden wollen.",
+"linklistsub"  => "(Liste der Verweise)",
+"linkshere"            => "Die folgenden Artikel verweisen hierhin:",
+"nolinkshere"  => "Kein Artikel verweist hierhin.",
+"isredirect"   => "Weiterleitungs-Seite",
+
+# Block/unblock IP
+#
+"blockip"              => "IP-Addresse blockieren",
+"blockiptext"  => "Benutzen Sie das Formular, um eine IP-Addresse zu blockieren.
+Dies sollte nur erfolgen, um Vandalismus zu verhindern, in Übereinstimmung mit den [[Wikipedia:Leitlinien|Wikipedia-Leitlinien]].
+Bitte tragen Sie den Grund für die Blockade ein.",
+"ipaddress"            => "IP-Addresse",
+"ipbreason"            => "Grund",
+"ipbsubmit"            => "Addresse blockieren",
+"badipaddress" => "Die IP-Addresse hat ein falsches Format.",
+"noblockreason" => "Sie müssen einen Grung für die Blockade angeben.",
+"blockipsuccesssub" => "Blockade erfolgreich",
+"blockipsuccesstext" => "Die IP-Addresse \"$1\" wurde blockiert.
+<br>Auf [[Spezial:Ipblocklist|IP block list]] ist eine Liste der Blockaden.",
+"unblockip"            => "IP-Addresse freigeben",
+"unblockiptext"        => "Benutzen Sie das Formular, um eine blockierte IP-Addresse freizugeben.",
+"ipusubmit"            => "Diese Addresse freigeben",
+"ipusuccess"   => "IP-Addresse \"$1\" wurde freigegeben",
+"ipblocklist"  => "Liste blockierter IP-Addressen",
+"blocklistline"        => "$1, $2 blockierte $3",
+"blocklink"            => "blockieren",
+"unblocklink"  => "freigeben",
+"contribslink" => "Beiträge",
+
+# Developer tools
+#
+"lockdb"               => "Datenbank sperren",
+"unlockdb"             => "Datenbank freigeben",
+"lockdbtext"   => "Mit dem Sperren der Datenbank werden alle Änderungen an Benutzereinstellungen, watchlisten, Artikeln usw. verhindert. Bitte bestätigen Sie Ihre Absicht, die Datenbank zu sperren.",
+"unlockdbtext" => "Das Aufheben der Datenbank-Sperre wird alle Änderungen wieder zulassen. Bitte bestätigen Sie Ihre Absicht, die Sperrung aufzuheben.",
+"lockconfirm"  => "Ja, ich möchte die Datenbank sperren.",
+"unlockconfirm"        => "Ja, ich möchte die Datenbank freigeben.",
+"lockbtn"              => "Datenbank sperren",
+"unlockbtn"            => "Datenbank freigeben",
+"locknoconfirm" => "Sie haben das Bestätigungsfeld nicht markiert.",
+"lockdbsuccesssub" => "Datenbank wurde erfolgreich gesperrt",
+"unlockdbsuccesssub" => "Datenbank wurde erfolgreich freigegeben",
+"lockdbsuccesstext" => "Die Wikipedia-Datenbank wurde gesperrt.
+<br>Bitte geben Sie die Datenbank wieder frei, sobald die Wartung abgeschlossen ist.",
+"unlockdbsuccesstext" => "Die Wikipedia-Datenbank wurde freigegeben.",
+
+# SQL query
+#
+"asksql"               => "SQL-Abfrage",
+"asksqltext"   => "Benutzen Sie das Formular für eine direkte Datenbank-Abfrage.
+Benutze einzelne Hochkommata ('so'), um Text zu begrenzen.
+Bitte diese Funktion vorsichtig benutzen!",
+"sqlquery"             => "Abfrage eingeben",
+"querybtn"             => "Abfrage starten",
+"selectonly"   => "Andere Abfragen als \"SELECT\" können nur von Entwicklern benutzt werden.",
+"querysuccessful" => "Abfrage erfolgreich",
+
+# Move page
+#
+"movepage"             => "Artikel verschieben",
+"movepagetext" => "Mit diesem Formular können Sie einen Artikel umbenennen, mitsamt allen Versionen. Der alte Titel wird zum neuen weiterleiten. Verweise auf den alten Titel werden nicht geändert, und die Diskussionsseite wird auch nicht mitverschoben.",
+"movepagetalktext" => "Die dazugehörige Diskussionsseite wird, sofern vorhanden, mitverschoben, '''es sei denn:'''
+*Sie verschieben die Seite in einen anderen Namensraum, oder
+*Es existiert bereits eine Diskussionsseite mit diesem Namen, oder
+*Sie wählen die untenstehende Option ab
+
+In diesen Fällen müssen Sie die Seite, falls gewünscht, von Hand verschieben.",
+"movearticle"  => "Artikel verschieben",
+"newtitle"             => "Zu neuem Titel",
+"movepagebtn"  => "Artikel verschieben",
+"pagemovedsub" => "Verschiebung erfolgreich",
+"pagemovedtext" => "Artikel \"$1\" wurde nach \"$2\" verschoben.",
+"articleexists" => "Unter diesem Namen existiert bereits ein Artikel.
+Bitte wählen Sie einen anderen Namen.",
+"movedto"              => "verschoben nach",
+"movetalk"             => "Die \"Diskussions\"-Seite mitverschieben, wenn möglich.",
+"talkpagemoved" => "Die \"Diskussions\"-Seite wurde ebenfalls verschoben.",
+"talkpagenotmoved" => "Die \"Diskussions\"-Seite wurde <strong>nicht</strong> verschoben.",
+
+);
+
+class LanguageDe extends Language {
+
+       function getDefaultUserOptions () {
+               global $wgDefaultUserOptionsDe ;
+               return $wgDefaultUserOptionsDe ;
+               }
+
+       function getBookstoreList () {
+               global $wgBookstoreListDe ;
+               return $wgBookstoreListDe ;
+       }
+
+       function getNamespaces() {
+               global $wgNamespaceNamesDe;
+               return $wgNamespaceNamesDe;
+       }
+
+       function getNsText( $index ) {
+               global $wgNamespaceNamesDe;
+               return $wgNamespaceNamesDe[$index];
+       }
+
+       function getNsIndex( $text ) {
+               global $wgNamespaceNamesDe;
+
+               foreach ( $wgNamespaceNamesDe as $i => $n ) {
+                       if ( 0 == strcasecmp( $n, $text ) ) { return $i; }
+               }
+               return false;
+       }
+
+       function specialPage( $name ) {
+               return $this->getNsText( Namespace::getSpecial() ) . ":" . $name;
+       }
+
+       function getQuickbarSettings() {
+               global $wgQuickbarSettingsDe;
+               return $wgQuickbarSettingsDe;
+       }
+
+       function getSkinNames() {
+               global $wgSkinNamesDe;
+               return $wgSkinNamesDe;
+       }
+
+       function getMathNames() {
+               global $wgMathNamesDe;
+               return $wgMathNamesDe;
+       }
+
+       function getUserToggles() {
+               global $wgUserTogglesDe;
+               return $wgUserTogglesDe;
+       }
+
+       function getLanguageNames() {
+               global $wgLanguageNamesDe;
+               return $wgLanguageNamesDe;
+       }
+
+       function getLanguageName( $code ) {
+               global $wgLanguageNamesDe;
+               if ( ! array_key_exists( $code, $wgLanguageNamesDe ) ) {
+                       return "";
+               }
+               return $wgLanguageNamesDe[$code];
+       }
+
+       function getMonthName( $key )
+       {
+               global $wgMonthNamesDe;
+               return $wgMonthNamesDe[$key-1];
+       }
+
+       function getMonthAbbreviation( $key )
+       {
+               global $wgMonthAbbreviationsDe;
+               return $wgMonthAbbreviationsDe[$key-1];
+       }
+
+       function getWeekdayName( $key )
+       {
+               global $wgWeekdayNamesDe;
+               return $wgWeekdayNamesDe[$key-1];
+       }
+
+       # Inherit userAdjust()
+       function date( $ts, $adj = false )
+       {
+               if ( $adj ) { $ts = $this->userAdjust( $ts ); }
+
+               $d = (0 + substr( $ts, 6, 2 )) . ". " .
+               $this->getMonthAbbreviation( substr( $ts, 4, 2 ) ) .
+                 " " . 
+                 substr( $ts, 0, 4 );
+               return $d;
+       }
+
+       function time( $ts, $adj = false )
+       {
+               if ( $adj ) { $ts = $this->userAdjust( $ts ); }
+
+               $t = substr( $ts, 8, 2 ) . ":" . substr( $ts, 10, 2 );
+               return $t;
+       }
+
+       function timeanddate( $ts, $adj = false )
+       {
+               return $this->time( $ts, $adj ) . ", " . $this->date( $ts, $adj );
+       }
+
+       function getValidSpecialPages()
+       {
+               global $wgValidSpecialPagesDe;
+               return $wgValidSpecialPagesDe;
+       }
+
+       function getSysopSpecialPages()
+       {
+               global $wgSysopSpecialPagesDe;
+               return $wgSysopSpecialPagesDe;
+       }
+
+       function getDeveloperSpecialPages()
+       {
+               global $wgDeveloperSpecialPagesDe;
+               return $wgDeveloperSpecialPagesDe;
+       }
+
+       function getMessage( $key )
+       {
+                global $wgAllMessagesDe, $wgAllMessagesEn;
+                $m = $wgAllMessagesDe[$key];
+
+                if ( "" == $m ) { return $wgAllMessagesEn[$key]; }
+                else return $m;
+       }
+}
+
+?>
diff --git a/languages/LanguageEn.php b/languages/LanguageEn.php
new file mode 100644 (file)
index 0000000..8d04d30
--- /dev/null
@@ -0,0 +1,8 @@
+<?
+# See language.doc
+
+class LanguageEn extends Language {
+       # Inherit everything
+}
+
+?>
diff --git a/languages/LanguageEo.php b/languages/LanguageEo.php
new file mode 100644 (file)
index 0000000..122f03e
--- /dev/null
@@ -0,0 +1,1261 @@
+<?
+include("utf8Case.php");
+$wgInputEncoding       = "utf-8";
+$wgOutputEncoding      = "utf-8";
+$wgEditEncoding                = "x";
+
+# See language.doc
+
+# The names of the namespaces can be set here, but the numbers
+# are magical, so don't change or move them!  The Namespace class
+# encapsulates some of the magic-ness.
+#
+/* private */ $wgNamespaceNamesEo = array(
+       -1      => "Speciala", # FIXME Is it safe to change this?
+       0       => "",
+       1       => "Diskuto",
+       2       => "Vikipediisto",
+       3       => "Vikipediista_diskuto",
+       4       => "Vikipedio",
+       5       => "Vikipedia_diskuto",
+       6       => "Dosiero", #FIXME: Check the magic for Image: and Media:
+       7       => "Dosiera_diskuto"
+);
+
+# Heredu apriorajn preferojn: wgDefaultUserOptionsEn
+
+/* private */ $wgQuickbarSettingsEo = array(
+       "Nenia", "Fiksiĝas maldekstre", "Fiksiĝas dekstre", "Ŝvebas maldekstre"
+);
+
+/* private */ $wgSkinNamesEo = array(
+       "Norma", "Nostalgio", "Kolonja Bluo"
+);
+
+/* private */ $wgMathNamesEo = array(
+       "Ĉiam krei PNG-bildon",
+       "HTMLigu se simple, aŭ PNG",
+       "HTMLigu se eble, aŭ PNG",
+       "Lasu TeX-fonton (por tekstfoliumiloj)"
+);
+
+/* private */ $wgUserTogglesEo = array(
+       "hover"         => "Montru helpilon super viki-ligiloj",
+       "underline" => "Substreku ligilojn",
+       "highlightbroken" => "Ruĝigu ligilojn al neekzistantaj paĝoj",
+       "justify"       => "Alkadrigu liniojn",
+       "hideminor" => "Kaŝu malgrandajn redaktetojn ĉe <i>Lastaj ŝanĝoj</i>",
+       "usenewrc"  => "Novstila Lastaj Ŝanĝoj (bezonas JavaSkripton)",
+       "numberheadings" => "Aŭtomate numeru sekciojn",
+       "rememberpassword" => "Memoru mian pasvorton",
+       "editwidth" => "Redaktilo estu plenlarĝa",
+       "editondblclick" => "Redaktu per duobla alklako (JavaScript)",
+       "watchdefault" => "Priatentu paĝojn de vi redaktintajn",
+       "minordefault" => "Marku ĉiujn redaktojn malgrandaj",
+       "altencoding" => "Montru supersignojn X-sisteme"
+);
+
+# Se eble, trovu Esperantajn libroservoj traserĉeblaj laŭ ISBN
+# $wgBookstoreListEo = ..
+
+# Tie, kie eble, uzu la memnomo de la lingvo
+# El listo de Landoj kaj Lingvoj ce http://www.bertilow.com/lanlin/isoling.php
+/* private */ $wgLanguageNamesEo = array(
+       "aa"    => "Afar",
+       "ab"    => "Abĥaza",
+       "af"    => "Afrikaans",
+       "am"    => "Amhara",
+       "ar" => "&#8238;&#1575;&#1604;&#1593;&#1585;&#1576;&#1610;&#1577;&#8236; (Araby)",
+       "as"    => "Asama",
+       "ay"    => "Aymara",
+       "az"    => "Azerbaijani",
+       "ba"    => "Bashkir",
+       "be" => "&#1041;&#1077;&#1083;&#1072;&#1088;&#1091;&#1089;&#1082;&#1080;",
+       "bh"    => "Bihara",
+       "bi"    => "Bislama",
+       "bn"    => "Bengali",
+       "bo"    => "Tibeta",
+       "br" => "Brezhoneg",
+       "bs" => "Bosna",
+       "ca" => "Catal&#224;",
+       "ch" => "Chamoru",
+       "co"    => "Corsika",
+       "cs" => "&#268;esk&#225;",
+       "cy" => "Cymraeg",
+       "da" => "Dansk", # Note two different subdomains.
+       "dk" => "Dansk", # 'da' is correct for the language.
+       "de" => "Deutsch",
+       "dz"    => "Bhutani",
+       "el" => "&#917;&#955;&#955;&#951;&#957;&#953;&#954;&#940; (Ellenika)",
+       "en"    => "English",
+       "eo"    => "Esperanto",
+       "es" => "Espa&#241;ol",
+       "et" => "Eesti",
+       "eu" => "Euskara",
+       "fa" => "&#8238;&#1601;&#1585;&#1587;&#1609;&#8236; (Farsi)",
+       "fi" => "Suomi",
+       "fj"    => "Fiĝia",
+       "fo"    => "Feroa",
+       "fr" => "Fran&#231;ais",
+       "fy" => "Frysk",
+       "ga" => "Gaelige",
+       "gl"    => "Galego",
+       "gn"    => "Guarani",
+       "gu" => "&#2711;&#2753;&#2716;&#2736;&#2750;&#2724;&#2752; (Gujarati)",
+       "ha"    => "Hausa",
+       "he" => "&#1506;&#1489;&#1512;&#1497;&#1514; (Ivrit)",
+       "hi" => "&#2361;&#2367;&#2344;&#2381;&#2342;&#2368; (Hindi)",
+       "hr" => "Hrvatski",
+       "hu" => "Magyar",
+       "hy"    => "Armena",
+       "ia"    => "Interlingua",
+       "id"    => "Indonesia",
+       "ik"    => "Inupiak",
+       "is" => "&#205;slenska",
+       "it" => "Italiano",
+       "iu"    => "Inuktitut",
+       "ja" => "&#26085;&#26412;&#35486; (Nihongo)",
+       "jv"    => "Javanese",
+       "ka" => "&#4325;&#4304;&#4320;&#4311;&#4309;&#4308;&#4314;&#4312; (Kartuli)",
+       "kk"    => "Kazakh",
+       "kl"    => "Groenlanda",
+       "km"    => "Kampuĉa",
+       "kn"    => "Kanada",
+       "ko" => "&#54620;&#44397;&#50612; (Hangukeo)",
+       "ks"    => "Kashmiri",
+       "kw" => "Kernewek",
+       "ky"    => "Kirghiz",
+       "la" => "Latina",
+       "ln"    => "Lingala",
+       "lo"    => "Laotian",
+       "lt" => "Lietuvi&#371;",
+       "lv"    => "Latvian",
+       "mg" => "Malagasy",
+       "mi"    => "Maori",
+       "mk"    => "Makedona",
+       "ml"    => "Malayalam",
+       "mn"    => "Mongola",
+       "mo"    => "Moldova",
+       "mr"    => "Marathi",
+       "ms" => "Bahasa Melayu",
+       "my"    => "Burma",
+       "na"    => "Nauru",
+       "ne" => "&#2344;&#2375;&#2346;&#2366;&#2354;&#2368; (Nepali)",
+       "nl" => "Nederlands",
+       "no" => "Norsk",
+       "oc"    => "Occitan",
+       "om"    => "Oromo",
+       "or"    => "Oriya",
+       "pa"    => "Punjabi",
+       "pl" => "Polski",
+       "ps"    => "Pashto",
+       "pt" => "Portugu&#234;s",
+       "qu"    => "Quechua",
+       "rm"    => "Rumantsch",
+       "rn"    => "Kirundi",
+       "ro" => "Rom&#226;n&#259;",
+       "ru" => "&#1056;&#1091;&#1089;&#1089;&#1082;&#1080;&#1081; (Russkij)",
+       "rw"    => "Kinyarwanda",
+       "sa" => "&#2360;&#2306;&#2360;&#2381;&#2325;&#2371;&#2340; (Samskrta)",
+       "sd"    => "Sindhi",
+       "sg"    => "Sangro",
+       "sh"    => "Srpskohvratski",
+       "si"    => "Sinhala",
+       "simple" => "Simple English",
+       "sk"    => "Slovak",
+       "sl"    => "Slovensko",
+       "sm"    => "Samoa",
+       "sn"    => "Shona",
+       "so" => "Soomaali",
+       "sq" => "Shqiptare",
+       "sr" => "Srpski",
+       "ss"    => "Siswati",
+       "st"    => "Sesotho",
+       "su"    => "Sudana",
+       "sv" => "Svenska",
+       "sw" => "Kiswahili",
+       "ta"    => "Tamil",
+       "te"    => "Telugu",
+       "tg"    => "Tajik",
+       "th"    => "Thai",
+       "ti"    => "Tigrinya",
+       "tk"    => "Turkmen",
+       "tl"    => "Tagalog",
+       "tn"    => "Setswana",
+       "to"    => "Tonga",
+       "tr" => "T&#252;rk&#231;e",
+       "ts"    => "Tsonga",
+       "tt"    => "Tatar",
+       "tw"    => "Twi",
+       "ug"    => "Uighur",
+       "uk" => "&#1059;&#1082;&#1088;&#1072;&#1111;&#1085;&#1089;&#1100;&#1082;&#1072; (Ukrayins`ka)",
+       "ur"    => "Urdu",
+       "uz"    => "Uzbek",
+       "vi"    => "Vietnamese",
+       "vo" => "Volap&#252;k",
+       "wo"    => "Wolof",
+       "xh" => "isiXhosa",
+       "yi"    => "Yiddish",
+       "yo"    => "Yoruba",
+       "za"    => "Zhuang",
+       "zh" => "&#20013;&#25991; (Zhongwen)",
+       "zu"    => "Zulu"
+);
+
+# Note capitalization; also some uses may require addition of final -n
+/* private */ $wgWeekdayNamesEo = array(
+       "dimanĉo", "lundo", "mardo", "merkredo" , "ĵaŭdo",
+       "vendredo", "sabato"
+);
+
+# Double-check capitalization
+/* private */ $wgMonthNamesEo = array(
+       "januaro", "februaro", "marto", "aprilo", "majo", "junio",
+       "julio", "aŭgusto", "septembro", "oktobro", "novembro",
+       "decembro"
+);
+
+# Hmm
+/* private */ $wgMonthAbbreviationsEo = array(
+       "Jan", "Feb", "Mar", "Apr", "Maj", "Jun", "Jul", "Aŭg",
+       "Sep", "Okt", "Nov", "Dec"
+);
+
+# All special pages have to be listed here: a description of ""
+# will make them not show up on the "Special Pages" page, which
+# is the right thing for some of them (such as the "targeted" ones).
+#
+# *Ne ŝanĝu* la nomojn en la maldekstra kolumno, ili estas internaj
+# nomoj de programfunkcioj. La dekstra kolumno enhavas kelkajn
+# malplenaĵojn; ili restu tiel, por ke tiuj funkcioj ne listiĝu
+# en la listo da specialaj paĝoj.
+/* private */ $wgValidSpecialPagesEo = array(
+       "Userlogin"             => "",
+       "Userlogout"    => "",
+       "Preferences"   => "Ŝanĝu miajn preferojn",
+       "Watchlist"             => "Mian atentaron", # Listo de paĝoj, kiujn la uzulo elektis por atenti
+       "Recentchanges" => "Lastaj ŝanĝoj al paĝoj",
+       "Upload"                => "Alŝutu bildojn kaj dosierojn",
+       "Imagelist"             => "Alŝutitaj dosieroj",
+       "Listusers"             => "Enskribitaj uzuloj",
+       "Statistics"    => "Statistiko pri la paĝaro",
+       "Randompage"    => "Hazarda paĝo",
+
+       "Lonelypages"   => "Paĝoj neligitaj",
+       "Unusedimages"  => "Bildoj neligitaj",
+       "Popularpages"  => "Plej vizitataj paĝoj",
+       "Wantedpages"   => "Plej dezirataj paĝoj",
+       "Shortpages"    => "Mallongaj artikoloj",
+       "Longpages"             => "Longegaj artikoloj",
+       "Newpages"              => "Novaj artikoloj",
+       "Allpages"              => "Ĉiu paĝo laŭ titolo",
+
+       "Ipblocklist"   => "Forbaritaj IP-adresoj",
+    "Maintenance" => "Ripariloj kaj zorgiloj", # angle "Maintenance page"
+       "Specialpages"  => "",
+       "Contributions" => "",
+    "Emailuser"     => "",
+       "Whatlinkshere" => "",
+       "Recentchangeslinked" => "",
+       "Movepage"              => "",
+       "Booksources"   => "Eksteraj libroservoj"
+);
+
+/* private */ $wgSysopSpecialPagesEo = array(
+       "Blockip"               => "Forbaru fi-IP-adreson",
+       "Asksql"                => "Informomendu je la datumbazo",
+       "Undelete"              => "Restarigu forigitan paĝon"
+);
+
+# FIXME
+/* private */ $wgDeveloperSpecialPagesEo = array(
+       "Lockdb"                => "Forŝlosi datumaron",
+       "Unlockdb"              => "Repermesu ŝanĝon al datumaro",
+       "Debug"                 => "Montru servilinformon"
+);
+
+/* private */ $wgAllMessagesEo = array(
+
+# Teksteroj uzataj fare de diversaj paĝoj:
+#
+# Tiuj literoj, kiuj aperu kiel parto de la ligilo en formo "[[lingvo]]jn" ktp:
+"linktrail"     => "/^([a-z]+)(.*)\$/sD",
+"mainpage"             => "Ĉefpaĝo",
+"about"                        => "Enkonduko",
+"aboutwikipedia" => "Pri Vikipedio", #FIXME
+"aboutpage"            => "Vikipedio:Enkonduko",
+"help"                 => "Helpo",
+"helppage"             => "Vikipedio:Helpo",
+"wikititlesuffix" => "Vikipedio",
+"bugreports"   => "Raportu cimojn",
+"bugreportspage" => "Vikipedio:Raportu_cimojn",
+"faq"                  => "Oftaj demandoj",
+"faqpage"              => "Vikipedio:Oftaj demandoj",
+"edithelp"             => "Helpo pri redaktado",
+"edithelppage" => "Vikipedio:Kiel_redakti_paĝon", #FIXME: Kontrolu
+"cancel"               => "Nuligu",
+"qbfind"               => "Trovu",
+"qbbrowse"             => "Foliumado", # FIXME
+"qbedit"               => "Redaktado", #FIXME
+"qbpageoptions" => "Paĝagado", #FIXME
+"qbpageinfo"   => "Paĝinformoj", #FIXME
+"qbmyoptions"  => "Personaĵoj", #FIXME
+"mypage"               => "Mia paĝo", #FIXME
+"mytalk"        => "Mia diskuto",
+"currentevents" => "Aktualaĵoj", #FIXME - Novaĵoj? Aktualaj novaĵoj? Aktualaj eventoj?
+"errorpagetitle" => "Eraro", #FIXME - Arero? ;)
+"returnto"             => "Revenu al $1.",
+"fromwikipedia"        => "El Vikipedio, la libera enciklopedio.",
+"whatlinkshere"        => "Paĝoj kiuj ligas ĉi tien",
+"help"                 => "Helpo",
+"search"               => "Serĉu",
+"go"                   => "Ek",
+"history"              => "Malnovaj versioj",
+"printableversion" => "Presebla versio", 
+"editthispage" => "Redaktu la paĝon",
+"deletethispage" => "Forigu la paĝon",
+"protectthispage" => "Protektu la paĝon", #FIXME: Ĉu 'gardu' / "protekti" bonas /Bertilo
+"unprotectthispage" => "Malprotektu la paĝon", #FIXME: ĉu 'malgardu', 'ne plu', ktp? / "(mal)gardi" ne estas bona /Bertilo
+"newpage"              => "Nova paĝo",
+"talkpage"             => "Diskutu la paĝon",
+"subjectpage"  => "Vidu la artikolon", #FIXME: ?
+"articlepage"  => "Vidu la artikolon",
+"userpage"             => "Vidu personan paĝon",
+"wikipediapage"        => "Vidu meta-paĝon",
+"imagepage"            => "Vidu dosieropaĝon",
+"viewtalkpage" => "Vidu diskutopaĝon",
+"otherlanguages" => "Aliaj lingvoj",
+"redirectedfrom" => "(Alidirektita el $1)",
+"lastmodified" => "Laste redaktita je $1.",
+"viewcount"            => "Montrita $1-foje.",
+"gnunote"              => "La enhavo de Vikipedio disponeblas laŭ permesilo <a class='internal' href='/wiki/GFDL'>GNU Free Documentation License</a>.",
+"printsubtitle" => "(El http://eo.wikipedia.org)",
+"protectedpage" => "Protektita paĝo", #FIXME: ĉu "gardita" ktp?
+"administrators" => "Vikipedio:Administrantoj", # FIXME?
+"sysoptitle"   => "Konto de administranto bezonatas",
+"sysoptext"            => "La ago kiun vi petis fari estas
+farebla nur de uzuloj agnoskitaj kiel \"sistemestroj\".
+Bonvolu legi $1.", #FIXME
+"developertitle" => "Sistemestra konto nepras",
+"developertext"        => "Nur tiuj kiuj havas la staton, \"programisto\", povas fari tiun agon.
+Vidu $1.",
+"nbytes"               => "$1 bitokoj",
+"go"                   => "Ek!", #FIXME
+"ok"                   => "Ek!", #FIXME
+"sitetitle"            => "Vikipedio", # Wikipedia
+"sitesubtitle" => "La Libera Enciklopedio",
+"retrievedfrom" => "Citita el \"$1\"", #FIXME: Aperas post presita paĝo
+"newmessages"  => "Jen $1 por vi.",
+"newmessageslink" => "nova mesaĝo",
+# Main script and global functions
+#
+"nosuchaction" => "Ne ekzistas tia ago",
+"nosuchactiontext" => "La agon ('action') nomitan de la URL
+ne agnoskas la programaro de Vikipedio",
+"nosuchspecialpage" => "Ne ekzistas tia speciala paĝo",
+"nospecialpagetext" => "Vi petis specialan paĝon kiun
+ne agnoskas la programaro de Vikipedio",
+
+# General errors
+#
+"error"         => "Eraro", #FIXME: Fuŝo
+"databaseerror" => "Datumbaza eraro",
+"dberrortext"  => "Sintakseraro okazis en informpeto al la datumaro.
+Eble kaŭzis tion malpermesita serĉomendo (vidu je $5),
+aŭ eble tio indikas cimon en la programaro.
+Jen la plej laste provita informmendo:
+<blockquote><tt><nowiki>$1</nowiki></tt></blockquote>
+el la funkcio \"<tt>$2</tt>\". 
+MySQL redonis eraron  \"<tt>$3: $4</tt>\".",
+"noconnect"            => "Neeblis konekti al la datumbazo je $1",
+"nodb"                 => "Neeblis elekti datumaron $1",
+"readonly"             => "Datumaro ŝlosita, nurlega",
+"enterlockreason" => "Bonvolu klarigi, kial oni ŝlosas la datumaron, kaj
+la estimatan tempon de malŝlosado.",
+"readonlytext" => "La datumaro de Vikipedio estas nun ŝlosita kontraŭ
+novaj aldonaj kaj aliaj ŝanĝoj, probable pro laŭkutima flegado de la datumaro.
+Bonvolu reprovu post iom da tempo.
+
+La ŝlosinto lasis la jenan mesaĝon:
+<p>$1\n",
+"missingarticle" => "La datumbazo ne trovis la tekston de
+artikolo, kiun ĝi devus trovi, nomita \"$1\".
+Ĉi tio ne estas eraro de la datumbazo, sed probable cimo en la programo.
+Bonvolu raporti ĉi tion al iu sistemestro, kaj rimarkigi la retadreson (URL).",
+"internalerror" => "Interna eraro",
+"filecopyerror" => "Neeblis kopii dosieron  \"$1\" al \"$2\".",
+"filerenameerror" => "Neeblis alinomi dosieron \"$1\" al \"$2\".",
+"filedeleteerror" => "Neeblis forigi dosieron \"$1\".",
+"filenotfound" => "Neeblis trovi dosieron \"$1\".",
+"unexpected"   => "Neatendita valuto: \"$1\"=\"$2\".",
+"formerror"            => "Eraro: neeblis liveri formulon",    
+"badarticleerror" => "Tiu ago ne povas esti aplikata al tiu artikolo.",
+"cannotdelete"  => "Neeblis forigi la elektitan paĝon aŭ dosieron.",
+"badtitle"             => "Nevalida titolo",
+"badtitletext" => "La petita paĝotitolo estas nevalida, malplena, aŭ
+malĝuste ligita interlingva aŭ intervikia titolo.",
+
+# Login and logout pages
+#
+"logouttitle"  => "Elsalutu!",
+"logouttext"   => "Vi elsalutis kaj finis vian seancon.
+Vi rajtas daŭre Vikipediumi sennome, aŭ vi povas reensaluti
+kiel la sama aŭ kiel alia uzulo.\n", #FIXME
+
+"welcomecreation" => "<h2>Bonvenon, $1!</h2> Via konto estas kreita.
+<font color=\"red\">Ne forgesu fari viajn Vikipedio-preferojn!</font>",
+
+"loginpagetitle" => "Ensalutu / enskribu", #FIXME
+"yourname"             => "Via salutnomo", #FIXME ĉu kaŝnomo ĉu uzantonomo ĉu kontonomo ktp?
+"yourpassword" => "Via pasvorto",
+"yourpasswordagain" => "Retajpu pasvorton",
+"newusersonly" => " (nur novaj uzuloj)",
+"remembermypassword" => "Rememoru mian pasvorton.",
+"loginproblem" => "<b>Okazis problemo pri via ensalutado.</b><br>Bonvolu reprovi!",
+"alreadyloggedin" => "<font color=\"red\"><b>Uzulo $1, vi jam estas ensalutinta!</b></font><br>\n",
+
+"areyounew"            => "Se vi estas nova ĉe la Vikipedio kaj volas akiri uzulan konton,
+bonvolu tajpi salutnomon, pasvorton, kaj refoje pasvorton.
+Laŭvole vi rajtas enmeti vian retpoŝtadreson por ke ni povu
+sendi al vi novan pasvorton, se vi perdos la nunan.<br>\n",
+
+"login"                        => "Ensalutu", #FIXME, what exactly do the following go to?
+"userlogin"            => "Ensalutu",
+"logout"               => "Elsalutu",
+"userlogout"   => "Elsalutu",
+"createaccount"        => "Kreu novan konton",
+"badretype"            => "La pasvortoj kiujn vi tajpis ne egalas.",
+"userexists"   => "Jam estas uzulo kun la nomo kiun vi elektis. Bonvolu elekti alian nomon.",
+"youremail"            => "Via retpoŝtadreso",
+"yournick"             => "Via kaŝnomo (por subskriboj)", #FIXME - ĉu kaŝnomo, plumnomo? / "Kaŝnomo" ŝajnas bona /Bertilo
+"emailforlost" => "Se vi forgesos vian pasvorton, vi povas peti ke ni sendu novan al via retpoŝtadreso.",
+"loginerror"   => "Ensaluta eraro", #FIXME
+"noname"               => "Vi ne enmetis validan salutnomon.",
+"loginsuccesstitle" => "Ensalutado sukcesis",
+"loginsuccess" => "Vi nun estas en la Vikipedio kiel uzulo \"$1\".",
+"nosuchuser"   => "Neniu uzulo nomiĝas \"$1\".
+Bonvolu kontroli vian literumadon, aŭ uzu la malsupran formularon por krei novan konton.",
+"wrongpassword"        => "Vi tajpis malĝustan pasvorton. Bonvolu provi denove.",
+"mailmypassword" => "Retpoŝtu al mi novan pasvorton",
+"passwordremindertitle" => "Rememorigo el Vikipedio pri perdita pasvorto", #FIXME
+"passwordremindertext" => "Iu (probable vi, el IP-adreso $1)
+petis, ke ni sendu al vi novan pasvorton por ensaluti Vikipedion.
+La pasvorto por uzulo \"$2\" nun estas \"$3\".
+Ni rekomendas, ke vi nun ensalutu kaj ŝanĝu vian pasvorton.", #FIXME
+"noemail"              => "Retpoŝtadreso ne estas registrita por uzulo \"\".",
+"passwordsent" => "Oni sendis novan pasvorton al la retpoŝtadreso
+registrita por \"$1\".
+Bonvolu saluti denove ricevinte ĝin.",
+
+# Edit pages
+#
+"summary"              => "Resumo",
+"minoredit"            => "Ĉi tiu ŝanĝo estas redakteto",
+"watchthis"            => "Atentadu la artikolon",
+"savearticle"  => "Konservu ŝanĝojn",
+"preview"              => "Antaŭrigardo",
+"showpreview"  => "Antaŭrigardu", #FIXME eh?
+"blockedtitle" => "Uzulo forbarita", #FIXME ĉu 'Konto forbarita'?
+"blockedtext"  => "Via konto aŭ IP-adreso estis forbarita fare de $1,
+kiu priskribis la kialon jene:<br>$2
+<p>Vi rajtas kontakti tiun administranton por pridiskuti la forbaradon.", #FIXME - sistemestro?
+"newarticle"   => "(Nova)",
+"newarticletext" => "Vi sekvis ligilon al paĝo jam ne ekzistanta.
+Se vi volas krei ĝin, ektajpu sube (vidu la [[Vikipedio:Helpo|helpopaĝo]] por klarigoj.)
+Se vi malintence alvenis ĉi tien, simple alklaku la \"reen\" butonon de via retumilo.",
+"anontalkpagetext" => "---- ''Jen diskutopaĝo por iu anonima kontribuanto kiu ne jam kreis
+konton aŭ ne uzas ĝin. Ni tial devas uzi la cifran [[IP-adreso]] por tiun identigi.
+Tia IA-adreso povas kundividiĝi de pluraj uzuloj. Se vi estas anonimulo kaj preferus
+eviti tiajn maltrafajn komentojn kaj konfuziĝon kun aliaj anonimuloj ĉe via retero,
+bonvolu [[Speciala:Userlogin|kreu konton aŭ ensalutu]].",
+"noarticletext" => "(La paĝo nun estas malplena)", #FIXME
+"updated"              => "(Ŝanĝo registrita)", #FIXME: ?
+"note"                 => "<strong>Noto:</strong> ", #FIXME: Where does this come from?
+"previewnote"  => "Memoru, ke ĉi tio estas nur antaŭrigardo kaj ne jam konservita!",
+"previewconflict" => "La jena antaŭrigardo montras la tekston el la supra tekstujo,
+kiel ĝi aperos se vi elektos konservi la paĝon.", #FIXME
+"editing"              => "Redaktante $1",
+"editconflict" => "Redakta konflikto: $1",
+"explainconflict" => "Iu alia ŝanĝis la paĝon post kiam vi ekredaktis.
+La supra tekstujo enhavas la aktualan tekston de la artikolo.
+Viaj ŝanĝoj estas en la malsupra tekstujo.
+Vi devas mem kunfandi viajn ŝanĝojn kaj la jaman tekston.
+<b>Nur</b> la teksto en la supra tekstujo estos konservita kiam
+vi alklakos \"Konservu\".\n<p>" , #FIXME - double-check that this makes sense
+"yourtext"             => "Via teksto",
+"storedversion" => "Registrita versio",
+"editingold"   => "<strong>AVERTO: Vi nun redaktas malnovan version de tiu ĉi artikolo.
+Se vi konservos vian redakton, ĉiuj ŝanĝoj faritaj post tiu versio perdiĝos.</strong>\n",
+"yourdiff"             => "Malsamoj",
+"copyrightwarning" => "Bonvolu noti, ke ĉiu kontribuaĵo al la Vikipedio
+estu rigardata kiel eldonita laŭ la <i>GNU Free Documentation License</i> (vidu je $1).
+Se vi volas, ke via verkaĵo ne estu redaktota senkompate kaj disvastigota
+laŭvole, ne alklaku \"Konservu\".
+Vi ankaŭ ĵuras, ke vi mem verkis la tekston, aŭ ke vi kopiis ĝin el
+fonto senkopirajta. <strong>NE UZU KOPIRAJTAJN VERKOJN SENPERMESE!</strong>",
+"longpagewarning" => "AVERTO: Tiu ĉi paĝo longas $1 kilobitokojn; kelkaj retumiloj
+povas fuŝi redaktante paĝojn je longo proksime aŭ preter 32kb.
+Se eble, bonvolu disigi la paĝon al malpli grandajn paĝerojn.",
+
+# History pages
+#
+"revhistory"   => "Historio de redaktoj",
+
+"nohistory"            => "Ne ekzistas historio de redaktoj por ĉi tiu paĝo.", #FIXME
+"revnotfound"  => "Ne ekzistas malnova versio de la artikolo", #fixme
+"revnotfoundtext" => "Ne eblis trovi malnovan version de la artikolo kiun vi petis.
+Bonvolu kontroli la retadreson (URL) kiun vi uzis por atingi la paĝon.\b",
+"loadhist"             => "Ŝarĝas redaktohistorion", #FIXME Apparently not used
+
+"currentrev"   => "Aktuala versio", #FIXME ĉu "plej lasta"?
+"revisionasof" => "Kiel registrite je $1",
+"cur"                  => "nun",
+
+"next"                 => "sekv",
+"last"                 => "ant",
+"orig"                 => "orig",
+"histlegend"   => "Klarigo: (nun) = vidu malsamojn kompare kun la nuna versio,
+(ant) = malsamojn kompare kun la antaŭa versio, M = malgranda redakteto",
+
+# Diffs
+#
+"difference"   => "(Malsamoj inter versioj)",
+"loadingrev"   => "ŝarĝas version por malsamoj", #FIXME Apparently not used
+"lineno"               => "Linio $1:",
+"editcurrent"  => "Redaktu la nunan version de la paĝo",
+
+# Search results
+#
+"searchresults" => "Serĉrezultoj",
+"searchhelppage" => "Vikipedio:Serĉado",
+"searchingwikipedia" => "Priserĉante la Vikipedion",
+"searchresulttext" => "Por pliaj informoj kiel priserĉi la Vikipedion, vidu .",
+"searchquery"  => "Serĉmendo \"$1\"",
+"badquery"             => "Misformita serĉmendo",
+"badquerytext" => "Via serĉmendo ne estis plenumebla.
+Eble vi provis serĉi vorton malpli longan ol tri literoj. 
+Tion la programo ne jam povas fari. Ankaŭ eblas, ke vi mistajpis la
+esprimon".
+#", ekzemple \"fiŝoj kaj kaj skaloj\"".   # FIXME ? eblas
+". Bonvolu reserĉi per alia mendo.",
+"matchtotals"  => "La serĉmendo \"$1\" liveris $2 artikolojn laŭ titolo
+kaj $3 artikolojn laŭ enhavo.",
+"nogomatch"    => "Neniu paĝo havas precize la titolon; provas tekstoserĉon... ",
+"titlematches" => "Trovitaj laŭ titolo",
+"notitlematches" => "Neniu trovita laŭ titolo",
+"textmatches"  => "Trovitaj laŭ enhavo",
+"notextmatches"        => "Neniu trovita laŭ enhavo",
+"prevn"                        => "$1 antaŭajn",
+"nextn"                        => "$1 sekvajn",
+"viewprevnext" => "Montru ($1) ($2) ($3).",
+"showingresults" => "Montras <b>$1</b> trovitajn ekde la <b>$2</b>-a.",
+"nonefound"            => "<strong>Noto</strong>: malsukcesaj serĉoj ofte
+okazas ĉar oni serĉas tro da ofte uzataj vortoj, kiujn ne enhavas la indekso,
+aŭ ĉar oni petas tro da serĉvortoj (nur paĝoj kiuj enhavas ĉiun serĉvorton
+montriĝos en la rezulto).",
+"powersearch" => "Trovu",
+
+"powersearchtext" => "
+Serĉu en sekcioj: :<br>
+$1<br>
+$2 Kun alidirektiloj   Serĉu $3 $9",
+
+# Preferences page
+#
+"preferences"  => "Preferoj",
+"prefsnologin" => "Ne jam salutis!",
+"prefsnologintext"     => "<a href=\"" .
+  wfLocalUrl( "Special:Userlogin" ) . "\">Ensalutu</a>
+kaj vi povos ŝanĝi viajn preferojn.",
+"prefslogintext" => "Vi ensalutis kiel \"$1\".
+Via interna identeconumero estas $2.",
+"prefsreset"   => "Preferoj reprenitaj el la registro.", #FIXME: Hmm...
+"qbsettings"   => "Preferoj pri ilaro", 
+"changepassword" => "Ŝanĝu pasvorton",
+"skin"                 => "Aspekto",
+"math"                 => "Tradukas matematikaĵon",
+"math_failure" => "Malsukcesis analizi formulon",
+"math_unknown_error"   => "Nekonata eraro",
+"math_unknown_function"        => "Nekonata funkcio",
+"math_lexing_error"    => "Leksika analizo malsukcesis",
+"math_syntax_error" => "Eraro de sintakso",
+"saveprefs"            => "Konservu preferojn",
+"resetprefs"   => "Restarigi antaŭajn preferojn",
+"oldpassword"  => "Malnova pasvorto",
+"newpassword"  => "Nova pasvorto",
+"retypenew"            => "Retajpu novan pasvorton",
+"textboxsize"  => "Grandeco de redakta tekstujo",
+"rows"                 => "Linioj",
+"columns"              => "Kolumnoj",
+"searchresultshead" => "Agordaĵoj pri serĉorezulto",
+"resultsperpage" => "Montru trovitajn po",
+"contextlines" => "Montru liniojn el paĝoj po",
+
+"contextchars" => "Montru literojn el linioj ĝis po",
+"stubthreshold" => "Indiku paĝojn malpli grandajn ol",
+"recentchangescount" => "Montru kiom da titoloj en 'Lastaj ŝanĝoj'",
+"savedprefs"   => "Viaj preferoj estas konservitaj.",
+"timezonetext" => "Indiku je kiom da horoj via
+loka horzono malsamas disde tiu de la servilo (UTC).
+Ekzemple, por la Centra Eŭropa Horzono, indiku \"1\" vintre aŭ \"2\" dum somertempo.",
+"localtime"    => "Loka horzono",
+"timezoneoffset" => "Malsamo", #FIXME (?)
+"emailflag"     => "Malakceptu retmesaĝojn de aliaj vikipediistoj",
+
+# Recent changes
+#
+"changes"      => "ŝanĝoj", # RIPARUMIN n?
+"recentchanges" => "Lastaj ŝanĝoj",
+"recentchangestext" => "Sekvu la plej lastajn ŝanĝojn al la Vikipedio per ĉi tiu paĝo.
+[[vikipedio:Bonvenon al la Vikipedio|Bonvenon al la Vikipedio]]!
+Bonvolu legi ĉi tiujn paĝojn: [[vikipedio:Oftaj demandoj|Oftaj demandoj]],
+[[vikipedio:Konsiletoj|Konsiletoj]]
+(aparte [[vikipedio:Nomoj de titoloj|Nomoj de titoloj]]
+kaj [[vikipedio:Neŭtrala vidpunkto|Neŭtrala vidpunkto]]),
+kaj [[vikipedio:Oftaj eraroj|Oftaj vikipediaj eraroj]].
+
+
+Se vi volas, ke la Vikipedio sukcesu, tre gravas ke vi ne aldonu
+materialojn kiujn oni ne laŭleĝe rajtas aldoni pro [[Vikipedio:Kopirajto|kopirajto]].
+La leĝa respondeco vere povus malhelpi la projekton,
+do bonvolu ne fari tion.
+
+Ankaŭ vidu la [http://meta.wikipedia.org/wiki/Special:Recentchanges lastatempan pri-vikipedian diskuton]
+(plurlingve)",
+"rcloaderr"            => "Ŝarĝas lastajn ŝanĝojn",
+"rcnote"               => "Jen la plej lastaj <b>$1</b> ŝanĝoj en la lastaj <b>$2</b> tagoj.",
+"rcnotefrom"   => "Jen la ŝanĝoj ekde <b>$2</b> (lastaj ĝis <b>$1</b>).",
+"rclistfrom"   => "Montru novajn ŝanĝojn ekde $1",
+"rclinks"              => "Montru $1 lastajn ŝanĝojn; montru la ŝanĝojn dum la $2 lastaj tagoj.",
+"diff"                 => "malsamoj",
+"hist"                 => "historio",
+"hide"                 => "kaŝu",
+"show"                 => "montru",
+"tableform"            => "tabelo",
+"listform"             => "listo",
+"nchanges"             => "$1 ŝanĝoj",
+"minoreditletter" => "M",
+"newpageletter" => "N",
+
+# Upload
+#
+"upload"               => "Alŝutu dosieron",
+"uploadbtn"            => "Alŝutu dosieron",
+"uploadlink"   => "Alŝutu bildon", # Ĉu neuzata?
+"reupload"             => "Realŝutu",
+"reuploaddesc" => "Revenu al la alŝuta formularo.",
+"uploadnologin" => "Ne ensalutinta",
+"uploadnologintext"    => "Se vi volas alŝuti dosierojn, vi devas <a href=\"" .
+  wfLocalUrl( "Speciala:Userlogin" ) . "\">ensaluti</a>.",
+"uploadfile"   => "Alŝutu dosieron",
+"uploaderror"  => "Eraro okazis dum alŝuto",
+"uploadtext"   => "Por okulumi aŭ serĉi jam alŝutitajn dosierojn,
+aliru la <a href=\"" . wfLocalUrl( "Special:Imagelist" ) .
+"\">liston de alŝutaĵoj</a>.
+Ĉiuj alŝutoj kaj forigoj estas registrataj en la <a href=\"" .
+wfLocalUrl( "Vikipedio:Loglibro de alŝutaĵoj" ) ."\">alŝuta loglibro</a>.</p>
+
+<p>Uzu ĉi tiun formularon por alŝuti novajn bildojn kaj aliajn dosierojn
+por ilustrado de viaj artikoloj.
+Ĉe kutimaj retumiloj, vi vidos ĉi-sube butonon \"Foliumi...\" aŭ simile;
+tiu malfermas la dosierelektilon de via operaciumo.
+Kiam vi elektos dosieron, ĝia nomo plenigos la tekstujon apud la butono.
+Vi ankaŭ nepre devas klakjesi la skatolon por aserti, ke vi ne
+malobeas la leĝan kopirajton de aliuloj per alŝuto de la dosiero.
+Por plenumi la alŝutadon, alklaku la butono \"Alŝutu\".
+Tio ĉi eble iomete longe daŭros, se estas granda dosiero kaj se via interreta konekto malrapidas.</p>
+
+<p>La dosiertipoj preferataj ĉe Vikipedio estas JPEG por fotografaĵoj,
+PNG por grafikaĵoj, diagramoj, ktp; kaj OGG por sonregistraĵoj.
+Bonvolu doni al via dosiero nomon informan, por eviti konfuzon.
+Por enmeti la dosieron en artikolon, skribu ligilon laŭ la formo
+<b>[[bildo:dosiero.jpg]]</b> aŭ <b>[[image:bildo.png|teksto por retumiloj negrafikaj]]</b>,
+aŭ <b>[[dosiero:dosiero.ogg]]</b> por sono.</p>
+
+<p>Bonvolu rimarki, ke same kiel artikoloj en la Vikipedio, aliaj Vikipediistoj
+rajtas redakti, anstataŭigi, aŭ forigi viajn alŝutaĵojn se ili pensas, ke
+tio servus la enciklopedion. Se vi aĉe misuzas la sistemon, eblas ke vi estos
+forbarita.</p>",
+"uploadlog"            => "loglibro de alŝutaĵoj",
+"uploadlogpage" => "Loglibro_de_alŝutaĵoj",
+"uploadlogpagetext" => "Jen la plej laste alŝutitaj dosieroj.
+Ĉiuj tempoj montriĝas laŭ la horzono UTC.
+<ul>
+</ul>
+",
+"filename"             => "Dosiernomo",
+"filedesc"             => "Priskribo",
+"affirmation"  => "Mi asertas, ke la laŭleĝa posedanto de la kopirajto
+de ĉi tiu dosiero konsentas eldoni ĝin laŭ la $1.",
+"copyrightpage" => "Vikipedio:Kopirajto",
+"copyrightpagename" => "permesilo GFDL uzata por la Vikipedio",
+"uploadedfiles"        => "Alŝutitaj dosieroj",
+"noaffirmation" => "Vi nepre devas aserti, ke via alŝutaĵo ne malobeas la leĝojn de kopirajto.",
+"ignorewarning"        => "Malatentu averton kaj tamen konservu la dosieron.",
+"minlength"            => "Dosiernomo devas havi pli ol du literojn.",
+"badfilename"  => "Dosiernomo estis ŝanĝita al \"$1\".",
+"badfiletype"  => "\".$1\" estas dosiertipo malrekomendata.",
+"largefile"            => "Oni rekomendas, ke dosieroj ne superu grandon de 100 megabitoj.",
+"successfulupload" => "Alŝuto sukcesis!",
+"fileuploaded" => "Vi sukcese alŝutis dosieron \"$1\".
+Bonvolu sekvi la jenan ligilo: ($2) al la priskrib-paĝo kaj
+verki iom da informo pri la dosiero. Ekzemple, de kie ĝi devenas;
+kiam ĝi estis kreita, kaj kiu kreis ĝin; kaj ion ajn, kion vi scias pri ĝi.",
+"uploadwarning" => "Averto",
+"savefile"             => "Konservu dosieron",
+"uploadedimage" => "alŝutis \"$1\"",
+
+# Image list
+#
+"imagelist"            => "Listo de alŝutitaj dosieroj",
+"imagelisttext"        => "Jen listo de $1 alŝutaĵoj, ordigitaj laŭ $2.",
+"getimagelist" => "akiras dosierliston",
+"ilshowmatch"  => "Montru tiujn dosierojn kies nomoj trafas",
+"ilsubmit"             => "Trovu!",
+"showlast"             => "Montru la $1 lastajn bildojn laŭ $2.",
+"all"                  => "ĉiuj",
+"byname"               => "nomo",
+"bydate"               => "dato",
+"bysize"               => "grandeco",
+"imgdelete"            => "forigu",
+"imgdesc"              => "pri",
+"imglegend"            => "(pri) = montru/redaktu priskribon de dosiero.",
+"imghistory"   => "Historio de alŝutoj",
+"revertimg"            => "res",
+"deleteimg"            => "for",
+"imghistlegend" => "(nun) = ĉi tiu estas la nuna versio de la dosiero, (for) = forigu
+ĉi tiun malnovan version, (res) = restarigu ĉi tiun malnovan version.
+<br><i>Por vidi la dosieron laŭdate, alklaku la daton</i>.",
+"imagelinks"   => "Ligiloj al la dosiero",
+"linkstoimage" => "La jenaj paĝoj ligas al ĉi tiu dosiero:",
+"nolinkstoimage" => "Neniu paĝo ligas al ĉi tiu dosiero.",
+
+# Statistics
+#
+"statistics"   => "Statistiko",
+"sitestats"            => "Pri la retejo",
+"userstats"            => "Pri la uzularo",
+"sitestatstext" => "Troviĝas en nia datumaro sume <b>$1</b> paĝoj.
+Tiu nombro enhavas \"diskutpaĝojn\", paĝojn pri Vikipedio, \"artikoletetojn\", alidirektilojn, kaj aliajn, kiuj eble ne vere estas artikoloj. Malatentante ilin, oni povas nombri <b>$2</b> probablajn ĝustajn
+artikolojn.</p>
+
+<p>Oni vidis sume <b>$3</b> paĝojn, kaj redaktis sume <b>$4</b> paĝojn
+ekde la starigo de la nuna vikiprogramo (novembro 2002).
+Tio estas meznombre po unu paĝo por <b>$5</b> paĝoj viditaj, kaj por <b>$6</b> redaktoj.",
+"userstatstext" => "Enskribiĝis <b>$1</b> uzuloj. El tiuj, <b>$2</b> estas administrantoj (vidu $3).",
+
+# Maintenance Page
+#
+"maintenance"          => "Ripariloj kaj zorgiloj",
+"maintnancepagetext"   => "Jen diversaj iloj por riparado kaj ĝenerala zorgado de la datumaro.
+Kelkaj funkcioj povas streĉi la datumbazon, do bonvolu ne reŝuti post ĉiu riparita ero!",
+"maintenancebacklink"  => "Revenu al la ilaro",
+"disambiguations"      => "Misligitaj apartigiloj",
+"disambiguationspage"  => "Vikipedio:Apartigiloj",
+"disambiguationstext"  => "La jenaj paĝoj alligas <i>paĝon-apartigilon</i>. Ili devus anstataŭe alligi la ĝustan temon.<br>Oni konsideras tiujn paĝojn, kiujn alligas $1 apartigiloj.<br>Ligado el ne-artikolaj sekcioj <i>ne</i> listiĝas ĉi tie.",
+"doubleredirects"      => "Duoblaj alidirektadoj",
+"doubleredirectstext"  => "<b>Atentu:</b> Eblas, ke la jena listo enhavas falsajn rezultojn. Ĝenerale, tio signifas, ke estas plua teksto kun ligiloj post la #REDIRECT.<br>
+Ĉiu linio montras ligilojn ĉe la unua kaj dua alidirektadoj, kaj la unua linio de la teksto de la dua alidirektado, kiu ĝenerale montras la \"veran\" artikolon, kiu devus celi la unuan alidirektadon.",
+"brokenredirects"      => "Rompitaj alidirektadoj",
+"brokenredirectstext"  => "La jenaj alidirektadoj ligas al neekzistantaj artikoloj.",
+"selflinks"            => "Paĝoj memligantaj",
+"selflinkstext"                => "La jenaj paĝoj enhavas ligilon al si mem, kiuj neutilas.",
+"mispeelings"           => "Paĝoj kun misliterumoj",
+"mispeelingstext"               => "La jenaj paĝoj enhavas unu el la oftaj misliterumadoj listitaj en $1. La ĝusta literumo montriĝos (ĉi tiel).",
+"mispeelingspage"       => "Listo de oftaj misliterumoj",
+"missinglanguagelinks"  => "Mankantaj interlingvaj ligiloj",
+"missinglanguagelinksbutton"    => "Montru mankajn interlingvajn ligilojn por",
+"missinglanguagelinkstext"      => "La jenaj artikoloj <i>ne</i> ligas al sia versio en la lingvo $1. Alidirektadoj kaj subpaĝoj <i>ne</i> montriĝas.",
+
+
+# Miscellaneous special pages
+#
+"orphans"              => "Neligitaj paĝoj",
+"lonelypages"  => "Neligitaj paĝoj",
+"unusedimages" => "Neuzataj bildoj",
+"popularpages" => "Plej vizitataj paĝoj",
+"nviews"               => "$1-foje",
+"wantedpages"  => "Dezirataj paĝoj",
+"nlinks"               => " ligiloj",
+"allpages"             => "Ĉiuj paĝoj",
+"randompage"   => "Hazarda paĝo",
+"shortpages"   => "Paĝetoj",
+"longpages"            => "Paĝegoj",
+"listusers"            => "Uzularo",
+"specialpages" => "Specialaj paĝoj",
+"spheading"            => "Specialaj paĝoj",
+"sysopspheading" => "Specialaj paĝoj por uzado de administrantoj",
+"developerspheading" => "Specialaj paĝoj nur por uzado de programistoj",
+"protectpage"  => "Protektu paĝon",
+"recentchangeslinked" => "Rilataj paĝoj",
+"rclsub"               => "(al paĝoj ligitaj de \"$1\")",
+"debug"                        => "Kontraŭcima", #CHUCK ĉu "malcimigu"? | Pli bone "sencimigi" /Bertilo
+"newpages"             => "Novaj paĝoj",
+"movethispage" => "Movu la paĝon",
+"unusedimagestext" => "<p>Notu, ke aliaj TTT-ejoj, ekzemple
+la alilingvaj Vikipedioj, povas rekte ligi al dosiero per URL.
+Tio ne estus enkalkutita en la jena listo.",
+"booksources"  => "Libroservoj",
+"booksourcetext" => "Jen ligilaro al aliaj TTT-ejoj, kiuj vendas librojn,
+kaj/aŭ informumos pri la libro ligita.
+La Vikipedio ne estas komerce ligita al tiuj vendejoj, kaj la listo ne estu
+komprenata kiel rekomendo aŭ reklamo.", 
+"alphaindexline" => "$1 ĝis $2",
+
+# Email this user
+#
+"mailnologin"  => "Neniu alsendota adreso",
+"mailnologintext" => "Vi nepre estu <a href=\"" .
+  wfLocalUrl( "Speciala:Userlogin" ) . "\">salutanta</a>
+kaj havanta validan retpoŝtadreson en viaj <a href=\"" .
+  wfLocalUrl( "Speciala:Preferences" ) . "\">preferoj</a>
+por retpoŝti al aliaj Vikipediistoj.",
+"emailuser"            => "Retpoŝtu",
+"emailpage"            => "Retpoŝtu",
+"emailpagetext"        => "Se la alsendota vikipediisto donis validan retpoŝtadreson
+en la preferoj, vi povas sendi unu mesaĝon per la jena formulo.
+La retpoŝtadreso, kiun vi metis en la preferoj, aperos kiel \"El\"-adreso
+de la poŝto, por ke la alsendonto povos respondi.",
+"noemailtitle" => "Neniu retpoŝtadreso",
+"noemailtext"  => "Ĉi tiuj vikipediistoj aŭ ne donis validan retpoŝtadreson
+aŭ elektis ne ricevi retpoŝton de aliaj vikipediistoj.",
+"emailfrom"            => "El",
+"emailto"              => "Al",
+"emailsubject" => "Subjekto",
+"emailmessage" => "Mesaĝo",
+"emailsend"            => "Sendu",
+"emailsent"            => "Retmesaĝo sendita",
+"emailsenttext" => "Via retmesaĝo estas sendita.",
+
+
+
+# Watchlist
+#
+"watchlist"            => "Atentaro",
+"watchlistsub" => "(de uzulo \"$1\")",
+"nowatchlist"  => "Vi ne jam elektis priatenti iun ajn paĝon.",
+"watchnologin" => "Ne salutinta",
+"watchnologintext"     => "Nepras <a href=\"" .
+  wfLocalUrl( "Speciala:Userlogin" ) . "\">saluti</a>
+por ŝanĝi vian atentaron.",
+"addedwatch"   => "Aldonis al atentaro",
+"addedwatchtext" => "La paĝo \"$1\" estis aldonita al via <a href=\"" .
+  wfLocalUrl( "Speciala:Watchlist" ) . "\">atentaro</a>.
+Estontaj ŝanĝoj al tiu paĝo aperos en <b>grasa tiparo</b> en la <a href=\"" .
+  wfLocalUrl( "Speciala:Recentchanges" ) . "\">listo de Lastaj Ŝanĝoj</a>,
+kaj estos kalkulita en la listo de via atentaro.
+
+<p>Se vi poste volos eksigi la paĝon el via atentaro, alklaku \"Malatentu paĝon\" en la ilobreto.",
+"removedwatch" => "Forigis el atentaro",
+"removedwatchtext" => "La paĝo \"$1\" estas forigita el via atentaro.",
+"watchthispage"        => "Priatentu paĝon",
+"unwatchthispage" => "Malatentu paĝon",
+"notanarticle" => "Ne estas artikolo",
+
+# Delete/protect/revert
+#
+"deletepage"   => "Forigu paĝon",
+"confirm"              => "Konfirmu",
+"confirmdelete" => "Konfirmu forigadon",
+"deletesub"            => "(Forigas \"$1\")",
+"confirmdeletetext" => "Vi forigos la artikolon aŭ dosieron kaj
+forviŝos ĝian tutan historion el la datumaro.<br>
+Bonvolu konfirmi, ke vi vere intencas tion, kaj ke vi komprenas
+la sekvojn, kaj ke vi ja sekvas la [[Vikipedio:Reguloj pri forigado|regulojn pri forigado]].",
+"confirmcheck" => "Jes, mi tutkore certas ke mi volas forigi tiun artikolon/dosieron.",
+"actioncomplete" => "Ago farita",
+"deletedtext"  => "\"$1\" estas forigita.
+Vidu la paĝon $2 por registro de lastatempaj forigoj.",
+"deletedarticle" => "forigis \"$1\"",
+"dellogpage"   => "Loglibro_de_forigoj", # NEPRE NE FORIGU LA "_"-SIGNOJN!
+"dellogpagetext" => "Jen listo de la plej lastaj forigoj el la datumaro.
+Ĉiuj tempoj sekvas la horzonon UTC.
+<ul>
+</ul>
+",
+"deletionlog"  => "listo de forigoj",
+"reverted"             => "Restarigis antaŭan version",
+"deletecomment"        => "Kialo por forigo",
+"imagereverted" => "Restarigo de antaŭa versio sukcesis.",
+"rollback"     => "Restarigu antaŭan redakton",
+"rollbacklink" => "restarigu antaŭan",
+"cantrollback" => "Neeblas restarigu antaŭan redakton; la redaktinto lasta estas la sola de la paĝo.",
+"revertpage"   => "Restarigis lastan redakton de $1",
+
+# Undelete
+"undelete" => "Restarigu forigitan paĝon",
+"undeletepage" => "Montru kaj restarigu forigitajn paĝojn",
+"undeletepagetext" => "La jenaj paĝoj estis forigitaj, sed ankoraŭ restas arkivitaj,
+kaj oni povas restarigi ilin. La arkivo povas esti malplenigita periode.",
+"undeletearticle" => "Restarigu forigitan artikolon",
+"undeleterevisions" => "$1 versioj arkivitaj",
+"undeletehistory" => "Se vi restarigos la paĝon, ĉiuj versioj estos restarigitaj
+en la historio. Se nova paĝo kun la sama nomo estis kreita post la forigo, la restarigitaj
+versioj aperos antaŭe en la historio, kaj la aktuala versio ne estos anstataŭigita.",
+"undeleterevision" => "Forigita versio de $1", # ( estas tempo)
+"undeletebtn" => "Restarigu!",
+"undeletedarticle" => "restarigis \"$1\"",
+"undeletedtext"   => "La artikolo [[$1]] estas sukcese restarigita.
+Vidu [[Vikipedio:Loglibro de forigoj]] por registro de lastatempaj forigoj kaj restarigoj.",
+
+# Contributions
+#
+"contributions"        => "Kontribuoj de Vikipediisto",
+"mycontris"    => "Miaj kontribuoj",
+"contribsub"   => "De $1",
+"nocontribs"   => "Trovis neniajn redaktojn laŭ tiu kriterio.",
+"ucnote"               => "Jen la <b>$1</b> lastaj redaktoj de tiu Vikipediisto dum la <b>$2</b> lastaj tagoj.",
+"uclinks"              => "Montru la $1 lastajn redaktojn; montru la $2 lastajn tagojn.",
+
+# What links here
+#
+"whatlinkshere"        => "Ligiloj ĉi tien",
+"notargettitle" => "Sen celpaĝo",
+"notargettext" => "Vi ne precizigis, kiun paĝon aŭ uzulon priumi.",
+"linklistsub"  => "(Listo de ligiloj)",
+"linkshere"            => "La jenaj paĝoj ligas ĉi tien:",
+"nolinkshere"  => "Neniu paĝo ligas ĉi tien.",
+"isredirect"   => "alidirekto",
+
+# Block/unblock IP
+#
+"blockip"              => "Forbaru IP-adreson",
+"blockiptext"  => "Per la jena formularo vi povas forbari iun IP-adreson
+je la rajto enskribiĝi en la vikion.
+Oni tion faru ''nur'' por eviti vandalismon, kaj sekvante la
+[[Vikipedio:Reguloj pri forbarado|regulojn pri forbarado]].
+Klarigu la precizan kialon malsupre (ekzemple, citu paĝojn, kiuj estis
+vandalumitaj).",
+"ipaddress"            => "IP-adreso",
+"ipbreason"            => "Kialo",
+"ipbsubmit"            => "Forbaru la adreson",
+"badipaddress" => "La IP-adreso estas misformita.",
+"noblockreason" => "Vi nepre klarigu kialon pri la forbaro.",
+"blockipsuccesssub" => "Sukcesis forbari",
+"blockipsuccesstext" => "La IP-adreso \"$1\" estas forbarita.
+<br>Vidu la [[Special:Ipblocklist|liston de IP-forbaroj]].",
+"unblockip"            => "Malforbaru IP-adreson",
+"unblockiptext"        => "Per la jena formulo vi povas repovigi al iu
+forbarita IP-adreso la povon enskribi en la vikio.",
+"ipusubmit"            => "Malforbaru la adreson",
+"ipusuccess"   => "IP-adreso \"$1\" estas malforbarita",
+"ipblocklist"  => "Listo de forbaritaj IP-adresoj",
+"blocklistline"        => "Je $1, $2 forbaris $3",
+"blocklink"            => "forbaru",
+"unblocklink"  => "malforbaru",
+"contribslink" => "kontribuoj",
+
+# Developer tools
+#
+"lockdb"               => "Ŝlosi datumaron",
+"unlockdb"             => "Malŝlosi datumaron",
+"lockdbtext"   => "Se vi ŝlosos la datumaron, tio malebligos al ĉiuj uzuloj
+redakti paĝojn, ŝanĝi preferojn, priumi atentarojn, kaj fari diversajn aliajn
+aferojn, por kiuj nepras ŝanĝi la datumaron.
+Bonvolu certigu, ke vi efektive intencas tion fari, kaj ke vi ja malŝlosos
+la datumaron post ol vi finos vian riparadon.",
+"unlockdbtext" => "Se vi malŝlosos la datumaron, tio reebligos al ĉiuj uzuloj
+redakti paĝojn, ŝanĝi preferojn, priumi la atentaron, kaj fari aliajn aferojn,
+por kiuj nepras ŝanĝi al la datumaro.
+Bonvolu certigu, ke vi efektive intencas tion fari.",
+"lockconfirm"  => "Jes, mi vere volas ŝlosi la datumaron.",
+"unlockconfirm"        => "Jes, mi vere volas malŝlosi la datumaron.",
+"lockbtn"              => "Ŝlosi datumaron",
+"unlockbtn"            => "Malŝlosi datumaron",
+"locknoconfirm" => "Vi ne konfirmis.",
+"lockdbsuccesssub" => "Datumaro ŝlosita",
+"unlockdbsuccesssub" => "Datumaro malŝlosita",
+"lockdbsuccesstext" => "La datumaro de Vikipedio estas ŝlosita.
+<br>Ne forgesu malŝlosi ĝin post kiam vi finos la riparadon.",
+"unlockdbsuccesstext" => "La datumaro de Vikipedio estas malŝlosita.",
+
+# SQL query
+#
+"asksql"               => "SQL-informpeto",
+"asksqltext"   => "Per la jena formulo vi povas rekte peti la datumbazon
+per informpeto SQL-a.
+Tio povas ege ŝarĝi la servilon, do bonvolu uzi tiun eblon ŝpare kaj singarde.",
+"sqlquery"             => "Tajpu informpeton",
+"querybtn"             => "Petu!",
+"selectonly"   => "Informpetojn krom \"SELECT\" estas limigitaj je
+Vikipedio-programistoj.",
+"querysuccessful" => "Informpeto sukcesis",
+
+# Move page
+#
+"movepage"             => "Movu paĝon",
+"movepagetext" => "Per la jena formulo vi povas ŝanĝi la nomon de iu paĝo, kunportante
+ĝian historion de redaktoj je la nova nomo.
+La antaŭa titolo fariĝos alidirektilo al la nova titolo.
+Ligiloj al la antaŭa titolo <i>ne</i> estos ŝanĝitaj; uzu
+la [[Speciala:Maintenance|riparilojn kaj zorgilojn]] por certigi,
+ke ne restos duoblaj aŭ fuŝitaj alidirektiloj.
+Kiel movanto, vi respondecas pri ĝustigado de fuŝitaj ligiloj.
+
+Notu, ke la paĝo '''ne''' estos movita se jam ekzistas paĝo
+ĉe la nova titolo, krom se ĝi estas malplena aŭ alidirektilo
+al ĉi tiu paĝo, kaj sen antaŭa redaktohistorio. Pro tio, vi ja
+povos removi la paĝon je la antaŭa titolo se vi mistajpus, kaj
+neeblas ke vi neintence forviŝus ekzistantan paĝon per movo.
+
+<b>AVERTO!</b>
+Tio povas esti drasta kaj neatendita ŝanĝo por populara paĝo;
+bonvolu certigi vin, ke vi komprenas ties konsekvencojn antaŭ
+ol vi antaŭeniru.",
+
+"movepagetalktext" => "La movo aŭtomate kunportos la diskuto-paĝon, se tia ekzistas, '''krom se:'''
+*Vi movas la paĝon tra sekcioj (ekz de ''Nomo'' je ''Vikipediisto:Nomo''),
+*Ne malplena diskuto-paĝo jam ekzistas je la nova nomo, aŭ
+*Vi malelektas la suban ŝaltilon.
+
+Tiujokaze, vi nepre permane kunigu la diskuto-paĝojn se vi tion deziras.",
+"movearticle"  => "Movu paĝon",
+"movenologin"  => "Ne ensalutinta",
+"movenologintext" => "Vi nepre estu registrita uzulo kaj <a href=\"" .
+  wfLocalUrl( "Speciala:Userlogin" ) . "\">ensalutu</a>
+por rajti movi paĝojn.",
+"newtitle"             => "Al nova titolo",
+"movepagebtn"  => "Movu paĝon",
+"pagemovedsub" => "Sukcesis movi",
+"pagemovedtext" => "Paĝo \"[[$1]]\" estas movita al \"[[$2]]\".",
+"articleexists" => "Paĝo kun tiu nomo jam ekzistas, aŭ la nomo kiun vi elektis ne validas.
+Bonvolu elekti alian nomon.",
+"talkexists"   => "Oni ja sukcesis movi la paĝon mem, sed
+ne movis la diskuto-paĝon ĉar jam ekzistas tia ĉe la nova titolo.
+Bonvolu permane kunigi ilin.",
+"movedto"              => "movis al",
+"movetalk"             => "Movu ankaŭ la \"diskuto\"-paĝon, se ĝi ekzistas.",
+"talkpagemoved" => "Ankaŭ la diskutpaĝo estas movita.",
+"talkpagenotmoved" => "La diskutpaĝo <strong>ne</strong> estas movita."
+
+);
+
+
+class LanguageEo extends Language {
+
+       function getDefaultUserOptions () {
+               $opt = Language::getDefaultUserOptions();
+               $opt["altencoding"] = 0;
+               $opt["skin"] = 2;
+               return $opt;
+       }
+
+       function getNamespaces() {
+               global $wgNamespaceNamesEo;
+               return $wgNamespaceNamesEo;
+       }
+
+       function getNsText( $index ) {
+               global $wgNamespaceNamesEo;
+               return $wgNamespaceNamesEo[$index];
+       }
+
+       function getNsIndex( $text ) {
+               global $wgNamespaceNamesEo;
+
+               foreach ( $wgNamespaceNamesEo as $i => $n ) {
+                       if ( 0 == strcasecmp( $n, $text ) ) { return $i; }
+               }
+               if( 0 == strcasecmp( "Special", $text ) ) return -1;
+               if( 0 == strcasecmp( "Wikipedia", $text ) ) return 4;
+               return false;
+       }
+
+       function specialPage( $name ) {
+               return $this->getNsText( Namespace::getSpecial() ) . ":" . $name;
+       }
+
+       function getQuickbarSettings() {
+               global $wgQuickbarSettingsEo;
+               return $wgQuickbarSettingsEo;
+       }
+
+       function getSkinNames() {
+               global $wgSkinNamesEo;
+               return $wgSkinNamesEo;
+       }
+
+       function getMathNames() {
+               global $wgMathNamesEo;
+               return $wgMathNamesEo;
+       }
+
+       function getUserToggles() {
+               global $wgUserTogglesEo;
+               return $wgUserTogglesEo;
+       }
+
+       function getLanguageName( $code ) {
+               global $wgLanguageNamesEo;
+               if ( ! array_key_exists( $code, $wgLanguageNamesEo ) ) {
+                       return "";
+               }
+               return $wgLanguageNamesEo[$code];
+       }
+
+       function getMonthName( $key )
+       {
+               global $wgMonthNamesEo;
+               return $wgMonthNamesEo[$key-1];
+       }
+
+       function getMonthAbbreviation( $key )
+       {
+               global $wgMonthAbbreviationsEo;
+               return $wgMonthAbbreviationsEo[$key-1];
+       }
+
+       function getWeekdayName( $key )
+       {
+               global $wgWeekdayNamesEo;
+               return $wgWeekdayNamesEo[$key-1];
+       }
+
+       # Heredu userAdjust()
+       # La dato- kaj tempo-funkciojn oni povas precizigi laŭ lingvo
+       function date( $ts, $adj = false )
+       {
+               if ( $adj ) { $ts = $this->userAdjust( $ts ); }
+
+               $d = (0 + substr( $ts, 6, 2 )) . ". " .
+               $this->getMonthAbbreviation( substr( $ts, 4, 2 ) ) .
+                 " " . 
+                 substr( $ts, 0, 4 );
+               return $d;
+       }
+
+       function time( $ts, $adj = false )
+       {
+               if ( $adj ) { $ts = $this->userAdjust( $ts ); }
+
+               $t = substr( $ts, 8, 2 ) . ":" . substr( $ts, 10, 2 );
+               return $t;
+       }
+
+       function timeanddate( $ts, $adj = false )
+       {
+               return $this->time( $ts, $adj ) . ", " . $this->date( $ts, $adj );
+       }
+
+       # Heredu rfs1123()
+
+       function getValidSpecialPages()
+       {
+               global $wgValidSpecialPagesEo;
+               return $wgValidSpecialPagesEo;
+       }
+
+       function getSysopSpecialPages()
+       {
+               global $wgSysopSpecialPagesEo;
+               return $wgSysopSpecialPagesEo;
+       }
+
+       function getDeveloperSpecialPages()
+       {
+               global $wgDeveloperSpecialPagesEo;
+               return $wgDeveloperSpecialPagesEo;
+       }
+
+       function getMessage( $key )
+       {
+               global $wgAllMessagesEo;
+               if(array_key_exists($key, $wgAllMessagesEo))
+                       return $wgAllMessagesEo[$key];
+               else
+                       return Language::getMessage($key);
+       }
+
+       function iconv( $in, $out, $string ) {
+               # For most languages, this is a wrapper for iconv
+               # Por multaj lingvoj, ĉi tiu nur voku la sisteman funkcion iconv()
+               # Ni ankaŭ konvertu X-sistemajn surogotajn
+               if( strcasecmp( $in, "x" ) == 0 and strcasecmp( $out, "utf-8" ) == 0) {
+                       $xu = array (
+                               "xx" => "x" , "xX" => "x" ,
+                               "Xx" => "X" , "XX" => "X" ,
+                               "Cx" => "\xc4\x88" , "CX" => "\xc4\x88" ,
+                               "cx" => "\xc4\x89" , "cX" => "\xc4\x89" ,
+                               "Gx" => "\xc4\x9c" , "GX" => "\xc4\x9c" ,
+                               "gx" => "\xc4\x9d" , "gX" => "\xc4\x9d" ,
+                               "Hx" => "\xc4\xa4" , "HX" => "\xc4\xa4" ,
+                               "hx" => "\xc4\xa5" , "hX" => "\xc4\xa5" ,
+                               "Jx" => "\xc4\xb4" , "JX" => "\xc4\xb4" ,
+                               "jx" => "\xc4\xb5" , "jX" => "\xc4\xb5" ,
+                               "Sx" => "\xc5\x9c" , "SX" => "\xc5\x9c" ,
+                               "sx" => "\xc5\x9d" , "sX" => "\xc5\x9d" ,
+                               "Ux" => "\xc5\xac" , "UX" => "\xc5\xac" ,
+                               "ux" => "\xc5\xad" , "uX" => "\xc5\xad"
+                               ) ;
+                       return preg_replace ( '/([cghjsu]x?)((?:xx)*)(?!x)/ei',
+                         'strtr( "$1", $xu ) . strtr( "$2", $xu )', $string );
+               } else if( strcasecmp( $in, "UTF-8" ) == 0 and strcasecmp( $out, "x" ) == 0 ) {
+                       $ux = array (
+                               "x" => "xx" , "X" => "Xx" ,
+                               "\xc4\x88" => "Cx" , "\xc4\x89" => "cx" ,
+                               "\xc4\x9c" => "Gx" , "\xc4\x9d" => "gx" ,
+                               "\xc4\xa4" => "Hx" , "\xc4\xa5" => "hx" ,
+                               "\xc4\xb4" => "Jx" , "\xc4\xb5" => "jx" ,
+                               "\xc5\x9c" => "Sx" , "\xc5\x9d" => "sx" ,
+                               "\xc5\xac" => "Ux" , "\xc5\xad" => "ux"
+                       ) ;
+                       # Double Xs only if they follow cxapelutaj literoj.
+                       return preg_replace( '/((?:[cghjsu]|\xc4[\x88\x89\x9c\x9d\xa4\xa5\xb4\xb5]'.
+                         '|\xc5[\x9c\x9d\xac\xad])x*)/ei', 'strtr( "$1", $ux )', $string );
+               }
+               return iconv( $in, $out, $string );
+       }
+       
+       function ucfirst( $string ) {
+               # For most languages, this is a wrapper for ucfirst()
+               # But that doesn't work right in a UTF-8 locale
+               global $wikiUpperChars, $wikiLowerChars;
+        return preg_replace (
+               '/^([\x00-\x7f]|[\xc0-\xff][\x80-\xbf]*)/e',
+               'strtr ( "$1" , $wikiUpperChars )',
+               $string );
+       }
+       
+       function stripForSearch( $string ) {
+               # MySQL fulltext index doesn't grok utf-8, so we
+               # need to fold cases and convert to hex
+               global $wikiLowerChars;
+               return preg_replace(
+                 "/([\xc0-\xff][\x80-\xbf]*)/e",
+                 "'U8' . bin2hex( strtr( \"\$1\", \$wikiLowerChars ) )",
+                 $string );
+       }
+
+       function checkTitleEncoding( $s ) {
+               global $wgInputEncoding;
+               
+               # Check for X-system backwards-compatibility URLs
+               $ishigh = preg_match( '/[\x80-\xff]/', $s);
+               $isutf = preg_match( '/^([\x00-\x7f]|[\xc0-\xdf][\x80-\xbf]|' .
+                       '[\xe0-\xef][\x80-\xbf]{2}|[\xf0-\xf7][\x80-\xbf]{3})+$/', $s );
+               
+               if($ishigh and !$isutf) {
+                       # Assume Latin1
+                       $s = utf8_encode( $s );
+               } else {
+                       if( preg_match( '/(\xc4[\x88\x89\x9c\x9d\xa4\xa5\xb4\xb5]'.
+                               '|\xc5[\x9c\x9d\xac\xad])/', $s ) )
+                       return $s;
+               }
+
+               if( preg_match( '/[cghjsu]x/i', $s ) )
+                       return $this->iconv( "x", "utf-8", $s );
+               return $s;
+       }
+
+       function setAltEncoding() {
+               global $wgEditEncoding, $wgInputEncoding, $wgOutputEncoding;
+               $wgInputEncoding = "utf-8";
+               $wgOutputEncoding = "x";
+               $wgEditEncoding = "";
+       }
+
+}
+
+?>
\ No newline at end of file
diff --git a/languages/LanguageEs.php b/languages/LanguageEs.php
new file mode 100644 (file)
index 0000000..3c73465
--- /dev/null
@@ -0,0 +1,1137 @@
+<?
+
+# The names of the namespaces can be set here, but the numbers
+# are magical, so don't change or move them!  The Namespace class
+# encapsulates some of the magic-ness.
+#
+/* private */ $wgNamespaceNamesEs = array(
+       -1      => "Especial",
+       0       => "",
+       1       => "Discusión",
+       2       => "Usuario",
+       3       => "Usuario_Discusión",
+       4       => "Wikipedia",
+       5       => "Wikipedia_Discusión",
+       6       => "Imagen",
+       7       => "Imagen_Discusión"
+);
+
+/* Note that some default options can be customized -- see
+   '$wgDefaultUserOptionsEn' in Language.php */
+
+/* private */ $wgQuickbarSettingsEs = array(
+       "Ninguna", "Fija a la derecha", "Fija a la izquierda", "Flotante a la izquierda"
+);
+
+/* private */ $wgSkinNamesEs = array(
+       "Standard", "Nostalgia", "Cologne Blue"
+);
+
+/* private */ $wgMathNamesEs = array(
+       "Producir siempre PNG",
+       "HTML si es muy simple, si no PNG",
+       "HTML si es posible,si no PNG",
+       "Dejar como TeX (para navegadores de texto)"
+);
+
+/* private */ $wgUserTogglesEs = array(
+       "hover"         => "Mostrar caja flotante sobre los enlaces wiki",
+       "underline" => "Subrayar enlaces",
+       "highlightbroken" => "Destacar enlaces a tópicos vacíos",
+       "justify"       => "Ajustar párrafos",
+       "hideminor" => "Esconder ediciones menores en cambios recientes",
+       "usenewrc" => "Cambios recientes realzados (no para todos los navegadores)",
+       "numberheadings" => "Auto-numerar encabezados",
+       "rememberpassword" => "Recordar la contraseña entre sesiones",
+       "editwidth" => "La caja de edición tiene el ancho máximo",
+       "editondblclick" => "Edit pages on double click (JavaScript)",
+       "watchdefault" => "Vigilar artículos nuevos y modificados",
+       "minordefault" => "Marcar todas las ediciones como menores por defecto"
+);
+
+/* Please customize this with some Spanish-language bookshops
+   and/or reference sites that can look up by ISBN number */
+/* private */ $wgBookstoreListEs = array(
+       "AddALL" => "http://www.addall.com/New/Partner.cgi?query=$1&type=ISBN",
+       "PriceSCAN" => "http://www.pricescan.com/books/bookDetail.asp?isbn=$1",
+       "Barnes & Noble" => "http://shop.barnesandnoble.com/bookSearch/isbnInquiry.asp?isbn=$1",
+       "Amazon.com" => "http://www.amazon.com/exec/obidos/ISBN=$1"
+);
+
+/* Where known, these should be native names and spellings of
+   languages, so the speakers can recognize them. */
+/* private */ $wgLanguageNamesEs = array(
+       "ab"    => "Abkhaziano",
+       "aa"    => "Afar",
+       "af"    => "Afrikaans",
+       "sq"    => "Albanés",
+       "am"    => "Amharico",
+       "ar"    => "Árabe",
+       "hy"    => "Armeno",
+       "as"    => "Assamese",
+       "ay"    => "Aymara",
+       "az"    => "Azerbaijani",
+       "ba"    => "Bashkir",
+       "eu"    => "Vasco",
+       "be"    => "Bieloruso",
+       "bn"    => "Bengalí",
+       "dz"    => "Bhutaní",
+       "bh"    => "Bihara",
+       "bi"    => "Bislama",
+       "my"    => "Burmese",
+       "km"    => "Camboyano",
+       "ca"    => "Català(Catalán)",
+       "zh"    => "Chino",
+       "co"    => "Corso",
+       "hr"    => "Croata",
+       "cs"    => "&#268;eská(Checo)",
+       "da"    => "Dansk(Danés)", # Note two different subdomains. 
+       "dk"    => "Dansk(Danés)", # 'da' is correct for the language.
+       "nl"    => "Nederlands (Holandés)",
+       "en"    => "English (Inglés)",
+       "simple" => "Inglés Simple",
+       "eo"    => "Esperanto",
+       "et"    => "Estoniano",
+       "fo"    => "Faeroese",
+       "fj"    => "Fijiés",
+       "fi"    => "Suomi (Finlandés)",
+       "fr"    => "Fran&#231;ais (Francés)",
+       "fy"    => "Frisio",
+       "gl"    => "Gallego",
+       "ka"    => "Georgiano",
+       "de"    => "Deutsch(Alemán)",
+       "el"    => "&#917;&#955;&#955;&#951;&#957;&#953;&#954;&#940; (Ellenika,Griego)",
+       "kl"    => "Groenlandés",
+       "gn"    => "Guarani",
+       "gu"    => "Gujarati",
+       "ha"    => "Hausa",
+       "he"    => "Hebreo",
+       "hi"    => "Hindi",
+       "hu"    => "Húngaro",
+       "is"    => "Islandés",
+       "id"    => "Indoneso",
+       "ia"    => "Interlingua",
+       "iu"    => "Inuktitut",
+       "ik"    => "Inupiak",
+       "ga"    => "Irlandés",
+       "it"    => "Italiano",
+       "ja"    => "&#26085;&#26412;&#35486; (Nihongo,Japonés)",
+       "jv"    => "Javanés",
+       "kn"    => "Kannada",
+       "ks"    => "Kashmiri",
+       "kk"    => "Kazakh",
+       "rw"    => "Kinyarwanda",
+       "ky"    => "Kirghiz",
+       "rn"    => "Kirundi",
+       "ko"    => "&#54620;&#44397;&#50612; (Hangukeo,Coreano)",
+       "lo"    => "Laotiano",
+       "la"    => "Latina",
+       "lv"    => "Letoniano",
+       "ln"    => "Lingala",
+       "lt"    => "Lituaniano",
+       "mk"    => "Macedoniano",
+       "mg"    => "Malagasy",
+       "ms"    => "Malay",
+       "ml"    => "Malayalam",
+       "mi"    => "Maori",
+       "mr"    => "Marathi",
+       "mo"    => "Moldavian",
+       "mn"    => "Mongolian",
+       "na"    => "Nauru",
+
+       "ne"    => "Nepali",
+       "no"    => "Noruego",
+       "oc"    => "Occitano",
+       "or"    => "Oriya",
+       "om"    => "Oromo",
+       "ps"    => "Pashto",
+       "fa"    => "Persa",
+       "pl"    => "Polaco",
+       "pt"    => "Portugués",
+       "pa"    => "Punjabi",
+       "qu"    => "Quechua",
+       "rm"    => "Rhaeto-Romance",
+       "ro"    => "Romaniano",
+       "ru"    => "Ruso",
+       "sm"    => "Samoano",
+       "sg"    => "Sangro",
+       "sa"    => "Sánscrito",
+       "sr"    => "Serbo",
+       "sh"    => "Serbocroata",
+       "st"    => "Sesotho",
+       "tn"    => "Setswana",
+       "sn"    => "Shona",
+       "sd"    => "Sindhi",
+       "si"    => "Sinhalés",
+       "ss"    => "Siswati",
+       "sk"    => "Eslovaco",
+       "sl"    => "Esloveno",
+       "so"    => "Somali",
+
+       "es"    => "Castellano",
+       "su"    => "Sudanés",
+       "sw"    => "Swahili",
+       "sv"    => "Sueco (Svensk)",
+       "tl"    => "Tagalog",
+       "tg"    => "Tajik",
+       "ta"    => "Tamil",
+       "tt"    => "Tatar",
+       "te"    => "Telugu",
+       "th"    => "Tailandés",
+       "bo"    => "Tibetano",
+       "ti"    => "Tigrinya",
+       "to"    => "Tonga",
+       "ts"    => "Tsonga",
+       "tr"    => "Turco",
+       "tk"    => "Turcomano",
+       "tw"    => "Twi",
+       "ug"    => "Uighur",
+       "uk"    => "Ucraniano",
+       "ur"    => "Urdu",
+       "uz"    => "Uzbek",
+       "vi"    => "Vietnamés",
+       "vo"    => "Volapuk",
+       "cy"    => "Galés",
+       "wo"    => "Wolof",
+       "xh"    => "Xhosa",
+       "yi"    => "Yiddish",
+       "yo"    => "Yoruba",
+       "za"    => "Zhuang",
+       "zu"    => "Zulu"
+);
+
+/* private */ $wgWeekdayNamesEs = array(
+       "Domingo", "Lunes", "Martes", "Miércoles", "Jueves",
+       "Viernes", "Sábado"
+);
+
+/* private */ $wgMonthNamesEs = array(
+       "enero", "febrero", "marzo", "abril", "mayo", "junio",
+       "julio", "agosto", "septiembre", "octubre", "noviembre",
+       "diciembre"
+);
+
+/* private */ $wgMonthAbbreviationsEs = array(
+       "ene", "feb", "mar", "abr", "may", "jun", "jul", "ago",
+       "sep", "oct", "nov", "dic"
+);
+
+# All special pages have to be listed here: a description of ""
+# will make them not show up on the "Special Pages" page, which
+# is the right thing for some of them (such as the "targeted" ones).
+#
+/* private */ $wgValidSpecialPagesEs = array(
+       "Userlogin"             => "",
+       "Userlogout"    => "",
+       "Preferences"   => "Preferencias de usuario",
+       "Watchlist"             => "Mi lista de seguimiento",
+       "Recentchanges" => "Cambio Recientes",
+       "Upload"                => "Subir una imagen",
+       "Imagelist"             => "Lista de imágenes",
+       "Listusers"             => "Usuarios registrados",
+       "Statistics"    => "Estadísticas del sitio",
+       "Randompage"    => "Artículo aleatorio",
+
+       "Lonelypages"   => "Artículos huérfanos",
+       "Unusedimages"  => "Imágenes huérfanas",
+       "Popularpages"  => "Artículos populares",
+       "Wantedpages"   => "Artículos más solicitados",
+       "Shortpages"    => "Artículos cortos",
+       "Longpages"             => "Artículos largos",
+       "Newpages"              => "Artículos nuevos",
+       "Allpages"              => "Todas las páginas (alfabético)",
+
+       "Ipblocklist"   => "Direcciones IP bloqueadas",
+       "Maintenance"   => "Página de mantención",
+       "Specialpages"  => "",
+       "Contributions" => "",
+       "Emailuser"     => "",
+       "Whatlinkshere" => "",
+       "Recentchangeslinked" => "",
+       "Movepage"              => "",
+       "Booksources"   => "Fuentes externas de libros"
+);
+
+/* private */ $wgSysopSpecialPagesEs = array(
+       "Blockip"               => "Bloquear una dirección IP",
+       "Asksql"                => "Búsqueda en la base de datos",
+       "Undelete"      => "Ver y restaurar páginas borradas"
+);
+
+/* private */ $wgDeveloperSpecialPagesEs = array(
+       "Lockdb"                => "Cerrar acceso de escritura a la base de datos",
+       "Unlockdb"              => "Restaurar acceso de escritura a la base de datos",
+       "Debug"                 => "Debugging information"
+);
+
+/* private */ $wgAllMessagesEs = array(
+
+# Bits of text used by many pages:
+#
+"linktrail"     => "/^([a-záéíóúñ]+)(.*)\$/sD",
+"mainpage"             => "Portada",
+"about"                        => "Acerca de",
+"aboutwikipedia" => "Acerca de Wikipedia",
+"aboutpage"            => "Wikipedia:Acerca de",
+"help"                 => "Ayuda",
+"helppage"             => "Wikipedia:Ayuda",
+"wikititlesuffix"              =>"Wikipedia",
+"bugreports"   => "Reportes de error de software",
+"bugreportspage" => "Wikipedia:Reportes_de_error",
+"faq"                  => "FAQ",
+"faqpage"              => "Wikipedia:FAQ",
+"edithelp"             => "Ayuda de edición",
+"edithelppage" => "Wikipedia:Cómo_se_edita_una_página",
+"cancel"               => "Cancelar",
+"qbfind"               => "Encontrar",
+"qbbrowse"             => "Hojear",
+"qbedit"               => "Editar",
+"qbpageoptions" => "Opciones de página",
+"qbpageinfo"   => "Información de página",
+"qbmyoptions"  => "Mis opciones",
+"mypage"               => "Mi página",
+"mytalk"        => "Mi discusión",
+"currentevents" => "Actualidad",
+"errorpagetitle" => "Error",
+"returnto"             => "Regresa a $1.",
+"fromwikipedia"        => "De Wikipedia, la enciclopedia libre.",
+"whatlinkshere"        => "Páginas que enlazan aquí",
+"help"                 => "Ayuda",
+"search"               => "Buscar",
+"history"              => "Historia",
+"printableversion" => "Versión para imprimir",
+"editthispage" => "Edita esta página",
+"deletethispage" => "Borra esta página",
+"protectthispage" => "Proteje esta página",
+"unprotectthispage" => "Desproteje esta página",
+"talkpage"             => "Discute esta página",
+"articlepage"   => "Ver artículo",
+"subjectpage"  => "Artículo",
+"userpage" => "Ver página de usuario",
+"wikipediapage" => "Ver página meta",
+"imagepage" =>         "Ver página de imagen",
+"otherlanguages" => "Otros idiomas",
+"redirectedfrom" => "(Redirigido desde $1)",
+"lastmodified" => "Esta página fue modificada por última vez el $1.",
+"viewcount"            => "Esta página ha sido visitada $1 veces.",
+"gnunote" => "Esta página se hace disponible bajo la <a class=internal href='/wiki/GNU_FDL'>GNU FDL</a>.",
+"printsubtitle" => "(De http://es.wikipedia.org)",
+"protectedpage" => "Página protegida",
+"administrators" => "Wikipedia:Administradores",
+"sysoptitle"   => "Acceso de Sysop requerido",
+"sysoptext"            => "La acción que has requerido sólo puede ser llevada a cabo
+ por usuarios con status de \"sysop\".
+Ver $1.",
+"developertitle" => "Acceso de developer requerido",
+"developertext"        => "La acción que has requerido sólo puede ser llevada a cabo 
+por usuarios con status de \"developer\".
+Ver $1.",
+"nbytes"               => "$1 bytes",
+"go"                   => "Ir",
+"ok"                   => "OK",
+"sitetitle"            => "Wikipedia",
+"sitesubtitle" => "La Enciclopedia Libre",
+"retrievedfrom" => "Obtenido de \"$1\"",
+
+# Main script and global functions
+#
+"nosuchaction" => "No existe tal acción",
+"nosuchactiontext" => "La acción especificada por el URL no es
+ reconocida por el software de Wikipedia",
+"nosuchspecialpage" => "No existe esa página especial",
+"nospecialpagetext" => "Has requerido una página especial que no es
+ reconocida por el software de Wikipedia.",
+
+# General errors
+#
+"error"                        => "Error",
+"databaseerror" => "Error de la base de datos",
+"dberrortext"  => "Ha ocurrido un error de sintaxis en una consulta
+a la base de datos. 
+Esto puede ser debido a una búsqueda ilegal (ver $5),
+o puede indicar un error en el software.
+La última consulta que se intentó fue:
+<blockquote><tt>$1</tt></blockquote>El error de retorno de 
+MySQL fue\"<tt>$3: $4</tt>\".",
+"noconnect"            => "No se pudo conectar a la base de datos en $1",
+"nodb"                 => "No se pudo seleccionar la base de datos$1",
+"readonly"             => "Base de datos bloqueada",
+"enterlockreason" => "Enter a reason for the lock, including an estimate
+of when the lock will be released",
+"readonlytext" => "La base de datos de Wikipedia está temporalmente
+bloqueda para nuevas entradas u otras modificaciones, probablemenete
+pare mantención de rutina, después de lo cual volverá a la normalidad.
+El administrador que la bloqueó ofreció esta explicación:
+<p>$1",
+"missingarticle" => "La base de datos no encontró el texto de una
+página que debería haber encontrado, llamada \"$1\".
+Esto no es un error de la base de datos, sino más probablemente
+un error en el software. Por favor, reporte esto a un administrador,
+notando el URL.",
+"internalerror" => "Error interno",
+"filecopyerror" => "No se pudo copiar el archivo \"$1\" a \"$2\".",
+"filerenameerror" => "No se pudo renombrar el archivo \"$1\" a \"$2\".",
+"filedeleteerror" => "No se pudo borrar el archivo \"$1\".",
+"filenotfound" => "No se pudo encontrar el archivo \"$1\".",
+"unexpected"   => "Valor no esperado: \"$1\"=\"$2\".",
+"formerror"            => "Error: no se pudo submitir la forma",       
+"badarticleerror" => "Esta acción no se puede llevar a cabo en esta página.",
+"cannotdelete" => "No se pudo borrar la página o imagen especificada.(Puede haber sido borrada por alguien antes)",
+"badtitle"             => "T&iacute;tulo incorrecto",
+"badtitletext" => "El t&iacute;tulo de la página requerida era inválido, vac&iacute;o, o un enlace interleguaje o interwiki incorrecto.",
+
+"perfdisabled" => "Lo siento, esta funcion esta temporalmente desactivada",
+
+# Login and logout pages&iacute;tulo
+"logouttitle"  => "Fin de sesión",
+"logouttext"   => "Has terminado tu sesión.
+Puedes continuar usando Wikipedia en forma anónima, o puedes
+iniciar sesión otra vez  como el mismo u otro usuario.\n",
+
+"welcomecreation" => "<h2>Bienvenido(a), $1!</h2><p>Tu cuenta ha sido creada.
+No olvides perzonalizar tus preferencia de Wikipedia.",
+
+"loginpagetitle" => "Registrarse/Entrar",
+"yourname"             => "Tu nombre de usuario",
+"yourpassword" => "Tu contraseña",
+"yourpasswordagain" => "Repite tu contraseña",
+"newusersonly" => " (sólo usuarios nuevos)",
+"remembermypassword" => "Quiero que recuerden mi contraseña entre sesiones.",
+"loginproblem" => "<b>Hubo un problema con tu entrada.</b><br>¡Trata otra vez!",
+"alreadyloggedin" => "<font color=red><b>Usuario $1, ya entraste!</b></font><br>\n",
+
+"areyounew"            => "Si eres nuevo en Wikipedia en Español, y
+quieres tener una cuenta de usuario, ingresa un nombre de usuario,
+y tipea y repite una contraseña.
+Tu dirección electrónica es opcional: si pierdes u olvidas tu
+contraseña, puedes pedir que se envíe a la dirección que des.  <br>\n",
+"login"                        => "Registrase/Entrar",
+"userlogin"            => "Registrase/Entrar",
+"logout"               => "Salir",
+"userlogout"   => "Salir",
+"createaccount"        => "Crea una nueva cuenta",
+"badretype"            => "Las contraseñas que ingresaste no concuerdan.",
+"userexists"   => "El nombre que entraste ya está en uso. Por favor, elije un nombre diferente.",
+"youremail"            => "Tu dirección electrónica (e-mail)",
+"yournick"             => "Tu apodo (para firmas)",
+"emailforlost" => "Si pierdes u olvidas tu contraseña, puedes pedir que se envíe una nueva a tu dirección electrónica.", 
+"loginerror"   => "Error de inicio de sesión",
+"noname"               => "No has especificado un nombre de usuario válido.",
+"loginsuccesstitle" => "Inicio de sesión exitoso",
+"loginsuccess" => "Has iniciado tu sesión en Wikipedia como \"$1\".",
+"nosuchuser"   => "No existe usuario alguno llamado \"$1\".
+Revisa tu deletreo, o usa la forma abajo para crear una nueva cuenta de usuario.",
+"wrongpassword"        => "La contraseña que ingresaste es incorrecta. Por favor trata otra vez.",
+"mailmypassword" => "Envíame una nueva contraseña por correo electrónico",
+"passwordremindertitle" => "Recordatorio de contraseña de Wikipedia",
+"passwordremindertext" => "Alguien (probablemente tú , desde la direccion IP $1)
+solicitó que te enviaramos una nueva contraseña para iniciar sesión en Wikipedia.
+La contraseña para el usuario \"$2\" es ahora \"$3\".
+Ahora deberías iniciar sesion y cambiar tu contraseña.",
+"noemail"              => "No hay dirección electrónica (e-mail) registrada para el(la) usuario(a) \"$1\".",
+"passwordsent" => "Una nueva contraseña ha sido enviada a la dirección electrónica
+registrada para \"$1\".
+Por favor entra otra vez después de que la recibas.",
+
+# Edit pages
+#
+"summary"              => "Resumen",
+"minoredit"            => "Esta es una edición menor.",
+"watchthis"            => "Vigila este artículo.",
+"savearticle"  => "Grabar la página",
+"preview"              => "Previsualizar",
+"showpreview"  => "Mostrar previsualización",
+"blockedtitle" => "El usuario está bloqueado",
+"blockedtext"  => "Tu nombre de usuario o dirección IP ha sido bloqueada por $1.
+La razón dada es la que sigue:<br>$2<p>Puedes contactar al administrador para
+discutir el bloqueo.",
+"newarticle"   => "(Nuevo)",
+"newarticletext" => "Pon tu texto para la nueva página aquí.",
+"noarticletext" => "(En este momento no hay texto en esta página)",
+"updated"              => "(Actualizado)",
+"note"                 => "<strong>Nota:</strong> ",
+"previewnote"  => "Recuerda que esto es sólo una previsualización, y no ha sido grabada todavía!",
+"previewconflict" => "Esta previsualización refleja el texto en el área
+de edición superior como aparecerá si eliges grabar.",
+"editing"              => "Editando $1",
+"editconflict" => "Conflicto de edición: $1",
+"explainconflict" => "Alguien más ha cambiado esta página desde que empezaste
+a editarla. 
+El área de texto superior contiene el texto de la página como existe
+actualmente. Tus cambios se muestran en el área de texto inferior.
+Vas a tener que incorporar tus cambio en el texto existente.
+<b>Sólo</b> el texto en el área de texto superior será grabado cuando presiones
+ \"Grabar pagina\".\n<p>",
+"yourtext"             => "Tu texto",
+"storedversion" => "Versión almacenada",
+"editingold"   => "<strong>ADVERTENCIA:Estás editando una versión antigua
+ de esta página.
+Si la grabas, los cambios hechos desde esa revisión se perderán.</strong>\n",
+"yourdiff"             => "Diferencias",
+"copyrightwarning" => "Nota por favor que todas las contribuciones a Wikipedia 
+se consideran hechas públicas bajo la Licencia de Documentación Libre GNU 
+(ver detalles en $1). 
+ Si no deseas que la gente corrija tus escritos sin piedad 
+y los distribuya libremente, entonces no los pongas aquí. <br>
+También tú nos aseguras que escribiste esto tú mismo y 
+eres dueño de los derechos de autor, o lo copiaste desde el dominio público 
+u otra fuente libre.
+ <strong>NO USES ESCRITOS CON COPYRIGHT SIN PERMISO!</strong><br>
+áéíóúÁÉÍÓÚüÜñÑ¡¿",
+
+# History pages
+#
+"revhistory"   => "Historia de revisiones",
+"nohistory"            => "No hay una historia de ediciones para esta página.",
+"revnotfound"  => "Revisión no encontrada",
+"revnotfoundtext" => "La revisión antigua de la página por la que preguntaste no se pudo encontrar.
+Por favor revisa el URL que usaste para acceder a esta página.\n",
+"loadhist"             => "Recuperando la historia de la página",
+"currentrev"   => "Revisión actual",
+"revisionasof" => "Revisión de $1",
+"cur"                  => "act",
+"next"                 => "sig",
+"last"                 => "prev",
+"orig"                 => "orig",
+"histlegend"   => "Simbología: (act) = diferencia con la versión actual,
+(prev) = diferencia con la versión previa, M = edición menor",
+
+# Diffs
+#
+"difference"   => "(Diferencia entre revisiones)",
+"loadingrev"   => "recuperando revisión para diff",
+"lineno"               => "Línea $1:",
+"editcurrent"  => "Edita la versión actual de esta página",
+
+# Search results
+#
+"searchresults" => "Resultados de búsqueda",
+"searchhelppage" => "Wikipedia:Búsqueda",
+"searchingwikipedia" => "Buscando en Wikipedia",
+"searchresulttext" => "Para más información acerca de búsquedas en Wikipedia, ve $1.",
+"searchquery"  => "Para consulta \"$1\"",
+"badquery"             => "Consulta de búsqueda formateada en forma incorrecta",
+"badquerytext" => "No pudimos procesar tu búsqueda.
+Esto es probablemente porque intentaste buscar una palabra de menos de tres letras, lo que todavía no es posible.
+También puede ser que hayas cometido un error de tipeo en la expresión.
+Por favor, trata una búsqueda diferente.",
+"matchtotals"  => "La consulta \"$1\" coincidió con $2  títulos de artículos
+y el texto de $3 artículos.",
+"titlematches" => "Coincidencias de título de artículo",
+"notitlematches" => "No hay coincidencias de título de artículo",
+"textmatches"  => "Coincidencias de texto de artículo",
+"notextmatches"        => "No hay coincidencias de texto de artículo",
+"prevn"                        => "$1 previos",
+"nextn"                        => "$1 siguientes",
+"viewprevnext" => "Ve ($1) ($2) ($3).",
+"showingresults" => "Mostrando abajo <b>$1</b> resultados empezando con #<b>$2</b>.",
+"nonefound"            => "<strong>Nota</strong>: búsquedas no exitosas son causadas a menudo
+por búsquedas de palabras comunes como \"la\" o \"de\",
+que no están en el índice, o por especificar más de una palabra para buscar( sólo páginas
+que contienen todos los términos de una búsqueda aparecerán en el resultado).",
+"powersearch" => "Búsqueda",
+"powersearchtext" => "
+Buscar en espacios de nombre :<br>
+$1<br>
+$2 Listar redirecciones &nbsp; Buscar $3 $9",
+
+# Preferences page
+#
+"preferences"  => "Preferencias",
+"prefsnologin" => "No has entrado",
+"prefsnologintext"     => "Debes haber <a href=\"" .
+  wfLocalUrl( "Especial:Userlogin" ) . "\">entrado</a>
+para seleccionar preferencias de usuario.",
+"prefslogintext" => "Has entrado con el nombre \"$1\".
+Tu número de identificación interno es $2.",
+"prefsreset"   => "Las preferencias han sido repuestas desde almacenaje.",
+"qbsettings"   => "Preferencias de \"Quickbar\"", 
+"changepassword" => "Cambia contraseña",
+"skin"                 => "Piel",
+"math"                 => "Cómo se muestran las fórmulas",
+"math_failure"         => "No se pudo entender",
+"math_unknown_error"   => "error desconocido",
+"math_unknown_function"        => "función desconocida",
+"math_lexing_error"    => "error de léxico",
+"math_syntax_error"    => "error de sintaxis",
+"saveprefs"            => "Grabar preferencias",
+"resetprefs"   => "Volver a preferencias por defecto",
+"oldpassword"  => "Contraseña antigua",
+"newpassword"  => "Contraseña nueva",
+"retypenew"            => "Reescriba la nueva contraseña",
+"textboxsize"  => "Dimensiones de la caja de texto",
+"rows"                 => "Filas",
+"columns"              => "Columnas",
+"searchresultshead" => "Preferencias de resultado de búsqueda",
+"resultsperpage" => "Resultados para mostrar por página",
+"contextlines" => "Líneas para mostrar por resultado",
+"contextchars" => "Caracteres de contexto por línea",
+"stubthreshold" => "Umbral de artículo mínimo" ,
+"recentchangescount" => "Número de títulos en cambios recientes",
+"savedprefs"   => "Tus preferencias han sido grabadas.",
+"timezonetext" => "Entra el número de horas de diferencia entre tu hora local
+y la hora del servidor (UTC).",
+"localtime"    => "Hora local",
+"timezoneoffset" => "Diferencia",
+"emailflag"     => "No quiero recibir correo electrónico de otros usuarios",
+
+# Recent changes
+#
+"recentchanges" => "Cambios Recientes",
+"recentchangestext" => "Sigue los cambios más recientes a Wikipedia en esta página.
+[[Wikipedia:Bienvenidos|Bienvenidos]]!
+Por favor, mira estas páginas: [[wikipedia:FAQ|Wikipedia FAQ]],
+[[Wikipedia:Políticas y guías|políticas de Wikipedia]]
+(especialmente [[wikipedia:Convenciones de nombres|las convenciones para nombrar artículos]]y
+[[wikipedia:Punto de vista neutral|punto de vista neutral]]).
+
+Si quieres que Wikipedia tenga éxito, es muy importante que no agregues
+material restringido por [[wikipedia:Copyrights|derechos de autor]].
+La responsabilidad legal realmente podría dañar  el proyecto, así que por favor no lo hagas.
+
+Ve también [http://meta.wikipedia.org/wiki/Special:Recentchanges discusión reciente en Meta (multilingüe)].",
+"rcloaderr"            => "cargando cambios recientes",
+"rcnote"               => "Abajo están los últimos <b>$1</b> cambios en los últimos <b>$2</b> días.",
+"rclistfrom"   => "Mostrar cambios nuevos desde $1",
+"rcnotefrom"   => "Abajo están los cambios desde <b>$2</b> (se muestran hasta <b>$1</b>).",
+"rclinks"              => "Ve los últimos $1 cambios en los últimos $2 días.",
+"rchide"               => "en forma $4 ; $1 ediciones menores; $2 espacios de nombre secundarios; $3 ediciones múltiples.",
+"diff"                 => "diferencias",
+"hist"                 => "historia",
+"hide"                 => "esconder",
+"show"                 => "mostrar",
+"tableform"     => "tabla",
+"listform"             => "lista",
+"nchanges"             => "$1 cambios",
+"minoreditletter" => "M",
+"newpageletter" => "N",
+
+# Upload
+#
+"upload"               => "Subir",
+"uploadbtn"            => "Subir un archivo",
+
+"uploadlink"   => "Subir imágenes",
+"reupload"             => "Subir otra vez",
+"reuploaddesc" => "Regresar al formulario para subir.",
+"uploadnologin" => "No ha iniciado sesión",
+"uploadnologintext"    => "Tú debes haber <a href=\"" .
+  wfLocalUrl( "Especial:Userlogin" ) . "\">entrado</a>
+para subir archivos.",
+"uploadfile"   => "Subir archivo",
+"uploaderror"  => "Error tratando de subir",
+"uploadtext"   => "Para ver o buscar imágenes que se hayan subido
+previamente, ve a la <a href=\"" . wfLocalUrlE( "Especial:Imagelist" ) .
+"\">lista de imágenes subidas</a>.
+Subidas y borrados son registrados en el <a href=\"" .
+wfLocalUrlE( "Wikipedia:Registro de subidas" ) . "\">registro de subidas</a>.
+Ve también la <a href=\"" . wfLocalUrlE( "Wikipedia:Política de uso de imágenes" ) .
+"\">política de uso de imágenes</a>.
+<p>Usa la forma abajo para subir nuevos archivos de imágenes que
+vas a usar ilustrando tus artículos.
+En la mayoría de los navegadores, verás un botón \"Browse...\", que
+traerá el diálogo de selección de archivos estándar en tu sistema operativo.
+Cuando elijas un archivo el nombre de ese archivo aparecerá en el campo de texto
+al lado del botón.
+También debes marcar la caja afirmando que no estás
+violando ningún copyright al subir el archivo.
+Presiona el boton \"Subir\" para completar la subida.
+Esto puede tomar algún tiempo si tienes una conección a internet lenta.
+<p>Los formatos preferidos son JPEG para imágenes fotográficas, PNG
+para dibujos y otras imágenes icónicas, y OGG para sonidos.
+Por favor, dale a tus archivos nombres descriptivos para evitar confusión.
+Para incluir la imagen en un artículo, usa un enlace de la forma
+<b>[[imagen:archivo.jpg]]</b> o <b>[[imagen:archivo.png|alt text]]</b>
+o <b>[[media:archivo.ogg]]</b> para sonidos.
+<p>Por favor nota que, al igual que con páginas Wikipedia, otros pueden
+editar o borrar los archivos que has subido si piensan que es bueno para
+la enciclopedia, y se te puede bloquear, impidiéndote subir archivos si abusas del sistema.",
+"uploadlog"            => "registro de subidas",
+"uploadlogpage" => "Registro_de_subidas",
+"uploadlogpagetext" => "Abajo hay una lista de los archivos que se han
+subido más recientemente. Todas las horas son del servidor (UTC).
+<ul>
+</ul>
+",
+"filename"             => "Nombre del archivo",
+"filedesc"             => "Sumario",
+"affirmation"  => "Afirmo que el dueño del copyright de este archivo
+está de acuerdo en licenciarlo bajo los términos de $1.",
+"copyrightpage" => "Wikipedia:Copyrights",
+"copyrightpagename" => "Wikipedia copyright",
+"uploadedfiles"        => "Archivos subidos",
+"noaffirmation" => "Tú debes afirmar que tus subidas de archivos no violan ningún
+copyright.",
+"ignorewarning"        => "Ignora la advertencia y graba el archivo de todos modos.",
+"minlength"            => "Los nombres de imágenes deben ser al menos tres letras.",
+"badfilename"  => "El nombre de la imagen se ha cambiado a \"$1\".",
+"badfiletype"  => "\".$1\" no es un formato de imagen recomendado.",
+"largefile"            => "Se recomienda que las imágenes no excedan 100k de tamaño.",
+"successfulupload" => "Subida exitosa",
+"fileuploaded" => "El archivo \"$1\" se subió en forma exitosa.
+Por favor sigue este enlace: ($2) a la página de descripción y llena
+la información acerca del archivo, tal como de dónde viene, cuándo fue
+creado y por quién, y cualquier otra cosa que puedas saber al respecto.",
+"uploadwarning" => "Advertencia de subida de archivo",
+"savefile"             => "Grabar archivo",
+"uploadedimage" => "\"$1\" subido.",
+
+# Image list
+#
+"imagelist"            => "Lista de imágenes",
+"imagelisttext"        => "Abajo hay una lista de $1 imágenes ordenadas $2.",
+"getimagelist" => " obteniendo la lista de imágenes",
+"ilshowmatch"  => "Muestra todas las imágenes con nombres que coincidan con",
+"ilsubmit"             => "Búsqueda",
+"showlast"             => "Mostrar las últimas $1 imágenes ordenadas  $2.",
+"all"                  => "todas",
+"byname"               => "por nombre",
+"bydate"               => "por fecha",
+"bysize"               => "por tamaño",
+"imgdelete"            => "borr",
+"imgdesc"              => "desc",
+"imglegend"            => "Simbología: (desc) = mostrar/editar la descripción de la imagen.",
+"imghistory"   => "Historia de la imagen",
+"revertimg"            => "rev",
+"deleteimg"            => "borr",
+"imghistlegend" => "Simbología: (act) = esta es la imagen actual, (borr) = borrar
+esta versión antigua, (rev) = revertir a esta versión antigua.
+<br><i>Click en la fecha para ver imagen subida en esa fecha</i>.",
+"imagelinks"   => "Enlaces a la imagen",
+"linkstoimage" => "Las siguientes páginas enlazan a esta imagen:",
+"nolinkstoimage" => "No hay páginas que enlacen a esta imagen.",
+
+# Statistics
+#
+"statistics"   => "Estadísticas",
+"sitestats"            => "Estadísticas del sitio",
+"userstats"            => "Estadísticas de usuario",
+"sitestatstext" => "Hay un total de <b>$1</b> páginas en la base de datos.
+Esto incluye páginas de discusión, páginas acerca de Wikipedia, páginas mínimas,
+redirecciones, y otras que probablemente no califican como artículos.
+Excluyendo aquellas, hay <b>$2</b> páginas que probablemente son artículos legítimos.<p>
+Ha habido un total de <b>$3</b> visitas a páginas, y <b>$4</b> ediciones de página
+desde que el software fue actualizado (Octubre 2002).
+Esto resulta en un promedio de <b>$5</b> ediciones por página, 
+y <b>$6</b> visitas por edición.",
+"userstatstext" => "Hay <b>$1</b> usuarios registrados.
+de los cuales <b>$2</b> son administradores (ver $3).",
+
+# Maintenance Page
+#
+"maintenance"          => "Página de mantención",
+"maintnancepagetext"   => "Esta página incluye varias herramientas utiles para mantención diaria. Algunas de estas funciones tienden a sobrecargar la base de datos, asi que, por favor, no vuelvas a cargar la página despues de cada item que arregles ;-)",
+"maintenancebacklink"  => "De vuelta a la Página de mantención",
+"disambiguations"      => "Páginas de desambiguación",
+"disambiguationspage"  => "Wikipedia:Enlaces a páginas de desambiguación",
+"disambiguationstext"  => "Los siguientes articulos enlazan a una<i>página de desambiguación</i>. Deberían enlazar al tópico apropiado.<br>Una página es considerada una página de desambiguación si es enlazada desde $1.<br>Enlaces desde otros espacios de nombre (Como Wikipedia: o usuario:) <i>no</i> son  listados aquí.",
+"doubleredirects"      => "Redirecciones Dobles",
+"doubleredirectstext"  => "<b>Atención:</b> Esta lista puede contener falsos positivos. Eso significa usualmente que hay texto adicional con enlaces bajo el primer #REDIRECT.<br>\nCada fila continen enlaces al segundo y tercer redirect, así como la primera línea del segundo redirect, lo que usualmente da el artículo \"real\", al que el primer redirect debería apuntar.",
+"selflinks"            => "Páginas con autoenlaces",
+"selflinkstext"                => "Las siguientes páginas contienen un enlace a sí mismas, lo que no es recomendado.",
+"mispeelings"       => "Páginas con faltas de ortografía",
+"mispeelingstext"               => "Las siguientes páginas contienen una falta de ortografía común, las cuales están listadas en $1. La escritura correcta puede estar dada (como esto).",
+"mispeelingspage"       => "Lista de faltas de ortografía comunes",           
+"missinglanguagelinks"  => "Enlaces Interleguaje Faltantes",
+"missinglanguagelinksbutton"    => "Encontrar los enlaces interlenguaje que faltan para",
+"missinglanguagelinkstext"      => "Estos artículos <i>no</i> enlazan a sus contrapartes en $1. <i>No</i> se muestran redirecciones y subpáginas.",
+
+
+# Miscellaneous special pages
+#
+"orphans"              => "Páginas huérfanas",
+"lonelypages"  => "Páginas huérfanas",
+"unusedimages" => "Imágenes sin uso",
+"popularpages" => "Páginas populares",
+"nviews"               => "$1 visitas",
+"wantedpages"  => "Páginas requeridas",
+"nlinks"               => "$1 enlaces",
+"allpages"             => "Todas las páginas",
+"randompage"   => "Página aleatoria",
+"shortpages"   => "Páginas cortas",
+"longpages"            => "Páginas largas",
+"listusers"            => "Lista de usuarios",
+"specialpages" => "Páginas especiales",
+"spheading"            => "Páginas especiales",
+"sysopspheading" => "Páginas especiales para uso de sysops",
+"developerspheading" => "Special pages for developer use",
+"protectpage"  => "Páginas protegidas",
+"recentchangeslinked" => "Seguimiento de enlaces",
+"rclsub"               => "(a páginas enlazadas desde \"$1\")",
+"debug"                        => "Debug",
+"newpages"             => "Páginas nuevas",
+"movethispage" => "Trasladar esta página",
+"unusedimagestext" => "<p>Por favor note que otros sitios web
+tales como otras wikipedias pueden enlazar a una imagen
+con un URL directo, y de esa manera todavía estar listada aquí
+a pesar de estar en uso activo.",
+"booksources"   => "Fuentes de libros",
+"booksourcetext" => "A continuacion hay una lista de enlaces a otros sitios que venden libros nuevos y usados, y también pueden contener información adicional acerca de los libros que estás buscando.
+Wikipedia no está afiliada con ninguno de estos negocios, y esta lista no puede ser considerada un patrocinio.",
+
+# Email this user
+#
+"mailnologin"  => "No enviar dirección",
+"mailnologintext" => "Debes haber <a href=\"" .
+
+  wfLocalUrl( "Especial:Userlogin" ) . "\">entrado</a>
+y tener una direccion electrónica válida en tus <a href=\"" .
+  wfLocalUrl( "Especial:Preferences" ) . "\">preferencias</a>
+para enviar correo electrónico a otros usuarios.",
+"emailuser"            => "Envía correo electrónico a este usuario",
+"emailpage"            => "Correo electrónico a usuario",
+"emailpagetext"        => "Si este usuario ha entrado una dirección electrónica válida en sus preferencias de usuario, la forma que sigue sirve para enviarle un mensaje.
+La dirección electrónica que entraste en tus preferencias de usuario aparecerá en el remitente, de manera que el destinatario pueda responder.",
+"noemailtitle" => "No hay dirección electrónica",
+"noemailtext"  => "Este usuario no ha especificado una dirección electrónica válida, o ha elegido no recibir correo electrónico de otros usuarios.",
+"emailfrom"            => "De",
+"emailto"              => "Para",
+"emailsubject" => "Tema",
+"emailmessage" => "Mensaje",
+"emailsend"            => "Enviar",
+"emailsent"            => "Correo electrónico enviado",
+"emailsenttext" => "Tu correo electrónico ha sido enviado.",
+
+# Watchlist
+#
+"watchlist"            => "Lista de seguimiento",
+"watchlistsub" => "(para el usuario \"$1\")",
+"nowatchlist"  => "No tienes ningún ítem en tu lista de seguimiento.",
+"watchnologin" => "No has iniciado sesión",
+"watchnologintext"     => "Debes haber <a href=\"" .
+  wfLocalUrl( "Especial:Userlogin" ) . "\">entrado</a>
+para modificar tu lista de seguimiento.",
+"addedwatch"   => "Añadido a lista de seguimiento",
+"addedwatchtext" => "La página \"$1\" ha sido añadida a tu  <a href=\"" .
+  wfLocalUrl( "Especial:Watchlist" ) . "\">lista se seguimiento</a>.
+Cambios futuros a esta página y su página de discusión asociada será listada ahí,  y la página aparecerá <b>en negritas</b> en la <a href=\"" .
+  wfLocalUrl( "Especial:Recentchanges" ) . "\">lista de cambios recientes</a> para hacerla más facil de notar.</p>
+
+<p>Cuando quieras remover la página de tu lista de seguimiento, presiona \"Dejar de vigilar\" en la barra del costado.",
+"removedwatch" => "Removida de lista de seguimiento",
+"removedwatchtext" => "La página \"$1\" ha sido removida de tu lista de seguimiento.",
+"watchthispage"        => "Vigilar esta página",
+"unwatchthispage" => "Dejar de vigilar",
+"notanarticle" => "No es un artículo",
+
+# Delete/protect/revert
+#
+"deletepage"   => "Borrar esta página",
+"confirm"              => "Confirma",
+"confirmdelete" => "Confirma el borrado",
+"deletesub"            => "(Borrando \"$1\")",
+"confirmdeletetext" => "Estás a punto de borrar una página o imagen 
+en forma permanente,
+así como toda su historia, de la base de datos.
+Por favor, confirma que realmente quieres hacer eso, que entiendes las
+consecuencias, y que lo estás haciendo de acuerdo con [[Wikipedia:Políticas]].",
+"confirmcheck" => "Sí, realmente quiero borrar esto.",
+"actioncomplete" => "Acción completa",
+"deletedtext"  => "\"$1\" ha sido borrado.
+Ve $2 para un registro de los borrados más recientes.",
+"deletedarticle" => "borrado \"$1\"",
+"dellogpage"   => "Registro_de_borrados",
+"dellogpagetext" => "Abajo hay una lista de los borrados más recientes.
+Todos los tiempos se muestran en hora del servidor (UTC).
+<ul>
+</ul>
+",
+"deletionlog"  => "registro de borrados",
+"reverted"             => "Revertido a una revisión anterior",
+"deletecomment"        => "Razon para el borrado",
+"imagereverted" => "Revertido a una versión anterior fue exitoso.",
+"rollback"             => "Revertir ediciones",
+"rollbacklink" => "Revertiy",
+"cantrollback" => "No se pueden revertir las ediciones; el último colaborador es el único autor de este artículo.",
+"revertpage"   => "Revertida a la última edición por $1",
+
+# Undelete
+"undelete" => "Restaura una página borrada",
+"undeletepage" => "Ve y restora páginas borradas",
+"undeletepagetext" => "Las siguientes páginas han sido borradas pero aún están en el archivo y pueden ser restauradas. El archivo puede ser limpiado periódicamente.",
+"undeletearticle" => "Restaurar artículo borrado",
+"undeleterevisions" => "$1 revisiones archivadas",
+"undeletehistory" => "Si tu restauras una página, todas las revisiones serán restauradas a la historia.
+Si una nueva página con el mismo nombre ha sido creada desde el borrado, las versiones restauradas aparecerán como historia anterior, y la revisión actual del la página \"viva\" no sera automáticamente reemplazada.",
+"undeleterevision" => "Revisión borrada al $1",
+"undeletebtn" => "Restaurar!",
+"undeletedarticle" => "restaurado \"$1\"",
+"undeletedtext"   => "El artículo [[$1]] ha sido restaurado exitosamente.
+Ve [[Wikipedia:Registro_de_borrados]] para una lista de borrados y restauraciones recientes.",
+
+# Contributions
+#
+"contributions"        => "Contribuciones del usuario",
+"contribsub"   => "Para $1",
+"nocontribs"   => "No se encontraron cambios que calzaran estos criterios.",
+"ucnote"               => "Abajo están los últimos <b>$1</b> cambios de este usuario en los últimos <b>$2</b> días.",
+"uclinks"              => "Ve los últimos $1 cambios; ve los últimos $2 días.",
+"uctop"                => " (arriba)" ,
+
+# What links here
+#
+"whatlinkshere"        => "Lo que enlaza aquí",
+"notargettitle" => "No hay página blanco",
+"notargettext" => "No has especificado en qué página
+llevar a cabo esta función.",
+"linklistsub"  => "(Lista de enlaces)",
+"linkshere"            => "Las siguientes páginas enlazan aquí:",
+"nolinkshere"  => "Ninguna página enlaza aquí.",
+"isredirect"   => "pagina redirigida",
+
+# Block/unblock IP
+#
+"blockip"              => "Bloqueo de direcciones IP",
+"blockiptext"  => "Usa la forma que sigue para bloquear el
+acceso de escritura desde una dirección IP específica.
+Esto debería ser hecho sólo para prevenir vandalismo, y de
+acuerdo a las [[Wikipedia:Políticas| políticas de Wikipedia]].
+Llena con una razón específica más abajo (por ejemplo, citando
+que páginas en particular estan siendo vadalizadas).",
+"ipaddress"            => "Dirección IP",
+"ipbreason"            => "Razón",
+"ipbsubmit"            => "Bloquear esta dirección",
+"badipaddress" => "La dirección IP no tiene el formato correcto.",
+"noblockreason" => "Debes dar una razón para el bloqueo.",
+"blockipsuccesssub" => "Bloqueo exitoso",
+"blockipsuccesstext" => "La direccion IP  \"$1\" ha sido bloqueada.
+<br>Ve [[Especial:Ipblocklist|lista de IP bloqueadas]] para revisar bloqueos.",
+"unblockip"            => "Desbloquear dirección IP",
+"unblockiptext"        => "Usa la forma que sigue para restaurar 
+acceso de escritura a una dirección IP previamente bloqueada.",
+"ipusubmit"            => "Desbloquea esta dirección",
+"ipusuccess"   => "Dirección IP \"$1\" desbloqueada",
+"ipblocklist"  => "Lista de direcciones IP bloqueadas",
+"blocklistline"        => "$1, $2 bloquea $3",
+"blocklink"            => "bloquear",
+
+"unblocklink"  => "desbloquear",
+"contribslink" => "contribuciones",
+
+# Developer tools
+#
+"lockdb"               => "Lock database",
+"unlockdb"             => "Unlock database",
+"lockdbtext"   => "Locking the database will suspend the ability of all
+users to edit pages, change their preferences, edit their watchlists, and
+other things requiring changes in the database.
+Please confirm that this is what you intend to do, and that you will
+unlock the database when your maintenance is done.",
+"unlockdbtext" => "Unlocking the database will restore the ability of all
+users to edit pages, change their preferences, edit their watchlists, and
+other things requiring changes in the database.
+Please confirm that this is what you intend to do.",
+"lockconfirm"  => "Yes, I really want to lock the database.",
+"unlockconfirm"        => "Yes, I really want to unlock the database.",
+"lockbtn"              => "Lock database",
+"unlockbtn"            => "Unlock database",
+"locknoconfirm" => "You did not check the confirmation box.",
+"lockdbsuccesssub" => "Database lock succeeded",
+"unlockdbsuccesssub" => "Database lock removed",
+"lockdbsuccesstext" => "The Wikipedia database has been locked.
+<br>Remember to remove the lock after your maintenance is complete.",
+"unlockdbsuccesstext" => "The Wikipedia database has been unlocked.",
+
+# SQL query
+#
+"asksql"               => "Consulta SQL",
+"asksqltext"   => "Usa la forma que sigue para hacer una consulta directa
+a la base de datos de Wikipedia. Usa comillas simples ('como estas') para delimitar
+cadenas de caracteres literales.
+Esto puede añadir una carga considerable al servidor, así que
+por favor usa esta función lo menos possible.",
+"sqlquery"             => "Entra la consulta",
+"querybtn"             => "Envía la consulta",
+"selectonly"   => "Consultas diferentes a \"SELECT\" están restringidas sólo
+a Wikipedia developers.",
+"querysuccessful" => "Consulta exitosa",
+
+# Move page
+#
+"movepage"             => "Renombrar página",
+"movepagetext" => "Usando el formulario que sigue renombrará una página,
+moviendo toda su historia al nombre nuevo.
+El título anterior se convertirá en un redireccionamiento al nuevo título.
+Enlaces al antiguo título de la página no se cambiarán. Asegúrate de [[Especial:Maintenance|verificar]] no dejar redirecciones dobles o rotas.
+Tú eres responsable de hacer que los enlaces sigan apuntando adonde se supone que lo hagan. 
+
+Nota que la página '''no''' será trasladada si ya existe una página con el nuevo título, a no ser que sea una página vacía o un ''redirect'' sin historia. 
+Esto significa que tu puedes renombrar de vuelta una página a su título original si cometes un error, y que no puedes sobreescribir una página existente.
+
+<b>ADVERTENCIA!</b>
+Este puede ser un cambio drástico e inesperado para una página popular;
+por favor, asegurate de entender las consecuencias que acarreara
+antes de seguir adelante.",
+"movepagetalktext" => "La página de discusión asociada, si existe, será trasladad automáticamente '''a menos que:'''
+*Estés moviendo la página entre espacios de nombre diferentes,
+*Una página de discusión no vacía ya existe con el nombre nuevo, o
+*Deseleccionaste la caja abajo.
+
+En esos casos, deberás trasladar o mezclar la página manualmente si lo deseas.",
+"movearticle"  => "Renombrar página",
+"movenologin"  => "No estás dentro de una sesion",
+"movenologintext" => "Tu debes ser un usuario registrado y <a href=\"" .
+  wfLocalUrl( "Especial:Userlogin" ) . "\">dentro de una sesión</a>
+para renombrar una página.",
+"newtitle"             => "A título nuevo",
+"movepagebtn"  => "Renombrar página",
+"pagemovedsub" => "Renombramiento exitoso",
+"pagemovedtext" => "Página \"[[$1]]\" renombrada a \"[[$2]]\".",
+"articleexists" => "Ya existe una página con ese nombre, o el nombre que has
+escogido no es válido.
+Por favor, elije otro nombre.",
+"talkexists"   => "La página misma fue renombrada exitosamente, pero la página de discusión no se pudo mover porque una ya existe en el título nuevo. Por favor incorporarlas manualmente.",
+"movedto"              => "renombrado a",
+"movetalk"     => "Renombrar la página de discusión también, si es aplicable.",
+"talkpagemoved" =>  "La página de discusión correspondiente también fue renombrada.",
+"talkpagenotmoved" => "La página de discusión correspondiente <strong>no</strong> fue renombrada.",
+
+);
+
+class LanguageEs extends Language {
+
+       # Inherent default user options unless customization is desired
+
+    function getBookstoreList () {
+               global $wgBookstoreListEn ;
+               return $wgBookstoreListEn ;
+       }
+
+       function getNamespaces() {
+               global $wgNamespaceNamesEs;
+               return $wgNamespaceNamesEs;
+       }
+
+       function getNsText( $index ) {
+               global $wgNamespaceNamesEs;
+               return $wgNamespaceNamesEs[$index];
+       }
+
+       function getNsIndex( $text ) {
+               global $wgNamespaceNamesEs;
+
+               foreach ( $wgNamespaceNamesEs as $i => $n ) {
+                       if ( 0 == strcasecmp( $n, $text ) ) { return $i; }
+               }
+               return false;
+       }
+       #function specialPage( $name ) {
+       #       return $this->getNsText( Namespace::getSpecial() ) . ":" . $name;
+       #}
+
+       function getQuickbarSettings() {
+               global $wgQuickbarSettingsEs;
+               return $wgQuickbarSettingsEs;
+       }
+
+       function getSkinNames() {
+               global $wgSkinNamesEs;
+               return $wgSkinNamesEs;
+       }
+
+       function getMathNames() {
+               global $wgMathNamesEs;
+               return $wgMathNamesEs;
+       }
+
+
+       function getUserToggles() {
+               global $wgUserTogglesEs;
+               return $wgUserTogglesEs;
+       }
+
+
+
+       function getLanguageNames() {
+               global $wgLanguageNamesEn;
+               return $wgLanguageNamesEn;
+       }
+
+       function getLanguageName( $code ) {
+               global $wgLanguageNamesEs;
+               if ( ! array_key_exists( $code, $wgLanguageNamesEs ) ) {
+                       return "";
+               }
+               return $wgLanguageNamesEs[$code];
+       }
+
+       function getMonthName( $key )
+       {
+               global $wgMonthNamesEs;
+               return $wgMonthNamesEs[$key-1];
+       }
+
+       function getMonthAbbreviation( $key )
+       {
+               global $wgMonthAbbreviationsEs;
+               return $wgMonthAbbreviationsEs[$key-1];
+       }
+
+       function getWeekdayName( $key )
+       {
+               global $wgWeekdayNamesEs;
+               return $wgWeekdayNamesEs[$key-1];
+       }
+
+       # Inherit userAdjust()
+        
+       function shortdate( $ts, $adj = false )
+       {
+               if ( $adj ) { $ts = $this->userAdjust( $ts ); }
+
+               $d = (0 + substr( $ts, 6, 2 )) . " " .$this->getMonthAbbreviation( substr( $ts, 4, 2 ) ) . ", " .
+                 substr( $ts, 0, 4 );
+               return $d;
+       }
+
+       function date( $ts, $adj = false )
+       {
+               if ( $adj ) { $ts = $this->userAdjust( $ts ); }
+
+               $d = (0 + substr( $ts, 6, 2 )) . " de " .$this->getMonthName( substr( $ts, 4, 2 ) ) . ", " .
+                 substr( $ts, 0, 4 );
+               return $d;
+       }
+
+       function time( $ts, $adj = false )
+       {
+               if ( $adj ) { $ts = $this->userAdjust( $ts ); }
+
+               $t = substr( $ts, 8, 2 ) . ":" . substr( $ts, 10, 2 );
+               return $t;
+       }
+
+       function timeanddate( $ts, $adj = false )
+       {
+               return $this->time( $ts, $adj ) . " " . $this->shortdate( $ts, $adj );
+       }
+
+       function getValidSpecialPages()
+       {
+               global $wgValidSpecialPagesEs;
+               return $wgValidSpecialPagesEs;
+       }
+
+       function getSysopSpecialPages()
+       {
+               global $wgSysopSpecialPagesEs;
+               return $wgSysopSpecialPagesEs;
+       }
+
+       function getDeveloperSpecialPages()
+       {
+               global $wgDeveloperSpecialPagesEs;
+               return $wgDeveloperSpecialPagesEs;
+       }
+
+       function getMessage( $key )
+       {
+               global $wgAllMessagesEs, $wgAllMessagesEn;
+               $m = $wgAllMessagesEs[$key];
+
+               if ( "" == $m ) { return $wgAllMessagesEn[$key]; }
+               else return $m;
+       }
+}
+
+?>
\ No newline at end of file
diff --git a/languages/LanguageFr.php b/languages/LanguageFr.php
new file mode 100644 (file)
index 0000000..7977787
--- /dev/null
@@ -0,0 +1,1034 @@
+<?
+
+# quelques modifications / Utilisateur:MarcQuinton
+# - j'ai laissé en commentaire les strings originales, et placé ma signature (MQ)
+
+# The names of the namespaces can be set here, but the numbers
+# are magical, so don't change or move them!  The Namespace class
+# encapsulates some of the magic-ness.
+#
+/* private */ $wgNamespaceNamesFr = array(
+       -1 => "Special",
+       0 => "",
+       1 => "Discuter",
+       2 => "Utilisateur",
+       3 => "Discussion_Utilisateur",
+       4 => "Wikipédia",
+       5 => "Discussion_Wikipédia",
+       6 => "Image",
+       7 => "Discussion_Image"
+);
+
+/* Some default options can be changed - see Language.php */
+
+/* private */ $wgQuickbarSettingsFr = array(
+       "Aucune", "Gauche", "Droite", "Flottante à gauche"
+);
+
+/* private */ $wgSkinNamesFr = array(
+       "Normal", "Nostalgie", "Cologne Blue"
+);
+
+/* private */ $wgUserTogglesFr = array(
+       "hover"  => "Afficher des info-bulles sur les liens wiki",
+       "underline" => "Liens soulignés",
+       "highlightbroken" => "Liens vers les sujets non existants en rouge",
+       "justify" => "Paragraphes justifiés",
+       "hideminor" => "Cacher les <i>Modifications récentes</i> mineures",
+       "numberheadings" => "Numérotation automatique des titres",
+       "rememberpassword" => "Se souvenir de mon mot de passe (cookie)",
+       "editwidth" => "La fenetre d'édition est en pleine largeur",
+       "editondblclick" => "Double cliquer pour éditer une page (JavaScript)",
+       "watchdefault" => "Suivre les articles que je crée ou modifie",
+       "minordefault" => "Mes modifications sont mineures par défaut",
+       "previewontop" => "Prevue se montre avant boite de redacter" # FIXME
+);
+
+/* Replace these with some French bookshops/lookup places */
+/* private */ $wgBookstoreListEn = array(
+       "AddALL" => "http://www.addall.com/New/Partner.cgi?query=$1&type=ISBN",
+       "PriceSCAN" => "http://www.pricescan.com/books/bookDetail.asp?isbn=$1",
+       "Barnes & Noble" => "http://shop.barnesandnoble.com/bookSearch/isbnInquiry.asp?isbn=$1",
+       "Amazon.com" => "http://www.amazon.com/exec/obidos/ISBN=$1"
+);
+
+/* private */ $wgLanguageNamesFr = array(
+    "aa" => "Afar",
+    "ab" => "Abkhazien",
+       "af" => "Afrikaans",
+       "am" => "Amharique",
+       "ar" => "&#1575;&#1604;&#1593;&#1585;&#1576;&#1610;&#1617;&#1577; (Araby)",
+       "as" => "Assamais",
+       "ay" => "Aymara",
+       "az" => "Azerbaïjanais",
+       "ba" => "Bashkir",
+       "be" => "Biélorusse",
+       "bh" => "Bihari",
+       "bi" => "Bislama",
+       "bn" => "Bengali",
+       "bo" => "Tibétain",
+       "ca" => "Català",
+       "co" => "Corse",
+       "cs" => "&#268;esky (Tchèque)",
+       "cy" => "Cymraeg",
+       "da" => "Dansk", # Note two different subdomains.
+       "dk" => "Dansk", # 'da' is correct for the language.
+       "de" => "Deutsch",
+       "dz" => "Bhoutani",
+       "el" => "&#917;&#955;&#955;&#951;&#957;&#953;&#954;&#940; (Ellenika)",
+       "en" => "English",
+    "simple" => "Anglais simplifié",
+       "eo" => "Esperanto",
+       "es" => "Español",
+       "et" => "Eesti",
+       "eu" => "Euskara",
+       "fa" => "Persan",
+       "fi" => "Suomi",
+       "fj" => "Fidjien",
+       "fo" => "Féroïen",
+       "fy" => "Frison",
+       "ga" => "Gaeilge",
+       "gl" => "Galicien",
+       "gn" => "Guarani",
+       "gu" => "Goujarati",
+       "ha" => "Haoussa",
+       "he" => "&#1506;&#1489;&#1512;&#1497;&#1514; (Ivrit)",
+       "hi" => "Hindi",
+       "hr" => "Hrvatski",
+       "hu" => "Magyar",
+       "hy" => "Arménien",
+       "ia" => "Interlingua",
+       "id" => "Indonesia",
+       "ik" => "Inupiak",
+       "is" => "Íslenska",
+       "it" => "Italiano",
+       "iu" => "Inuktitut",
+       "ja" => "&#26085;&#26412;&#35486; (Nihongo)",
+       "jv" => "Javanais",
+       "ka" => "Géorgien",
+       "kk" => "Kazakh",
+       "kl" => "Groenlandais",
+       "km" => "Cambodgien",
+       "kn" => "Kannada",
+       "ko" => "&#54620;&#44397;&#50612; (Hangukeo)",
+       "ks" => "Kashmiri",
+       "ky" => "Kirghize",
+       "la" => "Latin",
+       "ln" => "Lingala",
+       "lo" => "Laotien",
+       "lt" => "Lietuvi&#371;",
+       "lv" => "Letton",
+       "mg" => "Malgache",
+       "mi" => "Maori",
+       "mk" => "Macédonien",
+       "ml" => "Malayalam",
+       "mn" => "Mongol",
+       "mo" => "Moldave",
+       "mr" => "Marathe",
+       "ms" => "Malais",
+       "my" => "Birman",
+       "na" => "Nauri",
+       "ne" => "Népalais",
+       "nl" => "Nederlands",
+       "no" => "Norsk",
+       "oc" => "Occitan",
+       "om" => "Oromo",
+       "or" => "Oriya",
+       "pa" => "Pendjabi",
+       "pl" => "Polski",
+       "ps" => "Pashto",
+       "pt" => "Português",
+       "qu" => "Quechua",
+       "rm" => "Rhéto-Roman",
+       "rn" => "Kirundi",
+       "ro" => "Român&#259;",
+       "ru" => "&#1056;&#1091;&#1089;&#1089;&#1082;&#1080;&#1081; (Russkij)",
+       "rw" => "Kinyarwanda",
+       "sa" => "Sanscrit",
+       "sd" => "Sindhi",
+       "sg" => "Sango",
+       "sh" => "Serbo-croate",
+       "si" => "Singhalais",
+       "sk" => "Slovaque",
+       "sl" => "Slovensko",
+       "sm" => "Samoan",
+       "sn" => "Shona",
+       "so" => "Somali",
+       "sq" => "Albanais",
+       "sr" => "Serbe",
+       "ss" => "Siswati",
+       "st" => "Sésotho",
+       "su" => "Soudanais",
+       "sv" => "Svenska",
+       "sw" => "Kiswahili",
+       "ta" => "Tamoul",
+       "te" => "Télougou",
+       "tg" => "Tadjik",
+       "th" => "Thaï",
+       "ti" => "Tigrinya",
+       "tk" => "Turkmène",
+       "tl" => "Tagalog",
+       "tn" => "Setchwana",
+       "to" => "Tonga",
+       "tr" => "Türkçe",
+       "ts" => "Tsonga",
+       "tt" => "Tatar",
+       "tw" => "Tchi",
+       "ug" => "Ouïgour",
+       "uk" => "&#1059;&#1082;&#1088;&#1072;&#1111;&#1085;&#1089;&#1100;&#1082;&#1072; (Ukrayins`ka)",
+       "ur" => "Ourdou",
+       "uz" => "Ouzbek",
+       "vi" => "Vietnamien",
+       "vo" => "Volapük",
+       "wo" => "Ouolof",
+       "xh" => "isiXhosa",
+       "yi" => "Yiddish",
+       "yo" => "Yorouba",
+       "za" => "Zhuang",
+       "zh" => "&#20013;&#25991; (Zhongwen)",
+       "zu" => "Zoulou"
+);
+
+/* private */ $wgWeekdayNamesFr = array(
+       "dimanche", "lundi", "mardi", "mercredi", "jeudi",
+       "vendredi", "samedi"
+);
+
+/* private */ $wgMonthNamesFr = array(
+       "janvier", "février", "mars", "avril", "mai", "juin",
+       "juillet", "août", "septembre", "octobre", "novembre",
+       "décembre"
+);
+
+/* private */ $wgMonthAbbreviationsFr = array(
+       "jan", "fév", "mar", "avr", "mai", "jun", "jul", "aoû",
+       "sep", "oct", "nov", "déc"
+);
+
+# All special pages have to be listed here: a description of ""
+# will make them not show up on the "Special Pages" page, which
+# is the right thing for some of them (such as the "targeted" ones).
+#
+/* private */ $wgValidSpecialPagesFr = array(
+       "Userlogin"  => "",
+       "Userlogout" => "",
+       "Preferences" => "Préférences",
+       "Watchlist"  => "Liste de suivi",
+       "Recentchanges" => "Modifications récentes",
+       "Upload"  => "Copier un fichier",
+       "Imagelist"  => "Liste des images",
+       "Listusers"  => "Liste des participants",
+       "Statistics" => "Statistiques",
+       "Randompage" => "Une page au hasard",
+
+       "Lonelypages" => "Pages orphelines",
+       "Unusedimages" => "Images orphelines",
+       "Popularpages" => "Les plus populaires",
+       "Wantedpages" => "Les plus demandées",
+       "Shortpages" => "Articles courts",
+       "Longpages"  => "Articles longs",
+       "Newpages"  => "Nouvelles pages",
+       "Allpages"  => "Toutes les pages",
+
+       "Ipblocklist" => "Adresses IP bloquées",
+       "Maintenance" => "Page de Maintenance",
+       "Specialpages"  => "",  # "Pages Spéciales", # Cettes pages doient être vides
+       "Contributions" => "",  # "Contributions",   # car elles n'ont pas que l'interface
+       "Emailuser"  => "",             # "Email utilisateur", # diret.
+       "Whatlinkshere" => "",  #"Liens pointant ici",
+       "Recentchangeslinked" => "", #"Dernieres modifications",
+       "Movepage"  => "",              #"Page déplacée",
+       "Booksources" => "Librairies en ligne"
+);
+
+/* private */ $wgSysopSpecialPagesFr = array(
+       "Blockip"  => "Bloquer une adresse IP",
+       "Asksql"  => "Accès SQL",
+       "Undelete"      => "Gérer les pages effacées" // MQ "View and restore deleted pages"
+);
+
+/* private */ $wgDeveloperSpecialPagesFr = array(
+       "Lockdb"  => "Bloquer la base de données",
+       "Unlockdb"  => "Débloquer la base de données",
+       "Debug"   => "Informations de débogage"
+);
+
+/* private */ $wgAllMessagesFr = array(
+
+# Bits of text used by many pages:
+#
+"linktrail"     => "/^([a-zàâçéèêîôû]+)(.*)\$/sD",
+"mainpage"  => "Accueil",
+"about"   => "À propos",
+"aboutwikipedia" => "À propos de Wikipedia",
+"aboutpage"  => "Wikipédia:À_propos",
+"help"   => "Aide",
+"helppage"  => "Wikipédia:Aide",
+"wikititlesuffix" => "Wikipedia",
+"bugreports" => "Rapport d'erreurs",
+"bugreportspage" => "Wikipédia:Rapport_d'erreurs",
+"faq"   => "FAQ",
+"faqpage"  => "Wikipédia:FAQ",
+"edithelp"  => "Aide",
+"edithelppage" => "Wikipédia:Comment_éditer_une_page",
+"cancel"  => "Annuler",
+"qbfind"  => "Rechercher",
+"qbbrowse"  => "Défiler",
+"qbedit"  => "Éditer",
+"qbpageoptions" => "Option page",
+"qbpageinfo" => "Info page",
+"qbmyoptions" => "Mes options",
+"mypage"  => "Ma page",
+"mytalk"  => "Ma page de discussion",
+"currentevents" => "Actualités",
+"errorpagetitle" => "Erreur",
+"returnto"  => "Revenir à la page $1.",
+"fromwikipedia" => "Un article de Wikipédia, l'encyclopédie libre.",
+"whatlinkshere" => "Références à cette page",
+"help"   => "Aide",
+"search"  => "Rechercher",
+"history"  => "Historique",
+"printableversion" => "Version imprimable",
+"editthispage" => "Modifier cette page",
+"deletethispage" => "Supprimer cette page",
+"protectthispage" => "Protéger cette page",
+"unprotectthispage" => "Dé-protéger cette page",
+"talkpage"  => "Page de discussion",
+"subjectpage" => "Page sujet",
+"articlepage"  => "Page article",
+"userpage" => "Page utilisateur",
+"wikipediapage" => "Page méta",
+"imagepage" => "Page image",
+"otherlanguages" => "Autres langues",
+"redirectedfrom" => "(Redirigé depuis $1)",
+"lastmodified" => "Dernière modification de cette page : $1.",
+"viewcount"  => "Cette page a été consultée $1 fois.",
+"printsubtitle" => "(de http://www.wikipedia.org)",
+"protectedpage" => "Page protégée",
+"administrators" => "Wikipédia:Administrateurs",
+"sysoptitle" => "Accès administrateur requis",
+
+"sysoptext"  => "L'action que vous avez tentée ne peut être effectuée que par un utilisateur ayant le statut d'\"Administrateur\".
+Voir $1.",
+"developertitle" => "Accès développeur requis",
+"developertext" => "L'action que vous avez tentée ne peut être effectuée que par un utilisateur ayant le statut de \"développeur\".
+Voir $1.",
+"nbytes"  => "$1 octets",
+"go"   => "OK",
+"ok"   => "OK",
+"sitetitle"  => "Wikipédia",
+"sitesubtitle" => "L'encyclopédie libre",
+"retrievedfrom" => "Récupérée de \"$1\"",
+"newmessages" => "Vous avez des $1.",
+"newmessageslink" => "nouveaux messages",
+
+# Main script and global functions
+#
+"nosuchaction" => "Action inconnue",
+"nosuchactiontext" => "L'action spécifiée dans l'URL n'est pas reconnue par le logiciel Wikipédia.",
+"nosuchspecialpage" => "Page spéciale inexistante",
+"nospecialpagetext" => "Vous avez demandé une page spéciale qui n'est pas reconnue par le logiciel Wikipédia.",
+
+# General errors
+#
+"error"   => "Erreur",
+"databaseerror" => "Erreur base de données",
+"dberrortext" => "Erreur de syntaxe dans la base de données. Cette erreur peut être causée par une requête de recherche incorrecte (voir $5), ou une erreur dans le logiciel. La dernière requête traitée par la base de données était :
+<blockquote><tt>$1</tt></blockquote>
+depuis la fonction \"<tt>$2</tt>\".
+MySQL a renvoyé l'erreur \"<tt>$3: $4</tt>\".",
+"noconnect"  => "Connexion impossible à la base de données sur $1",
+"nodb"   => "Sélection impossible de la base de données $1",
+"readonly"  => "Mises à jour bloquées sur la base de données",
+"enterlockreason" => "Indiquez la raison du blocage, ainsi qu'une estimation de la durée de blocage ",
+"readonlytext" => "Les ajouts et mises à jour sur la base de données Wikipédia sont actuellement bloqués, probablement pour permettre la maintenance de la base, après quoi, tout rentrera dans l'ordre. Voici la raison pour laquelle l'administrateur a bloqué la base :
+<p>$1",
+"missingarticle" => "La base de données n'a pas pu trouver le texte d'une page existante, dont le titre est \"$1\".
+Ce n'est pas une erreur de la base de données, mais plus probablement un bogue du logiciel Wikipédia.
+Veuillez rapporter cette erreur à un administrateur, en lui indiquant l'adresse de la page fautive.",
+"internalerror" => "Erreur interne",
+"filecopyerror" => "Impossible de copier \"$1\" vers \"$2\".",
+"filerenameerror" => "Impossible de renommer \"$1\" en \"$2\".",
+"filedeleteerror" => "Impossible de supprimer \"$1\".",
+"filenotfound" => "Fichier \"$1\" introuvable.",
+"unexpected" => "Valeur inattendue : \"$1\"=\"$2\".",
+"formerror"  => "Erreur: Impossible de soumettre le formulaire",
+"badarticleerror" => "Cette action ne peut pas être effectuée sur cette page.",
+"cannotdelete" => "Impossible de supprimer la page ou l'image indiquée.",
+
+# Login and logout pages
+#
+"logouttitle" => "Déconnexion",
+"logouttext" => "Vous êtes à présent déconnecté(e).
+Vous pouvez continuer à utiliser Wikipédia de façon anonyme, ou vous reconnecter, éventuellement sous un autre nom.\n",
+
+"welcomecreation" => "<h2>Bienvenue, $1!</h2><p>Votre compte d'utilisateur a été créé.
+N'oubliez pas de personnaliser votre Wikipédia en consultant la page Préférences.",
+
+"loginpagetitle" => "Votre identifiant",
+"yourname"  => "Votre nom d'utilisateur",
+"yourpassword" => "Votre mot de passe",
+"yourpasswordagain" => "Entrez à nouveau votre mot de passe",
+"newusersonly" => " (nouveaux utilisateurs uniquement)",
+"remembermypassword" => "Se souvenir de mon mot de passe (cookie)",
+"loginproblem" => "<b>Problème d'identification.</b><br>Essayez à nouveau !",
+"alreadyloggedin" => "<font color=red><b>Utilisateur $1, vous êtes déjà identifié!</b></font><br>\n",
+
+"areyounew"  => "Si vous êtes nouveau sur Wikipédia et souhaitez créer un compte utilisateur, entrez un nom d'utilisateur et tapez deux fois votre mot de passe. L'adresse électronique est optionnelle, mais si vous perdez votre mot de passe, vous pourrez en demander un nouveau que nous vous ferons parvenir par ce moyen.<br>\n",
+
+"login"   => "Identification",
+"userlogin"  => "Identification",
+"logout"  => "Déconnexion",
+"userlogout" => "Déconnexion",
+"createaccount" => "Créer un nouveau compte",
+"badretype"  => "Les deux mots de passe que vous avez saisis ne sont pas identiques.",
+"userexists" => "Le nom d'utilisateur que vous avez saisi est déjà utilisé. Veuillez en choisir un autre.",
+"youremail"  => "Mon adresse électronique",
+"yournick"  => "Mon surnom (pour les signatures)",
+"emailforlost" => "Si vous égarez votre mot de passe, vous pouvez demander à ce qu'un nouveau vous soit envoyé à votre adresse électronique.",
+"loginerror" => "Problème d'identification",
+"noname"  => "Vous n'avez pas saisi de nom d'utilisateur.",
+"loginsuccesstitle" => "Identification réussie.",
+"loginsuccess" => "Vous êtes actuellement connecté(e) sur Wikipédia en tant que \"$1\".",
+"prefslogintext" => "Je suis connecté(e) en tant que $1 avec le numéro d'utilisateur $2.",
+"nosuchuser" => "L'utilisateur \"$1\" n'existe pas.
+Vérifiez que vous avez bien orthographié le nom, ou utilisez le formulaire ci-dessous pour créer un nouveau compte utilisateur.",
+"wrongpassword" => "Le mot de passe est incorrect. Essayez à nouveau.",
+"mailmypassword" => "Envoyez-moi un nouveau mot de passe",
+"passwordremindertitle" => "Votre nouveau mot de passe sur Wikipédia",
+"passwordremindertext" => "Quelqu'un (probablement vous) ayant l'adresse IP $1 a demandé à ce qu'un nouveau mot de passe vous soit envoyé pour votre accès à Wikipédia.
+Le mot de passe de l'utilisateur \"$2\" est à présent \"$3\".
+Nous vous conseillons de vous connecter et de modifier ce mot de passe dès que possible.",
+"noemail"  => "Aucune adresse électronique n'a été enregistrée pour l'utilisateur \"$1\".",
+"passwordsent" => "Un nouveau mot de passe a été envoyé à l'adresse électronique de l'utilisateur \"$1\".
+Veuillez vous identifier dès que vous l'aurez reçu.",
+
+# Edit pages
+#
+"summary"  => "Résumé",
+"minoredit"  => "Modification mineure.",
+"watchthis"            => "Suivre cet article",
+"savearticle" => "Sauvegarder",
+"preview"  => "Prévisualiser",
+
+"showpreview" => "Prévisualisation",
+"blockedtitle" => "Utilisateur bloqué",
+"blockedtext" => "Votre compte utilisateur ou votre adresse IP ont été bloqués par $1 pour la raison suivante :<br>$2<p> Vous pouvez contacter l'administrateur pour en discuter.",
+"newarticle" => "(Nouveau)",
+"newarticletext" => "Saisissez ici le texte de votre article.",
+"noarticletext" => "(Il n'y a pour l'instant aucun texte sur cette page)",
+"updated"  => "(Mis à jour)",
+"note"   => "<strong>Note:</strong> ",
+"previewnote" => "Attention, ce texte n'est qu'une prévisualisation et n'a pas encore été sauvegardé!",
+"previewconflict" => "La prévisualisation montre le texte de cette page tel qu'il apparaîtra une fois sauvegardé.",
+"editing"  => "modification de $1",
+"editconflict" => "Conflit de modification : $1",
+"explainconflict" => "<b>Cette page a été sauvegardée après que vous ayez commencé à la modifier.
+La zone d'édition supérieure contient le texte tel qu'il est enregistré actuellement dans la base de données. Vos modifications apparaissent dans la zone d'édition inférieure. Vous allez devoir apporter vos modifications au texte existant. Seul le texte de la zone supérieure sera sauvegardé.\n<p>",
+"yourtext"  => "Votre texte",
+"storedversion" => "Version enregistrée",
+"editingold" => "<strong>Attention : Vous êtes en train de modifier une version obsolète de cette page. Si vous sauvegardez, toutes les modifications effectuées depuis cette version seront perdues.</strong>\n",
+"yourdiff"  => "Différences",
+"copyrightwarning" => "Toutes les contributions à Wikipédia sont considérées comme publiées sous les termes de la GNU Free Documentation License, une licence de documentation libre (Voir $1 pour plus de détails). Si vous ne désirez pas que vos écrits soient édités et distribués à volonté, ne les envoyez pas. De même, merci de ne contribuer qu'en apportant vos propres écrits ou des écrits issus d'une source libre de droits. <b>N'UTILISEZ PAS DE TRAVAUX SOUS COPYRIGHT SANS AUTORISATION EXPRESSE!</b>",
+"longpagewarning" => "AVERTISSEMENT : Ceci page a longeur de $1 ko;
+quelques navigateurs mal trait des pages approchant ou plus de 32 ko à
+redaction. Peut-etre serait-il mieux si vous separer la page en sections
+plus petites.",
+
+# History pages
+#
+"revhistory" => "Versions précédentes",
+"nohistory"  => "Il n'existe pas d'historique pour cette page.",
+"revnotfound" => "Version introuvable",
+"revnotfoundtext" => "La version précédente de cette page n'a pas pu être retrouvée. Vérifiez l'URL que vous avez utilisée pour accéder à cette page.\n",
+"loadhist"  => "Chargement de l'historique de la page",
+"currentrev" => "Version actuelle",
+"revisionasof" => "Version du $1",
+"cur"   => "actu",
+"next"   => "suiv",
+"last"   => "dern",
+"orig"   => "orig",
+"histlegend" => "Légende: (actu) = différence avec la version actuelle ,
+(dern) = différence avec la version précédente, M = modification mineure",
+
+# Diffs
+#
+"difference" => "(Différences entre les versions)",
+"loadingrev" => "loading revision for diff",
+"lineno"  => "Ligne $1:",
+"editcurrent" => "Modifier la version actuelle de cette page",
+
+
+# Search results
+#
+"searchresults" => "Résultat de la recherche",
+"searchhelppage" => "Wikipédia:Recherche",
+"searchingwikipedia" => "Chercher dans Wikipédia",
+"searchresulttext" => "Pour plus d'informations sur la recherche dans Wikipédia, voir $1.",
+"searchquery" => "Pour la requête \"$1\"",
+"badquery"  => "Requête mal formée",
+"badquerytext" => "Nous n'avons pas pu traiter votre requête.
+Vous avez probablement recherché un mot d'une longueur inférieure
+à trois lettres, ce qui n'est pas encore possible. Vous avez
+aussi pu faire une erreur de syntaxe, telle que \"poisson et
+et écailles\".
+Veuillez essayer une autre requête.",
+"matchtotals" => "La requête \"$1\" correspond à $2 titres
+d'article et au texte de $3 articles.",
+"titlematches" => "Correspondances dans les titres",
+"notitlematches" => "Aucun titre d'article ne contient le(s) mot(s) demandé(s)",
+"textmatches" => "Correspondances dans les textes",
+"notextmatches" => "Aucun texte d'article ne contient le(s) mot(s) demandé(s)",
+"prevn"   => "$1 précédents",
+"nextn"   => "$1 suivants",
+"viewprevnext" => "Voir ($1) ($2) ($3).",
+"showingresults" => "Affichage de <b>$1</b> résultats à partir du #<b>$2</b>.",
+"nonefound"  => "<strong>Note</strong>: l'absence de résultat est souvent due à l'emploi de termes de recherche trop courants, comme \"a\" ou \"de\",
+qui ne sont pas indexés, ou à l'emploi de plusieurs termes de recherche (seules les pages
+contenant tous les termes apparaissent dans les résultats).",
+"powersearch" => "Search",
+"powersearchtext" => "
+Search in namespaces :<br>
+$1<br>
+$2 List redirects &nbsp; Search for $3 $9",
+
+
+# Preferences page
+#
+"preferences" => "Préférences",
+"prefsnologin" => "Non connecté",
+"prefsnologintext" => "Vous devez être <a href=\"" .
+               wfLocalUrl( "Special:Userlogin" ) . "\">connecté</a>
+pour modifier vos préférences d'utilisateur.",
+"prefsreset" => "Les préférences ont été rétablies à partir de la version enregistrée.",
+"qbsettings" => "Personnalisation de la barre outils",
+"changepassword" => "Modification du mot de passe",
+"skin"   => "Apparence",
+"saveprefs"  => "Enregistrer les préférences",
+"resetprefs" => "Rétablir les préférences",
+"oldpassword" => "Ancien mot de passe",
+"newpassword" => "Nouveau mot de passe",
+"retypenew"  => "Confirmation du nouveau mot de passe",
+"textboxsize" => "Taille de la fenêtre d'édition",
+"rows"   => "Rangées",
+"columns"  => "Colonnes",
+"searchresultshead" => "Affichage des résultats de recherche",
+"resultsperpage" => "Nombre de réponses sur chaque page",
+"contextlines" => "Nombre de lignes pour chaque réponse",
+"contextchars" => "Nombre de caractères du contexte sur chaque ligne",
+"stubthreshold" => "Threshold for stub display",
+"recentchangescount" => "Nombre de titres dans les modifications récentes",
+"savedprefs" => "Les préférences ont été sauvegardées.",
+"timezonetext" => "Si vous ne préciser pas de décalage horaire, c'est l'heure de l'Europe de l'ouest qui sera utilisée.",
+"localtime" => "Heure locale",
+"timezoneoffset" => "Décalage horaire",
+
+"emailflag"  => "Ne pas recevoir de courrier électronique des autres utilisateurs",
+
+# Recent changes
+#
+"changes" => "changes", # FIXME?
+"recentchanges" => "Modifications récentes",
+"recentchangestext" => "Suivez sur cette page les dernières modifications de Wikipédia.
+[[Wikipédia:Bienvenue|Bienvenue]] aux nouveaux participants!
+Jetez un coup d'&oelig;il sur ces pages: [[wikipédia:FAQ|Foire aux questions]],
+[[Wikipédia:Recommandations Et Règles à Suivre|Recommandations et règles à suivre]]
+(notamment [[Wikipédia:Règles De Nommage|Conventions de nommage]],
+[[Wikipédia:La Neutralité De Point De Vue|La neutralité de point de vue]]),
+et [[Wikipédia:Les Faux-Pas Les Plus Courants|Les faux-pas les plus courants]].
+
+Si vous voulez que Wikipédia connaisse le succès, n'y ajoutez pas de matériaux protégés par des [[wikipédia:Copyright|copyrights]].
+La responsabilité juridique pourrait compromettre le projet, alors s'il vous plaît ne le faites pas.
+Voyez aussi [http://meta.wikipedia.org/wiki/Special:Recentchanges les dernières discussions sur le site meta-wiki].",
+"rcloaderr"  => "Chargement des dernières modifications",
+"rcnote"  => "Voici les <strong>$1</strong> dernières modifications effectuées au cours des <strong>$2</strong> derniers jours.",
+"rcnotefrom"   => "Voici les modifications effectuées depuis <strong>$2</strong> (jusqu'à <b>$1</b>).",
+"rclistfrom"   => "Afficher les nouvelles modifications depuis $1",
+# "rclinks"  => "Afficher les $1 dernières modifications effectuées au cours des $2 dernières heures / $3 derniers jours",
+"rclinks"  => "Afficher les $1 dernières modifications effectuées au cours des $2 derniers jours.",
+"rchide"  => "in $4 form; $1 minor edits; $2 secondary namespaces; $3 multiple edits.",
+"diff"   => "diff",
+"hist"   => "hist",
+"hide"   => "cacher",
+"show"   => "montrer",
+"tableform"  => "table",
+"listform"  => "liste",
+"nchanges"  => "$1 modification(s)",
+"minoreditletter" => "M",
+"newpageletter" => "N",
+
+# Upload
+#
+"upload"  => "Copier sur le serveur",
+"uploadbtn"  => "Copier un fichier",
+"uploadlink" => "Copier des images",
+"reupload"  => "Copier à nouveau",
+"reuploaddesc" => "Retour au formulaire.",
+
+"uploadnologin" => "Non connecté(e)",
+"uploadnologintext" => "Vous devez être <a href=\"" .
+               wfLocalUrl( "Special:Userlogin" ) . "\">connecté</a>
+pour copier des fichiers sur le serveur.",
+"uploadfile" => "Copier un fichier",
+"uploaderror" => "Erreur",
+"uploadtext" => "<strong>STOP!</strong> Avant de copier votre fichier sur le serveur,
+prenez connaissance des <a href=\"" .
+wfLocalUrlE( "Wikipédia:règles d'utilisation des images" ) . "\">règles d'utilisation des images</a> de Wikipédia et assurez-vous que vous les respectez.
+<p>Pour voir les images déjà placées sur le serveur ou faire une recherche parmi celles-ci,
+allez à la <a href=\"" . wfLocalUrlE( "Special:Imagelist" ) .
+"\">liste des images</a>.
+Les uploads et les suppressions sont listés dans le <a href=\"" .
+wfLocalUrlE( "Wikipédia:Journal_des_uploads" ) . "\">journal des uploads</a>.
+<p>Utilisez le formulaire ci-dessous pour copier sur le serveur de nouvelles images destinées à illustrer vos articles.
+Sur la plupart des navigateurs, vous verrez un bouton \"Browse...\" qui ouvre la fenêtre de dialogue standard de votre système d'exploitation pour l'ouverture des fichiers.
+Sélectionnez un fichier, son nom apparaîtra dans le champ situé à côté du bouton.
+Vous devez également confirmer, en cochant la case prévue à cet effet, que la copie de ce fichier ne viole aucun copyright.
+Cliquez sur le bouton \"Envoyer\" pour terminer.
+Si votre connection est lente, l'opération peut prendre un certain temps.
+<p>Les formats recommandés sont JPEG pour les photos, PNG
+pour les dessins et les autres images, et OGG pour les fichiers sonores.
+Donnez à vos fichiers des noms descriptifs clairs, afin d'éviter toute confusion.
+Pour incorporer l'image dans un article, placez dans celui-ci un lien rédigé comme suit:
+<b>[[image:nom_du_fichier.jpg]]</b> ou <b>[[image:nom_du_fichier.png|autre texte]]</b>
+ou <b>[[media:nom_du_fichier.ogg]]</b> pour les sons.
+<p>N'oubliez pas que, comme toutes les pages de Wikipédia, les fichiers que vous copiez peuvent être modifiés ou supprimés par les autres utilisateurs s'ils estiment que cela est dans l'intérêt de l'encyclopédie. Sachez aussi que votre accès au serveur peut être bloqué si vous faites un mauvais usage du système.",
+"uploadlog"  => "log d'upload",
+"uploadlogpage" => "Log_d'upload",
+"uploadlogpagetext" => "Voici la liste des derniers fichiers copiés sur le serveur.
+L'heure indiquée est celle du serveur (UTC).
+<ul>
+</ul>
+",
+"filename"  => "Nom",
+"filedesc"  => "Description",
+"affirmation" => "Je déclare que le détenteur du copyright de ce fichier accepte de le diffuser selon les termes de la $1.",
+"copyrightpage" => "Wikipédia:Copyright",
+"copyrightpagename" => "licence Wikipédia",
+"uploadedfiles" => "Fichiers copiés",
+"noaffirmation" => "Vous devez confirmer que la copie de ce fichier ne viole aucun copyright.",
+"ignorewarning" => "Ignorer l'avertissement et copier le fichier quand même.",
+"minlength"  => "Les noms des images doivent comporter au moins trois lettres.",
+"badfilename" => "L'image a été renommée \"$1\".",
+"badfiletype" => "\".$1\" n'est pas un format recommandé pour les fichiers images.",
+"largefile"  => "La taille maximale conseillée pour les images est de 100Ko.",
+"successfulupload" => "Copie réussie",
+"fileuploaded" => "Le fichier \"$1\" a été copié sur le serveur.
+Suivez ce lien: ($2) pour accéder à la page de description, et donnez des informations sur le fichier, par exemple son origine, sa date de création, son auteur, ou tout autre renseignement en votre possession.",
+"uploadwarning" => "Attention!",
+"savefile"  => "Sauvegarder le fichier",
+"uploadedimage" => " \"$1\" copié sur le serveur",
+
+# Image list
+#
+"imagelist"  => "Liste des images",
+"imagelisttext" => "Voici une liste de $1 images classées $2.",
+"getimagelist" => "Récupération de la liste des images",
+"ilshowmatch" => "Afficher toutes les images dont le nom contient ",
+"ilsubmit"  => "Chercher",
+"showlast"  => "Afficher les $1 dernières images classées $2.",
+"all"   => "toutes",
+"byname"  => "par nom",
+"bydate"  => "par date",
+"bysize"  => "par taille",
+"imgdelete"  => "suppr",
+"imgdesc"  => "descr",
+"imglegend"  => "Légende: (descr) = afficher/modifier la description de l'image.",
+"imghistory" => "Historique de l'image",
+"revertimg"  => "rétab",
+"deleteimg"  => "suppr",
+"imghistlegend" => "Légende: (actu) = ceci est l'image actuelle, (suppr) = supprimer
+cette ancienne version, (rétab) = rétablir cette ancienne version.
+<br><i>Cliquez sur la date pour voir l'image copiée à cette date</i>.",
+"imagelinks" => "Liens vers l'image",
+"linkstoimage" => "Les pages ci-dessous comportent un lien vers cette image:",
+"nolinkstoimage" => "Aucune page ne comporte de lien vers cette image.",
+
+# Statistics
+#
+"statistics" => "Statistiques",
+"sitestats"  => "Statistiques du site",
+"userstats"  => "Statistiques utilisateur",
+"sitestatstext" => "La base de données contient actuellement <b>$1</b> pages.
+
+Ce chiffre inclut les pages \"discussion\", les pages relatives à Wikipédia, les pages minimales (\"bouchons\"),  les pages de redirection, ainsi que d'autres pages qui ne peuvent sans doute pas être considérées comme des articles.
+Si l'on exclut ces pages, il reste <b>$2</b> pages qui sont probablement de véritables articles.<p>
+<b>$3</b> pages ont été consultées et <b>$4</b> pages modifiées
+
+depuis la mise à jour du logiciel (?? ???? 2002).
+Cela représente une moyenne de <b>$5</b> modifications par page et de <b>$6</b> consultations pour une modification.",
+"userstatstext" => "Il y a <b>$1</b> utilisateurs enregistrés.
+Parmi ceux-ci, <b>$2</b> ont le statut d'administrateur (voir $3).",
+
+
+# Maintenance Page
+#
+"maintenance"          => "Page de maintenance",
+"maintnancepagetext"   => "Cette page inclut plusieurs utilitaires pour la maintenance quotidienne. Certain de ces outils ont tendance à charger la base de données; ne rechargez pas la page a chaque modification.",
+//MQ "This page includes several handy tools for everyday maintenance. Some of these functions tend to stress the database, so please do not hit reload after every item you fixed ;-)",
+"maintenancebacklink"  => "Retour à la page de maintenance", // "Back to Maintenance Page",
+"disambiguations"      => "Pages d'homonymie", // Disambiguation pages",
+"disambiguationspage"  => "Wikipédia:Liens_aux_pages_d'homonymie", // "Wikipédia:Links_to_disambiguating_pages",
+"disambiguationstext"  => "Les articles suivants sont liés vers une <i>page d'homonymie</i>. Or, il devraient etre liés vers le sujet.<br>Une page est considerée comme page d'homonymie si elle est liée a partir de $1.<br>Les liens a partir de <i>namespace</i> ne sont pas considérés.", // "The following articles link to a <i>disambiguation page</i>. They should link to the appropriate topic instead.<br>A page is treated as dismbiguation if it is linked from $1.<br>Links from other namespaces are <i>not</i> listed here.",
+"doubleredirects"      => "Double redirection", // MQ
+"doubleredirectstext"  => "<b>Attention:</b> cette liste peut contenir des faux positives. Dans ce cas, c'est probablement la page du premier #REDIRECT qui a du texte en plus.<br>Chaque rangée contient des liens a la 1ere et 2e page de redirection, ainsi que la première ligne de cette derniere, qui donne normalement la \"vraie\" destination. Le premier #REDIRECT devrait lier vers cetter destination.", //"<b>Attention:</b> This list may contain false positives. That usually means there is additional text with links below the first #REDIRECT.<br>\nEach row contains links to the first and second redirect, as well as the first line of the second redirect text, usually giving the \"real\" taget article, which the first redirect should point to.",
+"selflinks"            => "Page avec un lien circulaire", // MQ "Pages with Self Links",
+"selflinkstext"                => "Les pages suivantes contiennent un lien sur elles-memes, ce qui n'est pas permis.",
+// MQ "The following pages contain a link to themselves, which they should not.",
+"missinglanguagelinks"  => "Liens interlangues manquants", //"Missing Language Links",
+"missinglanguagelinksbutton"    => "Je n'ai pas trouvé de lien/langage pour cette page", // MQ "Find missing language links for",
+"missinglanguagelinkstext"      => "Ces articles ne lient pas à leur 'contre-parties' in $1. Les redirections et les liens ne sont pas affichés.",
+// MQ "These articles do <i>not</i> link to their counterpart in $1. Redirects and subpages are <i>not</i> shown.",
+
+
+# Miscellaneous special pages
+#
+"orphans"  => "Pages orphelines",
+"lonelypages" => "Pages orphelines",
+"unusedimages" => "Images orphelines",
+"popularpages" => "Pages les plus consultées",
+"nviews"  => "$1 consultations",
+"wantedpages" => "Pages les plus demandées",
+"nlinks"  => "$1 références",
+"allpages"  => "Toutes les pages",
+"randompage" => "Une page au hasard",
+"shortpages" => "Articles courts",
+"longpages"  => "Articles longs",
+"listusers"  => "Liste des participants",
+"specialpages" => "Pages spéciales",
+"spheading"  => "Pages spéciales",
+"sysopspheading" => "Pages spéciales à l'usage des administrateurs",
+"developerspheading" => "Pages spéciales à l'usage des développeurs",
+"protectpage" => "Protéger la page",
+"recentchangeslinked" => "Suivi des liens",
+"rclsub"  => "(des pages liées à \"$1\")",
+"debug"   => "Déboguer",
+"newpages"  => "Nouvelles pages",
+"movethispage" => "Déplacer la page",
+"unusedimagestext" => "<p>N'oubliez pas que d'autres sites, comme certaines Wikipédias non francophones, peuvent contenir un lien direct vers cette image, et que celle-ci peut être placée dans cette liste alors qu'elle est en réalité utilisée.",
+"booksources" => "Ouvrages de référence",
+"booksourcetext" => "Voici une liste de liens vers d'autres sites qui vendent des livres neufs et d'occasion et sur lesquels vous trouverez peut-être des informations sur les livres que vous cherchez. Wikipédia n'est liée à aucune de ces sociétés, et il n'y a aucune intention à en faire les objets d'une préférence particulière.",
+
+# Email this user
+#
+"mailnologin" => "Pas d'adresse",
+"mailnologintext" => "Vous devez être <a href=\"" .
+               wfLocalUrl( "Special:Userlogin" ) . "\">connecté</a>
+et avoir indiqué une adresse électronique valide dans vos <a href=\"" .
+               wfLocalUrl( "Special:Preferences" ) . "\">préférences</a>
+pour pouvoir envoyer un message à un autre utilisateur.",
+"emailuser"  => "Envoyer un message à cet utilisateur",
+"emailpage"  => "E-mail user",
+"emailpagetext" => "Si cet utilisateur a indiqué une adresse électronique valide dans ses préférences, le formulaire ci-dessous lui enverra un message.
+L'adresse électronique que vous avez indiquée dans vos préférences apparaîtra dans le champ \"Expéditeur\" de votre message, afin que le destinataire puisse vous répondre.",
+"noemailtitle" => "Pas d'adresse électronique",
+"noemailtext" => "Cet utilisateur n'a pas spécifié d'adresse électronique valide ou a choisi de ne pas recevoir de courrier électronique des autres utilisateurs.",
+
+"emailfrom"  => "Expéditeur",
+"emailto"  => "Destinataire",
+"emailsubject" => "Objet",
+"emailmessage" => "Message",
+"emailsend"  => "Envoyer",
+"emailsent"  => "Message envoyé",
+"emailsenttext" => "Votre message a été envoyé.",
+
+# Watchlist
+#
+"watchlist"  => "Liste de suivi",
+"watchlistsub" => "(pour l'utilisateur \"$1\")",
+"nowatchlist" => "Votre liste de suivi ne contient aucun article.",
+"watchnologin" => "Non connecté",
+"watchnologintext" => "Vous devez être <a href=\"" .
+               wfLocalUrl( "Special:Userlogin" ) . "\">connecté</a>
+pour modifier votre liste.",
+"addedwatch" => "Ajouté à la liste",
+"addedwatchtext" => "La page \"$1\" a été ajoutée à votre <a href=\"" .
+               wfLocalUrl( "Special:Watchlist" ) . "\">liste de suivi</a>.
+Les prochaines modifications de cette page et de la page discussion associée seront répertoriées ici, et la page apparaîtra <b>en gras</b> dans la <a href=\"" .
+               wfLocalUrl( "Special:Recentchanges" ) . "\">liste des modifications récentes</a> pour être repérée plus facilement.</p>
+
+<p>Pour supprimer cette page de votre liste de suivi, cliquez sur \"Ne plus suivre\" dans le cadre de navigation.",
+"removedwatch" => "Supprimé de la liste de suivi",
+"removedwatchtext" => "La page \"$1\" a été supprimée de votre liste de suivi.",
+"watchthispage" => "Suivre cette page",
+"unwatchthispage" => "Ne plus suivre",
+"notanarticle" => "Aucun article",
+
+# Delete/protect/revert
+#
+"deletepage" => "Supprimer une page",
+"confirm"  => "Confirmer",
+"confirmdelete" => "Confirmer la suppression",
+"deletesub"  => "(Suppression de \"$1\")",
+"confirmdeletetext" => "Vous êtes sur le point de supprimer définitivement de la base de données une page
+ou une image, ainsi que toutes ses versions antérieures.
+Veuillez confirmer que c'est bien là ce que vous voulez faire, que vous en comprenez les conséquences et que vous faites cela en accord avec les [[Wikipédia:Recommandations Et Règles à  Suivre|recommandations et règles à suivre]].",
+"confirmcheck" => "Oui, je confirme la suppression.",
+"actioncomplete" => "Suppression effectuée",
+"deletedtext" => "\"$1\" a été supprimé.
+Voir $2 pour une liste des suppressions récentes.",
+"deletedarticle" => "effacement de \"$1\"",
+"dellogpage" => "Deletion_log",
+"dellogpagetext" => "Voici la liste des suppressions récentes.
+L'heure indiquée est celle du serveur (UTC).
+<ul>
+</ul>
+",
+"deletionlog" => "trace des effacements", // MQ "deletion log",
+"reverted"  => "Rétablissement de la version précédente",
+"deletecomment" => "Motif de la suppression",
+"imagereverted" => "La version précédente a été rétablie.",
+"rollback"     => "révoquer modifications",
+"rollbacklink" => "révoquer",
+"cantrollback" => "Impossible de révoquer: dernier auteur est le seul à avoir modifié cet article",
+"revertpage"   => "restitution de la dernière modification de $1",
+
+# Undelete
+"undelete" => "Restaurer la page effacée", // MQ "Restore deleted page",
+"undeletepage" => "Voir et restaurer la page effacée", // MQ "View and restore deleted pages",
+"undeletepagetext" => "Cette page viens d'etre effacée et mise dans la corbeille,  elle est toujours en base de donnée et peut etre restaurée.
+La corbeille peut etre effacée periodiquement.", // MQ
+"The following pages have been deleted but are still in the archive and can be restored. The archive may be periodically cleaned out.",
+"undeletearticle" => "Restaurer les articles effacés", // MQ "Restore deleted article",
+"undeleterevisions" => "$1 revisions archived",
+"undeletehistory" => "If you restore the page, all revisions will be restored to the history.
+If a new page with the same name has been created since the deletion, the restored
+revisions will appear in the prior history, and the current revision of the live page
+will not be automatically replaced.",
+"undeleterevision" => "Deleted revision as of $1",
+"undeletebtn" => "Restore!",
+"undeletedarticle" => "restored \"$1\"",
+"undeletedtext"   => "The article [[$1]] has been successfully restored.
+See [[Wikipedia:Deletion_log]] for a record of recent deletions and restorations.",
+
+# Contributions
+#
+"contributions" => "Contributions",
+"mycontris" => "Mes contributions",
+"contribsub" => "Pour $1",
+"nocontribs" => "Aucune modification correspondant à ces critères n'a été trouvée.",
+"ucnote"  => "Voici les <b>$1</b> dernières modifications effectuées par cet utilisateur au cours des <b>$2</b> derniers jours.",
+"uclinks"  => "Afficher les $1 dernières modifications; afficher les $2 derniers jours.",
+
+# What links here
+#
+"whatlinkshere" => "Pages liées",
+"notargettitle" => "Pas de cible",
+"notargettext" => "Indiquez une page cible ou un utilisateur cible.",
+"linklistsub" => "(Liste de liens)",
+"linkshere"  => "Les pages ci-dessous contiennent un lien vers celle-ci:",
+"nolinkshere" => "Aucune page ne contient de lien vers celle-ci.",
+"isredirect" => "page de redirection",
+
+# Block/unblock IP
+#
+
+"blockip"  => "Bloquer une adresse IP",
+"blockiptext" => "Utilisez le formulaire ci-dessous pour bloquer l'accès en écriture à partir d'une adresse IP donnée.
+Une telle mesure ne doit être prise que pour empêcher le vandalisme et en accord avec [[Wikipédia:Recommandations Et Règles à Suivre|recommandations et règles à suivre]].
+Donnez ci-dessous une raison précise (par exemple en indiquant les pages qui ont été vandalisées).",
+"ipaddress"  => "Adresse IP",
+"ipbreason"  => "Motif",
+"ipbsubmit"  => "Bloquer cette adresse",
+"badipaddress" => "L'adresse IP n'est pas correcte.",
+"noblockreason" => "Vous devez indiquer le motif du blocage.",
+"blockipsuccesssub" => "Blocage réussi",
+"blockipsuccesstext" => "L'adresse IP \"$1\" a été bloquée.
+<br>Vous pouvez consulter sur cette [[Special:Ipblocklist|page]] la liste des adresses IP bloquées.",
+"unblockip"  => "Débloquer une adresse IP",
+"unblockiptext" => "Utilisez le formulaire ci-dessous pour rétablir l'accès en écriture
+à partir d'une adresse IP précédemment bloquée.",
+"ipusubmit"  => "Débloquer cette adresse",
+"ipusuccess" => "Adresse IP \"$1\" débloquée",
+"ipblocklist" => "Liste des adresses IP bloquées",
+"blocklistline" => "$1, $2 a bloqué $3",
+"blocklink"  => "bloquer",
+"unblocklink" => "débloquer",
+"contribslink" => "contribs",
+
+
+# Developer tools
+#
+"lockdb"  => "Verrouiller la base",
+"unlockdb"  => "Déverrouiller la base",
+"lockdbtext" => "Le verrouillage de la base de données empêchera tous les utilisateurs de modifier des pages, de sauvegarder leurs préférences, de modifier leur liste de suivi et d'effectuer toutes les autres opérations nécessitant des modifications dans la base de données.
+Veuillez confirmer que c'est bien là ce que vous voulez faire et que vous débloquerez la base dès que votre opération de maintenance sera terminée.",
+"unlockdbtext" => "Le déverrouillage de la base de données permettra à nouveau à tous les utilisateurs de modifier des pages, de mettre à jour leurs préférences et leur liste de suivi, ainsi que d'effectuer les autres opérations nécessitant des modifications dans la base de données.
+Veuillez confirmer que c'est bien là ce que vous voulez faire.",
+"lockconfirm" => "Oui, je confirme que je souhaite verrouiller la base de données.",
+"unlockconfirm" => "Oui, je confirme que je souhaite déverrouiller la base de données.",
+
+"lockbtn"  => "Verrouiller la base",
+"unlockbtn"  => "Déverrouiller la base",
+"locknoconfirm" => "Vous n'avez pas coché la case de confirmation.",
+"lockdbsuccesssub" => "Verrouillage de la base réussi.",
+"unlockdbsuccesssub" => "Base déverrouillée.",
+"lockdbsuccesstext" => "La base de données de Wikipédia est verrouillée.
+
+<br>N'oubliez pas de la déverrouiller lorsque vous aurez terminé votre opération de maintenance.",
+"unlockdbsuccesstext" => "La base de données de Wikipédia est déverrouillée.",
+
+# SQL query
+#
+"asksql"  => "Requête SQL",
+"asksqltext" => "Utilisez le formulaire ci-dessous pour faire une requête directe sur la base de données de Wikipédia.
+Utilisez des guillemets simples ('comme ceci') pour délimiter les chaînes de caractères.
+Cette opération peut surcharger considérablement le serveur, faites en usage
+avec modération.",
+"sqlquery"  => "Saisir la requête",
+
+"querybtn"  => "Envoyer la requête",
+"selectonly" => "Les requêtes autres que \"SELECT\" sont réservées aux développeurs de
+Wikipédia.",
+"querysuccessful" => "Requête réussie",
+
+# Move page
+#
+"movepage"  => "Déplacer un article",
+"movepagetext" => "Utilisez le formulaire ci-dessous pour renommer un article, en déplaçant toutes ses versions antérieures vers le nouveau nom.
+Le titre précédent deviendra une page de redirection vers le nouveau titre.
+Les liens vers l'ancien titre ne seront pas modifiés et la page discussion, si elle existe, ne sera pas déplacée.<br>
+<b>ATTENTION!</b>
+Il peut s'agir d'un changement radical et inattendu pour un article souvent consulté;
+assurez-vous que vous en comprenez bien les conséquences avant de procéder.",
+"movearticle" => "Déplacer l'article",
+"movenologin" => "Non connecté",
+"movenologintext" => "Pour pouvoir déplacer un article, vous devez être <a href=\"" .
+               wfLocalUrl( "Special:Userlogin" ) . "\">connecté</a>
+en tant qu'utilisateur enregistré.",
+"newtitle"  => "Nouveau titre",
+"movepagebtn" => "Déplacer l'article",
+"pagemovedsub" => "Déplacement réussi",
+"pagemovedtext" => "L'article \"[[$1]]\" a été déplacé vers \"[[$2]]\".",
+"articleexists" => "Il existe déjà un article portant ce titre, ou le titre que vous avez choisi n'est pas valide.
+Veuillez en choisir un autre.",
+"movedto"  => "déplacé vers",
+"movetalk"  => "Déplacer aussi la page \"discussion\", s'il y a lieu.",
+"talkpagemoved" => "La page discussion correspondante a également été déplacée.",
+"talkpagenotmoved" => "La page discussion correspondante n'a <strong>pas</strong> été déplacée.",
+
+);
+
+class LanguageFr extends Language {
+
+       function getNamespaces() {
+               global $wgNamespaceNamesFr;
+               return $wgNamespaceNamesFr;
+       }
+
+
+       function getNsText( $index ) {
+               global $wgNamespaceNamesFr;
+               return $wgNamespaceNamesFr[$index];
+       }
+
+       function getNsIndex( $text ) {
+               global $wgNamespaceNamesFr;
+
+               foreach ( $wgNamespaceNamesFr as $i => $n ) {
+                if ( 0 == strcasecmp( $n, $text ) ) { return $i; }
+               }
+               if( 0 == strcasecmp( "Wikipedia", $text ) ) return 4;
+               if( 0 == strcasecmp( "Discussion_Wikipedia", $text ) ) return 5;
+               return false;
+       }
+
+       function specialPage( $name ) {
+               return $this->getNsText( Namespace::getSpecial() ) . ":" . $name;
+       }
+
+       function getQuickbarSettings() {
+               global $wgQuickbarSettingsFr;
+               return $wgQuickbarSettingsFr;
+       }
+
+       function getSkinNames() {
+               global $wgSkinNamesFr;
+               return $wgSkinNamesFr;
+       }
+
+       function getUserToggles() {
+               global $wgUserTogglesFr;
+               return $wgUserTogglesFr;
+       }
+
+       function getLanguageName( $code ) {
+               global $wgLanguageNamesFr;
+               if ( ! array_key_exists( $code, $wgLanguageNamesFr ) ) {
+                return "";
+               }
+               return $wgLanguageNamesFr[$code];
+       }
+
+       function getMonthName( $key )
+       {
+               global $wgMonthNamesFr;
+               return $wgMonthNamesFr[$key-1];
+       }
+
+       function getMonthAbbreviation( $key )
+       {
+               global $wgMonthAbbreviationsFr;
+               return $wgMonthAbbreviationsFr[$key-1];
+       }
+
+       function getWeekdayName( $key )
+       {
+               global $wgWeekdayNamesFr;
+               return $wgWeekdayNamesFr[$key-1];
+       }
+
+       # Inherit userAdjust()
+
+       function date( $ts, $adj = false )
+       {
+               if ( $adj ) { $ts = $this->userAdjust( $ts ); }
+
+               $d = (0 + substr( $ts, 6, 2 )) . " " .
+                 $this->getMonthAbbreviation( substr( $ts, 4, 2 ) ) .
+                 " " . substr( $ts, 0, 4 );
+               return $d;
+       }
+
+       function time( $ts, $adj = false )
+       {
+               if ( $adj ) { $ts = $this->userAdjust( $ts ); }
+
+               $t = substr( $ts, 8, 2 ) . ":" . substr( $ts, 10, 2 );
+               return $t;
+       }
+
+       function timeanddate( $ts, $adj = false )
+       {
+               return $this->date( $ts, $adj ) . " à " . $this->time( $ts, $adj );
+       }
+
+       function getValidSpecialPages()
+       {
+               global $wgValidSpecialPagesFr;
+               return $wgValidSpecialPagesFr;
+       }
+
+       function getSysopSpecialPages()
+       {
+               global $wgSysopSpecialPagesFr;
+               return $wgSysopSpecialPagesFr;
+       }
+
+       function getDeveloperSpecialPages()
+       {
+               global $wgDeveloperSpecialPagesFr;
+               return $wgDeveloperSpecialPagesFr;
+       }
+
+       function getMessage( $key )
+       {
+               global $wgAllMessagesFr, $wgAllMessagesEn;
+               $m = $wgAllMessagesFr[$key];
+
+               if ( "" == $m ) { return $wgAllMessagesEn[$key]; }
+               else return $m;
+
+       }
+}
+
+?>
diff --git a/languages/LanguageIt.php b/languages/LanguageIt.php
new file mode 100644 (file)
index 0000000..377dcaf
--- /dev/null
@@ -0,0 +1,891 @@
+<?
+
+# NOTE: To turn off "Current Events" in the sidebar,
+# set "currentevents" => "-"
+
+# The names of the namespaces can be set here, but the numbers
+# are magical, so don't change or move them!  The Namespace class
+# encapsulates some of the magic-ness.
+#
+/* private */ $wgNamespaceNamesIt = array(
+       -1      => "Speciale",
+       0       => "",
+       1       => "Discussione",
+       2       => "Utente",
+       3       => "Utente_discussioni",
+       4       => "Wikipedia",
+       5       => "Wikipedia_discussioni",
+       6       => "Immagine",
+       7       => "Immagine_discussione"
+);
+
+/* private */ $wgDefaultUserOptionsIt = array(
+       "quickbar" => 1, "underline" => 1, "hover" => 1,
+       "cols" => 80, "rows" => 25, "searchlimit" => 20,
+       "contextlines" => 5, "contextchars" => 50,
+       "skin" => 0, "math" => 1, "rcdays" => 7, "rclimit" => 50,
+       "highlightbroken" => 1, "stubthreshold" => 0
+);
+
+/* private */ $wgQuickbarSettingsIt = array(
+       "Nessuno", "Fisso a sinistra", "Fisso a destra", "Fluttuante a sinistra"
+);
+
+/* private */ $wgSkinNamesIt = array(
+       "Standard", "Nostalgia", "Cologne Blue"
+);
+
+/* private */ $wgUserTogglesIt = array(
+       "hover"         => "Mostra etichetta sui wiki-links",
+       "underline" => "Sottolinea links",
+       "highlightbroken" => "Evidenzia i links che puntano ad<br>articoli ancora da scrivere",
+       "justify"       => "Paragrafo: giustificato",
+       "hideminor" => "Nascondi le modifiche minori<br>nella pagina \"Modifiche recenti\"",
+       "numberheadings" => "Auto-numerazione dei<br>titoli di paragrafo",
+       "rememberpassword" => "Ricorda la password<br>(non limitare a una sessione<br>- richiede uso di cookies)",
+       "editwidth" => "Casella di edizione ampliata<br>alla massima larghezza",
+       "editondblclick" => "Doppio click per modificare l'articolo<br>(richiede JavaScript)",
+       "watchdefault" => "Notifica articoli nuovi e modificati",
+       "minordefault" => "Indica ogni modifica come minore<br>(solo come predefinito)"
+       
+);
+
+/* These should be localized... any Italian online bookstores take ISBN searches? */
+/* private */ $wgBookstoreListIt = array(
+       "AddALL" => "http://www.addall.com/New/Partner.cgi?query=$1&type=ISBN",
+       "PriceSCAN" => "http://www.pricescan.com/books/bookDetail.asp?isbn=$1",
+       "Barnes & Noble" => "http://shop.barnesandnoble.com/bookSearch/isbnInquiry.asp?isbn=$1",
+       "Amazon.com" => "http://www.amazon.com/exec/obidos/ISBN=$1"
+);
+
+/* Just inherit the (mostly) native-language plus latinized formed */
+/* private */ $wgLanguageNamesIt = $wgLanguageNamesEn;
+
+/* private */ $wgWeekdayNamesIt = array(
+       "Domenica", "Lunedì", "Martedì", "Mercoledì", "Giovedì",
+       "Venerdì", "Sabato"
+);
+
+/* private */ $wgMonthNamesIt = array(
+       "Gennaio", "Febbraio", "Marzo", "Aprile", "Maggio", "Giugno",
+       "Luglio", "Agosto", "Settembre", "Ottobre", "Novembre",
+       "Dicembre"
+);
+
+/* private */ $wgMonthAbbreviationsIt = array(
+       "Gen", "Feb", "Mar", "Apr", "Mag", "Giu", "Lug", "Ago",
+       "Set", "Ott", "Nov", "Dic"
+);
+
+# All special pages have to be listed here: a description of ""
+# will make them not show up on the "Special Pages" page, which
+# is the right thing for some of them (such as the "targeted" ones).
+#
+/* private */ $wgValidSpecialPagesIt = array(
+       "Userlogin"             => "", # These two intentionally left blank
+       "Userlogout"    => "", #...
+       "Preferences"   => "Preferenze",
+       "Watchlist"             => "Osservati Speciali",
+       "Recentchanges" => "Ultime modifiche",
+       "Upload"                => "Salva immagini",
+       "Imagelist"             => "Elenco Immagini",
+       "Listusers"             => "Utenti registrati",
+       "Statistics"    => "Statistiche",
+       "Randompage"    => "Una pagina a caso",
+
+       "Lonelypages"   => "Articoli orfani",
+       "Unusedimages"  => "Immagini orfane",
+       "Popularpages"  => "Articoli più letti",
+       "Wantedpages"   => "Articoli più richiesti",
+       "Shortpages"    => "Articoli più corti",
+       "Longpages"             => "Articoli più lunghi",
+       "Newpages"              => "Articoli nuovi",
+       "Allpages"              => "Tutti i titoli",
+
+       "Ipblocklist"   => "Indirizzi IP bloccati",
+       "Maintenance" => "Manutenzioni",
+       "Specialpages"  => "", # From here on intentionally left blank!
+       "Contributions" => "",
+       "Emailuser"             => "",
+       "Whatlinkshere" => "",
+       "Recentchangeslinked" => "",
+       "Movepage"              => "",
+       "Booksources"   => ""
+);
+
+/* private */ $wgSysopSpecialPagesIt = array(
+       "Blockip"               => "Blocca indirizzo IP",
+       "Asksql"                => "Interroga database",
+       "Undelete"              => "Leggi e ripara pagine cancellate"
+);
+
+/* private */ $wgDeveloperSpecialPagesIt = array(
+       "Lockdb"                => "Rendi il database read-only (di sola lettura, blocca le modifiche)",
+       "Unlockdb"              => "Ripristina scrittura su database (lettura\/scrittura)",
+       "Debug"                 => "Informazioni per il Debugging"
+);
+
+/* private */ $wgAllMessagesIt = array(
+
+# Bits of text used by many pages:
+#
+"linktrail"            => "/^([a-z]+)(.*)\$/sD",
+"mainpage"             => "Wikipedia",
+"about"                        => "A proposito di ",
+"aboutwikipedia" => "A proposito di Wikipedia",
+"aboutpage"            => "Wikipedia:About",
+"help"                 => "Aiuto",
+"helppage"             => "Wikipedia:Aiuto",
+"wikititlesuffix" => "Wikipedia",
+"bugreports"   => "Malfunzionamenti",
+"bugreportspage" => "Wikipedia:Malfunzionamenti",
+"faq"                  => "FAQ",
+"faqpage"              => "Wikipedia:FAQ",
+"edithelp"             => "Guida",
+"edithelppage" => "Wikipedia:Come_scrivere_un_articolo",
+"cancel"               => "Cancella",
+"qbfind"               => "Trova",
+"qbbrowse"             => "Sfoglia",
+"qbedit"               => "Modifica",
+"qbpageoptions" => "Opzioni pagina",
+"qbpageinfo"   => "Informazioni sulla pagina",
+"qbmyoptions"  => "Le mie opzioni",
+"mypage"               => "La mia pagina",
+"mytalk"               => "Le mie discussioni",
+"currentevents" => "Attualità",
+"errorpagetitle" => "Errore",
+"returnto"             => "Torna a $1.",
+"fromwikipedia"        => "Da Wikipedia, l'enciclopedia libera.",
+"whatlinkshere"        => "Pagine che linkano questa",
+"help"                 => "Aiuto",
+"search"               => "Cerca",
+"history"              => "Versioni precedenti",
+"printableversion" => "Versione stampabile",
+"editthispage" => "Modifica articolo",
+"deletethispage" => "Cancella pagina",
+"protectthispage" => "Proteggi pagina",
+"unprotectthispage" => "Togli protezione",
+"talkpage"             => "Discussione",
+"articlepage"  => "Vedi articolo",
+"subjectpage"  => "Vedi articolo ", # For compatibility
+"userpage" => "Vedi pagina Utente",
+"wikipediapage" => "Vedi pagina meta ",
+"imagepage" =>         "Pagina immagine",
+"otherlanguages" => "Altre lingue",
+"redirectedfrom" => "(Reindirizzamento da $1)",
+"lastmodified" => "Ultima modifica il $1.",
+"viewcount"            => "Questo articolo è stato letto $1 volte.",
+"gnunote" => "Questa pagina è disponibile con licenza <a class=internal href='/wiki/GNU_FDL'>GNU FDL</a>.",
+"printsubtitle" => "(Articolo di http://www.wikipedia.org)",
+"protectedpage" => "Pagina protetta",
+"administrators" => "Wikipedia:Amministratori",
+"sysoptitle"   => "Riservato Sysop",
+"sysoptext"            => "Questa operazione può essere eseguita solo da Utenti con grado di \"sysop\".
+Vedi $1.",
+"developertitle" => "Riservato agli sviluppatori",
+"developertext"        => " Questa operazione può essere eseguita solo da Utenti con grado di \"developer\".
+Vedi $1.",
+"nbytes"               => "$1 bytes",
+"go"                   => "Vai",
+"ok"                   => "OK",
+"sitetitle"            => "Wikipedia",
+"sitesubtitle" => "L'Enciclopedia libera",
+"retrievedfrom" => "Ricavato da  \"$1\"",
+
+# Main script and global functions
+#
+"nosuchaction" => "Operazione non riconosciuta",
+"nosuchactiontext" => "L'operazione richiesta con la URL immessa non è stata riconosciuta dal software di Wikipedia",
+"nosuchspecialpage" => "Nessuna simile pagina speciale è disponibile",
+"nospecialpagetext" => "Hai richiesto una pagina speciale che non è stata riconosciuta dal software di Wikipedia, o che non è disponibile.",
+
+# General errors
+#
+"error"                        => "Errore",
+"databaseerror" => "Errore del database ",
+"dberrortext"  => "Errore di sintassi nella richiesta inoltrata al database.<br>Potrebbe trattarsi di una richiesta non consentita (vedi $5), oppure potrebbe esserci un errore software.<br>
+L'ultima richiesta inoltrata al database è stata:<br>
+<blockquote><tt>$1</tt></blockquote>
+dalla funzione \"<tt>$2</tt>\".<br>
+MySQL ha restituito un errore \"<tt>$3: $4</tt>\".",
+"noconnect"            => "Connessione al database fallita su $1",
+"nodb"                 => "Selezione del database $1 fallita",
+"readonly"             => "Accesso al database temporaneamente disabilitato",
+"enterlockreason" => "Fornisci una spiegazione sui motivi del blocco, includendo le probabili data ed ora di riattivazione o di rimozione del blocco.",
+"readonlytext" => "Il database di Wikipedia è al momento bloccato, e non consente nuove immissioni né modifiche, molto probabilmente per manutenzione server, nel qual caso il database sarà presto di nuovo completamente accessibile.<br>
+L'amministratore di sistema che ha imposto il blocco, ha lasciato questa nota:
+<p>:$1",
+"missingarticle" => "Il database non ha trovato il testo di una pagina, che invece avrebbe dovuto trovare, intitolata \"$1\".<br>
+Questo non è un errore del database, ma più probabilmente un problema del software.<br>
+Per favore, segnalate l'accaduto ad un amministratore di sistema, segnalando la URL e l'ora dell'incidente.",
+"internalerror" => "Errore interno",
+"filecopyerror" => "Non è stato possibile copiare il file \"$1\" come \"$2\".",
+"filerenameerror" => "Non è stato possibile rinominare il file \"$1\" in \"$2\".",
+"filedeleteerror" => "Non è stato possibile cancellare il file \"$1\".",
+"filenotfound" => " Non è stato possibile trovare il file \"$1\".",
+"unexpected"   => "Valore imprevisto: \"$1\"=\"$2\".",
+"formerror"            => "Errore: il modulo non è stato inviato correttamente",       
+"badarticleerror" => "Questa operazione non è consentita su questa pagina.",
+"cannotdelete" => "Impossibile cancellare la pagina o l'immagine richiesta.",
+"badtitle"             => "Titolo non corretto",
+"badtitletext" => "La pagina richiesta non è disponibile, potrebbe essere non valida, vuota, o potrebbe trattarsi di un errore in un link interlinguistico o fra diverse versioni di Wikipedia.",
+"perfdisabled" => "Siamo davvero rammaricati, ma questa funzionalità è temporaneamente disabilitata durante le ore di maggiore accesso al database, per ragioni di accessibilità al resto del sito!<br>Torna fra le 02:00 e le 14:00 UTC e riprova.<br><br>Grazie.",
+
+# Login and logout pages
+#
+"logouttitle"  => "Logout Utente",
+"logouttext"   => "Logout effettuato.
+Ora puoi continuare ad usare Wikipedia come utente anonimo (ma il tuo indirizzo IP resterà riconoscibile), oppure puoi nuovamente richiedere il login con il precedente username, oppure come uno diverso.\n",
+
+"welcomecreation" => "<h2>Benvenuto, $1!</h2><p>Il tuo account è stato creato con successo.<br>Grazie per aver scelto di far crescere Wikipedia con il tuo aiuto.<br>Per rendere Wikipedia più tua, e per usarla più scorrevolmente, non dimenticare di personalizzare le tue preferenze.",
+
+"loginpagetitle" => "Login",
+"yourname"             => "Il tuo  user name",
+"yourpassword" => "La tua  password",
+"yourpasswordagain" => "Ripeti la password",
+"newusersonly" => " (solo per nuovi Utenti)",
+"remembermypassword" => "Ricorda la mia password per più sessioni (richiede uso dei cookies).",
+"loginproblem" => "<b>Si è verificato un errore durante il tuo tentativo di login.</b><br>Riprova, sarai più fortunato!",
+"alreadyloggedin" => "<font color=red><b>Ehi, Utente $1, hai già fatto il login, sei già connesso al nostro server!</b></font><br>\n",
+
+"areyounew"            => "Se sei nuovo in Wikipedia e desideri creare un nuovo user account, immetti uno user name (che sarà il tuo nome per Wikipedia), poi digita una password e ripetila nella casella successiva.<br> 
+Indicare un indirizzo e-mail non è obbligatorio, solo facoltativo (sebbene consigliato).<br>Se per caso perdessi la tua password, potrai richiedere che ti sia rispedita alla casella di posta elettronica che ci fornirai.<br>\n",
+
+"login"                        => "Log in",
+"userlogin"            => "Log in",
+"logout"               => "Log out",
+"userlogout"   => "Log out",
+"createaccount"        => "Crea nuovo account",
+"badretype"            => "Le password che hai immesso non coincidono, sono diverse fra loro.",
+"userexists"   => "Siamo spiacenti.<br>Lo user name che hai scelto è già usato da un altro Utente.<br>Ti preghiamo perciò di voler scegliere uno user name diverso.",
+"youremail"            => "La tua e-mail",
+"yournick"             => "Il tuo diminutivo o soprannome (per le firme)",
+"emailforlost" => "Se per caso ti dimenticassi della tua password, ne potresti ricevere una nuova di zecca presso la casella e-mail che ci hai indicato.",
+"loginerror"   => "Errore di Login",
+"noname"               => "Lo user name indicato non è valido, non è possibile creare un account a questo nome.",
+"loginsuccesstitle" => "Login effettuato con successo!",
+"loginsuccess" => "Sei stato ammesso alla connessione al server di Wikipedia con il nome utente di \"$1\".",
+"nosuchuser"   => "Attenzione<br><br>a seguito di verifica, non ci risulta alcun Utente con il nome di  \"$1\".<br><br>
+Controlla per favore il nome digitato, oppure usa il modulo qui sotto per creare un nuovo user account.",
+"wrongpassword"        => "La password immessa non è corretta.<br><br>Riprova, per favore.",
+"mailmypassword" => "Spediscimi una nuova password in posta elettronica",
+"passwordremindertitle" => "Servizio Password Reminder di Wikipedia",
+"passwordremindertext" => "Qualcuno (probabilmente tu, con indirizzo IP $1)
+ha richiesto l'invio di una nuova password per il login a Wikipedia. 
+La password per l'Utente \"$2\" è ora \"$3\".
+Per evidenti ragioni di sicurezza, dovresti fare un log in il prima possibile, e cambiare la password immediatamente.",
+"noemail"              => "Nessuna casella e-mail risulta registrata per l'Utente \"$1\".",
+"passwordsent" => "Una nuova password è stata inviata alla casella e-mail registrata per l'Utente \"$1\".
+Per favore, fai subito un log in non appena la ricevi.",
+
+# Edit pages
+#
+"summary"              => "Oggetto",
+"minoredit"            => "Questa è una modifica minore",
+"watchthis"            => "Tieni d'occhio questo articolo",
+"savearticle"  => "Salva la pagina",
+"preview"              => "Anteprima",
+"showpreview"  => "Visualizza Anteprima",
+"blockedtitle" => "Questo User name corrisponde purtroppo ad un Utente che è stato disabilitato alla modifica degli articoli.",
+"blockedtext"  => "Il tuo User name o il tuo indirizzo IP sono stati bloccati da $1.<br>
+La motivazione del blocco è la seguente:<br>:''$2''<p>Se lo desideri, puoi contattare $1, o uno degli altri [[Wikipedia:administrators|amministratori]] per discutere del blocco.",
+"newarticle"   => "(Nuovo)",
+"newarticletext" => "Scrivi qui il tuo testo.",
+"noarticletext" => "(Questo articolo è vuoto, potresti gentilmente iniziare l'articolo, oppure richiedere la cancellazione di questa pagina)",
+"updated"              => "(Aggiornato)",
+"note"                 => "<strong>NOTA:</strong> ",
+"previewnote"  => "Tieni presente che questa è solo una ANTEPRIMA, e che la tua versione NON è ancora stata salvata!",
+"previewconflict" => "Questa anteprima rappresenta il testo nella casella di edizione di sopra, l'articolo apparirà in questa forma se sceglierai di salvare la pagina ora.",
+"editing"              => "Modifica di $1",
+"editconflict" => "Conflitto di edizione: $1",
+"explainconflict" => "Qualcun altro ha salvato una sua versione dell'articolo nel tempo in cui tu stavi preparando la tua versione.<br>
+La casella di modifica di sopra contiene il testo dell'articolo nella sua forma attuale (cioè il testo attualmente online). Le tue modifiche sono invece contenute nella casella di modifica inferiore. 
+Dovrai inserire, se lo desideri, le tue modifiche nel testo esistente, e perciò scriverle nella casella di sopra. 
+<b>Soltanto</b> il testo nella casella di sopra sarà salvato se premerai il bottone \"Salva\".\n<p>",
+"yourtext"             => "Il tuo testo",
+"storedversion" => "Versione in archivio",
+"editingold"   => "<strong>ATTENZIONE: Stai modificando una versione dell'articolo non aggiornata.<br>
+Se la salvi così, tutti i cambiamenti apportati dopo questa revisione verranno persi per sempre.</strong>\n",
+"yourdiff"             => "Differenze",
+"copyrightwarning" => "Nota, per favore, che tutti i contributi a Wikipedia si considerano rilasciati sotto licenza di tipo GNU Free Documentation License (vedi $1 per maggiori dettagli).
+Se non vuoi che il tuo testo possa essere modificato e ridistribuito da chiunque senza pietà e senza altri limiti, allora non inviarlo a Wikipedia, ma realizza piuttosto un tuo sito web personale.<br>
+Con l'invio di questo testo stai garantendo, a tua responsabilità, che il testo è stato scritto da te personalmente ed originalmente, oppure che è stato copiato da una fonte di publico dominio, o da una simile fonte, oppure che hai ottenuto espressa autorizzazione ad usare questo testo e che puoi dimostrarlo.
+<strong>NON USARE MATERIALE COPERTO DA DIRITTO DI AUTORE (COPYRIGHT - (c)) IN MANCANZA DI ESPRESSA AUTORIZZAZIONE!!!</strong>",
+
+
+# History pages
+#
+"revhistory"   => "Cronologia delle versioni di questa pagina.",
+"nohistory"            => "Cronologia delle versioni di questa pagina non reperibile.",
+"revnotfound"  => "Versione non trovata ",
+"revnotfoundtext" => "La versione precedente di questo articolo che hai richiesto, non è stata trovata.
+Controlla per favore la URL che hai usato per accedere a questa pagina.\n",
+"loadhist"             => "Caricamento cronologia di questa pagina",
+"currentrev"   => "Versione attuale",
+"revisionasof" => "Revisione $1",
+"cur"                  => "corr",
+"next"                 => "succ",
+"last"                 => "prec",
+"orig"                 => "orig",
+"histlegend"   => "Legend: (corr) = differenze con la versione corrente,
+(prec) = differenze con la versione precedente, M = modifica minore",
+
+# Diffs
+#
+"difference"   => "(Differenze fra le revisioni)",
+"loadingrev"   => "caricamento revisione per differenze",
+"lineno"               => "Riga $1:",
+"editcurrent"  => "Modifica la versione corrente di questa pagina",
+
+# Search results
+#
+"searchresults" => "Risultato della ricerca",
+"searchhelppage" => "Wikipedia:Ricerca",
+"searchingwikipedia" => "Ricerca in Wikipedia",
+"searchresulttext" => "Per maggiori informazioni sulla ricerca interna di Wikipedia, vedi $1.",
+"searchquery"  => "Richiesta \"$1\"",
+"badquery"             => "Richiesta mal inoltrata ",
+"badquerytext" => "La tua richiesta non ha potuto essere processata.
+Questo potrebbe dipendere dall'aver ricercato una parola di meno di tre caratteri.
+Oppure potresti aver scritto male la richiesta, per esempio \"pesce and and azzurro\".
+Per favore, riprova.",
+"matchtotals"  => "La ricerca per la voce \"$1\" ha trovato<br>$2 riscontri nei titoli degli articoli e<br>$3 riscontri nei testi degli articoli.",
+"titlematches" => "Nei titoli degli articoli",
+"notitlematches" => "Voce richiesta non trovata in titoli di articolo",
+"textmatches"  => "Nel testo degli articoli ",
+"notextmatches"        => "Voce richiesta non trovata in testi di articolo",
+"prevn"                        => "precedenti $1",
+"nextn"                        => "successivi $1",
+"viewprevnext" => "Vedi ($1) ($2) ($3).",
+"showingresults" => "Qui di seguito <b>$1</b> risultati, partendo dal numero #<b>$2</b>.",
+"nonefound"            => "<strong>Nota</strong>: la ricerca di parole troppo comuni, come \"avere\" o \"essere\", che non sono indicizzate, può causare un esito negativo, così come indicare più di un termine da ricercare (solo le pagine che contengano tutti i termini ricercati verrebbero infatti visualizzate fra i risultati).",
+"powersearch" => "Ricerca",
+"powersearchtext" => "
+Cerca fra i campi :<br>
+$1<br>
+$2 Elenca i redirects &nbsp; cerca per $3 $9",
+
+
+# Preferences page
+#
+"preferences"  => "Preferenze",
+"prefsnologin" => "Non hai eseguito il login",
+"prefsnologintext"     => "Devi avere eseguito il <a href=\"" .
+  wfLocalUrl( "Special:Userlogin" ) . "\">login</a>
+per poter personalizzare le tue preferenze.",
+"prefslogintext" => "Sei connesso a Wikipedia come \"$1\".
+Il tuo numero identificativo (ID) interno è $2.",
+"prefsreset"   => "Le tue Preferenze sono state ripescate dalla memoria di sistema del potente server di Wikipedia.",
+"qbsettings"   => "Settaggio barra menu", 
+"changepassword" => "Cambia password",
+"skin"                 => "Aspetto",
+"saveprefs"            => "Salva preferenze",
+"resetprefs"   => "Resetta preferenze",
+"oldpassword"  => "Vecchia password",
+"newpassword"  => "Nuova password",
+"retypenew"            => "Riscrivi la nuova password",
+"textboxsize"  => "Dimensione della casella di edizione ",
+"rows"                 => "Righe",
+"columns"              => "Colonne",
+"searchresultshead" => "Settaggio preferenze di ricerca ",
+"resultsperpage" => "Risultati da visualizzare per pagina",
+"contextlines" => "Righe di testo per ciascun risultato",
+"contextchars" => "Caratteri per linea",
+"stubthreshold" => "Stub visualizzati",
+"recentchangescount" => "Numero titoli in \"modifiche recenti\" ",
+"savedprefs"   => "Le tue preferenze sono state salvate.",
+"timezonetext" => "Immetti il numero di ore di differenza fra la tua ora locale e la ora del server (UTC).",
+"localtime"    => "Ora Locale",
+"timezoneoffset" => "Offset",
+"emailflag"            => "Nascondi la mia e-mail<br>agli altri utenti",
+
+# Recent changes
+#
+"recentchanges" => "Ultime Modifiche",
+"recentchangestext" => "Segui in questa pagina le ultime modifiche apportate agli articoli di Wikipedia.
+[[Wikipedia:Welcome,_newcomers|Benvenuto]]!
+Leggi anche queste pagine: [[wikipedia:FAQ|Wikipedia FAQ]],
+[[Wikipedia:Policies and guidelines|la policy di Wikipedia]]
+(specialmente [[wikipedia:Convenzioni di nomenclatura| Convenzioni di nomenclatura]],
+[[wikipedia:Neutral point of view|oggettività e neutralità]]),
+e [[wikipedia:Most common Wikipedia faux pas|facili errori nell'uso di Wikipedia]].
+
+Se tieni al successo di questo progetto, è molto importante che eviti di immettere materiale coperto da diritti di autore ([[wikipedia:Copyrights|copyrights]]).
+Gli aspetti legali connessi potrebbero dare fastidio a noi ed a te personalmente, perciò controlla bene che quanto scrivi sia di [[pubblico dominio]], o prova ad ottenere le relative autorizzazioni, che in genere vengono concesse molto facilmente. Vedi anche [http://meta.wikipedia.org/wiki/Special:Recentchanges recent meta discussion].",
+"rcloaderr"            => "Caricamento modifiche recenti ",
+"rcnote"               => "Qui di seguito sono elencate le ultime <strong>$1</strong> pagine modificate negli ultimi <strong>$2</strong> giorni.",
+"rcnotefrom"   => " Qui di seguito sono elencate le modifiche da <b>$2</b> (fino a <b>$1</b>).",
+"rclistfrom"   => "Mostra modifiche a partire da $1",
+# "rclinks"            => "Mostra le ultime $1 modifiche nelle ultime $2 ore / negli ultimi $3 giorni",
+"rclinks"              => " Mostra le ultime $1 modifiche negli ultimi $2 giorni.",
+"rchide"               => "in $4 form; $1 modifiche minori; $2 namespaces secondari; $3 modifiche multiple.",
+"diff"                 => "diff",
+"hist"                 => "cron",
+"hide"                 => "nascondi",
+"show"                 => "mostra",
+"tableform"            => "tabella",
+"listform"             => "elenco",
+"nchanges"             => "$1 modifiche",
+"minoreditletter" => "m",
+"newpageletter" => "N",
+
+# Upload
+#
+"upload"               => "Upload",
+"uploadbtn"            => "Upload",
+"uploadlink"   => "Upload immagini",
+"reupload"             => "Ri-upload",
+"reuploaddesc" => "Torna al modulo per lo upload.",
+"uploadnologin" => "Devi fare il login per eseguire questa operazione.",
+"uploadnologintext"    => "Devi eseguire  <a href=\"" .
+  wfLocalUrl( "Special:Userlogin" ) . "\">il login</a>
+per fare lo upload di files.",
+"uploadfile"   => "Upload",
+"uploaderror"  => "Errore di Upload",
+"uploadtext"   => "<strong>FERMA!</strong> Prima di effettuare un upload su Wikipedia, accertati di avere ben letto e soprattutto compreso <a href=\"" .
+wfLocalUrlE( "Wikipedia:Image_use_policy" ) . "\">le regole di Wikipedia sull'uso delle immagini</a>.
+<p>Per visualizzare o cercare immagini precedentemente caricate su Wikipedia, vai alla <a href=\"" . wfLocalUrlE( "Special:Imagelist" ) .
+"\">lista delle immagini già caricate</a>.
+Uploads e cancellazioni delle immagini sono registrati nello <a href=\"" .
+wfLocalUrlE( "Wikipedia:Upload_log" ) . "\">upload log</a>.
+<p>Usa il modulo sottostante per caricare nuovi files immagine da utilizzare per arricchire ed illustrare i tuoi articoli.
+Sulla maggior parte dei browsers, dovresti vedere un bottone con la scritta \"Browse...\" (oppure \"Sfoglia...\", che aprirà una comune finestra di dialogo.<br>
+Scegliendo uno dei files sul tuo PC, il nome di questo file verrà scritto in automatico nella casella di testo a fianco al bottone.<p>
+'''Devi anche selezionare la casellina nella quale affermi che con questo upload non stai violando nessun copyright.'''<p>
+Premi poi il bottone \"Upload\" per completare il caricamento.
+Il caricamento può richiedere qualche minuto se hai una connessione ad Internet lenta, o se l'immagine è eccessivamente pesante (sconsigliato).
+<p>I formati immagine preferibili sono il JPEG per immagini fotografiche, il PNG
+per disegni ed altre immagini iconiche o simboliche, l' OGG per i suoni.
+Per cortesia, rinomina i tuoi files, prima di caricarli, usando un nome il più possibile descrittivo del contenuto, così da evitare confusioni. 
+Per inserire poi la nuova immagine in un articolo, usa semplicemente un link nella forma
+<b>[[image:file.jpg]]</b> o <b>[[image:file.png|alt text, testo alternativo]]</b>
+o <b>[[media:file.ogg]]</b> per i suoni.
+<p>Tieni presente che, come per tutte le pagine di Wikipedia, chiunque può modificare o sostituire o cancellare i tuoi files ove ritenga che ciò sia negli interessi della nostra enciclopedia. Tieni anche presente che, in caso di abuso, o di sovraccarico sul sistema, potresti essere bloccato (oltre ad essere perseguito per le connesse responsabilità).",
+"uploadlog"            => "upload log",
+"uploadlogpage" => "Upload_log",
+"uploadlogpagetext" => "Qui di seguito la lista degli ultimi files caricati sul server di Wikipedia.
+Tutti i tempi indicati sono calcolati sul fuso orario del server (UTC).
+<ul>
+</ul>
+",
+"filename"             => "Nome del file",
+"filedesc"             => "Oggetto",
+"affirmation"  => "Io dichiaro che il titolare dei diritti di autore (copyright, (c)) su questo file consente a cederlo in licenza di uso nei termini del $1.",
+"copyrightpage" => "Wikipedia:Copyrights",
+"copyrightpagename" => "Wikipedia copyright",
+"uploadedfiles"        => "Files Caricati in Wikipedia",
+"noaffirmation" => "Devi dichiarare che il caricamento di questo file non viola, in alcun modo, alcun tipo di diritto altrui, e segnatamente non infrange nessun diritto di autore (copyright - (c)).",
+"ignorewarning"        => "Ignora le avvertenze e salva comunque il file.",
+"minlength"            => "I nomi dei file immagine debbono essere lunghi almeno tre caratteri, ma è preferibile usare nomi lumghi, purché descrittìvi.",
+"badfilename"  => "Il nome del file immagine è stato convertito in \"$1\".",
+"badfiletype"  => "\".$1\" non è un tipo di file raccomandato per le immagini, almeno ai nostri fini.",
+"largefile"            => "Il peso raccomandato per le immagini deve essere inferiore a 100kb.",
+"successfulupload" => "Caricamento completato",
+"fileuploaded" => "File \"$1\" correttamente caricato sul server.
+Segui questo link: ($2) per modificare la pagina di descrizione del file che hai appena caricato, e immetti subito le informazioni che ritieni opportune (cosa rappresenta, dove lo hai trovato, chi lo ha creato e quando, etc) oltre ad una nota circa la situazione di copyright sul file.<br>Non omettere la nota sul copyright, o il file verrebbe cancellato molto presto. ",
+"uploadwarning" => "Avviso di Upload",
+"savefile"             => "Salva file",
+"uploadedimage" => "caricato \"$1\"",
+
+# Image list
+#
+"imagelist"            => "Lista delle immagini",
+"imagelisttext"        => "Qui di seguito una lista di $1 immagini, ordinate per $2.",
+"getimagelist" => "ricerca nella lista delle immagini ",
+"ilshowmatch"  => "Mostra tutte le immagini con nomi di file corrispondenti alla ricerca",
+"ilsubmit"             => "Cerca",
+"showlast"             => "Lista di $1, fra le ultime immagini, ordinate per $2.",
+"all"                  => "tutte",
+"byname"               => "nome",
+"bydate"               => "data",
+"bysize"               => "peso",
+"imgdelete"            => "canc",
+"imgdesc"              => "desc",
+"imglegend"            => "Legenda: (desc) = mostra/modifica descrizione immagine.",
+"imghistory"   => "Storia di questa immagine",
+"revertimg"            => "ripr",
+"deleteimg"            => "canc",
+"imghistlegend" => "Legenda: (cur) = immagine corrente, (canc) = cancella questa vecchia versione, (ripr) = ripristina questa vecchia versione come versione attuale.
+<br><i>Clicca su una data per vedere tutte le immagini che sono state caricate in quella data </i>.",
+"imagelinks"   => "Link alle immagini",
+"linkstoimage" => "Le pagine seguenti linkano questa immagine:",
+"nolinkstoimage" => "Nessuna pagina linka questa immagine.",
+
+# Statistics
+#
+"statistics"   => "Statistiche",
+"sitestats"            => "Statistiche del sito",
+"userstats"            => "Statistiche del nostro Wikipediano",
+"sitestatstext" => "Ci sono ben <b>$1</b> pagine nel database.
+Questa cifra comprende le pagine \"talk\" (discussione), pagine su Wikipedia, articoli esigui (\"stub\"), redirects, e altre pagine che probabilmente non andrebbero conteggiate fra gli articoli.
+Escludendo queste, ci sono ben  <b>$2</b> pagine che sono con buona probabilità propriamente degli articoli.<p>
+Ci sono state un totale di <b>$3</b> pagine viste, e <b>$4</b> modifiche agli articoli da quando il software è stato potenziato (Dicembre, 2002).
+Questa media rivela che ci sono state una media di  <b>$5</b> modifiche per ciascun articolo, e che l'articolo è stato letto <b>$6</b> volte per ciascuna modifica.",
+"userstatstext" => "Ci sono <b>$1</b> Utenti registrati ([[Wikipediani]]).
+<b>$2</b> di questi hanno il grado di amministratori (vedi $3).",
+
+# Maintenance Page
+#
+"maintenance"          => "Pagina manutenzioni",
+"maintnancepagetext"   => "In questa pagina sono elencati alcuni utili strumenti per una comoda manutenzione quotidiana della nostra enciclopedia. Alcune delle funzioni tendono a stressare il database, assorbendo molte risorse, perciò non fatene un uso continuo: non aggiornate le pagine (reload, refresh) subito dopo ogni singolo intervento. ;-)",
+"maintenancebacklink"  => "Torna alla pagina manutenzione",
+"disambiguations"      => "Disambiguation pages",
+"disambiguationspage"  => "Wikipedia:Links_to_disambiguating_pages",
+"disambiguationstext"  => "The following articles link to a <i>disambiguation page</i>. They should link to the appropriate topic instead.<br>A page is treated as dismbiguation if it is linked from $1.<br>Links from other namespaces are <i>not</i> listed here.",
+"doubleredirects"      => "Doppi Redirects",
+"doubleredirectstext"  => "<b>Attenzione:</b> Questa lista può talvolta contenere dei risultati non corretti. Ciò potrebbe magari accadere perchè vi sono del testo aggiuntivo o dei link dopo il tag #REDIRECT.<br>\nOgni riga contiene i link al primo ed al secondo redirect, oltre alla prima riga di testo del secondo redirect che di solito contiene il \"reale\" articolo di destinazione, quello al quale anche il primo redirect dovrebbe puntare.",
+"brokenredirects"      => "Redirects errati",
+"brokenredirectstext"  => "I seguenti redirects puntano ad articoli non ancora creati.",
+"selflinks"            => "Pagine con Auto-Links",
+"selflinkstext"                => "Le pagine seguenti contengono link che puntano a sé stesse, e in questo caso occorre eliminare questi auto-links.",
+"mispeelings"           => "Pagine con errori di ortografia ",
+"mispeelingstext"               => "Le pagine che seguono contengono errori comuni di ortografia, che sono elencati alla pagina $1. ",
+"mispeelingspage"       => "Lista di comuni errori di ortografia",
+"missinglanguagelinks"  => "Link interlinguistici mancanti",
+"missinglanguagelinksbutton"    => "Trova interlinks per ",
+"missinglanguagelinkstext"      => "Questi articoli <i>non</i> hanno link verso i corrispondenti articoli in $1. Redirects e sub-pagine <i>non</i> sono elencati.",
+
+
+# Miscellaneous special pages
+#
+"orphans"              => "Pagine orfane",
+"lonelypages"  => "Pagine solitarie",
+"unusedimages" => "Immagini non utilizzate",
+"popularpages" => "Pagine più viste",
+"nviews"               => "$1 visite",
+"wantedpages"  => "Articoli più richiesti",
+"nlinks"               => "$1 links",
+"allpages"             => "Tutte le pagine",
+"randompage"   => "Una pagina a caso",
+"shortpages"   => "Pagine corte",
+"longpages"            => "Pagine lunghe",
+"listusers"            => "Elenco degli Utenti",
+"specialpages" => "Pagine speciali",
+"spheading"            => "Pagine speciali",
+"sysopspheading" => "Pagine speciali riservate ai sysop",
+"developerspheading" => " Pagine speciali riservate ai developer",
+"protectpage"  => "Proteggi questa pagina ",
+"recentchangeslinked" => "Modifiche correlate",
+"rclsub"               => "(alle pagine linkate da \"$1\")",
+"debug"                        => "Debug",
+"newpages"             => "Pagine nuove",
+"movethispage" => "Sposta questa pagina",
+"unusedimagestext" => "<p>Nota che altri siti web, come la Wikipedia internazionale, potrebbero aver messo un link ad una immagine per mezzo di una URL diretta, perciò le immagini potrebbero essere listate qui, essendo inutilizzate in questa versione di Wikipedia, anche essendo magari in uso altrove.",
+"booksources"  => "Book sources",
+"booksourcetext" => "Below is a list of links to other sites that
+sell new and used books, and may also have further information
+about books you are looking for.
+Wikipedia is not affiliated with any of these businesses, and
+this list should not be construed as an endorsement.",
+
+# Email this user
+#
+"mailnologin"  => "No send address",
+"mailnologintext" => "Devi fare il  <a href=\"" .
+  wfLocalUrl( "Special:Userlogin" ) . "\">login</a>
+ed aver registrato una valida casella e-mail nelle tue <a href=\"" .
+  wfLocalUrl( "Special:Preferences" ) . "\">preferenze</a> per mandare posta elettronica ad altri Utenti.",
+"emailuser"            => "Manda una E-mail a questo Utente",
+"emailpage"            => "E-mail user",
+"emailpagetext"        => "Se questo Utente ha registrato una valida casella e-mail, il modulo qui sotto ti consentirà di scrivergli un solo messaggio.
+La e-mail che hai indicato nelle tue preferenze apparirà nel campo \"From\" della mail, così che il destinatario possa, solo se lo desidera però, risponderti.",
+"noemailtitle" => "Nessun indirizzo e-mail",
+"noemailtext"  => "Questo Utente non ha registrato alcuna casella e-mail, oppure ha scelto di non ricevere posta elettronica dagli altri Utenti.",
+"emailfrom"            => "Da",
+"emailto"              => "A",
+"emailsubject" => "Oggetto",
+"emailmessage" => "Messaggio",
+"emailsend"            => "Invia",
+"emailsent"            => "E-mail inviata",
+"emailsenttext" => "La tua e-mail è stata inviata.",
+
+# Watchlist
+#
+"watchlist"            => "Osservati Speciali",
+"watchlistsub" => "(per l'Utente \"$1\")",
+"nowatchlist"  => "Non hai indicato articoli da tenere d'occhio.",
+"watchnologin" => "Manca il login",
+"watchnologintext"     => "Devi prima fare il <a href=\"" .
+  wfLocalUrl( "Special:Userlogin" ) . "\">login</a>
+per modificare la tua lista di osservati speciali.",
+"addedwatch"   => "Aggiunto ai tuoi Osservati Speciali",
+"addedwatchtext" => " La pagina  \"$1\" è stata aggiunta alla tua <a href=\"" .
+  wfLocalUrl( "Special:Watchlist" ) . "\"> lista di osservati speciali </a>.
+Le future modifiche a questa pagina ed alla relativa pagina di discussione saranno elencate qui, e la pagina apparirà in <b>grassetto</b> nella pagina delle <a href=\"" .
+  wfLocalUrl( "Special:Recentchanges" ) . "\">modifiche recenti</a> per essere più facile da tener d'occhio.</p>
+
+<p>Se in seguito vorrai togliere questo articolo dalla tua lista di Osservati Speciali, clicca \" Smetti di seguire \" nella barra dei menu.",
+"removedwatch" => "Rimosso dalla lista degli Osservati Speciali",
+"removedwatchtext" => "La pagina  \"$1\" è stata rimossa dalla lista dei tuoi Osservati Speciali.",
+"watchthispage"        => "Segui questo articolo",
+"unwatchthispage" => "Smetti di seguire",
+"notanarticle" => "Non è un articolo",
+
+# Delete/protect/revert
+#
+"deletepage"   => "Cancella pagina",
+"confirm"              => "Conferma",
+"confirmdelete" => "Conferma cancellazione",
+"deletesub"            => "(Cancellazione di \"$1\")",
+"confirmdeletetext" => "Stai per cancellare permanentemente dal database una pagina o una immagine, insieme a tutta la sua cronologia.<p>
+Per cortesia, conferma che è tua intenzione procedere a tale cancellazione, conferma che hai piena consapevolezza delle conseguenze della tua azione, e conferma che la tua azione è pienamente ottemperante alle regole stabilite nella 
+[[Wikipedia:Policy]].",
+"confirmcheck" => "Sì, voglio davvero procedere con la cancellazione della pagina.",
+"actioncomplete" => "Azione completata",
+"deletedtext"  => "La pagina \"$1\" è stata cancellata.
+Vedi $2 per un elenco delle pagine cancellate di recente.",
+"deletedarticle" => "Cancellata \"$1\"",
+"dellogpage"   => "Deletion_log",
+"dellogpagetext" => "Qui di seguito, un elenco delle pagine cancellate di recente.
+Tutti i tempi sono in ora del server (UTC).
+<ul>
+</ul>
+",
+"deletionlog"  => "deletion log",
+"reverted"             => "Ripristinata versione precedente",
+"deletecomment"        => "Motivazione della cancellazione ",
+"imagereverted" => "Versione precedente correttamente ripristinata.",
+"rollback"             => "Usa una revisione precedente",
+"cantrollback" => "Impossibile tornare ad una versione precedente: l'ultima modifica è stata apportata dall'unico utente che abbia lavorato a questo articolo.",
+"revertpage"   => "Riportata alla revisione precedente da $1",
+
+# Undelete
+"undelete" => "Recupera una pagina cancellata",
+"undeletepage" => "Vedi e recupera pagine cancellate ",
+"undeletepagetext" => "Le pagine qui di seguito indicate sono state cancellate, ma sono ancora in archivio e pertanto possono essere recuperate. L'archivio viene svuotato periodicamente.",
+"undeletearticle" => "Recupera un articolo cancellato",
+"undeleterevisions" => "$1 revisioni in archivio",
+"undeletehistory" => "Se recuperi questo articolo, tutte le sue revisioni verranno recuperate nella relativa cronologia.<br>
+Se una nuova pagina è stata creata con questo stesso nome dopo la cancellazione, le revisioni recuperate saranno inserite nella cronologia e la versione attualmente online della pagina non verrà modificata.",
+"undeleterevision" => "Cancellata revisione $1",
+"undeletebtn" => "RIPRISTINA!",
+"undeletedarticle" => "Recuperata \"$1\"",
+"undeletedtext"   => "La pagina [[$1]] è stata recuperata.
+Vedi [[Wikipedia:Deletion_log]] per un elenco delle pagine cancellate e recuperate di recente.",
+
+# Contributions
+#
+"contributions"        => "Contributi di questo Utente",
+"contribsub"   => "Per $1",
+"nocontribs"   => "Nessuna modifica trovata conformemente a questi criteri.",
+"ucnote"               => "Qui sotto troverai le ultime <b>$1</b> modifiche effettuate da questo Utente negli ultimi <b>$2</b> giorni.",
+"uclinks"              => "Vedi le ultime $1 modifiche; vedi gli ultimi $2 giorni.",
+"uctop"                => " (ultima per la pagina)" ,
+
+# What links here
+#
+"whatlinkshere"        => "Pagine che linkano questa",
+"notargettitle" => "Dati mancanti",
+"notargettext" => "Non hai specificato una pagina o un Utente in relazione al quale eseguire l'operazione richiesta.",
+"linklistsub"  => "(Lista di links)",
+"linkshere"            => "Le seguenti pagine contengono link che puntano qui:",
+"nolinkshere"  => "Nessuna pagina contiene links che puntano a questa.",
+"isredirect"   => "redirect ",
+
+# Block/unblock IP
+#
+"blockip"              => "Blocca indirizzo IP",
+"blockiptext"  => "Usa il modulo sottostante per bloccare l'accesso con diritto di scrittura da uno specifico indirizzo IP.<br>
+Questo blocco deve essere operato SOLO per prevenire atti di vandalismo, ed in stretta osservanza dei principi tutti della [[Wikipedia:Policy|policy di Wikipedia]].<br>Il blocco non può in nessun caso essere applicato per motivi ideologici.<p> 
+Scrivi un motivo specifico per il quale questo indirizzo IP dovrebbe a tuo avviso essere bloccato (per esempio, cita i titoli di pagine eventualmente già oggetto di vandalismo editoriale).",
+"ipaddress"            => "Indirizzo IP (IP Address)",
+"ipbreason"            => "Motivazione",
+"ipbsubmit"            => "Blocca questo indirizzo IP",
+"badipaddress" => "L'indirizzo IP indicato non è corretto.",
+"noblockreason" => "Devi obbligatoriamente fornire una motivazione per il blocco.",
+"blockipsuccesssub" => "Blocco eseguito",
+"blockipsuccesstext" => " L'indirizzo IP \"$1\" è stato bloccato.
+<br>Vedi [[Special:Ipblocklist|lista IP bloccati]].",
+"unblockip"            => " Sblocca indirizzo IP",
+"unblockiptext"        => "Usa il modulo sottostante per restituire il diritto di scrittura ad un indirizzo IP precedentemente bloccato.",
+"ipusubmit"            => "Sblocca questo indirizzo IP",
+"ipusuccess"   => "Indirizzo IP \"$1\" sbloccato",
+"ipblocklist"  => "Lista degli indirizzi IP bloccati",
+"blocklistline"        => "$1, $2 ha bloccato $3",
+"blocklink"            => "blocca",
+"unblocklink"  => "sblocca",
+"contribslink" => "contributi",
+
+# Developer tools
+#
+"lockdb"               => "Blocca il database",
+"unlockdb"             => "Sblocca il database",
+"lockdbtext"   => "Bloccare il database sospenderà la possibilità per tutti gli Utenti di modificare le pagine o di crearne di nuove, di cambiare le loro preferenze, di modificare le loro liste di Osservati Speciali, ed in genere non consentirà a nessuno di eseguire operazioni che richiedano modifiche del database.<br><br>
+Per cortesia, conferma che questo è effettivamente quanto tu intendi ora effettuare e, soprattutto, che il prima possibile sbloccherai nuovamente il database, ripristinandone la corretta funzionalità, non appena avrai terminato le tue manutenzioni.",
+"unlockdbtext" => "Sbloccare il database ripristinerà la possibilità per tutti gli Utenti di modificare le pagine o di crearne di nuove, di cambiare le loro preferenze, di modificare le loro liste di Osservati Speciali, ed in genere di eseguire operazioni che richiedano modifiche del database.
+Per cortesia, conferma che questo è effettivamente quanto tu intendi ora effettuare.",
+"lockconfirm"  => "Sì, effettivamente intendo, sotto la mia responsabilità, bloccare il database.",
+"unlockconfirm"        => " Sì, effettivamente intendo, sotto la mia responsabilità, sbloccare il database.",
+"lockbtn"              => "Blocca il database",
+"unlockbtn"            => "Sblocca il database",
+"locknoconfirm" => "Non hai spuntato la casellina di conferma.",
+"lockdbsuccesssub" => "Blocco del database eseguito",
+"unlockdbsuccesssub" => "Sblocco del database eseguito, rimosso blocco",
+"lockdbsuccesstext" => "Il database di Wikipedia è stato bloccato.
+<br>Ricordati di rimuovere il blocco non appena avrai terminatoi le tue manutenzioni.",
+"unlockdbsuccesstext" => " Il database di Wikipedia è stato sbloccato.",
+
+# SQL query
+#
+"asksql"               => "Interrogazione SQL",
+"asksqltext"   => "Usa il modulo sottostante per effettuare una interrogazione diretta (query) al database di Wikipedia.
+Usa singole virgolette ('come queste') per delimitare una stringa letterale.
+Questo può considerevolmente sovraccaricare e di fatto rallentare il server, perciò per cortesia usa questa funzionalità solo quando necessario.",
+"sqlquery"             => "Immetti stringa da ricercare",
+"querybtn"             => "Invia interrogazione",
+"selectonly"   => "Interrogazioni diverse da \"SELECT\" sono riservate agli sviluppatori di Wikipedia (developers).",
+"querysuccessful" => "Interrogazione riuscita",
+
+# Move page
+#
+"movepage"             => "Spostamento di pagina",
+"movepagetext" => "Con il modulo sottostante puoi rinominare una pagina, spostando anche tutta la sua cronologia al nuovo nome.
+Il vecchio titolo diverrà automaticamente un redirect che punta al nuovo titolo. 
+I link alla vecchia pagina non saranno aggiornati (e punteranno quindi al redirect); accertati di [[Special:Manutenzioni|controllare con cura]] che non si creino doppi redirects o redirects interrotti.
+Resta nella tua responsabilità di accertarti che i link continuino a puntare verso dove devono dirigersi.
+
+Nota bene: la pagina '''non''' sarà spostata se vi fosse già un articolo con il nuovo nome, a meno che non sia una pagina vuota o un redirect, e sempre che non abbia cronologia. Questo significa che, se commetti un errore, puoi nuovamente rinominare una pagina col vecchio titolo, ma non puoi sovrascrivere una pagina già esistente.
+
+<b>ATTENZIONE!</b>
+Questo cambiamento drastico potrebbe creare inattesi contrattempi, specialmente se si tratta di una pagina molto visitata. Accertati di aver ben valutato le conseguenze dello spostamento, prima di procedere. Nel dubbio, contatta un Amministratore.",
+"movepagetalktext" => "La corrispondente pagina di discussione, se esiste, sarà spostata automaticamente insieme all'articolo, '''tranne che nei seguenti casi:'''
+*Spostamento della pagina fra i namespaces,
+*Una pagina di discussione (non vuota) già esiste per il nuovo nome, oppure
+*Hai deselezionato la casellina qui sotto.
+In questi casi, se lo ritieni opportuno, dovrai spostare o aggiungere manualmente la pagina di discussione.",
+"movearticle"  => "Rinomina articolo",
+"movenologin"  => "Non hai effettuato il login",
+"movenologintext" => "Devi essere un Utente registrato ed aver effettuato il <a href=\"" .
+  wfLocalUrl( "Special:Userlogin" ) . "\">login</a>
+per poter spostare una pagina.",
+"newtitle"             => "Al nuovo titolo di ",
+"movepagebtn"  => "Sposta questa pagina",
+"pagemovedsub" => "Spostamento effettuato con successo",
+"pagemovedtext" => "Pagina \"[[$1]]\" rinominata in \"[[$2]]\".",
+"articleexists" => "Una pagina con questo nome esiste già, oppure il nome che hai scelto non è valido.<br>
+Scegli, per cortesia, un titolo diverso per l'articolo.",
+"talkexists"   => "La pagina è stata spostata correttamente, ma non si è potuto spostare la pagina di discussione perché ne esiste già un'altra con il nuovo titolo. Per favore, modifica manualmente i contenuti delle due pagine discussione, così da mantenerle entrambe per non perdere potenzialmente interessanti riflessioni.",
+"movedto"              => "spostata a ",
+"movetalk"             => "Sposta anche la corrispondente pagina \"discussione\", se possibile.",
+"talkpagemoved" => "Anche la corrispondente pagina di discussione è stata spostata.",
+"talkpagenotmoved" => "La corrispondente pagina di discussione <strong>non è stata spostata</strong>."
+
+);
+
+class LanguageIt extends Language {
+
+       function getDefaultUserOptions () {
+               global $wgDefaultUserOptionsIt;
+               return $wgDefaultUserOptionsIt;
+               }
+
+       function getBookstoreList () {
+               global $wgBookstoreListIt;
+               return $wgBookstoreListIt;
+       }
+
+       function getNamespaces() {
+               global $wgNamespaceNamesIt;
+               return $wgNamespaceNamesIt;
+       }
+
+       function getNsText( $index ) {
+               global $wgNamespaceNamesIt;
+               return $wgNamespaceNamesIt[$index];
+       }
+
+       function getNsIndex( $text ) {
+               global $wgNamespaceNamesIt;
+
+               foreach ( $wgNamespaceNamesIt as $i => $n ) {
+                       if ( 0 == strcasecmp( $n, $text ) ) { return $i; }
+               }
+               return false;
+       }
+
+       function getQuickbarSettings() {
+               global $wgQuickbarSettingsIt;
+               return $wgQuickbarSettingsIt;
+       }
+
+       function getSkinNames() {
+               global $wgSkinNamesIt;
+               return $wgSkinNamesIt;
+       }
+
+       function getUserToggles() {
+               global $wgUserTogglesIt;
+               return $wgUserTogglesIt;
+       }
+
+       function getLanguageNames() {
+               global $wgLanguageNamesIt;
+               return $wgLanguageNamesIt;
+       }
+
+       function getLanguageName( $code ) {
+               global $wgLanguageNamesIt;
+               if ( ! array_key_exists( $code, $wgLanguageNamesIt ) ) {
+                       return "";
+               }
+               return $wgLanguageNamesIt[$code];
+       }
+
+       function getMonthName( $key )
+       {
+               global $wgMonthNamesIt;
+               return $wgMonthNamesIt[$key-1];
+       }
+
+       function getMonthAbbreviation( $key )
+       {
+               global $wgMonthAbbreviationsIt;
+               return $wgMonthAbbreviationsIt[$key-1];
+       }
+
+       function getWeekdayName( $key )
+       {
+               global $wgWeekdayNamesIt;
+               return $wgWeekdayNamesIt[$key-1];
+       }
+
+       function date( $ts, $adj = false )
+       {
+               if ( $adj ) { $ts = $this->userAdjust( $ts ); }
+
+               $d = $this->getMonthAbbreviation( substr( $ts, 4, 2 ) ) .
+                 " " . (0 + substr( $ts, 6, 2 )) . ", " .
+                 substr( $ts, 0, 4 );
+               return $d;
+       }
+
+       function getValidSpecialPages()
+       {
+               global $wgValidSpecialPagesIt;
+               return $wgValidSpecialPagesIt;
+       }
+
+       function getSysopSpecialPages()
+       {
+               global $wgSysopSpecialPagesIt;
+               return $wgSysopSpecialPagesIt;
+       }
+
+       function getDeveloperSpecialPages()
+       {
+               global $wgDeveloperSpecialPagesIt;
+               return $wgDeveloperSpecialPagesIt;
+       }
+
+       function getMessage( $key )
+       {
+               global $wgAllMessagesIt;
+               if(array_key_exists($key, $wgAllMessagesIt))
+                       return $wgAllMessagesIt[$key];
+               else
+                       return Language::getMessage($key);
+       }
+
+}
+
+?>
diff --git a/languages/LanguageJa.php b/languages/LanguageJa.php
new file mode 100644 (file)
index 0000000..ce09f9d
--- /dev/null
@@ -0,0 +1,1175 @@
+<?php
+global $IP;
+include_once( "$IP/Utf8Case.php" );
+
+# The names of the namespaces can be set here, but the numbers
+# are magical, so don't change or move them!  The Namespace class
+# encapsulates some of the magic-ness.
+# 名前空間の名前はここで設定できますが、番号は特別なので、
+# 変更したり移動したりしないでね! 名前空間クラスは特殊性を幾らか
+# 隠匿します。
+#
+/* private */ $wgNamespaceNamesJa = array(
+       -1      => "特別" /* "Special" */, 
+       0       => "",
+       1       => "ノート" /* "Talk" */,
+       2       => "利用者" /* "User" */,
+       3       => "利用者‐会話" /* "User_talk" */,
+       4       => "Wikipedia" /* "Wikipedia" */,
+       5       => "Wikipedia‐ノート" /* "Wikipedia_talk" */,
+       6       => "画像" /* "Image" */,
+       7       => "画像‐ノート" /* "Image_talk" */
+);
+
+/* private */ $wgQuickbarSettingsJa = array(
+       "None", "Fixed left", "Fixed right", "Floating left"
+);
+
+/* private */ $wgSkinNamesJa = array(
+       "標準", "ノスタルジア", "ケルンブルー"
+);
+
+/* private */ $wgUserTogglesJa = array(
+       "hover"         => "Show hoverbox over wiki links",
+       "underline" => "Underline links",
+       "highlightbroken" => "Highlight links to empty topics",
+       "justify"       => "Justify paragraphs",
+       "hideminor" => "Hide minor edits in recent changes",
+       "numberheadings" => "Auto-number headings",
+       "rememberpassword" => "Remember password across sessions",
+       "editwidth" => "Edit box has full width",
+       "editondblclick" => "Edit pages on double click (JavaScript)",
+       "watchdefault" => "Watch new and modified articles",
+       "minordefault" => "Mark all edits minor by default"
+);
+
+/* Native/local names should be available where known for consistency
+   and so that people can recognize them when jumping languages */
+/* private */ $wgLanguageNamesJa = array(
+       "ab"    => "アブハズ語",
+       "aa"    => "アファル語",
+       "af"    => "アフリカーンス語",
+       "sq"    => "アルバニア語",
+       "am"    => "アムハラ語",
+       "ar"    => "アラビア語",
+       "hy"    => "アルメニア語",
+       "as"    => "アッサム語",
+       "ay"    => "アイマラ語",
+       "az"    => "アゼルバイジャン語",
+       "ba"    => "バシキール語",
+       "eu"    => "Euskara(バスク語)",
+       "be"    => "&#1041;&#1077;&#1083;&#1072;&#1088;&#1091;&#1089;&#1082;&#1080;(白ロシア語)",
+       "bn"    => "ベンガル語",
+       "dz"    => "ブータン語",
+       "bh"    => "ビハリ語",
+       "bi"    => "ビスラマ語",
+       "my"    => "ビルマ語",
+       "km"    => "カンボジア語",
+       "ca"    => "Catal&#224;(カタロニア語)",
+       "zh"    => "中文(中国語)",      # 漢語
+       "co"    => "コルシカ方言",
+       "hr"    => "Hrvatski(クロアチア語)",
+       "cs"    => "&#268;esk&#225;(チェコ語)",
+       "da"    => "Dansk(デンマーク語)", # Note two different subdomains. 
+       "dk"    => "Dansk(デンマーク語)", # 'da' is correct for the language.
+       "nl"    => "Nederlands(オランダ語)",
+       "en"    => "English(英語)",
+       "simple" => "Simple English(簡単な英語)",
+       "eo"    => "Esperanto(エスペラント)",
+       "et"    => "Eesti(エストニア語)",
+       "fo"    => "フェロー語",
+       "fj"    => "フィジー語",
+       "fi"    => "フィンランド語",
+       "fr"    => "Fran&#231;ais(フランス語)",
+       "fy"    => "Frysk(フリジア語)",
+       "gl"    => "ガリシア語",
+       "ka"    => "&#4325;&#4304;&#4320;&#4311;&#4309;&#4308;&#4314;&#4312;(グルジア語)",
+       "de"    => "Deutsch(ドイツ語)",
+       "el"    => "&#917;&#955;&#955;&#951;&#957;&#953;&#954;&#940;(ギリシア語)",
+       "kl"    => "グリーンランド語",
+       "gn"    => "グアラニー語",
+       "gu"    => "&#2711;&#2753;&#2716;&#2736;&#2750;&#2724;&#2752;(グジャラート語)",
+       "ha"    => "ハウサ語",
+       "he"    => "&#1506;&#1489;&#1512;&#1497;&#1514;(ヘブライ語)",
+       "hi"    => "&#2361;&#2367;&#2344;&#2381;&#2342;&#2368;(ヒンディー語)",
+       "hu"    => "Magyar (ハンガリー語)",
+       "is"    => "アイスランド語",
+       "id"    => "インドネシア語",
+       "ia"    => "Interlingua(インターリングア)",
+       "iu"    => "イヌクティトット語",
+       "ik"    => "イヌピアック語",
+       "ga"    => "アイルランド語",
+       "it"    => "Italiano(イタリア語)",
+       #"ja"   => "日本語", # Local links
+       "jv"    => "ジャワ語",
+       "kn"    => "カンナダ語",
+       "ks"    => "カシミール語",
+       "kk"    => "カザフ語",
+       "rw"    => "ルワンダ語",
+       "ky"    => "キルギス語",
+       "rn"    => "キルンジ語",
+       "ko"    => "&#54620;&#44397;&#50612;(韓国語)",
+       "lo"    => "ラオ語",
+       "la"    => "ラテン語",
+       "lv"    => "ラトビア語",
+       "ln"    => "リンガラ語",
+       "lt"    => "Lietuvi&#371;(リトアニア語)",
+       "mk"    => "マケドニア語",
+       "mg"    => "マダガスカル語",
+       "ms"    => "Bahasa Melayu(マレー語)",
+       "ml"    => "マラヤーラム語",
+       "mi"    => "マオリ語",
+       "mr"    => "マラーティー語",
+       "mo"    => "モルドバ語",
+       "mn"    => "モンゴル語",
+       "na"    => "ナウル語",
+       "ne"    => "&#2344;&#2375;&#2346;&#2366;&#2354;&#2368;(ネパール語)",
+       "no"    => "Norsk(ノルウェー語)",
+       "oc"    => "オクシタン語", # 南仏の言語
+       "or"    => "オリヤー語",
+       "om"    => "オロモ語",
+       "ps"    => "パシュト語",
+       "fa"    => "&#8238;&#1601;&#1585;&#1587;&#1609;&#8236;(ペルシャ語)",
+       "pl"    => "Polski(ポーランド語)",
+       "pt"    => "Portugu&#234;s(ポルトガル語)",
+       "pa"    => "パンジャブ語",
+       "qu"    => "ケチュア語",
+       "rm"    => "レートローマン語",
+       "ro"    => "Rom&#226;n&#259;(ルーマニア語)",
+       "ru"    => "&#1056;&#1091;&#1089;&#1089;&#1082;&#1080;&#1081;(ロシア語)",
+       "sm"    => "サモア語",
+       "sg"    => "サングロ語",
+       "sa"    => "&#2360;&#2306;&#2360;&#2381;&#2325;&#2371;&#2340;(サンスクリット)",
+       "sr"    => "セルビア語",
+       "sh"    => "セルボ・クロアチア語",
+       "st"    => "セソト語",
+       "tn"    => "セツワナ語",
+       "sn"    => "ショナ語",
+       "sd"    => "シンディ語",
+       "si"    => "シンハラ語",
+       "ss"    => "シスワティ語",
+       "sk"    => "スロバキア語",
+       "sl"    => "Slovensko(スロベニア語)",
+       "so"    => "ソマリア語",
+       "es"    => "Espa&#241;ol(スペイン語)",
+       "su"    => "スーダン語",
+       "sw"    => "スワヒリ語",
+       "sv"    => "Svenska(スウェーデン語)",
+       "tl"    => "タガログ語",
+       "tg"    => "タジク語",
+       "ta"    => "タミル語",
+       "tt"    => "タタール語",
+       "te"    => "テルグ語",
+       "th"    => "タイ語",
+       "bo"    => "チベット語",
+       "ti"    => "ティグリニャ語", # エチオピア北部
+       "to"    => "トンガ語",
+       "ts"    => "ツワナ語",
+       "tr"    => "T&#252;rk&#231;e(トルコ語)",
+       "tk"    => "トゥルクメン語",
+       "tw"    => "トウィ語",
+       "ug"    => "ウイグル語",
+       "uk"    => "&#1059;&#1082;&#1088;&#1072;&#1111;&#1085;&#1089;&#1100;&#1082;&#1072;(ウクライナ語)",
+       "ur"    => "ウルドゥ語",
+       "uz"    => "ウズベク語",
+       "vi"    => "ベトナム語",
+       "vo"    => "Volap&#252;k(ボラピュク語)", # 人工語
+       "cy"    => "ウェールズ語",
+       "wo"    => "ウォロフ語",
+       "xh"    => "ホサ語",
+       "yi"    => "イディッシュ語",
+       "yo"    => "ヨルバ語",
+       "za"    => "壮語",  # チワン語族(中国壮族のことばの総称) 
+       "zu"    => "ズールー語"
+);
+
+/* private */ $wgWeekdayNamesJa = array(
+       "日曜日", "月曜日", "火曜日", "水曜日", "木曜日",
+       "金曜日", "土曜日"
+);
+
+/* private */ $wgMonthNamesJa = array( # ???
+       "一月", "二月", "三月", "四月", "五月", "六月",
+       "七月", "八月", "九月", "十月", "十一月",
+       "十二月"
+);
+
+/* private */ $wgMonthAbbreviationsJa = array(
+       "1月", "2月", "3月", "4月", "5月", "6月",
+       "7月", "8月", "9月", "10月", "11月", "12月"
+);
+
+# All special pages have to be listed here: a description of ""
+# will make them not show up on the "Special Pages" page, which
+# is the right thing for some of them (such as the "targeted" ones).
+# 全ての特殊頁はここに列挙しないといけません。
+# "" (空文字列) という説明にすると「特殊頁」頁に掲載しません。
+# これは幾つか (「targeted」とか) に対しては適当なことです。
+
+/* private */ $wgValidSpecialPagesJa = array(
+       "Userlogin"             => "",
+       "Userlogout"    => "",
+       "Preferences"   => "ユーザー設定を保存",
+       "Watchlist"             => "ウォッチリスト",
+       "Recentchanges" => "最近更新したページ",
+       "Upload"                => "画像をアップロードする",
+       "Imagelist"             => "画像リスト",
+       "Listusers"             => "登録済みユーザー",
+       "Statistics"    => "サイトの統計",
+       "Randompage"    => "ランダム記事",
+
+       "Lonelypages"   => "孤立したページ",
+       "Unusedimages"  => "孤立した画像",
+       "Popularpages"  => "人気の記事",
+       "Wantedpages"   => "執筆が待望されている記事",
+       "Shortpages"    => "短い記事",
+       "Longpages"             => "長い記事",
+       "Newpages"              => "新しく登場した記事",
+       "Allpages"              => "タイトル別全ページ",
+
+       "Ipblocklist"   => "ブロックされたIPアドレス",
+       "Maintenance" => "管理ページ",
+       "Specialpages"  => "",
+       "Contributions" => "",
+       "Emailuser"             => "",
+       "Whatlinkshere" => "",
+       "Recentchangeslinked" => "",
+       "Movepage"              => "",
+       "Booksources"   => "外部の参考文献"
+);
+
+/* private */ $wgSysopSpecialPagesJa = array(
+       "Blockip"               => "IPアドレスをブロック",
+       "Asksql"                => "データベースに問い合わせ",
+       "Undelete"              => "消去されたページを閲覧し、復帰させる"
+);
+
+/* private */ $wgDeveloperSpecialPagesJa = array(
+       "Lockdb"                => "データベースを読み出し専用にする",
+       "Unlockdb"              => "データベースを書き込み可能にする",
+       "Debug"                 => "デバッグ情報"
+);
+
+/* private */ $wgAllMessagesJa = array(
+
+# Bits of text used by many pages:
+#
+"mainpage"             => "メインページ",
+"about"                        => "About",
+"aboutwikipedia" => "Wikipediaについて",
+"aboutpage"            => "Wikipedia:About",
+"help"                 => "ヘルプ",
+"helppage"             => "Wikipedia:Help",
+"wikititlesuffix" => "Wikipedia",
+"bugreports"   => "バグの報告",
+"bugreportspage" => "Wikipedia:バグの報告",
+"faq"                  => "FAQ",
+"faqpage"              => "Wikipedia:FAQ",
+"edithelp"             => "ヘルプを編集",
+"edithelppage" => "Wikipedia:編集の仕方",
+"cancel"               => "中止",
+"qbfind"               => "検索",
+"qbbrowse"             => "閲覧",
+"qbedit"               => "編集",
+"qbpageoptions" => "ページ・オプション",
+"qbpageinfo"   => "ページ情報",
+"qbmyoptions"  => "オプション",
+"mypage"               => "マイ・ページ",
+"mytalk"               => "マイ・トーク",
+"currentevents" => "最近の出来事",
+"errorpagetitle" => "エラー",
+"returnto"             => "$1 に戻る。",
+"fromwikipedia"        => "出典: フリー百科事典『ウィキペディア(Wikipedia)』",
+"whatlinkshere"        => "ここにリンクしているページ",
+"help"                 => "ヘルプ",
+"search"               => "検索",
+"history"              => "履歴",
+"printableversion" => "印刷用バージョン",
+"editthispage" => "このページを編集",
+"deletethispage" => "このページを削除",
+"protectthispage" => "このページを保護",
+"unprotectthispage" => "ページ保護解除",
+"talkpage"             => "この記事のノート",
+"subjectpage"  => "サブジェクト・ページ",
+"otherlanguages" => "他の言語",
+"redirectedfrom" => "($1 から転送)",
+"lastmodified" => "最終更新 $1。",
+"viewcount"            => "このページは $1 回アクセスされました。",
+"printsubtitle" => "(From http://www.wikipedia.org)",
+"protectedpage" => "保護されたページ",
+"administrators" => "Wikipedia:Administrators",
+"sysoptitle"   => "シスオペによるアクセスが必要",
+"sysoptext"            => "あなたの要求した処理は \"sysop\" のみが実行できます。
+ $1を参照してください。",
+"developertitle" => "開発者によるアクセスが必要",
+"developertext"        => "あなたの要求した処理を実行できるのは、 \"developer\" のみです。 $1を参照してください。",
+"nbytes"               => "$1 バイト",
+"go"                   => "行く",
+"ok"                   => "OK",
+"sitetitle"            => "Wikipedia",
+"sitesubtitle" => "フリー百科事典",
+"retrievedfrom" => "Retrieved from \"$1\"",
+
+# Main script and global functions
+#
+"nosuchaction" => "そのような動作はありません",
+"nosuchactiontext" => "URI で指定された動作は Wikipedia で認識できません。",
+"nosuchspecialpage" => "そのような特別ページはありません。",
+"nospecialpagetext" => "その特別ページの要求は Wikipedia には理解できません。",
+
+# General errors
+#
+"error"                        => "エラー",
+"databaseerror" => "データベース・エラー",
+"dberrortext"  => "データベース検索の文法エラー。
+検索問合わせが間違っているか($5 を参照),
+あるいはソフトウェアのバグかもしれません。
+最後に実行を試みた問い合わせ: 
+<blockquote><tt>$1</tt></blockquote>
+from within function \"<tt>$2</tt>\".
+MySQL returned error \"<tt>$3: $4</tt>\".",
+"noconnect"            => "$1 のデータベースに接続できません。",
+"nodb"                 => "$1 のデータベースを選択できません。",
+"readonly"             => "データベースはロックされています",
+"enterlockreason" => "ロックする理由を入力して下さい。ロックが解除されるのがいつになるかの見積もりについても述べて下さい。",
+"readonlytext" => "ウィキペディア・データベースは現在、新しい記事の追加や修正を受け付けない「ロック」状態になっています。これはおそらくは定期的なメンテナンスのためで、メンテナンス終了後は正常な状態に復帰します。
+データベースをロックした管理者は次のような説明をしています:
+<p>$1
+<p>The Wikipedia database is currently locked to new
+entries and other modifications, probably for routine database maintenance,
+after which it will be back to normal.
+The administrator who locked it offered this explanation:
+<p>$1",
+"missingarticle" => "データベースは、\"$1\"という題のページの、存在するはずの文章を見つけることができませんでした。
+<p>これはデータベースのエラーではなく、ソフトウェアのバグだろうと思われます。
+<p>URI と共に管理者に報告して下さるようにお願いします。
+<p>The database did not find the text of a page
+that it should have found, named \"$1\".
+<p>This is not a database error, but likely a bug in the software.
+<p>Please report this to an administrator, making note of the URI.",
+"internalerror" => "内部処理エラー Internal error",
+"filecopyerror" => "ファイルを\"$1\"から\"$2\"へ複製できませんでした。Could not copy file \"$1\" to \"$2\".",
+"filerenameerror" => "ファイル名を\"$1\"から\"$2\"へ変更できませんでした。Could not rename file \"$1\" to \"$2\".",
+"filedeleteerror" => "ファイル\"$1\"を削除できませんでした。Could not delete file \"$1\".",
+"filenotfound" => "ファイルを\"$1\"は見つかりませんでした。Could not find file \"$1\".",
+"unexpected"   => "エラー:\"$1\" と \"$2\" が同じです。Unexpected value: \"$1\"=\"$2\".",
+"formerror"            => "エラー: フォームを送信できませんでした。 Error: could not submit form",  
+"badarticleerror" => "この動作はこのページではとることができません。 This action cannot be performed on this page.",
+"cannotdelete" => "指定されたページ、または画像を削除できませんでした。 Could not delete the page or image specified.",
+
+# Login and logout pages
+#
+"logouttitle"  => "ユーザー ログアウト",
+"logouttext"   => "
+ログアウトしました。
+ウィキペディアを匿名で使い続うことができます。
+あるいはログインして元の、あるいは別のユーザーとして使うこともできます。
+<P>You are now logged out.
+You can continue to use Wikipedia anonymously, or you can log in
+again as the same or as a different user.\n",
+
+"welcomecreation" => "<h2>$1 さん、ようこそ!</h2><p>あなたのアカウントができました。
+お好みに合わせてユーザーオプションを変更することをお忘れなく。",
+
+"loginpagetitle" => "ユーザー・ログイン",
+"yourname"             => "あなたのユーザー名",
+"yourpassword" => "あなたのパスワード",
+"yourpasswordagain" => "パスワード再入力",
+"newusersonly" => " (新規ユーザのみ)",
+"remembermypassword" => "セッションをまたがってパスワードを保持する。",
+"loginproblem" => "<b>ログインでエラーが発生しました。</b><br>再度実行してください。",
+"alreadyloggedin" => "<font color=red><b>ユーザ $1 は、すでにログイン済みです。</b></font><br>\n",
+
+"areyounew"            => "もし Wikipedia を使うのが初めてで、ユーザー登録をしたい方は、ユーザー名、パスワード、さらに確認のため同じパスワードを再入力してください。
+電子メール・アドレスの登録は、必須ではありません。ですが、もしパスワードを忘れたときには、電子メールでパスワードを取り寄せることができるので便利です。<br>\n",
+
+
+"login"                        => "ログイン",
+"userlogin"            => "ログイン",
+"logout"               => "ログアウト",
+"userlogout"   => "ログアウト",
+"createaccount"        => "新規アカウント作成",
+"badretype"            => "両方のパスワードが一致しません。",
+"userexists"   => "そのユーザー名はすでに使われています。ほかの名前をお選びください。",
+"youremail"            => "電子メール",
+"yournick"             => "ニックネーム (署名用)",
+"emailforlost" => "パスワードを忘れたときには、あたらしいパスワードを電子メールで受け取ることが出来ます。",
+"loginerror"   => "ログイン・エラー",
+"noname"               => "ユーザ名を正しく指定していません。",
+"loginsuccesstitle" => "ログイン成功",
+"loginsuccess" => "あなたは現在 Wikipedia に \"$1\" としてログインしています。",
+"nosuchuser"   => " \"$1\" というユーザーは見当たりません。
+綴りが正しいか再度確認するか、下記のフォームを使ってアカウントを作成してください。",
+"wrongpassword"        => "パスワードが間違っています。再度入力してください。",
+"mailmypassword" => "新しいパスワードを、メールで送る",
+"passwordremindertitle" => "Password reminder from Wikipedia (ウィキペディアからのパスワードのお知らせ)",
+"passwordremindertext" => "どなたか ($1 のIPアドレスの使用者)が、Wikipediaのログイン・パスワードの再発行を依頼しました。
+ユーザ \"$2\" のパスワードを、 \"$3\" に変更しました。
+ログイン後、別のパスワードに変更しましょう。",
+"noemail"              => "ユーザ \"$1\" のメール・アドレスは登録されていません。",
+"passwordsent" => "あたらしいパスワードは \"$1\" さんの登録済みメール・アドレスにお送りしました。メールを受け取ったら、再度ログインしてください。",
+
+# Edit pages
+#
+"summary"              => "要約",
+"minoredit"            => "これは細部の修正です。",
+"savearticle"  => "ページを保存",
+"preview"              => "プレビュー",
+"showpreview"  => "プレビューを実行",
+"blockedtitle" => "ユーザはブロックされています。",
+"blockedtext"  => "あなたのユーザ名またはIPアドレスは $1 によってブロックされています。
+その理由は次の通りです。:<br>$2<p>詳細は管理者にお問い合わせください。",
+"newarticle"   => "(新規)",
+"newarticletext" => "新しい記事を書き込んでください。",
+"noarticletext" => "(このページには現在記事がありません。)",
+"updated"              => "(更新)",
+"note"                 => "<strong>注釈:</strong> ",
+"previewnote"  => "これはプレビューです。まだ保存されていません!",
+"previewconflict" => "このプレビューは、上の文章編集エリアの文章を保存した場合に
+どう見えるようになるかを示すものです。
+<p>" /* "This preview reflects the text in the upper 
+text editing area as it will appear if you choose to save." */,
+"editing"              => "Editing $1",
+"editconflict" => "編集競合: $1",
+"explainconflict" => "あなたがこのページを編集し始めてから誰か他の人が
+このページを変更してしまいました。
+上の文章エリアは現在の最新の状態を反映しています。
+あなたの加える変更の内容は下の文章エリアに示されています。
+変更内容を、上の文章エリアの内容に組み込んで下さい。
+<b>上の文章エリアの内容だけ</b>が、\"Save page\"をクリックした時に
+保存されることになります。\n<p>"
+/* Someone else has changed this page since you
+started editing it.
+The upper text area contains the page text as it currently exists.
+Your changes are shown in the lower text area.
+You will have to merge your changes into the existing text.
+<b>Only</b> the text in the upper text area will be saved when you
+press \"Save page\".\n<p>" */,
+"yourtext"             => "あなたの文章",
+"storedversion" => "保存された版",
+"editingold"   => "<strong>警告: あなたはこのページの古い版を
+編集しています。もしもこの文章を保存すると、この版以降に追加された
+全ての変更が無効になってしまいます。</strong>",
+/* <p><strong>WARNING: You are editing an out-of-date
+revision of this page.
+If you save it, any changes made since this revision will be lost.</strong>\n" */
+"yourdiff"             => "あなたの更新内容",
+"copyrightwarning" => "Wikipediaに投稿された文書は、すべて GNU Free Documentation License によって発行されたものとみなされますので、留意してください。
+<p>(詳細は $1 を参照, また、参考までに非公式日本語訳は &lt;http://www.opensource.jp/fdl/fdl.ja.html&gt; を参照)。
+<p>あなたの文章が他人によって自由に編集、配布されることを望まない場合は、投稿を控えて下さい。
+<p>また、あなたの投稿する文章はあなた自身によって書かれたものであるか、パブリック・ドメインかそれに類する自由なリソースからの複製であることを約束して下さい。
+<strong>著作権のある作品を許諾なしに投稿してはいけません!</strong>",
+
+
+# History pages
+#
+"revhistory"   => "改訂履歴",
+"nohistory"            => "このページには改訂履歴がありません。  There is no edit history for this page.",
+"revnotfound"  => "要求された版が見つかりません Revision not found",
+"revnotfoundtext" => "要求されたこのページの旧版は見つかりませんでした。
+URLをもう一度確認して、このページにアクセスしてみて下さい。
+
+The old revision of the page you asked for could not be found.
+Please check the URL you used to access this page.\n",
+"loadhist"             => "改訂履歴の読み込み中",
+"currentrev"   => "最新版",
+"revisionasof" => "$1の版",
+"cur"                  => "最新版",
+"next"                 => "次の版",
+"last"                 => "前の版",
+"orig"                 => "最古版",
+"histlegend"   => "凡例: (最新版) = 最新版との比較,
+(前の版) = 直前の版との比較, M = 細部の修正",
+
+# Diffs
+#
+"difference"   => "(版間での差分)" /* "(Difference between revisions)" */,
+"loadingrev"   => "差分をとるために古い版を読み込んでいます" /*"loading revision for diff" */,
+"lineno"               => "$1 行" /* "Line $1:" */,
+"editcurrent"  => "この頁の最新版を編集" /* "Edit the current version of this page" */,
+
+# 検索結果(Search results)
+#
+"searchresults" => "検索結果" /* "Search results" */,
+"searchhelppage" => "Wikipedia:Searching",
+"searchingwikipedia" => "Wikipedia を検索中" /* "Searching Wikipedia" */,
+"searchresulttext" => "Wikipedia の検索についての詳しい情報は、 $1 をご覧下さい。" /* "For more information about searching Wikipedia, see $1." */ ,
+"searchquery"  => "問い合わせ \"$1\" について、" /* "For query \"$1\"" */,
+"badquery"             => "おかしな形式の検索問い合わせ" /* "Badly formed search query" */,
+"badquerytext" => "問い合わせを処理できませんでした。
+これはおそらく、3文字未満の語を検索しようとしたためですが、これにはまだ対応していません。
+例えば「魚 and and 大きさ」のように、表現を誤記しているのかもしれません。"  /* "We could not process your query.
+This is probably because you have attempted to search for a
+word fewer than three letters long, which is not yet supported.
+It could also be that you have mistyped the expression, for
+example \"fish and and scales\".
+Please try another query." */,
+"matchtotals"  => "問い合わせ「$1」は $2 の記事の題及び $3 の記事の本文と一致しました。" /* "The query \"$1\" matched $2 article titles
+and the text of $3 articles." */,
+"titlematches" => "記事の題と一致" /* "Article title matches" */,
+"notitlematches" => "記事の題とは一致しませんでした" /* "No article title matches" */,
+"textmatches"  => "記事本文と一致" /* "Article text matches" */,
+"notextmatches"        => /* "No article text matches" */ "記事本文とは一致しませんでした",
+"prevn"                        => "前 $1" /* "previous $1" */,
+"nextn"                        => "次 $1" /* "next $1" */,
+"viewprevnext" => "($1) ($2) ($3) を見る" /* "View ($1) ($2) ($3)." */,
+"showingresults" => "$2 からの $1 個の結果を次に示します" /* "Showing below <b>$1</b> results starting with #<b>$2</b>." */,
+"nonefound"            => "<strong>Note</strong>: 検索がうまくいかないのは、「ある」や「から」のような一般的な語で索引付けされていないとか、複数の検索語を指定している (全ての検索語を含む頁だけが結果に示されます。) とかのためかもしれません。" /* "<strong>Note</strong>: unsuccessful searches are
+often caused by searching for common words like \"have\" and \"from\",
+which are not indexed, or by specifying more than one search term (only pages
+containing all of the search terms will appear in the result)." */,
+
+# Preferences page ユーザーオプション設定頁
+#
+"preferences"  => "オプション" /* "Preferences" */, 
+"prefsnologin" => "ログインしていません" /* "Not logged in" */,
+"prefsnologintext"     =>  "ユーザーオプションを変更するためには、
+<a href=\"" .
+  wfLocalUrl( "特別:Userlogin" ) . "\">ログイン</a>している必要があります。"
+/* "You must be <a href=\"" .
+  wfLocalUrl( "Special:Userlogin" ) . "\">logged in</a>
+to set user preferences." */,
+"prefsreset"   => "ユーザー設定は初期化されました。" /* "Preferences have been reset from storage." */,
+"qbsettings"   => "クイックバー設定" /* "Quickbar settings" */, 
+"changepassword" => "パスワード変更" /* "Change password" */,
+"skin"                 => "外装" /* "Skin" */,
+"saveprefs"            => "設定の保存" /* "Save preferences" */,
+"resetprefs"   => "設定の初期化" /* "Reset preferences" */,
+"oldpassword"  => "古いパスワード" /* "Old password" */,
+"newpassword"  => "新しいパスワード" /* "New password" */,
+"retypenew"            => "新しいパスワードを再入力して下さい" /* "Retype new password" */,
+"textboxsize"  => "テキストボックスの大きさ" /* "Textbox dimensions" */,
+"rows"                 => "縦" /* "Rows" */,
+"columns"              => "横" /* "Columns" */,
+"searchresultshead" => "検索結果の表示" /* "Search result settings" */,
+"resultsperpage" => "1ページあたりの表示件数" /* "Hits to show per page" */,
+"contextlines" => "1件あたりの行数" /* "Lines to show per hit" */,
+"contextchars" => "1行あたりの文字数" /* "Characters of context per line" */,
+"recentchangescount" => "最近更新されたページの表示件数" /* "Number of titles in recent changes" */,
+"savedprefs"   => "ユーザー設定を保存しました" /* "Your preferences have been saved." */,
+"timezonetext"  => "UTCとあなたの地域の標準時間との差を入力して下さい" /* "Enter number of hours your local time differs
+from server time (UTC)." */,
+"localtime"    => "あなたの地域の標準時間" /* "Local time" */,
+"timezoneoffset" =>"差" /* "Offset" */,
+"emailflag"            => "他のユーザーからのメール送付を差し止める" /* "Disable e-mail from other users" */,
+
+# 最近更新したページ(Recent changes)
+#
+"recentchanges" => "最近更新したページ",
+"recentchangestext" => "最近付け加えられた変更はこのページで確認することができます。
+[[Wikipedia:新規参加者の方、ようこそ]]!
+以下のページも参照して下さい:
+[[wikipedia:ウィキペディア よくある質問集]],
+[[Wikipedia:ウィキペディアの基本方針とガイドライン]]
+(特に[[Wikipedia:記事名のつけ方]],
+[[Wikipedia:中立的な観点]]),
+[[Wikipedia:ウィキペディアで起こしがちな間違い]].
+
+ウィキペディアが成功するためには、あなたの投稿する内容が他人の著作権などによって束縛されていないことがとても重要です。[[Wikipedia:著作権]]
+法的責任問題は、プロジェクトに致命傷を与えることもある問題です。他人の著作物などを流用することは絶対に避けてください。また次のページも参照して下さい。[http://meta.wikipedia.org/wiki/Special:Recentchanges recent meta discussion]"
+
+/* Track the most recent changes to Wikipedia on this page.
+[[Wikipedia:Welcome,_newcomers|Welcome, newcomers]]!
+Please have a look at these pages: [[wikipedia:FAQ|Wikipedia FAQ]],
+[[Wikipedia:Policies and guidelines|Wikipedia policy]]
+(especially [[wikipedia:Naming conventions|naming conventions]],
+[[wikipedia:Neutral point of view|neutral point of view]]),
+and [[wikipedia:Most common Wikipedia faux pas|most common Wikipedia faux pas]].
+
+If you want to see Wikipedia succeed, it's very important that you don't add
+material restricted by others' [[wikipedia:Copyrights|copyrights]].
+The legal liability could really hurt the project, so please don't do it.
+See also the [http://meta.wikipedia.org/wiki/Special:Recentchanges recent meta discussion]. */,
+"rcloaderr"            => "最近の更新情報をダウンロード中" /* "Loading recent changes" */,
+"rcnote"               => "以下は最近<strong>$2</strong>日間の<strong>$1</strong>件の更新です。" /* "Below are the last <strong>$1</strong> changes in last <strong>$2</strong> days." */,
+# "rclinks"            => "最近$2時間/$3日間の$1件分を表示する" /* "Show last $1 changes in last $2 hours / last $3 days" */,
+"rclinks"              => "最近$2日間の$1件分を表示する" /* "Show last $1 changes in last $2 days." */,
+"rchide"               => "in $4 form; $1 minor edits; $2 secondary namespaces; $3 multiple edits.",
+"diff"                 => "差分" /* "diff" */,
+"hist"                 => "履歴" /* "hist" */,
+"hide"                 => "省略" /* "hide" */,
+"show"                 => "表示" /* "show" */,
+"tableform"            => "表" /* "table" */,
+"listform"             => "リスト" /* "list" */,
+"nchanges"             => "$1件の変更" /* "$1 changes" */,
+
+# Upload
+#
+"upload"               => "アップロード Upload",
+"uploadbtn"            => "ファイルをアップロードする Upload file",
+"uploadlink"   => "イメージのアップロード Upload images",
+"reupload"             => "再アップロード Re-upload",
+"reuploaddesc" => "アップロードのフォームへ戻る Return to the upload form.",
+"uploadnologin" => "ログインしていません、 Not logged in",
+"uploadnologintext"    => "ユーザーオプションを変更するためには、
+<a href=\"" .
+  wfLocalUrl( "特別:Userlogin" ) . "\">ログイン</a>している必要があります。
+
+You must be <a href=\"" .
+  wfLocalUrl( "Special:Userlogin" ) . "\">logged in</a>
+to upload files.",
+"uploadfile"   => "ファイルのアップロード  Upload file",
+"uploaderror"  => "アップロード エラー  Upload error",
+"uploadtext"   => "<strong>ご注意!</strong> 
+ここにファイルをアップロードする前に、ウィキペディアの<a href=\"" .
+wfLocalUrlE( "Wikipedia:画像利用の方針" ) . "\">画像利用の方針</a>を
+よく読んで、方針に反することのないようにして下さい。.
+<p>
+これまでにアップロードされたイメージの一覧や検索には、
+<a href=\"" . wfLocalUrlE( "特別:Imagelist" ) .
+"\">画像リスト</a>が便利です。
+アップロードと削除の記録は<a href=\"" .
+wfLocalUrlE( "Wikipedia:Upload_log" ) . "\">にあります。</a>.
+<p>記事に必要な画像を新しくアップロードする場合には、以下のフォームを利用して下さい。
+
+ほとんどのブラウザーでは、\"Browse\"というボタンが表示されます。そのボタンを押すと、
+あなたの使用しているコンピューター(のオペレーティング・システム)でファイルを開く
+際のの標準的な手続きが始まります。ファイルを選択して、Browseというボタンの横にある
+空欄にファイル名が入力された状態にして下さい。
+また、あなたがそのファイルをアップロードすることが著作権を侵害に該当しないことを
+あなたが表明する必要があります。そのために、チェック欄にチェックを入れて下さい。
+ファイルをアップロードするボタンを押すことで、アップロード手続きは完了します。
+もしもあなたのインターネット接続が低速のものであれば、アップロードには多少時間が
+かかります。
+
+望ましいフォーマットは、写真などのイメージの場合はJPEG、手書きのものやアイコン
+などはPNG、サウンドにはOGGです。
+
+混乱を避けるために説明的な名前をつけて下さい。
+
+画像を記事に組み入れるためには、次のようなフォーマットでリンクを張ります。
+<b>[[画像:file.jpg]]</b>  <b>[[画像:file.png|説明文]]</b>
+また、サウンドには <b>[[media:file.ogg]]</b> を用います。
+<p>
+ウィキペディアの他のページと同じく、あなたがアップロードしたファイルも、より
+よい百科事典作成のために他のユーザーによって編集、削除されることがあります。
+また、アップロード機能を乱用した利用者は、アップロード機能の使用を禁じされることも
+ありますのでご承知下さい。",
+
+/* <strong>STOP!</strong> Before you upload here,
+make sure to read and follow Wikipedia's <a href=\"" .
+wfLocalUrlE( "Wikipedia:Image_use_policy" ) . "\">image use policy</a>.
+<p>To view or search previously uploaded images,
+go to the <a href=\"" . wfLocalUrlE( "Special:Imagelist" ) .
+"\">list of uploaded images</a>.
+Uploads and deletions are logged on the <a href=\"" .
+wfLocalUrlE( "Wikipedia:Upload_log" ) . "\">upload log</a>.
+<p>Use the form below to upload new image files for use in
+illustrating your articles.
+On most browsers, you will see a \"Browse...\" button, which will
+bring up your operating system's standard file open dialog.
+Choosing a file will fill the name of that file into the text
+field next to the button.
+You must also check the box affirming that you are not
+violating any copyrights by uploading the file.
+Press the \"Upload\" button to finish the upload.
+This may take some time if you have a slow internet connection.
+<p>The preferred formats are JPEG for photographic images, PNG
+
+for drawings and other iconic images, and OGG for sounds.
+Please name your files descriptively to avoid confusion.
+To include the image in an article, use a link in the form
+<b>[[image:file.jpg]]</b> or <b>[[image:file.png|alt text]]</b>
+or <b>[[media:file.ogg]]</b> for sounds.
+<p>Please note that as with Wikipedia pages, others may edit or
+delete your uploads if they think it serves the encyclopedia, and
+you may be blocked from uploading if you abuse the system." */
+"uploadlog"            => "upload log",
+"uploadlogpage" => "Upload_log",
+"uploadlogpagetext" => "以下は最近のファイルのアップロードのログです。
+記録は全てサーバーの時間であるUTCに基づくものです。
+<ul>
+</ul>
+"
+/* Below is a list of the most recent file uploads.
+All times shown are server time (UTC). */,
+
+"filename"             => "ファイル名",
+"filedesc"             => "ファイルの概要",
+"affirmation"  => "このファイルの著作権者は$1のライセンスに基づく
+使用を許可したことをここに表明します。
+
+I affirm that the copyright holder of this file
+agrees to license it under the terms of the $1.",
+"copyrightpage" => "Wikipedia:Copyrights",
+
+"copyrightpagename" => "ウィキペディアの著作権",
+"uploadedfiles"        => "アップロードされたファイル",
+"noaffirmation" => "あなたのアップロードが著作権の侵害にあたらない旨を
+表明して下さい。"
+/* "You must affirm that your upload does not violate
+any copyrights." */,
+"ignorewarning"        => "警告を無視し、保存してしまう" /* "Ignore warning and save file anyway." */,
+"minlength"            => "ファイル名は3文字以上である必要があります。" /* "Image names must be at least three letters." */,
+"badfilename"  => "ファイル名は\"$1\"へ変更されました。" /* "Image name has been changed to \"$1\"." */,
+"badfiletype"  => "\".$1\" は推奨されているファイルフォーマットではありません。" /* 
+"\".$1\" is not a recommended image file format." */,
+"largefile"            => "ファイルサイズは100キロバイト以下に抑えることが推奨されています。" /* It is recommended that images not exceed 100k in size." */,
+"successfulupload" => "アップロード成功" /* "Successful upload" */,
+"fileuploaded" => "ファイル\"$1\は無事にアップロードされました。
+以下のリンク($2)をクリックし、ファイルについての情報-出典、製作者や時期、
+その他知っている情報を書き込んで下さい。
+
+" /* " "File \"$1\" uploaded successfully. 
+Please follow this link: ($2) to the description page and fill
+in information about the file, such as where it came from, when it was
+created and by whom, and anything else you may know about it." */,
+
+"uploadwarning" => "アップロード 警告" /* "Upload warning" */,
+"savefile"             => "ファイルを保存" /* "Save file" */,
+"uploadedimage" => "\"$1\"をアップロードしました。" /* "uploaded \"$1\"" */,
+
+# Image list
+#
+"imagelist"            => "画像リスト",
+"imagelisttext"                => "$1枚の画像を$2に表示しています",
+"getimagelist"         => "画像リストを取得",
+"ilshowmatch"           => "マッチする名前の画像を全て表示",
+"ilsubmit"             => "検索",
+"showlast"             => "$2に$1枚の画像を表示",
+"all"                  => "全て",
+"byname"               => "名前順",
+"bydate"               => "日付順",
+"bysize"               => "サイズ順",
+"imgdelete"            => "削除",
+"imgdesc"              => "詳細",
+"imglegend"            => "凡例: (詳細)=画像の詳細を表示/編集",
+"imghistory"           => "画像の履歴",
+"revertimg"            => "差戻",
+"deleteimg"            => "削除",
+"imghistlegend"         => "凡例: (最新)=最新版の画像, (削除)=この版の画像を削除, (差戻)=この版の画像に差し戻す<br><b>アップロードされた画像を見るには日付をクリックします。</b>",
+"imagelinks"           => "リンク",
+"linkstoimage"         => "この画像にリンクしているページの一覧:",
+"nolinkstoimage"        => "この画像にリンクしているページはありません。",
+
+# Statistics
+#
+"statistics"           => "アクセス統計",
+"sitestats"            => "サイト全体の統計",
+"userstats"            => "ユーザー登録統計",
+"sitestatstext"         => "<p>データベース内には <b>$1</b> ページのデータがあります。この数字には「会話ページ」や「Wikipedia関連のページ」、「書きかけのページ」、「リダイレクト」など、記事とはみなせないページが含まれています。これらを除いた、記事とみなされるページ数は約 <b>$2</b> ページになります。</p><p>ページの総閲覧回数は <b>$3</b> 回です。また、ソフトウェアの更新(2002/06/20)以来、<b>$4</b> 回の編集が行われました。平均すると、1ページあたり <b>$5</b> 回の編集が行われ、1編集あたり <b>$6</b> 回閲覧されています。</p>",
+"userstatstext"         => "登録済みの利用者は <b>$1</b> 人で、内 <b>$2</b> 人が管理者権限を持っています。($3を参照)",
+
+# Miscellaneous special pages
+#
+"orphans"              => "孤立しているページ",
+"lonelypages"          => "孤立しているページ",
+"unusedimages"         => "使われていない画像",
+"popularpages"         => "人気のページ",
+"nviews"               => "$1 回表示",
+"wantedpages"          => "投稿が望まれているページ",
+"nlinks"               => "$1 個のリンク",
+"allpages"             => "全ページ",
+"randompage"           => "おまかせ表示",
+"shortpages"           => "短いページ",
+"longpages"            => "長いページ",
+"listusers"            => "登録ユーザー一覧",
+"specialpages"         => "特別ページ",
+"spheading"            => "特別ページ",
+"sysopspheading"        => "シスオペ用特別ページ (pages for sysop)",
+"developerspheading"    => "開発者用特別ページ (pages for developper)",
+"protectpage"          => "Protect page",
+"recentchangeslinked"   => "リンクを見張る",
+"rclsub"               => "(to pages linked from \"$1\")",
+"debug"                        => "デバッグ (debug)",
+"newpages"             => "新しいページ",
+"movethispage"         => "このページを移動する",
+"unusedimagestext" => "<p>ご注意:他言語版のウィキペディアも含め、他のウェブサイトがURLを直接用いて画像にリンクしている場合もあります。以下の画像一覧には、そのような形で利用されている画像が含まれている可能性があります。",
+"booksources"  => "文献資料",
+"booksourcetext" => "以下のリストは、新本、古本などを販売している外部サイトへのリンクです。
+あなたがお探しの本について、更に詳しい情報が提供されている場合もあります。
+ウィキペディアはこれらの業務とは提携関係は持っていません。また、このリストはリストされたサイトへのウィキペディアの支持を表すものでもありません。",
+
+# Email this user
+#
+"mailnologin"  => "送信先のアドレスがありません。" /* No send address"*/,
+"mailnologintext" => "ログインしていません。メールを送信するためには、
+あなたの電子メールアドレスを<a href=\"" .
+  wfLocalUrl( "Special:ユーザーオプション" ) . "\">ユーザーオプション</a>
+で指定し、
+<a href=\"" .
+  wfLocalUrl( "特別:Userlogin" ) . "\">ログイン</a>している必要があります。"
+/* You must be <a href=\"" .
+  wfLocalUrl( "Special:Userlogin" ) . "\">logged in</a>
+and have a valid e-mail address in your <a href=\"" .
+  wfLocalUrl( "Special:Preferences" ) . "\">preferences</a>
+to send e-mail to other users." */,
+"emailuser"            => "このユーザーにメールを送る" /* "E-mail this user" */,
+"emailpage"            => "メール送信ページ" /* "E-mail user" */,
+"emailpagetext"        => "もしメールを送る先のユーザーが、有効なメールアドレスを
+ユーザーオプションに登録してあれば、下のフォームを通じてメールを送ることができます。
+あなたが登録したご自分のメールアドレスはFrom:の欄に自動的に組み込まれ、受け取った相手が
+返事を出せるようになっています。"
+
+/* "If this user has entered a valid e-mail address in
+is user preferences, the form below will send a single message.
+The e-mail address you entered in your user preferences will appear
+as the \"From\" address of the mail, so the recipient will be able
+to reply."*/,
+"noemailtitle" => "送り先のメールアドレスがありません。" /* "No e-mail address" */,
+"noemailtext"  => "このユーザーは有効なメールアドレスを登録していないか、メールを受け取りたくないというオプションを選択しています。"
+ /* "This user has not specified a valid e-mail address,
+or has chosen not to receive e-mail from other users." */,
+"emailfrom"            => "あなたのアドレス" /* "From" */,
+"emailto"              => "あて先" /* "To" */,
+"emailsubject" => "題名" /* "Subject" */,
+"emailmessage" => "本文" /* "Message" */,
+"emailsend"            => "メール送信" /* "Send" */,
+"emailsent"            => "メールを送りました" /* "E-mail sent" */,
+"emailsenttext" => "メールは無事送信されました。" /* "Your e-mail message has been sent." */,
+
+# Watchlist ウォッチリスト
+#
+"watchlist"            => "ウォッチリスト",
+"watchlistsub" => "(ユーザー名 \"$1\")" /* (for user \"$1\") */,
+"nowatchlist"  => "あなたのウォッチリストは空です。" /* "You have no items on your watchlist." */,
+"watchnologin" => "ログインしていません" /* "Not logged in" */,
+"watchnologintext"     => "ウォッチリストを変更するためには、
+<a href=\"" .
+  wfLocalUrl( "特別:Userlogin" ) . "\">ログイン</a>している必要があります。"
+/* "You must be <a href=\"" .
+  wfLocalUrl( "Special:Userlogin" ) . "\">logged in</a>
+to modify your watchlist." */,
+"addedwatch"   => "ウォッチリストに加えました" /* "Added to watchlist" */,
+"addedwatchtext" => "ページ\"$1\" をあなたの
+<a href=\"" .
+  wfLocalUrl( "特別:Watchlist" ) . "\">ウォッチリスト</a>
+に追加しました。
+このページと、付属のノートのページに変更があった際にはそれをウォッチリストで
+知ることができます。また、
+<a href=\"" . wfLocalUrl( "特別:Recentchanges" ) . "\">最近更新したページ</a> では
+ウォッチリストに含まれているページは<b>ボールド体</b>で表示され、見つけやすく
+なります。</p>
+
+<p>もしもウォッチリストから特定のページを削除したい場合には、サイドバーにある
+\"ウォッチリストから削除\" のリンクをクリックして下さい。",
+
+/* The page \"$1\" has been added to your <a href=\"" .
+  wfLocalUrl( "Special:Watchlist" ) . "\">watchlist</a>.
+Future changes to this page and its associated Talk page will be listed there,
+and the page will appear <b>bolded</b> in the <a href=\"" .
+  wfLocalUrl( "Special:Recentchanges" ) . "\">list of recent changes</a> to
+make it easier to pick out.</p> 
+
+<p>If you want to remove the page from your watchlist later, click \"Stop watching\" in the sidebar." */
+
+"removedwatch" => "ウォッチリストから削除しました" /* "Removed from watchlist" */,
+"removedwatchtext" => "ページ\"$1\はウォッチリストから削除されました。" /* "The page \"$1\" has been removed from your watchlist." */,
+"watchthispage"        => "ウォッチリストに追加" /* "Watch this page" */,
+"unwatchthispage" => "ウォッチリストから削除" /* "Stop watching" */,
+"notanarticle" => "これは記事ではありません。" /* "Not an article" */,
+
+# Delete/protect/revert  (ここは管理者用の部分なので当面英文を残しておきます。)
+#
+"deletepage"   => "Delete page (ページ削除)",
+"confirm"              => "Confirm (確認)",
+"confirmdelete" => "Confirm delete (削除確認)",
+"deletesub"            => "(Deleting \"$1\") (サブページ\"$1\"を削除)",
+"confirmdeletetext" => "指定されたページまたはイメージは、その更新履歴と共に
+データベースから永久に削除されようとしています。
+あなたが削除を望んでおり、それがもたらす帰結を理解しており、かつあなたの
+しようとしていることが[[Wikipedia:Policy|ウィキペディアの基本方針]]に即したものであることを確認して下さい。
+
+You are about to permanently delete a page
+or image along with all of its history from the database.
+Please confirm that you intend to do this, that you understand the
+consequences, and that you are doing this in accordance with
+[[Wikipedia:Policy]].",
+"confirmcheck" => "はい。上記の通りです。 Yes, I really want to delete this.",
+"actioncomplete" => "削除を完了しました。 Action complete",
+"deletedtext"  => "\"$1\" は削除されました。 \"$1\" has been deleted.
+最近の削除に関しては$2 を参照して下さい。
+See $2 for a record of recent deletions.",
+"deletedarticle" => "\"$1\" を削除しました",
+"dellogpage"   => "削除記録 Deletion_log",
+"dellogpagetext" => "以下に示すのは最近の削除記録です。時間はサーバーの時間(UTC)によって記録されています。
+
+Below is a list of the most recent deletions.
+All times shown are server time (UTC).
+<ul>
+</ul>
+",
+"deletionlog"  => "削除記録 deletion log",
+"reverted"             => "以前のバージョンへの差し戻し。 Reverted to earlier revision",
+"deletecomment"        => "削除の理由 Reason for deletion",
+"imagereverted" => "以前のバージョンへの差し戻しに成功しました。 Revert to earlier version was successful.",
+
+# Contributions ユーザーの投稿記録
+#
+"contributions"        => "ユーザーの投稿記録",
+"contribsub"   => "ユーザー名:$1",
+"nocontribs"   => "ユーザーの投稿記録は見つかりませんでした。",
+"ucnote"               => "以下に示すのが過去<b>$2</b>日間における、最大<b>$1</b>件の投稿・編集です。" /*Below are this user's last <b>$1</b> changes in the last <b>$2</b> days."*/,
+"uclinks"              => "$1 件の投稿・編集を見る。; $2日間分の投稿・編集を見る。
+
+View the last $1 changes; view the last $2 days.",
+
+# What links here このページにリンクしている他のページ
+#
+"whatlinkshere"        => "ここにリンクしている他のページ" /* "what links here" */,
+"notargettitle" => "対象となるページが存在しません" /* "No target" */,
+"notargettext" => "対象となるページ又はユーザーが指定されていません" /* "You have not specified a target page or user
+to perform this function on." */,
+"linklistsub"  => "リンクのリスト" /* "(List of links)" */,
+"linkshere"            => "以下のページが指定されたページにリンクしています。" /* "The following pages link to here:" */,
+"nolinkshere"  => "指定されたページにリンクしているページはありません。" /* "No pages link to here." */,
+"isredirect"   => "リダイレクトページ" /* "redirect page" */,
+
+# Block/unblock IP (この部分は管理者用なので当面英文を残しておきます。)
+#
+"blockip"              => "Block IP address",
+"blockiptext"  => "Use the form below to block write access
+from a specific IP address.
+This should be done only only to prevent valndalism, and in
+accordance with [[Wikipedia:Policy|Wikipedia policy]].
+Fill in a specific reason below (for example, citing particular
+pages that were vandalized).",
+"ipaddress"            => "IP Address",
+"ipbreason"            => "Reason",
+"ipbsubmit"            => "Block this address",
+"badipaddress" => "The IP address is badly formed.",
+"noblockreason" => "You must supply a reason for the block.",
+"blockipsuccesssub" => "Block succeeded",
+"blockipsuccesstext" => "The IP address \"$1\" has been blocked.
+<br>See [[Special:Ipblocklist|IP block list]] to review blocks.",
+"unblockip"            => "Unblock IP address",
+"unblockiptext"        => "Use the form below to restore write access
+to a previously blocked IP address.",
+"ipusubmit"            => "Unblock this address",
+"ipusuccess"   => "IP address \"$1\" unblocked",
+"ipblocklist"  => "List of blocked IP addresses",
+"blocklistline"        => "$1, $2 blocked $3",
+"blocklink"            => "block",
+"unblocklink"  => "unblock",
+"contribslink" => "contribs",
+
+# Developer tools  (この部分は管理者用なので当面英文を残しておきます。)
+#
+"lockdb"               => "Lock database",
+"unlockdb"             => "Unlock database",
+"lockdbtext"   => "Locking the database will suspend the ability of all
+users to edit pages, change their preferences, edit their watchlists, and
+other things requiring changes in the database.
+Please confirm that this is what you intend to do, and that you will
+unlock the database when your maintenance is done.",
+"unlockdbtext" => "Unlocking the database will restore the ability of all
+users to edit pages, change their preferences, edit their watchlists, and
+other things requiring changes in the database.
+Please confirm that this is what you intend to do.",
+"lockconfirm"  => "Yes, I really want to lock the database.",
+"unlockconfirm"        => "Yes, I really want to unlock the database.",
+"lockbtn"              => "Lock database",
+"unlockbtn"            => "Unlock database",
+"locknoconfirm" => "You did not check the confirmation box.",
+"lockdbsuccesssub" => "Database lock succeeded",
+"unlockdbsuccesssub" => "Database lock removed",
+"lockdbsuccesstext" => "The Wikipedia database has been locked.
+<br>Remember to remove the lock after your maintenance is complete.",
+"unlockdbsuccesstext" => "The Wikipedia database has been unlocked.",
+
+# SQL query     (この部分は管理者用なので当面英文を残しておきます。)
+#
+"asksql"               => "SQL query",
+"asksqltext"   => "Use the form below to make a direct query of the
+Wikipedia database.
+Use single quotes ('like this') to delimit string literals.
+This can often add considerable load to the server, so please use
+this function sparingly.",
+"sqlquery"             => "Enter query",
+"querybtn"             => "Submit query",
+"selectonly"   => "Queries other than \"SELECT\" are restricted to
+Wikipedia developers.",
+"querysuccessful" => "Query successful",
+
+# Move page ページの移動
+#
+"movepage"             => "ページの移動",
+"movepagetext" => "以下のフォームを利用して、ページ名を変更し、
+そのページに付随する履歴の情報を変更先のページへ移動することができます。
+変更されるページは、変更後は変更先へのリダイレクトページになります。
+更新前のページへと張られたリンクは変更されません。また、ページに付随する
+ノートのページも移動されません。
+<b>注意!</b>
+これは人気のあるページにとって抜本的で予想外の変更になるかも知れません。
+ページの移動に伴う諸帰結をよく理解してから移動に踏み切るようにして下さい。"
+
+/* "Using the form below will rename a page, moving all
+of its history to the new name.
+The old title will become a redirect page to the new title.
+Links to the old page title will not be changed, and the talk
+page, if any, will not be moved.
+<b>WARNING!</b>
+This can be a drastic and unexpected change for a popular page;
+please be sure you understand the consequences of this before
+proceeding." */,
+"movearticle"  => "ページの移動",
+"movenologin"  => "ログインしていません",
+"movenologintext" => "この機能を利用するためには、ユーザー登録をして、
+<a href=\"" .
+  wfLocalUrl( "特別:Userlogin" ) . "\">ログイン</a>している必要が
+あります。",
+"newtitle"             => "新しいページへ" /* "To new title" */,
+"movepagebtn"  => "ページを移動" /* "Move page" */,
+"pagemovedsub" => "無事移動しました。" /* "Move succeeded" */,
+"pagemovedtext" => "ページ\"[[$1]]\" は \"[[$2]]\" に移動しました。" /* "Page \"[[$1]]\" moved to \"[[$2]]\"." */,
+"articleexists" => "指定された移動先には既にページが存在するか、名前が不適切です。" /* "A page of that name already exists, or the
+name you have chosen is not valid.
+Please choose another name." */,
+"movedto"              => "移動先:" /* "moved to" */,
+"movetalk"             => "付随するノートのページが存在する場合にはそれも同時に移動させる" /* "Move \"talk\" page as well, if applicable." */,
+"talkpagemoved" => "付随のノートのページも移動しました。" /* "The corresponding talk page was also moved." */,
+"talkpagenotmoved" => "付随のノートのページは<b>移動されませんでした。</b>" /* "The corresponding talk page was <strong>not</strong> moved." */,
+
+);
+
+class LanguageJa extends LanguageUtf8 {
+
+       function getNamespaces() {
+               global $wgNamespaceNamesJa;
+               return $wgNamespaceNamesJa;
+       }
+
+       function getNsText( $index ) {
+               global $wgNamespaceNamesJa;
+               return $wgNamespaceNamesJa[$index];
+       }
+
+       function getNsIndex( $text ) {
+               global $wgNamespaceNamesJa;
+
+               foreach ( $wgNamespaceNamesJa as $i => $n ) {
+                       if ( 0 == strcasecmp( $n, $text ) ) { return $i; }
+               }
+               return false;
+       }
+
+       function getQuickbarSettings() {
+               global $wgQuickbarSettingsJa;
+               return $wgQuickbarSettingsJa;
+       }
+
+       function getSkinNames() {
+               global $wgSkinNamesJa;
+               return $wgSkinNamesJa;
+       }
+
+
+       function getUserToggles() {
+               global $wgUserTogglesJa;
+               return $wgUserTogglesJa;
+       }
+
+       function getLanguageName( $code ) {
+               global $wgLanguageNamesJa;
+               if ( ! array_key_exists( $code, $wgLanguageNamesJa ) ) {
+                       return "";
+               }
+               return $wgLanguageNamesJa[$code];
+       }
+
+       function getMonthName( $key )
+       {
+               global $wgMonthNamesJa;
+               return $wgMonthNamesJa[$key-1];
+       }
+
+       function getMonthAbbreviation( $key )
+       {
+               global $wgMonthAbbreviationsJa;
+               return $wgMonthAbbreviationsJa[$key-1];
+       }
+
+       function getWeekdayName( $key )
+       {
+               global $wgWeekdayNamesJa;
+               return $wgWeekdayNamesJa[$key-1];
+       }
+
+       # Inherit default userAdjust()
+        
+       function date( $ts, $adj = false )
+       {
+               if ( $adj ) { $ts = $this->userAdjust( $ts ); }
+
+               $d = substr( $ts, 0, 4 ) . "年" .
+                 $this->getMonthAbbreviation( substr( $ts, 4, 2 ) ) .
+                 (0 + substr( $ts, 6, 2 )) . "日";
+               return $d;
+       }
+
+       function time( $ts, $adj = false )
+       {
+               if ( $adj ) { $ts = $this->userAdjust( $ts ); }
+
+               $t = substr( $ts, 8, 2 ) . ":" . substr( $ts, 10, 2 );
+               return $t;
+       }
+
+       function timeanddate( $ts, $adj = false )
+       {
+               return $this->time( $ts, $adj ) . " " . $this->date( $ts, $adj );
+       }
+
+       # Inherit default rfc1123()
+
+       function getValidSpecialPages()
+       {
+               global $wgValidSpecialPagesJa;
+               return $wgValidSpecialPagesJa;
+       }
+
+       function getSysopSpecialPages()
+       {
+               global $wgSysopSpecialPagesJa;
+               return $wgSysopSpecialPagesJa;
+       }
+
+       function getDeveloperSpecialPages()
+       {
+               global $wgDeveloperSpecialPagesJa;
+               return $wgDeveloperSpecialPagesJa;
+       }
+
+       function getMessage( $key )
+       {
+               global $wgAllMessagesJa;
+        if(array_key_exists($key, $wgAllMessagesJa))
+                       return $wgAllMessagesJa[$key];
+               else
+                       return Language::getMessage($key);
+       }
+
+       function stripForSearch( $string ) {
+               # MySQL fulltext index doesn't grok utf-8, so we
+               # need to fold cases and convert to hex
+               global $wikiLowerChars;
+               $s = $string;
+
+               # Strip known punctuation ?
+               #$s = preg_replace( '/\xe3\x80[\x80-\xbf]/', '', $s ); # U3000-303f
+
+               # Space strings of like hiragana/katakana/kanji
+               $hiragana = '(?:\xe3(?:\x81[\x80-\xbf]|\x82[\x80-\x9f]))'; # U3040-309f
+               $katakana = '(?:\xe3(?:\x82[\xa0-\xbf]|\x83[\x80-\xbf]))'; # U30a0-30ff
+               $kanji = '(?:\xe3[\x88-\xbf][\x80-\xbf]'
+                       . '|[\xe4-\xe8][\x80-\xbf]{2}'
+                       . '|\xe9[\x80-\xa5][\x80-\xbf]'
+                       . '|\xe9\xa6[\x80-\x99])';
+                       # U3200-9999 = \xe3\x88\x80-\xe9\xa6\x99
+               $s = preg_replace( "/({$hiragana}+|{$katakana}+|{$kanji}+)/", ' $1 ', $s );
+
+               # Double-width roman characters: ff00-ff5f ~= 0020-007f
+               $s = preg_replace( '/\xef\xbc([\x80-\xbf])/e', 'chr((ord("$1") & 0x3f) + 0x20)', $s );
+               $s = preg_replace( '/\xef\xbd([\x80-\x99])/e', 'chr((ord("$1") & 0x3f) + 0x60)', $s );
+
+               return trim( preg_replace(
+                 "/([\\xc0-\\xff][\\x80-\\xbf]*)/e",
+                 "'U8' . bin2hex( strtr( \"\$1\", \$wikiLowerChars ) )",
+                 $s ) );
+               return $s;
+       }
+
+}
+
+?>
diff --git a/languages/LanguageKo.php b/languages/LanguageKo.php
new file mode 100644 (file)
index 0000000..2517cd7
--- /dev/null
@@ -0,0 +1,1094 @@
+<?
+global $IP;
+include_once( "$IP/Utf8Case.php" );
+
+# The names of the namespaces can be set here, but the numbers
+# are magical, so don't change or move them!  The Namespace class
+# encapsulates some of the magic-ness.
+
+/* private */ $wgNamespaceNamesKo = array(
+       -1      => "특수기능",      # Special
+       0       => "",
+       1       => "토론",    # Talk
+       2       => "사용자", # User
+       3       => "사용자토론",   # User_talk
+       4       => "위키백과",      # Wikipedia
+       5       => "위키백과토론",# Wikipedia_talk
+       6       => "그림",    # Image
+       7       => "그림토론"       # Image_talk
+);
+
+# I always compare this file with japanese file, when I'm confused.
+# And DefaultUserOption isn't there in japanese one. What's
+# this? I don't have to translate this. Am I right?
+
+# The Japanese file is a bit obsolete, so don't trust it too much!
+# Don't translate the text strings here, but you can customize any
+# option values if you like. These will be the defaults for any user
+# who isn't logged in, or a newly created user account.
+
+/* private */ $wgDefaultUserOptionsKo = array(
+       "quickbar" => 1, "underline" => 1, "hover" => 1,
+       "cols" => 80, "rows" => 25, "searchlimit" => 20,
+       "contextlines" => 5, "contextchars" => 50,
+       "skin" => 0, "math" => 1, "rcdays" => 14, "rclimit" => 50,
+       "highlightbroken" => 1, "stubthreshold" => 0
+);
+
+/* private */ $wgQuickbarSettingsKo = array(
+#      "None", "Fixed left", "Fixed right", "Floating left"
+       "없음", "왼쪽 붙박이", "오른쪽 붙박이", "왼쪽 떠다님"
+
+);
+
+/* private */ $wgSkinNamesKo = array(
+#      "Standard", "Nostalgia", "Cologne Blue"
+       "보통", "그리움", "쾰른 파랑"
+);
+
+/* private */ $wgUserTogglesKo = array(
+       "hover"         => "위키고리 풍선상자로 보이기",
+       "underline" => "고리에 밑줄치기",
+       "highlightbroken" => "없는 문서로의 고리 돋보이기",
+       "justify"       => "문단 정렬",
+       "hideminor" => "사소한 편집 최근 바뀜에서 숨기기",
+       "numberheadings" => "머릿글 번호 매기기",
+       "rememberpassword" => "세션동안 암호 기억",
+       "editwidth" => "편집상자 너비 최대",
+       "editondblclick" => "Edit pages on double click (JavaScript)",
+       "watchdefault" => "Watch new and modified articles"
+);
+
+/* private */ $wgBookstoreListKo = array(
+       "AddALL" => "http://www.addall.com/New/Partner.cgi?query=$1&type=ISBN",
+       "PriceSCAN" => "http://www.pricescan.com/books/bookDetail.asp?isbn=$1",
+       "Barnes & Noble" => "http://shop.barnesandnoble.com/bookSearch/isbnInquiry.asp?isbn=$1",
+       "Amazon.com" => "http://www.amazon.com/exec/obidos/ISBN=$1",
+       "Aladdin.co.kr" => "http://www.aladdin.co.kr/catalog/book.asp?ISBN=$1"
+);
+
+/* These should preferably be the native names of the languages; the
+   point is for people who speak them to be able to navigate to them
+   from any language section of the Wikipedia. */
+/* 아래 언어명은 그 언어 사용자들을 위한 것이므로, 한국어로 고치지 마세요. */
+/* private */ $wgLanguageNamesKo = array(
+    "af" => "Afrikaans",
+       "ar" => "&#8238;&#1575;&#1604;&#1593;&#1585;&#1576;&#1610;&#1577;&#8236; (Araby)",
+       "be" => "&#1041;&#1077;&#1083;&#1072;&#1088;&#1091;&#1089;&#1082;&#1080;",
+       "br" => "Brezhoneg",
+       "ca" => "Catal&#224;",
+       "ch" => "Chamoru",
+       "cs" => "&#268;esk&#225;",
+       "cy" => "Cymraeg",
+       "da" => "Dansk", # Note two different subdomains. 
+       "dk" => "Dansk", # 'da' is correct for the language.
+       "de" => "Deutsch",
+       "el" => "&#917;&#955;&#955;&#951;&#957;&#953;&#954;&#940; (Ellenika)",
+       "en" => "English",
+       "simple" => "Simple English",
+       "eo" => "Esperanto",
+       "es" => "Espa&#241;ol",
+       "et" => "Eesti",
+       "eu" => "Euskara",
+       "fa" => "&#8238;&#1601;&#1585;&#1587;&#1609;&#8236;(Farsi)",
+       "fi" => "Suomi",
+       "fr" => "Fran&#231;ais",
+       "gu" => "&#2711;&#2753;&#2716;&#2736;&#2750;&#2724;&#2752; (Gujarati)",
+       "he" => "&#1506;&#1489;&#1512;&#1497;&#1514; (Ivrit)",
+       "hi" => "&#2361;&#2367;&#2344;&#2381;&#2342;&#2368; (Hindi)",
+       "hr" => "Hrvatski",
+       "hu" => "Magyar",
+       "ia" => "Interlingua",
+       "id" => "Indonesia",
+       "is" => "&#205;slenska",
+       "it" => "Italiano",
+       "ja" => "&#26085;&#26412;&#35486; (Nihongo)",
+       "ka" => "&#4325;&#4304;&#4320;&#4311;&#4309;&#4308;&#4314;&#4312; (Kartuli)",
+       "ko" => "한국어",
+       "kw" => "Kernewek",
+       "la" => "Latina",
+       "lt" => "Lietuvi&#371;",
+       "mg" => "Malagasy",
+       "ms" => "Bahasa Melayu",
+       "ne" => "&#2344;&#2375;&#2346;&#2366;&#2354;&#2368; (Nepali)",
+       "nl" => "Nederlands",
+       "no" => "Norsk",
+       "pl" => "Polski",
+       "pt" => "Portugu&#234;s",
+       "ro" => "Rom&#226;n&#259;",
+       "ru" => "&#1056;&#1091;&#1089;&#1089;&#1082;&#1080;&#1081; (Russkij)",
+       "sa" => "&#2360;&#2306;&#2360;&#2381;&#2325;&#2371;&#2340; (Samskrta)",
+       "so" => "Soomaali",
+       "sq" => "Shqiptare",
+       "sr" => "Srpski",
+       "sv" => "Svenska",
+       "sw" => "Kiswahili",
+       "tr" => "T&#252;rk&#231;e",
+       "uk" => "&#1059;&#1082;&#1088;&#1072;&#1111;&#1085;&#1089;&#1100;&#1082;&#1072; (Ukrayins`ka)",
+       "vo" => "Volap&#252;k",
+       "xh" => "isiXhosa",
+       "zh" => "&#20013;&#25991; (Zhongwen)"
+);
+
+/* private */ $wgWeekdayNamesKo = array(
+       "일요일", "월요일", "화요일", "수요일", "목요일",
+       "금요일", "토요일"
+);
+
+
+# (Okay, I think I got it right now. This can be adjusted
+#  in the 'date' function down at the bottom. --Brion)
+#
+# Thanks. And it's usual that the time comes after dates.
+# So I've change the timeanddate function, just exchanged $time and $date 
+# But you should check before you install it, 'cause I'm quite stupid about
+# the programming. 
+#
+
+/* private */ $wgWeekdayAbbreviationsKo = array(
+       "日", "月", "火", "水", "木",
+       "金", "土"
+);
+
+/* private */ $wgMonthNamesKo = array(
+       "1월", "2월", "3월", "4월", "5월", "6월",
+       "7월", "8월", "9월", "10월", "11월",
+       "12월"
+);
+
+/* private */ $wgMonthAbbreviationsKo = array(
+       "1", "2", "3", "4", "5", "6", "7", "8",
+        "9", "10", "11",       "12"
+);
+
+# All special pages have to be listed here: a description of ""
+# will make them not show up on the "Special Pages" page, which
+# is the right thing for some of them (such as the "targeted" ones).
+#
+
+
+/* private */ $wgValidSpecialPagesKo = array(
+       "Userlogin"             => "들어가기",
+       "Userlogout"    => "나오기",
+       "Preferences"   => "개인 맞춤",
+       "Watchlist"             => "눈여겨보기목록",
+       "Recentchanges" => "최근 바뀜",
+       "Upload"                => "파일 올리기",
+       "Imagelist"             => "그림 목록",
+       "Listusers"             => "사용자 목록",
+       "Statistics"    => "누리터 통계",
+       "Randompage"    => "아무거나",
+
+       "Lonelypages"   => "외톨이 문서",
+       "Unusedimages"  => "외톨이 그림",
+       "Popularpages"  => "인기있는 문서",
+       "Wantedpages"   => "가장 필요한 문서",
+       "Shortpages"    => "짧은 문서",
+       "Longpages"             => "긴 문서",
+       "Newpages"              => "새 문서",
+       "Allpages"              => "모두 나열",
+
+       "Ipblocklist"   => "막힌 IP",
+
+       "Maintenance" => "관리",
+       "Specialpages"  => "",
+       "Contributions" => "", # These are supposed to be blank;
+       "Emailuser"             => "", # they don't work without the target
+       "Whatlinkshere" => "", # link so can't be used from the
+       "Recentchangeslinked" => "", # plain special pages list
+       "Movepage"              => "",
+       "Booksources"   => "외부 책방"
+);
+
+# I'll leave this part in english, for it's more likely that
+# there will probably no Korean for the maintaining this site
+# in near future, and if any shows up, he would possibly speak
+# both Korean and English. And he can later koreanize this part.
+
+/* private */ $wgSysopSpecialPagesKo = array(
+       "Blockip"               => "Block an IP address",
+       "Asksql"                => "Query the database",
+       "Undelete"              => "Undelete Page"
+);
+
+/* private */ $wgDeveloperSpecialPagesKo = array(
+       "Lockdb"                => "Make database read-only",
+       "Unlockdb"              => "Restore database write access",
+       "Debug"                 => "Debugging information"
+);
+
+/* private */ $wgAllMessagesKo = array(
+
+# Bits of text used by many pages:
+#
+"mainpage"             => "대문",
+"about"                        => "소개",
+"aboutwikipedia" => "위키백과란",
+"aboutpage"            => "위키백과:소개",
+"help"                 => "도움말",
+"helppage"             => "위키백과:도움말",
+"wikititlesuffix" => "위키백과",
+"bugreports"   => "벌레 발견",
+"bugreportspage" => "위키백과:벌레_발견",
+"faq"                  => "잦은질문(FAQ)",
+"faqpage"              => "위키백과:잦은질문(FAQ)",
+"edithelp"             => "편집 도움말",
+"edithelppage" => "위키백과:문서_편집_방법",
+"cancel"               => "취소",
+"qbfind"               => "찾기",
+
+# where does this "browse" appear? I haven't seen it.
+# and therefore no idea what its function is.
+
+# (Select the Cologne Blue skin; it's a section header
+#  in the sidebar over 'main page', 'recent changes', etc.)
+
+"qbbrowse"             => "항해판",
+"qbedit"               => "고치기",
+"qbpageoptions" => "문서 기능",
+"qbpageinfo"   => "문서 정보",
+"qbmyoptions"  => "자기 기능",
+"mypage"               => "자기 문서",
+"mytalk"               => "자기 토론",
+"currentevents" => "요즘의 화제",
+"errorpagetitle" => "오류",
+"returnto"             => "$1(으)로 돌아가기.",
+"fromwikipedia"        => "위키백과, 우리 모두의 백과사전.",
+"whatlinkshere"        => "여길 가리키는 문서",
+"help"                 => "도움말",
+"search"               => "찾기",
+"history"              => "문서역사",
+"printableversion" => "인쇄용",
+"editthispage" => "문서 고치기",
+"deletethispage" => "문서 지우기",
+"protectthispage" => "문서 보호",
+"unprotectthispage" => "문서 보호 해제",
+"talkpage"             => "토론",
+"subjectpage"  => "본 문서",
+"otherlanguages" => "다른 언어",
+"redirectedfrom" => "($1에서 넘어옴.)",
+"lastmodified" => "이 문서는 최근 $1에 바뀌었습니다.",
+
+"viewcount"            => "이 문서는 총 $1번 읽혔습니다.",
+"printsubtitle" => "(http://www.wikipedia.org에서)",
+"protectedpage" => "보호되는 문서",
+"administrators" => "위키백과:관리자",
+"sysoptitle"   => "Sysop 권한 필요",
+"sysoptext"            => "해당 action은 \"Sysop\"만 실행할 수 있습니다.
+참조 $1.",
+"developertitle" => "Developer 권한 필요",
+"developertext"        => "해당 action은 \"developer\"만 실행할 수 있습니다.
+참조 $1.",
+"nbytes"               => "$1 바이트",
+"go"                   => "가기",
+"ok"                   => "확인",
+"sitetitle"            => "위키백과",
+"sitesubtitle" => "우리 모두의 백과사전",
+"retrievedfrom" => "\"$1\"에서",
+
+# Main script and global functions
+#
+"nosuchaction" => "그런 action은 없습니다.",
+"nosuchactiontext" => "위키백과 무른모는 URL로 주어진 action을
+모릅니다.",
+"nosuchspecialpage" => "틀린 특수기능",
+"nospecialpagetext" => "위키백과는 요청한 특수기능을
+모릅니다.",
+
+# General errors
+#
+# I'll leave this part in English for admins who don't understand Korean.
+"error"                        => "Error",
+"databaseerror" => "Database error",
+"dberrortext"  => "A database query syntax error has occurred.
+This could be because of an illegal search query (see $5),
+or it may indicate a bug in the software.
+The last attempted database query was:
+<blockquote><tt>$1</tt></blockquote>
+from within function \"<tt>$2</tt>\".
+MySQL returned error \"<tt>$3: $4</tt>\".",
+"noconnect"            => "Could not connect to DB on $1",
+"nodb"                 => "Could not select database $1",
+"readonly"             => "Database locked",
+"enterlockreason" => "Enter a reason for the lock, including an estimate
+of when the lock will be released",
+"readonlytext" => "The Wikipedia database is currently locked to new
+entries and other modifications, probably for routine database maintenance,
+after which it will be back to normal.
+The administrator who locked it offered this explanation:
+<p>$1",
+"missingarticle" => "The database did not find the text of a page
+that it should have found, named \"$1\".
+This is not a database error, but likely a bug in the software.
+Please report this to an administrator, making note of the URL.",
+"internalerror" => "Internal error",
+"filecopyerror" => "Could not copy file \"$1\" to \"$2\".",
+"filerenameerror" => "Could not rename file \"$1\" to \"$2\".",
+"filedeleteerror" => "Could not delete file \"$1\".",
+"filenotfound" => "Could not find file \"$1\".",
+"unexpected"   => "Unexpected value: \"$1\"=\"$2\".",
+"formerror"            => "Error: could not submit form",      
+"badarticleerror" => "This action cannot be performed on this page.",
+"cannotdelete" => "Could not delete the page or image specified.",
+
+# Login and logout pages
+#
+"logouttitle"  => "나옴",
+"logouttext"   => "위키백과에서 나왔습니다.
+이대로 이름없이 위키백과를 이용하거나, 방금 사용했던 또이름, 혹은 다른 또이름으로 들어가서 이용하세요.\n",
+
+"welcomecreation" => "<h2>$1 님, 환영합니다!</h2><p>또이름이 만들어 졌습니다.
+개인 맞춤에서 자잘한 환경들을 바꾸어 보세요.",
+
+"loginpagetitle" => "들어가기",
+"yourname"             => "또이름은",
+"yourpassword" => "암호는",
+"yourpasswordagain" => "암호 또 한번",
+"newusersonly" => " (새내기 사용자)",
+"remembermypassword" => "세쎤동안 암호를 기억합니다.",
+"loginproblem" => "<b>들어가는 데 문제가 있습니다.</b><br>다시 해 보세요!",
+"alreadyloggedin" => "<font color=red><b>$1 님, 벌써 들어와 있습니다!</b></font><br>\n",
+
+"areyounew"            => "위키백과에 처음 왔나요? 위키백과의 한 사람이 되고 싶다면, 
+또이름을 하나 지어 또이름란에 써 넣고, 암호를 두번 써 넣으세요. 
+누리편지주소는 넣지 않아도 됩니다. 다만,  
+암호를 잊었을 때, 편지로 새 암호를 보내드립니다.<br>\n",
+
+"login"                        => "들어가기",
+"userlogin"            => "들어가기",
+"logout"               => "나가기",
+"userlogout"   => "나오기",
+"createaccount"        => "또이름 새로 만들기",
+"badretype"            => "암호가 서로 다릅니다.",
+"userexists"   => "또이름이 벌써 사용중입니다. 다른 또이름을 지으세요.",
+"youremail"            => "당신의 누리편지",
+"yournick"             => "당신의 별명 (서명용)",
+"emailforlost" => "암호를 잊었을 때, 새 암호를 누리편지로 받을 수 있습니다.",
+"loginerror"   => "들어가기 오류",
+"noname"               => "또이름이 틀립니다.",
+"loginsuccesstitle" => "들어가기 성공",
+"loginsuccess" => "\"$1\" 위키백과에 들어왔습니다.",
+"nosuchuser"   => "\"$1\"란 또이름은 없습니다.".
+"철자가 맞는지 확인하고, 아직 또이름이 없다면, 아래를 채워 또이름을 새로이 만드세요.",
+"wrongpassword"        => "암호가 틀립니다. 다시 시도하세요.",
+"mailmypassword" => "새 암호를 누리편지로 보냅니다.",
+"passwordremindertitle" => "위키백과에서 보내는 새 암호",
+"passwordremindertext" => "누군가가 (IP $1 을 사용했던, 아마도 당신이)
+새 위키백과 암호를 보내달라고 부탁했습니다.
+또이름 \"$2\"의 암호는 이제 \"$3\"입니다.
+새 암호로 위키백과에 들어와서, 암호를 바꾸세요.",
+"noemail"              => "또이름 \"$1\"에 딸린 누리편지주소정보가 없습니다.",
+"passwordsent" => "\"$1\"의 새 암호를 누리편지로 보냈습니다.
+암호를 받고 다시 들어오세요.",
+
+# Edit pages
+#
+"summary"              => "바꾼내용 간추리기",
+"minoredit"            => "사소한 편집",
+"savearticle"  => "저장",
+"preview"              => "미리보기",
+"showpreview"  => "미리보기",
+"blockedtitle" => "사용자 접근금지",
+"blockedtext"  => "$1 가 당신의 또이름이나 IP를 막았습니다.
+이유는 다음과 같습니다:<br>$2<p> 접근금지에 대해선 관리자와 상의하십시오.",
+"newarticle"   => "(새문서)",
+"newarticletext" => "새문서에 내용을 써 넣으세요.",
+"noarticletext" => "(현재 문서는 비어 있습니다.)",
+"updated"              => "(바뀜)",
+"note"                 => "<strong>주의:</strong> ",
+"previewnote"  => "지금 미리보기로 보고 있는 내용은 아직 저장되지 않았습니다!",
+
+# when does this message show up? I have encountered it yet, I guess.
+# And what does it have to do with conflict? The message sound quite normal.
+# (I don't think it _can_ show up. It's only used if you preview and get
+# an edit conflict, but edit conflict is tripped only if you're saving.)
+"previewconflict" => "This preview reflects the text in the upper
+text editing area as it will appear if you choose to save.",
+
+"editing"              => "$1 고쳐쓰기", 
+"editconflict" => "고치기 충돌: $1",
+"explainconflict" => "문서를 고쳐쓰는 동안, 문서가 바뀌었습니다.
+위쪽이 바뀐 현재 문서이고, 아래쪽이 당신이 고쳐쓴 내용입니다.
+당신이 고쳐쓴 내용을 현재 문서에 다시 집어 넣어야 할 것입니다.
+지금 \"저장\"을 눌러도, 
+<b>오직</b> 위쪽에 있는 내용만 저장됩니다.\n<p>",
+"yourtext"             => "당신이 고쳐쓴 것",
+"storedversion" => "바뀐 현재 문서",
+"editingold"   => "<strong>경고: 지금 옛날 버젼의 문서를 고치고 있습니다.
+만약, 지금 여기서 저장을 하면, 그 때 이후의 모든 버젼을 잃게 됩니다.</strong>\n",
+"yourdiff"             => "차이",
+"copyrightwarning" => "위키백과에 당신이 기여한 것은 모두 GNU 자유 문서 사용허가서(GFDL)
+($1참조)에 따라 배포됩니다.
+당신이 써 넣은 내용이 제한없이 고쳐지고, 재배포되는 것이 싫다면, 저장하지 마십시오.에 반대할 때에는, 여기에 쓰지 마시길 바랍니다.<br>
+또한, 여기 써 넣은 내용을 스스로 썼음을, 혹은 모두에게 공개된 자료에서 빌어왔음을
+같이 약속해야 합니다.
+<strong>저작권의 보호를 받는 내용을 저작권자의 허가없이 보내지 마십시오!</strong>",
+
+
+# History pages
+#
+"revhistory"   => "바뀐역사",
+"nohistory"            => "이 문서는 역사가 없습니다.",
+"revnotfound"  => "버젼 찾지 못함",
+"revnotfoundtext" => "요청한 이 문서의 옛 버젼을 찾지 못했습니다.
+이 문서에 접근할 때의 URL을 확인해 주십시오.\n",
+"loadhist"             => "문서역사를 받고 있습니다.",
+"currentrev"   => "현재 버젼",
+"revisionasof" => "$1 버젼",
+"cur"                  => "현재",
+"next"                 => "다음",
+"last"                 => "이전",
+"orig"                 => "처음",
+"histlegend"   => "상세설명: (현재) = 현재 버젼과의 차이,
+(이전) = 바로 이전 버전과의 차이, 少 = 사소한 편집",
+
+# Diffs
+#
+"difference"   => "(버젼사이 차이)",
+"loadingrev"   => "버젼 차이를 받고 있습니다.",
+"lineno"               => "$1째 줄:",
+"editcurrent"  => "현재 버전의 문서를 고칩니다.",
+
+# Search results
+#
+"searchresults" => "찾아본 결과",
+"searchhelppage" => "위키백과:찾기",
+"searchingwikipedia" => "위키백과 찾기",
+"searchresulttext" => "위키백과 찾기에 대해 자세한 정보는 $1 를 보세요.",
+"searchquery"  => "열쇠말 \"$1\"",
+"badquery"             => "좋지 않은 열쇠말",
+
+# I think we should enable the less-than-3-letter query in Korean.
+# One korean letter corresponds to one syllable. And when I do a search
+# in google or yahoo. The query I type in is mostly 3, 4 of letters
+# and it works. I'll leave this part in English. I'll wait for the
+# software to be developed to be compitable three letter search.
+
+# It's really 3 bytes, not 3 letters. Any Korean letter in UTF-8 encoding
+# is 3 bytes, so in theory it should work. However, searches for Korean
+# text don't work anyway. I'll have to bang it into shape... --Brion
+
+# Then, one and a half, am I right?
+
+"badquerytext" => "<b>Sorry, a search with Korean doesn't work yet.</b>
+We could not process your query.
+This is probably because you have attempted to search for a
+word fewer than three letters long, which is not yet supported.
+It could also be that you have mistyped the expression, for
+example \"fish and and scales\".
+Please try another query.",
+
+"matchtotals"  => "열쇠말 \"$1\"이 제목에 들어있는 문서는 $2개 이고,
+내용에 담고있는 문서는 $3개 입니다.",
+"titlematches" => "문서 제목 일치",
+"notitlematches" => "제목과 맞는 문서가 없습니다.",
+"textmatches"  => "문서 내용 일치",
+"notextmatches"        => "내용에 열쇠말을 담고 있은 문서가 없습니다.",
+"prevn"                        => "이전 $1",
+"nextn"                        => "다음 $1",
+"viewprevnext" => "($1) ($2) 보기 ($3).",
+"showingresults" => "<b>$2</b>번 부터 <b>$1</b>개의 결과 입니다.",
+"nonefound"            => "<strong>Note</strong>: unsuccessful searches are
+often caused by searching for common words like \"have\" and \"from\",
+which are not indexed, or by specifying more than one search term (only pages
+containing all of the search terms will appear in the result).",
+"powersearch" => "찾기",
+"powersearchtext" => "
+Search in namespaces :<br>
+$1<br>
+$2 List redirects &nbsp; Search for $3 $9",
+
+
+# Preferences page
+#
+"preferences"  => "개인 맞춤",
+"prefsnologin" => "나와 있습니다.",
+"prefsnologintext"     => "<a href=\"" .
+  wfLocalUrl( "특수기능:Userlogin" ) . "\">들어와</a> 있을 때에만,
+# Special:Userlogin => 특수기능:들어가기 개인 환경을 맞출 수 있습니다.",
+"prefslogintext" => "당신은 \"$1\", 맞죠?
+당신의 내부 ID 번호는 $2입니다.",
+"prefsreset"   => "개인 맞춤을 보통으로 되돌렸습니다.",
+"qbsettings"   => "빨리가기 맞춤", 
+"changepassword" => "암호 바꾸기",
+"skin"                 => "옷",
+"saveprefs"            => "맞춤 저장",
+"resetprefs"   => "맞춤 보통으로",
+"oldpassword"  => "현재 암호",
+"newpassword"  => "새 암호",
+"retypenew"            => "새 암호 또 한번",
+"textboxsize"  => "문서상자 크기",
+"rows"                 => "줄수",
+"columns"              => "너비",
+"searchresultshead" => "찾기 결과 맞춤",
+"resultsperpage" => "쪽마다 보이는 결과",
+"contextlines" => "결과마다 보이는 줄수",
+"contextchars" => "줄수마다 보이는 글잣수",
+"stubthreshold" => "씨앗보기 문턱값",
+"recentchangescount" => "최근 바뀜에 보이는 항목 수",
+"savedprefs"   => "새 설정을 저장했습니다.",
+"timezonetext" => "현지 시간과 서버 시간(UTC)과 차이를 써 넣으세요.",
+"localtime"    => "현지 시각",
+"timezoneoffset" => "시간차",
+"emailflag"            => "다른 사용자에게서 누리편지 안 받음",
+
+# Recent changes
+#
+"recentchanges" => "최근 바뀜",
+"recentchangestext" => "아래 나열된 문서들이 최근에 바뀌었습니다.
+
+[[위키백과:새내기_환영|새내기, 환영합니다]]!
+새내기들은 다음 문서를 읽어 보세요.: [[위키백과:잦은질문(FAQ)|위키백과 잦은질문(FAQ)]],
+[[위키백과:정책과 지침|위키백과 정책]]
+(특별히 [[위키백과:제목달기 규칙|제목달기 규칙]],
+[[위키백과:중립적인 시각|중립적인 시각]]),
+그리고 [[위키백과:범하기_쉬운_실수|범하기 쉬운 실수]].
+
+위키백과가 성공하려면, 여러분이 저작권에 저촉되는 내용을 이곳에 써 넣지 않는 것이
+매우 중요합니다.' [[위키백과:저작권|저작권]].
+법적 문제가 프로젝트를 망칠 수 있습니다. 저작권에 유의해 주세요.
+또, [http://meta.wikipedia.org/wiki/Special:Recentchanges 최근 메타 토론]도 
+읽어 보세요.",
+"rcloaderr"            => "최근 바뀜을 받고 있습니다.",
+"rcnote"               => "다음이 최근 <strong>$2</strong>일간 바뀐  <strong>$1</strong>개의 문서입니다.",
+"rclinks"              => "최근 $2일 동안에 바뀐 $1개의 문서를 봅니다.",
+
+# <font color="red">where does rchide appear?
+# It doesn't, currently. I think it was proposed at one point.</font>
+"rchide"               => "in $4 form; $1 minor edits; $2 secondary namespaces; $3 multiple edits.",
+
+"diff"                 => "차이",
+"hist"                 => "역사",
+"hide"                 => "숨김",
+"show"                 => "보임",
+"tableform"            => "표로",
+"listform"             => "목록으로",
+"nchanges"             => "$1개 바뀜",
+"minoreditletter" => "少",
+"newpageletter" => "新",
+
+# Upload
+#
+"upload"               => "올리기",
+"uploadbtn"            => "파일 올리기",
+"uploadlink"   => "그림 올리기",
+"reupload"             => "다시 올리기",
+"reuploaddesc" => "올리기 틀로 돌아감",
+"uploadnologin" => "나와있습니다.",
+"uploadnologintext"    => "위키백과에 <a href=\"" .
+  wfLocalUrl( "특수기능:Userlogin" ) . "\">들어와</a> 있을 때에만
+# special:userlogin 특수기능:들어가기
+파일을 올릴 수 있습니다.",
+"uploadfile"   => "파일 올리기",
+"uploaderror"  => "올리기 오류",
+"uploadtext"   => "<strong>잠깐!</strong> 여기 그림을 올리기 전에,
+위키백과의 <a href=\"" .
+wfLocalUrlE( "위키백과:Image_use_policy" ) . "\">그림 사용 정책</a>읽고 따라 주세요.
+<p>
+이미 올라온 그림을 찾아 보려면, <a href=\"" . wfLocalUrlE( "특수기능:Imagelist" ) .
+"\">올라온 그림 목록</a>으로 가세요.
+# Special:Image list  특수기능:그림_목록
+그림을 올리거나 지우면 <a href=\"" .
+wfLocalUrlE( "위키백과:올리기_기록" ) . "\">올리기 기록</a>에 그 사실이 남습니다.
+# 위키백과:올리기_기록 위키백과:올리기_기록
+
+<p>
+밑에 있는 틀을 이용해서 문서에 담을 파일을 올리세요.
+대부분의 누리그물 훑개(browser)는, 아래 \"찾아보기...\" (영문 \"Browse...\") 단추로
+ 자기 컴퓨터의 파일을 찾게 해 줍니다.
+원하는 파일을 고르면, 단추 옆의 공간에 파일이름이 채워질 것입니다.
+또한, 저작권에 저촉되지 않는 파일을 올린다는 사실도
+확인해야 합니다.
+마지막으로, \"올리기\" 단추를 누르면 올라갑니다. 누리그물 연결이 느리면, 
+시간이 걸릴 수 있습니다.
+<p>
+위키백과는 사진은 JPEG형식을, 보통 그림, 아이콘은 PNG형식을, 소리는
+OGG형식을 더 좋아합니다.
+이름은 햇갈리지 않고, 내용을 잘 나타내는 것으로 지어주세요. 그림을 문서에
+담을 때에는 <b>[[image:file.jpg]]</b> 또는 <b>[[image:file.png|alt text]]</b>
+처럼, 소리를 담을 때에는<b>[[media:file.ogg]]</b>처럼 써서 고리를 걸어주면
+됩니다.
+<p>
+다른 사람들이 올린 파일을 고치거나 지울 수 있다는 것을 알아두십시오.
+또한, 시스템을 남용할 때에는, 파일 올리기가 금지될 수도 있습니다.
+",
+"uploadlog"            => "올리기 기록",
+"uploadlogpage" => "올리기_기록",
+"uploadlogpagetext" => "최근 올라온 그림 목록입니다.
+모든 시간은 서버 기준(UTC)입니다.
+<ul>
+</ul>
+",
+"filename"             => "파일이름",
+"filedesc"             => "짧은설명",
+"affirmation"  => "파일의 저작권자가
+$1의 조건으로 사용을 허가했음을 확인합니다.",
+"copyrightpage" => "위키백과:저작권",
+"copyrightpagename" => "위키백과 저작권",
+"uploadedfiles"        => "파일 올리기",
+"noaffirmation" => "올리는 파일이 어떤 저작권에도 저촉되지 않음을
+확인해야 합니다.",
+"ignorewarning"        => "경고 무시하고, 파일 저장",
+
+# three alphabets and how many for Korean character?
+"minlength"            => "그림이름은 두글자가 넘어야 합니다.",
+
+"badfilename"  => "그림이름이 \"$1\"로 바뀌었습니다.",
+"badfiletype"  => "\".$1\" 형식은 권장하지 않습니다.",
+"largefile"            => "그림크기는 100k이하를 권장합니다.",
+"successfulupload" => "올리기 성공",
+"fileuploaded" => "\"$1\"가 올라갔습니다.
+다음 고리($2)를 따라 가서, 설명문서에 파일에 대한 정보를(어디서 구했는지, 
+누가 언제 만들었는지, 또 그 이외 필요한 사항들을) 채우세요.",
+"uploadwarning" => "올리기 경고",
+"savefile"             => "파일 저장",
+"uploadedimage" => "\"$1\"를 올렸습니다.",
+
+# Image list
+#
+"imagelist"            => "그림 목록",
+"imagelisttext"        => "$2순으로 정리된 $1개의 그림입니다.",
+"getimagelist" => "그림 목록 가져오기",
+"ilshowmatch"  => "이름이 맞는 그림 모두 보이기",
+"ilsubmit"             => "찾기",
+"showlast"             => "$2순으로 이전 $1개의 그림 보이기",
+"all"                  => "모두",
+"byname"               => "이름",
+"bydate"               => "날짜",
+"bysize"               => "크기",
+"imgdelete"            => "지움",
+
+"imgdesc"              => "설명",
+"imglegend"            => "상세설명: (설명) = 그림 설명을 보입니다/고칩니다.",
+"imghistory"   => "그림역사",
+"revertimg"            => "돌림",
+"deleteimg"            => "지우기",
+"imghistlegend" => "상세설명: (현재) = 현재의 그림입니다, (지움) = 옛 버젼을 지웁니다, (돌림) = 옛 버젼으로 되돌려 놓습니다.
+<br><i>특정 날짜에 올라온 그림을 보려면, 날짜를 찍어 주세요</i>.",
+"imagelinks"   => "그림고리",
+"linkstoimage" => "다음 문서들이 이 그림을 담고 있습니다:",
+"nolinkstoimage" => "이 그림을 담고 있는 문서는 없습니다.",
+
+# Statistics
+#
+"statistics"   => "통계",
+"sitestats"            => "누리터 통계",
+"userstats"            => "사용자 통계",
+"sitestatstext" => "이곳 정보창고(DB)에는 총 <b>$1</b>개의 문서가 있습니다.
+이 숫자는 \"토론\" 문서, 위키백과 자체에 관한 문서, 자라기를 기다리는 \"씨앗\" 문서, 
+넘겨주기 문서, 그리고 아직 사전항목으로 부족한 문서들을 모두 포함한 것입니다.
+이들을 제외하면, <b>$2</b>개의 문서가 있습니다.<p>
+또, 무른모 업그레이드가 있었던 2002년 7월 20일 이래, 여러분은 총 <b>$3</b>번 문서를 
+읽었고, <b>$4</b>번 고쳤습니다. 
+따라서, 평균적으로 문서 하나가 <b>$5</b>번 바뀌었고, 한번 바뀔 때마다 <b>$6</b>번 읽힌
+셈이 됩니다.",
+"userstatstext" => "<b>$1</b>명의 사용자가 등록되어 있습니다.
+이 중 관리자는 <b>$2</b>명입니다.($3 참조)",
+
+# Maintenance Page
+# I leave it in english.
+
+"maintenance"          => "Maintenance page",
+"maintnancepagetext"   => "This page includes several handy tools for everyday maintenance. Some of these functions tend to stress the database, so please do not hit reload after every item you fixed ;-)",
+"maintenancebacklink"  => "Back to Maintenance Page",
+"disambiguations"      => "Disambiguation pages",
+"disambiguationspage"  => "위키백과:Links_to_disambiguating_pages",
+"disambiguationstext"  => "The following articles link to a <i>disambiguation page</i>. They should link to the appropriate topic instead.<br>A page is treated as dismbiguation if it is linked from $1.<br>Links from other namespaces are <i>not</i> listed here.",
+"doubleredirects"      => "Double Redirects",
+"doubleredirectstext"  => "<b>Attention:</b> This list may contain false positives. That usually means there is additional text with links below the first #REDIRECT.<br>\nEach row contains links to the first and second redirect, as well as the first line of the second redirect text, usually giving the \"real\" taget article, which the first redirect should point to.",
+"selflinks"            => "Pages with Self Links",
+"selflinkstext"                => "The following pages contain a link to themselves, which they should not.",
+"missinglanguagelinks"  => "Missing Language Links",
+"missinglanguagelinksbutton"    => "Find missing language links for",
+"missinglanguagelinkstext"      => "These articles do <i>not</i> link to their counterpart in $1. Redirects and subpages are <i>not</i> shown.",
+
+
+# Miscellaneous special pages
+#
+"orphans"              => "외톨이 문서",
+"lonelypages"  => "외톨이 문서",
+"unusedimages" => "안 쓰는 그림",
+"popularpages" => "인기있는 문서",
+"nviews"               => "$1 번 읽음",
+"wantedpages"  => "필요한 문서",
+"nlinks"               => "$1개의 고리",
+"allpages"             => "모든 문서",
+"randompage"   => "아무거나",
+"shortpages"   => "짧은 문서",
+"longpages"            => "긴 문서",
+"listusers"            => "사용자들",
+"specialpages" => "특수기능문서",
+"spheading"            => "특수기능문서",
+"sysopspheading" => "Special pages for sysop use",
+"developerspheading" => "Special pages for developer use",
+"protectpage"  => "보호된 문서",
+"recentchangeslinked" => "여기서 가리키는 문서",
+"rclsub"               => "(\"$1\"의 고리들이 가리키는)",
+"debug"                        => "Debug",
+"newpages"             => "새 문서",
+"movethispage" => "문서 옮기기",
+"unusedimagestext" => "<p>다음 그림중 어떤 것은, 다른 언어의 위키백과등 다른 
+누리터에서 URL바로걸기로 사용하고 있을 지도 모릅니다.",
+"booksources"  => "외부 책방",
+"booksourcetext" => "새책이나 헌책을 파는 몇몇 누리터입니다. 찾고 있는 책의
+정보를 담고 있을 수 있습니다.
+위키백과는 다음 중 어떤 기업과도 관련이 없으며,
+아래 목록이 상업적 광고로 오해되지 않기를 바랍니다.",
+
+# Email this user
+#
+"mailnologin"  => "누리편지주소 없음",
+"mailnologintext" => "위키백과에 <a href=\"" .
+  wfLocalUrl( "특수기능:Userlogin" ) . "\">들어와</a> 있을 때, 또,
+<a href=\"" .
+  wfLocalUrl( "특수기능:Preferences" ) . "\">개인 맞춤</a>에 
+자기의 누리편지주소를 기억시켰을 때에만,
+다른 사용자에게 편지를 보낼 수 있습니다.",
+"emailuser"            => "사용자에게 편지쓰기",
+"emailpage"            => "누리편지 쓰기",
+"emailpagetext"        => "이 사용자가 개인맞춤에 옳바른 주소를 써 넣었다면,
+아래 틀을 이용하여 편지를 보낼 수 있습니다.
+이 사용자가 바로 답장할 수 있도록, 당신의 개인맞춤에 넣었던 주소가,
+\"보낸이\" 주소에 들어갑니다.",
+"noemailtitle" => "누리편지 없음",
+"noemailtext"  => "이 사용자는 누리편지를 받지않음에 맞추어 놓았거나,
+옳바른 주소를 써 넣지 않았습니다.",
+"emailfrom"            => "보낸이",
+"emailto"              => "받는이",
+"emailsubject" => "제목",
+"emailmessage" => "편지내용",
+"emailsend"            => "보내기",
+"emailsent"            => "편지 보냄",
+"emailsenttext" => "누리편지를 보냈습니다.",
+
+# Watchlist
+#
+"watchlist"            => "눈여겨보기 목록",
+"watchlistsub" => "(\"$1\"의)",
+"nowatchlist"  => "눈여겨보는 문서가 아직 없습니다.",
+"watchnologin" => "나와있습니다.",
+"watchnologintext"     => "<a href=\"" .
+  wfLocalUrl( "특수기능:Userlogin" ) . "\">들어와</a>
+있을 때에만 눈여겨보기 목록을 볼 수 있습니다.",
+"addedwatch"   => "눈여겨 봅니다.",
+"addedwatchtext" => "앞으로 \"$1\"문서와 딸린 토론를
+<a href=\"" .
+  wfLocalUrl( "특수기능:Watchlist" ) . "\">눈여겨보기 목록</a>에서
+관찰할 수 있으며,<a href=\"" .
+  wfLocalUrl( "특수기능:Recentchanges" ) . "\">최근 바뀜</a>에는 금방 눈에 
+띄도록 <b>두터운 글씨체</b>로 나타납니다.</p>
+
+<p>더 이상 눈여겨 보지 않아도 될 때에는, 옆의 \"눈여겨 보지 않음\"을 누르면 됩니다.",
+"removedwatch" => "눈여겨 보지 않음",
+"removedwatchtext" => "\"$1\"를 더 이상 눈여겨 보지 않습니다.",
+"watchthispage"        => "눈여겨보기",
+"unwatchthispage" => "눈여겨 보지 않음",
+"notanarticle" => "문서가 아님",
+
+# Delete/protect/revert
+# I'll leave it in eng.
+"deletepage"   => "Delete page",
+"confirm"              => "Confirm",
+"confirmdelete" => "Confirm delete",
+"deletesub"            => "(Deleting \"$1\")",
+"confirmdeletetext" => "You are about to permanently delete a page
+or image along with all of its history from the database.
+Please confirm that you intend to do this, that you understand the
+consequences, and that you are doing this in accordance with
+[[위키백과:Policy]].",
+"confirmcheck" => "Yes, I really want to delete this.",
+"actioncomplete" => "Action complete",
+"deletedtext"  => "\"$1\" has been deleted.
+See $2 for a record of recent deletions.",
+"deletedarticle" => "deleted \"$1\"",
+"dellogpage"   => "Deletion_log",
+"dellogpagetext" => "Below is a list of the most recent deletions.
+All times shown are server time (UTC).
+<ul>
+</ul>
+",
+"deletionlog"  => "deletion log",
+"reverted"             => "Reverted to earlier revision",
+"deletecomment"        => "Reason for deletion",
+"imagereverted" => "Revert to earlier version was successful.",
+"undelete" => "Restore deleted page",
+"undeletepage" => "View and restore deleted pages",
+"undeletepagetext" => "The following pages have been deleted but are still in the archive and
+can be restored. The archive may be periodically cleaned out.",
+"undeletearticle" => "Restore deleted article",
+"undeleterevisions" => "$1 revisions archived",
+"undeletehistory" => "If you restore the page, all revisions will be restored to the history.
+If a new page with the same name has been created since the deletion, the restored
+revisions will appear in the prior history, and the current revision of the live page
+will not be automatically replaced.",
+"undeleterevision" => "Deleted revision as of $1",
+"undeletebtn" => "Restore!",
+"undeletedarticle" => "restored \"$1\"",
+"undeletedtext"   => "The article [[$1]] has been successfully restored.
+See [[위키백과:Deletion_log]] for a record of recent deletions and restorations.",
+
+# Contributions
+#
+"contributions"        => "사용자 기여",
+"contribsub"   => "$1의",
+"nocontribs"   => "이 사용는 어디에도 기여하지 않았습니다.",
+"ucnote"               => "<b>$2</b>일 동안 이 사용자가 바꾼 <b>$1</b>개의 문서입니다.",
+"uclinks"              => "최근 $1개 보기; 최근 $2일 보기",
+
+# What links here
+#
+"whatlinkshere"        => "여길 가리키는 문서",
+"notargettitle" => "문서 없음",
+"notargettext" => "기능을 수행할 목표 문서나 목표 사용자를
+지정하지 않았습니다.",
+"linklistsub"  => "(고리 목록)",
+"linkshere"            => "다음 문서들이 여기를 가리키고 있습니다.",
+"nolinkshere"  => "어떤 문서도 이곳을 가리키지 않습니다.",
+"isredirect"   => "넘겨주기 문서",
+
+# Block/unblock IP
+# leave it in eng
+"blockip"              => "Block IP address",
+"blockiptext"  => "Use the form below to block write access
+from a specific IP address.
+This should be done only only to prevent valndalism, and in
+accordance with [[위키백과:Policy|Wikipedia policy]].
+Fill in a specific reason below (for example, citing particular
+pages that were vandalized).",
+"ipaddress"            => "IP Address",
+"ipbreason"            => "Reason",
+"ipbsubmit"            => "Block this address",
+"badipaddress" => "The IP address is badly formed.",
+"noblockreason" => "You must supply a reason for the block.",
+"blockipsuccesssub" => "Block succeeded",
+"blockipsuccesstext" => "The IP address \"$1\" has been blocked.
+<br>See [[특수기능:Ipblocklist|IP block list]] to review blocks.",
+"unblockip"            => "Unblock IP address",
+"unblockiptext"        => "Use the form below to restore write access
+to a previously blocked IP address.",
+"ipusubmit"            => "Unblock this address",
+"ipusuccess"   => "IP address \"$1\" unblocked",
+"ipblocklist"  => "List of blocked IP addresses",
+"blocklistline"        => "$1, $2 blocked $3",
+"blocklink"            => "block",
+"unblocklink"  => "unblock",
+"contribslink" => "contribs",
+
+# Developer tools
+#
+"lockdb"               => "Lock database",
+"unlockdb"             => "Unlock database",
+"lockdbtext"   => "Locking the database will suspend the ability of all
+users to edit pages, change their preferences, edit their watchlists, and
+other things requiring changes in the database.
+Please confirm that this is what you intend to do, and that you will
+unlock the database when your maintenance is done.",
+"unlockdbtext" => "Unlocking the database will restore the ability of all
+users to edit pages, change their preferences, edit their watchlists, and
+other things requiring changes in the database.
+Please confirm that this is what you intend to do.",
+"lockconfirm"  => "Yes, I really want to lock the database.",
+"unlockconfirm"        => "Yes, I really want to unlock the database.",
+"lockbtn"              => "Lock database",
+"unlockbtn"            => "Unlock database",
+"locknoconfirm" => "You did not check the confirmation box.",
+"lockdbsuccesssub" => "Database lock succeeded",
+"unlockdbsuccesssub" => "Database lock removed",
+"lockdbsuccesstext" => "The Wikipedia database has been locked.
+<br>Remember to remove the lock after your maintenance is complete.",
+"unlockdbsuccesstext" => "The Wikipedia database has been unlocked.",
+
+# SQL query
+#
+"asksql"               => "SQL query",
+"asksqltext"   => "Use the form below to make a direct query of the
+Wikipedia database.
+Use single quotes ('like this') to delimit string literals.
+This can often add considerable load to the server, so please use
+this function sparingly.",
+"sqlquery"             => "Enter query",
+"querybtn"             => "Submit query",
+"selectonly"   => "Queries other than \"SELECT\" are restricted to
+Wikipedia developers.",
+"querysuccessful" => "Query successful",
+
+# Move page
+#
+"movepage"             => "문서 옮기기",
+"movepagetext" => "아래 틀을 채워 문서이름을 바꾸세요. 
+문서역사도 함께 새문서로 갑니다.
+기존의 문서는 새이름의 문서로 넘겨주는 역할만 하는 넘겨주기 문서가 됩니다.
+기존 문서로의 고리도 바뀌지 않습니다. 딸린토론이 있어도, 옮기지
+않습니다.
+<b>경고!</b>
+인기있는 문서를 옮기면 예상치 못한 엄청난 결과를 가져올 수 있습니다.
+옮기는 것이 옳다는 확신이 들 때에만 진행하세요.",
+"movearticle"  => "문서 옮기기",
+"movenologin"  => "나와 있습니다.",
+"movenologintext" => "위키백과에 <a href=\"" .
+  wfLocalUrl( "특수기능:Userlogin" ) . "\">들어와</a> 있을 때에만
+문서를 옮길 수 있습니다.",
+"newtitle"             => "새 이름",
+"movepagebtn"  => "옮기기",
+"pagemovedsub" => "문서 옮김",
+"pagemovedtext" => "\"[[$1]]\"를 \"[[$2]]\"로 옮겼습니다.",
+"articleexists" => "그 이름의 문서가 이미 존재하거나, 새 이름이 옳바르지
+않습니다. 이름을 다시 지으세요.",
+"movedto"              => "새 이름",
+"movetalk"             => "딸린 \"토론\"도 함께 옮깁니다.",
+"talkpagemoved" => "딸린토론도 옮겼습니다.",
+"talkpagenotmoved" => "딸린토론은 옮기지 <strong>않았습니다</strong>.",
+
+);
+
+class LanguageKo extends LanguageUtf8 {
+
+       function getDefaultUserOptions () {
+               global $wgDefaultUserOptionsKo ;
+               return $wgDefaultUserOptionsKo ;
+               }
+
+       function getBookstoreList () {
+               global $wgBookstoreListKo ;
+               return $wgBookstoreListKo ;
+       }
+
+       function getNamespaces() {
+               global $wgNamespaceNamesKo;
+               return $wgNamespaceNamesKo;
+       }
+
+       function getNsText( $index ) {
+               global $wgNamespaceNamesKo;
+               return $wgNamespaceNamesKo[$index];
+       }
+
+       function getNsIndex( $text ) {
+               global $wgNamespaceNamesKo;
+
+               foreach ( $wgNamespaceNamesKo as $i => $n ) {
+                       if ( 0 == strcasecmp( $n, $text ) ) { return $i; }
+               }
+               return false;
+       }
+
+       function getQuickbarSettings() {
+               global $wgQuickbarSettingsKo;
+               return $wgQuickbarSettingsKo;
+       }
+
+       function getSkinNames() {
+               global $wgSkinNamesKo;
+               return $wgSkinNamesKo;
+       }
+
+       function getUserToggles() {
+               global $wgUserTogglesKo;
+               return $wgUserTogglesKo;
+       }
+
+       function getLanguageNames() {
+               global $wgLanguageNamesKo;
+               return $wgLanguageNamesKo;
+       }
+
+       function getLanguageName( $code ) {
+               global $wgLanguageNamesKo;
+               if ( ! array_key_exists( $code, $wgLanguageNamesKo ) ) {
+                       return "";
+               }
+               return $wgLanguageNamesKo[$code];
+       }
+
+       function getMonthName( $key )
+       {
+               global $wgMonthNamesKo;
+               return $wgMonthNamesKo[$key-1];
+       }
+
+       function getMonthAbbreviation( $key )
+       {
+               global $wgMonthAbbreviationsKo;
+               return $wgMonthAbbreviationsKo[$key-1];
+       }
+
+       function getWeekdayName( $key )
+       {
+               global $wgWeekdayNamesKo;
+               return $wgWeekdayNamesKo[$key-1];
+       }
+
+       # Inherit default userAdjust()
+       function date( $ts, $adj = false )
+       {
+               global $wgWeekdayAbbreviationsKo;
+               if ( $adj ) { $ts = $this->userAdjust( $ts ); }
+
+        # This is horribly inefficient; I need to rework this
+        $x = getdate(mktime(( (int)substr( $ts, 8, 2) ) + $diff,
+                 (int)substr( $ts, 10, 2 ), (int)substr( $ts, 12, 2 ),
+                 (int)substr( $ts, 4, 2 ), (int)substr( $ts, 6, 2 ),
+          (int)substr( $ts, 0, 4 )));
+        
+        $d = substr( $ts, 0, 4 ) . "년 " .
+                 $this->getMonthAbbreviation( substr( $ts, 4, 2 ) ) . "월 " .
+                 (0 + substr( $ts, 6, 2 )) . "일 " .
+                 "(" . $wgWeekdayAbbreviationsKo[$x["wday"]] . ")";
+               return $d;
+       }
+
+       function time( $ts, $adj = false )
+       {
+               if ( $adj ) { $ts = $this->userAdjust( $ts ); }
+
+               $t = substr( $ts, 8, 2 ) . ":" . substr( $ts, 10, 2 );
+               return $t;
+       }
+
+       function timeanddate( $ts, $adj = false )
+       {
+               return $this->date( $ts, $adj ) . " " . $this->time( $ts, $adj );
+       }
+
+       function rfc1123( $ts )
+       {
+               return date( "D, d M Y H:i:s T", $ts );
+       }
+
+       function getValidSpecialPages()
+       {
+               global $wgValidSpecialPagesKo;
+               return $wgValidSpecialPagesKo;
+       }
+
+       function getSysopSpecialPages()
+       {
+               global $wgSysopSpecialPagesKo;
+               return $wgSysopSpecialPagesKo;
+       }
+
+       function getDeveloperSpecialPages()
+       {
+               global $wgDeveloperSpecialPagesKo;
+               return $wgDeveloperSpecialPagesKo;
+       }
+
+       function getMessage( $key )
+       {
+               global $wgAllMessagesKo, $wgAllMessagesEn;
+               $m = $wgAllMessagesKo[$key];
+
+               if ( "" == $m ) { return $wgAllMessagesEn[$key]; }
+               else return $m;
+       }
+       
+       # Inherit default iconv()
+       
+       # Inherit ucfirst() and stripForSearch() from LanguageUtf8
+       
+       # Inherit default checkTitleEncoding()
+
+}
+
+?>
diff --git a/languages/LanguageNl.php b/languages/LanguageNl.php
new file mode 100644 (file)
index 0000000..77cc9ac
--- /dev/null
@@ -0,0 +1,1008 @@
+<?
+
+# The names of the namespaces can be set here, but the numbers
+# are magical, so don't change or move them!  The Namespace class
+# encapsulates some of the magic-ness.
+
+/* private */ $wgNamespaceNamesNl = array(
+ -1 => "Speciaal",
+ 0 => "",
+ 1 => "Overleg",
+ 2 => "Gebruiker",
+ 3 => "Overleg_gebruiker",
+ 4 => "Wikipedia",
+ 5 => "Overleg_Wikipedia",
+ 6 => "Afbeelding",
+ 7 => "Overleg_afbeelding"
+);
+
+/* private */ $wgDefaultUserOptionsNl = array(
+ "quickbar" => 1, "underline" => 1, "hover" => 1,
+ "cols" => 80, "rows" => 25, "searchlimit" => 20,
+ "contextlines" => 5, "contextchars" => 50,
+ "skin" => 0, "math" => 1, "rcdays" => 3, "rclimit" => 50,
+ "highlightbroken" => 0
+);
+
+/* private */ $wgQuickbarSettingsNl = array(
+ "Uitgeschakeld", "Links vast", "Rechts vast", "Links zwevend"
+);
+
+/* private */ $wgSkinNamesNl = array(
+ "Standaard", "Nostalgie", "Keuls blauw"
+);
+
+/* private */ $wgMathNamesNl = array(
+           "Altijd als PNG weergeven",
+           "HTML voor eenvoudige formules, anders PNG",
+           "HTML indien mogelijk, anders PNG",
+           "Laat de TeX broncode staan (voor tekstbrowsers)",
+           "Aanbevolen methode voor recente browsers"
+);
+
+/* private */ $wgUserTogglesNl = array(
+ "hover"  => "Wikilinks in zwevend tekstvak tonen",
+ "underline" => "Links onderstrepen",
+ "highlightbroken" => "Links naar lege pagina's laten oplichten",
+ "justify" => "Paragrafen uitvullen",
+ "hideminor" => "Kleine wijzigingen verbergen in recente wijzigingen",
+ "usenewrc" => "Gebruik de uitgebreide Recente Wijzigingen-pagina (niet op alle browsers mogelijk)",
+ "numberheadings" => "Koppen automatisch nummeren",
+ "rememberpassword" => "Wachtwoord onthouden",
+ "editwidth" => "Bewerkingsveld over volle breedte",
+ "editondblclick" => "Dubbelklikken levert bewerkingspagina (vereist JavaScript)",
+ "watchdefault" => "Artikelen die u wijzigt automatisch volgen",
+ "minordefault" => "Maak 'kleine' veranderingen mijn standaard",
+ "previewontop" => "Toon controlepagina boven bewerkingsveld"
+);
+
+/* private */ $wgLanguageNamesNl = array(
+ "nl" => "Nederlands",
+ "en" => "English",
+ "de" => "Deutsch",
+ "pl" => "Polski",
+ "eo" => "Esperanto",
+ "fr" => "Français",
+ "sv" => "Svenska",
+ "es" => "Español",
+ "it" => "Italiano",
+ "pt" => "Português",
+ "no" => "Norsk",
+ "da" => "Dansk",
+ "fy" => "Frysk",
+ "af" => "Afrikaans",
+ "ab" => "Abchazisch",
+ "aa" => "Afar",
+ "am" => "Amhaars",
+ "ar" => "Arabisch",
+ "hy" => "Armeens",
+ "as" => "Assamitisch",
+ "ay" => "Aymara",
+ "az" => "Azerbeidzjaans",
+ "ba" => "Basjkir",
+ "bn" => "Bengaals",
+ "dz" => "Bhutaans",
+ "bh" => "Bihari",
+ "my" => "Birmaans",
+ "bi" => "Bislama",
+ "bs" => "Bosnisch",
+ "km" => "Cambodjaans",
+ "ca" => "Català",
+ "cs" => "Cesky",
+ "co" => "Corsicaans",
+ "et" => "Eesti",
+ "eu" => "Euskara",
+ "fo" => "Faeroers",
+ "fa" => "Farsi",
+ "fj" => "Fijisch",
+ "gl" => "Galicisch",
+ "ka" => "Georgisch",
+ "el" => "Grieks",
+ "kl" => "Groenlands",
+ "gn" => "Guarani",
+ "gu" => "Gujarati",
+ "zh" => "Hanyu",
+ "ha" => "Hausa",
+ "hr" => "Hrvatsky",
+ "hi" => "Hindi",
+ "he" => "Ivrit",
+ "is" => "IJslands",
+ "id" => "Bahasa Indonesia",
+ "ia" => "Interlingua",
+ "iu" => "Inuktitut",
+ "ik" => "Inupiak",
+ "ga" => "Irish Gaelic",
+ "jv" => "Javaans",
+ "yi" => "Jiddisch",
+ "yo" => "Joruba",
+ "kn" => "Kannada",
+ "ks" => "Kashmiri",
+ "kk" => "Kazachstaans",
+ "rw" => "Kinyarwanda",
+ "ky" => "Kirgizisch",
+ "rn" => "Kirundi",
+ "ko" => "Koreaans",
+ "lo" => "Laotiaans",
+ "la" => "Latina",
+ "lv" => "Lets",
+ "ln" => "Lingala",
+ "lt" => "Litouws",
+ "mk" => "Macedonisch",
+ "hu" => "Magyar",
+ "mg" => "Malagasi",
+ "ms" => "Bahasa Melayu",
+ "ml" => "Malayalam",
+ "mi" => "Maori",
+ "mr" => "Marathi",
+ "mo" => "Moldavisch",
+ "mn" => "Mongools",
+ "na" => "Nauruaans",
+ "ne" => "Nepalees",
+ "ja" => "Nihongo",
+ "oc" => "Occitaans",
+ "ug" => "Oeigoers",
+ "uk" => "Oekraïens",
+ "uz" => "Oezbeeks",
+ "or" => "Oriya",
+ "om" => "Oromo",
+ "ps" => "Pashtu",
+ "pa" => "Punjabi",
+ "qu" => "Quechua",
+ "rm" => "Reto-Romaans",
+ "ro" => "Roemeens",
+ "ru" => "Russkiy",
+ "sm" => "Samoaans",
+ "sg" => "Sangro",
+ "sa" => "Sanskriet",
+ "sq" => "Shqiptare",
+ "sr" => "Srpski",
+ "sh" => "Srpskohrvatska",
+ "st" => "Sesotho",
+ "tn" => "Setswana",
+ "sn" => "Shona",
+ "sd" => "Sindhi",
+ "si" => "Singalees",
+ "ss" => "Siswati",
+ "sl" => "Slovensko",
+ "sk" => "Slowaaks",
+ "su" => "Soedanees",
+ "so" => "Somali",
+ "fi" => "Suomi",
+ "sw" => "Swahili",
+ "tl" => "Tagalog",
+ "tg" => "Tadzjieks",
+ "ta" => "Tamil",
+ "tt" => "Tataars",
+ "te" => "Telugu",
+ "th" => "Thais",
+ "bo" => "Tibetaans",
+ "ti" => "Tigrinya",
+ "to" => "Tongaans",
+ "ts" => "Tsonga",
+ "tr" => "Turks",
+ "tk" => "Turkmeens",
+ "tw" => "Twi",
+ "ur" => "Urdu",
+ "vi" => "Vietnamees",
+ "vo" => "Volapuk",
+ "cy" => "Welsh",
+ "be" => "Witrussisch",
+ "wo" => "Wolof",
+ "xh" => "isiXhosa",
+ "za" => "Zhuang",
+ "zu" => "isiZulu",
+ "simple" => "Simplified English",
+ "dk" => "Gebruik voor Deens da"
+);
+
+/* private */ $wgWeekdayNamesNl = array(
+ "zondag", "maandag", "dinsdag", "woensdag", "donderdag",
+ "vrijdag", "zaterdag"
+);
+
+/* private */ $wgMonthNamesNl = array(
+ "januari", "februari", "maart", "april", "mei", "juni",
+ "juli", "augustus", "september", "oktober", "november",
+ "december"
+);
+
+/* private */ $wgMonthAbbreviationsNl = array(
+ "jan", "feb", "mrt", "apr", "mei", "jun", "jul", "aug",
+ "sep", "oct", "nov", "dec"
+);
+
+# All special pages have to be listed here: a description of ""
+# will make them not show up on the "Special Pages" page, which
+# is the right thing for some of them (such as the "targeted" ones).
+#
+/* private */ $wgValidSpecialPagesNl = array(
+ "Userlogin"  => "",
+ "Userlogout" => "",
+ "Preferences" => "Mijn gebruikersvoorkeuren instellen",
+ "Watchlist"  => "Mijn volglijst tonen",
+ "Recentchanges" => "Recent bijgewerkte pagina's tonen",
+ "Upload"  => "Afbeeldingen uploaden",
+ "Imagelist"  => "Lijst ge-uploade afbeeldingen tonen",
+ "Listusers"  => "Geregistreerde gebruikers tonen",
+ "Statistics" => "Statistieken tonen",
+ "Randompage" => "Ga naar een willekeurig artikel",
+
+ "Lonelypages" => "Niet-gelinkte artikels tonen",
+ "Unusedimages" => "Niet-gelinkte afbeeldingen tonen",
+ "Popularpages" => "Populaire artikels tonen",
+ "Wantedpages" => "Meest gewenste artikels tonen",
+ "Shortpages" => "Korte artikels tonen",
+ "Longpages"  => "Lange artikels tonen",
+ "Newpages"  => "Nieuwe artikels tonen",
+ "Intl" => "Taallinks",
+ "Allpages"  => "Alle paginatitels tonen",
+
+ "Ipblocklist" => "Geblokkeerde IP-adressen tonen",
+ "Maintenance" => "Onderhoudspagina",
+ "Specialpages"  => "",
+ "Contributions" => "",
+ "Emailuser"  => "",
+ "Whatlinkshere" => "",
+ "Recentchangeslinked" => "",
+ "Movepage"  => "",
+ "Booksources" => "Boekhandels"
+);
+
+/* private */ $wgSysopSpecialPagesNl = array(
+ "Blockip"  => "Blokkeer een IP-adres",
+ "Asksql"  => "Raadpleeg de database",
+ "Undelete" => "Verwijderde pagina's herstellen"
+);
+
+/* private */ $wgDeveloperSpecialPagesNl = array(
+ "Lockdb"  => "Maak de database alleen-lezen",
+ "Unlockdb"  => "Maak de database overschrijfbaar",
+ "Debug"   => "Foutverwijderingsinformatie tonen"
+);
+
+/* private */ $wgAllMessagesNl = array(
+
+# Bits of text used by many pages:
+# Diverse stukjes tekst
+"linktrail" => "/^([a-z]+)(.*)\$/sD",
+"mainpage"  => "Hoofdpagina",
+"about"   => "Info",
+"aboutwikipedia" => "Over Wikipedia",
+"aboutpage"  => "Wikipedia:info",
+"help"   => "Help",
+"helppage"  => "Wikipedia:Help",
+"wikititlesuffix" => "Wikipedia NL",
+"bugreports" => "Foutenrapportage",
+"bugreportspage" => "Wikipedia:Foutenrapportage",
+"faq"   => "FAQ",
+"faqpage"  => "Wikipedia:Veelgestelde vragen",
+"edithelp"  => "Hulp bij bewerken",
+"edithelppage" => "Wikipedia:Instructies",
+"cancel"  => "Annuleren",
+"qbfind"  => "Zoeken",
+"qbbrowse"  => "Bladeren",
+"qbedit"  => "Bewerken",
+"qbpageoptions" => "Pagina-opties",
+"qbpageinfo" => "Pagina-informatie",
+"qbmyoptions" => "Mijn opties",
+"mypage"  => "Mijn gebruikerspagina",
+"mytalk"  => "Mijn overleg",
+"currentevents" => "In het nieuws",
+"errorpagetitle" => "Fout",
+"returnto"  => "Terugkeren naar $1.",
+"fromwikipedia" => " ",
+"whatlinkshere" => "Pagina's die hierheen verwijzen",
+"help"   => "Help",
+"search"  => "Zoeken",
+"go" => "Ga naar pagina",
+"history"  => "Voorgeschiedenis",
+"printableversion" => "Printer-vriendelijke versie",
+"editthispage" => "Pagina bewerken",
+"deletethispage" => "Verwijderen",
+"protectthispage" => "Beveiligen",
+"unprotectthispage" => "Beveiliging opheffen",
+"newpage" => "Nieuwe pagina",
+"talkpage"  => "Overlegpagina",
+"subjectpage" => "Artikel",
+"articlepage"   => "Artikel",
+"userpage" => "Gebruikerspagina",
+"wikipediapage" => "Artikel",
+"imagepage" => "Beschrijvingspagina",
+"viewtalkpage" => "Bekijk de overlegpagina",
+"otherlanguages" => "Andere talen",
+"redirectedfrom" => "(Doorverwezen vanaf $1)",
+"lastmodified" => "en is voor het laatst gewijzigd op $1.",
+"viewcount"  => "Deze pagina werd $1 maal bekeken ",
+"gnunote" => "Alle tekst op deze pagina valt onder de  <a class=internal href='/wiki/Gnu_Vrije_Documentatie_Licentie'>GNU FDL</a>.",
+"printsubtitle" => "(Uit http://nl.wikipedia.org)",
+"protectedpage" => "Beveiligde pagina",
+"administrators" => "Wikipedia:Systeembeheerders",
+"sysoptitle" => "Toegang alleen voor systeembeheerders",
+"sysoptext"  => "De gevraagde handeling kan enkel uitgevoerd worden door systeembeheerders. Zie $1.",
+"developertitle" => "Toegang alleen voor systeemontwikkelaars",
+"developertext" => "De gevraagde handeling kan enkel uitgevoerd worden door systeemontwikkelaars. Zie $1.",
+"nbytes"  => "$1 bytes",
+"go"   => "OK",
+"ok"   => "OK",
+"sitetitle"  => "<span style=\"text-transform: none\">Wikipedia NL</span>", # Okay, HERE's an ugly hack. There should be a cleaner way to do this.
+"sitesubtitle" => "De vrije encyclopedie",
+"retrievedfrom" => "Afkomstig van Wikipedia NL, de Vrije Encyclopedie. \"$1\"",
+"newmessages" => "Er zijn $1.",
+"newmessageslink" => "nieuwe berichten voor u",
+
+# Main script and global functions
+# Algemene functies
+"nosuchaction" => "Gevraagde handeling bestaat niet",
+"nosuchactiontext" => "De door de URL gespecifieerde handeling wordt niet herkend door de Wikipedia software",
+"nosuchspecialpage" => "De gevraagde speciale pagina is onvindbaar",
+"nospecialpagetext" => "U heeft een speciale pagina aangevraagd die niet wordt herkend door de Wikipedia software",
+
+# General errors
+# Algemene foutmeldingen
+"error"   => "Fout",
+"databaseerror" => "Database fout",
+"dberrortext" => "Bij het zoeken is een syntaxfout in de database opgetreden.
+Dit kan zijn veroorzaakt door een illegale zoekactie (zie $5),
+ of het duidt op een fout in de software. 
+De laatste zoekpoging in de database was:
+<blockquote><tt>$1</tt></blockquote>
+vanuit de functie \"<tt>$2</tt>\".
+MySQL gaf the foutmelding \"<tt>$3: $4</tt>\".",
+"noconnect"  => "Verbinden met de database op $1 was niet mogelijk",
+"nodb"   => "Selectie van database $1 niet mogelijk",
+"readonly"  => "Database geblokeerd",
+"enterlockreason" => "Geef een reden voor de blokkering en hoelang het waarschijnlijk gaat duren. De ingegeven reden zal aan de gebruikers getoond worden.",
+"readonlytext" => "De database van Wikipedia is momenteel gesloten voor nieuwe bewerkingen en wijzigingen, waarschijnlijk voor bestandsonderhoud.
+De verantwoordelijke systeembeheerder gaf hiervoor volgende reden op:
+<p>$1",
+"missingarticle" => "De database heeft een paginatekst (\"$1\") die het zou moeten vinden niet gevonden. Dit is geen fout in de database, maar waarschijnlijk in de software. Meld dit a.u.b. aan een beheerder, met vermelding van de URL.",
+"internalerror" => "Interne fout",
+"filecopyerror" => "Bestand \"$1\" naar \"$2\" kopiëren niet mogelijk.",
+"filerenameerror" => "Wijziging titel bestand \"$1\" in \"$2\" niet mogelijk.",
+"filedeleteerror" => "Kon bestand \"$1\" niet verwijderen.",
+"filenotfound" => "Kon bestand \"$1\" niet vinden.",
+"unexpected" => "Onverwachte waarde: \"$1\"=\"$2\".",
+"formerror"  => "Fout: kon formulier niet verzenden", 
+"badarticleerror" => "Deze handeling kan op deze pagina niet worden uitgevoerd.",
+"cannotdelete" => "Kon de pagina of afbeelding niet verwijderen.",
+"badtitle"              => "Ongeldige paginatitel", 
+"badtitletext"  => "De opgevraagde pagina is niet beschikbaar of leeg.",
+"perfdisabled" => "Om overbelasting van het systeem te voorkomen, is deze optie momenteel niet bruikbaar.",
+
+# Login and logout pages
+# Aanmelden en afmelden
+"logouttitle" => "Afmelden gebruiker",
+"logouttext" => "U bent nu afgemeld.
+U kan Wikipedia anoniem blijven gebruiken, of u opnieuw aanmelden onder dezelfde of onder een andere naam.\n",
+
+"welcomecreation" => "<h2>Welkom, $1!</h2><p>Uw gebruikersprofiel is aangemaakt. U kan nu uw persoonlijke voorkeuren instellen.",
+
+"loginpagetitle" => "Gebruikersnaam",
+"yourname"  => "Uw gebruikersnaam",
+"yourpassword" => "Uw wachtwoord",
+"yourpasswordagain" => "Wachtwoord opnieuw ingeven",
+"newusersonly" => " (alleen nieuwe gebruikers)",
+"remembermypassword" => "Mijn wachtwoord onthouden voor latere sessies.",
+"loginproblem" => "<b>Er is een probleem met het aanmelden.</b><br>Probeer het opnieuw a.u.b.",
+"alreadyloggedin" => "<font color=red><b>Gebruiker $1, u bent al aangemeld.</b></font><br>\n",
+
+"areyounew"  => "Bent u nieuw op Wikipedia en wilt u een gebruikersprofiel aanmaken, voer dan een gebruikersnaam in en voer tweemaal hetzelfde wachtwoord in.
+Invoeren van uw e-mailadres is niet verplicht; het is handig als u uw wachtwoord bent vergeten; dat kan dan per e-mail worden opgestuurd.<br>\n",
+
+"login"   => "Aanmelden",
+"userlogin"  => "Aanmelden",
+"logout"  => "Afmelden",
+"userlogout" => "Afmelden",
+"createaccount" => "Nieuw gebruikersprofiel aanmaken.",
+"badretype"  => "De ingevoerde wachtwoorden verschillen van elkaar.",
+"userexists" => "De gebruikersnaam die u heeft ingevoerd is al in gebruik. Gelieve een andere naam te kiezen.",
+"youremail"  => "Uw e-mailadres",
+"yournick"  => "Uw bijnaam (voor handtekeningen)",
+"emailforlost" => "Het opgeven van een e-mailadres is niet verplicht.<br>Het geeft anderen de mogelijkheid u via de website te e-mailen zonder dat uw e-mailadres bekend wordt, en als u uw paswoord vergeet, kan u een nieuw paswoord opgestuurd worden.",
+"loginerror" => "Inlogfout",
+"noname"  => "U dient een gebruikersnaam op te geven.",
+"loginsuccesstitle" => "Aanmelden gelukt.",
+"loginsuccess" => "U bent nu aangemeld bij Wikipedia NL als \"$1\".",
+"nosuchuser" => "Er bestaat geen gebruiker met de naam \"$1\". Controleer uw spelling, of gebruik onderstaand formulier om een nieuw gebruikersprofiel aan te maken.",
+"wrongpassword" => "Het ingegeven wachtwoord is niet juist. Probeer het opnieuw.",
+"mailmypassword" => "Stuur mij een nieuw wachtwoord op",
+"passwordremindertitle" => "Herinnering wachtwoord Wikipedia NL",
+"passwordremindertext" => "Iemand (waarschijnlijk uzelf) vanaf IP-adres $1 heeft verzocht u een nieuw wachtwoord voor Wikipedia NL toe te zenden. Het nieuwe wachtwoord voor gebruiker \"$2\" is \"$3\". Advies: nu aanmelden en uw wachtwoord wijzigigen.",
+"noemail"  => "Er is geen e-mailadres geregistreerd voor \"$1\".",
+"passwordsent" => "Er is een nieuw wachtwoord verzonden naar het e-mailadres wat geregistreerd staat voor \"$1\".
+Gelieve na ontvangst opnieuw aan te melden.",
+
+# Edit pages
+# Pagina bewerken
+"summary"  => "Samenvatting",
+"minoredit"  => "Dit is een kleine wijziging",
+"watchthis" => "Volg deze pagina",
+"savearticle" => "Pagina opslaan",
+"preview"  => "Nakijken",
+"showpreview" => "Toon bewerking ter controle",
+"blockedtitle" => "Gebruiker is geblokkeerd",
+"blockedtext" => "Uw gebruikersnaam of IP-adres is door $1 geblokkeerd. De opgegeven reden:<br>$2<p>. U kunt voor overleg contact opnemen met de [[Wikipedia:Systeembeheerders|systeembeheerders]].",
+"newarticle" => "(Nieuw)",
+"newarticletext" => "Er bestaat nog geen artikel over dit onderwerp.<br>Als u wilt, kunt u hieronder een nieuw artikel schrijven.<br>Was dit niet de bedoeling, gebruik dan de 'Terug' knop van uw browser.",
+"anontalkpagetext" => "<hr>Deze overlegpagina hoort bij een anonieme gebruiker die hetzij geen loginnaam heeft, hetzij deze niet gebruikt. We gebruiken daarom het IP-adres ter identificatie. Het kan echter zijn dat meerdere personen hetzelfde IP-adres gebruiken. Het kan daarom zijn dat u hier berichten ontvangt die niet voor u bedoeld zijn. Mocht u dat willen voorkomen, dan kunt u [[Speciaal:Userlogin|een gebruikersnaam aanvragen of u aanmelden]].",
+"noarticletext" => "(Deze pagina bevat momenteel geen tekst)",
+"updated"  => "(Bijgewerkt)",
+"note"   => "<strong>Opmerking:</strong> ",
+"previewnote" => "Let op: dit is een controlepagina; uw tekst is nog niet opgeslagen!",
+"previewconflict" => "Deze versie toont hoe de tekst in het bovenste veld eruit gaat zien wanneer u zou opslaan.",
+"editing"  => "Bewerkingspagina: $1",
+"editconflict" => "Bewerkingsconflict: $1",
+"explainconflict" => "Iemand anders heeft deze pagina gewijzigd nadat u aan deze bewerking bent begonnen. Het bovenste tekstveld toont de huidige versie van de pagina. U zal uw eigen wijzigingen moeten integreren in die tekst. Alleen de tekst in het bovenste veld wordt bewaard wanneer u kiest voor \"Pagina opslaan\".\n<p>",
+"yourtext"  => "Uw tekst",
+"storedversion" => "Opgeslagen versie",
+"editingold" => "<strong>WAARSCHUWING: U bent bezig een oude versie van deze pagina te bewerken. Wanneer u uw bewerking opslaat, gaan alle wijzigingen die na deze versie gedaan zijn verloren.\n.</strong>\n",
+"yourdiff"  => "Wijzigingen",
+"copyrightwarning" => "Opgelet: Alle bijdragen aan Wikipedia worden geacht te zijn vrijgegeven onder de GNU Free Documentation License. Als u niet wil dat uw tekst door anderen naar believen bewerkt en verspreid kan worden, kies dan niet voor 'Pagina Opslaan'.<br> Hierbij belooft u ons tevens dat u deze tekst zelf hebt geschreven, of overgenomen uit een vrije, openbare bron.<br> <strong>GEBRUIK GEEN MATERIAAL DAT BESCHERMD WORDT DOOR AUTEURSRECHT, TENZIJ JE DAARTOE TOESTEMMING HEBT!</strong>",
+"longpagewarning" => "Waarschuwing! Deze pagina is $1 kilobyte lang. Pagina's langer dan 32 kb zorgen voor problemen op sommige browsers. Het is daarom waarschijnlijk een goed idee deze pagina in meerdere pagina's te splitsen.",
+
+# History pages
+# Geschiedenis pagina's
+"revhistory" => "Bewerkingsgeschiedenis",
+"nohistory"  => "Deze pagina heeft nog geen bewerkingen ondergaan.",
+"revnotfound" => "Wijziging niet gevonden",
+"revnotfoundtext" => "De opgevraagde oude versie van deze pagina is onvindbaar. Controleer a.u.b. de URL die u gebruikte om naar deze pagina te gaan.\n",
+"loadhist"  => "Bezig met het laden van de paginageschiedenis",
+"currentrev" => "Huidige versie",
+"revisionasof" => "Versie op $1",
+"cur"   => "huidig",
+"next"   => "volgende",
+"last"   => "vorige",
+"orig"   => "orig",
+"histlegend" => "Verklaring afkortingen: (wijz) = verschil met huidige versie, (vorige) = verschil met voorgaande versie, K = kleine wijziging",
+
+# Diffs
+# Verschil
+"difference" => "(Verschil tussen bewerkingen)",
+"loadingrev" => "bezig paginaversie te laden",
+"lineno"  => "Regel $1:",
+"editcurrent" => "De huidige versie van deze pagina bewerken",
+
+# Search results
+# Zoek resultaten
+"searchresults" => "Zoekresultaten",
+"searchhelppage" => "Wikipedia:Zoeken",
+"searchingwikipedia" => "Zoeken op Wikipedia",
+"searchresulttext" => "Voor meer informatie over zoeken op Wikipedia: zie $1.",
+"searchquery" => "Voor zoekopdracht \"$1\"",
+"badquery"  => "Slecht geformuleerde zoekopdracht",
+"badquerytext" => "Uw zoekopdracht kon niet worden uitgevoerd. Dit komt wellicht doordat u heeft geprobeerd een woord van minder dan drie letters te zoeken; dat wordt door de software niet ondersteund. Het is ook mogelijk dat u de zoekterm verkeerd hebt ingetypt, zoals bij \"vissen en en schubben\".",
+"matchtotals" => "De zoekterm \"$1\" is gevonden in $2 paginatitels en in de tekst van $3 pagina's.",
+"nogomatch" => "Er bestaat geen pagina met deze titel, op zoek naar pagina's waarin de tekst voorkomt.",
+"titlematches" => "Overeenkomst met volgende titels",
+"notitlematches" => "Geen enkele paginatitel gevonden met de opgegeven zoekterm",
+"textmatches" => "Overeenkomst met artikel inhoud",
+"notextmatches" => "Geen artikel gevonden met opgegeven zoekterm",
+"prevn"   => "vorige $1",
+"nextn"   => "volgende $1",
+"viewprevnext" => "($1) ($2) ($3) bekijken.",
+"showingresults" => "Hieronder de <b>$1</b> resultaten vanaf nummer <b>$2</b>.",
+"nonefound"  => "<strong>Merk op:</strong> wanneer een zoekopdracht mislukt komt dat vaak door gebruik van (in het Engels) veel voorkomende woorden zoals \"of\" en \"be\", die niet geïndexeerd zijn, of door verschillende zoektermen tegelijk op te geven (u krijgt dan alleen in pagina's waaarin alle opgegeven termen voorkomen).",
+"powersearch" => "Zoeken",
+"powersearchtext" => "   
+ Zoek in naamruimten :<br>
+$1<br>
+$2 Toon redirects &nbsp; Zoek: $3 $9",   
+
+# Preferences page
+# Voorkeuren
+"preferences" => "Voorkeuren",
+"prefsnologin" => "Niet aangemeld",
+"prefsnologintext" => "U dient <a href=\"" .
+  wfLocalUrl( "Special:Userlogin" ) . "\">aangemeld</a> te zijn om voorkeuren te kunnen instellen.",
+"prefslogintext" => "U bent aangemeld als \"$1\". Uw interne identificatienummer is $2.",
+"prefsreset" => "Standaardvoorkeuren hersteld.",
+"qbsettings" => "Menubalkinstellingen", 
+"changepassword" => "Wachtwoord wijzigen",
+"skin" => "Wikipedia-Uiterlijk",
+"math" => "Wiskundige formules tonen",
+"math_failure" => "Wiskundige formule niet begrijpelijk",
+"math_unknown_error" => "Onbekende fout in formule",
+"math_unknown_function" => "Onbekende functie in formule",
+"math_lexing_error" => "Lexicografische fout in formule",
+"math_syntax_error" => "Syntax-fout in formule",
+"saveprefs"  => "Voorkeuren opslaan",
+"resetprefs" => "Standaardvoorkeuren herstellen",
+"oldpassword" => "Huidig wachtwoord",
+"newpassword" => "Nieuw wachtwoord",
+"retypenew"  => "Voer het nieuwe wachtwoord nogmaals in",
+"textboxsize" => "Afmetingen tekstveld",
+"rows"   => "Regels",
+"columns"  => "Kolommen",
+"searchresultshead" => "Instellingen voor zoekresultaten",
+"resultsperpage" => "Aantal per bladzijde te tonen zoekresultaten",
+"contextlines" => "Aantal regels per gevonden pagina",
+"contextchars" => "Aantal tekens van de context per regel",
+"stubthreshold" => "Grootte waaronder een pagina als 'stub' wordt aangegeven",
+"recentchangescount" => "Aantal titels in lijst recente wijzigingen",
+"savedprefs" => "Uw voorkeuren zijn opgeslagen.",
+"timezonetext" => "De tijd van de server is UTC (Coordinated Universal Time) Geef aan hoeveel uur de plaatselijke tijd in uw woonplaats verschilt met die van de server. Voor o.a. België en Nederland: +1 (+2 zomertijd); voor Suriname en voor de Nederlandse Antillen: -4; voor Zuid-Afrika: +2.",
+"localtime" => "Plaatselijke tijd",
+"timezoneoffset" => "Tijdsverschil",
+"emailflag"  => "E-mail ontvangen van andere gebruiken uitschakelen",
+
+# Recent changes
+# Recente wijzigingen
+"changes" => "wijzigingen",
+"recentchanges" => "Recente wijzigingen",
+"recentchangestext" => "Deze pagina toont de meest recente wijzigingen aan Wikipedia NL
+Mocht u hier nieuw zijn, dan welkom bij Wikipedia! Bekijk AUB de volgende pagina's eens: [[Wikipedia:Veel gestelde vragen|Veel gestelde vragen]], [[Wikipedia:Instructies|Instructies]], [[Wikipedia:Objectiviteit|Objectiviteit]] en [[Wikipedia:Wat je niet moet doen|Wat je NIET moet doen]].
+Als u pagina's wilt verwijderen, ga naar [[Wikipedia:Te verwijderen pagina's|Te verwijderen pagina's]], als u iets wilt bediscussi&euml;ren, ga naar [[Wikipedia:Overleg gewenst|Overleg gewenst]]. Er is ook een email-lijst voor WikipediaNL: [http://www.wikipedia.org/mailman/listinfo/wikinl-l WikiNL-l].
+<br>Om Wikipedia te laten slagen is het erg belangrijk '''geen''' materiaal toe te voegen waarop iemand anders auteursrechten heeft, tenzij u daartoe toestemming heeft. De wettelijke gevolgen van inbreuk op de rechten van anderen zouden de hele onderneming zwaar kunnen schaden.",
+"rcloaderr"  => "Meest recente wijzigingen laden",
+"rcnote"  => "Hieronder zijn de <strong>$1</strong> laatste wijzigingen gedaan in de laatste <strong>$2</strong> dagen.",
+"rcnotefrom"  => "Veranderingen sinds <b>$2</b> (met een maximum van <b>$1</b> veranderingen).",
+"rclistfrom"  => "Toon de veranderingen vanaf $1",
+# "rclinks"  => "Bekijk de $1 laatste wijzigingen in de laatste $2 uren / laatste $3 dagen.",
+"rclinks"  => "Bekijk de $1 laatste wijzigingen in de laatste $2 dagen.",
+"rchide"  => "in $4 vorm; $1 kleine wijzigingen; $2 wijzigingen op speciale pagina's zoals overleg- en gebruikerspagina's; $3 meervoudige wijzigingen.",
+"diff"   => "wijz",
+"hist"   => "hist",
+"hide"   => "verberg",
+"show"   => "toon",
+"tableform"  => "tabel",
+"listform"  => "lijst",
+"nchanges"  => "$1 wijzigingen",
+"minoreditletter" => "K",
+"newpageletter" => "N",
+
+# Upload
+#
+"upload"  => "Upload",
+"uploadbtn"  => "upload bestand",
+"uploadlink" => "upload afbeelding",
+"reupload"  => "Opnieuw uploaden",
+"reuploaddesc" => "Terug naar het uploadformulier.",
+"uploadnologin" => "Niet aangemeld",
+"uploadnologintext" => "U dient <a href=\"" .
+  wfLocalUrl( "Speciaal:Userlogin" ) . "\">aangemeld te zijn</a>
+om bestanden te uploaden.",
+"uploadfile" => "upload bestand",
+"uploaderror" => "upload fout",
+"uploadtext" => "<strong>STOP!</strong> Voor u iets hier upload,
+wees zeker dat het in overeenkomst is met het Wikipedia NL <a href=\"" .
+wfLocalUrlE( "Wikipedia:Beleid_voor_gebruik_van_afbeeldingen" ) . "\">afbeeldingsbeleid</a>.
+<p>Om de reeds ge-uploade bestanden te bekijken of te zoeken ga naar de <a href=\"" . wfLocalUrlE( "Speciaal:Imagelist" ) .
+"\">lijst van ge-uploade bestanden</a>.
+Uploads en verwijderingen worden bijgehouden in het <a href=\"" .
+wfLocalUrlE( "Wikipedia:Upload_logboek" ) . "\">upload logboek</a>.
+<p>Gebruik het onderstaande formulier om bestanden zoals afbeeldingen en geluidsbestanden die relevant zijn voor uw artikel te u-loaden. Bij de meeste browers zoals 'Internet Explorer' en 'Mozilla' zult u een \"Bladeren...\" of \"Browse..\" knop zien die een standaard dialoogscherm van uw bestuuringssysteem oproept. Kiest u een bestand, dan zal het ingevuld worden in het veld naast de \"Bladeren...\" knop. U dient ook het vakje aan te vinken waarmee u bevestigt dat er geen schending van auteursrechten plaatsvindt door het gebruik van dat bestand. Vul het veld \"Omschrijving\" in. Druk op de \"Upload\" knop om het uploaden te voltooien. Dit kan even duren als u een langzame internetverbinding gebruikt.
+<p>Gebruik bij voorkeur JPEG voor foto's, PNG voor tekeningen en dergelijke en OGG voor geluid. 
+Geef uw bestanden een duidelijk omschrijvende naam om verwarring te voorkomen. Om het bestand in een pagina te laten verschijnen, kunt u het volgende doen;  <b>[[afbeelding:uw_foto.jpg]]</b> of <b>[[afbeelding:uw_logo.png|alt text]]</b> of <b>[[media:uw_geluid.ogg]]</b> voor audio.
+<p>Vergeet niet dat net als met andere pagina's op Wikipedia anderen de ge-uploade bestanden kunnen verwijderen indien men denkt dat dat in het voordeel van het project is. Bij misbruik van dit systeem kan u de toegang tot Wikipedia NL ontzegd worden.",
+"uploadlog"  => "upload logboek",
+"uploadlogpage" => "Upload_logboek",
+"uploadlogpagetext" => "Hieronder de lijst met de meest recent ge-uploade bestanden. Alle tijden zijn servertijd (UTC).
+<ul>
+</ul>
+",
+"filename"  => "Bestandsnaam",
+"filedesc"  => "Beschrijving",
+"affirmation" => "Ik verklaar dat de eigenaar van de rechten op dit bestand toestemt om het onder de voorwaarden van $1 te verspreiden.",
+"copyrightpage" => "Wikipedia:Auteursrechten",
+"copyrightpagename" => "Wikipedia NL auteursrechten",
+"uploadedfiles" => "Ge-uploade bestanden",
+"noaffirmation" => "U dient te bevestigen dat deze handeling geen inbreuk maakt op auteursrechten.",
+"ignorewarning" => "Negeer de waarschuwing en sla het bestand op.",
+"minlength"  => "De naam van het bestand moet uit ten minste drie tekens bestaan.",
+"badfilename" => "De naam van het bestand is gewijzigd in \"$1\".",
+"badfiletype" => "\".$1\" is geen aanbevolen afbeeldings bestandsformaat.",
+"largefile"  => "Aanbeveling: maak afbeeldingen niet groter dan 100k",
+"successfulupload" => "De upload was succesvol",
+"fileuploaded" => "<b>Het uploaden van bestand \"$1\" is geslaagd.</b> Gelieve deze link naar de omschrijvingspagina te volgen: ($2). Vul daar informatie in over dit bestand, bijvoorbeeld de oorsprong, wanneer en door wie het gemaakt is en wat u verder er nog over te vertellen heeft.",
+"uploadwarning" => "Upload waarschuwing ",
+"savefile"  => "Bestand opslaan",
+"uploadedimage" => "heeft ge-upload: \"$1\"",
+
+# Image list
+# Afbeeldingslijst
+"imagelist"  => "Lijst van afbeeldingen",
+"imagelisttext" => "Hier volgt een lijst met $1 afbeeldingen geordend $2.",
+"getimagelist" => "Lijst van afbeeldingen ophalen",
+"ilshowmatch" => "Toon alle afbeeldingen waarvan de naam voldoet aan",
+"ilsubmit"  => "Zoek",
+"showlast"  => "Toon de laatste $1 afbeeldingen geordend $2.",
+"all"   => "alle",
+"byname"  => "op naam",
+"bydate"  => "op datum",
+"bysize"  => "op grootte",
+"imgdelete"  => "verw",
+"imgdesc"  => "besc",
+"imglegend"  => "Verklaring: (besc) = toon/verander beschrijving van de afbeelding, (verw) = verwijdering de afbeelding.",
+"imghistory" => "Geschiedenis van de afbeelding",
+"revertimg"  => "rev",
+"deleteimg"  => "verw",
+"imghistlegend" => "Verklaring: (cur)= huidige afbeelding, (verw) = verwijder de oude versie, (rev) = breng oude versie terug.<br>
+<i>Klik op de datum om de afbeeldingen die ge-upload zijn op die datum te zien</i>.",
+"imagelinks" => "Afbeeldingsverwijzingen",
+"linkstoimage" => "Deze afbeelding wordt gebruikt op de volgende pagina's:",
+"nolinkstoimage" => "Geen enkele pagina gebruikt deze afbeelding.",
+
+# Statistics
+# Statistieken
+"statistics" => "Statistieken",
+"sitestats"  => "Statistieken betreffende Wikipedia NL",
+"userstats"  => "Statistieken betreffende gebruikers",
+"sitestatstext" => "Er zijn <b>$1</b> pagina's in de database. Hierbij zijn inbegrepen \"Overleg\" pagina's, pagina's over Wikipedia, extreem korte \"stub\" pagina's, redirects, en diverse andere pagina's die waarschijnlijk niet als artikel moeten worden geteld. Na uitsluiting daarvan, is er een geschat aantal van <b>$2</b> artikels.<p>
+Er is in totaal $3 maal een pagina bekeken, en $4 maal een pagina bewerkt. Dat geeft een gemiddelde van $5 bewerkingen per pagina, en $6 paginabezoeken per wijziging.",
+"userstatstext" => "Er zijn momenteel $1 geregistreerde gebruikers; hiervan zijn er $2 systeembeheerders (zie $3).",
+
+# Maintenance Page   
+#
+"maintenance"           => "Onderhoudspagina",
+"maintnancepagetext"    => "Op deze pagina vindt u een aantal handige zoekopdrachten om kleine alledaagse problemen in de Wikipedia te verhelpen. Sommige van deze zoekopdrachten vormen een grote belasting voor de database; ga dus niet na elke paar pagina's die u hersteld heeft, de pagina opnieuw laden.",
+"maintenancebacklink"   => "Terug naar de Onderhoudspagina",
+"disambiguations"       => "Doorverwijspagina's",
+"disambiguationspage"   => "Wikipedia:Doorverwijspagina",
+"disambiguationstext"   => "De onderstaande artikelen verwijzen naar een [[Wikipedia:Doorverwijspagina|doorverwijspagina]]. Deze zouden waarschijnlijk direct naar de onderwerpspagina moeten verwijzen. <br>Als doorverwijspagina's worden die pagina's beschouwd waar vanaf $1 naar verwezen wordt.<br>Opmerking: Deze lijst toont alleen pagina's vanuit de hoofdnaamruimte, en dus niet Overlegpagina's, Wikipedia:pagina's en dergelijke.",
+"doubleredirects"       => "Dubbele redirects",
+"doubleredirectstext"   => "<b>Let op:</b> Er kunnen in deze lijst redirects staan die er niet in thuishoren. Dat komt over het algemeen doordat er na de #REDIRECT nog andere links op de pagina staan.<br>\nOp elke regel vindt u de eerste redirectpagina, de tweede redirectpagina en de eerste regel van de tweede redirectpagina. Normaal gesproken bevat deze laatste de pagina waar de eerste redirect naartoe zou moeten verwijzen.",
+"brokenredirects"       => "Gebroken redirects",
+"brokenredirectstext"   => "De onderstaande redirectpagina's bevatten een redirect naar een niet-bestaande pagina.",
+"selflinks"             => "Pagina's die naar zichzelf verwijzen",
+"selflinkstext"         => "De volgende pagina's verwijzen naar zichzelf, wat niet hoort te gebeuren.",
+"mispeelings"           => "Pagina's met spelfouten",
+"mispeelingstext"       => "De volgende pagina's bevatten een veel voorkomende spel- of typfout, die staat aangegeven op de lijst in $1. Daar staat meestal ook (tussen haakjes) de juiste spelling.",
+"mispeelingspage"       => "Veel voorkomende spelfouten",
+"missinglanguagelinks"  => "Ontbrekende taallinks",
+"missinglanguagelinksbutton"    => "Vind ontbrekende taallinks voor",
+"missinglanguagelinkstext"      => "De onderstaande artikelen bevatten geen taallink naar een overeenkomende pagina in de taal \"$1\".",
+
+# Miscellaneous special pages
+# Diverse speciale pagina's
+"orphans"  => "Weespagina's",
+"lonelypages" => "Weespagina's",
+"unusedimages" => "Ongebruikte afbeeldingen",
+"popularpages" => "Populaire artikels",
+"nviews"  => "$1 keer bekeken",
+"wantedpages" => "Gewenste pagina's",
+"nlinks"  => "$1 verwijzingen",
+"allpages"  => "Alle pagina's",
+"randompage" => "Willekeurig artikel",
+"shortpages" => "Korte artikels",
+"longpages"  => "Lange artikels",
+"listusers"  => "Lijst van gebruikers",
+"specialpages" => "Speciale pagina's",
+"spheading"  => "Speciale pagina's",
+"sysopspheading" => "Speciale pagina's voor systeembeheerders",
+"developerspheading" => "Speciale pagina's voor systeemontwikkelaars",
+"protectpage" => "Beveilig pagina",
+"recentchangeslinked" => "Volg links",
+"rclsub"  => "(van pagina's waarnaar \"$1\" verwijst)",
+"debug"   => "Bugreparatie",
+"newpages"  => "Nieuwe pagina's",
+"intl" => "Taallinks",
+"movethispage" => "Verplaats deze pagina",
+"unusedimagestext" => "<p>Let op! Het zou kunnen dat er via een directe link verwezen wordt naar een afbeelding, bijvoorbeeld vanuit een anderstalige Wikipedia. Het is daarom mogelijk dat een afbeelding hier vermeld staat terwijl het wel degelijk gebruikt wordt.",
+"booksources" => "Boekhandels",
+"booksourcetext" => "Hieronder is een lijst van externe websites die boeken verkopen en ook verdere informatie hierover kunnen verstekken. Via een ISBN-nummer in een artikel kan u via deze pagina een werk opzoeken. <p>Deze dienst is enkel ter uwer informatie. Wikipedia NL heeft <u>geen enkele</u> relatie met deze websites.",
+"alphaindexline" => "$1 tot $2",
+
+# Email this user
+# E-mail deze gebruiker
+"mailnologin" => "Geen e-mailadres gekend voor deze gebruiker",
+"mailnologintext" => "U dient <a href=\"" .
+  wfLocalUrl( "Speciaal:Userlogin" ) . "\">aangemeld te zijn </a>
+en een geldig e-mailadres in uw <a href=\"" .
+  wfLocalUrl( "Speciaal:Preferences" ) . "\">voorkeuren</a>
+to send e-mail to other users.",
+"emailuser"  => "E-mail deze gebruiker",
+"emailpage"  => "E-mail gebruiker",
+"emailpagetext" => "Indien deze gebruiker een geldig e-mailadres heeft opgegeven dan kan u via dit formulier een bericht verzenden. Het e-mailadres dat u heeft opgegeven bij uw voorkeuren zal als afzender gebruikt worden.",
+"noemailtitle" => "Geen e-mailadres gekend voor deze gebruiker",
+"noemailtext" => "Deze gebruiker heeft geen geldig e-mailadres opgegeven of heeft deze functie uitgeschakelt.",
+"emailfrom"  => "Van",
+"emailto"  => "Aan",
+"emailsubject" => "Onderwerp",
+"emailmessage" => "Bericht",
+"emailsend"  => "Verstuur bericht",
+"emailsent"  => "E-mail versturen",
+"emailsenttext" => "Uw bericht is verzonden.",
+
+# Watchlist
+# Volglijst
+"watchlist"  => "Volglijst",
+"watchlistsub" => "(van gebruiker \"$1\")",
+"nowatchlist" => "Er staat niets op uw volglijst.",
+"watchnologin" => "U bent niet aangemeld",
+"watchnologintext" => "Om uw volglijst te veranderen dient u eerst <a href=\"" .
+  wfLocalUrl( "Speciaal:Userlogin" ) . "\">aangemeld</a>
+te zijn.",
+"addedwatch" => "Toegevoegd aan volglijst",
+"addedwatchtext" => "De pagina \"$1\" is aan uw <a href=\"" .
+  wfLocalUrl( "Speciaal:Watchlist" ) . "\">volglijst</a> toegevoegd.
+Toekomstige wijzigingen aan deze pagina en overlegpagina zullen hier vermeld worden. 
+Ook zullen deze pagina's in het <b>vet</b> verschijnen in de <a href=\"" .
+  wfLocalUrl( "Speciaal:Recentchanges" ) . "\">lijst van recente wijzigingen</a> zodat u ze eenvoudiger kan opmerken.</p>
+
+<p>Indien u een pagina wenst te verwijderen van uw volglijst klik dan op \"Van volglijst verwijderen\" in de menubalk.",
+"removedwatch" => "Van volglijst verwijderen",
+"removedwatchtext" => "De pagina \"$1\" is van uw volglijst verwijderd.",
+"watchthispage" => "Volg deze pagina",
+"unwatchthispage" => "Niet meer volgen",
+"notanarticle" => "Is geen artikel",
+
+
+# Delete/protect/revert
+# Verwijderen/beschermen/annuleren
+"deletepage" => "Pagina verwijderen",
+"confirm"  => "Bevestig",
+"confirmdelete" => "Bevestig verwijdering",
+"deletesub"  => "(Verwijderen \"$1\")",
+"confirmdeletetext" => "U bent staat op het punt een pagina of afbeelding voorgoed te verwijderen. Dit verwijdert alle inhoud en geschiedenis van de database. Bevestig hieronder dat dit inderdaad uw bedoeling is, dat u de gevolgen begrijpt, en dat uw verwijdering overeenkomt met de [[Wikipedia:Instructies]].",
+"confirmcheck" => "Ja, ik wil dit voorgoed verwijderen.",
+"actioncomplete" => "Actie voltooid",
+"deletedtext" => "\"$1\" is verwijderd. Zie $2 voor een overzicht van recente verwijderingen.",
+"deletedarticle" => "\"$1\" is verwijderd",
+"dellogpage" => "Logboek_verwijderde_pagina's", # This one needs the underscores!
+"dellogpagetext" => "Hieronder ziet u een lijst van de meest recentelijk verwijderde pagina's en afbeeldingen. Alle tijden zijn servertijd, UTC-0.",
+"deletionlog" => "Logboek verwijderde pagina's",
+"reverted"  => "Eerdere versie hersteld",
+"deletecomment" => "Reden voor verwijdering",
+"imagereverted" => "De omzetting naar de oudere versie is geslaagd.",
+"rollback"      => "Wijzigingen ongedaan maken",
+"rollbacklink"  => "Terugdraaien",
+"cantrollback"  => "Ongedaan maken van wijzigingen onmogelijk: Dit artikel heeft slechts 1 auteur.",
+"revertpage"    => "Hersteld tot de versie na de laatste wijziging door $1.",
+
+# Undelete
+"undelete" => "Verwijderde pagina terugplaatsen",
+"undeletepage" => "Verwijderde pagina's bekijken en terugplaatsen",
+"undeletepagetext" => "De onderstaande pagina's zijn verwijderd, maar bevinden zich nog steeds in het archief, en kunnen teruggeplaatst worden.",
+"undeletearticle" => "Verwijderde pagina terugplaatsen",
+"undeleterevisions" => "$1 versies in het archief",
+"undeletehistory" => "Als u een pagina terugplaatst, worden alle versies als oude versies teruggeplaatst. Als er al een nieuwe pagina met dezelfde naam is aangemaakt, zullen deze versies als oude versies worden teruggeplaatst, maar de huidige versie niet gewijzigd worden.",
+"undeleterevision" => "Verwijderde versie van $1",
+"undeletebtn" => "Terugplaatsen!",
+"undeletedarticle" => "\"$1\" is teruggeplaatst.",
+"undeletedtext" =>"Het artikel [[$1]] is teruggeplaatst. Zie [[Wikipedia:Logboek verwijderde pagina's]] voor een lijst van de meest recente verwijderingen en terugplaatsingen.",
+
+# Contributions
+# Bijdragen
+"contributions" => "Bijdragen per gebruiker",
+"mycontris" => "Mijn bijdragen",
+"contribsub" => "Voor $1",
+"nocontribs" => "Geen wijzigingen gevonden die aan de gestelde criteria voldoen.",
+"ucnote"  => "Hieronder ziet u de laatste <b>$1</b> wijzigingen van deze gebruiker in de laatste <b>$2</b> dagen.",
+"uclinks"  => "Bekijk de laatste <b>$1</b> veranderingen; bekijk de laatste <b>$2</b> dagen.",
+"uctop" => " (laatste wijziging)",
+
+# What links here
+# Wat linkt hier
+"whatlinkshere" => "Referenties",
+"notargettitle" => "Geen doelpagina",
+"notargettext" => "U hebt niet gezegd voor welke pagina u deze functie wilt bekijken.",
+"linklistsub" => "(lijst van verwijzingen)",
+"linkshere"  => "De volgende pagina's verwijzen hiernaartoe:",
+"nolinkshere" => "Geen enkele pagina verwijst hierheen.",
+"isredirect" => "redirect pagina",
+
+# Block/unblock IP
+#
+"blockip"  => "Blokkeer IP-adres",
+"blockiptext" => "Gebruik het onderstaande formulier om schrijftoegang van een bepaald IP-adres te verbieden. Dit mag enkel gedaan worden om vandalisme te voorkomen en moet in overeenstemming zijn met de [[Wikipedia:spelregels|spelregels]] van Wikipedia NL. Vul een specifieke reden in.",
+"ipaddress"  => "IP-adres",
+"ipbreason"  => "Reden",
+"ipbsubmit"  => "Blokkeer dit IP-adres",
+"badipaddress" => "Het IP-adres heeft een ongeldige opmaak.",
+"noblockreason" => "U dient een reden op te geven voor het blokkeren van een IP-adres.",
+"blockipsuccesssub" => "Blokkering gelukt",
+"blockipsuccesstext" => "Het IP-adres \"$1\" is geblokkeerd.<br>
+Zie de [[speciaal:Ipblocklist|Lijst van geblokkeerde IP-adressen]].",
+"unblockip"  => "De-blokkeer IP-adres",
+"unblockiptext" => "Gebruik het onderstaande formulier om terug schrijftoegang te geven aan een geblokkeerd IP-adres.",
+"ipusubmit"  => "De-blokkeer dit IP-adres.",
+"ipusuccess" => "Het IP-adres \"$1\" is gedeblokkeerd.",
+"ipblocklist" => "Lijst van geblokkeerde IP-adressen.",
+"blocklistline" => "Op $1 blokkeerde $2 het adres $3",
+"blocklink"  => "blokkeer",
+"unblocklink" => "de-blokkeer",
+"contribslink" => "bijdragen",
+
+# Developer tools
+# Ontwikkelingsgereedsschap
+"lockdb"  => "Blokkeer de database",
+"unlockdb"  => "De-blokkeer de database",
+"lockdbtext" => "Waarschuwing: De database blokkeren heeft tot gevolg dat geen enkele gebruiker meer in staat is de pagina's te bewerken, hun voorkeuren te wijzigen of iets anders te doen waarvoor er wijzigingen in de database nodig zijn.",
+"unlockdbtext" => "Het de-blokkeren van de database zal de gebruikers de mogelijkheid geven om wijzigingen aan pagina's op te slaan, hun voorkeuren te wijzigen en alle andere bewerkingen waarvoor er wijzigingen in de database nodig zijn. Is dit inderdaad wat u wilt doen?.",
+"lockconfirm" => "Ja, ik wil de database blokkeren.",
+"unlockconfirm" => "Ja, ik wil de database de-blokkeren.",
+"lockbtn"  => "Blokkeer de database",
+"unlockbtn"  => "De-blokkeer de database",
+"locknoconfirm" => "U heeft niet het vakje aangevinkt om uw keuze te bevestigen.",
+"lockdbsuccesssub" => "Blokkering database succesvol",
+"unlockdbsuccesssub" => "Blokkering van de database opgeheven",
+"lockdbsuccesstext" => "De database van Wikipedia NL is geblokkeerd.
+Vergeet niet de database opnieuw te de-blokkeren zodra u klaar bent met uw onderhoud.",
+"unlockdbsuccesstext" => "Blokkering van de database van Wikipedia NL is opgeheven.",
+
+# SQL query
+# SQL raadplegen
+"asksql"  => "SQL raadplegen",
+"asksqltext" => "Gebruik het onderstaande formulier om een direct verzoek naar de database van Wikipedia NL te zenden. Gebruik enkelvoudige aanhalingstekens ('zoals hier') voor letterlijke teksten. Een ingewikkelde aanvraag kan de sever vaak extra belasten. Gelieve deze mogelijkheid daarom spaarzaam te gebruiken. Zie ook: [[Wikipedia:SQL opdrachten]].",
+"sqlquery"  => "Voer opdracht in",
+"querybtn"  => "Verstuur opdracht",
+"selectonly" => "Opdrachten anders dan \"SELECT\" zijn voorbehouden aan Wikipedia ontwikkelaars.",
+"querysuccessful" => "Opdracht succesvol",
+
+# Move page
+# Verplaats pagina
+"movepage"  => "Verplaats pagina",
+"movepagetext" => "Door middel van het onderstaande formulier kan u de titel van een pagina hernoemen. De voorgeschiedenis van de oude pagina zal deze van de nieuwe worden. De oude titel zal automatisch een doorverwijzing worden naar de nieuwe. U kunt een dergelijke hernoeming alleen doen plaatsvinden, als er geen pagina bestaat met de nieuwe naam, of als er slechts een redirect zonder verdere geschiedenis is.",
+"movepagetalktext" => "De bijbehorende overlegpagina wordt ook verplaatst, maar '''niet''' in de volgende gevallen:
+* Als de pagina naar een andere naamruimte wordt verplaatst
+* Als er al een niet-lege Overlegpagina bestaat onder de andere naam
+* Als u de onderstaande radiobox niet aangevinkt laat",
+"movearticle" => "Verplaats pagina",
+"movenologin" => "Niet aangemeld",
+"movenologintext" => "U dient <a href=\"" .
+  wfLocalUrl( "Speciaal:Userlogin" ) . "\">aangemeld</a>
+te zijn om een pagina te verplaatsen.",
+"newtitle"  => "Naar de nieuwe titel",
+"movepagebtn" => "Verplaats pagina",
+"pagemovedsub" => "De verplaatsing was succesvol",
+"pagemovedtext" => "Pagina \"[[$1]]\" verplaatst naar \"[[$2]]\".",
+"articleexists" => "Er is reeds een pagina met deze titel of de titel is ongeldig. <br>Gelieve een andere titel te kiezen.",
+"talkexists" => "De pagina zelf is verplaatst, maar de Overlegpagina kon niet worden verplaatst, omdat de doeltitel al een niet-lege overlegpagina had. Combineer de overlegpagina's a.u.b. handmatig.",
+"movedto"  => "verplaatst naar",
+"movetalk"  => "Verplaats \"Overleg\" pagina ook indien aanwezig.",
+"talkpagemoved" => "De bijhorende overlegpagina is ook verplaatst.",
+"talkpagenotmoved" => "De bijhorende overlegpagina is <strong>niet</strong> verplaatst.",
+
+);
+
+class LanguageNl extends Language {
+
+ function getDefaultUserOptions () {
+  global $wgDefaultUserOptionsNl ;
+  return $wgDefaultUserOptionsNl ;
+  }
+
+ function getBookstoreList () {
+  global $wgBookstoreListEn ; # No locals defined... yet
+  return $wgBookstoreListEn ;
+ }
+
+ function getNamespaces() {
+  global $wgNamespaceNamesNl;
+  return $wgNamespaceNamesNl;
+ }
+
+ function getNsText( $index ) {
+  global $wgNamespaceNamesNl;
+  return $wgNamespaceNamesNl[$index];
+ }
+
+ function getNsIndex( $text ) {
+  global $wgNamespaceNamesNl;
+
+  foreach ( $wgNamespaceNamesNl as $i => $n ) {
+   if ( 0 == strcasecmp( $n, $text ) ) { return $i; }
+  }
+  return false;
+ }
+
+ # Inherit specialPage()
+
+ function getQuickbarSettings() {
+  global $wgQuickbarSettingsNl;
+  return $wgQuickbarSettingsNl;
+ }
+
+ function getSkinNames() {
+  global $wgSkinNamesNl;
+  return $wgSkinNamesNl;
+ }
+
+ function getMathNames() {
+  global $wgMathNamesNl;
+  return $wgMathNamesNl;
+ }
+
+ function getUserToggles() {
+  global $wgUserTogglesNl;
+  return $wgUserTogglesNl;
+ }
+
+ function getLanguageNames() {
+  global $wgLanguageNamesNl;
+  return $wgLanguageNamesNl;
+ }
+
+ function getLanguageName( $code ) {
+  global $wgLanguageNamesNl;
+  if ( ! array_key_exists( $code, $wgLanguageNamesNl ) ) {
+   return "";
+  }
+  return $wgLanguageNamesNl[$code];
+ }
+
+ function getMonthName( $key )
+ {
+  global $wgMonthNamesNl;
+  return $wgMonthNamesNl[$key-1];
+ }
+
+ /* by default we just return base form; this should be ok for Nl */
+
+ function getMonthNameGen( $key )
+ {
+  global $wgMonthNamesNl;
+  return $wgMonthNamesNl[$key-1];
+ }
+
+ function getMonthAbbreviation( $key )
+ {
+  global $wgMonthAbbreviationsNl;
+
+  return $wgMonthAbbreviationsNl[$key-1];
+ }
+
+ function getWeekdayName( $key )
+ {
+  global $wgWeekdayNamesNl;
+  return $wgWeekdayNamesNl[$key-1];
+ }
+
+ # Inherit userAdjust()
+ function date( $ts, $adj = false )
+ {
+  if ( $adj ) { $ts = $this->userAdjust( $ts ); }
+
+  $d = (0 + substr( $ts, 6, 2 )) . " " .
+    $this->getMonthAbbreviation( substr( $ts, 4, 2 ) ) . " " . 
+    substr( $ts, 0, 4 );
+  return $d;
+ }
+
+ function time( $ts, $adj = false )
+ {
+  if ( $adj ) { $ts = $this->userAdjust( $ts ); }
+
+  $t = substr( $ts, 8, 2 ) . ":" . substr( $ts, 10, 2 );
+  return $t;
+ }
+
+ function timeanddate( $ts, $adj = false )
+ {
+  return $this->date( $ts, $adj ) . " " . $this->time( $ts, $adj );
+ }
+
+ function getValidSpecialPages()
+ {
+  global $wgValidSpecialPagesNl;
+  return $wgValidSpecialPagesNl;
+ }
+
+
+ function getSysopSpecialPages()
+ {
+  global $wgSysopSpecialPagesNl;
+  return $wgSysopSpecialPagesNl;
+ }
+
+ function getDeveloperSpecialPages()
+ {
+  global $wgDeveloperSpecialPagesNl;
+  return $wgDeveloperSpecialPagesNl;
+ }
+
+ function getMessage( $key )
+ {
+                global $wgAllMessagesNl, $wgAllMessagesEn;
+                $m = $wgAllMessagesNl[$key];
+
+                if ( "" == $m ) { return $wgAllMessagesEn[$key]; }
+                else return $m;
+ }
+
+ # Inherit iconv(), ucfirst(), stripForSearch(), recodeForEdit(), recodeInput()
+ # since they are same as English/Latin1
+
+}
+?>
diff --git a/languages/LanguagePl.php b/languages/LanguagePl.php
new file mode 100644 (file)
index 0000000..d1b1cf4
--- /dev/null
@@ -0,0 +1,1224 @@
+<?
+global $IP;
+include_once("$IP/Utf8Case.php");
+
+# NOTE: To turn off "Current Events" in the sidebar,
+# set "currentevents" => "-"
+
+# The names of the namespaces can be set here, but the numbers
+# are magical, so don't change or move them!  The Namespace class
+# encapsulates some of the magic-ness.
+#
+/* private */ $wgNamespaceNamesPl = array(
+       -1      => "Specjalna",
+       0       => "",
+       1       => "Dyskusja",
+       2       => "Wikipedysta",
+       3       => "Dyskusja_wikipedysty",
+       4       => "Wikipedia",
+       5       => "Dyskusja_Wikipedii",
+       6       => "Grafika",
+       7       => "Dyskusja_grafiki"
+);
+
+/* private */ $wgDefaultUserOptionsPl = array(
+       "quickbar" => 1, "underline" => 1, "hover" => 1,
+       "cols" => 80, "rows" => 25, "searchlimit" => 20,
+       "contextlines" => 5, "contextchars" => 50,
+       "skin" => 0, "math" => 1, "rcdays" => 3, "rclimit" => 50,
+       "highlightbroken" => 1, "stubthreshold" => 0
+);
+
+/* private */ $wgQuickbarSettingsPl = array(
+       "Brak", "Stały, z lewej", "Stały, z prawej", "Unoszący się, z lewej"
+);
+
+/* private */ $wgSkinNamesPl = array(
+       "Standard", "Nostalgia", "Cologne Blue"
+);
+
+/* private */ $wgMathNamesPl = array( 
+    "Zawsze jako PNG",
+       "HTML dla prostych, dla reszty PNG",
+       "Spróbuj HTML; jeśli zawiedzie, to PNG",
+       "Pozostaw w TeXu (tekst)",
+       "HTML, dla nowszych przeglądarek"
+); 
+
+/* private */ $wgUserTogglesPl = array(
+       "hover"         => "Pokazuj okienko podpowiedzi ponad linkami",
+       "underline" => "Podkreślenie linków",
+       "highlightbroken" => "<a href=\"\" class=\"new\">Podświetl</a> linki pustych stron (alternatywa: znak zapytania<a href=\"\" class=\"internal\">?</a>).",
+       "justify"       => "Wyrównuj tekst artykułu w kolumnie",
+       "hideminor" => "Ukryj drobne zmiany w \"Ostatnich zmianach\"",
+       "usenewrc" => "Konsolidacja ostatnich zmian (JavaScript)",
+       "numberheadings" => "Automatyczna numeracja nagłówków",
+       "rememberpassword" => "Pamiętaj hasło między sesjami",
+       "editwidth" => "Obszar edycji o pełnej szerokości",
+       "editondblclick" => "Podwójne kliknięcie rozpoczyna edycję (JavaScript)",
+       "watchdefault" => "Obserwuj nowe i zmodyfikowane artykuły",
+       "minordefault" => "Wszystkie zmiany zaznaczaj domyślnie jako drobne",
+       "previewontop" => "Pokazuj podgląd przed oknem edycji"
+);
+
+/* private */ $wgBookstoreListPl = array(
+       "AddALL" => "http://www.addall.com/New/Partner.cgi?query=$1&type=ISBN",
+       "PriceSCAN" => "http://www.pricescan.com/books/bookDetail.asp?isbn=$1",
+       "Barnes & Noble" => "http://shop.barnesandnoble.com/bookSearch/isbnInquiry.asp?isbn=$1",
+       "Amazon.com" => "http://www.amazon.com/exec/obidos/ISBN=$1"
+);
+
+/* private */ $wgLanguageNamesPl = array(
+       "ab"    => "abchaska",
+       "aa"    => "w afar",
+       "af"    => "w afrikaans",
+       "sq"    => "albańska",
+       "am"    => "amharska",
+       "ar"    => "arabska",
+       "hy"    => "armeńska",
+       "as"    => "asamska",
+       "ay"    => "w ajmara",
+       "az"    => "azerbejdżańska",
+       "ba"    => "baszkirska",
+       "eu"    => "baskijska",
+       "be"    => "białoruska",
+       "bn"    => "bengalska",
+       "dz"    => "w druk",
+       "bh"    => "biharska",
+       "bi"    => "w bislama",
+       "my"    => "birmańska",
+       "km"    => "kambodżańska",
+       "ca"    => "katalońska",
+       "zh"    => "chińska",
+       "co"    => "korsykańska",
+       "hr"    => "chorwacka",
+       "cs"    => "czeska",
+       "da"    => "duńska", # Note two different subdomains. 
+       "dk"    => "duńska", # 'da' is correct for the language.
+       "nl"    => "holenderska",
+       "en"    => "angielska",
+       "w"     => "angielska", # Should this be in list this?
+       "simple" => "uproszczona angielska",
+       "eo"    => "esperanto",
+       "et"    => "estońska",
+       "fo"    => "farerska",
+       "fj"    => "fidżyjska",
+       "fi"    => "fińska",
+       "fr"    => "francuska",
+       "fy"    => "fryzyjska",
+       "gl"    => "galicyjska",
+       "ka"    => "gruzińska",
+       "de"    => "niemiecka",
+       "el"    => "grecka",
+       "kl"    => "grenlandzka",
+       "gn"    => "w guarani",
+       "gu"    => "w gudżarati",
+       "ha"    => "w hausa",
+       "he"    => "hebrajska",
+       "hi"    => "w hindi",
+       "hu"    => "węgierska",
+       "is"    => "islandzka",
+       "id"    => "indonezyjska",
+       "ia"    => "w interlingua",
+       "iu"    => "w inuktitut",
+       "ik"    => "w inupiak",
+       "ga"    => "irlandzka",
+       "it"    => "włoska",
+       "ja"    => "japońska",
+       "jv"    => "jawajska",
+       "kn"    => "w kannada",
+       "ks"    => "kaszmirska",
+       "kk"    => "kazachska",
+       "rw"    => "w kinya-ruanda",
+       "ky"    => "kirgiska",
+       "rn"    => "w urundi",
+       "ko"    => "koreańska",
+       "lo"    => "laotańska",
+       "la"    => "łacińska",
+       "lv"    => "łotewska",
+       "ln"    => "w lingala",
+       "lt"    => "litewska",
+       "mk"    => "macedońska",
+       "mg"    => "malagaska",
+       "ms"    => "malajska",
+       "ml"    => "w malajalam",
+       "mi"    => "maoryjska",
+       "mr"    => "w marathi",
+       "mo"    => "mołdawska",
+       "mn"    => "mongolska",
+       "na"    => "w nauru",
+       "ne"    => "nepalska",
+       "no"    => "norweska",
+       "oc"    => "prowansalska",
+       "or"    => "w orija",
+       "om"    => "w oromo",
+       "ps"    => "w paszto",
+       "fa"    => "perska",
+       "pl"    => "polska",
+       "pt"    => "portugalska",
+       "pa"    => "pendżabska",
+       "qu"    => "w keczua",
+       "rm"    => "retoromańska",
+       "ro"    => "rumuńska",
+       "ru"    => "rosyjska",
+       "sm"    => "samoańska",
+       "sg"    => "w sangro",  //??
+       "sa"    => "w sanskrycie",
+       "sr"    => "serbska",
+       "sh"    => "serbochorwacka",
+       "st"    => "w sotho",
+       "tn"    => "w setswana",
+       "sn"    => "w szona",
+       "sd"    => "w sindhi",
+       "si"    => "syngaleska",
+       "ss"    => "w suazi",
+       "sk"    => "słowacka",
+       "sl"    => "słoweńska",
+       "so"    => "w somali",
+       "es"    => "hiszpańska",
+       "su"    => "arabska (sudańska)",
+       "sw"    => "w suahili",
+       "sv"    => "szwedzka",
+       "tl"    => "w tagalog",
+       "tg"    => "tadżycka",
+       "ta"    => "tamilska",
+       "tt"    => "tatarska",
+       "te"    => "w telugu",
+       "th"    => "tajska",
+       "bo"    => "tybetańska",
+       "ti"    => "w tigrinia",
+       "to"    => "w tonga",
+       "ts"    => "w tsonga",
+       "tr"    => "turecka",
+       "tk"    => "turkmeńska",
+       "tw"    => "w twi",
+       "ug"    => "ujgurska",
+       "uk"    => "ukraińska",
+       "ur"    => "w urdu",
+       "uz"    => "uzbecka",
+       "vi"    => "wietnamska",
+       "vo"    => "w volapuk",
+       "cy"    => "walijska",
+       "wo"    => "w wolof",
+       "xh"    => "w xhosa",
+       "yi"    => "w jidisz",
+       "yo"    => "w joruba",
+       "za"    => "w zhuang",
+       "zu"    => "w zulu"
+);
+
+/* private */ $wgWeekdayNamesPl = array(
+       "niedziela", "poniedziałek", "wtorek", "środa", "czwartek",
+       "piątek", "sobota"
+);
+
+/* private */ $wgMonthNamesPl = array(
+       "styczeń", "luty", "marzec", "kwiecień", "maj", "czerwiec",
+       "lipiec", "sierpień", "wrzesień", "październik", "listopad",
+       "grudzień"
+);
+
+/* private */ $wgMonthNamesGenPl = array(
+       "stycznia", "lutego", "marca", "kwietnia", "maja", "czerwca",
+       "lipca", "sierpnia", "wrzeĹ\9bnia", "paĹşdziernika", "listopada",
+       "grudnia"
+);
+
+/* private */ $wgMonthAbbreviationsPl = array(
+       "sty", "lut", "mar", "kwi", "maj", "cze", "lip", "sie",
+       "wrz", "paź", "lis", "gru"
+);
+
+# All special pages have to be listed here: a description of ""
+# will make them not show up on the "Special Pages" page, which
+# is the right thing for some of them (such as the "targeted" ones).
+#
+/* private */ $wgValidSpecialPagesPl = array(
+       "Userlogin"             => "",
+       "Userlogout"    => "",
+       "Preferences"   => "Zmiana moich preferencji",
+       "Watchlist"             => "Obserwowane",
+       "Recentchanges" => "Ostatnio zmienione",
+       "Upload"                => "Przesyłanie plików",
+       "Imagelist"             => "Lista obrazków i multimediów",
+       "Listusers"             => "Zarejestrowani użytkownicy",
+       "Statistics"    => "Statystyka",
+       "Randompage"    => "Losowa strona",
+
+       "Lonelypages"   => "Porzucone artykuły",
+       "Unusedimages"  => "Porzucone pliki",
+       "Popularpages"  => "Najpopularniejsze",
+       "Wantedpages"   => "Najbardziej potrzebne",
+       "Shortpages"    => "Najkrótsze",
+       "Longpages"             => "Najdłuższe",
+       "Newpages"              => "Nowoutworzone",
+       "Allpages"              => "Wszystkie",
+
+       "Ipblocklist"   => "Zablokowane adresy IP",
+       "Maintenance"   => "Prosta administracja",
+       "Specialpages"  => "",
+       "Contributions" => "",
+       "Emailuser"             => "",
+       "Whatlinkshere" => "",
+       "Recentchangeslinked" => "",
+       "Movepage"              => "",
+       "Booksources"   => "Książki"
+);
+
+/* private */ $wgSysopSpecialPagesPl = array(
+       "Blockip"               => "Zablokuj adres IP",
+       "Asksql"                => "Zapytanie SQL",
+       "Undelete"              => "Odtwarzanie skasowanych stron"
+
+);
+
+/* private */ $wgDeveloperSpecialPagesPl = array(
+       "Lockdb"                => "Zablokuj zapis do bazy danych",
+       "Unlockdb"              => "Odblokuj zapis do bazy danych",
+       "Debug"                 => "Odpluskwianie"
+);
+
+/* private */ $wgAllMessagesPl = array(
+
+# Bits of text used by many pages:
+#
+"linktrail"            => "/^([a-z]+)(.*)\$/sD",
+"mainpage"             => "Strona główna",
+"about"                        => "O Wikipedii",
+"aboutwikipedia" => "O Wikipedii",
+"aboutpage"            => "Wikipedia:O_Wikipedii",
+"help"                 => "Pomoc",
+"helppage"             => "Wikipedia:Pomoc",
+"wikititlesuffix" => "Wikipedia",
+"bugreports"   => "Raport o błędach",
+"bugreportspage" => "Wikipedia:Błędy",
+"faq"                  => "FAQ",
+"faqpage"              => "Wikipedia:FAQ",
+"edithelp"             => "Pomoc w edycji",
+"edithelppage" => "Wikipedia:Jak_edytować_stronę",
+"cancel"               => "Anuluj",
+"qbfind"               => "Znajdź",
+"qbbrowse"             => "Przeglądanie",
+"qbedit"               => "Edycja",
+"qbpageoptions" => "Opcje strony",
+"qbpageinfo"   => "O stronie",
+"qbmyoptions"  => "Moje opcje",
+"mypage"               => "Moja strona",
+"mytalk"               => "Moja dyskusja",
+"currentevents" => "Bieżące wydarzenia",
+"errorpagetitle" => "Błąd",
+"returnto"             => "Wróć do strony: $1.",
+"fromwikipedia"        => "Z Wikipedii, wolnej encyklopedii.",
+"whatlinkshere"        => "Strony, które odwołują się do tej",
+"help"                 => "Pomoc",
+"search"               => "Szukaj",
+"go"            => "OK",
+"history"              => "Historia strony",
+"printableversion" => "Wersja do druku",
+"editthispage" => "Edytuj",
+"deletethispage" => "Usuń",
+"protectthispage" => "Zabezpiecz",
+"unprotectthispage" => "Odbezpiecz",
+"newpage" => "Nowa strona",
+"talkpage"             => "Dyskusja",
+"subjectpage"  => "Strona dyskutowana", # for compatibility
+"articlepage"   => "Strona dyskutowana", 
+"userpage" => "Strona wikipedysty", 
+"wikipediapage" => "Strona dyskutowana", 
+"imagepage" =>  "Strona grafiki", 
+"viewtalkpage" => "Strona dyskusji",
+"otherlanguages" => "Wersja",
+"redirectedfrom" => "(Przekierowano z $1)",
+"lastmodified" => "ostatnio zmodyfikowano o $1;",
+"viewcount"            => "Tę stronę obejrzano $1 razy;",
+"gnunote" => "udostępniana jest w oparciu o licencję <a class=internal href='/wiki/GNU_FDL'>GNU FDL</a>.",
+"printsubtitle" => "(z http://pl.wikipedia.org)",
+"protectedpage" => "Strona zabezpieczona",
+"administrators" => "Wikipedia:Administratorzy",
+"sysoptitle"   => "Wymagane prawa dostępu administratora",
+"sysoptext"            => "Ta operacja może być wykonana tylko przez
+użytkowania o statusie \"administrator\".
+Zobacz $1.",
+"developertitle" => "Wymagane prawa dostępu Programisty",
+"developertext"        => "Ta operacja może być wykonana tylko przez
+użytkownika o prawach \"Programisty\".
+Zobacz $1.",
+"nbytes"               => "$1 bajtów",
+"go"                   => "OK",
+"ok"                   => "OK",
+"sitetitle"            => "Wikipedia",
+"sitesubtitle" => "Wolna Encyklopedia",
+"retrievedfrom" => "Źródło: \"$1\"",
+"newmessages"   => "Masz $1.",
+"newmessageslink" => "Nowe wiadomości",
+
+# Main script and global functions
+#
+"nosuchaction" => "Nie ma takiej operacji",
+"nosuchactiontext" => "Oprogramowanie Wikipedii nie rozpoznaje
+operacji takiej jak podana w URL",
+"nosuchspecialpage" => "Nie ma takiej strony specjalnej",
+"nospecialpagetext" => "Oprogramowanie Wikipedii nie rozpozaje takiej
+specjalnej strony.",
+
+# General errors
+#
+"error"                        => "Błąd",
+"databaseerror" => "Błąd bazy danych",
+"dberrortext"  => "Wystąpił błąd składni w zapytaniu do bazy danych.
+Mogło to być spowodowane przez złe sformułowanie zapytania (zobacz $5)
+albo przez błąd w oprogramowaniu.
+Ostatnie, nieudane zapytanie to:
+<blockquote><tt>$1</tt></blockquote>
+wysłane przez funkcję \"<tt>$2</tt>\".
+MySQL zgłosił błąd \"<tt>$3: $4</tt>\".",
+"noconnect"            => "Poprzez $1 nie można połączyc się z systemem zarządzającym bazą danych",
+"nodb"                 => "Nie można odnaleźć bazy danych $1",
+"readonly"             => "Baza danych jest zablokowana",
+"enterlockreason" => "Podaj powód zablokowania bazy oraz szacunkowy czas
+jej odblokowania",
+"readonlytext" => "Baza danych Wikipedii jest w tej chwili zablokowana
+- nie można wprowadzać nowych artykułów ani modyfikować istniejących. Powodem
+są prawdopodobnie czynności administracyjne. Po ich zakończeniu przywrócona
+zostanie pełna funkcjonalność bazy.
+Administrator, który zablokował bazę, podał następujące wyjaśnienie:
+<p>$1",
+"missingarticle" => "System bazy danych nie odnalazł tekstu strony,
+która powinna się znajdować w bazie, tzn. strony \"$1\".
+Nie jest to błąd bazy danych, ale najprawdopodobniej błąd w oprogramowaniu.
+Zgłoś, proszę, ten fakt administratorowi podając także, o który URL chodzi.",
+"internalerror" => "Błąd wewnętrzny",
+"filecopyerror" => "Nie można skopiowac pliku \"$1\" do \"$2\".",
+"filerenameerror" => "Nie można zmienić nazwy pliku \"$1\" na \"$2\".",
+"filedeleteerror" => "Nie można skasować pliku \"$1\".",
+"filenotfound" => "Nie można znaleźć pliku \"$1\".",
+"unexpected"   => "Niespodziewana wartość: \"$1\"=\"$2\".",
+"formerror"            => "Błąd: nie można wysłać formularza",    
+"badarticleerror" => "Dla tej strony ta operacja nie może być wykonana.",
+"cannotdelete" => "Nie można skasować podanej strony lub obrazka.",
+"badtitle"             => "Niepoprawny tytuł",
+"badtitletext" => "Podano niepoprawny tytuł strony. Prawdopodobnie zawiera
+zabronione znaki lub jest pusty.",
+"perfdisabled" => "Przepraszamy! By odciążyć serwer, wykonanie tej czynności
+zostało w okresie szczytu tymczasowo uniemożliwione. Wróć, proszę,
+i spróbuj jeszcze raz między 02:00 a 14:00 czasu UTC.",
+
+# Login and logout pages
+#
+"logouttitle"  => "Wylogowanie użytkownika",
+"logouttext"   => "Wylogowano Cię.
+Możesz kontynuować pracę z Wikipedią jako niezarejestrowany użytkownik
+albo zalogować się ponownie jako ten sam lub inny użytkownik.\n",
+
+"welcomecreation" => "<h2>Witaj, $1!</h2><p>Właśnie utworzyliśmy dla Ciebie konto.
+Nie zapomnij dostosować <i>preferencji</i>.",
+
+"loginpagetitle" => "User login",
+"yourname"             => "Twój login",
+"yourpassword" => "Twoje hasło",
+"yourpasswordagain" => "Powtórz hasło",
+"newusersonly" => " (tylko nowi użytkownicy)",
+"remembermypassword" => "Pamiętaj moje hasło między sesjami.",
+"loginproblem" => "<b>Są problemy z Twoim logowaniem.</b><br>Spróbuj ponownie!",
+"alreadyloggedin" => "<font color=red><b>$1, jesteś już zalogowany!</b></font><br>\n",
+
+"areyounew"            => "Jeśli jesteś po raz pierwszy na Wikipedii i chcesz mieć
+własne konto użytkownika, wprowadź swój pseudonim (login), a następnie wpisz
+dwukrotnie wybrane hasło. Podanie adresu e-mailowego jest opcjonalne - jeśli
+zapomnisz hasła możesz poprosić o przesłanie go na ów adres.<br>\n",
+
+"login"                        => "Zaloguj mnie",
+"userlogin"            => "Logowanie",
+"logout"               => "Wyloguj mnie",
+"userlogout"   => "Wylogowanie",
+"createaccount"        => "Załóż nowe konto",
+"badretype"            => "Wprowadzone hasła różnią się między soba.",
+"userexists"   => "Wybrana przez Ciebie nazwa użytkownika jest już zajęta. Wybierz, proszę, inną.",
+"youremail"            => "Twój e-mail",
+"yournick"             => "Twój podpis",
+"emailforlost" => "Jeśli zapomnisz hasła, możesz poprosić o przesłanie nowego na adres podany w Twoich preferencjach.",
+"loginerror"   => "Błąd logowania",
+"noname"               => "To nie jest poprawna nazwa użytkownika.",
+"loginsuccesstitle" => "Udane logowanie",
+"loginsuccess" => "Zalogowano Cię do Wikipedii jako \"$1\".",
+"nosuchuser"   => "Nie ma użytkowniku nazywającego się \"$1\".
+Sprawdź pisownię lub użyj poniższego formularza by utworzyć nowe konto.",
+"wrongpassword"        => "Podane przez Ciebie hasło jest nieprawidłowe. Spróbuj jeszcze raz.",
+"mailmypassword" => "Wyślij mi nowe hasło",
+"passwordremindertitle" => "Wikipedia przypomina o haśle",
+"passwordremindertext" => "Ktoś (prawdopodobnie Ty, spod adresu $1)
+poprosił od nas o wysłanie nowego hasła dostępu do Wikipedii.
+Aktualne hasło dla użytkownika \"$2\" to \"$3\". 
+Najlepiej będzie jak zalogujesz się teraz i od razu zmienisz hasło.",
+"noemail"              => "W bazie nie ma adresu e-mailowego dla użytkownika \"$1\".",
+"passwordsent" => "Nowe hasło zostało wysłane na adres e-mailowy użytkownika \"$1\"
+Po otrzymaniu go zaloguj się ponownie.",
+
+# Edit pages
+#
+"summary"              => "Opis zmian",
+"minoredit"            => "To jest drobna zmiana.",
+"watchthis"            => "Obserwuj",
+"savearticle"  => "Zapisz",
+"preview"              => "Podgląd",
+"showpreview"  => "Podgląd",
+"blockedtitle" => "Użytkownik jest zablokowany",
+"blockedtext"  => "Twoje konto lub adres IP zostały zablokowane przez $1.
+Podany powód to:<br>$2<p>. Możesz się skontaktować z $1 lub innym
+[[Wikipedia:Administratorzy|administratorem]] by wyjaśnić sprawę zablokowania.",
+"newarticle"   => "(Nowy)",
+"newarticletext" => "Nie ma jeszcze artykułu o tym tytule. W poniższym polu można wpisać pierwszy jego fragment. Jeśli nie to było Twoim zamiarem, wciśnij po prostu ''Wstecz''.",
+"anontalkpagetext" => "---- ''To jest strona dyskusyjna dla użytkowników
+anonimowych - takich, którzy nie mają jeszcze swojego konta na Wikipedii lub
+nie chcą go w tej chwili używać. By ich identyfikować używamy [[IP|numerów IP]].
+Jeśli jesteś anonimowym użytkownikiem i wydaje Ci się, że zamieszczone tu komentarze
+nie są skierowane do Ciebie, [[Specjalna:Userlogin|utwórz proszę konto i/albo zaloguj się]]
+- dzięki temu unikniesz w przyszłości podobnych nieporozumień.'' ",
+"noarticletext" => "(Nie ma jeszcze artykułu o tym tytule. Wybierz ''Edytuj'' by go rozpocząć.)",
+"updated"              => "(Zmodyfikowano)",
+"note"                 => "<strong>Uwaga:</strong> ",
+"previewnote"  => "To jest tylko podgląd - artykuł nie został jeszcze zapisany!",
+"previewconflict" => "Wersja podglądana odnosi się do tekstu
+z górnego pola edycji. Tak będzie wyglądać strona jeśli zdecydujesz się ją zapisać.",
+"editing"              => "Edytujesz \"$1\"",
+"editconflict" => "Konflikt edycji: $1",
+"explainconflict" => "Ktoś zdążył wprowadzić swoją wersję artykułu
+w trakcie Twojej edycji.
+Górne pole edycji zawiera tekst strony aktualnie zapisany w bazie danych.
+Twoje zmiany znajdują się w dolnym polu edycji.
+By wprowadzić swoje zmiany musisz zmodyfikować tekst z górnego pola.
+<b>Tylko</b> tekst z górnego pola będzie zapisany w bazie gdy wciśniesz
+\"Zapisz\".\n<p>",
+"yourtext"             => "Twój tekst",
+"storedversion" => "Zapisana wersja",
+"editingold"   => "<font color=\"red\"><strong>OSTRZEŻENIE: Edytujesz inną niż bieżąca wersję tej strony.
+Jeśli zapiszesz ją wszystkie późniejsze wersje zostaną skasowane.</strong></font>\n",
+"yourdiff"             => "Różnice",
+"copyrightwarning" => "Proszę pamiętać o tym, że przyjmuje się, iż wszelki
+wkład do Wikipedii jest udostępniany na zasadach <i>GNU Free Documentation License</i>
+(szczegóły w $1).  <br>Jeśli nie chcesz, żeby
+Twój tekst był bezlitośnie edytowany i rozpowszechniany bez ograniczeń,
+nie umieszczaj go w Wikipedii.
+Niniejszym jednocześnie oświadczasz, że ten tekst jest Twoim
+dziełem lub pochodzi z materiałów dostępnych na zasadach <i>public domain</i> albo
+licencji <i>GNU Free Documentation License</i> lub kompatybilnej.
+<br><strong>PROSZĘ NIE UŻYWAĆ BEZ POZWOLENIA MATERIAŁÓW OBJĘTYCH PRAWEM
+AUTORSKIM!</strong>",
+"longpagewarning" => "UWAGA: Ta strona ma $1 kilobajt-y/-ów; w przypadku niektórych
+przeglądarek mogą wystąpić problemy w edycji stron mających więcej niż 32 kilobajty.
+Jeśli to możliwe, spróbuj podzielić tekst na mniejsze części.",
+
+
+# History pages
+#
+"revhistory"   => "Historia modyfikacji",
+"nohistory"            => "Ta strona nie ma swojej historii edycji.",
+"revnotfound"  => "Wersja nie została odnaleziona",
+"revnotfoundtext" => "Ta (starsza) wersja strony nie może zostać odnaleziona.
+Sprawdź proszę URL użyty przez Ciebie by uzyskać dostęp do tej strony.\n",
+"loadhist"             => "Pobieranie historii tej strony",
+"currentrev"   => "Aktualna wersja",
+"revisionasof" => "Wersja z dnia $1",
+"cur"                  => "bież",
+"next"                 => "następna",
+"last"                 => "poprz",
+"orig"                 => "oryginał",
+"histlegend"   => "Legenda: (bież) = różnice z wersją bieżącą,
+(poprz) = różnice z wersją poprzedzającą, M = drobne zmiany",
+
+# Diffs
+#
+"difference"   => "(Różnice między wersjami)",
+"loadingrev"   => "pobieranie wersji w celu porównania",
+"lineno"               => "Linia $1:",
+"editcurrent"  => "Edytuj bieżącą wersję tej strony",
+
+# Search results
+#
+"searchresults" => "Wyniki wyszukiwania",
+"searchhelppage" => "Wikipedia:Przeszukiwanie",
+"searchingwikipedia" => "Przeszukiwanie Wikipedii",
+"searchresulttext" => "Aby dowiedzieć się więcej o przeszukiwaniu Wikipedii, zobacz $1.",
+"searchquery"  => "Dla zapytania \"$1\"",
+"badquery"             => "Źle sformułowane zapytanie",
+"badquerytext" => "Nie można zrealizować Twojego zapytania.
+Prawdopodobna przyczyna to obecność słowa krótszego niż trzyliterowe.
+Spróbuj, proszę, innego zapytania.",
+"matchtotals"  => "Zapytanie \"$1\", liczba znalezionych tytułów: $2,
+liczba znalezionych artykułów: $3.",
+"nogomatch" => "Nie istnieją strony o dokładnie takim tytule. Spróbuj pełnego przeszukiwania. ",
+"titlematches" => "Znaleziono w tytułach:",
+"notitlematches" => "Nie znaleziono w tytułach",
+"textmatches"  => "Znaleziono w artykułach:",
+"notextmatches"        => "Nie znaleziono w artykułach",
+"prevn"                        => "poprzednie $1",
+"nextn"                        => "następne $1",
+"viewprevnext" => "Zobacz ($1) ($2) ($3).",
+"showingresults" => "Oto lista <b>$1</b> pozycji, poczynając od numeru <b>$2</b>.",
+"nonefound"            => "<strong>Uwaga</strong>: brak rezultatów wyszukiwania
+spowodowany jest bardzo często szukaniem najpopularniejszych słów, takich jak
+\"jest\" czy \"nie\", które nie są indeksowane, albo z powodu podania w
+zapytaniu więcej niż jednego słowa (na liście odnalezionych stron znajdą się
+tylko te, które zawierają wszystkie podane słowa).",
+"powersearch" => "Szukaj", 
+"powersearchtext" => "
+Szukaj w przestrzeniach nazw :<br>
+$1<br>
+$2 Pokaż przekierowania &nbsp; Szukany tekst $3 $9",
+
+
+# Preferences page
+#
+"preferences"  => "Preferencje",
+"prefsnologin" => "Brak logowania",
+"prefsnologintext"     => "Musisz się <a href=\"" .
+  wfLocalUrl( "Specjalna:Userlogin" ) . "\">zalogować</a>
+przez zmianą swoich preferencji.",
+"prefslogintext" => "Zalogowano Cię jako \"$1\".
+Twój numer identyfikacyjny to $2.",
+"prefsreset"   => "Preferencje domyślne zostały odtworzone.",
+"qbsettings"   => "Pasek szybkiego dostępu", 
+"changepassword" => "Zmiana hasła",
+"skin"                 => "Skórka",
+"math"                  => "Prezentacja wzorów matematycznych", 
+"math_failure"          => "Parser nie umiał rozpoznać", 
+"math_unknown_error"    => "nieznany błąd", 
+"math_unknown_function" => "nieznana funkcja ", 
+"math_lexing_error"     => "błąd leksera", 
+"math_syntax_error"     => "błąd składni", 
+"saveprefs"            => "Zapisz preferencje",
+"resetprefs"   => "Preferencje domyślne",
+"oldpassword"  => "Stare hasło",
+"newpassword"  => "Nowe hasło",
+"retypenew"            => "Powtórz nowe hasło",
+"textboxsize"  => "Wymiary pola edycji",
+"rows"                 => "Wiersze",
+"columns"              => "Kolumny",
+"searchresultshead" => "Ustawienia wyszukiwarki",
+"resultsperpage" => "Liczba wyników na stronie",
+"contextlines" => "Pierwsze wiersze artykułu",
+"contextchars" => "Litery kontekstu w linijce",
+"stubthreshold"  => "Maksymalny rozmiar artykułu prowizorycznego",
+"recentchangescount" => "Liczba pozycji na liście ostatnich zmian",
+"savedprefs"   => "Twoje preferencje zostały zapisane.",
+"timezonetext" => "Podaj liczbę godzin różnicy między Twoim czasem,
+a czasem uniwersalnym (UTC). Np. dla Polski jest to liczba \"2\" (czas letni)
+lub \"1\" (czas zimowy).",
+"localtime"    => "Twój czas",
+"timezoneoffset" => "Różnica",
+"emailflag"            => "Nie chcę otrzymywać e-maili od innych użytkowników",
+
+# Recent changes
+#
+"changes" => "zmian-a/-y",
+"recentchanges" => "Ostatnie zmiany",
+"recentchangestext" => "Na tej stronie odnajdziesz historię ostatnich zmian na Wikipedii.
+
+[[Wikipedia:Powitanie nowicjuszy|Witaj]]! Jeśli jesteś tu po raz pierwszy,
+zapoznaj się, proszę, z tymi stronami: [[wikipedia:FAQ|Wikipedia FAQ]],
+[[Wikipedia:Zasady i wskazówki|polityka Wikipedii]]
+(a zwłaszcza [[Wikipedia:Nazewnictwo|konwencje nazywania stron]],
+[[Wikipedia:Neutralny punkt widzenia|neutralny punkt widzenia]])
+oraz [[Wikipedia:Najczęstsze nieporozumienia|najczęstsze nieporozumienia]].
+
+Jeśli chcesz przyczynić się do sukcesu Wikipedii, nie dodawaj materiałów
+zastrzeżonych prawami autorskimi. Konsekwencje prawne złamania tej zasady
+mogłyby Wikipedii bardzo zaszkodzić.
+Zobacz także [http://meta.wikipedia.org/wiki/Special:Recentchanges ostatnie metadyskusje].",
+"rcloaderr"            => "Ładuję ostatnie zmiany",
+"rcnote"               => "To ostatnie <strong>$1</strong> zmian dokonanych na Wikipedii w ciągu ostatnich <strong>$2</strong> dni.",
+"rcnotefrom"   => "Poniżej pokazano zmiany dokonane po <b>$2</b> (nie więcej niż <b>$1</b> pozycji).",
+"rclistfrom"   => "Pokaż nowe zmiany począwszy od $1",
+"rclinks"              => "Wyświetl ostatnie $1 zmian w ciągu ostatnich $2 dni.",
+"rchide"               => "in $4 form; $1 drobnych zmian; $2 innych przestrzeni nazw; $3 wielokrotnych edycji.",
+"diff"                 => "różn",
+"hist"                 => "hist",
+"hide"                 => "schowaj",
+"show"                 => "pokaż",
+"tableform"            => "tabelka",
+"listform"             => "lista",
+"nchanges"             => "$1 zmian",
+"minoreditletter" => "M",
+"newpageletter" => "N",
+
+# Upload
+#
+"upload"               => "Prześlij plik",
+"uploadbtn"            => "Prześlij plik",
+"uploadlink"   => "Prześlij obrazki",
+"reupload"             => "Prześlij ponownie",
+"reuploaddesc" => "Wróć do formularza wysyłki.",
+"uploadnologin" => "Brak logowania",
+"uploadnologintext"    => "Musisz się <a href=\"" .
+  wfLocalUrl( "Specjalna:Userlogin" ) . "\">zalogować</a>
+przed przesłaniem pików.",
+"uploadfile"   => "Prześlij plik",
+"uploaderror"  => "Błąd przesyłki",
+"uploadtext"   => "<strong>STOP!</strong> Zanim prześlesz plik,
+przeczytaj <a href=\"" . wfLocalUrlE( "Wikipedia:Zasady_dołączania_plików" ) .
+"\">zasady dołączania plików</a> i upewnij się, że przesyłając pozostaniesz z
+nimi w zgodzie.
+<p>Jeśli chcesz przejrzeć lub przeszukać dotychczas przesłane pliki,
+przejdź do <a href=\"" . wfLocalUrlE( "Specjalna:Imagelist" ) .
+"\">listy dołączonych plików</a>.
+Wszystkie przesyłki i skasowania są odnotowane na
+specjalnych wykazach (<a href=\"" .  wfLocalUrlE( "Wikipedia:Dołączone" ) .
+"\">dołączone</a>, <a href=\"" . wfLocalUrlE( "Wikipedia:Usunięte" ) .
+"\">usunięte</a>).
+<p>By przesłać nowy plik mający zilustrować Twój artykuł skorzystaj
+z poniższego formularza.
+W przypadku większości przeglądarek zobaczysz przycisk <i>Browse...</i>
+albo <i>Przeglądaj...</i>, który umożliwi Ci otworzenie standardowego
+okienka wyboru pliku. Wybranie pliku spowoduje umieszczenie jego nazwy
+w polu tekstowym obok przycisku.
+Musisz także zaznaczając odpowiednie pole, potwierdzić, że przesyłając
+plik nie naruszasz niczyich praw autorskich.
+Przesyłka rozpocznie się po naciśnięciu <i>Prześlij plik</i>.
+Może zająć kilka chwil, zwłaszcza jeśli masz wolne połączenie z internetem.
+<p>Preferowane formaty to JPEG dla zdjęć fotograficznych, PNG dla rysunków
+i obrazków o charakterze ikon oraz OGG dla dźwięków.
+Aby uniknąć nieporozumień nadawaj plikom nazwy związane z zawartością.
+Aby umieścić obrazek w artykule, użyj linku w postaci
+<b>[[grafika:obrazek.jpg]]</b> lub <b>[[grafika:obrazek.png|opcjonalny tekst]]</b>.
+Dla plików dźwiękowych link będzie miał postać <b>[[media:file.ogg]]</b>.
+<p>Pamiętaj, proszę, że tak jak w przypadku zwykłych stron Wikipedii,
+inni użytkownicy mogą edytować lub kasować przesłane przez Ciebie pliki,
+jeśli stwierdzą, że to będzie lepiej służyć całemu projektowi.
+Twoje prawo do przesyłania może zostać Ci odebrane, jeśli nadużyjesz systemu.",
+"uploadlog"            => "Wykaz przesyłek",
+"uploadlogpage" => "Dołączone",
+"uploadlogpagetext" => "Oto lista ostatnio przesłanych plików.
+Wszystkie czasy odnoszą się do strefy czasu uniwersalnego (UTC).
+<ul>
+</ul>
+",
+"filename"             => "Plik",
+"filedesc"             => "Opis",
+"affirmation"  => "Potwierdzam, że właściciel praw autorskich do tego pliku
+zgadza się udzielić licencji zgodnie z $1.",
+"copyrightpage" => "Wikipedia:Prawa_autorskie",
+"copyrightpagename" => "prawami autorskimi Wikipedii",
+"uploadedfiles"        => "Przesłane pliki",
+"noaffirmation" => "Musisz potwierdzić, że Twoja przesyłka nie narusza żadnych
+praw autorskich.",
+"ignorewarning"        => "Zignoruj ostrzeżenie i prześlij plik.",
+"minlength"            => "Nazwa obrazku musi mieć co najmniej trzy litery.",
+"badfilename"  => "Nazwę obrazku zmieniona na \"$1\".",
+"badfiletype"  => "\".$1\" nie jest zalecanym formatem pliku.",
+"largefile"            => "Zalecane jest aby rozmiar pliku z obrazkiem nie był większy niż 100 kilobajtów.",
+"successfulupload" => "Wysyłka powiodła się",
+"fileuploaded" => "Plik \"$1\" został pomyślnie przesłany.
+Przejdź, proszę, do strony opisu pliku ($2) i podaj dotyczące go informacje
+takie jak: pochodzenie pliku, kiedy i przez kogo został utworzony
+i cokolwiek co wiesz o pliku, a wydaje Ci się ważne.",
+"uploadwarning" => "Ostrzeżenie o przesyłce",
+"savefile"             => "Zapisz plik",
+"uploadedimage" => "przesłano \"$1\"",
+
+# Image list
+#
+"imagelist"            => "Lista plików",
+"imagelisttext"        => "To jest lista $1 plików posortowanych $2.",
+"getimagelist" => "pobieranie listy plików",
+"ilshowmatch"  => "Pokaż wszystkie pliki o takiej samej nazwie",
+"ilsubmit"             => "Szukaj",
+"showlast"             => "Pokaż ostatnie $1 plików posortowane $2.",
+"all"                  => "wszystkie",
+"byname"               => "według nazwy",
+"bydate"               => "według daty",
+"bysize"               => "według rozmiaru",
+"imgdelete"            => "usuń",
+"imgdesc"              => "opisz",
+"imglegend"            => "Legenda: (opisz) = pokaż/edytuj opis pliku.",
+"imghistory"   => "Historia pliku",
+"revertimg"            => "przywróć",
+"deleteimg"            => "usuń",
+"imghistlegend" => "Legenda: (bież) = to jest obecny plik, (usuń) = usuń
+tę starszą wersję, (przywróć) = przywróć tę starszą wersję.
+<br><i>Kliknij na datę aby zobaczyć jakie pliki przesłano tego dnia</i>.",
+"imagelinks"   => "Linki do pliku",
+"linkstoimage" => "Oto strony odwołujące się do tego pliku:",
+"nolinkstoimage" => "Żadna strona nie odwołuje się do tego pliku.",
+
+# Statistics
+#
+"statistics"   => "Statystyka",
+"sitestats"            => "Statystyka artykułów",
+"userstats"            => "Statystyka użytkowników",
+"sitestatstext" => "W bazie danych jest w sumie <b>$1</b> stron.
+Ta liczba uwzględnia strony <i>Dyskusji</i>, strony na temat samej Wikipedii,
+strony typu <i>stub</i> (prowizoryczne), strony przekierowujące, oraz inne, które trudno
+uznać za artykuły. Wyłączając powyższe, jest prawdopodobnie <b>$2</b> stron, które można uznać
+za artykuły.<p>
+Było w sumie <b>$3</b> odwiedzin oraz <b>$4</b> edycji od kiedy dokonano
+upgrade'u oprogramowania (22 listopada 2002).
+Daje to średnio <b>$5</b> edycji na jedną stronę i <b>$6</b> odwiedzin na jedną edycję.",
+"userstatstext" => "Jest <b>$1</b> zarejestrowanych użytkowników.
+Spośród nich <b>$2</b> ma status administratora (zobacz $3).",
+
+# Maintenance Page
+#
+"maintenance"          => "Prosta administracja",
+"maintnancepagetext"   => "Na tej stronie zgrupowano kilka użytecznych narzędzi
+pomagających w prostej administracji. Niektóre z nich obciążają bazę danych, proszę
+więc, by ich nie nadużywać.",
+"maintenancebacklink"  => "Powrót do strony prostej administracji",
+"disambiguations"      => "Strony ujednoznaczniające",
+"disambiguationspage"  => "Wikipedia:Strony_ujednoznaczniające",
+"disambiguationstext"  => "Poniższe artykuły odwołują się do <i>stron
+ujednoznaczniających</i>, a powinny odwoływać się bezpośrednio do hasła
+związanego z treścią artykułu.<br>Strona uznawana jest za ujednoznaczniającą
+jeśli odwołuje się do niej $1.<br>Linki z innych przestrzeni nazw <i>nie</i>
+zostały tu uwzględnione.",
+"doubleredirects"      => "Podwójne przekierowania",
+"doubleredirectstext"  => "<b>Uwaga:</b> Na tej liście mogą znajdować się
+przekierowania pozorne. Oznacza to, że poniżej pierwszej linii artykułu,
+zawierającej \"#REDIRECT ...\", może znajdować się dodatkowy tekst.<br>Każdy
+wiersz listy zawiera odwołania do pierwszego i drugiego przekierowania oraz
+pierwszą linię tekstu drugiego przekierowania. Umożliwia to w większości
+przypadków odnalezienie właściwego artykułu, do którego powinno się
+przekierowywać.",
+"brokenredirects"      => "Zerwane przekierowania",
+"brokenredirectstext"  => "Poniższe przekierowania wskazują na nieistniejące artykuły.",
+"selflinks"            => "Strony zawierające odwołania do siebie samych",
+"selflinkstext"                => "Poniższe strony zawierają odnośniki do samych siebie
+(co nie powinno mieć miejsca).",
+"mispeelings"           => "Strony z błędami pisowni",
+"mispeelingstext"               => "Poniższe strony zawierają najczęstsze błędy
+pisowni (ich listę można znaleźć w $1). Poprawna pisownia może być podana obok w
+nawiasach.", 
+"mispeelingspage"       => "Lista najczęstszych błędów pisowni",
+"missinglanguagelinks"  => "Brakujące odnośniki do innych wersji językowych",
+"missinglanguagelinksbutton"    => "Znajdź brakujące odnośniki, wersja",
+"missinglanguagelinkstext"      => "Dla wielu artykułów istnieje wersja $1.
+Artykuły umieszczone na poniższej liście <i>nie</i> odnoszą się do swojego
+odpowiednika w tym języku. Na tej liście <i>pominięto</i> podstrony oraz przekierowania.",
+
+# Miscellaneous special pages
+#
+"orphans"              => "Porzucone strony",
+"lonelypages"  => "Porzucone strony",
+"unusedimages" => "Nie używane pliki",
+"popularpages" => "Najpopularniejsze strony",
+"nviews"               => "odwiedzono $1 razy",
+"wantedpages"  => "Najpotrzebniejsze strony",
+"nlinks"               => "$1 linków",
+"allpages"             => "Wszystkie strony",
+"randompage"   => "Losuj stronę",
+"shortpages"   => "Najkrótsze strony",
+"longpages"            => "Najdłuższe strony",
+"listusers"            => "Lista użytkowników",
+"specialpages" => "Strony specjalne",
+"spheading"            => "Strony specjalne",
+"sysopspheading" => "Strony specjalne tylko dla użytkowników z prawami Administratora",
+"developerspheading" => "Strony specjalne tylko dla użytkowników z prawami Programisty",
+"protectpage"  => "Zabezpiecz stronę",
+"recentchangeslinked" => "Dolinkowane",
+"rclsub"               => "(dla stron dolinkowanych do \"$1\")",
+"debug"                        => "Odpluskwianie",
+"newpages"             => "Nowe strony",
+"movethispage" => "Przenieś",
+"unusedimagestext" => "<p>Pamiętaj, proszę, że inne witryny,
+np. Wikipedie w innych językach, mogą odwoływać się do tych plików
+używając bezpośrednio URL. Dlatego też niektóre z plików mogą się znajdować
+na tej liście mimo, że żadna strona tej Wikipedii nie odwołuje się do nich.",
+"booksources"  => "Książki",
+"booksourcetext" => "Oto lista linków do innych witryn,
+które pośredniczą w sprzedaży nowych i używanych książek i mogą podać
+informacje o książkach, których szukasz.
+Wikipedia nie jest stowarzyszona z żadnym ze sprzedawców,
+a ta lista nie powinna być interpretowana jako świadectwo udziału w zyskach.",
+
+# Email this user
+#
+"mailnologin"  => "Brak adresu",
+"mailnologintext" => "Musisz się <a href=\"" .
+  wfLocalUrl( "Specjalna:Userlogin" ) . "\">zalogować</a>
+i mieć wpisany aktualny adres e-mailowy w swoich <a href=\"" .
+  wfLocalUrl( "Specjalna:Preferencje" ) . "\">preferencjach</a>,
+aby móc wysłać e-mail do innych użytkowaników.",
+"emailuser"            => "Wyślij e-mail do tego użytkownika",
+"emailpage"            => "Wyślij e-mail do użytkownika",
+"emailpagetext"        => "Jeśli ten użytkownik wpisał poprawny adres e-mailowy
+w swoich preferencjach, to poniższy formularz umożliwi Ci wysłanie jednej wiadomości.
+Adres e-mailowy, który został przez Ciebie wprowadzony w Twoich preferencjach
+pojawi się w polu \"Od\"; dzięki temu odbiorca będzie mógł Ci odpowiedzieć.",
+"noemailtitle" => "Brak adresu e-mailowego",
+"noemailtext"  => "Ten użytkownik nie podał poprawnego adresu e-mailowego,
+albo zadecydował, że nie chce otrzymywać e-maili od innych użytkowników.",
+"emailfrom"            => "Od",
+"emailto"              => "Do",
+"emailsubject" => "Temat",
+"emailmessage" => "Wiadomość",
+"emailsend"            => "Wyślij",
+"emailsent"            => "Wiadomość została wsyłana",
+"emailsenttext" => "Twoja wiadomość została wysłana.",
+
+# Watchlist
+#
+"watchlist"            => "Obserwowane",
+"watchlistsub" => "(dla użytkownika \"$1\")",
+"nowatchlist"  => "Nie ma żadnych pozycji na liście obserwowanych przez Ciebie stron.",
+"watchnologin" => "Brak logowania",
+"watchnologintext"     => "Musisz się <a href=\"" .
+  wfLocalUrl( "Specjalna:Userlogin" ) . "\">zalogować</a>
+przed modyfikacją listy obserwowanych artykułów.",
+"addedwatch"   => "Dodana do listy obserwowanych",
+"addedwatchtext" => "Strona \"$1\" została dodana do Twojej <a href=\"" .
+  wfLocalUrl( "Specjalna:Watchlist" ) . "\">listy obserwowanych</a>.
+Na tej liście znajdzie się rejestr przyszłych zmian tej strony i stowarzyszonej z nią strony Dyskusji,
+a nazwa samej strony zostanie <b>wytłuszczona</b> na <a href=\"" .
+  wfLocalUrl( "Specjalna:Recentchanges" ) . "\">liście ostatnich zmian</a> aby
+łatwiej było Ci sam fakt zmiany zauważyć.</p>
+
+<p>Jeśli chcesz usunąć stronę ze swojej listy obserwowanych, kliknij na
+\"Przestań obserwować\".",
+"removedwatch" => "Usunięto z listy obserwowanych",
+"removedwatchtext" => "Strona \"$1\" została usunięta z Twojej listy obserwowanych.",
+"watchthispage"        => "Obserwuj",
+"unwatchthispage" => "Przestań obserwować",
+"notanarticle" => "To nie artykuł",
+
+# Delete/protect/revert
+#
+"deletepage"   => "Usuń stronę",
+"confirm"              => "Potwierdź",
+"confirmdelete" => "Potwierdź usunięcie",
+"deletesub"            => "(Usuwanie \"$1\")",
+"confirmdeletetext" => "Zamierzasz trwale usunąć stronę
+lub plik z bazy danych razem z dotyczącą ich historią.
+Potwierdź, proszę, swoje zamiary, tzn., że rozumiesz konsekwencje,
+i że robisz to w zgodzie z
+[[Wikipedia:Zasady i wskazówki|zasadami Wikipedii]].",
+"confirmcheck" => "Tak, naprawdę chcę usunąć.",
+"actioncomplete" => "Operacja wykonana",
+"deletedtext"  => "Usunięto \"$1\".
+Rejestr ostatnio dokonanych kasowań możesz obejrzeć tutaj: $2.",
+"deletedarticle" => "usunięto \"$1\"",
+"dellogpage"   => "Usunięte",
+"dellogpagetext" => "To jest lista ostatnio wykonanych kasowań.
+Podane czasy odnoszą się do strefy czasu uniwersalnego (UTC).
+<ul>
+</ul>
+",
+"deletionlog"  => "rejestr usunięć",
+"reverted"             => "Przywrócono starszą wersję",
+"deletecomment"        => "Powód usunięcia",
+"imagereverted" => "Przywrócenie wcześniejszej wersji powiodło się.",
+"rollback"              => "Cofnij edycję", 
+"rollbacklink" => "cofnij",
+"cantrollback"  => "Nie można cofnąć edycji; jest tylko jedna wersja tego artykułu.",
+"revertpage"    => "Przywrócono przedostatnią wersję, jej autor to $1", 
+
+# Undelete
+#
+"undelete" => "Odtwórz skasowaną stronę",
+"undeletepage" => "Odtwarzanie skasowanych stron",
+"undeletepagetext" => "Poniższe strony zostały skasowane, ale ich kopia wciąż
+znajduje się w archiwum.<br><b>Uwaga:</b> archiwum co jakiś czas także jest kasowane!",
+"undeletearticle" => "Odtwórz skasowany artykuł",
+"undeleterevisions" => "Liczba zarchiwizowanych wersji: $1",
+"undeletehistory" => "Odtworzenie strony spowoduje przywrócenie także jej
+wszystkich poprzednich wersji. Jeśli od czasu skasowania ktoś utworzył nową stronę
+o tej nazwie, odtwarzane wersje znajdą się w jej historii, a obecna wersja
+pozostanie bez zmian.",
+"undeleterevision" => "Skasowano wersję z $1",
+"undeletebtn" => "Odtwórz!",
+"undeletedarticle" => "odtworzono \"$1\"",
+"undeletedtext"   => "Pomyślnie odtworzono artykuł [[$1]].
+Zobacz [[Wikipedia:Usunięte]], jeśli chcesz przejrzeć rejestr ostatnio
+skasowanych i odtworzonych stron.",
+
+# Contributions
+#
+"contributions"        => "Wkład użytkownika",
+"mycontris"     => "Moje edycje",
+"contribsub"   => "Dla $1",
+"nocontribs"   => "Brak zmian odpowiadających tym kryteriom.",
+"ucnote"               => "Oto lista ostatnich <b>$1</b> zmian dokonanych przez
+użytkownika w ciągu ostatnich <b>$2</b> dni.",
+"uclinks"              => "Zobacz ostatnie $1 zmian; zobacz ostatnie $2 dni.",
+"uctop"                        => " (jako ostatnia)",
+
+# What links here
+#
+"whatlinkshere"        => "Linkujące",
+"notargettitle" => "Wskazywana strona nie istnieje",
+"notargettext" => "Nie podano strony albo użytkownika, dla których
+ta operacja ma być wykonana.",
+"linklistsub"  => "(Lista linków)",
+"linkshere"            => "Do tej strony odwołują się następujące inne strony:",
+"nolinkshere"  => "Do tej strony nie odwołuje się do żadna inna.",
+"isredirect"   => "strona przekierowująca",
+
+# Block/unblock IP
+#
+"blockip"              => "Zablokuj adres IP",
+"blockiptext"  => "Użyj poniższego formularza aby zablokować prawo
+zapisu spod określonego adresu IP.
+Powinno się to robić jedynie by zapobiec wandalizmowi, a zarazem
+w zgodzie z [[Wikipedia:Zasady i wskazówki|zasadami Wikipedii]].
+Podaj powód (np. umieszczając nazwy stron, na których dopuszczono
+się wandalizmu).",
+"ipaddress"            => "Adres IP",
+"ipbreason"            => "Powód",
+"ipbsubmit"            => "Zablokuj ten adres",
+"badipaddress" => "Adres IP jest źle utworzony.",
+"noblockreason" => "Musisz podać powód blokady.",
+"blockipsuccesssub" => "Zablokowanie powiodło się",
+"blockipsuccesstext" => "Adres IP \"$1\" został zablokowany.
+<br>Przejdź do [[Specjalna:Ipblocklist|Listy zablokowanych adresów IP]] by przejrzeć blokady.",
+"unblockip"            => "Odblokuj adres IP",
+"unblockiptext"        => "Użyj poniższego formularza by przywrócić prawa zapisu
+dla poprzednio zablokowanego adresu IP.",
+"ipusubmit"            => "Odblokuj ten adress",
+"ipusuccess"   => "Adress IP \"$1\" został odblokowany",
+"ipblocklist"  => "Lista zablokowanych adresów IP",
+"blocklistline"        => "$1, $2 zablokował $3",
+"blocklink"            => "zablokuj",
+"unblocklink"  => "odblokuj",
+"contribslink" => "wkład",
+
+# Developer tools
+#
+"lockdb"               => "Zablokuj bazę danych",
+"unlockdb"             => "Odblokuj bazę danych",
+"lockdbtext"   => "Zablokowanie bazy danych uniemożliwi wszystkim użytkownikom
+edycję stron, zmianę preferencji, edycję list obserwowanych artykułów oraz inne
+czynności wymagające dostępu do bazy danych.
+Potwierdź, proszę, że to jest zgodne z Twoimi zamiarami, i że odblokujesz
+bazę danych, gdy tylko zakończysz zadania administracyjne.",
+"unlockdbtext" => "Odblokowanie bazy danych umożliwi wszystkim użytkownikom
+edycję stron, zmianę preferencji, edycję list
+obserwowanych artykułów oraz inne czynności związane ze zmianami w bazie danych.
+Potwierdź, proszę, że to jest zgodne z Twoimi zamiarami.",
+"lockconfirm"  => "Tak, naprawdę chcę zablokować bazę danych.",
+"unlockconfirm"        => "Tak, naprawdę chcę odblokowac bazę danych.",
+"lockbtn"              => "Zablokuj bazę danych",
+"unlockbtn"            => "Odblokuj bazę danych",
+"locknoconfirm" => "Nie zaznaczyłeś pola potwierdzenia.",
+"lockdbsuccesssub" => "Baza danych została pomyślnie zablokowana",
+"unlockdbsuccesssub" => "Blokada bazy danych usunięta",
+"lockdbsuccesstext" => "Baza danych Wikipedii została zablokowana.
+<br>Pamiętaj usunąć blokadę po zakończeniu spraw administracyjnych.",
+"unlockdbsuccesstext" => "Baza danych Wikipedii została odblokowana.",
+
+# SQL query
+#
+"asksql"               => "Zapytanie SQL",
+"asksqltext"   => "Użyj poniższego formularza by wysłać bezpośrednie zapytanie
+do bazy danych Wikipedii.
+Do ograniczania literałów łańcuchowych używaj pojedynczych cudzysłowów ('tak jak tu').
+Twoje zapytanie może poważnie obciążyć serwer, więc używaj tej możliwości
+z rozwagą.",
+"sqlquery"             => "Podaj zapytanie",
+"querybtn"             => "Wyślij zapytanie",
+"selectonly"   => "Zapytania inne niż \"SELECT\" są zastrzeżone tylko dla
+użytkowników o statusie Programisty.",
+"querysuccessful" => "Zapytanie zakończone sukcesem",
+
+# Move page
+#
+"movepage"             => "Przenieś stronę",
+"movepagetext" => "Za pomocą poniższego formularza zmienisz nazwę strony,
+przenosząc jednocześnie jej historę.
+Pod starym tytułem zostanie umieszczona strona przekierowująca.
+Linki do starego tytułu pozostaną niezmienione.
+[[Specjalna:Maintenance|Upewnij się]], że uwzględniasz podwójne
+lub zerwane przekierowania. Odpowiadasz za to, żeby linki odnosiły
+się do właściwych artykułów!
+
+Strona '''nie''' będzie przeniesiona jeśli:
+*jest pusta i nigdy nie była edytowana
+*jest stroną przekierowującą
+*strona o nowej nazwie już istnieje
+
+<b>UWAGA!</b>
+Może to być drastyczna lub nieprzewidywalna zmiana w przypadku popularnych stron;
+upewnij się co do konsekwencji tej operacji zanim się na nią zdecydujesz.",
+"movepagetalktext" => "Odpowiednia strona dyskusji, jeśli istnieje, będzie
+przeniesiona automatycznie, pod warunkiem, że:
+*nie przenosisz strony do innej przestrzeni nazw
+*nie istnieje strona dyskusji o nowej nazwie
+W takich przypadkach tekst dyskusji trzeba przenieść, i ewentualnie połączyć
+z istniejącym, ręcznie.
+Możesz też zrezygnować z przeniesienia dyskusji (poniższy <i>checkbox</i>).",
+"movearticle"  => "Przenieś stronę",
+"movenologin"  => "Brak logowania",
+"movenologintext" => "Musisz być zarejestrowanym i <a href=\"" .
+  wfLocalUrl( "Specjalna:Userlogin" ) . "\">zalogowanym</a>
+użytkownikiem aby móc przenieść stronę.",
+"newtitle"             => "Nowy tytuł",
+"movepagebtn"  => "Przenieś stronę",
+"pagemovedsub" => "Przeniesienie powiodło się",
+"pagemovedtext" => "Strona \"[[$1]]\" została przeniesiona do \"[[$2]]\".",
+"articleexists" => "Strona o podanej nazwie już istnieje albo
+wybrana przez Ciebie nazwa nie jest poprawna.
+Wybierz, proszę, nową nazwę.",
+"movedto"              => "przeniesiono do",
+"movetalk"             => "Przenieś także stronę <i>Dyskusji</i>, jeśli to możliwe.",
+"talkpagemoved" => "Odpowiednia strona z <i>Dyskusją</i> także została przeniesiona.",
+"talkpagenotmoved" => "Odpowiednia strona z <i>Dyskusją</i> <strong>nie</strong> została przeniesiona.",
+
+);
+
+class LanguagePl extends LanguageUtf8 {
+
+       function getNamespaces() {
+               global $wgNamespaceNamesPl;
+               return $wgNamespaceNamesPl;
+       }
+
+       function getNsText( $index ) {
+               global $wgNamespaceNamesPl;
+               return $wgNamespaceNamesPl[$index];
+       }
+
+       function getNsIndex( $text ) {
+               global $wgNamespaceNamesPl;
+
+               foreach ( $wgNamespaceNamesPl as $i => $n ) {
+                       if ( 0 == strcasecmp( $n, $text ) ) { return $i; }
+               }
+               return false;
+       }
+
+       function getQuickbarSettings() {
+               global $wgQuickbarSettingsPl;
+               return $wgQuickbarSettingsPl;
+       }
+
+       function getSkinNames() {
+               global $wgSkinNamesPl;
+               return $wgSkinNamesPl;
+       }
+
+       function getMathNames() { 
+               global $wgMathNamesPl; 
+               return $wgMathNamesPl; 
+    }
+
+       function getUserToggles() {
+               global $wgUserTogglesPl;
+               return $wgUserTogglesPl;
+       }
+
+       function getLanguageName( $code ) {
+               global $wgLanguageNamesPl;
+               if ( ! array_key_exists( $code, $wgLanguageNamesPl ) ) {
+                       return "";
+               }
+               return $wgLanguageNamesPl[$code];
+       }
+
+       function getMonthName( $key )
+       {
+               global $wgMonthNamesPl;
+               return $wgMonthNamesPl[$key-1];
+       }
+
+       function getMonthNameGen( $key )
+       {
+               global $wgMonthNamesGenPl;
+               return $wgMonthNamesGenPl[$key-1];
+       }
+
+       function getMonthAbbreviation( $key )
+       {
+               global $wgMonthAbbreviationsPl;
+               return $wgMonthAbbreviationsPl[$key-1];
+       }
+
+       function getWeekdayName( $key )
+       {
+               global $wgWeekdayNamesPl;
+               return $wgWeekdayNamesPl[$key-1];
+       }
+
+       function userAdjust( $ts )
+       {
+               global $wgUser;
+
+               $diff = $wgUser->getOption( "timecorrection" );
+               if ( ! $diff ) { $diff = 0; }
+               if ( 0 == $diff ) { return $ts; }
+
+               $t = mktime( ( (int)substr( $ts, 8, 2) ) + $diff,
+                 (int)substr( $ts, 10, 2 ), (int)substr( $ts, 12, 2 ),
+                 (int)substr( $ts, 4, 2 ), (int)substr( $ts, 6, 2 ),
+                 (int)substr( $ts, 0, 4 ) );
+               return date( "YmdHis", $t );
+       }
+
+       function date( $ts, $adj = false )
+       {
+               if ( $adj ) { $ts = $this->userAdjust( $ts ); }
+
+               $d = (0 + substr( $ts, 6, 2 )) . 
+                 " " . $this->getMonthAbbreviation( substr( $ts, 4, 2 ) ) .
+                 " " . substr( $ts, 0, 4 );
+               return $d;
+       }
+
+       function time( $ts, $adj = false )
+       {
+               if ( $adj ) { $ts = $this->userAdjust( $ts ); }
+
+               $t = substr( $ts, 8, 2 ) . ":" . substr( $ts, 10, 2 );
+               return $t;
+       }
+
+       function timeanddate( $ts, $adj = false )
+       {
+               return $this->time( $ts, $adj ) . ", " . $this->date( $ts, $adj );
+       }
+
+       function rfc1123( $ts )
+       {
+               return date( "D, d M Y H:i:s T", $ts );
+       }
+
+       function getValidSpecialPages()
+       {
+               global $wgValidSpecialPagesPl;
+               return $wgValidSpecialPagesPl;
+       }
+
+       function getSysopSpecialPages()
+       {
+               global $wgSysopSpecialPagesPl;
+               return $wgSysopSpecialPagesPl;
+       }
+
+       function getDeveloperSpecialPages()
+       {
+               global $wgDeveloperSpecialPagesPl;
+               return $wgDeveloperSpecialPagesPl;
+       }
+
+       function getMessage( $key )
+       {
+               global $wgAllMessagesPl;
+        if(array_key_exists($key, $wgAllMessagesPl))
+                       return $wgAllMessagesPl[$key];
+               else
+                       return Language::getMessage($key);
+       }
+
+       # Inherit ucfirst() and stripForSearch() from LanguageUtf8
+
+       function checkTitleEncoding( $s ) {
+        # Check for Latin-2 backwards-compatibility URLs
+               $ishigh = preg_match( '/[\x80-\xff]/', $s);
+               $isutf = preg_match( '/^([\x00-\x7f]|[\xc0-\xdf][\x80-\xbf]|' .
+                '[\xe0-\xef][\x80-\xbf]{2}|[\xf0-\xf7][\x80-\xbf]{3})+$/', $s );
+        
+        if($ishigh and !$isutf)
+               return iconv( "ISO-8859-2", "UTF-8", $s );
+        
+        return $s;
+       }
+
+}
+
+?>
diff --git a/languages/LanguageRu.php b/languages/LanguageRu.php
new file mode 100644 (file)
index 0000000..4307a02
--- /dev/null
@@ -0,0 +1,25 @@
+<?
+# See language.doc
+global $IP;
+include_once("$IP/Utf8Case.php");
+
+class LanguageRu extends LanguageUtf8 {
+       # Inherit everything
+
+       function checkTitleEncoding( $s ) {
+               global $wgInputEncoding;
+               
+               # Check for non-UTF-8 URLs; assume they are Windows-1251
+               $ishigh = preg_match( '/[\x80-\xff]/', $s);
+               $isutf = ($ishigh ? preg_match( '/^([\x00-\x7f]|[\xc0-\xdf][\x80-\xbf]|' .
+                '[\xe0-\xef][\x80-\xbf]{2}|[\xf0-\xf7][\x80-\xbf]{3})+$/', $s ) : true );
+
+               if( $ishigh and !$isutf )
+                       return iconv( "windows-1251", "utf-8", $s );
+               
+               return $s;
+       }
+
+}
+
+?>
diff --git a/languages/LanguageSv.php b/languages/LanguageSv.php
new file mode 100644 (file)
index 0000000..2bcfdac
--- /dev/null
@@ -0,0 +1,1110 @@
+<?
+
+// NOTE: To turn off "Current Events" in the sidebar,
+// set "currentevents" => "-"
+// 
+// The names of the namespaces can be set here, but the numbers
+// are magical, so don't change or move them!  The Namespace class
+// encapsulates some of the magic-ness.
+// 
+
+/* private */ $wgNamespaceNamesSv = array(
+        -1      => "Special",
+        0       => "",
+        1       => "Diskussion",
+        2       => "Användare",
+        3       => "Användare_diskussion",
+        4       => "Wikipedia",
+        5       => "Wikipedia_diskussion",
+        6       => "Bild",
+        7       => "Bild_diskussion"
+);
+
+/* private */ $wgDefaultUserOptionsSv = array(
+        "quickbar" => 1,
+       "underline" => 1,
+       "hover" => 1,
+        "cols" => 80,
+       "rows" => 25,
+       "searchlimit" => 20,
+        "contextlines" => 5,
+       "contextchars" => 50,
+        "skin" => 0,
+       "math" => 1, 
+       "rcdays" => 7,
+       "rclimit" => 50,
+        "highlightbroken" => 1,
+       "stubthreshold" => 0
+);
+
+/* private */ $wgQuickbarSettingsSv = array(
+        "Ingen", "Fast vänster", "Fast höger", "Flytande vänster"
+);
+
+/* private */ $wgSkinNamesSv = array(
+        "Standard", "Nostalgi", "Cologne Blå"
+);
+
+/* private */ $wgUserTogglesSv = array(
+        "hover"            => "Svävande text över wikilänkar",
+        "underline"        => "Understrukna länkar",
+        "highlightbroken"  => "Röda länkar till tomma sidor",
+        "justify"          => "Justera indrag",
+        "hideminor"        => "Göm små redigeringar vid senaste ändring",
+        "numberheadings"   => "Automatisk numrering av överskrifter",
+        "rememberpassword" => "Kom ihåg lösenord till nästa besök",
+        "editwidth"        => "Redigeringsboxen har full bredd",
+        "editondblclick"   => "Redigera sidor med dubbelklick (JavaScript)",
+        "watchdefault"     => "Övervaka nya och ändrade artiklar",
+        "minordefault"     => "Markera som standard alla ändringer som mindre"
+);
+
+/* private */ $wgBookstoreListSv = array(
+        "AddALL"         => "http://www.addall.com/New/Partner.cgi?query=$1&type=ISBN",
+        "PriceSCAN"      => "http://www.pricescan.com/books/bookDetail.asp?isbn=$1",
+        "Barnes & Noble" => "http://shop.barnesandnoble.com/bookSearch/isbnInquiry.asp?isbn=$1",
+        "Amazon.com"     => "http://www.amazon.com/exec/obidos/ISBN=$1"
+);
+
+/* Note: native names of languages are preferred where known to maximize
+   ease of navigation -- people should be able to recognize their own
+   languages! */
+/* private */ $wgLanguageNamesSv = array(
+        "aa" => "Afar",
+        "ab" => "Abkhasiska",
+        "af" => "Afrikaans",
+        "am" => "Amhariska",
+        "ar" => "Arabiska",
+        "as" => "Assami",
+        "ay" => "Aymara",
+        "az" => "Aserbajdsjanska",
+        "ba" => "Basjkiriska",
+        "be" => "Vitryska",
+        "bh" => "Bihari",
+        "bi" => "Bislama",
+        "bn" => "Bengali",
+        "bo" => "Tibetanska",
+        "br" => "Bretonska",
+        "ca" => "Katalanska",
+        "ch" => "Chamorro",
+        "co" => "Korsikanska",
+        "cs" => "Tjeckiska",
+        "cy" => "Walesiska",
+        "da" => "Danska", # Note two different subdomains. 
+        "dk" => "Danska", # 'da' is correct for the language.
+        "de" => "Tyska",
+        "dz" => "Bhutanesiska",
+        "el" => "Grekiska",
+        "en" => "Engelska",
+        "eo" => "Esperanto",
+        "es" => "Spanska",
+        "et" => "Estniska",
+        "eu" => "Baskiska",
+        "fa" => "Persiska",
+        "fi" => "Finska",
+        "fj" => "Fidjianska",
+        "fo" => "Färöiska",
+        "fr" => "Franska",
+        "fy" => "Frisiska",
+        "ga" => "Irländska",
+        "gl" => "Galiciska",
+        "gn" => "Guarani",
+        "gu" => "Gujarati",
+        "ha" => "Hausa",
+        "he" => "Hebreiska",
+        "hi" => "Hindi",
+        "hr" => "Kroatiska",
+        "hu" => "Ungerska",
+        "hy" => "Armeniska",
+        "ia" => "Interlingua",
+        "id" => "Indonesiska",
+        "ik" => "Inupiaq",
+        "is" => "Isländska",
+        "it" => "Italienska",
+        "iu" => "Inuktitut",
+        "ja" => "Japanska",
+        "jv" => "Javanesiska",
+        "ka" => "Georgiska",
+        "kk" => "Kazakiska",
+        "kl" => "Grönländska",
+        "km" => "Kambodjanska",
+        "kn" => "Kanaresiska",
+        "ko" => "Koreanska",
+        "ks" => "Kashmiri",
+        "kw" => "Corniska",
+        "ky" => "Kirgisiska",
+        "la" => "Latin",
+        "ln" => "Lingala",
+        "lo" => "Laotiska",
+        "lt" => "Litauiska",
+        "lv" => "Lettiska",
+        "mg" => "Malagassiska",
+        "mi" => "Maori",
+        "mk" => "Makedoniska",
+        "ml" => "Malyalam",
+        "mn" => "Mongoliska",
+        "mo" => "Moldaviska",
+        "mr" => "Marathi",
+        "ms" => "Malajiska",
+        "my" => "Burmesiska",
+        "na" => "Nauriska",
+        "ne" => "Nepaliska",
+        "nl" => "Nederländska",
+       "nn" => "Nynorska",
+        "no" => "Norska",
+        "oc" => "Occitanska",
+        "om" => "Afan Oromoo",
+        "or" => "Oriya",
+        "pa" => "Punjabi",
+        "pl" => "Polska",
+        "ps" => "Pashto",
+        "pt" => "Portugisiska",
+        "qu" => "Quechua",
+        "rm" => "Rätoromanska",
+        "rn" => "Rundi",
+        "ro" => "Rumänska",
+        "ru" => "Ryska", 
+        "rw" => "Rwanda",
+        "sa" => "Sanskrit",
+        "sd" => "Sindhi",
+        "sg" => "Sango",
+        "sh" => "Serbokroatiska",
+        "si" => "Singalesiska",
+        "simple" => "enkel Engelska",
+        "sk" => "Slovakiska",
+        "sl" => "Slovenska",
+        "sm" => "Samoanska",
+        "sn" => "Shona",
+        "so" => "Somaliska",
+        "sq" => "Albanska",
+        "sr" => "Serbiska",
+        "ss" => "Siswati",
+        "st" => "Sotho",
+        "su" => "Sudanesiska",
+        "sv" => "Svenska",
+        "sw" => "Swahili",
+        "ta" => "Tamil",
+        "te" => "Telugo",
+        "tg" => "Tadjikiska",
+        "th" => "Thailändska",
+        "ti" => "Tigrinya",
+        "tk" => "Turkmeniska",
+        "tl" => "Tagalog",
+        "tn" => "Tswana",
+        "to" => "Tonga",
+        "tr" => "Turkiska",
+        "ts" => "Tsonga",
+        "tt" => "Tatariska",
+        "tw" => "Twi",
+        "ug" => "Uiguriska",
+        "uk" => "Ukrainska",
+        "ur" => "Urdu",
+        "uz" => "Uzbekiska",
+        "vi" => "Vietnamesiska",
+        "vo" => "Volap&#252;k",
+        "wo" => "Wolof",
+        "xh" => "Xhosa",
+        "yi" => "Jiddisch",
+        "yo" => "Yoruba",
+        "za" => "Zhuang",
+        "zh" => "Kinesiska",
+        "zu" => "Zulu"
+);
+
+/* private */ $wgWeekdayNamesSv = array(
+        "söndag", "måndag", "tisdag", "onsdag", "torsdag",
+        "fredag", "lördag"
+);
+
+/* private */ $wgMonthNamesSv = array(
+        "januari", "februari", "mars", "april", "maj", "juni",
+        "juli", "augusti", "september", "oktober", "november",
+        "december"
+);
+
+/* private */ $wgMonthAbbreviationsSv = array(
+        "jan", "feb", "mar", "apr", "maj", "jun", "jul", "aug",
+        "sep", "okt", "nov", "dec"
+);
+
+// All special pages have to be listed here: a description of ""
+// will make them not show up on the "Special Pages" page, which
+// is the right thing for some of them (such as the "targeted" ones).
+//#
+
+// private
+$wgValidSpecialPagesSv = array(
+        "Userlogin"     => "",
+        "Userlogout"    => "",
+        "Preferences"   => "Mina användarinställningar",
+        "Watchlist"     => "Min övervakningslista",
+        "Recentchanges" => "Senaste ändringar",
+
+        "Upload"        => "Ladda upp filer",
+        "Imagelist"     => "Bildlista",
+        "Listusers"     => "Registrerade användare",
+        "Statistics"    => "Sidstatistik",
+
+        "Randompage"    => "Slumpmässig sida",
+        "Lonelypages"   => "Föräldralösa sidor",
+        "Unusedimages"  => "Föräldralösa filer",
+        "Popularpages"  => "Populära artiklar",
+        "Wantedpages"   => "Mest önskade artiklar",
+        "Shortpages"    => "Korta artiklar",
+        "Longpages"     => "Långa artiklar",
+        "Newpages"      => "De nyaste artiklarna",
+        "Allpages"      => "Alla sidor efter titel",
+
+        "Ipblocklist"   => "Blockerade IP adresser",
+        "Maintenance"   => "Underhållssida",
+        "Specialpages"  => "Specialsidor",
+        "Contributions" => "",
+        "Emailuser"     => "E-postanvändare",
+        "Whatlinkshere" => "",
+        "Recentchangeslinked" => "",
+        "Movepage"      => "",
+        "Booksources"   => "Externa bokkällor"
+);
+
+/* private */ $wgSysopSpecialPagesSv = array(
+        "Blockip"       => "Blockera en IP-adress",
+        "Asksql"        => "Gör en sökning i databasen",
+        "Undelete"      => "Se och återställ raderade sidor"
+);
+
+/* private */ $wgDeveloperSpecialPagesSv = array(
+        "Lockdb"        => "Skrivskydda databasen",
+        "Unlockdb"      => "Återställ skrivning till databasen",
+        "Debug"         => "Debuginformation"
+);
+
+/* private */ $wgAllMessagesSv = array(
+
+// Bits of text used by many pages:
+//     
+"linktrail"             => "/^([a-zäöå]+)(.*)\$/sD",
+"mainpage"              => "Huvudsida",
+"about"                 => "Om",
+"aboutwikipedia"        => "Om Wikipedia",
+"aboutpage"             => "Wikipedia:Om",
+"help"                  => "Hjälp",
+"helppage"              => "Wikipedia:Hjälp",
+"wikititlesuffix"       => "Wikipedia",
+"bugreports"            => "Felrapporter",
+"bugreportspage"        => "Wikipedia:Felrapporter",
+"faq"                   => "FAQ",
+"faqpage"               => "Wikipedia:FAQ",
+"edithelp"              => "Redigeringshjälp",
+"edithelppage"          => "Wikipedia:Hur_redigerar_jag_en_sida",
+"cancel"                => "Avbryt",
+"qbfind"                => "SnabbSök",
+"qbbrowse"              => "Genomsök",
+"qbedit"                => "Redigera",
+"qbpageoptions"         => "Sidinställningar",
+"qbpageinfo"            => "Sidinformation",
+"qbmyoptions"           => "Mina inställingar",
+"mypage"                => "Min sida",
+"mytalk"                => "Min diskussion",
+"currentevents"         => "-",
+"errorpagetitle"        => "Fel",
+"returnto"              => "Tillbaka till $1.",
+"fromwikipedia"         => "Från Wikipedia, den fria encyklopedin.",
+"whatlinkshere"         => "Vilka sidor länkar hit?",
+"help"                  => "Hjälp",
+"search"                => "Sök",
+"history"               => "Versionshistorik",
+"printableversion"      => "Skrivarvänlig version",
+"editthispage"          => "Redigera den här sidan",
+"deletethispage"        => "Radera den här sidan",
+"protectthispage"       => "Skydda den här sida",
+"unprotectthispage"     => "Ta bort skydd av denna sida",
+"talkpage"              => "Diskussionssida",
+"subjectpage"           => "Ämnessida",
+"userpage"              => "Visa användarsida",
+"wikipediapage"         => "Visa metasida",
+"imagepage"             => "Visa bildsida",
+"otherlanguages"        => "Andra språk",
+"redirectedfrom"        => "(Omdirigerad från $1)",
+"lastmodified"          => "Denna sida blev senast ändrad $1.",
+"viewcount"             => "Denna sida har visats $1 gånger.",
+"gnunote"               => "Denna sida är publicerad under <a class=internal href='/wiki/GNU_FDL'>GNU FDL</a>.",
+"printsubtitle"         => "(Från http://sv.wikipedia.org)",
+"protectedpage"         => "Skyddad sida",
+"administrators"        => "Wikipedia:Administratörer",
+"sysoptitle"            => "Sysop-behörighet krävs",
+"sysoptext"             => "Denna funktion kan bara utföras av användare med \"sysop\" status.
+Se $1.",
+"developertitle"        => "Utvecklarbehörighet krävs",
+"developertext"         => "Denna funktion kan bara utföras av användare med \"developer\" status.
+Se $1.",
+"nbyte"                 => " bytes",
+"go"                    => "Utför",
+"ok"                    => "OK",
+"sitetitle"             => "Wikipedia",
+"sitesubtitle"          => "Den fria encyklopedin",
+"retrievedfrom"         => "Hämtat från \"$1\"",
+
+// Main script and global functions
+//
+"nosuchaction"          => "Funktionen finns inte",
+"nosuchactiontext"      => "Den funktion som specificerats i URL:en kan inte
+hittas av Wikipediaprogramvaran",
+"nosuchspecialpage"     => "Sådan specialsida finns inte",
+"nospecialpagetext"     => "Du har önskat en specialsida som inte
+hittas av Wikipediaprogramvaran.",
+
+// General errors
+//
+"error"                 => "Fel",
+"databaseerror"         => "Databasfel",
+"dberrortext"           => "Ett syntaxfel i databasfrågan har uppstått. Detta kan bero på en felaktig sökfråga (se $5) eller det kan bero på ett fel i programvaran.
+Den senste utförda databasfrågan var:
+<blockquote><tt>$1</tt></blockquote>
+från funktionen \"<tt>$2</tt>\".
+MySQL returnerade felen \"$3<tt>: $4</tt>\".",
+"noconnect"             => "Kunde inte ansluta till databasen på $1",
+"nodb"                  => "Kunde inte välja databasen $1",
+"readonly"              => "Databasen är skrivskyddad",
+"enterlockreason"       => "Skriv en grund för skrivskyddet, inklusive 
+en uppskattning på när skrivskyddet skall upphävas",
+"readonlytext"          => "Wikipediadatabasen är för ögonblicket skrivskyddad för 
+nya sidor och andra modifikationer, beroende på rutinmässigt 
+underhåll av databasen, varefter den återgår till normalstatus.
+Den administratör som skrivskyddade den har gett följande förklaring:
+<p>$1",
+"missingarticle"        => "Databasen fann inte texten på en sida
+som den skulle hitta, med namnet \"$1\".
+Dette är inte ett databas fel, utan beror på ett fel i mjukvaran.
+Skicka vänligen en rapport om detta till en administratör, där du också nämner 
+URL:en.",
+"internalerror"         => "Internt fel",
+"filecopyerror"         => "Kunde inte kopiera filen \"$1\" til \"$2\".",
+"filerenameerror"       => "Kunde inte byta namn på filen \"$1\" til \"$2\".",
+"filedeleteerror"       => "Kunde inte radera filen \"$1\".",
+"filenotfound"          => "Kunde inte hitta filen \"$1\".",
+"unexpected"            => "Oväntat värde: \"$1\"=\"$2\".",
+"formerror"             => "Fel: Kunde inte sända formulär",
+"badarticleerror"       => "Denna funktion kan inte utföras på denna sida.",
+"cannotdelete"          => "Kunde inte radera sidan, eller filen som specificerades.",
+"badtitle"              => "Felaktig titel",
+"badtitletext"          => "Den önskade sidans titel var inte tillåten, tom eller sidan
+är felaktigt länkad från en Wikipedia på ett annat språk.",
+
+
+// Login and logout pages
+//
+"logouttitle"           => "Logga ut Användare",
+"logouttext"            => "Du är nu utloggad.
+Du kan fortsätta som anonym Wikipediaanvändare, eller så kan du logga in
+igen som samma eller annan användare.\n",
+
+
+"welcomecreation"       => "<h2>Välkommen, $1!</h2><p>Ditt konto har skapats. Glöm inte att anpassa dina Wikipediainställningar.",
+
+"loginpagetitle"        => "Logga in Användare",
+"yourname"              => "Ditt användarnamn",
+"yourpassword"          => "Ditt lösenord",
+"yourpasswordagain"     => "Upprepa lösenord",
+"newusersonly"          => " (bara för nya användare)",
+"remembermypassword"    => "Kom ihåg mitt lösenord till nästa gång.",
+"loginproblem"          => "<b>Det var svårt att logga in dig .</b><br>Pröva igen!",
+"alreadyloggedin"       => "<font color=red><b>Användare $1, du är redan inloggad !</b></font><br>\n",
+
+"areyounew"             => "Om du är ny på Wikipedia och önskar ett användarkonto, så skriv in ett användarnamn, därefter skriver du ett lösenord som du sedan upprepar.
+
+Observera att det finns bättre och sämre val av användarnamn, försök välja något unikt, och där du löper mindre risk att en dag behöva dela detta användarnamn med ett större antal användare som kan ha rätt till det. Exempel: Johansson, eller Peter. Allra helst ser vi attt du använder ditt eget för och efternamn, men du bestämmer naturligtvis själv.
+
+Din e-postadress är frivillig; men om du glömmer ditt lösenord kan du till exempel be om att få det tillsänt till den adress du har anget.<br>\n",
+
+"login"                 => "Logga in",
+"userlogin"             => "Logga in",
+"logout"                => "Logga ut",
+"userlogout"            => "Logga ut",
+"createaccount"         => "Skapa ett konto",
+"badretype"             => "De lösenord du uppgett överenstämmer inte med varandra.",
+"userexists"            => "Detta användarnamn används redan. Ange ett annat användarnamn.",
+"youremail"             => "Din e-postadress",
+"yournick"              => "Ditt smeknamn (till signaturer)",
+"emailforlost"          => "Har du glömt ditt lösenord, så kan du få ett nytt lösenord skickat till din e-post",
+"loginerror"            => "Inloggningsproblem",
+"noname"                => "Det användarnamn som du angett finns inte",
+"loginsuccesstitle"     => "Inloggningen lyckades",
+"loginsuccess"          => "Du är nu inloggad på wikipedia med användarnamnet \"$1\".",
+"nosuchuser"            => "Det finns ingen användare med namnet \"$1\".
+Kontrollera stavningen, eller använd formuläret nedan för att skapa ett nytt konto.",
+"wrongpassword"         => "Lösenordet du skrev är felaktigt. Pröva igen",
+"mailmypassword"        => "Sänd mig ett nytt lösenord",
+"passwordremindertitle" => "Nytt lösenord från Wikipedia",
+"passwordremindertext"  => "Någon (förmodligen du, med IP-numret $1)
+har bett oss sända dig ett nytt lösenord för din Wikipedia-inloggning
+Lösenordet för användare \"$2\" är nu \"$3\".
+Du ska logga in på din användare och byta lösenord.",
+"noemail"               => "Det finns ingen e-postadress registrerad för användare \"$1\".",
+"passwordsent"          => "Ett nytt lösenord har skickats till e-posten registrerad av användaren\"$1\".
+Var snäll och logga in igen när du fått meddelandet.",
+
+
+// Edit pages
+//
+"summary"               => "Sammanfattning",
+"minoredit"             => "Detta är en mindre ändring",
+"watchthis"             => "Bevaka den här artikeln",
+"savearticle"           => "Spara",
+"preview"               => "Förhandsgranska",
+"showpreview"           => "Visa förhandgranskning",
+"blockedtitle"          => "Användaren är spärrad",
+"blockedtext"           => "Ditt användarnamn har blivit spärrat av $1.
+Anledning är att:<br>''$2''<p>Ta kontakt med $1 eller en av de andra
+[[Wikipedia:Administratörer|administratörerna]] för att diskutera varför du blivit spärrad", // "
+"newarticle"            => "(Ny)",
+"newarticletext"        => "Skriv den nya sidan här.",
+"noarticletext"         => "(Det finns för tillfället ingen text på den här sidan.)",
+"updated"               => "(Uppdaterad)",
+"note"                  => "<strong>Notera:</strong> ",
+"previewnote"           => "Observera att detta är en förhandsvisning, och att sidan ännu inte sparats!",
+"previewconflict"       => "Denna förhandsvisning är resultatet av den 
+redigerbara texten ovanför,
+så som det kommer att se ut om du väljer att spara.",
+"editing"               => "Redigerar $1",
+"editconflict"          => "Redigeringskonflikt: $1",
+"explainconflict"       => "Någon har ändrat denna sida efter att du började att redigera den.
+Det översta text blocket innehåller den nuvarande texten.
+Dina ändringer syns i det nedersta blocket.
+Du måste infoga dina ändringar i den existerande texten.
+<b>Bara</b> texten i den översta textboxen sparas om du trycker \"Spara sida\".\n<p>",
+"yourtext"              => "Din text",
+"storedversion"         => "Din sparade version",
+"editingold"            => "<strong>VARNING: Du redigerar en gammal version
+av denna sida. Om du sparar den, kommer alla ändringar på denns sida föregående revison att bli överskrivna.</strong>\n",
+"yourdiff"              => "Skillnader",
+"copyrightwarning"      => "Lägg märke till att alla bidrag till Wikipedia är
+att betrakta som utgivna under GNU Free Documentation License
+(se $1 för detaljer).
+Om du inte vill ha din text redigerad och kopierad efter andras gottfinnade så skall du inte skriva någon text här.<br>
+Du lovar oss också att du skrev texten själv, eller kopierade från en
+public domain eller liknande fri resurs.
+
+<strong>
+LÄGG ALDRIG UT MATERIAL HÄR SOM SKYDDAS AV UPPHOVSRÄTTSLAGEN UTAN FÖRFATTARENS TILLÅTELSE!
+</strong>", //'"
+
+
+// History pages
+//
+"revhistory"            => "Versionshistoria",
+"nohistory"             => "Det finns ingen versionshistoria för denna sida.",
+"revnotfound"           => "Versionen hittades inte",
+"revnotfoundtext"       => "Den gamla versionen av den sida du frågade efter kan inte hittas. Kontrollera den URL du använde för att nå denna sida.\n",
+"loadhist"              => "Läser sidans versioner",
+"currentrev"            => "Nuvarande version",
+"revisionasof"          => "Versionen från",
+"cur"                   => "nuvarande",
+"next"                  => "nästa",
+"last"                  => "föregående",
+"orig"                  => "original",
+"histlegend"            => "Förklaring: (nuvarande) = skillnad mot den nuvarande versionen,
+ (föregående) = skillnad mot den föregående versionen, M = mindre ändring",
+
+
+// Diffs
+//
+"difference"            => "(Skillnad mellan versioner)",
+"loadingrev"            => "läser version för att se skillnad",
+"lineno"                => "Rad $1:",
+"editcurrent"           => "Redigera den nuvarande versionen av denna sida",
+
+// Search results
+//
+"searchresults"         => "Sökresultat",
+"searchhelppage"        => "Wikipedia:Sökning",
+"searchingwikipedia"    => "Sökning på Wikipedia",
+"searchresulttext"      => "För mer information om sökning på Wikipedia, se $1.",
+"searchquery"           => "For query \"$1\"",
+"badquery"              => "Felaktigt utformat sökbegrepp",
+"badquerytext"          => "Vi kunde inte utföra din sökning.
+Detta beror sannolikt på att du försökt söka efter ett ord med färre än tre bokstäver, något som f.n. inte stöds. Det kan också vara så att du har anget en felaktig sökning, till exempel \"fisk och och skaldjur\". Prova att formulera om sökningen.",
+"matchtotals"           => "Sökordet förekommer i \"$1\" överensstämde med $2 artiklar titlar
+och texter i $3 artiklar.",
+"titlematches"          => "Artikel titlar som överensstämmer med sökordet",
+"notitlematches"        => "Ingen artikel titlar överensstämmer med sökordet",
+"textmatches"           => "Artikel texter som överensstämmer med sökordet",
+"notextmatches"         => "Ingen artikel texter överensstämmer med sökordet",
+"prevn"                 => "förra $1",
+"nextn"                 => "nästa $2",
+
+"viewprevnext"          => "Om ($1) ($2) ($3).",
+"showingresults"        => "Nedan visas <b>$1</b> resultat som startar med nummer <b>$2</b>.",
+"nonefound"             => "<strong>Note</strong>: Misslyckade sökningar förorsakas ofta av
+ att man söker efter vanliga ord som \"har\" och \"från\",
+vilka inte indexeras, eller att specificera flera sökord (bara 
+sidor som innehåller alla sökorden hittas).",
+"powersearch"           => "Sök",
+"powersearchtext"       => "
+Sök i namnutrymme :<br>
+$1<br>
+$2 List redirects &nbsp; Sök efter $3 $9",
+
+
+// Preferences page
+//
+"preferences"           => "Inställningar",
+"prefsnologin"          => "Du är inte inloggad",
+"prefsnologintext"      => "Du måste vara <a href=\"" .
+  wfLocalUrl( "Special:Userlogin" ) . "\">inloggad</a>
+för att kunna ändra i inställningar.",
+"prefslogintext"        => "Du är inloggad som \"$1\".
+Ditt IP-nummer är $2.",
+"prefsreset"            => "Inställningar har blivit återställda från minne.",
+"qbsettings"            => "Inställningar för snabbmeny",
+"changepassword"        => "Byt lösenord",
+"skin"                  => "Utseende",
+"saveprefs"             => "Spara inställningar",
+"resetprefs"            => "Återställ inställningar",
+"oldpassword"           => "Gammalt lösenord",
+"newpassword"           => "Nytt lösenord",
+"retypenew"             => "Skriv om nytt lösenord",
+"textboxsize"           => "Textbox dimensioner",
+"rows"                  => "Rader",
+"columns"               => "Kolumner",
+"searchresultshead"     => "Inställningar för sökresultat",
+"resultsperpage"        => "Resultat att visa per sida",
+"contextlines"          => "Linjer att visa per sida",
+"contextchars"          => "Antalet bokstäver per linje i resultatet",
+"stubthreshold"         => "Gränser för visning av stubs",
+"recentchangescount"    => "Antalet artiklar i \"senaste ändringarna\" ",
+"savedprefs"            => "Dina inställningar har blivit sparade",
+"timezonetext"          => "Skriv in antalet timmar som din lokal tid skiljer sig från
+serverns klocka (UTC).
+Den blir automatiskt inställd efter svensk tid eller skulle man till exempel för svensk vintertid, endast ha \"1\" (och \"2\" när vi har sommartid).",
+"localtime"             => "Lokal tid",
+"timezoneoffset"        => "Utjämna",
+"emailflag"             => "Stoppa andra användare att skicka e-post till dig",
+
+// Recent changes
+//
+"recentchanges"         => "Senaste ändringarna",
+"recentchangestext"     => "Se de senaste redigerade sidorna i Wikipedia på denna 
+sida.
+
+[[Wikipedia:Välkommen|Välkommen]]!
+Vänligen läs dessa sidor: [[wikipedia:FAQ|Ofta ställda 
+frågor]], [[Wikipedia:Policy|policy]]
+
+(särskilt [[wikipedia:Namngivning|namngivning]],
+[[wikipedia:Skriv Wikipedia ifrån en neutral synpunkt|Skriv Wikipedia ifrån en neutral synpunkt]],
+och [[wikipedia:Mest vanliga nybörjarfel på Wikipedia|Mest vanliga nybörjarfel på Wikipedia]]).
+
+Det är mycket viktigt att du inte lägger material på 
+Wikipedia som andra äger upphovsrätten till. De rättsliga konsekvenserna kan bli 
+mycket kostbara och skadligt för projektet, så vänligen låt bli, om du är osäker.
+Se också [http://meta.wikipedia.org/wiki/Special:Recentchanges 
+recent meta discussion] (oftast på engelska).",
+"rcloaderr"             => "Läser senaste redigerade sidor",
+"rcnote"                => "Nedanför är de senaste <strong>$1</strong> ändringarna under de 
+sista <strong>$2</strong> dagarna.",
+"rcnotefrom"            => "Nedanför är ändringarna från <b>$2</b> till <b>$1</b> visade.",
+"rclistfrom"            => "Visa nya ändringar från och med $1",
+"rclinks"               => "Visa de senaste $1 ändringarna under de senaste $2 timmarna / $3 dagarna",
+// "rclinks"             => "Visa de senaste $1 ändringarna under de senaste $2 dagarna",
+"rchide"                => "i $4 form; $1 mindre ändringar; $2 andra namnrum; $3 mer än en redigering.",
+"diff"                  => "skillnad",
+"hist"                  => "historia",
+"hide"                  => "göm",
+"show"                  => "visa",
+
+"tableform"             => "tabell",
+"listform"              => "lista",
+"nchanges"              => "$1 ändringar",
+"minoreditletter"       => "M",
+"newpageletter"         => "N",
+
+// Upload
+//
+"upload"                => "Ladda upp",
+"uploadbtn"             => "Ladda upp fil",
+"uploadlink"            => "Ladda upp bild",
+"reupload"              => "återuppladdning",
+"reuploaddesc"          => "Tillbaka till uppladdningsformulär.",
+"uploadnologin"         => "Inte inloggad",
+"uploadnologintext"     => "Du måste vara <a href=\"" .
+  wfLocalUrl( "Special:Userlogin" ) . "\">inloggad</a>
+för att kunna ladda upp filer.",
+"uploadfile"            => "Ladda upp fil",
+"uploaderror"           => "Uppladdnings fel",
+"uploadtext"            => "<strong>STOPP!</strong> Innan du laddar upp här,
+så måste du ha läst och följa Wikipedias <a href=\"" .
+wfLocalUrlE( "Wikipedia:Policy om bruk av bilder" ) . "\">policy om hur 
+bilder får användas</a>.
+<p>För att visa eller söka tidigare uppladdade bilder gå till
+<a href=\"" . wfLocalUrlE( "Special:Imagelist" ) .
+"\">lista över uppladdade bilder</a>.
+Uppladdningar och borttagningar loggas i <a href=\"" .
+wfLocalUrlE( "Wikipedia:Upload_log" ) . "\">uppladdnings logg</a>.
+<p>Använd formuläret nedan för att ladda upp nya filer, som 
+du kan illustrera dina artiklar med.
+På de flesta webbläsare kommer du att se en \"Browse...\" knapp eller en 
+\"Öppna...\" knapp, som startar ditt operativsystems dialogruta för att öppna filer. När du valt en fil kommer namnet på den filen att visas i textfältet brevid knappen. Du måste även kryssa för rutan, för att du inte gör något som strider mot upphovsrätten av filen som laddas upp.
+Tryck på \"Upload\" knappen för att ladda upp filen.
+Detta kan dröja ett tag om du har en långsam internetförbindelse.
+<p>Formaten på filerna ska helst vara JPEG för bilder, PNG för ritningar 
+och andra ikonliknande bilder och OGG för ljud.
+Var vänlig namnge filen med ett så beskrivande namn som möjligt, för att undvika förvirring.
+För att använda en fil i en artikel, skriv följande om det är en bild: <b>[[bild:filnamn.jpg]]</b> eller <b>[[bild:filnamn.png|alternativ text]]</b>
+eller <b>[[media:filnamn.ogg]]</b> om det är en ljudfil.
+<p>Kom ihåg att det här är en wiki, vilket gör att andra kan redigera eller ta bort dina uppladdningar om de tycker de inte passar i en artikel. Om du missbrukar systemet med uppladdningar kommer filen avlägsnas och du bli spärrad från att ladda upp filer i framtiden.",
+"uploadlog"             => "upload log",
+"uploadlogpage"         => "Upload_log",
+"uploadlogpagetext"     => "Nedan följer en lista med de senaste uppladdade filerna.
+Alla tider visas efter serverns tid (UTC).
+<ul>
+</ul>
+",
+"filename"              => "Filnamn",
+"filedesc"              => "Beskrivning",
+"affirmation"           => "Jag bekräftar att ägaren till upphovsrätten accepterar att licensiera enligt följande avtal $1.",
+"copyrightpage"         => "Wikipedia:copyright",
+"copyrightpagename"     => "Wikipedia copyright",
+"uploadedfiles"         => "Uppladdade filer",
+"noaffirmation"         => "Du måste bekräfta att uppladdningen inte kränker någon copyright",
+"ignorewarning"         => "Ignorera varning och spara fil.",
+"minlength"             => "Namnet på bildfilen ska vara minst tre bokstäver",
+"badfilename"           => "Bildnamn har blivit ändrat till \"$1\".",
+"badfiletype"           => "\".$1\" är inte ett rekomenderat bildformat.",
+"largefile"             => "Bilder ska helst inte vara större än 100k.",
+"successfulupload"      => "Uppladdningen lyckades",
+"fileuploaded"          => "Filen \"$1\" laddades upp korrekt.
+Följ denna länk: ($2) till beskrivningssidan och fyll i
+information om filen, som till exempel var den kommer ifrån, 
+när den skapades och vem som gjort den och allt annat du vet om den.",
+"uploadwarning"         => "Uppladdnings varning",
+"savefile"              => "Spara fil",
+"uploadedimage"         => "uppladdad \"$1\"",
+
+// Image list
+//
+"imagelist"             => "Bildlista",
+"imagelisttext"         => "Nedan är en lista med $1 bilder sorterad $2",
+"getimagelist"          => "hämta bildlista",
+"ilshowmatch"           => "Visa alla bilder med namn som matchar",
+"ilsubmit"              => "Sök",
+"showlast"              => "Visa de senaste $1 bilderna sorterad $2.",
+"all"                   => "alla",
+"byname"                => "efter namn",
+"bydate"                => "efter datum",
+"bysize"                => "efter storlek",
+"imgdelete"             => "ta bort",
+"imgdesc"               => "beskrivning",
+"imglegend"             => "Legend: (beskrivning) = visa/redigera bildbeskrivning.",
+"imghistory"            => "Bildhistoria",
+"revertimg"             => "återgå",
+"deleteimg"             => "radera",
+"imghistlegend"         => "Legend: (nuvarande) = detta är den nuvarande bilden, 
+(ta bort) = ta bort den gamla version, (återgå) = återgå till en gammal version.
+<br><i>Klicka på ett datum för att se bilden som laddades upp den dagen</i>.", //"
+"imagelinks"            => "Bildlänk",
+"linkstoimage"          => "De följande sidorna länkar till denna bild:",
+"nolinkstoimage"        => "Det finns ingen sida som länkar till denna bild.",
+
+// Statistics
+//
+"statistics"            => "Statistik",
+"sitestats"             => "Statistiksida",
+"userstats"             => "Användarstatistik",
+"sitestatstext"         => "Det är <b>$1</b> sidor i databasen.
+Detta inkluderer diskussionssidorna, sidor om Wikipedia, mycket korta\"stub\"
+sidor, omdirigeringssidor, och andra sidor som kvalificerar sig som artiklar.
+Om man tar bort ovanstående så är det <b>$2</b> sidor som anses som riktiga artiklar.<p>
+Det har varit totalt <b>$3</b> sidvisningar och det har varit <b>$4</b> sidor som har ändrats
+sedan uppdateringen av mjukvaran (1 december 2002).
+Det vill säga <b>$5</b> ändringar per sida genomsnittligt, 
+och <b>$6</b> sidvisningar per ändring.",
+"userstatstext"         => "Det är <b>$1</b> registrerade användare.
+<b>$2</b> av dem är administratörer (se $3).",
+
+// Maintenance Page
+//
+"maintenance"           => "Underhållssida",
+"maintnancepagetext"    => "Den här sidan innehåller flera verktyg för att sköta sidan. Vissa av dessa funktioner tenderar att stressa databasen (allt tar lång tid), så var snäll och  tryck inte på reloadknappen varje gång du gjort en liten ändring.",
+"maintenancebacklink"   => "Tillbaka till underhållssidorna",
+"disambiguations"       => "Sidor med tvetydiga länkar",
+"disambiguationspage"   => "Wikipedia:Länkar till sidor med tvetydiga titlar",
+"disambiguationstext"   => "Följande artiklar länkar till en <i>sidor med tvetydliga titlar</i>. De ska länka till en sidor med en korrekt titel.<br>En sida behandlar som tvetydig om den länkar från $1. <br>Länkar från andra namngrupper är <i>inte</i> listade här.",
+"doubleredirects"       => "Dubbla omdirigeringar",
+"doubleredirectstext"   => "<b>OBS:</b> Denna lista kan innehålla falska resultat. Detta betyder normalt att det finns ytterligare text under den första #REDIRECT.<br>\n Varje rad innehåller en länk till den första och andra omdirigering och den första raden av den andra omdirigeringen ger oftast den \"riktiga\" artikeln, vilket egentligen den första omdirigeringen ska peka på.",
+"brokenredirects"       => "Dåliga omdirigeringar",
+"brokenredirectstext"   => "Följande länkar omdirigerar till en artikel som inte existerar.",
+"selflinks"             => "Sidor med länkar till sig själva",
+"selflinkstext"         => "Följande sidor innehåller länkar till sig själv, vilket de inte ska göra.",
+"mispeelings"           => "Sidor med felstavningar",
+"mispeelingstext"       => "Följande sidor innerhåller vanliga felstavningar, som visas i $1. Den korrekta stavningen kanske ska se ut såhär.",
+"mispeelingspage"       => "Lista med vanliga stavfel",
+"missinglanguagelinks"  => "Saknade språklänkar",
+"missinglanguagelinksbutton"    => "Sök efter saknade språklänkar för",
+"missinglanguagelinkstext"      => "De här artiklarna är <i>inte</i> länkade 
+till deras i $1. Redirects och undersidor visas <i>inte</i>.",
+
+// Miscellaneous special pages
+//
+"orphans"               => "Föräldralösa sidor",
+"lonelypages"           => "Föräldralösa sidor",
+"unusedimages"          => "Oanvända bilder",
+"popularpages"          => "Populära sidor",
+"nviews"                => "$1 visningar",
+"wantedpages"           => "Önskelista",
+"nlinks"                => "$1 länkar",
+"allpages"              => "Alla sidor",
+"randompage"            => "Slumpartikel",
+"shortpages"            => "Korta sidor",
+"longpages"             => "Långa sidor",
+"listusers"             => "Användarlista",
+"specialpages"          => "Speciella sidor",
+"spheading"             => "Speciella sidor",
+"sysopspheading"        => "Speciella sidor för sysop",
+"developerspheading"    => "Speciella sidor för utvecklare",
+"protectpage"           => "Skydda sida",
+"recentchangeslinked"   => "Relaterade ändringar",
+"rclsub"                => "(till sidor som är länkade från \"$1\")",
+"debug"                 => "Debug",
+"newpages"              => "Nya sidor",
+"movethispage"          => "Flytta den här sidan",
+"unusedimagestext"      => "<p>Lägg märket till att andra hemsidor
+som till exempel de internationella wikipedias kan länka till bilder 
+med en direkt URL, och kan därför bli listade här trots att de används kontinuerligt.",
+"booksources"           => "Bokkällor",
+"booksourcetext"        => "Nedan följer en lista över länkar till hemsidor som säljer
+nya och begagnade böcker, och mycket annan information om de böcker du söker.
+Wikipedia har <b>inget</b> affärssamarbete med ovanstående företag och ska inte heller tolkas som en uppmuntran.",
+
+// Email this user
+//
+"mailnologin"           => "Ingen adress att skicka till",
+"mailnologintext"       => "Du ska vara<a href=\"" .
+  wfLocalUrl( "Special:Userlogin" ) . "\">inloggad</a>
+och ha angivit en korrekt epost-adress i dina <a href=\"" .
+  wfLocalUrl( "Special:Preferences" ) . "\">användarinställningar</a>
+för att kunna skicka e-post till andra användare.",
+"emailuser"             => "Skicka e-post till den här användaren",
+"emailpage"             => "Skicka e-post till annan användare",
+"emailpagetext"         => "Om den här användaren har skrivit in en korrekt e-postadress, i sina
+användarinställningar, kommer formuläret nedan skicka ett meddelande.
+Den epost-adress du anget i dina användarinställningar kommer att skrivas
+i \"Från\"fältet i detta e-post, så mottagaren har möjlighet att svara.",
+"noemailtitle"          => "Ingen e-postadress",
+"noemailtext"           => "Den här användaren har inte angivet en korrekt e-postadress eller
+valt att inte ta emot något mail från andra användare.",
+"emailfrom"             => "Från",
+"emailto"               => "Till",
+"emailsubject"          => "Ämne",
+"emailmessage"          => "Meddelande",
+"emailsend"             => "Skickat",
+"emailsent"             => "E-post sskickat",
+"emailsenttext"         => "Din e-post har skickats.",
+
+// Watchlist
+//
+"watchlist"             => "Min övervakningslista",
+"watchlistsub"          => "(för användare \"$1\")",
+"nowatchlist"           => "Du har inga sidor upptagna på din övervakningslista.",
+"watchnologin"          => "Du är inte inloggad",
+"watchnologintext"      => "Du ska vara<a href=\"" .
+  wfLocalUrl( "Special:Userlogin" ) . "\">inloggad</a>
+för att kunna göra ändringar på din övervakningslista.",
+"addedwatch"            => "Tillagd på övervakningslistan",
+"addedwatchtext"        => "Sidan \"$1\" har satts upp på din <a href=\"" .
+  wfLocalUrl( "Special:Watchlist" ) . "\">övervakningslista</a>.
+Framtida ändringar av den här sidan och dess diskussionssida vill listas där, 
+
+och sidan kommer att markeras med <b>fet stil</b> i <a href=\"" .
+  wfLocalUrl( "Special:Recentchanges" ) . "\">listan över de senaste ändringarna
+</a> för att lättare kunna hittas</p>
+
+<p>Om du vill ta bort denna sida från din övervakningslista, så klicka 
+\"Ta bort övervakning\" ute i sidan.",
+"removedwatch"          => "Borttagen från övervakningslista",
+"removedwatchtext"      => "Sidan \"$1\" har blivit borttagen från din övervakningslista",
+"watchthispage"         => "Övervaka sida",
+"unwatchthispage"       => "Stoppa övervakning",
+"notanarticle"          => "Inte en artikel",
+
+// Delete/protect/revert
+//
+"deletepage"            => "Ta bort sida",
+"confirm"               => "Bekräfta",
+"confirmdelete"         => "Bekräfta borttagning",
+"deletesub"             => "(Tar bort \"$1\")",
+"confirmdeletetext"     => "Du håller på och permanent ta bort en sida
+eller bild med all dess historia från databasen.
+Bekräfta att du förstår vad du håller på med och vilka konsekvenser
+detta leder till, och att det följer 
+[[Wikipedia:Policy]].", 
+"confirmcheck"          => "Ja, jag vill verkligen ta bort det här.", //"
+"actioncomplete"        => "Genomfört",
+"deletedtext"           => "\"$1\" har blivit borttagen.
+Se $2 för lista över senaste borttagningar",
+"deletedarticle"        => "borttagen \"\$1\"",
+"dellogpage"            => "Borttagningslogg",
+"dellogpagetext"        => "Nedan är en lista över de senaste borttagningarna.
+De tidsangivelser som anges följer serverns klocka (UTC).
+<ul>
+</ul>
+",
+"deletionlog"           => "borttagningslogg",
+"reverted"              => "Återgått till yngre version",
+"deletecomment"         => "Anledningen till borttagning",
+"imagereverted"         => "Återställandet av nyare artikelversion lyckades",
+
+// Undelete
+//
+"undelete"              => "Återställ borttagna sidor",
+"undeletepage"          => "Visa och återställ borttagna sidor",
+"undeletepagetext"      => "Följande sidor har blivit borttagna, men är fortfarande i arkivet och kan användas vid återställning.
+Arkivet kan ibland rensas på gamla versioner.",
+"undeletearticle"       => "Återställ borttagen artikel",
+"undeleterevisions"     => "$1 versioner arkiverade",
+"undeletehistory"       => "Om du återställer sidan kommer allt tidigare versioner att sparas i versionshanteraren.
+Om en ny sida med samma namn har blivit skapad sedan borttagningen så kommer den återställda versionen att
+hamna i den äldre versionshanteraren och den senaste versionen av sidan kommer inte blir automatiskt ersatt.",
+"undeleterevision"      => "Tog bort version $1",
+"undeletebtn"           => "Återställd!",
+"undeletedarticle"      => "återställd \"$1\"",
+"undeletedtext"         => "Artikeln [[$1]] har blivit återställd
+Se [[Wikipedia:Borttagningslogg]] för en lista över nyligen gjorda borttagningar och återställningar",
+
+// Contributions
+//
+"contributions"         => "Användarbidrag",
+"contribsub"            => "För $1",
+"nocontribs"            => "Inga ändringar var funna som motsvarar dessa kriterier",
+"ucnote"                => "Nedan visas dennes användares senaste <b>$1</b> ändringar, under de senaste <b>$2</b> dagarna.",
+"uclinks"               => "Visa de senaste $1 ändringarna. Visa de senaste $2 dagarna.",
+"uctop"                 => " (top)",
+
+// What links here
+//
+"whatlinkshere"         => "Vilka sidor länkar hit",
+"notargettitle"         => "Inget mål",
+"notargettext"          => "Du har inte specificerat en sida eller användare
+för att genomföra den här funktionen.",
+"linklistsub"           => "(Länklista)",
+"linkshere"             => "Följande sidor länkas hit:",
+"nolinkshere"           => "Inga sidor länkar hit.",
+"isredirect"            => "Länka vidare sida",
+
+// Block/unblock IP
+//
+"blockip"               => "Blockera IP-adress",
+"blockiptext"           => "Använd formuläret nedan för att blockera skrivåtkomst 
+från en viss IP-adress
+Detta ska bara genomföras för att stoppa klotter och
+överstämma med [[Wikipedia:Politik|Wikipedia politik]].
+Fyll i anledningen till blockering nedan (till exempel vilka artiklar som klottrats ner).",
+"ipaddress"             => "IP-adress",
+"ipbreason"             => "Anledning",
+"ipbsubmit"             => "Blockera den här IP-adressen",
+"badipaddress"          => "Du har inte skrivit IP-adressen korrekt.",
+"noblockreason"         => "Du måste ange en anledning till varför du blockerar.",
+"blockipsuccesssub"     => "Blockeringen lyckades",
+"blockipsuccesstext"    => "IP-adressen \"$1\" har blockerats.
+<br>Se [[Speciel:Ipblocklist|IP blockeringslistan]] för alla blockeringar.",
+"unblockip"             => "Ta bort blockering av IP-adress",
+"unblockiptext"         => "Använd nedanstående formulär för att återställa skrivrättigheten för en tidigare blockerad IP-adress.",
+"ipusubmit"             => "Ta bort blockering för denna adress",
+"ipusuccess"            => "Blockeringen för IP-adressen \"$1\" har tagits bort",
+
+"ipblocklist"           => "Lista över blockerade IP-adresser",
+"blocklistline"         => "$1, $2 blockerade $3",
+"blocklink"             => "blockera",
+"unblocklink"           => "ta bort blockering",
+"contribslink"          => "bidrag",
+
+// Developer tools 
+//
+"lockdb"                => "Lås databas",
+"unlockdb"              => "Lås upp databas",
+"lockdbtext"            => "En låsning av databasen hindrar alla användare från att redigera sidor, ändra inställningar och andra saker som kräver ändringar i databasen.
+Bekräfta att du verkligen vill göra detta och att du kommer att låsa upp databasen när underhållet är utfört.",
+"unlockdbtext"          => "Genom att låsa upp databasen kommer alla användare att kunna redigera sidor, ändra inställningar etc. igen.
+Bekräfta att du vill göra detta.",
+"lockconfirm"           => "Ja, jag vill verkligen låsa databasen.",
+"unlockconfirm"         => "Ja, jag vill verkligen låsa upp databasen.",
+"lockbtn"               => "Lås databasen",
+"unlockbtn"             => "Lås upp databasen",
+"locknoconfirm"         => "Du har inte bekräftat låsningen.",
+"lockdbsuccesssub"      => "Databasen har låsts",
+"unlockdbsuccesssub"    => "Databasen har låsts upp",
+"lockdbsuccesstext"     => "Wikipediadatabasen är låst.
+<br>Kom ihåg att ta bort låsningen när du är färdig med ditt underhåll.",
+"unlockdbsuccesstext"   => "Wikipediadatabasen är upplåst.",
+
+// SQL query
+//
+"asksql"                => "SQL-fråga",
+"asksqltext"            => "Använd nedanstående formulär för att ställa frågor direkt till Wikipedias databas.
+Använd enkla citationstecken ('så här') för att markera strängar.
+Detta belastar ofta servern hårt, så använd denna funktion med omtanke.",
+"sqlquery"              => "Skriv fråga",
+"querybtn"              => "Skicka fråga",
+"selectonly"            => "Andra frågor än \"SELECT\" får endast utföras av Wikipedias utvecklare.",
+"querysuccessful"       => "Frågan genomfördes korrekt",
+
+// Move page
+//
+"movepage"              => "Flytta sida",
+"movepagetext"          => "Formuläret nedan byter namn på sidan och flyttar hela dess historia till det nya namnet. Den gamla sidan blir en omdirigeringssida till den nya. Länkar till den gamla sidan kommer inte att ändras. Om det finns en diskussionssida kommer den inte att flyttas. <b>OBS!</b> Detta kan innebära en drastisk ändring på en populär sida; var säker på att du inser konsekvenserna i förväg.",
+"movearticle"           => "Flytta sida",
+"movenologin"           => "Ej inloggad",
+"movenologintext"       => "Du måste vara registrerad användare och ha <a href=\"" .
+  wfLocalUrl( "Speciel:Userlogin" ) . "\">loggat in</a>
+för att kunna flytta en sida.",
+"newtitle"              => "Till ny titel",
+"movepagebtn"           => "Flytta sida",
+"pagemovedsub"          => "Sidan har flyttats",
+"pagemovedtext"         => "Sidan \"[[$1]]\" har flyttats till \"[[$2]]\".",
+"articleexists"         => "Det finns redan en sida med detta namn eller så är namnet du angett ogiltigt. Välj ett annat namn.",
+"talkexists"            => "Sidan  flyttades korrekt, men den tilhörande diskussionssidan kunde inte flyttas, eftersom det redan existerar en sida med denna nya titel. Du måste sammanfoga dem manuellt.",
+"movedto"               => "flyttat till",
+"movetalk"              => "Flytta även diskussionssidan, om den finns.",
+"talkpagemoved"         => "Sidans diskussionssida flyttades också.",
+"talkpagenotmoved"      => "Sidans diskussionssida flyttades <strong>inte</strong>.",
+
+);
+
+class LanguageSv extends Language {
+
+        function getNamespaces() {
+                global $wgNamespaceNamesSv;
+                return $wgNamespaceNamesSv;
+        }
+
+        function getBookstoreList () {
+                global $wgBookstoreListSv ;
+                return $wgBookstoreListSv ;
+        }
+
+        function getDefaultUserOptions () {
+                global $wgDefaultUserOptionsSv ;
+                return $wgDefaultUserOptionsSv ;
+                }
+
+        function getNsText( $index ) {
+                global $wgNamespaceNamesSv;
+                return $wgNamespaceNamesSv[$index];
+        }
+
+        function getNsIndex( $text ) {
+                global $wgNamespaceNamesSv;
+
+                foreach ( $wgNamespaceNamesSv as $i => $n ) {
+                        if ( 0 == strcasecmp( $n, $text ) ) { return $i; }
+                }
+               
+                // Consider Special: and Speciel: equal... which is preferred?
+                if ( 0 == strcasecmp( "speciel", $text ) ) { return -1; }
+                return false;
+        }
+
+        // inherit specialPage()
+
+        function getQuickbarSettings() {
+                global $wgQuickbarSettingsSv;
+                return $wgQuickbarSettingsSv;
+        }
+
+        function getSkinNames() {
+                global $wgSkinNamesSv;
+                return $wgSkinNamesSv;
+        }
+
+        function getUserToggles() {
+                global $wgUserTogglesSv;
+                return $wgUserTogglesSv;
+        }
+
+        function getLanguageNames() {
+                global $wgLanguageNamesSv;
+                return $wgLanguageNamesSv;
+        }
+
+        function getLanguageName( $code ) {
+                global $wgLanguageNamesSv;
+                if ( ! array_key_exists( $code, $wgLanguageNamesSv ) ) {
+                        return "";
+                }
+                return $wgLanguageNamesSv[$code];
+        }
+
+        function getMonthName( $key )
+        {
+                global $wgMonthNamesSv;
+                return $wgMonthNamesSv[$key-1];
+        }
+
+        function getMonthAbbreviation( $key )
+        {
+                global $wgMonthAbbreviationsSv;
+                return $wgMonthAbbreviationsSv[$key-1];
+        }
+
+        function getWeekdayName( $key )
+        {
+                global $wgWeekdayNamesSv;
+                return $wgWeekdayNamesSv[$key-1];
+        }
+
+        # Inherit userAdjust()
+
+        function date( $ts, $adj = false )
+        {
+                if ( $adj ) { $ts = $this->userAdjust( $ts ); }
+
+                $d = (0 + substr( $ts, 6, 2 )) . " " .
+                  $this->getMonthName( substr( $ts, 4, 2 ) ) . " " .
+                  substr( $ts, 0, 4 );
+                return $d;
+        }
+
+       // "." is used as the character to separate the
+       // hours from the minutes in the date output
+        function time( $ts, $adj = false )
+        {
+                if ( $adj ) { $ts = $this->userAdjust( $ts ); }
+
+                $t = substr( $ts, 8, 2 ) . "." . substr( $ts, 10, 2 );
+                return $t;
+        }
+
+        function timeanddate( $ts, $adj = false )
+        {
+                return $this->date( $ts, $adj ) . " kl." . $this->time( $ts, $adj );
+        }
+
+        function getValidSpecialPages()
+        {
+                global $wgValidSpecialPagesSv;
+                return $wgValidSpecialPagesSv;
+        }
+
+        function getSysopSpecialPages()
+        {
+                global $wgSysopSpecialPagesSv;
+                return $wgSysopSpecialPagesSv;
+        }
+
+        function getDeveloperSpecialPages()
+        {
+                global $wgDeveloperSpecialPagesSv;
+                return $wgDeveloperSpecialPagesSv;
+        }
+
+       function getMessage( $key )
+        {
+                global $wgAllMessagesSv;
+                if( array_key_exists( $key, $wgAllMessagesSv ) )
+                        return $wgAllMessagesSv[$key];
+                else
+                        return Language::getMessage($key);
+        }
+
+}
+
+?>
\ No newline at end of file
diff --git a/languages/LanguageZh.php b/languages/LanguageZh.php
new file mode 100644 (file)
index 0000000..767bf2c
--- /dev/null
@@ -0,0 +1,1156 @@
+<?
+global $IP;
+include_once( "$IP/Utf8Case.php" );
+
+# NOTE: To turn off "Current Events" in the sidebar,
+# set "currentevents" => "-"
+
+# The names of the namespaces can be set here, but the numbers
+# are magical, so don't change or move them!  The Namespace class
+# encapsulates some of the magic-ness.
+#
+/* private */ $wgNamespaceNamesZh = array(
+       -1      => "特殊", /* Special */
+       0       => "",
+       1       => "对话", /* Talk */
+       2       => "用户", /* User */
+       3       => "用户对话", /* User_talk */
+       4       => "Wikipedia", /* Wikipedia */
+       5       => "Wikipedia_对话", /* Wikipedia_talk */
+       6       => "图像", /* Image */
+       7       => "图像对话" /* Image_talk */
+);
+
+/* private */ $wgDefaultUserOptionsZh = array(
+       "quickbar" => 1, "underline" => 1, "hover" => 1,
+       "cols" => 80, "rows" => 25, "searchlimit" => 20,
+       "contextlines" => 5, "contextchars" => 50,
+       "skin" => 0, "rcdays" => 3, "rclimit" => 50,
+       "highlightbroken" => 1, "stubthreshold" => 0
+);
+
+/* private */ $wgQuickbarSettingsZh = array(
+       "无", /* "None" */ 
+       "左侧固定", /* "Fixed left" */ 
+       "右侧固定", /* "Fixed right" */ 
+       "左侧漂移" /* "Floating left" */ 
+);
+
+/* private */ $wgSkinNamesZh = array(
+       "标准",/* "Standard" */ 
+       "怀旧",/* "Nostalgia" */ 
+       "科隆香水蓝" /* "Cologne Blue" */ 
+);
+
+/* private */ $wgUserTogglesZh = array(
+       "hover"         => "滑过连接时显示注释",
+       "underline" => "下划连接",
+       "highlightbroken" => "高亮空白连接",
+       "justify"       => "段落对齐",
+       "hideminor" => "在最近更改页中隐藏细微修改",
+       "numberheadings" => "标题自动编号",
+       "rememberpassword" => "下次登录时记住密码",
+       "editwidth" => "编辑栏最大宽度",
+       "editondblclick" => "双击编辑页面(JavaScript)",
+        "watchdefault" => "Watch new and modified articles"
+);
+
+/* private */ $wgBookstoreListZh = array(
+       "AddALL" => "http://www.addall.com/New/Partner.cgi?query=$1&type=ISBN",
+       "PriceSCAN" => "http://www.pricescan.com/books/bookDetail.asp?isbn=$1",
+       "Barnes & Noble" => "http://shop.barnesandnoble.com/bookSearch/isbnInquiry.asp?isbn=$1",
+       "Amazon.com" => "http://www.amazon.com/exec/obidos/ISBN=$1"
+);
+
+/* private */ $wgLanguageNamesZh = array(
+       "aa"    => "Afar", /* 阿法尔语 */
+       "ab"    => "Abkhazian", /* 阿布哈西亚语 */
+       "af"    => "Afrikaans", /* 南非荷兰语 */
+       "am"    => "Amharic",/* 阿姆哈拉语 */
+       "ar"    => "&#8238;&#1575;&#1604;&#1593;&#1585;&#1576;&#1610;&#1577;&#8236;(Araby)", /* 阿拉伯语 */
+       "as"    => "Assamese", /* 阿萨姆语 */
+       "ay"    => "Aymara", /* 艾马拉语 */
+       "az"    => "Azerbaijani", /* 阿塞拜疆语 */
+       "ba"    => "Bashkir", /* 巴什基尔语 */
+       "be"    => "(&#1041;&#1077;&#1083;&#1072;&#1088;&#1091;&#1089;&#1082;&#1080;)", /* 白俄罗斯语 */
+       "bh"    => "Bihara", /* 比哈尔语 */
+       "bi"    => "Bislama", /* 比斯拉马语 */
+       "bn"    => "Bengali", /* 孟加拉语 */
+       "bo"    => "Tibetan", /* 藏语 */
+       "br"    => "Brezhoneg", /* 布列塔尼語 */
+       "ca"    => "Catal&#224;", /* 加泰罗尼亚语 */
+       "ch"    => "Chamoru", /* 查莫罗语 */
+       "co"    => "Corsican", /* 科西嘉语 */
+       "cs"    => "&#268;esk&#225;", /* 捷克语 */
+       "cy"    => "Cymraeg", /* 威尔士语 */
+       "da"    => "Dansk", # Note two different subdomains. /* 丹麦语 */
+       "dk"    => "Dansk", # 'da' is correct for the language. /* 丹麦语 */
+       "de"    => "Deutsch", /* 德语 */
+       "dz"    => "Bhutani", /* 不丹语 */
+       "el"    => "&#917;&#955;&#955;&#951;&#957;&#953;&#954;&#940;(Ellenika)",
+                /* 希腊语 */
+       "en"    => "English", /* 英语 */
+       "eo"    => "Esperanto",/* 世界语 */
+       "es"    => "Espa&#241;ol", /* 西班牙语 */
+       "et"    => "Eesti", /* 爱沙尼亚语 */
+       "eu"    => "Euskara", /* 巴斯克語 */
+       "fa"    => "&#8238;&#1601;&#1585;&#1587;&#1609;&#8236;(Farsi)",
+                /* 法尔西语 波斯语 */
+       "fi"    => "Suomi", /* 芬兰语 */
+       "fj"    => "Fijian", /* 斐济语 */
+       "fo"    => "Faeroese", /* 法罗语 */
+       "fr"    => "Fran&#231;ais", /* 法语 */
+       "fy"    => "Frysk", /* 弗里斯兰语 */
+       "ga"    => "Gaelige", /* 爱尔兰语 */
+       "gl"    => "Galician", /* 加利西亚语 */
+       "gn"    => "Guarani", /* 瓜拉尼语 */
+       "gu"    => "&#2711;&#2753;&#2716;&#2736;&#2750;&#2724;&#2752;(Gujarati)", 
+               /* 古吉拉特语 */
+       "ha"    => "Hausa", /* 豪萨语 */
+       "he"    => "&#1506;&#1489;&#1512;&#1497;&#1514;(Ivrit)",
+               /* 希伯来语 */
+       "hi"    => "&#2361;&#2367;&#2344;&#2381;&#2342;&#2368;(Hindi)",
+                /* 印地语 */
+       "hr"    => "Hrvatski", /* 克罗地亚语 */
+       "hu"    => "Magyar", /* 马札尔语 */
+       "hy"    => "Armenian", /* 亚美尼亚语 */
+       "ia"    => "Interlingua", /* 拉丁国际语 */
+       "id"    => "Indonesia", /* 印度尼西亚语 */
+       "ik"    => "Inupiak", /* Inupiak */
+       "is"    => "&#205;slenska", /* 冰岛语 */
+       "it"    => "Italiano", /* 意大利语 */
+       "iu"    => "Inuktitut",
+       "ja"    => "&#26085;&#26412;&#35486;(Nihongo)", /* 日本语 */
+       "jv"    => "Javanese", /* 爪哇语 */
+       "ka"    => "&#4325;&#4304;&#4320;&#4311;&#4309;&#4308;&#4314;&#4312;(Kartuli)", 
+                /* 格鲁吉亚语 */
+       "kk"    => "Kazakh", /* 哈萨克语 */
+       "kl"    => "Greenlandic", /* 格陵兰语 */
+       "km"    => "Cambodian", /* 柬埔寨语 */
+       "kn"    => "Kannada", /* 卡纳达语 */
+       "ko"    => "&#54620;&#44397;&#50612;(Hangukeo)",
+               /* 韩国语 */
+       "ks"    => "Kashmiri", /* 克什米尔语 */
+       "kw"    => "Kernewek", /* 康沃尔语 */
+       "ky"    => "Kirghiz", /* 吉尔吉斯语 (柯尔克孜语)*/
+       "la"    => "Latina", /* 拉丁语 */
+       "ln"    => "Lingala", /* 林加拉语 */
+       "lo"    => "Laotian", /* 老挝语 */
+       "lt"    => "Lietuvi&#371;", /* 立陶宛语 */
+
+       "lv"    => "Latvian", /* 拉脱维亚语 */
+       "mg"    => "Malagasy", /* 马尔加什语 */
+       "mi"    => "Maori", /* 毛利人 */
+       "mk"    => "Macedonian", /* 马其顿语 */
+       "ml"    => "Malayalam", /* 马拉雅拉姆语 ?德拉维语*/
+       "mn"    => "Mongolian", /* 蒙古语 */
+       "mo"    => "Moldavian", /* 摩尔多瓦语 */
+       "mr"    => "Marathi", /* 马拉地语 */
+       "ms"    => "Bahasa Melayu", /* 马来语 */
+       "my"    => "Burmese", /* 缅甸语 */
+       "na"    => "Nauru", /* 瑙鲁语 */
+       "ne"    => "&#2344;&#2375;&#2346;&#2366;&#2354;&#2368;(Nepali)",
+                /* 尼泊尔语 */
+       "nl"    => "Nederlands", /* 荷兰语 */
+       "no"    => "Norsk", /* 挪威语 */
+       "oc"    => "Occitan", /* 奥克语 */
+       "om"    => "Oromo", /* 奥罗莫语 */
+       "or"    => "Oriya", /* 奥里亚语 */
+       "pa"    => "Punjabi", /* 旁遮普语 */
+       "pl"    => "Polski", /* 波兰语 */
+       "ps"    => "Pashto", /* 普什图语 */
+       "pt"    => "Portugu&#234;s", /* 葡萄牙语 */
+       "qu"    => "Quechua", /* 盖丘亚语 */
+       "rm"    => "Rhaeto-Romance", /* Rhaeto-Romance */
+       "rn"    => "Kirundi", /* 基隆迪语 */
+       "ro"    => "Rom&#226;n&#259;", /* 罗马尼亚语 */
+       "ru"    => "&#1056;&#1091;&#1089;&#1089;&#1082;&#1080;&#1081;(Russkij)",
+                /*  俄语 */
+       "rw"    => "Kinyarwanda",
+       "sa"    => "&#2360;&#2306;&#2360;&#2381;&#2325;&#2371;&#2340;(Samskrta)",
+                /* 梵语 */
+       "sd"    => "Sindhi", /* 信德语 */
+       "sg"    => "Sangro", /* 桑戈语 */
+       "sh"    => "Serbocroatian", /* 塞尔维亚-克罗地亚语 */
+       "si"    => "Sinhalese", /* 僧伽罗语 */
+       "simple"=> "Simple English", /* 简单英语 */
+       "sk"    => "Slovak", /* 斯洛伐克语 */
+       "sl"    => "Slovensko", /* 斯洛文尼亚语 */
+       "sm"    => "Samoan", /* 萨摩亚语 */
+       "sn"    => "Shona", /* 绍纳语 */
+       "so"    => "Soomaali", /* 索马里语 */
+       "sq"    => "Shqiptare", /* 阿尔巴尼亚 */
+       "sr"    => "Srpski", /* 塞尔维亚语 */
+       "ss"    => "Siswati", /* 西斯瓦提语 */
+       "st"    => "Sesotho", /* 塞索托语 */
+       "su"    => "Sudanese", /* 苏丹语 */
+       "sv"    => "Svenska", /* 瑞典语 */
+       "sw"    => "Kiswahili", /* 斯瓦希里语 */
+       "ta"    => "Tamil", /* 泰米尔语 */
+       "te"    => "Telugu", /* 泰卢固语 */
+       "tg"    => "Tajik", /* 塔吉克语 */
+       "th"    => "Thai", /* 泰国语 */
+       "ti"    => "Tigrinya", /* 提格里尼亚语 */
+       "tk"    => "Turkmen", /* 土库曼语 */
+       "tl"    => "Tagalog", /* 塔加路语 */
+       "tn"    => "Setswana", /* 茨瓦纳语 */
+       "to"    => "Tonga", /* 汤加语 */
+       "tr"    => "T&#252;rk&#231;e", /* 土耳其语 */
+       "ts"    => "Tsonga", /* 通加语 ?聪加语*/
+       "tt"    => "Tatar", /* 鞑靼语 */
+       "tw"    => "Twi", /* 特威语 ?契维、特维*/
+       "ug"    => "Uighur", /* 维吾尔语 */
+       "uk"    => "&#1059;&#1082;&#1088;&#1072;&#1111;&#1085;&#1089;&#1100;&#1082;&#1072;(Ukrayins`ka)", 
+               /*  乌克兰语 */
+       "ur"    => "Urdu", /* 乌尔都语 */
+       "uz"    => "Uzbek", /* 乌兹别克语 */
+       "vi"    => "Vietnamese", /* 越南语 */
+       "vo"    => "Volap&#252;k", /* 沃拉卜克语?佛拉普克语 */
+       "wo"    => "Wolof", /* 沃洛夫语 */
+       "xh"    => "isiXhosa", /* 科萨语 */
+       "yi"    => "Yiddish", /* 意第绪语 */
+       "yo"    => "Yoruba", /* 约鲁巴语 */
+       "za"    => "Zhuang", /* 壮语 ? */
+       "zh"    => "中文(Zhongwen)", /* Zhongwen */
+       "zu"    => "Zulu" /* 祖鲁语 */
+);
+
+/* private */ $wgWeekdayNamesZh = array(
+       "星期日", "星期一", "星期二", "星期三", "星期四",
+       "星期五", "星期六"
+);
+
+/* private */ $wgMonthNamesZh = array(
+       "1月", "2月", "3月", "4月", "5月", "6月",
+       "7月", "8月", "9月", "10月", "11月",
+       "12月"
+);
+
+/* private */ $wgMonthAbbreviationsZh = array(
+       "1月", "2月", "3月", "4月", "5月", "6月",
+       "7月", "8月", "9月", "10月", "11月",
+       "12月"
+);
+
+# All special pages have to be listed here: a description of ""
+# will make them not show up on the "Special Pages" page, which
+# is the right thing for some of them (such as the "targeted" ones).
+#
+/* private */ $wgValidSpecialPagesZh = array(
+       "Userlogin"     => "",
+       "Userlogout"    => "",
+       "Preferences"   => "我的设置", /* Set my user preferences */
+       "Watchlist"     => "监视列表", /* My watchlist */
+       "Recentchanges" => "最近更改",  /* Recently updated pages */
+       "Upload"        => "上载图像",  /* Upload image files */
+       "Imagelist"     => "图像列表",  /* Image list */
+       "Listusers"     => "注册用户",  /* Registered users */
+       "Statistics"    => "站点统计",  /* Site statistics */
+       "Randompage"    => "随机条目",  /* Random article */
+
+       "Lonelypages"   => "孤立条目",  /* Orphaned articles */
+       "Unusedimages"  => "孤立图像",  /* Orphaned images */
+       "Popularpages"  => "热点条目",  /* Popular articles */
+       "Wantedpages"   => "待撰页面",  /* Most wanted articles */
+       "Shortpages"    => "短条目",  /* Short articles */
+       "Longpages"     => "长条目",  /* Long articles */
+       "Newpages"      => "新条目",  /* Newly created articles */
+       "Allpages"      => "所有条目",  /* All pages by title */
+
+       "Ipblocklist"   => "被封 IP 地址",  /* Blocked IP addresses */
+       "Maintenance"   => "维护页",  /* Maintenance page */
+       "Specialpages"  => "", /* Next few intentionally left blank! 特殊页面 */
+       "Contributions" => "", /* 参与者 */
+       "Emailuser"     => "", /* 给用户发信 */
+       "Whatlinkshere" => "", /* 链入页面 */
+       "Recentchangeslinked" => "", /* 近期链出页面更改 */
+       "Movepage"      => "", /* 移动页面 */
+       "Booksources"   => "站外书源"  /* External book sources */
+);
+
+/* private */ $wgSysopSpecialPagesZh = array(
+       "Blockip"       => "禁封一个 IP 地址",  /* Block an IP address */
+       "Asksql"        => "查询数据库",  /* Query the database */
+       "Undelete"      => "查看并恢复被删页面"
+        /* View and restore deleted pages */
+);
+
+/* private */ $wgDeveloperSpecialPagesZh = array(
+       "Lockdb"        => "使数据库只读",  /* Make database read-only */
+       "Unlockdb"      => "恢复数据库写操作",  /* Restore database write access */
+       "Debug"         => "调试信息"  /* Debugging information */
+);
+
+/* private */ $wgAllMessagesZh = array(
+
+# Bits of text used by many pages:
+#
+"linktrail"    => "/^([a-z]+)(.*)\$/sD",
+"mainpage"     => "首页", /* Main Page */
+"about"                => "关于", /* About */
+"aboutwikipedia" => "关于 Wikipedia", /* About Wikipedia */
+"aboutpage"    => "Wikipedia:关于", /*  */
+"help"         => "帮助", /* Help */
+"helppage"     => "Wikipedia:帮助", /* Wikipedia:Help */
+"wikititlesuffix" => "Wikipedia", /* Wikipedia */
+"bugreports"   => "错误报告", /* Bug reports */
+"bugreportspage" => "Wikipedia:错误报告", /*  */
+"faq"          => "常见问题解答", /* FAQ */
+"faqpage"      => "Wikipedia:常见问题解答", /* Wikipedia:FAQ */
+"edithelp"     => "编辑帮助", /* Editing help */
+"edithelppage" => "Wikipedia:如何编辑页面", /* Wikipedia:How_does_one_edit_a_page */
+"cancel"       => "取消", /* Cancel */
+"qbfind"       => "查找", /* Find */
+"qbbrowse"     => "浏览", /* Browser */
+"qbedit"       => "编辑", /* Edit */
+"qbpageoptions" => "页面设置", /* Page options */
+"qbpageinfo"   => "页面信息", /* Page info */
+"qbmyoptions"  => "我的设置", /* My options */
+"mypage"       => "我的页面", /* My page */
+"mytalk"       => "我的对话", /* My talk */
+"currentevents" => "新闻动态", /* Current events */
+"errorpagetitle" => "错误", /* Error */
+"returnto"     => "返回到 $1 ", /* Return to $1. */
+"fromwikipedia"        => "Wikipedia ,自由的百科全书。", /* From Wikipedia, the free encyclopedia. */
+"whatlinkshere"        => "链到本页的页面", /* Pages that link here */
+"help"         => "帮助", /* Help */
+"search"       => "搜索", /* Search */
+"history"      => "修订历史", /* History */
+"printableversion" => "可打印版", /* Printable version */
+"editthispage" => "编辑页面", /* Edit this page */
+"deletethispage" => "删除页面", /* Delete this page */
+"protectthispage" => "保护页面", /* Protect this page */
+"unprotectthispage" => "免除保护", /* Unprotect this page */
+"talkpage"     => "对话页", /* Talk page */
+"subjectpage"  => "主题页", /* Subject page */
+"otherlanguages" => "其它语言", /* Other languages */
+"redirectedfrom" => "(重新定向自 $1 )", /* (Redirected from $1) */
+"lastmodified" => "最后更改于 $1。", /* The page was last modified $1. */
+"viewcount"    => "页面已被浏览 $1 次", /* This page has been accessed $1 times. */
+"printsubtitle" => "(自 http://zh.wikipedia.org )", /* (From http://www.wikipedia.org) */
+"protectedpage" => "被保护页", /* Protected page */
+"administrators" => "Wikipedia:管理员", /* Wikipedia:Administrators */
+"sysoptitle"   => "需要 sysop 权限", /* Sysop access required */
+"sysoptext"    => "您请求的命令只能被拥有 \"sysop\" 权限的用户执行。请参见 $1 。",
+/* The action you have requested can only be performed by users with \"sysop\" status.See $1. */
+"developertitle" => "需要 developer 权限", /* Developer access required */
+"developertext"        => "您请求的命令只能被拥有 \"developer\" 权限的用户执行。请参见 $1 。",
+/* The action you have requested can only be performed by users with \"developer\" status. See $1.*/
+"nbytes"       => "$1 字节", /* $1 bytes */
+"go"           => "进入", /* Go */
+"ok"           => "确定", /* OK */
+"sitetitle"    => "Wikipedia", /* Wikipedia */
+"sitesubtitle" => "自由的百科全书", /* The Free Encyclopedia */
+"retrievedfrom" => "取自 \"$1\"", /* Retrieved from \"$1\" */
+
+# Main script and global functions
+#
+"nosuchaction" => "没有这个命令。", /* No such action */
+"nosuchactiontext" => "URL 请求的命令无法被 Wikipedia 软件识别。",
+/* The action specified by the URL is not recognized by the Wikipedia software */
+"nosuchspecialpage" => "没有这个特殊页。", /* No such special page */
+"nospecialpagetext" => "您请求的页面无法被 Wikipedia 软件识别。",
+/* You have requested a special page that is not recognized by the Wikipedia software. */
+
+# General errors
+#
+"error"                        => "错误",
+"databaseerror" => "数据库错误",
+"dberrortext"  => "数据库指令语法错误。
+这可能是由于非法搜索指令所引起的(见 $5),
+也可能是由于软件自身的错误所引起。
+最后一次数据库指令是:
+<blockquote><tt>$1</tt></blockquote>
+来自于函数 \"<tt>$2</tt>\".
+MySQL返回错误 \"<tt>$3: $4</tt>\".",
+"noconnect"    => "无法在 $1上连接数据库",
+"nodb"         => "无法选择数据库 $1",
+"readonly"     => "数据库禁止访问",
+"enterlockreason" => "请输入禁止访问原因, 包括估计重新开放的时间",
+"readonlytext" => "Wikipedia数据库目前禁止输入新内容及更改,
+这很可能是由于数据库正在维修,之后即可恢复。
+管理员有如下解释:
+<p>$1",
+"missingarticle" => "数据库找不到文字\"$1\".
+这不是一个数据库错误,而可能是由于软件错误所引起。
+请将情况连同URL告知管理员。",
+"internalerror" => "内部错误",
+"filecopyerror" => "无法复制文件\"$1\"到\"$2\".",
+"filerenameerror" => "无法重命名文件\"$1\" 到\"$2\".",
+"filedeleteerror" => "无法删除文件 \"$1\".",
+"filenotfound" => "找不到文件 \"$1\".",
+"unexpected"   => "不正常值: \"$1\"=\"$2\".",
+"formerror"            => "错误: 无法提交表单",        
+"badarticleerror" => "This action cannot be performed on this page.",
+"cannotdelete" => "无法删除选定页或图像.",
+"badtitle"      => "错误的标题", /* Bad title */
+"badtitletext" => "所请求页面的标题是无效的或者不存在,或者是错误的跨语言链接标题。",
+/* The requested page title was invalid, empty, or an incorrectly linked inter-language or inter-wiki title. */
+
+# Login and logout pages
+#
+"logouttitle"  => "用户退出",
+"logouttext"   => "你现在已经退出.
+你可以继续以匿名方式使用Wikipeida,或再次以相同或不同用户身份登录。\n",
+
+"welcomecreation" => "<h2>欢迎, $1!</h2><p>你的帐号已经建立,不要忘记设置Wikipedia个人参数。",
+
+"loginpagetitle" => "用户登录",
+"yourname"     => "用户名",
+"yourpassword" => "密码",
+"yourpasswordagain" => "重复密码",
+"newusersonly" => " (仅限新用户)",
+"remembermypassword" => "下次登录记住密码.",
+"loginproblem" => "<b>登录有问题。</b><br>再试一次!",
+"alreadyloggedin" => "<font color=red><b> $1, 你已经登录了!</b></font><br>\n",
+
+"areyounew"    => "如果你是Wikipedia的新用户并想得到一个用户帐号,
+请输入用户名,然后重复输入密码两次。
+你可以选择输入电子邮件地址; 这样如果你忘了密码时可以要求将密码寄往你所输入的地址。<br>\n",
+
+"login"                => "登录",
+"userlogin"    => "用户登录",
+"logout"       => "退出",
+"userlogout"   => "用户退出",
+"createaccount"        => "建立新帐号",
+"badretype"    => "你所输入的密码并不相同。",
+"userexists"   => "你所输入的用户名已有人使用。请另选一个。",
+
+"youremail"    => "电子邮件",
+"yournick"     => "绰号 (签名时用)",
+"emailforlost" => "如果你忘了你的密码, 你可以得到一个寄往你的电子邮件地址的新密码。",
+"loginerror"   => "登录错误",
+"noname"       => "你没有输入一个有效的用户名。",
+"loginsuccesstitle" => "登录成功",
+"loginsuccess" => "你现在以 \"$1\"的身份登录Wikipedia。",
+"nosuchuser"   => "找不到用户 \"$1\".
+检查是否输入错误,或使用下面的表单创建新帐号。",
+"wrongpassword"        => "你所输入的密码错误。请再试一次。",
+"mailmypassword" => "请将密码寄给我。",
+"passwordremindertitle" => "Wikipedia密码提醒",
+"passwordremindertext" => "有人 (可能是你, 来自 IP 地址 $1)要求我们将新的Wikipedia登录密码寄给你。
+用户 \"$2\" 的密码现在是 \"$3\".
+请立即登录并更改密码。",
+"noemail"      => "用户\"$1\"没有登记电子邮件地址。",
+"passwordsent" => "用户\"$1\"的新密码已经寄往所登记的电子邮件地址。
+请在收到后再登录。",
+
+# Edit pages
+#
+"summary"      => "简述",
+"minoredit"    => "这是一个细微修改",
+"savearticle"  => "保存页面",
+"preview"      => "预览",
+"showpreview"  => "显示预览",
+"blockedtitle" => "用户被封",
+"blockedtext"  => "你的用户名或IP地址已被$1封。
+理由是:<br>$2<p>你可以联系管理员讨论。",
+"newarticle"   => "(新)",
+"newarticletext" => "在这里输入新页面内容。",
+"noarticletext" => "(本页目前没有文字)",
+"updated"      => "(更新)",
+"note"         => "<strong>注意:</strong> ",
+"previewnote"  => "请记住这只是预览,内容还未保存!",
+"previewconflict" => "这个预览显示了上面文字编辑区中的内容。它将在你选择保存后出现。",
+"editing"      => "正在编辑$1",
+"editconflict" => "编辑冲突: $1",
+"explainconflict" => "有人在你开始编辑后更改了页面。
+上面的文字框内显示的是目前本页的内容。
+你所做的修改显示在下面的文字框中。
+你应当将你所做的修改加入现有的内容中。
+<b>只有</b>在上面文字框中的内容会在你点击\"保存页面\"后被保存。\n<p>",
+"yourtext"     => "你的文字",
+"storedversion" => "已保存版本",
+"editingold"   => "<strong>警告:你正在编辑的是本页的旧版本。
+如果你保存它的话,在本版本之后的任何修改都会丢失。</strong>\n",
+"yourdiff"     => "不同",
+"copyrightwarning" => "请注意对Wikipedia的任何贡献都将被认为是在GNU自由文档协议证书下发布。
+(细节请见$1).
+如果你不希望你的文字被任意修改和再散布,请不要提交。<br>
+你同时也向我们保证你所提交的内容是你自己所作,或得自一个不受版权保护或相似自由的来源。
+<strong>不要在未获授权的情况下发表!</strong>",
+/* You are also promising us that you wrote this yourself, or copied it from a
+public domain or similar free resource. */
+
+# History pages
+#
+"revhistory"   => "修订历史", /* Revision history */
+"nohistory"    => "没有本页的修订记录。",
+/* There is no edit history for this page. */
+"revnotfound"  => "没有找到修订记录", /* Revision not found */
+"revnotfoundtext" => "您请求的更早版本的修订记录没有找到。请检查您请求本页面用的 URL 是否正确。\n",
+/* The old revision of the page you asked for could not be found.Please check the URL you used to access this page.\n */
+"loadhist"     => "载入页面修订历史", /* Loading page history */
+"currentrev"   => "Current revision", /* 当前修订版本 */
+"revisionasof" => "$1 的修订版本", /* Revision as of $1 */
+"cur"          => "当前", /* cur */
+"next"         => "后继", /* next */
+"last"         => "先前", /* last */
+"orig"         => "初始", /* orig */
+"histlegend"   => "说明:(当前)指与当前修订版本比较;(先前)指与前一个修订版本比较,小 指细微修改。",
+/* Legend: (cur) = difference with current version,
+(last) = difference with preceding version, M = minor edit */
+
+# Diffs
+#
+"difference"   => "(修订版本间差异)", /* Difference between revisions */
+"loadingrev"   => "载入修订版本比较", /* loading revision for diff */
+"lineno"       => "第 $1 行:", /* Line $1:",  */
+"editcurrent"  => "编辑本页的当前修订版本",
+/* Edit the current version of this page */
+
+# Search results
+#
+"searchresults" => "Search results",
+"searchhelppage" => "Wikipedia:Searching",
+"searchingwikipedia" => "Searching Wikipedia",
+"searchresulttext" => "For more information about searching Wikipedia, see $1.",
+"searchquery"  => "For query \"$1\"",
+"badquery"             => "Badly formed search query",
+"badquerytext" => "We could not process your query.
+This is probably because you have attempted to search for a
+word fewer than three letters long, which is not yet supported.
+It could also be that you have mistyped the expression, for
+example \"fish and and scales\".
+Please try another query.",
+"matchtotals"  => "The query \"$1\" matched $2 article titles
+and the text of $3 articles.",
+"titlematches" => "Article title matches",
+"notitlematches" => "No article title matches",
+"textmatches"  => "Article text matches",
+"notextmatches"        => "No article text matches",
+"prevn"                => "previous $1",
+"nextn"                => "next $1",
+"viewprevnext" => "View ($1) ($2) ($3).",
+"showingresults" => "Showing below <b>$1</b> results starting with #<b>$2</b>.",
+"nonefound"            => "<strong>Note</strong>: unsuccessful searches are
+often caused by searching for common words like \"have\" and \"from\",
+which are not indexed, or by specifying more than one search term (only pages
+containing all of the search terms will appear in the result).",
+"powersearch" => "Search",
+"powersearchtext" => "
+Search in namespaces :<br>
+$1<br>
+$2 List redirects &nbsp; Search for $3 $9",
+
+
+# Preferences page
+#
+"preferences"  => "参数设置",
+"prefsnologin" => "还未登录",
+"prefsnologintext" => "你必须先<a href=\"" .
+  wfLocalUrl( "Special:Userlogin" ) . "\">登录</a>才能设置个人参数。",
+"prefslogintext" => "你已经以\"$1\"的身份登录。
+你的内部ID是$2.",
+"prefsreset"   => "参数重新设置。",
+"qbsettings"   => "快速导航条设置", 
+"changepassword" => "更改密码",
+"skin"         => "Skin",
+"saveprefs"    => "保存参数设置",
+"resetprefs"   => "重设参数",
+"oldpassword"  => "旧密码",
+"newpassword"  => "新密码",
+"retypenew"    => "重复新密码",
+"textboxsize"  => "文字框尺寸",
+"rows"         => "行",
+"columns"      => "列",
+"searchresultshead" => "搜索结果设定",
+"resultsperpage" => "每页显示连接数",
+"contextlines" => "每连接行数",
+"contextchars" => "每行字数",
+"stubthreshold" => "Threshold for stub display",
+"recentchangescount" => "最近更改页行数",
+"savedprefs"   => "你的个人参数设置已经保存。",
+"timezonetext" => "输入当地时间与服务器时间(UTC)的时差。",
+"localtime"    => "当地时间",
+"timezoneoffset" => "差",
+"emailflag"    => "禁止其他用户发e-mail给我",
+
+# Recent changes
+#
+
+"recentchanges" => "最近更改", /* Recent changes */
+
+"recentchangestext" =>
+"本页用来察看 Wikipedia 最近的更改。
+请参看[[wikipedia:欢迎,新来者|欢迎,新来者]]、
+[[wikipedia:常见问题解答|常见问题解答]]、
+[[Wikipedia:守则与指导|参与者守则与指导]]
+(特别是[[Wikipedia:命名常规|命名常规]]、[[Wikipedia:中性的观点|中性的观点]])
+和[[Wikipedia:最常见失礼行为|最常见失礼行为]]。
+
+如果您希望 Wikipedia 成功,那么请您不要增加受其它[[wikipedia:版权信息|版权]]
+限制的材料,这一点将非常重要。相关的法律责任会伤害本项工程,所以请不要这样做。
+此外请参见
+[http://meta.wikipedia.org/wiki/Special:Recentchanges 最近的 meta 讨论]。
+",
+/*
+Track the most recent changes to Wikipedia on this page.
+[[Wikipedia:Welcome,_newcomers|Welcome, newcomers]]!
+Please have a look at these pages: [[wikipedia:FAQ|Wikipedia FAQ]],
+[[Wikipedia:Policies and guidelines|Wikipedia policy]]
+(especially [[wikipedia:Naming conventions|naming conventions]],
+[[wikipedia:Neutral point of view|neutral point of view]]),
+and [[wikipedia:Most common Wikipedia faux pas|most common Wikipedia faux pas]].
+
+If you want to see Wikipedia succeed, it's very important that you don't add
+material restricted by others' [[wikipedia:Copyrights|copyrights]].
+The legal liability could really hurt the project, so please don't do it.
+See also the [http://meta.wikipedia.org/wiki/Special:Recentchanges recent meta discussion].
+*/
+
+"rcloaderr"    => "载入最近更改", /* Loading recent changes */
+"rcnote"       => "下面是最近 <strong>$2</strong> 天内最新的 <strong>$1</strong> 次改动。",
+/* Below are the last <strong>$1</strong> changes in last <strong>$2</strong> days. */
+# "rclinks"    => "Show last $1 changes in last $2 hours / last $3 days",
+"rclinks"      => "显示最近 $2 天内最新的 $1 次改动。",
+/* Show last $1 changes in last $2 days. */
+"rchide"       => "in $4 form; $1 minor edits; $2 secondary namespaces; $3 multiple edits.",
+/* in $4 form; $1 minor edits; $2 secondary namespaces; $3 multiple edits. */
+"diff"         => "差异", /* diff */
+"hist"         => "历史", /* hist */
+"hide"         => "隐藏", /* hide */
+"show"         => "显示", /* show */
+"tableform"    => "表格", /* table */
+"listform"     => "列表", /* list */
+"nchanges"     => "$1 次更改", /* $1 changes */
+"minoreditletter" => "小", /* M */
+"newpageletter" => "新", /* N */
+
+# Upload
+#
+"upload"       => "上载", /* Upload */
+"uploadbtn"    => "上载文件",
+"uploadlink"   => "上载图像",
+"reupload"     => "重新上载",
+"reuploaddesc" => "返回上载表单。",
+"uploadnologin" => "未登录",
+"uploadnologintext"    => "您必须先<a href=\"" .
+  wfLocalUrl( "Special:Userlogin" ) . "\">登录</a>
+才能上载文件。",
+"uploadfile"   => "上载文件",
+"uploaderror"  => "上载错误",
+"uploadtext"   => "<strong>停止!</strong>在您上载之前,请先阅读并遵守Wikipedia<a href=\"" .
+wfLocalUrlE( "Wikipedia:Image_use_policy" ) . "\">图像使用守则</a>。
+<p>如果您要查看或搜索之前上载的图像,
+请到<a href=\"" . wfLocalUrlE( "Special:Imagelist" ) .
+"\">已上载图像列表</a>.
+所有上载与删除行为都被记录在<a href=\"" .
+wfLocalUrlE( "Wikipedia:上载纪录" ) . "\">上载纪录</a>内。
+<p>使用下面的表单来上载用在条目内新的图像文件。
+在绝大多数浏览器内,你会看到一个\"浏览...\"按钮,点击它后就会跳出一个打开文件对话框。
+选择一个文件后文件名将出现在按钮旁边的文字框中。
+您也必须点击旁边的复选框确认您所上载的文件并没有违反相关版权法律。
+点击\"上载\" 按钮完成上载程序。
+如果您使用的是较慢的网络连接的话那么这个上载过程会需要一些时间。
+<p>我们建议照相图片使用JPEG格式,绘图及其他图标图像使用PNG格式,音像则使用OGG格式。
+请使用具有描述性的语言来命名您的文件以避免混乱。
+要在文章中加入图像,使用以下形式的连接:
+<b>[[图像:file.jpg]]</b>或者<b>[[图像:file.png|解释文字]]</b>
+或<b>[[media:file.ogg]]</b>来连接音像文件。
+<p>请注意在Wikipedia页面中,其他人可能会为了百科全书的利益而编辑或删除您的上载文件,
+而如果您滥用上载系统,您则有可能被禁止使用上载功能。",
+"uploadlog"            => "上载纪录",
+"uploadlogpage" => "上载纪录",
+"uploadlogpagetext" => "以下是最近上载的文件的一览表。
+所有显示的时间都是服务器时间(UTC)。
+<ul>
+</ul>
+",
+"filename"     => "文件名",
+"filedesc"     => "简述",
+"affirmation"  => "我保证本文件的版权持有人同意将其在$1条款下发布。",
+"copyrightpage" => "Wikipedia:版权信息",
+"copyrightpagename" => "Wikipedia版权",
+"uploadedfiles"        => "已上载文件",
+"noaffirmation" => "您必须保证您所上载的文件没有违反任何版权法律。",
+"ignorewarning"        => "忽略警告并保存文件。",
+"minlength"            => "图像名字必须至少有三个字母。",
+"badfilename"  => "图像名已被改为\"$1\".",
+"badfiletype"  => "\".$1\"不是所推荐的图像文件格式。",
+"largefile"            => "我们建议图像大小不超过100k。",
+"successfulupload" => "上载成功",
+"fileuploaded" => "文件\"$1\"上载成功。
+请根据连接($2)到图像描述页添加有关文件信息,例如它的来源,在何时由谁创造,
+以及其他任何您知道的关于改图像的信息。",
+"uploadwarning" => "上载警告",
+"savefile"             => "保存文件",
+"uploadedimage" => "已上载\"$1\"",
+
+# Image list
+#
+"imagelist"            => "图像列表",
+"imagelisttext"        => "以下是$1幅图像。",
+"getimagelist" => "正在获取图像列表",
+"ilshowmatch"  => "显示所有匹对的图像",
+"ilsubmit"             => "搜索",
+"showlast"             => "显示最后$1幅图像。",
+"all"                  => "全部",
+"byname"               => "按名字",
+"bydate"               => "按日期",
+"bysize"               => "按大小",
+"imgdelete"            => "删",
+"imgdesc"              => "述",
+"imglegend"            => "图标:(述) = 显示/编辑图像描述页。",
+"imghistory"   => "图像历史",
+"revertimg"            => "恢复rev",
+"deleteimg"            => "删",
+"imghistlegend" => "Legend: (现) = 目前的图像,(删) = 删除旧版本,
+(恢复) = 恢复到旧版本。
+<br><i>点击日期查看当天上载的图像</i>.",
+"imagelinks"   => "图像连接",
+"linkstoimage" => "以下页面连接到本图像:",
+"nolinkstoimage" => "没有页面连接到本图像.",
+
+# Statistics
+# 统计
+#
+
+"statistics"   => "统计", /* Statistics */
+"sitestats"            => "站点统计", /* Site statistics */
+"userstats"            => "用户统计", /* User statistics */
+
+"sitestatstext" => "数据库中共有 <b>$1</b> 页页面;
+其中包括对话页、关于 Wikipedia 的页面、最少量的\"stub\"页、重定向的页面,
+以及未达到条目质量的页面;除此之外还有 <b>$2</b> 页可能是合乎标准的条目。
+<p>从系统软件升级( 2002 年 10 月 27 日)以来,全站点共有页面浏览 <b>$3</b> 次,
+页面编辑 <b>$4</b> 次,每页平均编辑 <b>$5</b> 次,
+各次编辑后页面的每个版本平均浏览 <b>$6</b> 次。",
+/* There are <b>$1</b> total pages in the database.
+This includes \"talk\" pages, pages about Wikipedia, minimal \"stub\"
+pages, redirects, and others that probably don't qualify as articles.
+Excluding those, there are <b>$2</b> pages that are probably legitimate
+articles.<p>There have been a total of <b>$3</b> page views, and <b>$4</b> page edits since the software was upgraded (July 20, 2002). That comes to <b>$5</b> average edits per page, and <b>$6</b> views per edit. */
+
+"userstatstext" => "现有 <b>$1</b> 位注册用户,
+其中 <b>$2</b> 位是管理员(参见 $3 )。",
+/* There are <b>$1</b> registered users.<b>$2</b> of these are administrators (see $3). */
+
+
+# Maintenance Page
+#
+"maintenance"          => "维护页",
+"maintnancepagetext"   => "这页面提供了几个帮助Wikipedia日常维护的工具。但其中几个会对我们的数据库造成压力,所以请您不要在每修理好几个项目后就按重新载入 ;-)",
+"maintenancebacklink"  => "回去维护页",
+"disambiguations"      => "消含糊页",
+"disambiguationspage"  => "Wikipedia:Links_to_disambiguating_pages",
+"disambiguationstext"  => "以下的条目都有到消含糊页的链接,但它们应该是链到适当的题目。<br>一个页面会被视为消含糊页如果它是链自$1.<br>由其它他名字空间来的链接<i>不会</i>在这儿被列出来。",
+"doubleredirects"      => "雙重重定向",
+"doubleredirectstext"  => "<b>请注意:</b>这列表可能包括不正确的反应。这通常表示在那页面第一个#REDIRECT之下还有文字。<br>\n每一行都包含到第一跟第二个重定向页的链接,以及第二个重定向页的第一行文字,通常显示的都会是\“真正\” 的目标页面,也就是第一个重定向页应该指向的条目。",
+"brokenredirects"      => "损坏的重定向页",
+"brokenredirectstext"  => "以下的重定向页指向的是不存在的条目。",
+"selflinks"            => "有自我链接的页面",
+"selflinkstext"                => "以下的页面都错误地包含了连到自己的链接。",
+"mispeelings"           => "Pages with misspellings",
+"mispeelingstext"               => "The following pages contain a common misspelling, which are listed on $1. The correct spelling might be given (like this).",
+"mispeelingspage"       => "List of common misspellings",
+"missinglanguagelinks"  => "Missing Language Links",
+"missinglanguagelinksbutton"    => "Find missing language links for",
+"missinglanguagelinkstext"      => "These articles do <i>not</i> link to their counterpart in $1. Redirects and subpages are <i>not</i> shown.",
+
+
+# Miscellaneous special pages
+#
+"orphans"      => "孤立页面", /* Orphaned pages */
+"lonelypages"  => "孤立页面", /* Orphaned pages */
+"unusedimages" => "未用图像", /* Unused images */
+"popularpages" => "热点条目", /* Popular pages */
+"nviews"       => "$1 次浏览", /* $1 views */
+"wantedpages"  => "待撰页面", /* Wanted pages */
+"nlinks"       => "$1 个链接", /* $1 links */
+"allpages"     => "所有条目", /* All pages */
+"randompage"   => "随机页面", /* Random page */
+"shortpages"   => "短条目", /* Short pages */
+"longpages"    => "长条目", /* Long pages */
+"listusers"    => "用户列表", /* User list */
+"specialpages" => "特殊页面", /* Special pages */
+"spheading"    => "特殊页面", /* Special pages */
+"sysopspheading" => "Special pages for sysop use", /* Special pages for sysop use */
+"developerspheading" => "Special pages for developer use", /* Special pages for developer use */
+"protectpage"  => "保护页面", /* Protect page */
+"recentchangeslinked" => "链出更改", /* Watch links */
+"rclsub"       => "(从 \"$1\"链出的页面)", /* to pages linked from \"$1\") */
+"debug"                => "调试", /* Debug */
+"newpages"     => "新页面", /* New pages */
+"movethispage" => "移动页面", /* Move this page */
+"unusedimagestext" => "<p>Please note that other web sites
+such as the international Wikipedias may link to an image with
+a direct URL, and so may still be listed here despite being
+in active use.", /*  */
+"booksources"  => "书目来源", /* Book sources */
+"booksourcetext" => "Below is a list of links to other sites that
+sell new and used books, and may also have further information
+about books you are looking for.
+Wikipedia is not affiliated with any of these businesses, and
+this list should not be construed as an endorsement.", 
+/*  */
+
+# Email this user
+#
+"mailnologin"  => "No send address",
+"mailnologintext" => "You must be <a href=\"" .
+  wfLocalUrl( "Special:Userlogin" ) . "\">logged in</a>
+and have a valid e-mail address in your <a href=\"" .
+  wfLocalUrl( "Special:Preferences" ) . "\">preferences</a>
+to send e-mail to other users.",
+"emailuser"    => "给用户发信", /* E-mail this user */
+"emailpage"    => "E-mail user",
+"emailpagetext"        => "If this user has entered a valid e-mail address in
+is user preferences, the form below will send a single message.
+The e-mail address you entered in your user preferences will appear
+as the \"From\" address of the mail, so the recipient will be able
+to reply.",
+"noemailtitle" => "No e-mail address",
+"noemailtext"  => "This user has not specified a valid e-mail address,
+or has chosen not to receive e-mail from other users.",
+"emailfrom"    => "发件人", /* From*/
+"emailto"      => "收件人", /* To*/
+"emailsubject" => "主题", /* Subject */
+"emailmessage" => "正文", /* Message */
+"emailsend"    => "发送", /* Send */
+"emailsent"    => "邮件发送", /* E-mail sent */
+"emailsenttext" => "您的邮件已经被发送",
+/* Your e-mail message has been sent. */
+
+# Watchlist
+#
+
+"watchlist"    => "监视列表", /* Watch list */
+"watchlistsub" => "(用户\"$1\")", /* (for user \"$1\") */
+"nowatchlist"  => "You have no items on your watchlist.", /*  */
+"watchnologin" => "Not logged in", /*  */
+"watchnologintext"     => "You must be <a href=\"" .
+  wfLocalUrl( "Special:Userlogin" ) . "\">logged in</a>
+to modify your watchlist.",
+/*  */
+"addedwatch"   => "Added to watchlist", /*  */
+"addedwatchtext" => "The page \"$1\" has been added to your <a href=\"" .
+  wfLocalUrl( "Special:Watchlist" ) . "\">watchlist</a>.
+Future changes to this page and its associated Talk page will be listed there,
+and the page will appear <b>bolded</b> in the <a href=\"" .
+  wfLocalUrl( "Special:Recentchanges" ) . "\">list of recent changes</a> to
+make it easier to pick out.</p>
+
+<p>If you want to remove the page from your watchlist later, click \"Stop watching\" in the sidebar.",
+ /*  */
+"removedwatch" => "", /* Removed from watchlist */
+"removedwatchtext" => "The page \"$1\" has been removed from your watchlist.",
+/*  */
+"watchthispage"        => "监视本页", /* Watch this page */
+"unwatchthispage" => "停止监视", /* Stop watching */
+"notanarticle" => "Not an article",
+
+# Delete/protect/revert
+#
+"deletepage"   => "Delete page",
+"confirm"      => "Confirm",
+"confirmdelete" => "Confirm delete",
+"deletesub"    => "(Deleting \"$1\")",
+"confirmdeletetext" => "You are about to permanently delete a page
+or image along with all of its history from the database.
+Please confirm that you intend to do this, that you understand the
+consequences, and that you are doing this in accordance with
+[[Wikipedia:Policy]].",
+"confirmcheck" => "Yes, I really want to delete this.",
+"actioncomplete" => "Action complete",
+"deletedtext"  => "\"$1\" has been deleted.
+See $2 for a record of recent deletions.",
+"deletedarticle" => "deleted \"$1\"",
+"dellogpage"   => "Deletion_log",
+"dellogpagetext" => "Below is a list of the most recent deletions.
+All times shown are server time (UTC).
+<ul>
+</ul>
+",
+"deletionlog"  => "deletion log",
+"reverted"     => "Reverted to earlier revision",
+"deletecomment"        => "Reason for deletion",
+"imagereverted" => "Revert to earlier version was successful.",
+
+# Undelete
+"undelete" => "Restore deleted page",
+"undeletepage" => "View and restore deleted pages",
+"undeletepagetext" => "The following pages have been deleted but are still in the archive and
+can be restored. The archive may be periodically cleaned out.",
+"undeletearticle" => "Restore deleted article",
+"undeleterevisions" => "$1 revisions archived",
+"undeletehistory" => "If you restore the page, all revisions will be restored to the history.
+If a new page with the same name has been created since the deletion, the restored
+revisions will appear in the prior history, and the current revision of the live page
+will not be automatically replaced.",
+"undeleterevision" => "Deleted revision as of $1",
+"undeletebtn" => "Restore!",
+"undeletedarticle" => "restored \"$1\"",
+"undeletedtext"   => "The article [[$1]] has been successfully restored.
+See [[Wikipedia:Deletion_log]] for a record of recent deletions and restorations.",
+
+# Contributions
+#
+"contributions"        => "用户贡献", /* User contributions */
+"contribsub"   => "For $1",
+"nocontribs"   => "No changes were found matching these criteria.",
+"ucnote"       => "Below are this user's last <b>$1</b> changes in the last <b>$2</b> days.",
+"uclinks"      => "View the last $1 changes; view the last $2 days.",
+
+# What links here
+#
+"whatlinkshere"        => "链入页面", /* What links here */
+"notargettitle" => "No target", /*  */
+"notargettext" => "You have not specified a target page or user
+to perform this function on.",
+/*  */
+
+"linklistsub"  => "(链到本页的页面列表)", /* (List of links) */
+"linkshere"            => "下列页面链接到本页:",
+/* The following pages link to here:",  */
+"nolinkshere"  => "没有页面连接到这里。", /* No pages link to here. */
+"isredirect"   => "重定向页面", /* redirect page */
+
+# Block/unblock IP
+#
+"blockip"              => "Block IP address",
+"blockiptext"  => "Use the form below to block write access
+from a specific IP address.
+This should be done only only to prevent valndalism, and in
+accordance with [[Wikipedia:Policy|Wikipedia policy]].
+Fill in a specific reason below (for example, citing particular
+pages that were vandalized).",
+"ipaddress"            => "IP Address",
+"ipbreason"            => "Reason",
+"ipbsubmit"            => "Block this address",
+"badipaddress" => "The IP address is badly formed.",
+"noblockreason" => "You must supply a reason for the block.",
+"blockipsuccesssub" => "Block succeeded",
+"blockipsuccesstext" => "The IP address \"$1\" has been blocked.
+<br>See [[Special:Ipblocklist|IP block list]] to review blocks.",
+"unblockip"            => "Unblock IP address",
+"unblockiptext"        => "Use the form below to restore write access
+to a previously blocked IP address.",
+"ipusubmit"            => "Unblock this address",
+"ipusuccess"   => "IP address \"$1\" unblocked",
+"ipblocklist"  => "List of blocked IP addresses",
+"blocklistline"        => "$1, $2 blocked $3",
+"blocklink"            => "block",
+"unblocklink"  => "unblock",
+"contribslink" => "contribs",
+
+# Developer tools
+#
+"lockdb"       => "Lock database",
+"unlockdb"     => "Unlock database",
+"lockdbtext"   => "Locking the database will suspend the ability of all
+users to edit pages, change their preferences, edit their watchlists, and
+other things requiring changes in the database.
+Please confirm that this is what you intend to do, and that you will
+unlock the database when your maintenance is done.",
+"unlockdbtext" => "Unlocking the database will restore the ability of all
+users to edit pages, change their preferences, edit their watchlists, and
+other things requiring changes in the database.
+Please confirm that this is what you intend to do.",
+"lockconfirm"  => "Yes, I really want to lock the database.",
+"unlockconfirm"        => "Yes, I really want to unlock the database.",
+"lockbtn"      => "Lock database",
+"unlockbtn"    => "Unlock database",
+"locknoconfirm" => "You did not check the confirmation box.",
+"lockdbsuccesssub" => "Database lock succeeded",
+"unlockdbsuccesssub" => "Database lock removed",
+"lockdbsuccesstext" => "The Wikipedia database has been locked.
+<br>Remember to remove the lock after your maintenance is complete.",
+"unlockdbsuccesstext" => "The Wikipedia database has been unlocked.",
+
+# SQL query
+#
+"asksql"       => "SQL query",
+"asksqltext"   => "Use the form below to make a direct query of the
+Wikipedia database.
+Use single quotes ('like this') to delimit string literals.
+This can often add considerable load to the server, so please use
+this function sparingly.",
+"sqlquery"     => "Enter query",
+"querybtn"     => "Submit query",
+"selectonly"   => "Queries other than \"SELECT\" are restricted to
+Wikipedia developers.",
+"querysuccessful" => "Query successful",
+
+# Move page
+#
+"movepage"     => "移动页面", /* Move page */
+"movepagetext" => "Using the form below will rename a page, moving all
+of its history to the new name.
+The old title will become a redirect page to the new title.
+Links to the old page title will not be changed, and the talk
+page, if any, will not be moved.
+<b>WARNING!</b>
+This can be a drastic and unexpected change for a popular page;
+please be sure you understand the consequences of this before
+proceeding.",
+"movearticle"  => "移动页面", /* Move page */
+"movenologin"  => "Not logged in",
+"movenologintext" => "You must be a registered user and <a href=\"" .
+  wfLocalUrl( "Special:Userlogin" ) . "\">logged in</a>
+to move a page.",
+"newtitle"     => "To new title",
+"movepagebtn"  => "移动页面", /* Move page */
+"pagemovedsub" => "移动成功", /* Move succeeded */
+"pagemovedtext" => "Page \"[[$1]]\" moved to \"[[$2]]\".",
+"articleexists" => "A page of that name already exists, or the
+name you have chosen is not valid.
+Please choose another name.",
+"movedto"      => "moved to",
+"movetalk"     => "Move \"talk\" page as well, if applicable.",
+"talkpagemoved" => "The corresponding talk page was also moved.",
+"talkpagenotmoved" => "The corresponding talk page was <strong>not</strong> moved.",
+
+);
+
+class LanguageZh extends LanguageUtf8 {
+
+       function getDefaultUserOptions () {
+               global $wgDefaultUserOptionsZh ;
+               return $wgDefaultUserOptionsZh ;
+               }
+
+       function getBookstoreList () {
+               global $wgBookstoreListZh ;
+               return $wgBookstoreListZh ;
+       }
+
+       function getNamespaces() {
+               global $wgNamespaceNamesZh;
+               return $wgNamespaceNamesZh;
+       }
+
+       function getNsText( $index ) {
+               global $wgNamespaceNamesZh;
+               return $wgNamespaceNamesZh[$index];
+       }
+
+       function getNsIndex( $text ) {
+               global $wgNamespaceNamesZh;
+
+               foreach ( $wgNamespaceNamesZh as $i => $n ) {
+                       if ( 0 == strcasecmp( $n, $text ) ) { return $i; }
+               }
+               # Aliases
+        if ( 0 == strcasecmp( "Special", $text ) ) { return -1; }
+               return false;
+       }
+
+       function getQuickbarSettings() {
+               global $wgQuickbarSettingsZh;
+               return $wgQuickbarSettingsZh;
+       }
+
+       function getSkinNames() {
+               global $wgSkinNamesZh;
+               return $wgSkinNamesZh;
+       }
+
+
+       function getUserToggles() {
+               global $wgUserTogglesZh;
+               return $wgUserTogglesZh;
+       }
+
+       function getLanguageNames() {
+               global $wgLanguageNamesZh;
+               return $wgLanguageNamesZh;
+       }
+
+       function getLanguageName( $code ) {
+               global $wgLanguageNamesZh;
+               if ( ! array_key_exists( $code, $wgLanguageNamesZh ) ) {
+                       return "";
+               }
+               return $wgLanguageNamesZh[$code];
+       }
+
+       function getMonthName( $key )
+       {
+               global $wgMonthNamesZh;
+               return $wgMonthNamesZh[$key-1];
+       }
+
+       function getMonthAbbreviation( $key )
+       {
+               global $wgMonthAbbreviationsZh;
+               return $wgMonthAbbreviationsZh[$key-1];
+       }
+
+       function getWeekdayName( $key )
+       {
+               global $wgWeekdayNamesZh;
+               return $wgWeekdayNamesZh[$key-1];
+       }
+
+       # The date and time functions can be tweaked if need be
+
+       # inherit userAdjust()
+        
+    function date( $ts, $adj = false )
+       {
+               if ( $adj ) { $ts = $this->userAdjust( $ts ); }
+
+               $d = substr( $ts, 0, 4 ) . "年" .
+                 $this->getMonthAbbreviation( substr( $ts, 4, 2 ) ) .
+                 (0 + substr( $ts, 6, 2 )) . "日";
+               return $d;
+       }
+
+       function time( $ts, $adj = false )
+       {
+               if ( $adj ) { $ts = $this->userAdjust( $ts ); }
+
+               $t = substr( $ts, 8, 2 ) . ":" . substr( $ts, 10, 2 );
+               return $t;
+       }
+
+       function timeanddate( $ts, $adj = false )
+       {
+               return $this->date( $ts, $adj ) . " " . $this->time( $ts, $adj );
+       }
+
+       # inherit default rfc1123()
+
+       function getValidSpecialPages()
+       {
+               global $wgValidSpecialPagesZh;
+               return $wgValidSpecialPagesZh;
+       }
+
+       function getSysopSpecialPages()
+       {
+               global $wgSysopSpecialPagesZh;
+               return $wgSysopSpecialPagesZh;
+       }
+
+       function getDeveloperSpecialPages()
+       {
+               global $wgDeveloperSpecialPagesZh;
+               return $wgDeveloperSpecialPagesZh;
+       }
+
+       function getMessage( $key )
+       {
+               global $wgAllMessagesZh, $wgAllMessagesEn;
+               $m = $wgAllMessagesZh[$key];
+
+               if ( "" == $m ) { return $wgAllMessagesEn[$key]; }
+               else return $m;
+       }
+               
+       # inherit default iconv(), ucfirst(), checkTitleEncoding()
+
+       function stripForSearch( $string ) {
+               # MySQL fulltext index doesn't grok utf-8, so we
+               # need to fold cases and convert to hex
+               global $wikiLowerChars;
+               return preg_replace(
+                 "/([\\xc0-\\xff][\\x80-\\xbf]*)/e",
+                 "' U8' . bin2hex( strtr( \"\$1\", \$wikiLowerChars ) )",
+                 $string );
+       }
+
+}
+
+?>
diff --git a/maintenance/README b/maintenance/README
new file mode 100644 (file)
index 0000000..2a68f1b
--- /dev/null
@@ -0,0 +1,10 @@
+The .sql scripts in this directory are not meant to be run
+standalone, although they can be in some cases if you know
+what you're doing.  Most of the time you'll want to run the
+.php scripts from the command line.  You must run them from
+this directory, and the LocalSettings.php file in the
+directory above must point to the installation.
+
+The scripts in archive are for updating databases from
+older versions of the software.
+
diff --git a/maintenance/apache-ampersand.diff b/maintenance/apache-ampersand.diff
new file mode 100644 (file)
index 0000000..f281ce1
--- /dev/null
@@ -0,0 +1,53 @@
+--- orig/apache_1.3.26/src/modules/standard/mod_rewrite.h      Wed Mar 13 13:05:34 2002
++++ apache_1.3.26/src/modules/standard/mod_rewrite.h   Tue Oct 15 14:07:21 2002
+@@ -447,6 +447,7 @@
+ static char *rewrite_mapfunc_toupper(request_rec *r, char *key);
+ static char *rewrite_mapfunc_tolower(request_rec *r, char *key);
+ static char *rewrite_mapfunc_escape(request_rec *r, char *key);
++static char *rewrite_mapfunc_ampescape(request_rec *r, char *key);
+ static char *rewrite_mapfunc_unescape(request_rec *r, char *key);
+ static char *select_random_value_part(request_rec *r, char *value);
+ static void  rewrite_rand_init(void);
+--- orig/apache_1.3.26/src/modules/standard/mod_rewrite.c      Wed May 29 10:39:23 2002
++++ apache_1.3.26/src/modules/standard/mod_rewrite.c   Tue Oct 15 14:07:49 2002
+@@ -502,6 +502,9 @@
+         else if (strcmp(a2+4, "unescape") == 0) {
+             new->func = rewrite_mapfunc_unescape;
+         }
++        else if (strcmp(a2+4, "ampescape") == 0) {
++            new->func = rewrite_mapfunc_ampescape;
++        }
+         else if (sconf->state == ENGINE_ENABLED) {
+             return ap_pstrcat(cmd->pool, "RewriteMap: internal map not found:",
+                               a2+4, NULL);
+@@ -2982,6 +2985,30 @@
+     value = ap_escape_uri(r->pool, key);
+     return value;
++}
++
++static char *rewrite_mapfunc_ampescape(request_rec *r, char *key)
++{
++    /* We only need to escape the ampersand */
++    char *copy = ap_palloc(r->pool, 3 * strlen(key) + 3);
++    const unsigned char *s = (const unsigned char *)key;
++    unsigned char *d = (unsigned char *)copy;
++    unsigned c;
++
++    while ((c = *s)) {
++      if (c == '&') {
++          *d++ = '%';
++          *d++ = '2';
++          *d++ = '6';
++      }
++      else {
++          *d++ = c;
++      }
++      ++s;
++    }
++    *d = '\0';
++    
++    return copy;
+ }
+ static char *rewrite_mapfunc_unescape(request_rec *r, char *key)
diff --git a/maintenance/archives/convertdb.php b/maintenance/archives/convertdb.php
new file mode 100644 (file)
index 0000000..31b77a9
--- /dev/null
@@ -0,0 +1,592 @@
+<?
+
+print "This script is obsolete!";
+print "It is retained in the source here in case some of its
+code might be useful for ad-hoc conversion tasks, but it is
+not maintained and probably won't even work as is.";
+exit();
+
+# Database conversion (from May 2002 format).  Assumes that
+# the old tables have been loaded into an empty database from
+# dump files.
+
+global $IP;
+include_once( "../LocalSettings.php" );
+include_once( "../AdminSettings.php" );
+include_once( "$IP/Setup.php" );
+
+$wgTitle = Title::newFromText( "Conversion script" );
+include_once( "./rebuildLinks.inc" );
+include_once( "./rebuildRecentchanges.inc" );
+include_once( "./buildTables.inc" );
+set_time_limit(0);
+
+$wgDBuser                      = "wikiadmin";
+$wgDBpassword          = $wgDBadminpassword;
+# $wgImageDirectory    = "/usr/local/apache/htdocs/wikiimages";
+$wgImageDirectory      = "/usr/local/apache/htdocs/upload";
+$wgMetaImageDirectory   = "/usr/local/apache/htdocs-meta/upload";
+
+renameOldTables();
+buildTables();
+initializeTables();
+
+# convertImageDirectories();
+convertUserTable();
+convertOldTable();
+convertCurTable();
+
+buildIndexes();
+
+rebuildLinkTablesPass1();
+rebuildLinkTablesPass2();
+
+# This is kinda ugly, could be done cleaner
+convertImageDirectories();
+#rebuildLinkTablesPass1();
+#rebuildLinkTablesPass2();
+#
+
+removeOldTables();
+
+refillRandom();
+rebuildRecentChangesTable();
+
+print "Done.\n";
+exit();
+
+########## End of script, beginning of functions.
+
+function convertUserTable()
+{
+       $count = 0;
+       print "Converting USER table.\n";
+
+       $sql = "LOCK TABLES old_user READ, user WRITE";
+       $newres = wfQuery( $sql );
+
+       $sql = "SELECT user_id,user_name,user_rights,user_password," .
+         "user_email,user_options,user_watch FROM old_user";
+       $oldres = wfQuery( $sql );
+
+       $sql = "DELETE FROM user";
+       $newres = wfQuery( $sql );
+
+       $sql = "";
+       while ( $row = mysql_fetch_object( $oldres ) ) {
+               $name = addslashes( fixUserName( $row->user_name ) );
+               if ( "" == $name ) continue; # Don't convert illegal names
+
+               if ( 0 == ( $count % 10 ) ) {
+                       if ( 0 != $count ) { $newres = wfQuery( $sql ); }
+
+                       $sql = "INSERT INTO user (user_id,user_name,user_rights," .
+                         "user_password,user_newpassword,user_email,user_options," .
+                         "user_watch) VALUES ";
+               } else {
+                       $sql .= ",";
+               }
+               $ops = addslashes( fixUserOptions( $row->user_options ) );
+               $rights = addslashes( fixUserRights( $row->user_rights ) );
+               $email = addslashes( $row->user_email );
+               $pwd = addslashes( md5( $row->user_password ) );
+               $watch = addslashes( $row->user_watch );
+
+               $sql .= "({$row->user_id},'{$name}','{$rights}','{$pwd}',''," .
+                 "'{$email}','{$ops}','{$watch}')";
+
+               if ( ( ++$count % 1000 ) == 0 ) {
+                       print "$count user records processed.\n";
+               }
+       }
+       if ( $sql ) { $newres = wfQuery( $sql ); }
+
+       print "$count user records processed.\n";
+       mysql_free_result( $oldres );
+
+       $sql = "UNLOCK TABLES";
+       $newres = wfQuery( $sql );
+}
+
+# Convert May 2002 version of database into new format.
+#
+function convertCurTable()
+{
+       $count = $countables = 0;
+       print "Converting CUR table.\n";
+
+       $sql = "LOCK TABLES old_cur READ, cur WRITE, site_stats WRITE";
+       $newres = wfQuery( $sql );
+
+       $sql = "SELECT cur_id,cur_title,cur_text,cur_comment,cur_user," .
+         "cur_timestamp,cur_minor_edit,cur_restrictions," .
+         "cur_counter,cur_ind_title,cur_user_text FROM old_cur";
+       $oldres = wfQuery( $sql );
+
+       $sql = "DELETE FROM cur";
+       wfQuery( $sql );
+
+       $sql = "DELETE FROM site_stats";
+       wfQuery( $sql );
+
+       $sql = "";
+       while ( $row = mysql_fetch_object( $oldres ) ) {
+               $nt = Title::newFromDBkey( $row->cur_title );
+               $title = addslashes( $nt->getDBkey() );
+               $ns = $nt->getNamespace();
+               $text = addslashes( convertMediaLinks( $row->cur_text ) );
+
+               $ititle = addslashes( indexTitle( $nt->getText() ) );
+               $itext = addslashes( indexText( $text, $ititle ) );
+
+               $com = addslashes( $row->cur_comment );
+               $cr = addslashes( fixUserRights( $row->cur_restrictions ) );
+               $cut = addslashes( $row->cur_user_text );
+               if ( "" == $cut ) { $cut = "Unknown"; }
+
+               if ( 2 == $row->cur_minor_edit ) { $isnew = 1; }
+               else { $isnew = 0; }
+               if ( 0 != $row->cur_minor_edit ) { $isme = 1; }
+               else { $isme = 0; }
+
+               # $counter = $row->cur_counter;
+               # if ( ! $counter ) { $counter = 0; }
+
+               if ( preg_match( "/^#redirect/i", $text ) ) {
+                       $redir = 1;
+                       $text = fixRedirect( $text );
+               } else { $redir = 0; }
+
+               $sql = "INSERT INTO cur (cur_id,cur_namespace," .
+                 "cur_title,cur_text,cur_comment,cur_user," .
+                 "cur_timestamp,cur_minor_edit,cur_is_new," .
+                 "cur_restrictions,cur_counter,cur_ind_title," .
+                 "cur_ind_text,cur_is_redirect,cur_user_text) VALUES ";
+               $sql .= "({$row->cur_id},{$ns},'{$title}','{$text}'," .
+                 "'{$com}',{$row->cur_user},'{$row->cur_timestamp}'," .
+                 "{$isme},{$isnew},'{$cr}',0,'{$ititle}','{$itext}'," .
+                 "{$redir},'{$cut}')";
+               wfQuery( $sql );
+
+               if ( ( ++$count % 1000 ) == 0 ) {
+                       print "$count article records processed.\n";
+               }
+               if ( 0 != $ns ) { continue; }
+               if ( 0 != $redir ) { continue; }
+               if ( false === strstr( $text, "," ) ) { continue; }
+               ++$countables;
+       }
+       print "$count article records processed.\n";
+       mysql_free_result( $oldres );
+
+       $sql = "REPLACE INTO site_stats (ss_row_id,ss_total_views," .
+         "ss_total_edits,ss_good_articles) VALUES (1,0,0,{$countables})";
+       wfQuery( $sql );
+
+       $sql = "UNLOCK TABLES";
+       $newres = wfQuery( $sql );
+}
+
+# Convert May 2002 version of database into new format.
+#
+function convertOldTable()
+{
+       $count = 0;
+       print "Converting OLD table.\n";
+
+       $sql = "LOCK TABLES old_old READ, old WRITE";
+       $newres = wfQuery( $sql );
+
+       $sql = "SELECT old_id,old_title,old_text,old_comment,old_user," .
+         "old_timestamp,old_minor_edit,old_user_text FROM old_old";
+       $oldres = wfQuery( $sql );
+
+       $sql = "DELETE FROM old";
+       $newres = wfQuery( $sql );
+
+       while ( $row = mysql_fetch_object( $oldres ) ) {
+               $nt = Title::newFromDBkey( $row->old_title );
+               $title = addslashes( $nt->getDBkey() );
+               $ns = $nt->getNamespace();
+               #$text = addslashes( convertMediaLinks( $row->old_text ) );
+               # DO NOT convert media links on old versions!!!!!
+               # Old table should always be left intact
+               $text = addslashes($row->old_text);
+
+               $com = addslashes( $row->old_comment );
+               $cut = addslashes( $row->old_user_text );
+               if ( "" == $cut ) { $cut = "Unknown"; }
+
+               if ( 0 != $row->old_minor_edit ) { $isme = 1; }
+               else { $isme = 0; }
+
+               if ( preg_match( "/^#redirect/i", $text ) ) {
+                       $redir = 1;
+                       $text = fixRedirect( $text );
+               } else { $redir = 0; }
+
+               $sql = "INSERT INTO old (old_id,old_namespace,old_title," .
+                 "old_text,old_comment,old_user," .
+                 "old_timestamp,old_minor_edit,old_user_text) VALUES ";
+               $sql .= "({$row->old_id},{$ns},'{$title}','{$text}'," .
+                 "'{$com}',{$row->old_user},'{$row->old_timestamp}'," .
+                 "{$isme},'{$cut}')";
+               wfQuery( $sql );
+
+               if ( ( ++$count % 1000 ) == 0 ) {
+                       print "$count history records processed.\n";
+               }
+       }
+       print "$count history records processed.\n";
+       mysql_free_result( $oldres );
+
+       $sql = "UNLOCK TABLES";
+       $newres = wfQuery( $sql );
+}
+
+function convertImageDirectoriesX()
+{
+       global $wgImageDirectory, $wgMetaImageDirectory, $wgUploadDirectory;
+       $count = 0;
+
+       print "Moving image files.\n";
+       $dir = opendir( $wgImageDirectory ) or die(
+         "Couldn't open directory \"{$wgImageDirectory}\".\n" );
+
+       while ( false !== ( $oname = readdir( $dir ) ) ) {
+               if ( "." == $oname{0} ) continue;
+
+               $nt = Title::newFromText( $oname );
+               $nname = $nt->getDBkey();
+
+               $exts = array( "png", "gif", "jpg", "jpeg", "ogg" );
+               $ext = strrchr( $nname, "." );
+               if ( false === $ext ) { $ext = ""; }
+               else { $ext = strtolower( substr( $ext, 1 ) ); }
+               if ( ! in_array( $ext, $exts ) ) {
+                       print "Skipping \"{$oname}\"\n";
+                       continue;
+               }
+               $oldumask = umask(0);
+               $hash = md5( $nname );
+               $dest = $wgUploadDirectory . "/" . $hash{0};
+               if ( ! is_dir( $dest ) ) {
+                       mkdir( $dest, 0777 ) or die( "Can't create \"{$dest}\".\n" );
+               }
+               $dest .= "/" . substr( $hash, 0, 2 );
+               if ( ! is_dir( $dest ) ) {
+                       mkdir( $dest, 0777 ) or die( "Can't create \"{$dest}\".\n" );
+               }
+               umask( $oldumask );
+
+               if ( copy( "{$wgImageDirectory}/{$oname}", "{$dest}/{$nname}" ) ) {
+                       ++$count;
+
+                       $sql = "DELETE FROM image WHERE img_name='" .
+                         addslashes( $nname ) . "'";
+                       $res = wfQuery( $sql );
+
+                       $sql = "INSERT INTO image (img_name,img_timestamp,img_user," .
+                         "img_user_text,img_size,img_description) VALUES ('" .
+                         addslashes( $nname ) . "','" .
+                         date( "YmdHis" ) . "',0,'(Automated conversion)','" .
+                         filesize( "{$dest}/{$nname}" ) . "','')";
+                       $res = wfQuery( $sql );
+               } else {
+                       die( "Couldn't copy \"{$oname}\" to \"{$nname}\"\n" );
+               }
+       }
+       print "{$count} images moved.\n";
+}
+
+function convertImageDirectories()
+{
+       global $wgImageDirectory, $wgMetaImageDirectory, $wgUploadDirectory;
+       $count = 0;
+
+
+       $sql = "SELECT DISTINCT il_to FROM imagelinks";
+       $result = wfQuery ( $sql ) ;
+
+   while ( $row = mysql_fetch_object ( $result ) ) {
+       $oname = $row->il_to ;
+       $nname = ucfirst ( $oname ) ;
+       
+        $exts = array( "png", "gif", "jpg", "jpeg", "ogg" );
+               $ext = strrchr( $nname, "." );
+               if ( false === $ext ) { $ext = ""; }
+               else { $ext = strtolower( substr( $ext, 1 ) ); }
+               if ( ! in_array( $ext, $exts ) ) {
+                       print "Skipping \"{$oname}\"\n";
+                       continue;
+               }
+               $oldumask = umask(0);
+               $hash = md5( $nname );
+               $dest = $wgUploadDirectory . "/" . $hash{0};
+               $wgImageDirectoryHash = $wgImageDirectory . "/" . $hash{0} . "/" . substr ( $hash , 0, 2);
+               $wgMetaImageDirectoryHash = $wgMetaImageDirectory . "/" . $hash{0} . "/" . substr( $hash, 0, 2);
+               if ( ! is_dir( $dest ) ) {
+                       mkdir( $dest, 0777 ) or die( "Can't create \"{$dest}\".\n" );
+               }
+               $dest .= "/" . substr( $hash, 0, 2 );
+               if ( ! is_dir( $dest ) ) {
+                       mkdir( $dest, 0777 ) or die( "Can't create \"{$dest}\".\n" );
+               }
+               umask( $oldumask );
+
+               #echo "Would be copying {$wgImageDirectoryHash}/{$oname} to {$dest}/{$nname}\n";
+               #continue;
+               
+               if ( copy( "{$wgImageDirectoryHash}/{$nname}", "{$dest}/{$nname}" )
+                 or copy( "{$wgImageDirectory}/{$oname}", "{$dest}/{$nname}" )
+                 or copy( "{$wgImageDirectory}/".strtolower($oname), "{$dest}/{$nname}" )
+          or copy( "{$wgMetaImageDirectoryHash}/{$oname}", "{$dest}/{$nname}" )
+          or copy( "{$wgMetaImageDirectory}/{$oname}", "{$dest}/{$nname}" )
+          or copy( "{$wgMetaImageDirectory}/".strtolower($oname), "{$dest}/{$nname}" ) ) {
+                       ++$count;
+
+                       $sql = "DELETE FROM image WHERE img_name='" .
+                         addslashes( $nname ) . "'";
+                       $res = wfQuery( $sql );
+
+                       $sql = "INSERT INTO image (img_name,img_timestamp,img_user," .
+                         "img_user_text,img_size,img_description) VALUES ('" .
+                         addslashes( $nname ) . "','" .
+                         date( "YmdHis" ) . "',0,'(Automated conversion)','" .
+                         filesize( "{$dest}/{$nname}" ) . "','')";
+                       $res = wfQuery( $sql );
+               } else {
+            echo( "Couldn't copy \"{$oname}\" to \"{$nname}\"\n" );
+        }
+       }
+}
+
+# Utility functions for the above.
+#
+function convertMediaLinks( $text )
+{
+       global $wgLang;
+       $ins = $wgLang->getNsText( Namespace::getImage() );
+
+       $q = $text;
+       $text = preg_replace(
+         "/(^|[^[])http:\/\/(www.||meta.)wikipedia.(?:com|org)\/upload\/(?:[0-9a-f]\/[0-9a-f][0-9a-f]\/|)" .
+         "([a-zA-Z0-9_:.~\%\-]+)\.(png|PNG|jpg|JPG|jpeg|JPEG|gif|GIF)/",
+         "\\1[[{$ins}:\\3.\\4]]", $text );
+       $text = preg_replace(
+         "/(^|[^[])http:\/\/(www.||meta.)wikipedia.(?:com|org)\/images\/uploads\/" .
+         "([a-zA-Z0-9_:.~\%\-]+)\.(png|PNG|jpg|JPG|jpeg|JPEG|gif|GIF)/",
+         "\\1[[{$ins}:\\3.\\4]]", $text );
+
+       $text = preg_replace(
+         "/(^|[^[])http:\/\/(www.||meta.)wikipedia.(?:com|org)\/upload\/(?:[0-9a-f]\/[0-9a-f][0-9a-f]\/|)" .
+         "([a-zA-Z0-9_:.~\%\-]+)/", "\\1[[media:\\3]]", $text );
+       $text = preg_replace(
+         "/(^|[^[])http:\/\/(www.||meta.)wikipedia.(?:com|org)\/images\/uploads\/" .
+         "([a-zA-Z0-9_:.~\%\-]+)/", "\\1[[media:\\3]]", $text );
+
+       if ($q != $text) echo "BOOF!"; else echo ".";
+       return $text;
+}
+
+function fixRedirect( $text )
+{
+       $tc = "[&;%\\-,.\\(\\)' _0-9A-Za-z\\/:\\xA0-\\xff]";
+       $re = "#redirect";
+       if ( preg_match( "/^{$re}\\s*\\[{$tc}+\\]/i", $text ) ) {
+               $text = preg_replace( "/^({$re})\\s*\\[\\s*({$tc}+)\\]/i",
+                 "\\1 [[\\2]]", $text, 1 );
+       } else if ( preg_match( "/^{$re}\\s+{$tc}+/i", $text ) ) {
+               $text = preg_replace( "/^({$re})\\s+({$tc}+)/i",
+                 "\\1 [[\\2]]", $text, 1 );
+       }
+       return $text;
+}
+
+function fixUserOptions( $in )
+{
+       $s = urldecode( $in );
+       $a = explode( "\n", $s );
+
+       foreach ( $a as $l ) {
+               if ( preg_match( "/^([A-Za-z0-9_]+)=(.*)/", $l, $m ) ) {
+                       $ops[$m[1]] = $m[2];
+               }
+       }
+       $nops = array();
+
+       $q = strtolower( $ops["quickBar"] );
+       if ( $q == "none" ) { $q = 0; }
+       else { $q = 1; } # Default to left
+       $nops["quickbar"] = $q;
+
+       if ( $ops["markupNewTopics"] == "inverse" ) {
+               $nops["highlightbroken"] = 1;
+       }
+       $sk = substr( strtolower( $ops["skin"] ), 0, 4 );
+       if ( "star" == $sk ) { $sk = 0; }
+       else if ( "nost" == $sk ) { $sk = 1; }
+       else if ( "colo" == $sk ) { $sk = 2; }
+       else { $sk = 0; }
+       $nops["skin"] = $sk;
+
+       $u = strtolower( $ops["underlineLinks"] );
+       if ( "yes" == $u || "on" == $u ) { $nops["underline"] = 1; }
+       else { $nops["underline"] = 0; }
+
+       $t = ( (int) ($ops["hourDiff"]) );
+       if ( $t < -23 || $t > 23 ) { $t = 0; }
+       if ( 0 != $t ) { $nops["timecorrection"] = $t; }
+
+       $j = strtolower( $ops["justify"] );
+       if ( "yes" == $j || "on" == $j ) { $nops["justify"] = 1; }
+       $n = strtolower( $ops["numberHeadings"] );
+       if ( "yes" == $n || "on" == $n ) { $nops["numberheadings"] = 1; }
+       $h = strtolower( $ops["hideMinor"] );
+       if ( "yes" == $h || "on" == $h ) { $nops["hideminor"] = 1; }
+       $r = strtolower( $ops["rememberPassword"] );
+       if ( "yes" == $r || "on" == $r ) { $nops["rememberpassword"] = 1; }
+       $s = strtolower( $ops["showHover"] );
+       if ( "yes" == $s || "on" == $s ) { $nops["hover"] = 1; }
+
+       $c = $ops["cols"];
+       if ( $c < 20 || c > 200 ) { $nops["cols"] = 80; }
+       else { $nops["cols"] = $c; }
+       $r = $ops["rows"];
+       if ( $r < 5 || $r > 100 ) { $nops["rows"] = 20; }
+       else { $nops["rows"] = $r; }
+       $r = $ops["resultsPerPage"];
+       if ( $r < 3 || $r > 500 ) { $nops["searchlimit"] = 20; }
+       else { $nops["searchlimit"] = $r; }
+       $r = $ops["viewRecentChanges"];
+       if ( $r < 10 || $r > 1000 ) { $nops["rclimit"] = 50; }
+       else { $nops["rclimit"] = $r; }
+       $nops["rcdays"] = 3;
+
+       $a = array();
+       foreach ( $nops as $oname => $oval ) {
+               array_push( $a, "$oname=$oval" );
+       }
+       $s = implode( "\n", $a );
+       return $s;
+}
+
+function fixUserRights( $in )
+{
+       $a = explode( ",", $in );
+       $b = array();
+       foreach ( $a as $r ) {
+               if ( "is_developer" == strtolower( trim( $r ) ) ) {
+                       array_push( $b, "developer" );
+               } else if ( "is_sysop" == strtolower( trim( $r ) ) ) {
+                       array_push( $b, "sysop" );
+               }
+       }
+       $out = implode( ",", $b );
+       return $out;
+}
+
+function fixUserName( $in )
+{
+       $lc = "-,.()' _0-9A-Za-z\\/:\\xA0-\\xFF";
+       $out = preg_replace( "/[^{$lc}]/", "", $in );
+       $out = ucfirst( trim( str_replace( "_", " ", $out ) ) );
+       return $out;
+}
+
+function indexTitle( $in )
+{
+       $lc = "A-Za-z_'0-9&#;\\x90-\\xFF\\-";
+       $t = preg_replace( "/[^{$lc}]+/", " ", $in );
+#      $t = preg_replace( "/\\b[{$lc}][{$lc}]\\b/", " ", $t );
+       $t = preg_replace( "/\\b[{$lc}]\\b/", " ", $t );
+       $t = preg_replace( "/\\s+/", " ", $t );
+       return $t;
+}
+
+function indexText( $text, $ititle )
+{
+       global $wgLang;
+       $lc = SearchEngine::legalSearchChars() . "&#;";
+
+       $text = preg_replace( "/<\\/?\\s*[A-Za-z][A-Za-z0-9]*\\s*([^>]*?)>/",
+         " ", strtolower( " " . $text . " " ) ); # Strip HTML markup
+       $text = preg_replace( "/(^|\\n)\\s*==\\s+([^\\n]+)\\s+==\\s/sD",
+         "\\2 \\2 \\2 ", $text ); # Emphasize headings
+
+       # Strip external URLs
+       $uc = "A-Za-z0-9_\\/:.,~%\\-+&;#?!=()@\\xA0-\\xFF";
+       $protos = "http|https|ftp|mailto|news|gopher";
+       $pat = "/(^|[^\\[])({$protos}):[{$uc}]+([^{$uc}]|$)/";
+       $text = preg_replace( $pat, "\\1 \\3", $text );
+
+       $p1 = "/([^\\[])\\[({$protos}):[{$uc}]+]/";
+       $p2 = "/([^\\[])\\[({$protos}):[{$uc}]+\\s+([^\\]]+)]/";
+       $text = preg_replace( $p1, "\\1 ", $text );
+       $text = preg_replace( $p2, "\\1 \\3 ", $text );
+
+       # Internal image links
+       $ins = $wgLang->getNsText( Namespace::getImage() );
+       $pat2 = "/\\[\\[$ins:([{$uc}]+)\\.(gif|png|jpg|jpeg)([^{$uc}])/i";
+       $text = preg_replace( $pat2, " \\1 \\3", $text );
+
+       $text = preg_replace( "/([^{$lc}])([{$lc}]+)]]([a-z]+)/",
+         "\\1\\2 \\2\\3", $text ); # Handle [[game]]s
+
+       # Strip all remaining non-search characters
+       $text = preg_replace( "/[^{$lc}]+/", " ", $text );
+
+       # Handle 's, s'
+       $text = preg_replace( "/([{$lc}]+)'s /", "\\1 \\1's ", $text );
+       $text = preg_replace( "/([{$lc}]+)s' /", "\\1s ", $text );
+
+       # Strip wiki '' and '''
+       $text = preg_replace( "/''[']*/", " ", $text );
+
+       # Strip 1- and 2-letter words
+#      $text = preg_replace( "/\\s[{$lc}][{$lc}]\\s/", " ", $text );
+#      $text = preg_replace( "/\\s[{$lc}][{$lc}]\\s/", " ", $text );
+       $text = preg_replace( "/\\s[{$lc}]\\s/", " ", $text );
+       $text = preg_replace( "/\\s[{$lc}]\\s/", " ", $text );
+
+       return $text;
+}
+
+function refillRandom()
+{
+       $sql = "INSERT INTO random(ra_current,ra_title) SELECT 0,cur_title " .
+         "FROM cur WHERE cur_namespace=0 AND cur_is_redirect=0 " .
+         "ORDER BY RAND() LIMIT 1000";
+       wfQuery( $sql, $fname );
+
+       $sql = "UPDATE random SET ra_current=(ra_current+1)";
+       wfQuery( $sql, $fname );
+
+       $sql = "DELETE FROM random WHERE ra_current>1";
+       wfQuery( $sql, $fname );
+}
+
+function renameOldTables()
+{
+       $sql = "ALTER TABLE user RENAME TO old_user";
+       wfQuery( $sql );
+       $sql = "ALTER TABLE cur RENAME TO old_cur";
+       wfQuery( $sql );
+       $sql = "ALTER TABLE old RENAME TO old_old";
+       wfQuery( $sql );
+       $sql = "DROP TABLE IF EXISTS linked";
+       wfQuery( $sql );
+       $sql = "DROP TABLE IF EXISTS unlinked";
+       wfQuery( $sql );
+}
+
+function removeOldTables()
+{
+       wfQuery( "DROP TABLE IF EXISTS old_user" );
+       wfQuery( "DROP TABLE IF EXISTS old_linked" );
+       wfQuery( "DROP TABLE IF EXISTS old_unlinked" );
+       wfQuery( "DROP TABLE IF EXISTS old_cur" );
+       wfQuery( "DROP TABLE IF EXISTS old_old" );
+}
+
+?>
diff --git a/maintenance/archives/importTests.php b/maintenance/archives/importTests.php
new file mode 100644 (file)
index 0000000..2ca2909
--- /dev/null
@@ -0,0 +1,261 @@
+<html>
+<head>
+<title>Unit tests for UseMod-to-PediaWiki import script</title>
+<meta http-equiv="Refresh" content="10;URL=importTests.php">
+<style>
+.pass { color: green }
+.fail { color: red }
+</style>
+</head>
+<body>
+
+<?php
+
+# Unit tests for importUseModWiki
+# Well, more or less ;)
+
+$testingonly = true;
+
+setlocale( LC_ALL, "C" );
+
+include( "importUseModWiki.php" );
+
+$wgRootDirectory = "./testconvert";
+runTests();
+
+function runTests() {
+       $success =
+               testTimestamp()
+               && testRecode()
+               && testFreeToNormal()
+               && testTransformTitle()
+               && testMediaLinks()
+               && testRemoveTalkLink()
+               && testSubPages()
+               ;
+       if( $success ) {
+               echo "\n<h1 class='pass'>** Passed all tests! **</h1>\n";
+       } else {
+               echo "\n<h1 class='fail'>-- FAILED ONE OR MORE TESTS --</h1>\n";
+       }
+       return $success;
+}
+
+function passTest( $testname, $note = "" ) {
+       if( $notes != "" ) $notes = " -- $notes";
+       echo "<span class='pass'>.. passed test $testname $notes</span><br />\n";
+       return true;
+}
+
+function failTest( $testname, $notes = "" ) {
+       if ( $notes != "" ) $notes = " -- $notes";
+       echo "<span class='fail'>** FAILED TEST $testname **$notes</span><br />\n";
+       return false;
+}
+
+function testTimestamp() {
+       $tn = "Timestamp";
+       $x = wfUnix2Timestamp( 0 );
+       if( $x != "19700101000000" ) {
+               return failTest( $tn, "wfUnix2Timestamp for epoch returned unexpected $x" );
+       }
+       
+       $x = wfTimestamp2Unix( "19700101000000" );
+       if( $x != 0 ) {
+               return failTest( $tn, "wfTimestamp2Unix for epoch returned unexpected $x" );
+       }
+       
+       return passTest( $tn );
+}
+
+function testRecode() {
+       $tn = "Recode";
+       
+       # These functions are dummies for now
+       $a = "abcd";
+       $x = recodeInput( $a );
+       if( $a != $x ) return failTest( $tn, "eo test returned different value" );
+
+       $a = "ĉeĥa ŝaŭmmanĝaĵo";
+       $x = recodeInput( $a );
+       if( $a != $x ) return failTest( $tn, "eo test returned different value" );
+       
+       return passTest( $tn );
+}
+
+function testFreeToNormal() {
+       $tn = "FreeToNormal";
+       $a = "WikiName"; $x = FreeToNormal( $a );
+       if( $a != $x ) return failTest( $tn, "$a -> $a != $x" );
+       
+       $a = "With_Underscore"; $x = FreeToNormal( $a );
+       if( $a != $x ) return failTest( $tn, "$a -> $a != $x" );
+       
+       $a = "With Space"; $x = FreeToNormal( $a );
+       if( "With_Space" != $x ) return failTest( $tn, "$a -> With_Space != $x" );
+       
+       $a = "Mixed case"; $x = FreeToNormal( $a );
+       if( "Mixed_Case" != $x ) return failTest( $tn, "$a -> Mixed_Case != $x" );
+       
+       $a = "\xe9cole"; $x = FreeToNormal( $a );
+       if( $a != $x ) return failTest( $tn, "$a -> $a != $x (must replicate high caps bug)" );
+       
+       return passTest( $tn );
+}
+
+function testTransformTitle() {
+       global $talkending;
+       $oldtalkending = $talkending;
+       $tn = "TransformTitle";
+       
+       $a = "WikiName"; $x = transformTitle( $a );
+       if( $x->namespace != 0 or $x->title != "WikiName" ) return failTest( $tn, "$a -> 0, WikiName instead -> $x->namespace , $x->title" );
+       
+       $talkending = "Talk";
+       $a = "WikiName/Talk"; $x = transformTitle( $a );
+       if( $x->namespace != 1 or $x->title != "WikiName" ) return failTest( $tn, "$a -> 1, WikiName instead -> $x->namespace , $x->title" );
+
+       $a = "WikiName/talk"; $x = transformTitle( $a );
+       if( $x->namespace != 1 or $x->title != "WikiName" ) return failTest( $tn, "$a -> 1, WikiName instead -> $x->namespace , $x->title" );
+       
+       $talkending = "Diskuto";
+       $a = "WikiName/Diskuto"; $x = transformTitle( $a );
+       if( $x->namespace != 1 or $x->title != "WikiName" ) return failTest( $tn, "$a -> 1, WikiName instead -> $x->namespace , $x->title" );
+
+       $talkending = $oldtalkending;
+       return passTest( $tn );
+}
+
+function testMediaLinks() {
+       $tn = "MediaLinks";
+
+       # Fetch
+       $a = "magic.gif";
+       $x = fetchMediaFile( "???", "magic.gif" );
+       
+
+       # Media links
+       $a = "[http://www.wikipedia.org/upload/magic.gif]";
+       $b = "[[Media:Magic.gif]]"; # Or should it?
+       $x = fixMediaLinks( $a );
+       if( $x != $b ) return failTest( $tn, "$a should be $b, is $x" );
+       
+       $a = "[http://www.wikipedia.org/upload/magic.gif Click image]";
+       $b = "[[Media:Magic.gif|Click image]]";
+       $x = fixMediaLinks( $a );
+       if( $x != $b ) return failTest( $tn, "$a should be $b, is $x" );
+
+       # Image links:
+       $a = "http://www.wikipedia.org/upload/magic.gif";
+       $b = "[[Image:Magic.gif]]";
+       $x = fixImageLinks( $a );
+       if( $x != $b ) return failTest( $tn, "$a should be $b, is $x" );
+
+       $a = "http://www.wikipedia.org/upload/a/a4/magic.gif";
+       $b = "[[Image:Magic.gif]]";
+       $x = fixImageLinks( $a );
+       if( $x != $b ) return failTest( $tn, "$a should be $b, is $x" );
+
+       return passTest( $tn );
+}
+
+function testRemoveTalkLink() {
+       global $talkending;
+       $tn = "RemoveTalkLink";
+       $oldtalkending = $talkending;
+       $talkending = "Talk";
+       
+       $a = "Blah blah blah blah\nFoo bar baz.\n/Talk";
+       $b = "Blah blah blah blah\nFoo bar baz.";
+       $x = removeTalkLink( $a );
+       if( $x != $b ) return failTest( $tn, "removing talk link: '$a' -> '$x', should be '$b'" );
+       
+       $a = "Blah blah blah blah\nFoo bar baz.\n[[/Talk]]";
+       $b = "Blah blah blah blah\nFoo bar baz.";
+       $x = removeTalkLink( $a );
+       if( $x != $b ) return failTest( $tn, "removing talk link: '$a' -> '$x', should be '$b'" );
+
+       $a = "Blah blah blah blah\nFoo bar baz.\n/talk"; # wait... should this not work?
+       $b = "Blah blah blah blah\nFoo bar baz.";
+       $x = removeTalkLink( $a );
+       if( $x != $b ) return failTest( $tn, "removing talk link: '$a' -> '$x', should be '$b'" );
+
+       $talkending = "Priparolu";
+       $a = "Blah blah blah blah\nFoo bar baz.\n/Priparolu";
+       $b = "Blah blah blah blah\nFoo bar baz.";
+       $x = removeTalkLink( $a );
+       if( $x != $b ) return failTest( $tn, "removing talk link: '$a' -> '$x', should be '$b'" );
+       
+       $talkending = $oldtalkending;
+       return passTest( $tn );
+}
+
+function testSubPages() {
+       $tn = "SubPages";
+       
+       $t = "TopPage";
+       $a = "Blah /Subpage blah";
+       $b = "Blah [[TopPage/Subpage|/Subpage]] blah";
+       $x = fixSubPages( $a, $t );
+       if ( $x != $b ) return failTest( "'$a' -> '$x', should be '$b'" );
+       
+       $a = "Blah /subpage blah";
+       $b = $a;
+       $x = fixSubPages( $a, $t );
+       if ( $x != $b ) return failTest( "'$a' -> '$x', should be '$b'" );
+       
+       $a = "Blah [[/Subpage]] blah";
+       $b = "Blah [[TopPage/Subpage|/Subpage]] blah";
+       $x = fixSubPages( $a, $t );
+       if ( $x != $b ) return failTest( "'$a' -> '$x', should be '$b'" );
+       
+       $a = "Blah [[/subpage]] blah";
+       $b = "Blah [[TopPage/Subpage|/subpage]] blah";
+       $x = fixSubPages( $a, $t );
+       if ( $x != $b ) return failTest( "'$a' -> '$x', should be '$b'" );
+       
+       $a = "Blah [[/Subpage|Fizzle]] blah";
+       $b = "Blah [[TopPage/Subpage|Fizzle]] blah";
+       $x = fixSubPages( $a, $t );
+       if ( $x != $b ) return failTest( "'$a' -> '$x', should be '$b'" );
+
+       $a = "Blah [[/subpage|Fizzle]] blah";
+       $b = "Blah [[TopPage/Subpage|Fizzle]] blah";
+       $x = fixSubPages( $a, $t );
+       if ( $x != $b ) return failTest( "'$a' -> '$x', should be '$b'" );
+       
+       $a = "Blah /\xc9cole blah";
+       $b = "Blah [[TopPage/\xc9cole|/\xc9cole]] blah";
+       $x = fixSubPages( $a, $t );
+       if ( $x != $b ) return failTest( "'$a' -> '$x', should be '$b'" );
+       
+       $a = "Blah /\xe9cole blah";
+       $b = $a;
+       $x = fixSubPages( $a, $t );
+       if ( $x != $b ) return failTest( "'$a' -> '$x', should be '$b'" );
+       
+       $a = "Blah [[/\xc9cole]] blah";
+       $b = "Blah [[TopPage/\xc9cole|/\xc9cole]] blah";
+       $x = fixSubPages( $a, $t );
+       if ( $x != $b ) return failTest( "'$a' -> '$x', should be '$b'" );
+       
+       $a = "Blah [[/\xe9cole]] blah";
+       $b = "Blah [[TopPage/\xe9cole|/\xe9cole]] blah";
+       $x = fixSubPages( $a, $t );
+       if ( $x != $b ) return failTest( "'$a' -> '$x', should be '$b'" );
+       
+       $a = "Blah [[/xe9cole|Fizzle]] blah";
+       $b = "Blah [[TopPage/\xe9cole|Fizzle]] blah";
+       $x = fixSubPages( $a, $t );
+       if ( $x != $b ) return failTest( "'$a' -> '$x', should be '$b'" );
+
+       $a = "Blah [[/subpage|Fizzle]] blah";
+       $b = "Blah [[TopPage/\xe9cole|Fizzle]] blah";
+       $x = fixSubPages( $a, $t );
+       if ( $x != $b ) return failTest( "'$a' -> '$x', should be '$b'" );
+       return passTest( $tn );
+}
+
+?>
+</body>
+</html>
diff --git a/maintenance/archives/importUseModWiki.php b/maintenance/archives/importUseModWiki.php
new file mode 100644 (file)
index 0000000..5e033a5
--- /dev/null
@@ -0,0 +1,468 @@
+<?php
+
+/*
+       Import data from a UseModWiki into a PediaWiki wiki
+       2003-02-09 Brion VIBBER <brion@pobox.com>
+       Based loosely on Magnus's code from 2001-2002
+
+         Pass one: collect data on links & title case, users
+         Pass two: spit out SQL for
+         Separately, be sure to run the link & index rebuilding scripts!
+
+  */
+
+/* globals
+       */
+$wgRootDirectory = "/home/brion/vikio/wiki-ca/lib-http/db/wiki";
+$wgFieldSeparator = "\xb3"; # Some wikis may use different char
+       $FS = $wgFieldSeparator ;
+       $FS1 = $FS."1" ;
+       $FS2 = $FS."2" ;
+       $FS3 = $FS."3" ;
+
+# Images to import
+$imageimport = '(http:\/\/(?:www\.|meta\.|)wikipedia\.(?:com|org)\/upload\/(?:[a-z]\/[a-z][0-9]\/)?(.*\.(?:gif|jpg|jpeg|png)))';
+
+# Number of *seconds to add* to timestamp to get UTC/GMT
+#$wgTimezoneCorrection = 0;            # GMT
+$wgTimezoneCorrection = 8*3600;        # PST - California
+
+# Other options...
+$historyonly = false;          # Don't add converted revisions to cur table; just get old histories
+$lasthistoryonly = false;      # Only add the _original_ form of the _current_ revision
+
+/* Vary by language */
+$namespaces = array( 0 => "", 1 => "Talk:", 2 => "User:", 3 => "User_talk:", 4
+=> "Wikipedia:", 5 => "Wikipedia_talk:", 6 => "Image:", 7 => "Image_talk:" );
+$talkending = "Talk";
+$mediatext = "Media";
+$conversionscript = "Conversion script";
+$conversioncomment = "Automatic conversion";
+$redirectcomment = "Automatic converion, moved to \$1";
+$conversiontime = gmdate( "YmdHis" ); # Conversions will be marked with this timestamp
+
+# Stats and caches
+$oldtitles = array();
+$usercache = array();
+$titlecache = array();
+$linkcache = array();
+
+# Some oversimplified test types
+class Title {
+       var $title, $namespace;
+       function fromData( $namespace, $title ) {
+               $x = new Title;
+               $x->namespace = $namespace;
+               $x->title = $title;
+               return $x;
+       }
+}
+
+# See tests in importTests.php
+if( ! $testingonly ) {
+       firstPass();
+       secondPass();
+}
+
+# ------------------------------------------------------------------------------
+
+/* First pass:
+       Information please!
+       */
+function firstPass()
+{
+       global $wgRootDirectory, $oldtitles;
+       
+       $letters = array(
+               'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I',
+               'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R',
+               'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'other' );
+       foreach( $letters as $letter ) {
+               firstPassDirectory( "$wgRootDirectory/page/$letter" );
+       }
+}
+
+function firstPassDirectory( $dir )
+{
+       global $titlecache;
+       
+       $mydir = opendir( $dir );
+       while( $entry = readdir( $mydir ) ) {
+               if( $entry != '.' && $entry != '..' ) {
+                       if( is_dir( "$dir/$entry" ) ) {
+                               firstPassDirectory( "$dir/$entry" );
+                       }
+               } elseif( preg_match( '/$(.+)\.db$/', $entry, $m ) ) {
+                       $titlecache[$title] = transformTitle( $m[1] );
+                       countLinksFrom( $title );
+               } else {
+                       echo "-- File '$entry' doesn't seem to contain an article. Skipping.\n";
+               }
+       }
+}
+
+/* Second pass:
+       make the dang SQL
+       */
+function secondPass()
+{
+       global $titlecache, $usercache, $redirects;
+       
+       foreach( $usercache as $oldname => $user ) {
+               echo importUser( $oldname );
+       }
+       foreach( $titlecache as $oldtitle => $newtitle ) {
+               echo importPage( $oldtitle );
+       }
+       
+       echo "\n-- Done!\n";
+}
+
+
+# ------------------------------------------------------------------------------
+
+/* fetch_ functions
+       Grab a given item from the database
+       */
+function fetchUser( $uid )
+{
+       global $FS,$FS2,$FS3, $wgRootDirectory;
+       
+       $fname = $wgRootDirectory . "/pages/" . $title;
+       if( !file_exists( $fname ) ) return false;
+       
+       $data = splitHash( implode( "", file( $fname ) ) );
+       # enough?
+       
+       return $data;
+}
+
+function fetchPage( $title )
+{
+       global $FS,$FS2,$FS3, $wgRootDirectory;
+       
+       $fname = $wgRootDirectory . "/pages/" . $title;
+       if( !file_exists( $fname ) ) return false;
+       
+       $page = splitHash( implode( "", file( $fname ) ) );
+       $section = splitHash( $FS2, $page["text_default"] );
+       $text = splitHash( $FS3, $section["data"] );
+       
+       return array ( "text" => $text["text"] , "summary" => $text["summary"] ,
+               "minor" => $text["minor"] , "ts" => $section["ts"] ,
+               "username" => $section["username"] , "host" => $section["host"] ) ;
+}
+
+function fetchKeptPages( $title )
+{
+       global $FS,$FS2,$FS3, $wgRootDirectory, $wgTimezoneCorrection;
+       
+       $fname = $wgRootDirectory . "/keep/" . $title . ".kp";
+       if( !file_exists( $fname ) ) return array();
+       
+       $keptlist = explode( $FS1, implode( "", file( $fname ) ) );
+       array_shift( $keptlist ); # Drop the junk at beginning of file
+       
+       $revisions = array();
+       foreach( $keptlist as $rev ) {
+               $section = splitHash( $FS2, $rev );
+               $text = splitHash( $FS3, $section["data"] );
+               if ( $text["text"] && $text["minor"] != "" && ( $section["ts"]*1 > 0 ) ) {
+                       array_push( $revisions, array ( "text" => $text["text"] , "summary" => $text["summary"] ,
+                               "minor" => $text["minor"] , "ts" => $section["ts"] ,
+                               "username" => $section["username"] , "host" => $section["host"] ) );
+               } else {
+                       echo "-- skipped a bad old revision\n";
+               }
+       }
+       return $revisions;
+}
+
+function splitHash ( $sep , $str ) {
+       $temp = explode ( $sep , $str ) ;
+       $ret = array () ;
+       for ( $i = 0; $i+1 < count ( $temp ) ; $i++ ) {
+               $ret[$temp[$i]] = $temp[++$i] ;
+               }
+       return $ret ;
+       }
+
+
+/* import_ functions
+       Take a fetched item and produce SQL
+       */
+
+/* importUser
+       $uid is the UseMod user id number.
+       The new ones will be assigned arbitrarily and are for internal use only.
+       
+       THIS IS DELAYED SINCE PUBLIC DUMPS DONT INCLUDE USER DIR
+       */
+function importUser( $uid )
+{
+       global $last_uid, $user_list, $wgTimestampCorrection;
+
+       return "";
+
+       $stuff = fetchUser( $uid );
+       $last_uid++;
+
+       $name = wfStrencode( $stuff->username );
+       $hash = md5hash( $stuff->password ); # Doable?
+       $tzoffset = $stuff['tzoffset'] - ($wgTimestampCorrection / 3600); # -8 to 0; +9 to +1
+       $hideminor = ($stuff['rcall'] ? 0 : 1);
+       $options = "cols={$stuff['editcols']}
+rows={$stuff['editrows']}
+rcdays={$stuff['rcdays']}
+timecorrection={$tzoffset}
+hideminor={$hideminor}
+       ";
+       
+       $sql = "INSERT
+               INTO user (user_id,user_name,user_password,user_options)
+               VALUES ({$last_uid},'{$name}','{$hash}','{$options}');\n";
+       return $sql;
+}
+
+function checkUserCache( $name, $host )
+{
+       global $usercache;
+
+       if( $name ) {
+               if( in_array( $name, $usercache ) ) {
+                       $userid = $usercache[$name];
+               } else {
+                       # If we haven't imported user accounts
+                       $userid = 0;
+               }
+               $username = wfStrencode( $name );
+       } else {
+               $userid = 0;
+               $username = wfStrencode( $host );
+       }
+       return array( $userid, $username );
+}
+
+function importPage( $title )
+{
+       global $wgTimezoneCorrection, $titlecache, $usercache;
+       global $conversionscript, $conversioncomment, $conversiontime;
+       global $historyonly, $lasthistoryonly;
+       
+       $page = fetchPage( $title );
+
+       $newtext = wfStrencode( rewritePage( $title, $page->text ) );
+       $t = renamePage( $title );
+       $newtitle = wfStrencode( $t->title );
+       $namespace = $t->namespace;
+               
+       # Current revision:
+       $text = wfStrencode( $page->text );
+       $minor = ($page->minor ? 1 : 0);
+       list( $userid, $username ) = checkUserCache( $page->username, $page->host );
+       $timestamp = wfUnix2Timestamp( $page->timestamp + $wgTimezoneCorrection );
+       $redirect = ( preg_match( '/^#REDIRECT/', $page->text ) ? 1 : 0 );
+       $sql = "\n";
+       if( !$historyonly ) {
+               $sql .= "INSERT
+               INTO cur (cur_namespace,cur_title,cur_text,cur_comment,cur_user,cur_user_text,cur_timestamp,cur_is_redirect,cur_minor_edit)
+               VALUES ($namespace,'$newtitle','$newtext','$conversioncomment',0,'$conversionscript','$conversiontime',$redirect,$minor);\n";
+       }
+       $sql .= "INSERT
+               INTO old (old_namespace,old_title,old_text,old_comment,old_user,old_user_text,old_timestamp,old_minor_edit)
+               VALUES";
+       $sqlfinal = "\t\t($namespace,'$newtitle','$text','$comment',$userid,'$username','$timestamp',$minor)\n";
+
+       # History
+       if( !$lasthistoryonly ) {
+               $revisions = fetchKeptPages( $title );
+               foreach( $revisions as $rev ) {
+                       $text = wfStrencode( $rev->text );
+                       $minor = ($rev->minor ? 1 : 0);
+                       list( $userid, $username ) = checkUserCache( $rev->username, $rev->host );
+                       $timestamp = wfUnix2Timestamp( $rev->timestamp + $wgTimezoneCorrection );
+                       $sql .= "\t\t($namespace,'$newtitle','$text','$comment',$userid,'$username','$timestamp',$redirect,$minor),\n";
+               }
+       }
+       return $sql . $sqlfinal;
+}
+
+
+# Count up basic links
+function countLinksFrom( $title )
+{
+       $page = fetchPage( $title );
+       $page->text = preg_replace(
+               '/<nowiki>.*<\/nowiki>/sDU',
+               '',
+               $page->text );
+       $page->text = preg_replace(
+               '/\[\[\s*([0-9a-zA-Z_ \x80-\xff]+)\s*(?:\|\s*([^]]+))?\s*\]\]/e',
+               'countLinkTo( ucfirst( "$1" ) )',
+               $page->text );
+}
+
+function countLinkTo( $title )
+{
+       global $linkcache;
+       $t = transformTitle( $title );
+       $linkform = FreeToNormal( $t->title );
+       $x = $linkcache[$title];
+       if ( count ( $x ) ) {
+               $y = $x[$linkform] ;
+               if ( $y ) $y++; else $y = 1 ;
+               $x[$linkform] = $y ;
+       } else {
+               $x = array ( $linkform => 1 ) ;
+       }
+       $linkcache[$title] = $x;
+}
+
+# Preferentially change case
+function renamePage( $title )
+{
+       global $linkcache;
+       $t = transformTitle( $title );
+       
+       # We want to use the most frequently linked-to form as the title
+       $maxcount = 0 ; $maxform = $t->title ;
+       foreach ( $linkcache[$title] as $linkform => $count ) {
+               if ( $count > $maxcount ) {
+                       $maxcount = $count ;
+                       $maxform = $linkform ;
+               }
+       }
+       if( $maxform != $t->title) {
+               doRenamePage( $t, $maxform );
+       }
+}
+
+function doRenamePage( $title, $maxform )
+{
+       global $linkcache, $redirectcomment, $conversionscript, $conversiontime;
+       $sql = "INSERT INTO cur (cur_namespace,cur_title,cur_text,cur_comment,cur_user,cur_user_text,cur_timestamp,cur_is_redirect,cur_minor_edit)
+       VALUES ";
+       $redirsql = array();
+       foreach( $linkcache[$title] as $linkform => $count ) {
+               if( $linkform != $maxform ) {
+                       $comment = wfStrencode( str_replace( "$1", $maxform, $redirectcomment ) );
+                       array_push( $redirsql, "($namespace,'$redirtitle','$comment',0,'$conversionscript','$conversiontime',1,1)" );
+               }
+       }
+       $sql .= implode( ",\n\t", $redirsql ) . ";\n";
+       return $sql;
+}
+
+# Account for syntax changes
+function rewritePage( $title, $text )
+{
+       # ...
+       $text = removeTalkLink( $text );
+       $text = preg_replace( '/(^|<nowiki>).+?(<\/nowiki>|$)/esD',
+               'rewritePageBits( $title, "$1")',
+               $text );
+       return $text;
+}
+
+function rewritePageBits( $title, $text ) {
+       $text = fixSubpages( $title, $text );
+       $text = fixMedialinks( $text );
+       $text = fixImagelinks( $text );
+       return $text;
+}
+
+function removeTalkLink( &$text ) {
+       global $talkending;
+       return preg_replace( "[\\n*(?:\[\[)?/{$talkending}(?:\]\])?\\s*]sDi", '', $text );
+}
+
+function fixSubpages( $text, &$title ) {
+       $old = preg_quote( $text );
+       $text = preg_replace( "<(^|\s)/([A-Z\xc0-\xdf].*?)\b>",
+               "$1[[$title/$2|/$2]]", $text );
+       $text = preg_replace( "<\[\[/([^|]*?)\]\]>e",
+               "\"[[$title/\" . ucfirst( \"$1|/$1]]\" )", $text );
+       $text = preg_replace( "<\[\[/(.*?)\]\]>e",
+               "\"[[$title/\" . ucfirst( \"$1]]\" )", $text );
+       return $text;
+}
+
+function fixImagelinks( &$text ) {
+       global $imageimport, $namespaces;
+       return preg_replace( "/$imageimport/e",
+               '"[[{$namespaces[6]}" . fetchMediaFile( "$1", "$2" ) . "]]"',
+               $text );
+}
+
+function fixMedialinks( &$text ) {
+       global $imageimport, $mediatext;
+       $text = preg_replace( "/\[$imageimport\]/e",
+               '"[[$mediatext:" . fetchMediaFile( "$1", "$2" ) . "]]"',
+               $text );
+       return preg_replace( "/\[$imageimport (.+?)\]/e",
+               '"[[$mediatext:" . fetchMediaFile( "$1", "$2" ) . "|$3]]"',
+               $text );
+}
+
+function fetchMediaFile( $url, $filename )
+{
+       # Copy an image file into local upload space
+       # FIXME
+       return ucfirst( $filename );
+}
+
+# Simple move of talk pages, etc
+function transformTitle( $title, $dorename = false )
+{
+       global $talkending;
+       if( preg_match( "/^(.+)[ _]?\\/[ _]?($talkending)/i", $title, $m ) ) {
+               $thetitle = $m[1];
+               $namespace = 1;
+       } else {
+               $thetitle = $title;
+               $namespace = 0;
+       }
+       return Title::fromData( $namespace, $thetitle );
+}
+
+# Translated out of old usemod wiki...
+function FreeToNormal ( $id , $FreeUpper = true ) {
+  $id = str_replace ( " ", "_", $id ) ;
+  $id = ucfirst($id);
+  if (strstr($id, '_') != false) {  # Quick check for any space/underscores
+    $id = preg_replace ( '/__+/' , "_" , $id ) ;
+    $id = preg_replace ( '/^_/' , "", $id ) ;
+    $id = preg_replace ( '/_$/' , "", $id ) ;
+    #if ($UseSubpage) {
+      $id = preg_replace ( '|_/|', "/" , $id ) ;
+      $id = preg_replace ( '|/_|', "/" , $id ) ;
+    #}
+  }
+  if ($FreeUpper) {
+    # Note that letters after ' are *not* capitalized
+    if (preg_match ( '|[-_.,\(\)/][a-z]|' , $id ) ) { # Quick check for non-canon
+      $id = preg_replace ( '|([-_.,\(\)/])([a-z])|e' , '"$1" . strtoupper("$2")' , $id ) ;
+    }
+  }
+  return $id;
+}
+
+# Whee!
+function recodeInput( $text )
+{
+       return $text;
+}
+
+function wfUnix2Timestamp( $unixtime ) {
+        return gmdate( "YmdHis", $timestamp );
+}
+
+function wfTimestamp2Unix( $ts )
+{
+        return gmmktime( ( (int)substr( $ts, 8, 2) ),
+                  (int)substr( $ts, 10, 2 ), (int)substr( $ts, 12, 2 ),
+                  (int)substr( $ts, 4, 2 ), (int)substr( $ts, 6, 2 ),
+                  (int)substr( $ts, 0, 4 ) );
+}
+
+?>
diff --git a/maintenance/archives/patch-bot.sql b/maintenance/archives/patch-bot.sql
new file mode 100644 (file)
index 0000000..c171afa
--- /dev/null
@@ -0,0 +1,11 @@
+-- Add field to recentchanges for easy filtering of bot entries
+-- edits by a user with 'bot' in user.user_rights should be
+-- marked 1 in rc_bot.
+
+-- Change made 2002-12-15 by Brion VIBBER <brion@pobox.com>
+-- this affects code in Article.php, User.php SpecialRecentchanges.php
+-- column also added to buildTables.inc
+
+ALTER TABLE recentchanges
+  ADD COLUMN rc_bot tinyint(3) unsigned NOT NULL default '0'
+  AFTER rc_minor;
diff --git a/maintenance/archives/patch-cache.sql b/maintenance/archives/patch-cache.sql
new file mode 100644 (file)
index 0000000..6ce484b
--- /dev/null
@@ -0,0 +1,41 @@
+-- patch-cache.sql
+-- 2003-03-22  <brion@pobox.com>
+--
+-- Add 'last touched' fields to cur and user tables.
+-- These are useful for maintaining cache consistency.
+-- (Updates to OutputPage.php and elsewhere.)
+--
+-- cur_touched should be set to the current time whenever:
+--  * the page is updated
+--  * a linked page is created
+--  * a linked page is destroyed
+--
+-- The cur_touched time will then be compared against the
+-- timestamps of cached pages to ensure consistency; if
+-- cur_touched is later, the page must be regenerated.
+
+ALTER TABLE cur
+  ADD COLUMN cur_touched char(14) binary NOT NULL default '';
+
+-- Existing pages should be initialized to the current
+-- time so they don't needlessly rerender until they are
+-- changed for the first time:
+
+UPDATE cur
+  SET cur_touched=NOW()+0;
+
+-- user_touched should be set to the current time whenever:
+--  * the user logs in
+--  * the user saves preferences (if no longer default...?)
+--  * the user's newtalk status is altered
+--
+-- The user_touched time should also be checked against the
+-- timestamp reported by a browser requesting revalidation.
+-- If user_touched is later than the reported last modified
+-- time, the page should be rerendered with new options and
+-- sent again.
+
+ALTER TABLE user
+  ADD COLUMN user_touched char(14) binary NOT NULL default '';
+UPDATE user
+  SET user_touched=NOW()+0;
diff --git a/maintenance/archives/patch-list.txt b/maintenance/archives/patch-list.txt
new file mode 100644 (file)
index 0000000..b660a5b
--- /dev/null
@@ -0,0 +1,107 @@
+List of database patches and upgrades as the PediaWiki software evolves...
+
+* 2002-11-23: Search index format changed for UTF-8 wikis
+For wikis using the UTF-8 languages, the search index entries
+need to be rebuild to allow searching to work. (Other wikis
+that have been run through the old phase2->phase3 conversion
+script should also be reindexed to catch apostrophe misplacement.)
+
+Run rebuildIndex.php on your wiki.
+
+
+
+* 2002-11-27: Watchlist format changed
+Converts the user_watchlist entries out to a separate table which
+links user_id<->cur_id and can be more handily queried.
+
+Run upgradeWatchlist.php on your wiki.
+
+
+
+* 2002-12-14: Recentchanges table bot/hidden column
+Adds a column to indicate changes by registered bots (or perhaps
+later other admin actions) that should be hidden from the default
+Recentchanges list because people think they're tedious, but should
+still be available in article histories, contribs lists, and
+power-user RC lists.
+
+Run bot.sql against your database.
+
+
+
+* 2002-12-17: Watchlist format changed again
+Now using namespace, title instead of cur_id. This can track deleted/
+recreated pages better, makes it easier to handle talk pages (now with
+the auto-watch feature there's a lot more watching of talk pages!)
+and whatnot.
+
+Run patch-watchlist.sql against your database. If all is well, drop
+the oldwatchlist table which is no longer needed. (Note that this update
+also drops the vestigial user_watchlist column.)
+
+
+
+* 2002-12-26: TeX math rendering adds 'math' table
+A new 'math' table is used to cache TeX sections.
+
+Run patch-math.sql against your database, and add 'tmp' and 'math'
+subdirectories to your tree alongside the upload directory, and copy
+the 'math' source subdirectory under the wiki's PHP directory and run
+"make" to compile the texvc evaluator. (whew!)
+
+TeX support requires TeX, OCaml, and ImageMagick. If you don't want
+to use TeX support on your wiki, you can globally disable it by
+setting $wgUseTeX=false in LocalSettings.php.
+
+
+
+* 2003-01-25: searchindex table
+A new 'searchindex' table separates the fulltext index fields from
+'cur'. This enables use of InnoDB tables, which don't support fulltext
+search, for the main data, and will keep junk out of the backup dumps.
+
+Run patch-searchindex.sql on the database. If you wish to change table
+tables on the others, use 'alter table' manually. (See MySQL docs.)
+
+
+* 2003-01-24: Talk pages for anonymous users
+A new table user_newtalk contains a list of talk pages that were
+changed, both pages by anonymous and those by non-anonymous users.
+
+Run patch-usernewtalk.sql if your database was created before
+this date.
+
+
+* 2003-02-02: Math table changed
+Rerun patch-math.sql to recreate it.
+
+* 2003-02-03: Index added to USER table for performance reasons. Run
+patch-userindex.sql to create it.
+
+
+* 2003-02-09: Random table & inverse timestamps
+The random page queue table has been removed in favor of a column
+in the cur table. This eliminates the ssllooww queue refill step;
+pre-storing random indices in an indexed column means we can do the
+random sort instantly; each element is re-randomized upon selection.
+
+Also, an inverse_timestamp field has been added to the cur and old
+tables. This will allow fast index-based sorting in history lists,
+user contribs, linked recentchanges, etc with MySQL 3, which doesn't
+allow DESC ordering on an indexed field. This may be removed later
+when MySQL is found to be stable.
+
+
+* 2003-03-22: Last touched fields for caching
+'Last touched' timestamp fields have been added to the cur and user
+tables to aid in maintaining cache consistency. Web clients will
+be forced to reload a page if it has been touched since the client's
+cached copy (this will catch indirect changes like creation of
+linked pages) or if a user changes preferences or logs in anew (so
+visual changes and login status are taken into account).
+
+Run patch-cache.sql on the database to set these fields up. This is
+required for changes to OutputPage.php and elsewhere to continue
+working on an older database.
+
+OutputPage.php User.php maintenance/buildTables.inc maintenance/patch-cache.sql maintenance/patch-list.txt
diff --git a/maintenance/archives/patch-math.sql b/maintenance/archives/patch-math.sql
new file mode 100644 (file)
index 0000000..430fb7a
--- /dev/null
@@ -0,0 +1,16 @@
+-- Creates table math used for caching TeX blocks.  Needs to be run
+-- on old installations when adding TeX support (2002-12-26)
+-- Or, TeX can be disabled via $wgUseTeX=false in LocalSettings.php
+
+-- Note: math table has changed, and this script needs to be run again
+-- to create it. (2003-02-02)
+
+DROP TABLE IF EXISTS math;
+CREATE TABLE math (
+    math_inputhash varchar(16) NOT NULL,
+    math_outputhash varchar(16) NOT NULL,
+    math_html_conservativeness tinyint(1) NOT NULL,
+    math_html text,
+    math_mathml text,
+    UNIQUE KEY math_inputhash (math_inputhash)
+);
diff --git a/maintenance/archives/patch-random-dateindex.sql b/maintenance/archives/patch-random-dateindex.sql
new file mode 100644 (file)
index 0000000..e239827
--- /dev/null
@@ -0,0 +1,54 @@
+-- patch-random-dateindex.sql
+-- 2003-02-09
+--
+-- This patch does two things:
+--  * Adds cur_random column to replace random table
+--    (Requires change to SpecialRandom.php)
+--    random table no longer needs refilling
+--    Note: short-term duplicate results *are* possible, but very unlikely on large wiki
+--
+--  * Adds inverse_timestamp columns to cur and old and indexes
+--    to allow descending timestamp sort in history, contribs, etc
+--    (Requires changes to Article.php, DatabaseFunctions.php,
+--     ... )
+--                       cur_timestamp  inverse_timestamp
+--     99999999999999 - 20030209222556 = 79969790777443
+--     99999999999999 - 20030211083412 = 79969788916587
+--
+--    We won't need this on MySQL 4; there will be a removal patch later.
+
+-- Indexes:
+-- cur needs (cur_random) for random sort
+-- cur and old need (namespace,title,timestamp) index for history,watchlist,rclinked
+-- cur and old need (user,timestamp) index for contribs
+-- cur and old need (user_text,timestamp) index for contribs
+
+ALTER TABLE cur
+  DROP INDEX cur_user,
+  DROP INDEX cur_user_text,
+  ADD COLUMN cur_random real unsigned NOT NULL,
+  ADD COLUMN inverse_timestamp char(14) binary NOT NULL default '',
+  ADD INDEX (cur_random),
+  ADD INDEX name_title_timestamp (cur_namespace,cur_title,inverse_timestamp),
+  ADD INDEX user_timestamp (cur_user,inverse_timestamp),
+  ADD INDEX usertext_timestamp (cur_user_text,inverse_timestamp);
+
+UPDATE cur SET
+  inverse_timestamp=99999999999999-cur_timestamp,
+  cur_random=RAND();
+
+ALTER TABLE old
+  DROP INDEX old_user,
+  DROP INDEX old_user_text,
+  ADD COLUMN inverse_timestamp char(14) binary NOT NULL default '',
+  ADD INDEX name_title_timestamp (old_namespace,old_title,inverse_timestamp),
+  ADD INDEX user_timestamp (old_user,inverse_timestamp),
+  ADD INDEX usertext_timestamp (old_user_text,inverse_timestamp);
+
+UPDATE old SET
+  inverse_timestamp=99999999999999-old_timestamp;
+
+-- If leaving wiki publicly accessible in read-only mode during
+-- the upgrade, comment out the below line; leave 'random' table
+-- in place until the new software is installed.
+DROP TABLE random;
diff --git a/maintenance/archives/patch-searchindex.sql b/maintenance/archives/patch-searchindex.sql
new file mode 100644 (file)
index 0000000..aafe21f
--- /dev/null
@@ -0,0 +1,33 @@
+-- Break fulltext search index out to separate table from cur
+-- This is being done mainly to allow us to use InnoDB tables
+-- for the main db while keeping the MyISAM fulltext index for
+-- search.
+
+-- 2002-12-16, 2003-01-25 Brion VIBBER <brion@pobox.com>
+
+-- Creating searchindex table...
+DROP TABLE IF EXISTS searchindex;
+CREATE TABLE searchindex (
+  si_page int(8) unsigned NOT NULL,
+  si_title varchar(255) NOT NULL default '',
+  si_text mediumtext NOT NULL default '',
+  UNIQUE KEY (si_page)
+) TYPE=MyISAM PACK_KEYS=1;
+
+-- Copying data into new table...
+INSERT INTO searchindex
+  (si_page,si_title,si_text)
+  SELECT
+    cur_id,cur_ind_title,cur_ind_text
+    FROM cur;
+
+
+-- Creating fulltext index...
+ALTER TABLE searchindex
+  ADD FULLTEXT si_title (si_title),
+  ADD FULLTEXT si_text (si_text);
+
+-- Dropping index columns from cur table.
+ALTER TABLE cur
+  DROP COLUMN cur_ind_title,
+  DROP COLUMN cur_ind_text;
diff --git a/maintenance/archives/patch-userindex.sql b/maintenance/archives/patch-userindex.sql
new file mode 100644 (file)
index 0000000..4a178dd
--- /dev/null
@@ -0,0 +1 @@
+ ALTER TABLE `user` ADD INDEX ( `user_name` );
\ No newline at end of file
diff --git a/maintenance/archives/patch-usernewtalk.sql b/maintenance/archives/patch-usernewtalk.sql
new file mode 100644 (file)
index 0000000..735f2cb
--- /dev/null
@@ -0,0 +1,20 @@
+--- This table stores all the IDs of users whose talk
+--- page has been changed (the respective row is deleted
+--- when the user looks at the page).
+--- The respective column in the user table is no longer
+--- required and therefore dropped.
+
+CREATE TABLE user_newtalk (
+  user_id int(5) NOT NULL default '0',
+  user_ip varchar(40) NOT NULL default '',
+  KEY user_id (user_id),
+  KEY user_ip (user_ip)
+) TYPE=MyISAM;
+
+INSERT INTO
+  user_newtalk (user_id, user_ip)
+  SELECT user_id, ''
+    FROM user
+    WHERE user_newtalk != 0;
+
+ALTER TABLE user DROP COLUMN user_newtalk;
diff --git a/maintenance/archives/patch-watchlist.sql b/maintenance/archives/patch-watchlist.sql
new file mode 100644 (file)
index 0000000..adee010
--- /dev/null
@@ -0,0 +1,30 @@
+-- Convert watchlists to new new format ;)
+
+-- Ids just aren't convenient when what we want is to
+-- treat article and talk pages as equivalent.
+-- Better to use namespace (drop the 1 bit!) and title
+
+-- 2002-12-17 by Brion Vibber <brion@pobox.com>
+-- affects, affected by changes to SpecialWatchlist.php, User.php,
+-- Article.php, Title.php, SpecialRecentchanges.php
+
+DROP TABLE IF EXISTS watchlist2;
+CREATE TABLE watchlist2 (
+  wl_user int(5) unsigned NOT NULL,
+  wl_namespace tinyint(2) unsigned NOT NULL default '0',
+  wl_title varchar(255) binary NOT NULL default '',
+  UNIQUE KEY (wl_user, wl_namespace, wl_title)
+) TYPE=MyISAM PACK_KEYS=1;
+
+INSERT INTO watchlist2 (wl_user,wl_namespace,wl_title)
+  SELECT DISTINCT wl_user,(cur_namespace | 1) - 1,cur_title
+  FROM watchlist,cur WHERE wl_page=cur_id;
+
+ALTER TABLE watchlist RENAME TO oldwatchlist;
+ALTER TABLE watchlist2 RENAME TO watchlist;
+
+-- Check that the new one is correct, then:
+-- DROP TABLE oldwatchlist;
+
+-- Also should probably drop the ancient and now unused:
+ALTER TABLE user DROP COLUMN user_watch;
diff --git a/maintenance/archives/rebuildRecentchanges.inc b/maintenance/archives/rebuildRecentchanges.inc
new file mode 100644 (file)
index 0000000..6406d0b
--- /dev/null
@@ -0,0 +1,116 @@
+<?
+
+# Rebuild recent changes table.
+
+function rebuildRecentChangesTable()
+{
+       $sql = "DROP TABLE IF EXISTS recentchanges";
+       wfQuery( $sql );
+
+       $sql = "CREATE TABLE recentchanges (
+  rc_timestamp varchar(14) binary NOT NULL default '',
+  rc_cur_time varchar(14) binary NOT NULL default '',
+  rc_user int(10) unsigned NOT NULL default '0',
+  rc_user_text varchar(255) binary NOT NULL default '',
+  rc_namespace tinyint(3) unsigned NOT NULL default '0',
+  rc_title varchar(255) binary NOT NULL default '',
+  rc_comment varchar(255) binary NOT NULL default '',
+  rc_minor tinyint(3) unsigned NOT NULL default '0',
+  rc_new tinyint(3) unsigned NOT NULL default '0',
+  rc_cur_id int(10) unsigned NOT NULL default '0',
+  rc_this_oldid int(10) unsigned NOT NULL default '0',
+  rc_last_oldid int(10) unsigned NOT NULL default '0',
+  INDEX rc_cur_id (rc_cur_id),
+  INDEX rc_cur_time (rc_cur_time),
+  INDEX rc_timestamp (rc_timestamp),
+  INDEX rc_namespace (rc_namespace),
+  INDEX rc_title (rc_title)
+) TYPE=MyISAM PACK_KEYS=1;";
+       wfQuery( $sql );
+
+       print( "Loading from CUR table...\n" );
+
+       $sql = "INSERT INTO recentchanges (rc_timestamp,rc_cur_time,rc_user," .
+         "rc_user_text,rc_namespace,rc_title,rc_comment,rc_minor,rc_new," .
+         "rc_cur_id,rc_this_oldid,rc_last_oldid) SELECT cur_timestamp," .
+         "cur_timestamp,cur_user,cur_user_text,cur_namespace,cur_title," .
+         "cur_comment,cur_minor_edit,cur_is_new,cur_id,0,0 FROM cur " .
+         "ORDER BY cur_timestamp DESC LIMIT 5000";
+       wfQuery( $sql );
+
+       print( "Loading from OLD table...\n" );
+
+       $sql = "INSERT INTO recentchanges (rc_timestamp,rc_cur_time,rc_user," .
+      "rc_user_text,rc_namespace,rc_title,rc_comment,rc_minor,rc_new," .
+      "rc_cur_id,rc_this_oldid,rc_last_oldid) SELECT old_timestamp,''," .
+         "old_user,old_user_text,old_namespace,old_title,old_comment," .
+         "old_minor_edit,0,0,old_id,0 FROM old ORDER BY old_timestamp " .
+         "DESC LIMIT 5000";
+       wfQuery( $sql );
+
+       $sql = "SELECT rc_timestamp FROM recentchanges " .
+         "ORDER BY rc_timestamp DESC LIMIT 5000,1";
+       $res = wfQuery( $sql );
+       $obj = wfFetchObject( $res );
+       $ts = $obj->rc_timestamp;
+
+       $sql = "DELETE FROM recentchanges WHERE rc_timestamp < '{$ts}'";
+       wfQuery( $sql );
+
+       rebuildRecentChangesTablePass2();
+}
+
+function rebuildRecentChangesTablePass2()
+{
+       $ns = $id = $count = 0;
+       $title = $ct =  "";
+
+       print( "Updating links...\n" );
+
+       $sql = "SELECT rc_namespace,rc_title,rc_timestamp FROM recentchanges " .
+         "ORDER BY rc_namespace,rc_title,rc_timestamp DESC";
+       $res = wfQuery( $sql );
+
+       while ( $obj = wfFetchObject( $res ) ) {
+               if ( ! ( $ns == $obj->rc_namespace &&
+                          0 == strcmp( $title, wfStrencode( $obj->rc_title ) ) ) ) {
+
+                       $ns = $obj->rc_namespace;
+                       $title = wfStrencode( $obj->rc_title );
+
+                       $sql = "SELECT cur_id,cur_timestamp FROM cur WHERE " .
+                         "cur_namespace={$ns} AND cur_title='{$title}'";
+                       $res2 = wfQuery( $sql );
+                       $obj2 = wfFetchObject( $res2 );
+
+                       $id = $obj2->cur_id;
+                       $ct = $obj2->cur_timestamp;
+               }
+               $sql = "SELECT old_id FROM old WHERE old_namespace={$ns} " .
+                 "AND old_title='{$title}' AND old_timestamp < '" .
+                 "{$obj->rc_timestamp}' ORDER BY old_timestamp DESC LIMIT 1";
+               $res2 = wfQuery( $sql );
+
+               if ( 0 != wfNumRows( $res2 ) ) {
+                       $obj2 = wfFetchObject( $res2 );
+
+                       $sql = "UPDATE recentchanges SET rc_cur_id={$id},rc_cur_time=" .
+                         "'{$ct}',rc_last_oldid={$obj2->old_id} WHERE " .
+                         "rc_namespace={$ns} AND rc_title='{$title}' AND " .
+                         "rc_timestamp='{$obj->rc_timestamp}'";
+                       wfQuery( $sql );
+               } else {
+                       $sql = "UPDATE recentchanges SET rc_cur_id={$id},rc_cur_time=" .
+                         "'{$ct}' WHERE rc_namespace={$ns} AND rc_title='{$title}' " .
+                         "AND rc_timestamp='{$obj->rc_timestamp}'";
+                       wfQuery( $sql );
+               }
+
+               if ( 0 == ( ++$count % 500 ) ) {
+                       printf( "%d records processed.\n", $count );
+               }
+       }
+}
+
+
+?>
diff --git a/maintenance/archives/upgradeWatchlist.php b/maintenance/archives/upgradeWatchlist.php
new file mode 100644 (file)
index 0000000..d8f5f95
--- /dev/null
@@ -0,0 +1,54 @@
+<?
+# Convert watchlists to new format
+
+global $IP;
+include_once( "../LocalSettings.php" );
+include_once( "$IP/Setup.php" );
+
+$wgTitle = Title::newFromText( "Rebuild links script" );
+set_time_limit(0);
+
+$wgDBuser                      = "wikiadmin";
+$wgDBpassword          = $wgDBadminpassword;
+
+$sql = "DROP TABLE IF EXISTS watchlist";
+wfQuery( $sql );
+$sql = "CREATE TABLE watchlist (
+  wl_user int(5) unsigned NOT NULL,
+  wl_page int(8) unsigned NOT NULL,
+  UNIQUE KEY (wl_user, wl_page)
+) TYPE=MyISAM PACK_KEYS=1";
+wfQuery( $sql );
+
+$lc = new LinkCache;
+
+# Now, convert!
+$sql = "SELECT user_id,user_watch FROM user";
+$res = wfQuery( $sql );
+$nu = wfNumRows( $res );
+$sql = "INSERT into watchlist (wl_user,wl_page) VALUES ";
+$i = $n = 0;
+while( $row = wfFetchObject( $res ) ) {
+       $list = explode( "\n", $row->user_watch );
+       $bits = array();
+       foreach( $list as $title ) {
+               if( $id = $lc->addLink( $title ) and ! $bits[$id]++) {
+                       $sql .= ($i++ ? "," : "") . "({$row->user_id},{$id})";
+               }
+       }
+       if( ($n++ % 100) == 0 ) echo "$n of $nu users done...\n";
+}
+echo "$n users done.\n";
+if( $i ) {
+       wfQuery( $sql );
+}
+
+
+# Add index
+# is this necessary?
+$sql = "ALTER TABLE watchlist
+  ADD INDEX wl_user (wl_user),
+  ADD INDEX wl_page (wl_page)";
+#wfQuery( $sql );
+
+?>
diff --git a/maintenance/build-intl-wiki.sql b/maintenance/build-intl-wiki.sql
new file mode 100644 (file)
index 0000000..f094c8b
--- /dev/null
@@ -0,0 +1,31 @@
+-- Experimental: create shared international database
+-- for new interlinking code.
+--
+
+CREATE DATABASE intl;
+
+GRANT DELETE,INSERT,SELECT,UPDATE ON intl.*
+TO wikiuser@'%' IDENTIFIED BY 'userpass';
+GRANT DELETE,INSERT,SELECT,UPDATE ON intl.*
+TO wikiuser@localhost IDENTIFIED BY 'userpass';
+GRANT DELETE,INSERT,SELECT,UPDATE ON intl.*
+TO wikiuser@localhost.localdomain IDENTIFIED BY 'userpass';
+
+USE intl;
+
+CREATE TABLE ilinks (
+ lang_from varchar(5) default NULL,
+ lang_to varchar(5) default NULL,
+ title_from tinyblob,
+ title_to tinyblob,
+ target_exists tinyint(1) default NULL
+) TYPE=MyISAM;
+
+CREATE TABLE recentchanges (
+ user_name tinyblob,
+ user_lang varchar(5) default NULL,
+ date timestamp(14) NOT NULL,
+ message tinyblob
+) TYPE=MyISAM;
+
+
diff --git a/maintenance/cleandb.php b/maintenance/cleandb.php
new file mode 100644 (file)
index 0000000..cf346a0
--- /dev/null
@@ -0,0 +1,24 @@
+<?
+
+# Creating a new empty database; either this or the conversion
+# script from the old format needs to be run, but not both.
+
+global $IP;
+include_once( "../LocalSettings.php" );
+include_once( "$IP/Setup.php" );
+
+$wgTitle = Title::newFromText( "Database creation script" );
+include_once( "./buildTables.inc" );
+set_time_limit(0);
+
+#$wgDBname                     = "wikidb";
+#$wgDBuser                     = "wikiadmin";
+#$wgDBpassword         = "adminpass";
+
+cleanDatabase();
+initializeTables();
+
+print "Done.\n";
+exit();
+
+?>
diff --git a/maintenance/database.sql b/maintenance/database.sql
new file mode 100644 (file)
index 0000000..812156e
--- /dev/null
@@ -0,0 +1,7 @@
+-- SQL script to create database for wiki.  This is run from
+-- the installation script which replaces the variables with
+-- their values from local settings.
+--
+
+DROP DATABASE IF EXISTS {$wgDBname};
+CREATE DATABASE {$wgDBname};
diff --git a/maintenance/fetchInterwiki.pl b/maintenance/fetchInterwiki.pl
new file mode 100644 (file)
index 0000000..1d688fa
--- /dev/null
@@ -0,0 +1,186 @@
+#!/usr/bin/perl
+
+$intermap = "http://usemod.com/intermap.txt";
+unless( -r "intermap.txt" ) {
+       print "Fetching $intermap...\n";
+       # For some reason we're redirected to microsoft.com with wget useragent
+       print `wget -U "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.0.1) Gecko/20020823 Netscape/7.0" $intermap`;
+}
+
+open IW, ">Interwiki.php";
+print IW "<?
+# Note -- this file is generated by maintenance/fetchInterwiki.pl
+# Edit and rerun that script rather than modifying this directly.
+
+/* private */ \$wgValidInterwikis = array(
+       # General interwiki links from the InterMap
+";
+
+open MAP, "<intermap.txt";
+while( $x = <MAP> ) {
+       $x =~ /^([a-z0-9]+)\s(http:\/\/.+)$/i;
+       ($name, $url) = ($1, $2);
+       print IW "\t\"$name\" => \"$url\$1\",\n";
+}
+
+print IW <<arrgghsomanyofthem
+
+       # Some custom additions:
+       "ReVo"  =>      "http://purl.org/NET/voko/revo/art/\$1.html",
+         # eg [[ReVo:cerami]], [[ReVo:astero]] - note X-sensitive!
+       "EcheI" =>      "http://www.ikso.net/cgi-bin/wiki.pl?\$1",
+       "E\\xc4\\x89eI" =>      "http://www.ikso.net/cgi-bin/wiki.pl?\$1",
+       "UnuMondo"      =>      "http://unumondo.com/cgi-bin/wiki.pl?\$1", # X-sensitive!
+       "JEFO"  =>      "http://esperanto.jeunes.free.fr/vikio/index.php?\$1",
+       "PMEG"  =>      "http://www.bertilow.com/pmeg/\$1.php",
+               # ekz [[PMEG:gramatiko/kunligaj vortetoj/au]]
+       "EnciclopediaLibre" => "http://enciclopedia.us.es/wiki.phtml?title=\$1",
+
+       # Wikipedia-specific stuff:
+       # Special cases
+       "w"             => "http://www.wikipedia.org/wiki/\$1",
+       "m"             => "http://meta.wikipedia.org/wiki/\$1",
+       "meta"          => "http://meta.wikipedia.org/wiki/\$1",
+       "sep11"         => "http://sep11.wikipedia.org/wiki/\$1",
+       "simple"=> "http://simple.wikipedia.com/wiki.cgi?\$1",
+       "wiktionary"    => "http://wiktionary.wikipedia.org/wiki/\$1",
+
+       # ISO 639 2-letter language codes
+       "aa"    => "http://aa.wikipedia.com/wiki.cgi?\$1",
+       "ab"    => "http://ab.wikipedia.com/wiki.cgi?\$1",
+       "af"    => "http://af.wikipedia.com/wiki.cgi?\$1",
+       "am"    => "http://am.wikipedia.com/wiki.cgi?\$1",
+       "ar"    => "http://ar.wikipedia.com/wiki.cgi?\$1",
+       "as"    => "http://as.wikipedia.com/wiki.cgi?\$1",
+       "ay"    => "http://ay.wikipedia.com/wiki.cgi?\$1",
+       "az"    => "http://az.wikipedia.com/wiki.cgi?\$1",
+       "ba"    => "http://ba.wikipedia.com/wiki.cgi?\$1",
+       "be"    => "http://be.wikipedia.com/wiki.cgi?\$1",
+       "bh"    => "http://bh.wikipedia.com/wiki.cgi?\$1",
+       "bi"    => "http://bi.wikipedia.com/wiki.cgi?\$1",
+       "bn"    => "http://bn.wikipedia.com/wiki.cgi?\$1",
+       "bs"    => "http://bs.wikipedia.org/wiki/\$1",
+       "bo"    => "http://bo.wikipedia.com/wiki.cgi?\$1",
+       "ca"    => "http://ca.wikipedia.com/wiki.cgi?\$1",
+       "co"    => "http://co.wikipedia.com/wiki.cgi?\$1",
+       "cs"    => "http://cs.wikipedia.org/wiki/\$1",
+       "cy"    => "http://cy.wikipedia.com/wiki.cgi?\$1",
+       "da"    => "http://da.wikipedia.org/wiki/\$1",
+       "de"    => "http://de.wikipedia.org/wiki/\$1",
+       "dk"    => "http://da.wikipedia.org/wiki/\$1",
+       "dz"    => "http://dz.wikipedia.com/wiki.cgi?\$1",
+       "el"    => "http://el.wikipedia.org/wiki/\$1",
+       "en"    => "http://www.wikipedia.org/wiki/\$1",    # May in future be renamed to en.wikipedia.org; should work as alternate
+       "eo"    => "http://eo.wikipedia.org/wiki/\$1",
+       "es"    => "http://es.wikipedia.org/wiki/\$1",
+       "et"    => "http://et.wikipedia.com/wiki.cgi?\$1",
+       "eu"    => "http://eu.wikipedia.com/wiki.cgi?\$1",
+       "fa"    => "http://fa.wikipedia.com/wiki.cgi?\$1",
+       "fi"    => "http://fi.wikipedia.com/wiki.cgi?\$1",
+       "fj"    => "http://fj.wikipedia.com/wiki.cgi?\$1",
+       "fo"    => "http://fo.wikipedia.com/wiki.cgi?\$1",
+       "fr"    => "http://fr.wikipedia.org/wiki/\$1",
+       "fy"    => "http://fy.wikipedia.com/wiki.cgi?\$1",
+       "ga"    => "http://ga.wikipedia.com/wiki.cgi?\$1",
+       "gl"    => "http://gl.wikipedia.com/wiki.cgi?\$1",
+       "gn"    => "http://gn.wikipedia.com/wiki.cgi?\$1",
+       "gu"    => "http://gu.wikipedia.com/wiki.cgi?\$1",
+       "ha"    => "http://ha.wikipedia.com/wiki.cgi?\$1",
+       "he"    => "http://he.wikipedia.com/wiki.cgi?\$1",
+       "hi"    => "http://hi.wikipedia.com/wiki.cgi?\$1",
+       "hr"    => "http://hr.wikipedia.org/wiki/\$1",
+       "hu"    => "http://hu.wikipedia.com/wiki.cgi?\$1",
+       "hy"    => "http://hy.wikipedia.com/wiki.cgi?\$1",
+       "ia"    => "http://ia.wikipedia.com/wiki.cgi?\$1",
+       "id"    => "http://id.wikipedia.com/wiki.cgi?\$1",
+       "ik"    => "http://ik.wikipedia.com/wiki.cgi?\$1",
+       "is"    => "http://is.wikipedia.com/wiki.cgi?\$1",
+       "it"    => "http://it.wikipedia.com/wiki.cgi?\$1",
+       "iu"    => "http://iu.wikipedia.com/wiki.cgi?\$1",
+       "ja"    => "http://ja.wikipedia.org/wiki/\$1",
+       "jv"    => "http://jv.wikipedia.com/wiki.cgi?\$1",
+       "ka"    => "http://ka.wikipedia.com/wiki.cgi?\$1",
+       "kk"    => "http://kk.wikipedia.com/wiki.cgi?\$1",
+       "kl"    => "http://kl.wikipedia.com/wiki.cgi?\$1",
+       "km"    => "http://km.wikipedia.com/wiki.cgi?\$1",
+       "kn"    => "http://kn.wikipedia.com/wiki.cgi?\$1",
+       "ko"    => "http://ko.wikipedia.org/wiki/\$1",
+       "ks"    => "http://ks.wikipedia.com/wiki.cgi?\$1",
+       "ku"    => "http://ku.wikipedia.com/wiki.cgi?\$1",
+       "ky"    => "http://ky.wikipedia.com/wiki.cgi?\$1",
+       "la"    => "http://la.wikipedia.com/wiki.cgi?\$1",
+       "lo"    => "http://lo.wikipedia.com/wiki.cgi?\$1",
+       "lv"    => "http://lv.wikipedia.com/wiki.cgi?\$1",
+       "mg"    => "http://mg.wikipedia.com/wiki.cgi?\$1",
+       "mi"    => "http://mi.wikipedia.com/wiki.cgi?\$1",
+       "mk"    => "http://mk.wikipedia.com/wiki.cgi?\$1",
+       "ml"    => "http://ml.wikipedia.org/wiki/\$1",
+       "mn"    => "http://mn.wikipedia.com/wiki.cgi?\$1",
+       "mo"    => "http://mo.wikipedia.com/wiki.cgi?\$1",
+       "mr"    => "http://mr.wikipedia.com/wiki.cgi?\$1",
+       "ms"    => "http://ms.wikipedia.org/wiki/\$1",
+       "my"    => "http://my.wikipedia.com/wiki.cgi?\$1",
+       "na"    => "http://na.wikipedia.com/wiki.cgi?\$1",
+       "ne"    => "http://ne.wikipedia.com/wiki.cgi?\$1",
+       "nl"    => "http://nl.wikipedia.org/wiki/\$1",
+       "no"    => "http://no.wikipedia.com/wiki.cgi?\$1",
+       "oc"    => "http://oc.wikipedia.com/wiki.cgi?\$1",
+       "om"    => "http://om.wikipedia.com/wiki.cgi?\$1",
+       "or"    => "http://or.wikipedia.com/wiki.cgi?\$1",
+       "pa"    => "http://pa.wikipedia.com/wiki.cgi?\$1",
+       "pl"    => "http://pl.wikipedia.org/wiki/\$1",
+       "ps"    => "http://ps.wikipedia.com/wiki.cgi?\$1",
+       "pt"    => "http://pt.wikipedia.com/wiki.cgi?\$1",
+       "qu"    => "http://qu.wikipedia.com/wiki.cgi?\$1",
+       "rm"    => "http://rm.wikipedia.com/wiki.cgi?\$1",
+       "rn"    => "http://rn.wikipedia.com/wiki.cgi?\$1",
+       "ro"    => "http://ro.wikipedia.com/wiki.cgi?\$1",
+       "ru"    => "http://ru.wikipedia.org/wiki/\$1",
+       "rw"    => "http://rw.wikipedia.com/wiki.cgi?\$1",
+       "sa"    => "http://sa.wikipedia.com/wiki.cgi?\$1",
+       "sd"    => "http://sd.wikipedia.com/wiki.cgi?\$1",
+       "sg"    => "http://sg.wikipedia.com/wiki.cgi?\$1",
+       "sh"    => "http://sh.wikipedia.org/wiki/\$1",
+       "si"    => "http://si.wikipedia.com/wiki.cgi?\$1",
+       "sk"    => "http://sk.wikipedia.com/wiki.cgi?\$1",
+       "sl"    => "http://sl.wikipedia.com/wiki.cgi?\$1",
+       "sm"    => "http://sm.wikipedia.com/wiki.cgi?\$1",
+       "sn"    => "http://sn.wikipedia.com/wiki.cgi?\$1",
+       "so"    => "http://so.wikipedia.com/wiki.cgi?\$1",
+       "sq"    => "http://sq.wikipedia.com/wiki.cgi?\$1",
+       "sr"    => "http://sr.wikipedia.org/wiki/\$1",
+       "ss"    => "http://ss.wikipedia.com/wiki.cgi?\$1",
+       "st"    => "http://st.wikipedia.com/wiki.cgi?\$1",
+       "su"    => "http://su.wikipedia.com/wiki.cgi?\$1",
+       "sv"    => "http://sv.wikipedia.org/wiki/\$1",
+       "sw"    => "http://sw.wikipedia.com/wiki.cgi?\$1",
+       "ta"    => "http://ta.wikipedia.com/wiki.cgi?\$1",
+       "te"    => "http://te.wikipedia.com/wiki.cgi?\$1",
+       "tg"    => "http://tg.wikipedia.com/wiki.cgi?\$1",
+       "th"    => "http://th.wikipedia.com/wiki.cgi?\$1",
+       "ti"    => "http://ti.wikipedia.com/wiki.cgi?\$1",
+       "tk"    => "http://tk.wikipedia.com/wiki.cgi?\$1",
+       "tl"    => "http://tl.wikipedia.com/wiki.cgi?\$1",
+       "tn"    => "http://tn.wikipedia.com/wiki.cgi?\$1",
+       "to"    => "http://to.wikipedia.com/wiki.cgi?\$1",
+       "tr"    => "http://tr.wikipedia.org/wiki/\$1",
+       "ts"    => "http://ts.wikipedia.com/wiki.cgi?\$1",
+       "tt"    => "http://tt.wikipedia.com/wiki.cgi?\$1",
+       "tw"    => "http://tw.wikipedia.com/wiki.cgi?\$1",
+       "ug"    => "http://ug.wikipedia.com/wiki.cgi?\$1",
+       "uk"    => "http://uk.wikipedia.com/wiki.cgi?\$1",
+       "ur"    => "http://ur.wikipedia.com/wiki.cgi?\$1",
+       "uz"    => "http://uz.wikipedia.com/wiki.cgi?\$1",
+       "vi"    => "http://vi.wikipedia.com/wiki.cgi?\$1",
+       "vo"    => "http://vo.wikipedia.com/wiki.cgi?\$1",
+       "wo"    => "http://wo.wikipedia.com/wiki.cgi?\$1",
+       "xh"    => "http://xh.wikipedia.com/wiki.cgi?\$1",
+       "yi"    => "http://yi.wikipedia.com/wiki.cgi?\$1",
+       "yo"    => "http://yo.wikipedia.com/wiki.cgi?\$1",
+       "za"    => "http://za.wikipedia.com/wiki.cgi?\$1",
+       "zh"    => "http://zh.wikipedia.org/wiki/\$1",
+       "zu"    => "http://zu.wikipedia.com/wiki.cgi?\$1"
+);
+?>
+arrgghsomanyofthem
+;
diff --git a/maintenance/indexes.sql b/maintenance/indexes.sql
new file mode 100644 (file)
index 0000000..d8f8d99
--- /dev/null
@@ -0,0 +1,56 @@
+-- SQL to add non-unique indexes to Wikipedia database tables.
+-- This is read and executed by the install script; you should
+-- never have to run it by itself.
+--
+
+ALTER TABLE user
+  ADD INDEX user_name (user_name(10));
+
+ALTER TABLE user_newtalk
+  ADD INDEX user_id (user_id),
+  ADD INDEX user_ip (user_ip);
+
+ALTER TABLE cur
+  ADD INDEX cur_namespace (cur_namespace),
+  ADD INDEX cur_title (cur_title(20)),
+  ADD INDEX cur_timestamp (cur_timestamp),
+  ADD INDEX (cur_random),
+  ADD INDEX name_title_timestamp (cur_namespace,cur_title,inverse_timestamp),
+  ADD INDEX user_timestamp (cur_user,inverse_timestamp),
+  ADD INDEX usertext_timestamp (cur_user_text,inverse_timestamp);
+
+ALTER TABLE old
+  ADD INDEX (old_namespace,old_title(20)),
+  ADD INDEX old_timestamp (old_timestamp),
+  ADD INDEX name_title_timestamp (old_namespace,old_title,inverse_timestamp),
+  ADD INDEX user_timestamp (old_user,inverse_timestamp),
+  ADD INDEX usertext_timestamp (old_user_text,inverse_timestamp);
+
+ALTER TABLE links
+  ADD INDEX l_from (l_from (10)),
+  ADD INDEX l_to (l_to);
+
+ALTER TABLE brokenlinks
+  ADD INDEX bl_from (bl_from),
+  ADD INDEX bl_to (bl_to(10));
+
+ALTER TABLE imagelinks
+  ADD INDEX il_from (il_from(10)),
+  ADD INDEX il_to (il_to(10));
+
+ALTER TABLE ipblocks
+  ADD INDEX ipb_address (ipb_address),
+  ADD INDEX ipb_user (ipb_user);
+
+ALTER TABLE image
+  ADD INDEX img_name (img_name(10)),
+  ADD INDEX img_size (img_size),
+  ADD INDEX img_timestamp (img_timestamp);
+
+ALTER TABLE oldimage
+  ADD INDEX oi_name (oi_name(10));
+
+ALTER TABLE searchindex
+  ADD FULLTEXT si_title (si_title),
+  ADD FULLTEXT si_text (si_text);
+
diff --git a/maintenance/initialdata.sql b/maintenance/initialdata.sql
new file mode 100644 (file)
index 0000000..7e6ec37
--- /dev/null
@@ -0,0 +1,15 @@
+-- SQL to load database with initial values for testing.
+-- Most will be overwritten by install script.
+--
+
+INSERT INTO user (user_name,user_rights,user_password)
+  VALUES ('WikiSysop','sysop','d41d8cd98f00b204e9800998ecf8427e'),
+  ('WikiDeveloper','sysop,developer','d41d8cd98f00b204e9800998ecf8427e');
+
+INSERT INTO cur (cur_namespace,cur_title,cur_text,cur_restrictions)
+  VALUES (4,'Upload_log','Below is a list of the most recent file uploads.\nAll times shown are server time (UTC).\n<ul>\n</ul>\n','sysop'),
+  (4,'Deletion_log','Below is a list of the most recent deletions.\nAll times shown are server time (UTC).\n<ul>\n</ul>\n','sysop'),
+  (0,'Main_Page','Wiki software successfully installed!','');
+
+INSERT INTO site_stats VALUES (1,0,0,0);
+
diff --git a/maintenance/rebuildIndex.php b/maintenance/rebuildIndex.php
new file mode 100644 (file)
index 0000000..1bd085c
--- /dev/null
@@ -0,0 +1,46 @@
+<?
+
+# Rebuild the fulltext search indexes. This may take a while
+# depending on the database size and server configuration.
+
+global $IP;
+include_once( "../LocalSettings.php" );
+include_once( "$IP/Setup.php" );
+include_once( "$IP/SearchUpdate.php" );
+set_time_limit(0);
+
+$wgDBuser                      = "wikiadmin";
+$wgDBpassword          = $wgDBadminpassword;
+
+# May run faster if you drop the index; but will break attempts to search
+# while it's running if you're online.
+#echo "Dropping index...\n";
+##$sql = "ALTER TABLE searchindex DROP INDEX si_title, DROP INDEX si_text";
+#$res = wfQuery($sql);
+
+$sql = "SELECT COUNT(*) AS count FROM cur";
+$res = wfQuery($sql);
+$s = wfFetchObject($res);
+echo "Rebuilding index fields for {$s->count} pages...\n";
+$n = 0;
+
+$sql = "SELECT cur_id, cur_namespace, cur_title, cur_text FROM cur";
+$res = wfQuery($sql);
+while( $s = wfFetchObject($res)) {
+       $u = new SearchUpdate( $s->cur_id, $s->cur_title, $s->cur_text );
+       $u->doUpdate();
+       if ( ( (++$n) % 500) == 0) {
+               echo "$n\n";
+       }
+}
+wfFreeResult( $res );
+
+#echo "Rebuild the index...\n";
+##$sql = "ALTER TABLE searchindex ADD FULLTEXT si_title (si_title),
+##  ADD FULLTEXT si_text (si_text)";
+#$res = wfQuery($sql);
+
+print "Done.\n";
+exit();
+
+?>
diff --git a/maintenance/rebuildLinks.inc b/maintenance/rebuildLinks.inc
new file mode 100644 (file)
index 0000000..e98d6d7
--- /dev/null
@@ -0,0 +1,166 @@
+<?
+
+# Functions for rebuilding the link tracking tables; must
+# be included within a script that also includes the Setup.
+# See convertdb.php, for example.
+#
+
+function rebuildLinkTablesPass1()
+{
+       global $wgLang;
+       $count = 0;
+       print "Rebuilding link tables (pass 1).\n";
+
+       $sql = "DROP TABLE IF EXISTS rebuildlinks";
+       wfQuery( $sql );
+
+       $sql = "CREATE TABLE rebuildlinks (
+  rl_f_id int(8) unsigned NOT NULL default 0,
+  rl_f_title varchar(255) binary NOT NULL default '',
+  rl_to varchar(255) binary NOT NULL default '',
+  INDEX rl_to (rl_to) ) TYPE=MyISAM";
+       wfQuery( $sql );
+
+       $sql = "LOCK TABLES cur READ, rebuildlinks WRITE";
+       wfQuery( $sql );
+
+       $sql = "DELETE FROM rebuildlinks";
+       wfQuery( $sql );
+
+       $sql = "SELECT cur_id,cur_namespace,cur_title,cur_text FROM cur";
+       $res = wfQuery( $sql );
+       $total = wfNumRows( $res );
+
+       $tc = Title::legalChars();
+       while ( $row = wfFetchObject( $res ) ) {
+               $id = $row->cur_id;
+               $ns = $wgLang->getNsText( $row->cur_namespace );
+               if ( "" == $ns ) {
+                       $title = addslashes( $row->cur_title );
+               } else {
+                       $title = addslashes( "$ns:{$row->cur_title}" );
+               }
+               $text = $row->cur_text;
+               $numlinks = preg_match_all( "/\\[\\[([{$tc}]+)(]|\\|)/", $text,
+                 $m, PREG_PATTERN_ORDER );
+
+               if ( 0 != $numlinks ) {
+                       $sql = "INSERT INTO rebuildlinks (rl_f_id,rl_f_title,rl_to) VALUES ";
+                       for ( $i = 0; $i < $numlinks; ++$i ) {
+                               $nt = Title::newFromText( $m[1][$i] );
+                               $dest = addslashes( $nt->getPrefixedDBkey() );
+
+                               if ( 0 != $i ) { $sql .= ","; }
+                               $sql .= "({$id},'{$title}','{$dest}')";
+                       }
+                       wfQuery( $sql );
+               }
+               if ( ( ++$count % 1000 ) == 0 ) {
+                       print "$count of $total articles scanned.\n";
+               }
+       }
+       print "$count articles scanned.\n";
+       mysql_free_result( $res );
+
+       $sql = "UNLOCK TABLES";
+       wfQuery( $sql );
+}
+
+function rebuildLinkTablesPass2()
+{
+       global $wgLang;
+       $count = 0;
+       print "Rebuilding link tables (pass 2).\n";
+
+       $sql = "LOCK TABLES cur READ, rebuildlinks READ, " .
+         "links WRITE, brokenlinks WRITE, imagelinks WRITE";
+       wfQuery( $sql );
+
+       $sql = "DELETE FROM links";
+       wfQuery( $sql );
+
+       $sql = "DELETE FROM brokenlinks";
+       wfQuery( $sql );
+
+       $sql = "DELETE FROM links";
+       wfQuery( $sql );
+
+       $ins = $wgLang->getNsText( Namespace::getImage() );
+       $inslen = strlen($ins)+1;
+       $sql = "SELECT rl_f_title,rl_to FROM rebuildlinks " .
+         "WHERE rl_to LIKE '$ins:%'";
+       $res = wfQuery( $sql );
+
+       $sql = "INSERT INTO imagelinks (il_from,il_to) VALUES ";
+       $sqlX = "";
+       $first = true;
+       while ( $row = wfFetchObject( $res ) ) {
+               $iname = addslashes( substr( $row->rl_to, $inslen ) );
+               $pname = addslashes( $row->rl_f_title );
+
+               if ( ! $first ) { $sqlX .= ","; }
+               $first = false;
+
+               $sqlX .= "('{$pname}','{$iname}')";
+       }
+       if ($sqlX != "") {
+         $sql .= $sqlX;
+         wfFreeResult( $res );
+         wfQuery( $sql );
+       }
+
+       $sql = "SELECT DISTINCT rl_to FROM rebuildlinks " .
+         "ORDER BY rl_to";
+       $res = wfQuery( $sql );
+       $count = 0;
+       $total = wfNumRows( $res );
+
+       while ( $row = wfFetchObject( $res ) ) {
+               if ( 0 == strncmp( "$ins:", $row->rl_to, $inslen ) ) { continue; }
+
+               $nt = Title::newFromDBkey( $row->rl_to );
+               $id = $nt->getArticleID();
+               $to = addslashes( $row->rl_to );
+
+               if ( 0 == $id ) {
+                       $sql = "SELECT rl_f_id FROM rebuildlinks WHERE rl_to='{$to}'";
+                       $res2 = wfQuery( $sql );
+
+                       $sql = "INSERT INTO brokenlinks (bl_from,bl_to) VALUES ";
+                       $first = true;
+                       while ( $row2 = wfFetchObject( $res2 ) ) {
+                               $from = $row2->rl_f_id;
+                               if ( ! $first ) { $sql .= ","; }
+                               $first = false;
+                               $sql .= "({$from},'{$to}')";
+                       }
+                       wfFreeResult( $res2 );
+                       if ( ! $first ) { wfQuery( $sql ); }
+               } else {
+                       $sql = "SELECT rl_f_title FROM rebuildlinks WHERE rl_to='{$to}'";
+                       $res2 = wfQuery( $sql );
+
+                       $sql = "INSERT INTO links (l_from,l_to) VALUES ";
+                       $first = true;
+                       while ( $row2 = wfFetchObject( $res2 ) ) {
+                               $from = addslashes( $row2->rl_f_title );
+                               if ( ! $first ) { $sql .= ","; }
+                               $first = false;
+                               $sql .= "('{$from}',{$id})";
+                       }
+                       wfFreeResult( $res2 );
+                       if ( ! $first ) { wfQuery( $sql ); }
+               }
+               if ( ( ++$count % 1000 ) == 0 ) {
+                       print "$count of $total titles processed.\n";
+               }
+       }
+       wfFreeResult( $res );
+
+       $sql = "UNLOCK TABLES";
+       wfQuery( $sql );
+
+       $sql = "DROP TABLE rebuildlinks";
+       wfQuery( $sql );
+}
+?>
diff --git a/maintenance/rebuildLinks.php b/maintenance/rebuildLinks.php
new file mode 100644 (file)
index 0000000..2890507
--- /dev/null
@@ -0,0 +1,25 @@
+<?
+
+# Rebuild link tracking tables from scratch.  This takes several
+# hours, depending on the database size and server configuration.
+
+global $IP;
+include_once( "../LocalSettings.php" );
+include_once( "$IP/Setup.php" );
+include_once( "./rebuildLinks.inc" );
+include_once( "./rebuildRecentChanges.inc" );
+$wgTitle = Title::newFromText( "Rebuild links script" );
+set_time_limit(0);
+
+$wgDBuser                      = "wikiadmin";
+$wgDBpassword          = $wgDBadminpassword;
+
+rebuildLinkTablesPass1();
+rebuildLinkTablesPass2();
+
+rebuildRecentChangesTable();
+
+print "Done.\n";
+exit();
+
+?>
diff --git a/maintenance/tables.sql b/maintenance/tables.sql
new file mode 100644 (file)
index 0000000..09556af
--- /dev/null
@@ -0,0 +1,185 @@
+-- SQL to create the initial tables for the Wikipedia database.
+-- This is read and executed by the install script; you should
+-- never have to run it by itself.
+--
+-- Only UNIQUE keys are defined here; the rest are added by
+-- indexes.sql.
+--
+
+DROP TABLE IF EXISTS user;
+CREATE TABLE user (
+  user_id int(5) unsigned NOT NULL auto_increment,
+  user_name varchar(255) binary NOT NULL default '',
+  user_rights tinyblob NOT NULL default '',
+  user_password tinyblob NOT NULL default '',
+  user_newpassword tinyblob NOT NULL default '',
+  user_email tinytext NOT NULL default '',
+  user_options blob NOT NULL default '',  
+  user_touched char(14) binary NOT NULL default '',
+  UNIQUE KEY user_id (user_id)
+) TYPE=MyISAM PACK_KEYS=1;
+       
+DROP TABLE IF EXISTS user_newtalk;
+CREATE TABLE user_newtalk (
+  user_id int(5) NOT NULL default '0',
+  user_ip varchar(40) NOT NULL default ''
+) TYPE=MyISAM;
+
+DROP TABLE IF EXISTS cur;
+CREATE TABLE cur (
+  cur_id int(8) unsigned NOT NULL auto_increment,
+  cur_namespace tinyint(2) unsigned NOT NULL default '0',
+  cur_title varchar(255) binary NOT NULL default '',
+  cur_text mediumtext NOT NULL default '',
+  cur_comment tinyblob NOT NULL default '',
+  cur_user int(5) unsigned NOT NULL default '0',
+  cur_user_text varchar(255) binary NOT NULL default '',
+  cur_timestamp char(14) binary NOT NULL default '',
+  cur_restrictions tinyblob NOT NULL default '',
+  cur_counter bigint(20) unsigned NOT NULL default '0',
+  cur_is_redirect tinyint(1) unsigned NOT NULL default '0',
+  cur_minor_edit tinyint(1) unsigned NOT NULL default '0',
+  cur_is_new tinyint(1) unsigned NOT NULL default '0',
+  cur_random real unsigned NOT NULL,
+  cur_touched char(14) binary NOT NULL default '',
+  inverse_timestamp char(14) binary NOT NULL default '',
+  UNIQUE KEY cur_id (cur_id)
+) TYPE=MyISAM PACK_KEYS=1;
+
+DROP TABLE IF EXISTS old;
+CREATE TABLE old (
+  old_id int(8) unsigned NOT NULL auto_increment,
+  old_namespace tinyint(2) unsigned NOT NULL default '0',
+  old_title varchar(255) binary NOT NULL default '',
+  old_text mediumtext NOT NULL default '',
+  old_comment tinyblob NOT NULL default '',
+  old_user int(5) unsigned NOT NULL default '0',
+  old_user_text varchar(255) binary NOT NULL,
+  old_timestamp char(14) binary NOT NULL default '',
+  old_minor_edit tinyint(1) NOT NULL default '0',
+  old_flags tinyblob NOT NULL default '',
+  inverse_timestamp char(14) binary NOT NULL default '',
+  UNIQUE KEY old_id (old_id)
+) TYPE=MyISAM PACK_KEYS=1;
+
+DROP TABLE IF EXISTS archive;
+CREATE TABLE archive (
+  ar_namespace tinyint(2) unsigned NOT NULL default '0',
+  ar_title varchar(255) binary NOT NULL default '',
+  ar_text mediumtext NOT NULL default '',
+  ar_comment tinyblob NOT NULL default '',
+  ar_user int(5) unsigned NOT NULL default '0',
+  ar_user_text varchar(255) binary NOT NULL,
+  ar_timestamp char(14) binary NOT NULL default '',
+  ar_minor_edit tinyint(1) NOT NULL default '0',
+  ar_flags tinyblob NOT NULL default ''
+) TYPE=MyISAM PACK_KEYS=1;
+
+DROP TABLE IF EXISTS links;
+CREATE TABLE links (
+  l_from varchar(255) binary NOT NULL default '',
+  l_to int(8) unsigned NOT NULL default '0'
+) TYPE=MyISAM;
+
+DROP TABLE IF EXISTS brokenlinks;
+CREATE TABLE brokenlinks (
+  bl_from int(8) unsigned NOT NULL default '0',
+  bl_to varchar(255) binary NOT NULL default ''
+) TYPE=MyISAM;
+
+DROP TABLE IF EXISTS imagelinks;
+CREATE TABLE imagelinks (
+  il_from varchar(255) binary NOT NULL default '',
+  il_to varchar(255) binary NOT NULL default ''
+) TYPE=MyISAM;
+
+DROP TABLE IF EXISTS site_stats;
+CREATE TABLE site_stats (
+  ss_row_id int(8) unsigned NOT NULL,
+  ss_total_views bigint(20) unsigned default '0',
+  ss_total_edits bigint(20) unsigned default '0',
+  ss_good_articles bigint(20) unsigned default '0',
+  UNIQUE KEY ss_row_id (ss_row_id)
+) TYPE=MyISAM;
+
+DROP TABLE IF EXISTS ipblocks;
+CREATE TABLE ipblocks (
+  ipb_address varchar(40) binary NOT NULL default '',
+  ipb_user int(8) unsigned NOT NULL default '0',
+  ipb_by int(8) unsigned NOT NULL default '0',
+  ipb_reason tinyblob NOT NULL default '',
+  ipb_timestamp char(14) binary NOT NULL default ''
+) TYPE=MyISAM PACK_KEYS=1;
+
+DROP TABLE IF EXISTS image;
+CREATE TABLE image (
+  img_name varchar(255) binary NOT NULL default '',
+  img_size int(8) unsigned NOT NULL default '0',
+  img_description tinyblob NOT NULL default '',
+  img_user int(5) unsigned NOT NULL default '0',
+  img_user_text varchar(255) binary NOT NULL default '',
+  img_timestamp char(14) binary NOT NULL default ''
+) TYPE=MyISAM PACK_KEYS=1;
+
+DROP TABLE IF EXISTS oldimage;
+CREATE TABLE oldimage (
+  oi_name varchar(255) binary NOT NULL default '',
+  oi_archive_name varchar(255) binary NOT NULL default '',
+  oi_size int(8) unsigned NOT NULL default 0,
+  oi_description tinyblob NOT NULL default '',
+  oi_user int(5) unsigned NOT NULL default '0',
+  oi_user_text varchar(255) binary NOT NULL default '',
+  oi_timestamp char(14) binary NOT NULL default ''
+) TYPE=MyISAM PACK_KEYS=1;
+
+DROP TABLE IF EXISTS random;
+CREATE TABLE random (
+  ra_current tinyint(1) unsigned not null default 0,
+  ra_title varchar(255) binary not null default ''
+) TYPE=MyISAM PACK_KEYS=1;
+
+DROP TABLE IF EXISTS recentchanges;
+CREATE TABLE recentchanges (
+  rc_timestamp varchar(14) binary NOT NULL default '',
+  rc_cur_time varchar(14) binary NOT NULL default '',
+  rc_user int(10) unsigned NOT NULL default '0',
+  rc_user_text varchar(255) binary NOT NULL default '',
+  rc_namespace tinyint(3) unsigned NOT NULL default '0',
+  rc_title varchar(255) binary NOT NULL default '',
+  rc_comment varchar(255) binary NOT NULL default '',
+  rc_minor tinyint(3) unsigned NOT NULL default '0',
+  rc_bot tinyint(3) unsigned NOT NULL default '0',
+  rc_new tinyint(3) unsigned NOT NULL default '0',
+  rc_cur_id int(10) unsigned NOT NULL default '0',
+  rc_this_oldid int(10) unsigned NOT NULL default '0',
+  rc_last_oldid int(10) unsigned NOT NULL default '0'
+) TYPE=MyISAM PACK_KEYS=1;
+
+DROP TABLE IF EXISTS watchlist;
+CREATE TABLE watchlist (
+  wl_user int(5) unsigned NOT NULL,
+  wl_namespace tinyint(2) unsigned NOT NULL default '0',
+  wl_title varchar(255) binary NOT NULL default '',
+  UNIQUE KEY (wl_user, wl_namespace, wl_title)
+) TYPE=MyISAM PACK_KEYS=1;
+
+DROP TABLE IF EXISTS math;
+CREATE TABLE math (
+    math_inputhash varchar(16) NOT NULL,
+    math_outputhash varchar(16) NOT NULL,
+    math_html_conservativeness tinyint(1) NOT NULL,
+    math_html text,
+    math_mathml text,
+    UNIQUE KEY math_inputhash (math_inputhash)
+) TYPE=MyISAM;
+
+-- Table searchindex must be MyISAM for fulltext support
+
+DROP TABLE IF EXISTS searchindex;
+CREATE TABLE searchindex (
+  si_page int(8) unsigned NOT NULL,
+  si_title varchar(255) NOT NULL default '',
+  si_text mediumtext NOT NULL default '',
+  UNIQUE KEY (si_page)
+) TYPE=MyISAM PACK_KEYS=1;
+
diff --git a/maintenance/users.sql b/maintenance/users.sql
new file mode 100644 (file)
index 0000000..f620dc4
--- /dev/null
@@ -0,0 +1,115 @@
+-- SQL script to create required database users with proper
+-- access rights.  This is run from the installation script
+-- which replaces the password variables with their values
+-- from local settings.
+--
+
+GRANT ALL ON {$wgDBname}.*
+ TO {$wgDBadminuser}@'%' IDENTIFIED BY '{$wgDBadminpassword}';
+GRANT ALL ON {$wgDBname}.*
+ TO {$wgDBadminuser}@localhost IDENTIFIED BY '{$wgDBadminpassword}';
+GRANT ALL ON {$wgDBname}.*
+ TO {$wgDBadminuser}@localhost.localdomain IDENTIFIED BY '{$wgDBadminpassword}';
+
+GRANT DELETE,INSERT,SELECT,UPDATE ON {$wgDBname}.*
+ TO {$wgDBuser}@'%' IDENTIFIED BY '{$wgDBpassword}';
+GRANT DELETE,INSERT,SELECT,UPDATE ON {$wgDBname}.*
+ TO {$wgDBuser}@localhost IDENTIFIED BY '{$wgDBpassword}';
+GRANT DELETE,INSERT,SELECT,UPDATE ON {$wgDBname}.*
+ TO {$wgDBuser}@localhost.localdomain IDENTIFIED BY '{$wgDBpassword}';
+
+GRANT SELECT (user_id,user_name,user_rights,user_options) ON {$wgDBname}.user
+ TO {$wgDBsqluser}@'%' IDENTIFIED BY '{$wgDBsqlpassword}';
+GRANT SELECT ON {$wgDBname}.cur
+ TO {$wgDBsqluser}@'%' IDENTIFIED BY '{$wgDBsqlpassword}';
+GRANT SELECT ON {$wgDBname}.old
+ TO {$wgDBsqluser}@'%' IDENTIFIED BY '{$wgDBsqlpassword}';
+GRANT SELECT ON {$wgDBname}.archive
+ TO {$wgDBsqluser}@'%' IDENTIFIED BY '{$wgDBsqlpassword}';
+GRANT SELECT ON {$wgDBname}.links
+ TO {$wgDBsqluser}@'%' IDENTIFIED BY '{$wgDBsqlpassword}';
+GRANT SELECT ON {$wgDBname}.brokenlinks
+ TO {$wgDBsqluser}@'%' IDENTIFIED BY '{$wgDBsqlpassword}';
+GRANT SELECT ON {$wgDBname}.imagelinks
+ TO {$wgDBsqluser}@'%' IDENTIFIED BY '{$wgDBsqlpassword}';
+GRANT SELECT ON {$wgDBname}.site_stats
+ TO {$wgDBsqluser}@'%' IDENTIFIED BY '{$wgDBsqlpassword}';
+GRANT SELECT ON {$wgDBname}.ipblocks
+ TO {$wgDBsqluser}@'%' IDENTIFIED BY '{$wgDBsqlpassword}';
+GRANT SELECT ON {$wgDBname}.image
+ TO {$wgDBsqluser}@'%' IDENTIFIED BY '{$wgDBsqlpassword}';
+GRANT SELECT ON {$wgDBname}.oldimage
+ TO {$wgDBsqluser}@'%' IDENTIFIED BY '{$wgDBsqlpassword}';
+GRANT SELECT ON {$wgDBname}.random
+ TO {$wgDBsqluser}@'%' IDENTIFIED BY '{$wgDBsqlpassword}';
+GRANT SELECT ON {$wgDBname}.recentchanges
+ TO {$wgDBsqluser}@'%' IDENTIFIED BY '{$wgDBsqlpassword}';
+GRANT SELECT ON {$wgDBname}.watchlist
+ TO {$wgDBsqluser}@'%' IDENTIFIED BY '{$wgDBsqlpassword}';
+GRANT SELECT ON {$wgDBname}.math
+ TO {$wgDBsqluser}@'%' IDENTIFIED BY '{$wgDBsqlpassword}';
+
+GRANT SELECT (user_id,user_name,user_rights,user_options)
+ ON {$wgDBname}.user
+ TO {$wgDBsqluser}@localhost IDENTIFIED BY '{$wgDBsqlpassword}';
+GRANT SELECT ON {$wgDBname}.cur
+ TO {$wgDBsqluser}@localhost IDENTIFIED BY '{$wgDBsqlpassword}';
+GRANT SELECT ON {$wgDBname}.old
+ TO {$wgDBsqluser}@localhost IDENTIFIED BY '{$wgDBsqlpassword}';
+GRANT SELECT ON {$wgDBname}.archive
+ TO {$wgDBsqluser}@localhost IDENTIFIED BY '{$wgDBsqlpassword}';
+GRANT SELECT ON {$wgDBname}.links
+ TO {$wgDBsqluser}@localhost IDENTIFIED BY '{$wgDBsqlpassword}';
+GRANT SELECT ON {$wgDBname}.brokenlinks
+ TO {$wgDBsqluser}@localhost IDENTIFIED BY '{$wgDBsqlpassword}';
+GRANT SELECT ON {$wgDBname}.imagelinks
+ TO {$wgDBsqluser}@localhost IDENTIFIED BY '{$wgDBsqlpassword}';
+GRANT SELECT ON {$wgDBname}.site_stats
+ TO {$wgDBsqluser}@localhost IDENTIFIED BY '{$wgDBsqlpassword}';
+GRANT SELECT ON {$wgDBname}.ipblocks
+ TO {$wgDBsqluser}@localhost IDENTIFIED BY '{$wgDBsqlpassword}';
+GRANT SELECT ON {$wgDBname}.image
+ TO {$wgDBsqluser}@localhost IDENTIFIED BY '{$wgDBsqlpassword}';
+GRANT SELECT ON {$wgDBname}.oldimage
+ TO {$wgDBsqluser}@localhost IDENTIFIED BY '{$wgDBsqlpassword}';
+GRANT SELECT ON {$wgDBname}.random
+ TO {$wgDBsqluser}@localhost IDENTIFIED BY '{$wgDBsqlpassword}';
+GRANT SELECT ON {$wgDBname}.recentchanges
+ TO {$wgDBsqluser}@localhost IDENTIFIED BY '{$wgDBsqlpassword}';
+GRANT SELECT ON {$wgDBname}.watchlist
+ TO {$wgDBsqluser}@localhost IDENTIFIED BY '{$wgDBsqlpassword}';
+GRANT SELECT ON {$wgDBname}.math
+ TO {$wgDBsqluser}@localhost IDENTIFIED BY '{$wgDBsqlpassword}';
+
+GRANT SELECT (user_id,user_name,user_rights,user_options)
+ ON {$wgDBname}.user
+ TO {$wgDBsqluser}@localhost.localdomain IDENTIFIED BY '{$wgDBsqlpassword}';
+GRANT SELECT ON {$wgDBname}.cur
+ TO {$wgDBsqluser}@localhost.localdomain IDENTIFIED BY '{$wgDBsqlpassword}';
+GRANT SELECT ON {$wgDBname}.old
+ TO {$wgDBsqluser}@localhost.localdomain IDENTIFIED BY '{$wgDBsqlpassword}';
+GRANT SELECT ON {$wgDBname}.archive
+ TO {$wgDBsqluser}@localhost.localdomain IDENTIFIED BY '{$wgDBsqlpassword}';
+GRANT SELECT ON {$wgDBname}.links
+ TO {$wgDBsqluser}@localhost.localdomain IDENTIFIED BY '{$wgDBsqlpassword}';
+GRANT SELECT ON {$wgDBname}.brokenlinks
+ TO {$wgDBsqluser}@localhost.localdomain IDENTIFIED BY '{$wgDBsqlpassword}';
+GRANT SELECT ON {$wgDBname}.imagelinks
+ TO {$wgDBsqluser}@localhost.localdomain IDENTIFIED BY '{$wgDBsqlpassword}';
+GRANT SELECT ON {$wgDBname}.site_stats
+ TO {$wgDBsqluser}@localhost.localdomain IDENTIFIED BY '{$wgDBsqlpassword}';
+GRANT SELECT ON {$wgDBname}.ipblocks
+ TO {$wgDBsqluser}@localhost.localdomain IDENTIFIED BY '{$wgDBsqlpassword}';
+GRANT SELECT ON {$wgDBname}.image
+ TO {$wgDBsqluser}@localhost.localdomain IDENTIFIED BY '{$wgDBsqlpassword}';
+GRANT SELECT ON {$wgDBname}.oldimage
+ TO {$wgDBsqluser}@localhost.localdomain IDENTIFIED BY '{$wgDBsqlpassword}';
+GRANT SELECT ON {$wgDBname}.random
+ TO {$wgDBsqluser}@localhost.localdomain IDENTIFIED BY '{$wgDBsqlpassword}';
+GRANT SELECT ON {$wgDBname}.recentchanges
+ TO {$wgDBsqluser}@localhost.localdomain IDENTIFIED BY '{$wgDBsqlpassword}';
+GRANT SELECT ON {$wgDBname}.watchlist
+ TO {$wgDBsqluser}@localhost.localdomain IDENTIFIED BY '{$wgDBsqlpassword}';
+GRANT SELECT ON {$wgDBname}.math
+ TO {$wgDBsqluser}@localhost.localdomain IDENTIFIED BY '{$wgDBsqlpassword}';
+
diff --git a/math/Makefile b/math/Makefile
new file mode 100644 (file)
index 0000000..47c40f9
--- /dev/null
@@ -0,0 +1,64 @@
+OBJ=render_info.cmo tex.cmo texutil.cmo parser.cmo lexer.cmo texvc.cmo \
+render_info.cmx tex.cmx texutil.cmx parser.cmx lexer.cmx texvc.cmx \
+lexer.cmi parser.cmi render_info.cmi tex.cmi texutil.cmi texvc.cmi \
+lexer.o parser.o render_info.o tex.o texutil.o texvc.o \
+lexer.ml parser.ml parser.mli texvc texvc.bc texvc_test.cmo \
+texvc_test.cmx texvc_test.cmi texvc_test.o texvc_test util.o \
+util.cmo util.cmx util.cmi texvc_cgi.cmi texvc_cgi texvc_cgi.cmo \
+render.o render.cmi render.cmo render.cmx texvc_tex.cmx \
+texvc_tex.o texvc_tex.cmi texvc_tex html.cmi html.cmo html.cmx \
+html.o mathml.cmi mathml.cmo mathml.cmx mathml.o
+CGIPATH=-I /usr/lib/ocaml/cgi -I /usr/lib/ocaml/netstring -I /usr/lib/ocaml/pcre
+
+all: texvc texvc_test texvc_tex
+texvc.bc: util.cmo parser.cmo html.cmo mathml.cmo texutil.cmo render.cmo lexer.cmo texvc.cmo
+       ocamlc -o $@ unix.cma $^
+texvc: util.cmx parser.cmx html.cmx mathml.cmx texutil.cmx render.cmx lexer.cmx texvc.cmx
+       ocamlopt -o $@ unix.cmxa $^
+texvc_test: util.cmx parser.cmx html.cmx mathml.cmx texutil.cmx lexer.cmx texvc_test.cmx
+       ocamlopt -o $@ $^
+texvc_tex: util.cmx parser.cmx html.cmx mathml.cmx texutil.cmx lexer.cmx texvc_tex.cmx
+       ocamlopt -o $@ $^
+%.ml: %.mll
+       ocamllex $<
+%.mli %.ml: %.mly
+       ocamlyacc $<
+%.cmo: %.ml
+       ocamlc -c $<
+%.cmx: %.ml
+       ocamlopt -c $<
+%.cmi: %.mli
+       ocamlc -c $<
+texvc_cgi.cmo: texvc_cgi.ml
+       ocamlc -c $(CGIPATH) $<
+texvc_cgi: util.cmo parser.cmo texutil.cmo render.cmo lexer.cmo texvc_cgi.cmo
+       ocamlc -o $@ unix.cma $(CGIPATH) pcre.cma netstring.cma cgi.cma $^
+       chmod g-w $@
+clean:
+       rm -f $(OBJ)
+
+html.cmo: render_info.cmi tex.cmi util.cmo html.cmi 
+html.cmx: render_info.cmi tex.cmi util.cmx html.cmi 
+html.cmi: tex.cmi 
+lexer.cmo: parser.cmi render_info.cmi tex.cmi texutil.cmi 
+lexer.cmx: parser.cmx render_info.cmi tex.cmi texutil.cmx 
+mathml.cmo: tex.cmi mathml.cmi 
+mathml.cmx: tex.cmi mathml.cmi 
+mathml.cmi: tex.cmi 
+parser.cmo: render_info.cmi tex.cmi parser.cmi 
+parser.cmx: render_info.cmi tex.cmi parser.cmi 
+parser.cmi: render_info.cmi tex.cmi 
+render.cmo: texutil.cmi util.cmo 
+render.cmx: texutil.cmx util.cmx 
+tex.cmi: render_info.cmi 
+texutil.cmo: html.cmi parser.cmi render_info.cmi tex.cmi util.cmo texutil.cmi 
+texutil.cmx: html.cmx parser.cmx render_info.cmi tex.cmi util.cmx texutil.cmi 
+texutil.cmi: parser.cmi tex.cmi 
+texvc.cmo: html.cmi lexer.cmo mathml.cmi parser.cmi render.cmo texutil.cmi util.cmo 
+texvc.cmx: html.cmx lexer.cmx mathml.cmx parser.cmx render.cmx texutil.cmx util.cmx 
+texvc_cgi.cmo: lexer.cmo parser.cmi render.cmo texutil.cmi util.cmo 
+texvc_cgi.cmx: lexer.cmx parser.cmx render.cmx texutil.cmx util.cmx 
+texvc_test.cmo: html.cmi lexer.cmo parser.cmi texutil.cmi util.cmo 
+texvc_test.cmx: html.cmx lexer.cmx parser.cmx texutil.cmx util.cmx 
+texvc_tex.cmo: lexer.cmo parser.cmi texutil.cmi util.cmo 
+texvc_tex.cmx: lexer.cmx parser.cmx texutil.cmx util.cmx 
diff --git a/math/README b/math/README
new file mode 100644 (file)
index 0000000..1093cc4
--- /dev/null
@@ -0,0 +1,18 @@
+texvc output format is like that:
+    +%5                ok, but not html or mathml
+    c%5%h      ok, conservative html, no mathml
+    m%5%h      ok, moderate html, no mathml
+    l%5%h      ok, liberal html, no mathml
+    C%5%h\0%m  ok, conservative html, with mathml
+    M%5%h\0%m  ok, moderate html, with mathml
+    L%5%h\0%m  ok, liberal html, with mathml
+    X%5%m      ok, no html, with mathml
+    S          syntax error
+    E          lexing error
+    F%s                unknown function %s
+    -          other error
+
+\0 - null character
+%5 - md5, 32 hex characters
+%h - html code, without \0 characters
+%m - mathml code, without \0 characters
diff --git a/math/TODO b/math/TODO
new file mode 100644 (file)
index 0000000..bd8d1f4
--- /dev/null
+++ b/math/TODO
@@ -0,0 +1,3 @@
+* It would be better if PNGs were transparent
+* CJK support
+* Documentation, in particular about instalation of Latex support for Unicode
diff --git a/math/html.ml b/math/html.ml
new file mode 100644 (file)
index 0000000..5f63e5e
--- /dev/null
@@ -0,0 +1,119 @@
+open Render_info
+open Tex
+open Util
+
+exception Too_difficult_for_html
+type context = CTX_NORMAL | CTX_IT | CTX_RM 
+type conservativeness_t = CONSERVATIVE | MODERATE | LIBERAL
+
+let conservativeness = ref CONSERVATIVE
+let html_liberal () = conservativeness := LIBERAL
+let html_moderate () = if !conservativeness = CONSERVATIVE then conservativeness := MODERATE else ()
+
+
+let new_ctx = function
+    FONTFORCE_IT -> CTX_IT
+  | FONTFORCE_RM -> CTX_RM
+let font_render lit = function
+    (_,     FONT_UFH) -> lit
+  | (_,     FONT_UF)  -> lit
+  | (CTX_IT,FONT_RTI) -> raise Too_difficult_for_html
+  | (_,     FONT_RTI) -> lit
+  | (CTX_IT,FONT_RM)  -> "<i>"^lit^"</i>"
+  | (_,     FONT_RM)  -> lit
+  | (CTX_RM,FONT_IT)  -> lit
+  | (_,     FONT_IT)  -> "<i>"^lit^"</i>"
+
+let rec html_render_flat ctx = function
+    TEX_LITERAL (HTMLABLE (ft,_,sh))::r -> (html_liberal (); (font_render sh (ctx,ft))^html_render_flat ctx r)
+  | TEX_LITERAL (HTMLABLEC(ft,_,sh))::r -> (font_render sh (ctx,ft))^html_render_flat ctx r
+  | TEX_LITERAL (MHTMLABLEC(ft,_,sh,_,_))::r -> (font_render sh (ctx,ft))^html_render_flat ctx r
+  | TEX_LITERAL (HTMLABLEM(ft,_,sh))::r -> (html_moderate(); (font_render sh (ctx,ft))^html_render_flat ctx r)
+  | TEX_LITERAL (HTMLABLE_BIG (_,sh))::r -> (html_liberal (); sh^html_render_flat ctx r)
+  | TEX_FUN1hl (_,(f1,f2),a)::r -> f1^(html_render_flat ctx [a])^f2^html_render_flat ctx r
+  | TEX_FUN1hf (_,ff,a)::r -> (html_render_flat (new_ctx ff) [a])^html_render_flat ctx r
+  | TEX_DECLh (_,ff,a)::r -> (html_render_flat (new_ctx ff) a)^html_render_flat ctx r
+  | TEX_CURLY ls::r -> html_render_flat ctx (ls @ r)
+  | TEX_DQ (a,b)::r  -> (html_liberal ();
+                        let bs = html_render_flat ctx [b] in match html_render_size ctx a with
+                        true, s -> raise Too_difficult_for_html
+                      | false, s -> s^"<sub>"^bs^"</sub>")^html_render_flat ctx r
+  | TEX_UQ (a,b)::r  -> (html_liberal ();
+                        let bs = html_render_flat ctx [b] in match html_render_size ctx a with
+                        true, s ->  raise Too_difficult_for_html
+                      | false, s -> s^"<sup>"^bs^"</sup>")^html_render_flat ctx r
+  | TEX_FQ (a,b,c)::r -> (html_liberal ();
+                        (let bs = html_render_flat ctx [b] in let cs = html_render_flat ctx [c] in
+                         match html_render_size ctx a with
+                         true, s -> raise Too_difficult_for_html
+                       | false, s -> s^"<sub>"^bs^"</sub><sup>"^cs^"</sup>")^html_render_flat ctx r)
+  | TEX_BOX (_,s)::r -> s^html_render_flat ctx r
+  | TEX_LITERAL (TEX_ONLY _)::_ -> raise Too_difficult_for_html
+  | TEX_FUN1 _::_ -> raise Too_difficult_for_html
+  | TEX_FUN2  _::_ -> raise Too_difficult_for_html
+  | TEX_FUN2h  _::_ -> raise Too_difficult_for_html
+  | TEX_FUN2sq  _::_ -> raise Too_difficult_for_html
+  | TEX_INFIX _::_ -> raise Too_difficult_for_html
+  | TEX_INFIXh _::_ -> raise Too_difficult_for_html
+  | TEX_MATRIX _::_ -> raise Too_difficult_for_html
+  | TEX_LR _::_ -> raise Too_difficult_for_html
+  | TEX_BIG _::_ -> raise Too_difficult_for_html
+  | [] -> ""
+and html_render_size ctx = function
+    TEX_LITERAL (HTMLABLE_BIG (_,sh)) -> true,sh
+  | x -> false,html_render_flat ctx [x]
+
+let rec html_render_deep ctx = function
+    TEX_LITERAL (HTMLABLE (ft,_,sh))::r -> (html_liberal (); ("",(font_render sh (ctx,ft)),"")::html_render_deep ctx r)
+  | TEX_LITERAL (HTMLABLEM(ft,_,sh))::r -> (html_moderate(); ("",(font_render sh (ctx,ft)),"")::html_render_deep ctx r)
+  | TEX_LITERAL (HTMLABLEC(ft,_,sh))::r -> ("",(font_render sh (ctx,ft)),"")::html_render_deep ctx r
+  | TEX_LITERAL (MHTMLABLEC(ft,_,sh,_,_))::r -> ("",(font_render sh (ctx,ft)),"")::html_render_deep ctx r
+  | TEX_LITERAL (HTMLABLE_BIG (_,sh))::r -> (html_liberal (); ("",sh,"")::html_render_deep ctx r)
+  | TEX_FUN2h (_,f,a,b)::r -> (html_liberal (); (f a b)::html_render_deep ctx r)
+  | TEX_INFIXh (_,f,a,b)::r -> (html_liberal (); (f a b)::html_render_deep ctx r)
+  | TEX_CURLY ls::r -> html_render_deep ctx (ls @ r)
+  | TEX_DQ (a,b)::r  -> (let bs = html_render_flat ctx [b] in match html_render_size ctx a with
+                        true, s ->  "","<font size=+2>"^s^"</font>",bs
+                      | false, s -> "",(s^"<sub>"^bs^"</sub>"),"")::html_render_deep ctx r
+  | TEX_UQ (a,b)::r  -> (let bs = html_render_flat ctx [b] in match html_render_size ctx a with
+                        true, s ->  bs,"<font size=+2>"^s^"</font>",""
+                      | false, s -> "",(s^"<sup>"^bs^"</sup>"),"")::html_render_deep ctx r
+  | TEX_FQ (a,b,c)::r -> (html_liberal ();
+                        (let bs = html_render_flat ctx [b] in let cs = html_render_flat ctx [c] in
+                         match html_render_size ctx a with
+                         true, s ->  (cs,"<font size=+2>"^s^"</font>",bs)
+                       | false, s -> ("",(s^"<sub>"^bs^"</sub><sup>"^cs^"</sup>"),""))::html_render_deep ctx r)
+  | TEX_FUN1hl (_,(f1,f2),a)::r -> ("",f1,"")::(html_render_deep ctx [a]) @ ("",f2,"")::html_render_deep ctx r
+  | TEX_FUN1hf (_,ff,a)::r -> (html_render_deep (new_ctx ff) [a]) @ html_render_deep ctx r
+  | TEX_DECLh  (_,ff,a)::r -> (html_render_deep (new_ctx ff) a) @ html_render_deep ctx r
+  | TEX_BOX (_,s)::r -> ("",s,"")::html_render_deep ctx r
+  | TEX_LITERAL (TEX_ONLY _)::_ -> raise Too_difficult_for_html
+  | TEX_FUN1 _::_ -> raise Too_difficult_for_html
+  | TEX_FUN2 _::_ -> raise Too_difficult_for_html
+  | TEX_FUN2sq  _::_ -> raise Too_difficult_for_html
+  | TEX_INFIX _::_ -> raise Too_difficult_for_html
+  | TEX_MATRIX _::_ -> raise Too_difficult_for_html
+  | TEX_LR _::_ -> raise Too_difficult_for_html
+  | TEX_BIG _::_ -> raise Too_difficult_for_html
+  | [] -> []
+
+let rec html_render_table = function
+    sf,u,d,("",a,"")::("",b,"")::r -> html_render_table (sf,u,d,(("",a^b,"")::r))
+  | sf,u,d,(("",a,"") as c)::r     -> html_render_table (c::sf,u,d,r)
+  | sf,u,d,((_,a,"") as c)::r      -> html_render_table (c::sf,true,d,r)
+  | sf,u,d,(("",a,_) as c)::r      -> html_render_table (c::sf,u,true,r)
+  | sf,u,d,((_,a,_) as c)::r       -> html_render_table (c::sf,true,true,r)
+  | sf,false,false,[]              -> mapjoin (function (u,m,d) -> m) (List.rev sf)
+  | sf,true,false,[]               -> let ustr,mstr = List.fold_left (fun (us,ms) (u,m,d) -> (us^"<td>"^u,ms^"<td>"^u))
+                                       ("","") (List.rev sf) in
+                                       "<table><tr align=center valign=bottom>" ^ ustr ^ "</tr><tr align=center>" ^ mstr ^ "</tr></table>"
+  | sf,false,true,[]               -> let mstr,dstr = List.fold_left (fun (ms,ds) (u,m,d) -> (ms^"<td>"^m,ds^"<td>"^d))
+                                       ("","") (List.rev sf) in
+                                       "<table><tr align=center>" ^ mstr ^ "</tr><tr align=center valign=top>" ^ dstr ^ "</tr></table>"
+  | sf,true,true,[]               -> let ustr,mstr,dstr = List.fold_left (fun (us,ms,ds) (u,m,d) ->
+                                       (us^"<td>"^u,ms^"<td>"^m,ds^"<td>"^d)) ("","","") (List.rev sf) in
+                                       "<table><tr align=center valign=bottom>" ^ ustr ^ "</tr><tr align=center>" ^ mstr ^ "</tr><tr align=center valign=top>" ^ dstr ^ "</tr></table>"
+
+let html_render tree = html_render_table ([],false,false,html_render_deep CTX_NORMAL tree)
+
+let render tree = try Some (html_render tree) with _ -> None
diff --git a/math/html.mli b/math/html.mli
new file mode 100644 (file)
index 0000000..00b41cf
--- /dev/null
@@ -0,0 +1,5 @@
+val render : Tex.t list -> string option
+val html_render : Tex.t list -> string
+
+type conservativeness_t = CONSERVATIVE | MODERATE | LIBERAL
+val conservativeness : conservativeness_t ref
diff --git a/math/lexer.mll b/math/lexer.mll
new file mode 100644 (file)
index 0000000..ff871cb
--- /dev/null
@@ -0,0 +1,90 @@
+{
+    open Parser
+    open Render_info
+    open Tex
+}
+let space = [' ' '\t' '\n' '\r']
+let alpha = ['a'-'z' 'A'-'Z']
+let literal_id = ['a'-'z' 'A'-'Z']
+let literal_mn = ['0'-'9']
+let literal_uf_lt = [',' ':' ';' '?' '!' '\'']
+let delimiter_uf_lt = ['(' ')' '.']
+let literal_uf_op = ['+' '-' '*' '=']
+let delimiter_uf_op = ['/' '|']
+let boxchars  = ['0'-'9' 'a'-'z' 'A'-'Z' '+' '-' '*' ',' '=' '(' ')' ':' '/' ';' '?' '.' '!' ' ' '\128'-'\255']
+let aboxchars = ['0'-'9' 'a'-'z' 'A'-'Z' '+' '-' '*' ',' '=' '(' ')' ':' '/' ';' '?' '.' '!' ' ']
+
+rule token = parse
+    space +                    { token lexbuf }
+  | "\\mbox" space * '{' aboxchars + '}'
+                               { let str = Lexing.lexeme lexbuf in
+                                 let n = String.index str '{' + 1 in
+                                 BOX ("\\mbox", String.sub str n (String.length str - n - 1)) }
+  | "\\hbox" space * '{' aboxchars + '}'
+                               { let str = Lexing.lexeme lexbuf in
+                                 let n = String.index str '{' + 1 in
+                                 BOX ("\\hbox", String.sub str n (String.length str - n - 1)) }
+  | "\\vbox" space * '{' aboxchars + '}'
+                               { let str = Lexing.lexeme lexbuf in
+                                 let n = String.index str '{' + 1 in
+                                 BOX ("\\vbox", String.sub str n (String.length str - n - 1)) }
+  | "\\mbox" space * '{' boxchars + '}'
+                               { let str = Lexing.lexeme lexbuf in
+                                 let n = String.index str '{' + 1 in
+                                 Texutil.tex_use_nonascii();
+                                 BOX ("\\mbox", String.sub str n (String.length str - n - 1)) }
+  | "\\hbox" space * '{' boxchars + '}'
+                               { let str = Lexing.lexeme lexbuf in
+                                 let n = String.index str '{' + 1 in
+                                 Texutil.tex_use_nonascii();
+                                 BOX ("\\hbox", String.sub str n (String.length str - n - 1)) }
+  | "\\vbox" space * '{' boxchars + '}'
+                               { let str = Lexing.lexeme lexbuf in
+                                 let n = String.index str '{' + 1 in
+                                 Texutil.tex_use_nonascii();
+                                 BOX ("\\vbox", String.sub str n (String.length str - n - 1)) }
+  | literal_id                 { let str = Lexing.lexeme lexbuf in LITERAL (MHTMLABLEC (FONT_IT, str,str,MI,str)) }
+  | literal_mn                 { let str = Lexing.lexeme lexbuf in LITERAL (MHTMLABLEC (FONT_RM, str,str,MN,str)) }
+  | literal_uf_lt              { let str = Lexing.lexeme lexbuf in LITERAL (HTMLABLEC (FONT_UFH, str,str)) }
+  | delimiter_uf_lt            { let str = Lexing.lexeme lexbuf in DELIMITER (HTMLABLEC (FONT_UFH, str,str)) }
+  | literal_uf_op              { let str = Lexing.lexeme lexbuf in LITERAL (MHTMLABLEC (FONT_UFH, str," "^str^" ",MO,str)) }
+  | delimiter_uf_op            { let str = Lexing.lexeme lexbuf in DELIMITER (MHTMLABLEC (FONT_UFH, str," "^str^" ",MO,str)) }
+  | "\\" alpha +               { Texutil.find (Lexing.lexeme lexbuf) }
+  | "\\sqrt" space * "["       { FUN_AR1opt "\\sqrt" }
+  | "\\,"                      { LITERAL (HTMLABLE (FONT_UF, "\\,","&nbsp;")) }
+  | "\\ "                      { LITERAL (HTMLABLE (FONT_UF, "\\ ","&nbsp;")) }
+  | "\\;"                      { LITERAL (HTMLABLE (FONT_UF, "\\;","&nbsp;")) }
+  | "\\!"                      { LITERAL (TEX_ONLY "\\!") }
+  | "\\{"                      { DELIMITER (HTMLABLEC(FONT_UFH,"\\{","{")) }
+  | "\\}"                      { DELIMITER (HTMLABLEC(FONT_UFH,"\\}","}")) }
+  | "\\|"                      { DELIMITER (HTMLABLE (FONT_UFH,"\\|","||")) }
+  | "\\_"                      { LITERAL (HTMLABLEC(FONT_UFH,"\\_","_")) }
+  | "\\#"                      { LITERAL (HTMLABLE (FONT_UFH,"\\#","#")) }
+  | "\\%"                      { LITERAL (HTMLABLE (FONT_UFH,"\\%","%")) }
+  | "&"                                { NEXT_CELL }
+  | "\\\\"                     { NEXT_ROW }
+  | "\\begin{matrix}"          { Texutil.tex_use_ams(); BEGIN__MATRIX }
+  | "\\end{matrix}"            { END__MATRIX }
+  | "\\begin{pmatrix}"         { Texutil.tex_use_ams(); BEGIN_PMATRIX }
+  | "\\end{pmatrix}"           { END_PMATRIX }
+  | "\\begin{bmatrix}"         { Texutil.tex_use_ams(); BEGIN_BMATRIX }
+  | "\\end{bmatrix}"           { END_BMATRIX }
+  | "\\begin{Bmatrix}"         { Texutil.tex_use_ams(); BEGIN_BBMATRIX }
+  | "\\end{Bmatrix}"           { END_BBMATRIX }
+  | "\\begin{vmatrix}"         { Texutil.tex_use_ams(); BEGIN_VMATRIX }
+  | "\\end{vmatrix}"           { END_VMATRIX }
+  | "\\begin{Vmatrix}"         { Texutil.tex_use_ams(); BEGIN_VVMATRIX }
+  | "\\end{Vmatrix}"           { END_VVMATRIX }
+  | "\\begin{cases}"           { Texutil.tex_use_ams(); BEGIN_CASES }
+  | "\\end{cases}"             { END_CASES }
+  | '>'                                { LITERAL (HTMLABLEC(FONT_UFH,">"," &gt; ")) }
+  | '<'                                { LITERAL (HTMLABLEC(FONT_UFH,"<"," &lt; ")) }
+  | '%'                                { LITERAL (HTMLABLEC(FONT_UFH,"\\%","%")) }
+  | '~'                                { LITERAL (HTMLABLE (FONT_UF, "~","&nbsp;")) }
+  | '['                                { DELIMITER (HTMLABLEC(FONT_UFH,"[","[")) }
+  | ']'                                { SQ_CLOSE }
+  | '{'                                { CURLY_OPEN }
+  | '}'                                { CURLY_CLOSE }
+  | '^'                                { SUP }
+  | '_'                                { SUB }
+  | eof                                { EOF }
diff --git a/math/mathml.ml b/math/mathml.ml
new file mode 100644 (file)
index 0000000..b6c76af
--- /dev/null
@@ -0,0 +1,20 @@
+open Tex
+open Render_info
+
+type t = TREE_MN of string | TREE_MO of string | TREE_MI of string
+
+let rec make_mathml_tree = function
+    TREE_MN a::otr,TEX_LITERAL(MHTMLABLEC(_,_,_,MN,b))::itr -> make_mathml_tree(TREE_MN (a^b)::otr,itr)
+  | otr,TEX_LITERAL(MHTMLABLEC(_,_,_,MN,a))::itr -> make_mathml_tree(TREE_MN a::otr,itr)
+  | otr,TEX_LITERAL(MHTMLABLEC(_,_,_,MO,a))::itr -> make_mathml_tree(TREE_MO a::otr,itr)
+  | otr,TEX_LITERAL(MHTMLABLEC(_,_,_,MI,a))::itr -> make_mathml_tree(TREE_MI a::otr,itr)
+  | otr,TEX_CURLY(crl)::itr -> make_mathml_tree(otr,crl@itr)
+  | otr,[] -> List.rev otr
+  | _ -> failwith "failed to render mathml"
+
+let render_mathml_tree = function
+    TREE_MN s -> "<mn>"^s^"</mn>"
+  | TREE_MI s -> "<mi>"^s^"</mi>"
+  | TREE_MO s -> "<mo>"^s^"</mo>"
+
+let render tree = try Some (Util.mapjoin render_mathml_tree (make_mathml_tree ([],tree))) with _ -> None
diff --git a/math/mathml.mli b/math/mathml.mli
new file mode 100644 (file)
index 0000000..fcc2cd4
--- /dev/null
@@ -0,0 +1 @@
+val render : Tex.t list -> string option
diff --git a/math/parser.mly b/math/parser.mly
new file mode 100644 (file)
index 0000000..4787db3
--- /dev/null
@@ -0,0 +1,103 @@
+%{
+    open Tex
+    open Render_info
+    
+    let sq_close_ri = HTMLABLEC(FONT_UFH,"]", "]")
+%}
+%token <Render_info.t> LITERAL DELIMITER
+%token <string> FUN_AR2 FUN_INFIX FUN_AR1 DECL FUN_AR1opt BIG
+%token <string*string> BOX
+%token <string*(string*string)> FUN_AR1hl
+%token <string*Render_info.font_force> FUN_AR1hf DECLh
+%token <string*(Tex.t->Tex.t->string*string*string)> FUN_AR2h
+%token <string*(Tex.t list->Tex.t list->string*string*string)> FUN_INFIXh
+%token EOF CURLY_OPEN CURLY_CLOSE SUB SUP SQ_CLOSE NEXT_CELL NEXT_ROW
+%token BEGIN__MATRIX BEGIN_PMATRIX BEGIN_BMATRIX BEGIN_BBMATRIX BEGIN_VMATRIX BEGIN_VVMATRIX BEGIN_CASES
+%token END__MATRIX END_PMATRIX END_BMATRIX END_BBMATRIX END_VMATRIX END_VVMATRIX END_CASES
+%token LEFT RIGHT
+
+%type <Tex.t list> tex_expr
+%start tex_expr
+
+%%
+tex_expr:
+    expr EOF                   { $1 }
+  | ne_expr FUN_INFIX ne_expr EOF
+                               { [TEX_INFIX($2,$1,$3)] }
+  | ne_expr FUN_INFIXh ne_expr EOF
+                               { let t,h=$2 in [TEX_INFIXh(t,h,$1,$3)] }
+expr:
+    /* */                      { [] }
+  | ne_expr                    { $1 }
+ne_expr:
+    lit_aq expr                        { $1 :: $2 }
+  | litsq_aq expr              { $1 :: $2 }
+  | DECLh expr                 { let t,h = $1 in [TEX_DECLh(t,h,$2)] }
+litsq_aq:
+    litsq_zq                   { $1 }
+  | litsq_dq                   { let base,downi = $1 in TEX_DQ(base,downi) }
+  | litsq_uq                   { let base,upi = $1   in TEX_UQ(base,upi)}
+  | litsq_fq                   { $1 }
+litsq_fq:
+    litsq_dq SUP lit           { let base,downi = $1 in TEX_FQ(base,downi,$3) }
+  | litsq_uq SUB lit           { let base,upi = $1   in TEX_FQ(base,$3,upi) }
+litsq_uq:
+    litsq_zq SUP lit           { $1,$3 }
+litsq_dq:
+    litsq_zq SUB lit           { $1,$3 }
+litsq_zq:
+  | SQ_CLOSE                   { TEX_LITERAL sq_close_ri }
+expr_nosqc:
+    /* */                      { [] }
+  | lit_aq expr_nosqc          { $1 :: $2 }
+lit_aq:
+    lit                                { $1 }
+  | lit_dq                     { let base,downi = $1 in TEX_DQ(base,downi) }
+  | lit_uq                     { let base,upi = $1   in TEX_UQ(base,upi)}
+  | lit_fq                     { $1 }
+lit_fq:
+    lit_dq SUP lit             { let base,downi = $1 in TEX_FQ(base,downi,$3) }
+  | lit_uq SUB lit             { let base,upi = $1   in TEX_FQ(base,$3,upi) }
+lit_uq:
+    lit SUP lit                        { $1,$3 }
+lit_dq:
+    lit SUB lit                        { $1,$3 }
+left:
+    LEFT DELIMITER             { $2 }
+  | LEFT SQ_CLOSE              { sq_close_ri }
+right:
+    RIGHT DELIMITER            { $2 }
+  | RIGHT SQ_CLOSE             { sq_close_ri }
+lit:
+    LITERAL                    { TEX_LITERAL $1 }
+  | DELIMITER                  { TEX_LITERAL $1 }
+  | BIG DELIMITER              { TEX_BIG ($1,$2) }
+  | BIG SQ_CLOSE               { TEX_BIG ($1,sq_close_ri) }
+  | left expr right            { TEX_LR ($1,$3,$2) }
+  | FUN_AR1 lit                        { TEX_FUN1($1,$2) }
+  | FUN_AR1hl lit              { let t,h=$1 in TEX_FUN1hl(t,h,$2) }
+  | FUN_AR1hf lit              { let t,h=$1 in TEX_FUN1hf(t,h,$2) }
+  | FUN_AR1opt expr_nosqc SQ_CLOSE lit { TEX_FUN2sq($1,TEX_CURLY $2,$4) }
+  | FUN_AR2 lit lit            { TEX_FUN2($1,$2,$3) }
+  | FUN_AR2h lit lit           { let t,h=$1 in TEX_FUN2h(t,h,$2,$3) }
+  | BOX                                { let bt,s = $1 in TEX_BOX (bt,s) }
+  | CURLY_OPEN expr CURLY_CLOSE
+                               { TEX_CURLY $2 }
+  | CURLY_OPEN ne_expr FUN_INFIX ne_expr CURLY_CLOSE
+                               { TEX_INFIX($3,$2,$4) }
+  | CURLY_OPEN ne_expr FUN_INFIXh ne_expr CURLY_CLOSE
+                               { let t,h=$3 in TEX_INFIXh(t,h,$2,$4) }
+  | BEGIN__MATRIX  matrix END__MATRIX  { TEX_MATRIX ("matrix", $2) }
+  | BEGIN_PMATRIX  matrix END_PMATRIX  { TEX_MATRIX ("pmatrix", $2) }
+  | BEGIN_BMATRIX  matrix END_BMATRIX  { TEX_MATRIX ("bmatrix", $2) }
+  | BEGIN_BBMATRIX matrix END_BBMATRIX { TEX_MATRIX ("Bmatrix", $2) }
+  | BEGIN_VMATRIX  matrix END_VMATRIX  { TEX_MATRIX ("vmatrix", $2) }
+  | BEGIN_VVMATRIX matrix END_VVMATRIX { TEX_MATRIX ("Vmatrix", $2) }
+  | BEGIN_CASES    matrix END_CASES    { TEX_MATRIX ("cases", $2) }
+matrix:
+    line                       { [$1] }
+  | line NEXT_ROW matrix       { $1::$3 }
+line:
+    expr                       { [$1] }
+  | expr NEXT_CELL line                { $1::$3 }
+;;
diff --git a/math/render.ml b/math/render.ml
new file mode 100644 (file)
index 0000000..fd358d2
--- /dev/null
@@ -0,0 +1,29 @@
+let cmd_dvips tmpprefix = "dvips -R -E " ^ tmpprefix ^ ".dvi -o -"
+let cmd_latex tmpprefix = "latex " ^ tmpprefix ^ ".tex >/dev/null"
+let cmd_convert finalpath = "convert -quality 100 -density 120 ps:- " ^ finalpath ^ " >/dev/null 2>/dev/null"
+
+exception ExternalCommandFailure of string
+
+let render tmppath finalpath outtex md5 =
+    let tmpprefix = (tmppath^"/"^(string_of_int (Unix.getpid ()))^"_"^md5) in
+    let unlink_all () =
+      begin
+(*
+       Sys.remove (tmpprefix ^ ".dvi");
+       Sys.remove (tmpprefix ^ ".aux");
+       Sys.remove (tmpprefix ^ ".log");
+        Sys.remove (tmpprefix ^ ".tex")
+*)
+      end in
+    let f = (Util.open_out_unless_exists (tmpprefix ^ ".tex")) in
+      begin
+       output_string f (Texutil.get_preface ());
+       output_string f outtex;
+       output_string f (Texutil.get_footer ());
+       close_out f;
+       if Util.run_in_other_directory tmppath (cmd_latex tmpprefix) != 0
+       then (unlink_all (); raise (ExternalCommandFailure "latex"))
+       else if (Sys.command ((cmd_dvips tmpprefix) ^ " | " ^ (cmd_convert (finalpath^"/"^md5^".png"))) != 0)
+       then (unlink_all (); raise (ExternalCommandFailure ("dvips")))
+       else unlink_all ()
+      end
diff --git a/math/render_info.mli b/math/render_info.mli
new file mode 100644 (file)
index 0000000..d5e7fde
--- /dev/null
@@ -0,0 +1,20 @@
+type font_force =
+    FONTFORCE_IT
+  | FONTFORCE_RM
+type font_class =
+    FONT_IT  (* IT default, may be forced to be RM *)
+  | FONT_RM  (* RM default, may be forced to be IT *)
+  | FONT_UF  (* not affected by IT/RM setting *)
+  | FONT_RTI (* RM - any, IT - not available in HTML *)
+  | FONT_UFH (* in TeX UF, in HTML RM *)
+type math_class =
+    MN
+  | MI
+  | MO
+type t =
+      HTMLABLEC of font_class * string * string
+    | HTMLABLEM of font_class * string * string
+    | HTMLABLE of font_class * string * string
+    | MHTMLABLEC of font_class * string * string * math_class * string
+    | HTMLABLE_BIG of string * string
+    | TEX_ONLY of string
diff --git a/math/tex.mli b/math/tex.mli
new file mode 100644 (file)
index 0000000..9e6013d
--- /dev/null
@@ -0,0 +1,19 @@
+type t =
+      TEX_LITERAL of Render_info.t
+    | TEX_CURLY of t list
+    | TEX_FQ of t * t * t
+    | TEX_DQ of t * t
+    | TEX_UQ of t * t
+    | TEX_LR of Render_info.t * Render_info.t * t list
+    | TEX_BOX of string * string
+    | TEX_BIG of string * Render_info.t
+    | TEX_FUN1 of string * t
+    | TEX_FUN2 of string * t * t
+    | TEX_INFIX of string * t list * t list
+    | TEX_FUN2sq of string * t * t
+    | TEX_FUN1hl  of string * (string * string) * t
+    | TEX_FUN1hf  of string * Render_info.font_force * t
+    | TEX_FUN2h  of string * (t -> t -> string * string * string) * t * t
+    | TEX_INFIXh of string * (t list -> t list -> string * string * string) * t list * t list
+    | TEX_MATRIX of string * t list list list
+    | TEX_DECLh  of string * Render_info.font_force * t list
diff --git a/math/texutil.ml b/math/texutil.ml
new file mode 100644 (file)
index 0000000..6f42cef
--- /dev/null
@@ -0,0 +1,453 @@
+open Parser
+open Render_info
+open Tex
+open Util
+
+let tex_part = function
+    HTMLABLE (_,t,_) -> t
+  | HTMLABLEM (_,t,_) -> t
+  | HTMLABLEC (_,t,_) -> t
+  | MHTMLABLEC (_,t,_,_,_) -> t
+  | HTMLABLE_BIG (t,_) -> t
+  | TEX_ONLY t -> t
+let rec render_tex = function
+    TEX_FQ (a,b,c) -> (render_tex a) ^ "_{" ^ (render_tex  b) ^ "}^{" ^ (render_tex  c) ^ "}"
+  | TEX_DQ (a,b) -> (render_tex a) ^ "_{" ^ (render_tex  b) ^ "}"
+  | TEX_UQ (a,b) -> (render_tex a) ^ "^{" ^ (render_tex  b) ^ "}" 
+  | TEX_LITERAL s -> tex_part s
+  | TEX_FUN1 (f,a) -> "{" ^ f ^ " " ^ (render_tex a) ^ "}"
+  | TEX_FUN1hl (f,_,a) -> "{" ^ f ^ " " ^ (render_tex a) ^ "}"
+  | TEX_FUN1hf (f,_,a) -> "{" ^ f ^ " " ^ (render_tex a) ^ "}"
+  | TEX_DECLh (f,_,a) -> "{" ^ f ^ "{" ^ (mapjoin render_tex a) ^ "}}"
+  | TEX_FUN2 (f,a,b) -> "{" ^ f ^ " " ^ (render_tex a) ^ (render_tex b) ^ "}"
+  | TEX_FUN2h (f,_,a,b) -> "{" ^ f ^ " " ^ (render_tex a) ^ (render_tex b) ^ "}"
+  | TEX_FUN2sq (f,a,b) -> "{" ^ f ^ "[ " ^ (render_tex a) ^ "]" ^ (render_tex b) ^ "}"
+  | TEX_CURLY (tl) -> "{" ^ (mapjoin render_tex tl) ^ "}"
+  | TEX_INFIX (s,ll,rl) -> "{" ^ (mapjoin render_tex ll) ^ " " ^ s ^ "" ^ (mapjoin render_tex rl) ^ "}"
+  | TEX_INFIXh (s,_,ll,rl) -> "{" ^ (mapjoin render_tex ll) ^ " " ^ s ^ "" ^ (mapjoin render_tex rl) ^ "}"
+  | TEX_BOX (bt,s) -> "{"^bt^"{" ^ s ^ "}}"
+  | TEX_BIG (bt,d) -> "{"^bt^(tex_part d)^"}"
+  | TEX_MATRIX (t,rows) -> "{\\begin{"^t^"}"^(mapjoine "\\\\" (mapjoine "&" (mapjoin render_tex)) rows)^"\\end{"^t^"}}"
+  | TEX_LR (l,r,tl) -> "\\left "^(tex_part l)^(mapjoin render_tex tl)^"\\right "^(tex_part r)
+
+(* Dynamic loading*)
+type encoding_t = LATIN1 | LATIN2 | UTF8
+
+let modules_ams = ref false
+let modules_nonascii = ref false
+let modules_encoding = ref UTF8
+
+let tex_use_ams ()     = modules_ams := true
+let tex_use_nonascii () = modules_nonascii := true
+let tex_mod_reset ()   = (modules_ams := false; modules_nonascii := false; modules_encoding := UTF8)
+
+let get_encoding = function
+    UTF8 -> "\\usepackage{ucs}\n\\usepackage[utf8]{inputenc}\n"
+  | LATIN1 -> "\\usepackage[latin1]{inputenc}\n"
+  | LATIN2 -> "\\usepackage[latin2]{inputenc}\n"
+
+let get_preface ()  = "\\nonstopmode\n\\documentclass[12pt]{article}\n" ^
+                     (if !modules_nonascii then get_encoding !modules_encoding else "") ^
+                     (if !modules_ams then "\\usepackage{amsmath}\n\\usepackage{amsfonts}\n\\usepackage{amssymb}\n" else "") ^
+                     "\\pagestyle{empty}\n\\begin{document}\n$$\n"
+let get_footer  ()  = "\n$$\n\\end{document}\n"
+
+let set_encoding = function
+    "ISO-8859-1" -> modules_encoding := LATIN1
+  | "iso-8859-1" -> modules_encoding := LATIN1
+  | "ISO-8859-2" -> modules_encoding := LATIN2
+  | _ -> modules_encoding := UTF8
+
+(* Turn that into hash table lookup *)
+exception Illegal_tex_function of string
+
+let find = function
+      "\\alpha"            -> LITERAL (HTMLABLEC (FONT_UF,  "\\alpha ", "&alpha;"))
+    | "\\Alpha"            -> LITERAL (HTMLABLEC (FONT_RTI, "A", "&Alpha;"))
+    | "\\beta"             -> LITERAL (HTMLABLEC (FONT_UF,  "\\beta ",  "&beta;"))
+    | "\\Beta"             -> LITERAL (HTMLABLEC (FONT_RTI, "B",  "&Beta;"))
+    | "\\gamma"            -> LITERAL (HTMLABLEC (FONT_UF,  "\\gamma ", "&gamma;"))
+    | "\\Gamma"            -> LITERAL (HTMLABLEC (FONT_RTI, "\\Gamma ", "&Gamma;"))
+    | "\\delta"            -> LITERAL (HTMLABLEC (FONT_UF,  "\\delta ", "&delta;"))
+    | "\\Delta"            -> LITERAL (HTMLABLEC (FONT_RTI, "\\Delta ", "&Delta;"))
+    | "\\epsilon"          -> LITERAL (HTMLABLEC (FONT_UF,  "\\epsilon ", "&epsilon;"))
+    | "\\Epsilon"          -> LITERAL (HTMLABLEC (FONT_RTI, "E", "&Epsilon;"))
+    | "\\varepsilon"       -> LITERAL (TEX_ONLY "\\varepsilon ")
+    | "\\zeta"             -> LITERAL (HTMLABLEC (FONT_UF,  "\\zeta ", "&zeta;"))
+    | "\\Zeta"             -> LITERAL (HTMLABLEC (FONT_RTI, "Z", "&Zeta;"))
+    | "\\eta"              -> LITERAL (HTMLABLEC (FONT_UF,  "\\eta ", "&eta;"))
+    | "\\Eta"              -> LITERAL (HTMLABLEC (FONT_RTI, "H", "&Eta;"))
+    | "\\theta"            -> LITERAL (HTMLABLEC (FONT_UF,  "\\theta ", "&theta;"))
+    | "\\Theta"            -> LITERAL (HTMLABLEC (FONT_RTI, "\\Theta ", "&Theta;"))
+    | "\\vartheta"         -> LITERAL (HTMLABLE  (FONT_UF,  "\\vartheta ", "&thetasym;"))
+    | "\\thetasym"         -> LITERAL (HTMLABLE  (FONT_UF,  "\\vartheta ", "&thetasym;"))
+    | "\\iota"             -> LITERAL (HTMLABLEC (FONT_UF,  "\\iota ", "&iota;"))
+    | "\\Iota"             -> LITERAL (HTMLABLEC (FONT_RTI, "I", "&Iota;"))
+    | "\\kappa"            -> LITERAL (HTMLABLEC (FONT_UF,  "\\kappa ", "&kappa;"))
+    | "\\Kappa"            -> LITERAL (HTMLABLEC (FONT_RTI, "K", "&Kappa;"))
+    | "\\lambda"           -> LITERAL (HTMLABLEC (FONT_UF,  "\\lambda ", "&lambda;"))
+    | "\\Lambda"           -> LITERAL (HTMLABLEC (FONT_RTI, "\\Lambda ", "&Lambda;"))
+    | "\\mu"               -> LITERAL (HTMLABLEC (FONT_UF,  "\\mu ", "&mu;"))
+    | "\\Mu"               -> LITERAL (HTMLABLEC (FONT_RTI, "M", "&Mu;"))
+    | "\\nu"               -> LITERAL (HTMLABLEC (FONT_UF,  "\\nu ", "&nu;"))
+    | "\\Nu"               -> LITERAL (HTMLABLEC (FONT_RTI, "N", "&Nu;"))
+    | "\\pi"               -> LITERAL (HTMLABLEC (FONT_UF,  "\\pi ", "&pi;"))
+    | "\\Pi"               -> LITERAL (HTMLABLEC (FONT_RTI, "\\Pi ", "&Pi;"))
+    | "\\varpi"            -> LITERAL (TEX_ONLY "\\varpi ")
+    | "\\rho"              -> LITERAL (HTMLABLEC (FONT_UF,  "\\rho ", "&rho;"))
+    | "\\Rho"              -> LITERAL (HTMLABLEC (FONT_RTI, "P", "&Rho;"))
+    | "\\varrho"           -> LITERAL (TEX_ONLY "\\varrho ")
+    | "\\sigma"            -> LITERAL (HTMLABLEC (FONT_UF,  "\\sigma ", "&sigma;"))
+    | "\\Sigma"            -> LITERAL (HTMLABLEC (FONT_RTI, "\\Sigma ", "&Sigma;"))
+    | "\\varsigma"         -> LITERAL (TEX_ONLY "\\varsigma ")
+    | "\\tau"              -> LITERAL (HTMLABLEC (FONT_UF,  "\\tau ", "&tau;"))
+    | "\\Tau"              -> LITERAL (HTMLABLEC (FONT_RTI, "T", "&Tau;"))
+    | "\\upsilon"          -> LITERAL (HTMLABLEC (FONT_UF,  "\\upsilon ", "&upsilon;"))
+    | "\\Upsilon"          -> LITERAL (HTMLABLEC (FONT_RTI, "\\Upsilon ", "&Upsilon;"))
+    | "\\phi"              -> LITERAL (HTMLABLEC (FONT_UF,  "\\phi ", "&phi;"))
+    | "\\Phi"              -> LITERAL (HTMLABLEC (FONT_RTI, "\\Phi ", "&Phi;"))
+    | "\\varphi"           -> LITERAL (TEX_ONLY "\\varphi ")
+    | "\\chi"              -> LITERAL (HTMLABLEC (FONT_UF,  "\\chi ", "&chi;"))
+    | "\\Chi"              -> LITERAL (HTMLABLEC (FONT_RTI, "X", "&Chi;"))
+    | "\\psi"              -> LITERAL (HTMLABLEC (FONT_UF,  "\\psi ", "&psi;"))
+    | "\\Psi"              -> LITERAL (HTMLABLEC (FONT_RTI, "\\Psi ", "&Psi;"))
+    | "\\omega"            -> LITERAL (HTMLABLEC (FONT_UF,  "\\omega ", "&omega;"))
+    | "\\Omega"            -> LITERAL (HTMLABLEC (FONT_RTI, "\\Omega ", "&Omega;"))
+    | "\\xi"               -> LITERAL (HTMLABLEC (FONT_UF,  "\\xi ", "&xi;"))
+    | "\\Xi"               -> LITERAL (HTMLABLEC (FONT_RTI, "\\Xi ", "&Xi;"))
+    | "\\aleph"            -> LITERAL (HTMLABLE  (FONT_UF,  "\\aleph ", "&alefsym;"))
+    | "\\alef"             -> LITERAL (HTMLABLE  (FONT_UF,  "\\aleph ", "&alefsym;"))
+    | "\\alefsym"          -> LITERAL (HTMLABLE  (FONT_UF,  "\\aleph ", "&alefsym;"))
+    | "\\larr"             -> LITERAL (HTMLABLEM (FONT_UF,  "\\leftarrow ", "&larr;"))
+    | "\\leftarrow"        -> LITERAL (HTMLABLEM (FONT_UF,  "\\leftarrow ", "&larr;"))
+    | "\\rarr"             -> LITERAL (HTMLABLEM (FONT_UF,  "\\rightarrow ", "&rarr;"))
+    | "\\to"               -> LITERAL (HTMLABLEM (FONT_UF,  "\\to ", "&rarr;"))
+    | "\\gets"             -> LITERAL (HTMLABLEM (FONT_UF,  "\\gets ", "&larr;"))
+    | "\\rightarrow"       -> LITERAL (HTMLABLEM (FONT_UF,  "\\rightarrow ", "&rarr;"))
+    | "\\longleftarrow"    -> LITERAL (HTMLABLE  (FONT_UF,  "\\longleftarrow ", "&larr;"))
+    | "\\longrightarrow"   -> LITERAL (HTMLABLE  (FONT_UF,  "\\longrightarrow ", "&rarr;"))
+    | "\\Larr"             -> LITERAL (HTMLABLE  (FONT_UF,  "\\Leftarrow ", "&lArr;"))
+    | "\\lArr"             -> LITERAL (HTMLABLE  (FONT_UF,  "\\Leftarrow ", "&lArr;"))
+    | "\\Leftarrow"        -> LITERAL (HTMLABLE  (FONT_UF,  "\\Leftarrow ", "&lArr;"))
+    | "\\Rarr"             -> LITERAL (HTMLABLE  (FONT_UF,  "\\Rightarrow ", "&rArr;"))
+    | "\\rArr"             -> LITERAL (HTMLABLE  (FONT_UF,  "\\Rightarrow ", "&rArr;"))
+    | "\\Rightarrow"       -> LITERAL (HTMLABLEM (FONT_UF,  "\\Rightarrow ", "&rArr;"))
+    | "\\mapsto"           -> LITERAL (HTMLABLE  (FONT_UF,  "\\mapsto ", "&rarr;"))
+    | "\\longmapsto"       -> LITERAL (HTMLABLE  (FONT_UF,  "\\longmapsto ", "&rarr;"))
+    | "\\Longleftarrow"    -> LITERAL (HTMLABLE  (FONT_UF,  "\\Longleftarrow ", "&lArr;"))
+    | "\\Longrightarrow"   -> LITERAL (HTMLABLE  (FONT_UF,  "\\Longrightarrow ", "&rArr;"))
+    | "\\uarr"             -> DELIMITER (HTMLABLEM (FONT_UF,  "\\uparrow ", "&uarr;"))
+    | "\\uparrow"          -> DELIMITER (HTMLABLEM (FONT_UF,  "\\uparrow ", "&uarr;"))
+    | "\\uArr"             -> DELIMITER (HTMLABLE  (FONT_UF,  "\\Uparrow ", "&uArr;"))
+    | "\\Uarr"             -> DELIMITER (HTMLABLE  (FONT_UF,  "\\Uparrow ", "&uArr;"))
+    | "\\Uparrow"          -> DELIMITER (HTMLABLE  (FONT_UF,  "\\Uparrow ", "&uArr;"))
+    | "\\darr"             -> DELIMITER (HTMLABLEM (FONT_UF,  "\\downarrow ", "&darr;"))
+    | "\\downarrow"        -> DELIMITER (HTMLABLEM (FONT_UF,  "\\downarrow ", "&darr;"))
+    | "\\dArr"             -> DELIMITER (HTMLABLE  (FONT_UF,  "\\Downarrow ", "&dArr;"))
+    | "\\Darr"             -> DELIMITER (HTMLABLE  (FONT_UF,  "\\Downarrow ", "&dArr;"))
+    | "\\Downarrow"        -> DELIMITER (HTMLABLE  (FONT_UF,  "\\Downarrow ", "&dArr;"))
+    | "\\updownarrow"      -> DELIMITER (TEX_ONLY "\\updownarrow ")
+    | "\\Updownarrow"      -> DELIMITER (TEX_ONLY "\\Updownarrow ")
+    | "\\leftrightarrow"   -> LITERAL (HTMLABLE  (FONT_UF,  "\\leftrightarrow ", "&harr;"))
+    | "\\lrarr"            -> LITERAL (HTMLABLE  (FONT_UF,  "\\leftrightarrow ", "&harr;"))
+    | "\\harr"             -> LITERAL (HTMLABLE  (FONT_UF,  "\\leftrightarrow ", "&harr;"))
+    | "\\Leftrightarrow"   -> LITERAL (HTMLABLE  (FONT_UF,  "\\Leftrightarrow ", "&hArr;"))
+    | "\\Lrarr"            -> LITERAL (HTMLABLE  (FONT_UF,  "\\Leftrightarrow ", "&hArr;"))
+    | "\\Harr"             -> LITERAL (HTMLABLE  (FONT_UF,  "\\Leftrightarrow ", "&hArr;"))
+    | "\\lrArr"            -> LITERAL (HTMLABLE  (FONT_UF,  "\\Leftrightarrow ", "&hArr;"))
+    | "\\hAar"             -> LITERAL (HTMLABLE  (FONT_UF,  "\\Leftrightarrow ", "&hArr;"))
+    | "\\Longleftrightarrow"->LITERAL (HTMLABLE  (FONT_UF,  "\\Longleftrightarrow ", "&harr;"))
+    | "\\iff"              -> LITERAL (HTMLABLE  (FONT_UF,  "\\iff ", "&harr;"))
+    | "\\searrow"          -> LITERAL (TEX_ONLY "\\searrow ")
+    | "\\nearrow"          -> LITERAL (TEX_ONLY "\\nearrow ")
+    | "\\swarrow"          -> LITERAL (TEX_ONLY "\\swarrow ")
+    | "\\nwarrow"          -> LITERAL (TEX_ONLY "\\nwarrow ")
+    | "\\sim"              -> LITERAL (TEX_ONLY "\\sim ")
+    | "\\simeq"            -> LITERAL (TEX_ONLY "\\simeq ")
+    | "\\star"             -> LITERAL (TEX_ONLY "\\star ")
+    | "\\ell"              -> LITERAL (TEX_ONLY "\\ell ")
+    | "\\P"                -> LITERAL (TEX_ONLY "\\P ")
+    | "\\smile"            -> LITERAL (TEX_ONLY "\\smile ")
+    | "\\frown"            -> LITERAL (TEX_ONLY "\\frown ")
+    | "\\bigcap"           -> LITERAL (TEX_ONLY "\\bigcap ")
+    | "\\bigodot"          -> LITERAL (TEX_ONLY "\\bigodot ")
+    | "\\bigcup"           -> LITERAL (TEX_ONLY "\\bigcup ")
+    | "\\bigotimes"        -> LITERAL (TEX_ONLY "\\bigotimes ")
+    | "\\coprod"           -> LITERAL (TEX_ONLY "\\coprod ")
+    | "\\bigsqcup"         -> LITERAL (TEX_ONLY "\\bigsqcup ")
+    | "\\bigoplus"         -> LITERAL (TEX_ONLY "\\bigoplus ") 
+    | "\\bigvee"           -> LITERAL (TEX_ONLY "\\bigvee ") 
+    | "\\biguplus"         -> LITERAL (TEX_ONLY "\\biguplus ")
+    | "\\oint"            -> LITERAL (TEX_ONLY "\\oint ")
+    | "\\bigwedge"         -> LITERAL (TEX_ONLY "\\bigwedge ")
+    | "\\models"           -> LITERAL (TEX_ONLY "\\models ")
+    | "\\vdash"            -> LITERAL (TEX_ONLY "\\vdash ")
+    | "\\triangle"         -> LITERAL (TEX_ONLY "\\triangle ")
+    | "\\wr"              -> LITERAL (TEX_ONLY "\\wr ")
+    | "\\triangleleft"     -> LITERAL (TEX_ONLY "\\triangleleft ")
+    | "\\triangleright"    -> LITERAL (TEX_ONLY "\\triangleright ")
+    | "\\textvisiblespace" -> LITERAL (TEX_ONLY "\\textvisiblespace ")
+    | "\\ker"             -> LITERAL (TEX_ONLY "\\ker ")
+    | "\\lim"             -> LITERAL (TEX_ONLY "\\lim ")
+    | "\\limsup"           -> LITERAL (TEX_ONLY "\\limsup ")
+    | "\\liminf"           -> LITERAL (TEX_ONLY "\\liminf ")
+    | "\\sup"             -> LITERAL (TEX_ONLY "\\sup ")
+    | "\\Pr"              -> LITERAL (TEX_ONLY "\\Pr ")
+    | "\\hom"             -> LITERAL (TEX_ONLY "\\hom ")
+    | "\\arg"             -> LITERAL (TEX_ONLY "\\arg ")
+    | "\\dim"             -> LITERAL (TEX_ONLY "\\dim ")
+    | "\\inf"             -> LITERAL (TEX_ONLY "\\inf ")
+    | "\\circ"            -> LITERAL (TEX_ONLY "\\circ ")
+    | "\\hbar"            -> LITERAL (TEX_ONLY "\\hbar ")
+    | "\\imath"                   -> LITERAL (TEX_ONLY "\\imath ")
+    | "\\lnot"            -> LITERAL (TEX_ONLY "\\lnot ")
+    | "\\hookrightarrow"   -> LITERAL (TEX_ONLY "\\hookrightarrow ")
+    | "\\hookleftarrow"    -> LITERAL (TEX_ONLY "\\hookleftarrow ")
+    | "\\mp"               -> LITERAL (TEX_ONLY "\\mp ")
+    | "\\approx"           -> LITERAL (TEX_ONLY "\\approx ")
+    | "\\flat"             -> LITERAL (TEX_ONLY "\\flat ")
+    | "\\sharp"            -> LITERAL (TEX_ONLY "\\sharp ")
+    | "\\natural"          -> LITERAL (TEX_ONLY "\\natural ")
+    | "\\int"             -> LITERAL (HTMLABLE_BIG ("\\int ", "&int;"))
+    | "\\sum"             -> LITERAL (HTMLABLE_BIG ("\\sum ", "&sum;"))
+    | "\\prod"            -> LITERAL (HTMLABLE_BIG ("\\prod ", "&prod;"))
+    | "\\vdots"            -> LITERAL (TEX_ONLY "\\vdots ")
+    | "\\top"              -> LITERAL (TEX_ONLY "\\top ")
+    | "\\sin"             -> LITERAL (HTMLABLEC(FONT_UFH,"\\sin ","sin"))
+    | "\\cos"             -> LITERAL (HTMLABLEC(FONT_UFH,"\\cos ","cos"))
+    | "\\sinh"            -> LITERAL (HTMLABLEC(FONT_UFH,"\\sinh ","sinh"))
+    | "\\cosh"            -> LITERAL (HTMLABLEC(FONT_UFH,"\\cosh ","cosh"))
+    | "\\tan"             -> LITERAL (HTMLABLEC(FONT_UFH,"\\tan ","tan"))
+    | "\\tanh"            -> LITERAL (HTMLABLEC(FONT_UFH,"\\tanh ","tanh"))
+    | "\\sec"             -> LITERAL (HTMLABLEC(FONT_UFH,"\\sec ","sec"))
+    | "\\csc"             -> LITERAL (HTMLABLEC(FONT_UFH,"\\csc ","csc"))
+    | "\\arcsin"           -> LITERAL (HTMLABLEC(FONT_UFH,"\\arcsin ","arcsin"))
+    | "\\arctan"           -> LITERAL (HTMLABLEC(FONT_UFH,"\\arctan ","arctan"))
+    | "\\arccos"           -> (tex_use_ams (); LITERAL (HTMLABLEC(FONT_UFH,"\\mathop{\\mathrm{arccos}}","arccos")))
+    | "\\arccot"           -> (tex_use_ams (); LITERAL (HTMLABLEC(FONT_UFH,"\\mathop{\\mathrm{arccot}}","arccot")))
+    | "\\arcsec"           -> (tex_use_ams (); LITERAL (HTMLABLEC(FONT_UFH,"\\mathop{\\mathrm{arcsec}}","arcsec")))
+    | "\\arccsc"           -> (tex_use_ams (); LITERAL (HTMLABLEC(FONT_UFH,"\\mathop{\\mathrm{arccsc}}","arccsc")))
+    | "\\sgn"              -> (tex_use_ams (); LITERAL (HTMLABLEC(FONT_UFH,"\\mathop{\\mathrm{sgn}}","sgn")))
+    | "\\cot"             -> LITERAL (HTMLABLEC(FONT_UFH,"\\cot ","cot"))
+    | "\\coth"            -> LITERAL (HTMLABLEC(FONT_UFH,"\\coth ","coth"))
+    | "\\log"             -> LITERAL (HTMLABLEC(FONT_UFH,"\\log ", "log"))
+    | "\\lg"              -> LITERAL (HTMLABLEC(FONT_UFH,"\\lg ", "lg"))
+    | "\\ln"              -> LITERAL (HTMLABLEC(FONT_UFH,"\\ln ", "ln"))
+    | "\\exp"             -> LITERAL (HTMLABLEC(FONT_UFH,"\\exp ", "exp"))
+    | "\\min"             -> LITERAL (HTMLABLEC(FONT_UFH,"\\min ", "min"))
+    | "\\max"             -> LITERAL (HTMLABLEC(FONT_UFH,"\\max ", "max"))
+    | "\\gcd"             -> LITERAL (HTMLABLEC(FONT_UFH,"\\gcd ", "gcd"))
+    | "\\deg"             -> LITERAL (HTMLABLEC(FONT_UFH,"\\deg ", "deg"))
+    | "\\det"             -> LITERAL (HTMLABLEC(FONT_UFH,"\\det ", "det"))
+    | "\\bullet"           -> LITERAL (HTMLABLE (FONT_UFH, "\\bullet ", "&bull;"))
+    | "\\bull"             -> LITERAL (HTMLABLE (FONT_UFH, "\\bullet ", "&bull;"))
+    | "\\angle"            -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UF, "\\angle ", "&ang;")))
+    | "\\dagger"           -> LITERAL (HTMLABLEM(FONT_UFH, "\\dagger ", "&dagger;"))
+    | "\\ddagger"          -> LITERAL (HTMLABLEM(FONT_UFH, "\\ddagger ", "&Dagger;"))
+    | "\\Dagger"           -> LITERAL (HTMLABLEM(FONT_UFH, "\\ddagger ", "&Dagger;"))
+    | "\\colon"            -> LITERAL (HTMLABLEC(FONT_UFH, "\\colon ", ":"))
+    | "\\Vert"             -> DELIMITER (HTMLABLEM(FONT_UFH, "\\Vert ", "||"))
+    | "\\vert"             -> DELIMITER (HTMLABLEM(FONT_UFH, "\\vert ", "|"))
+    | "\\wp"               -> LITERAL (HTMLABLE (FONT_UF,  "\\wp ", "&weierp;"))
+    | "\\weierp"           -> LITERAL (HTMLABLE (FONT_UF,  "\\wp ", "&weierp;"))
+    | "\\wedge"            -> LITERAL (HTMLABLE (FONT_UF,  "\\wedge ", "&and;"))
+    | "\\and"              -> LITERAL (HTMLABLE (FONT_UF,  "\\land ", "&and;"))
+    | "\\land"             -> LITERAL (HTMLABLE (FONT_UF,  "\\land ", "&and;"))
+    | "\\vee"              -> LITERAL (HTMLABLE (FONT_UF,  "\\vee ", "&or;"))
+    | "\\or"               -> LITERAL (HTMLABLE (FONT_UF,  "\\lor ", "&or;"))
+    | "\\lor"              -> LITERAL (HTMLABLE (FONT_UF,  "\\lor ", "&or;"))
+    | "\\sub"              -> LITERAL (HTMLABLE (FONT_UF,  "\\subset ", "&sub;"))
+    | "\\supe"             -> LITERAL (HTMLABLE (FONT_UF,  "\\supseteq ", "&supe;"))
+    | "\\sube"             -> LITERAL (HTMLABLE (FONT_UF,  "\\subseteq ", "&sube;"))
+    | "\\supset"           -> LITERAL (HTMLABLE (FONT_UF,  "\\supset ", "&sup;"))
+    | "\\subset"           -> LITERAL (HTMLABLE (FONT_UF,  "\\subset ", "&sub;"))
+    | "\\supseteq"         -> LITERAL (HTMLABLE (FONT_UF,  "\\supseteq ", "&supe;"))
+    | "\\subseteq"         -> LITERAL (HTMLABLE (FONT_UF,  "\\subseteq ", "&sube;"))
+    | "\\perp"             -> LITERAL (HTMLABLE (FONT_UF,  "\\perp ", "&perp;"))
+    | "\\bot"              -> LITERAL (HTMLABLE (FONT_UF,  "\\bot ", "&perp;"))
+    | "\\lfloor"           -> DELIMITER (HTMLABLE (FONT_UF,  "\\lfloor ", "&lfloor;"))
+    | "\\rfloor"           -> DELIMITER (HTMLABLE (FONT_UF,  "\\rfloor ", "&rfloor;"))
+    | "\\lceil"            -> DELIMITER (HTMLABLE (FONT_UF,  "\\lceil ", "&lceil;"))
+    | "\\rceil"            -> DELIMITER (HTMLABLE (FONT_UF,  "\\rceil ", "&rceil;"))
+    | "\\lbrace"           -> DELIMITER (HTMLABLEC(FONT_UFH, "\\lbrace ", "{"))
+    | "\\rbrace"           -> DELIMITER (HTMLABLEC(FONT_UFH, "\\rbrace ", "}"))
+    | "\\infty"            -> LITERAL (HTMLABLEM(FONT_UF,  "\\infty ", "&infin;"))
+    | "\\infin"            -> LITERAL (HTMLABLEM(FONT_UF,  "\\infty ", "&infin;"))
+    | "\\isin"             -> LITERAL (HTMLABLE (FONT_UF,  "\\in ", "&isin;"))
+    | "\\in"               -> LITERAL (HTMLABLE (FONT_UF,  "\\in ", "&isin;"))
+    | "\\ni"               -> LITERAL (HTMLABLE (FONT_UF,  "\\ni ", "&ni;"))
+    | "\\notin"            -> LITERAL (HTMLABLE (FONT_UF,  "\\notin ", "&notin;"))
+    | "\\smallsetminus"    -> (tex_use_ams (); LITERAL (TEX_ONLY "\\smallsetminus "))
+    | "\\And"              -> (tex_use_ams (); LITERAL (HTMLABLEM(FONT_UFH, "\\And ", "&nbsp;&amp;&nbsp;")))
+    | "\\forall"           -> LITERAL (HTMLABLE (FONT_UFH, "\\forall ", "&forall;"))
+    | "\\exists"           -> LITERAL (HTMLABLE (FONT_UFH, "\\exists ", "&exist;"))
+    | "\\exist"            -> LITERAL (HTMLABLE (FONT_UFH, "\\exists ", "&exist;"))
+    | "\\equiv"            -> LITERAL (HTMLABLEM(FONT_UFH, "\\equiv ", "&equiv;"))
+    | "\\ne"               -> LITERAL (HTMLABLEM(FONT_UFH, "\\neq ", "&ne;"))
+    | "\\neq"              -> LITERAL (HTMLABLEM(FONT_UFH, "\\neq ", "&ne;"))
+    | "\\Re"               -> LITERAL (HTMLABLE (FONT_UF,  "\\Re ", "&real;"))
+    | "\\real"             -> LITERAL (HTMLABLE (FONT_UF,  "\\Re ", "&real;"))
+    | "\\Im"               -> LITERAL (HTMLABLE (FONT_UF,  "\\Im ", "&image;"))
+    | "\\image"            -> LITERAL (HTMLABLE (FONT_UF,  "\\Im ", "&image;"))
+    | "\\prime"            -> LITERAL (HTMLABLE (FONT_UFH,"\\prime ", "&prime;"))
+    | "\\backslash"        -> DELIMITER (HTMLABLEM(FONT_UFH,"\\backslash ", "\\"))
+    | "\\setminus"         -> LITERAL (HTMLABLEM(FONT_UFH,"\\setminus ", "\\"))
+    | "\\times"            -> LITERAL (HTMLABLEM(FONT_UFH,"\\times ", "&times;"))
+    | "\\pm"               -> LITERAL (HTMLABLEM(FONT_UFH,"\\pm ", "&plusmn;"))
+    | "\\plusmn"           -> LITERAL (HTMLABLEM(FONT_UFH,"\\pm ", "&plusmn;"))
+    | "\\cdot"             -> LITERAL (HTMLABLE (FONT_UFH,"\\cdot ", "&sdot;"))
+    | "\\cdots"            -> LITERAL (HTMLABLE (FONT_UFH,"\\cdots ", "&sdot;&sdot;&sdot;"))
+    | "\\sdot"             -> LITERAL (HTMLABLE (FONT_UFH,"\\cdot ", "&sdot;"))
+    | "\\oplus"            -> LITERAL (HTMLABLE (FONT_UF, "\\oplus ", "&oplus;"))
+    | "\\otimes"           -> LITERAL (HTMLABLE (FONT_UF, "\\otimes ", "&otimes;"))
+    | "\\cap"              -> LITERAL (HTMLABLEM(FONT_UF, "\\cap ", "&cap;"))
+    | "\\cup"              -> LITERAL (HTMLABLE (FONT_UF, "\\cup ", "&cup;"))
+    | "\\empty"            -> LITERAL (HTMLABLE (FONT_UF, "\\emptyset ", "&empty;"))
+    | "\\emptyset"         -> LITERAL (HTMLABLE (FONT_UF, "\\emptyset ", "&empty;"))
+    | "\\O"                -> LITERAL (HTMLABLE (FONT_UF, "\\emptyset ", "&empty;"))
+    | "\\S"                -> LITERAL (HTMLABLEM(FONT_UFH,"\\S ", "&sect;"))
+    | "\\sect"             -> LITERAL (HTMLABLEM(FONT_UFH,"\\S ", "&sect;"))
+    | "\\nabla"            -> LITERAL (HTMLABLE (FONT_UF, "\\nabla ", "&nabla;"))
+    | "\\geq"              -> LITERAL (HTMLABLE (FONT_UFH,"\\geq ", "&ge;"))
+    | "\\ge"               -> LITERAL (HTMLABLE (FONT_UFH,"\\geq ", "&ge;"))
+    | "\\leq"              -> LITERAL (HTMLABLE (FONT_UFH,"\\leq ", "&le;"))
+    | "\\le"               -> LITERAL (HTMLABLE (FONT_UFH,"\\leq ", "&le;"))
+    | "\\cong"             -> LITERAL (HTMLABLE (FONT_UF, "\\cong ", "&cong;"))
+    | "\\ang"              -> LITERAL (HTMLABLE (FONT_UF, "\\angle ", "&ang;"))
+    | "\\part"             -> LITERAL (HTMLABLEM(FONT_UF, "\\partial ", "&part;"))
+    | "\\partial"          -> LITERAL (HTMLABLEM(FONT_UF, "\\partial ", "&part;"))
+    | "\\ldots"            -> LITERAL (HTMLABLEM(FONT_UFH,"\\ldots ", "..."))
+    | "\\dots"             -> LITERAL (HTMLABLEM(FONT_UFH,"\\dots ", "..."))
+    | "\\quad"                    -> LITERAL (HTMLABLE (FONT_UF, "\\quad ","&nbsp;&nbsp;"))
+    | "\\qquad"                   -> LITERAL (HTMLABLE (FONT_UF, "\\qquad ","&nbsp;&nbsp;&nbsp;&nbsp;"))
+    | "\\mid"              -> LITERAL (HTMLABLEM(FONT_UFH,"\\mid ", " | "))
+    | "\\neg"              -> LITERAL (HTMLABLEM(FONT_UFH,"\\neg ", "&not;"))
+    | "\\langle"           -> DELIMITER (HTMLABLE (FONT_UFH,"\\langle ","&lang;"))
+    | "\\rangle"           -> DELIMITER (HTMLABLE (FONT_UFH,"\\rangle ","&rang;"))
+    | "\\lang"             -> DELIMITER (HTMLABLE (FONT_UFH,"\\langle ","&lang;"))
+    | "\\rang"             -> DELIMITER (HTMLABLE (FONT_UFH,"\\rangle ","&rang;"))
+    | "\\lbrack"          -> DELIMITER (HTMLABLEC(FONT_UFH,"[","["))
+    | "\\rbrack"          -> DELIMITER (HTMLABLEC(FONT_UFH,"]","]"))
+    | "\\ddots"            -> LITERAL (TEX_ONLY "\\ddots ")
+    | "\\clubs"            -> LITERAL (TEX_ONLY "\\clubsuit ")
+    | "\\clubsuit"         -> LITERAL (TEX_ONLY "\\clubsuit ")
+    | "\\spades"           -> LITERAL (TEX_ONLY "\\spadesuit ")
+    | "\\spadesuit"        -> LITERAL (TEX_ONLY "\\spadesuit ")
+    | "\\hearts"           -> LITERAL (TEX_ONLY "\\heartsuit ")
+    | "\\heartsuit"        -> LITERAL (TEX_ONLY "\\heartsuit ")
+    | "\\diamonds"         -> LITERAL (TEX_ONLY "\\diamondsuit ")
+    | "\\diamondsuit"      -> LITERAL (TEX_ONLY "\\diamondsuit ")
+    | "\\implies"          -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UF, "\\implies ", "&rArr;")))
+    | "\\mod"             -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UFH,"\\mod ", "mod")))
+    | "\\Diamond"          -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UF, "\\Diamond ", "&loz;")))
+    | "\\dotsb"            -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UF, "\\dotsb ", "&sdot;&sdot;&sdot;")))
+    | "\\reals"            -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UFH,"\\mathbb{R}", "<b>R</b>")))
+    | "\\Reals"            -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UFH,"\\mathbb{R}", "<b>R</b>")))
+    | "\\R"                -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UFH,"\\mathbb{R}", "<b>R</b>")))
+    | "\\cnums"            -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UFH,"\\mathbb{C}", "<b>C</b>")))
+    | "\\Complex"          -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UFH,"\\mathbb{C}", "<b>C</b>")))
+    | "\\Z"                -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UFH,"\\mathbb{Z}", "<b>Z</b>")))
+    | "\\natnums"          -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UFH,"\\mathbb{N}", "<b>N</b>")))
+    | "\\N"               -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UFH,"\\mathbb{N}", "<b>N</b>")))
+    | "\\lVert"            -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UFH,"\\lVert ", "||")))
+    | "\\rVert"            -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UFH,"\\rVert ", "||")))
+    | "\\nmid"             -> (tex_use_ams (); LITERAL (TEX_ONLY "\\nmid "))
+    | "\\lesssim"          -> (tex_use_ams (); LITERAL (TEX_ONLY "\\lesssim "))
+    | "\\ngeq"             -> (tex_use_ams (); LITERAL (TEX_ONLY "\\ngeq "))
+    | "\\smallsmile"       -> (tex_use_ams (); LITERAL (TEX_ONLY "\\smallsmile "))
+    | "\\smallfrown"       -> (tex_use_ams (); LITERAL (TEX_ONLY "\\smallfrown "))
+    | "\\nleftarrow"       -> (tex_use_ams (); LITERAL (TEX_ONLY "\\nleftarrow "))
+    | "\\nrightarrow"      -> (tex_use_ams (); LITERAL (TEX_ONLY "\\nrightarrow "))
+    | "\\trianglelefteq"   -> (tex_use_ams (); LITERAL (TEX_ONLY "\\trianglelefteq "))
+    | "\\trianglerighteq"  -> (tex_use_ams (); LITERAL (TEX_ONLY "\\trianglerighteq "))
+    | "\\square"           -> (tex_use_ams (); LITERAL (TEX_ONLY "\\square "))
+    | "\\supsetneq"        -> (tex_use_ams (); LITERAL (TEX_ONLY "\\supsetneq "))
+    | "\\subsetneq"        -> (tex_use_ams (); LITERAL (TEX_ONLY "\\subsetneq "))
+    | "\\Box"              -> (tex_use_ams (); LITERAL (TEX_ONLY "\\Box "))
+    | "\\nleq"             -> (tex_use_ams (); LITERAL (TEX_ONLY "\\nleq "))
+    | "\\upharpoonright"   -> (tex_use_ams (); LITERAL (TEX_ONLY "\\upharpoonright "))
+    | "\\upharpoonleft"    -> (tex_use_ams (); LITERAL (TEX_ONLY "\\upharpoonleft "))
+    | "\\downharpoonright" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\downharpoonright "))
+    | "\\downharpoonleft"  -> (tex_use_ams (); LITERAL (TEX_ONLY "\\downharpoonleft "))
+    | "\\nless"            -> (tex_use_ams (); LITERAL (TEX_ONLY "\\nless "))
+    | "\\Vdash"            -> (tex_use_ams (); LITERAL (TEX_ONLY "\\Vdash "))
+    | "\\vDash"            -> (tex_use_ams (); LITERAL (TEX_ONLY "\\vDash "))
+    | "\\varkappa"         -> (tex_use_ams (); LITERAL (TEX_ONLY "\\varkappa "))
+    | "\\digamma"          -> (tex_use_ams (); LITERAL (TEX_ONLY "\\digamma "))
+    | "\\beth"             -> (tex_use_ams (); LITERAL (TEX_ONLY "\\beth "))
+    | "\\daleth"           -> (tex_use_ams (); LITERAL (TEX_ONLY "\\daleth "))
+    | "\\gimel"            -> (tex_use_ams (); LITERAL (TEX_ONLY "\\gimel "))
+    | "\\complement"       -> (tex_use_ams (); LITERAL (TEX_ONLY "\\complement "))
+    | "\\eth"              -> (tex_use_ams (); LITERAL (TEX_ONLY "\\eth "))
+    | "\\hslash"           -> (tex_use_ams (); LITERAL (TEX_ONLY "\\hslash "))
+    | "\\mho"              -> (tex_use_ams (); LITERAL (TEX_ONLY "\\mho "))
+    | "\\Finv"             -> (tex_use_ams (); LITERAL (TEX_ONLY "\\Finv "))
+    | "\\Game"             -> (tex_use_ams (); LITERAL (TEX_ONLY "\\Game "))
+    | "\\varlimsup"        -> (tex_use_ams (); LITERAL (TEX_ONLY "\\varlimsup "))
+    | "\\varliminf"        -> (tex_use_ams (); LITERAL (TEX_ONLY "\\varliminf "))
+    | "\\varinjlim"        -> (tex_use_ams (); LITERAL (TEX_ONLY "\\varinjlim "))
+    | "\\varprojlim"       -> (tex_use_ams (); LITERAL (TEX_ONLY "\\varprojlim "))
+    | "\\injlim"           -> (tex_use_ams (); LITERAL (TEX_ONLY "\\injlim "))
+    | "\\projlim"          -> (tex_use_ams (); LITERAL (TEX_ONLY "\\projlim "))
+    | "\\iint"             -> (tex_use_ams (); LITERAL (TEX_ONLY "\\iint "))
+    | "\\iiint"            -> (tex_use_ams (); LITERAL (TEX_ONLY "\\iiint "))
+    | "\\iiiint"           -> (tex_use_ams (); LITERAL (TEX_ONLY "\\iiiint "))
+    | "\\varnothing"       -> (tex_use_ams (); LITERAL (TEX_ONLY "\\varnothing "))
+    | "\\left"             -> LEFT
+    | "\\right"            -> RIGHT
+    | "\\hat"             -> FUN_AR1 "\\hat "
+    | "\\widehat"          -> FUN_AR1 "\\widehat "
+    | "\\overline"         -> FUN_AR1 "\\overline "
+    | "\\overbrace"        -> FUN_AR1 "\\overbrace "
+    | "\\underline"        -> FUN_AR1 "\\underline "
+    | "\\underbrace"       -> FUN_AR1 "\\underbrace "
+    | "\\overleftarrow"    -> FUN_AR1 "\\overleftarrow "
+    | "\\overrightarrow"   -> FUN_AR1 "\\overrightarrow "
+    | "\\overleftrightarrow"->FUN_AR1 "\\overleftrightarrow "
+    | "\\check"                   -> FUN_AR1 "\\check "
+    | "\\acute"                   -> FUN_AR1 "\\acute "
+    | "\\grave"                   -> FUN_AR1 "\\grave "
+    | "\\bar"             -> FUN_AR1 "\\bar "
+    | "\\vec"             -> FUN_AR1 "\\vec "
+    | "\\dot"             -> FUN_AR1 "\\dot "
+    | "\\ddot"            -> FUN_AR1 "\\ddot "
+    | "\\breve"                   -> FUN_AR1 "\\breve "
+    | "\\tilde"                   -> FUN_AR1 "\\tilde "
+    | "\\not"             -> FUN_AR1 "\\not "
+    | "\\choose"           -> FUN_INFIX "\\choose "
+    | "\\atop"             -> FUN_INFIX "\\atop "
+    | "\\binom"            -> FUN_AR2 "\\binom "
+    | "\\frac"             -> FUN_AR2h ("\\frac ", fun num den -> Html.html_render [num], "<hr style=\"{background: black}\">", Html.html_render [den])
+    | "\\over"             -> FUN_INFIXh ("\\over ", fun num den -> Html.html_render num, "<hr style=\"{background: black}\">", Html.html_render den)
+    | "\\sqrt"             -> FUN_AR1 "\\sqrt "
+    | "\\pmod"             -> FUN_AR1hl ("\\pmod ", ("(mod ", ")"))
+    | "\\bmod"             -> FUN_AR1hl ("\\bmod ", ("mod ", ""))
+    | "\\emph"             -> FUN_AR1 "\\emph "
+    | "\\texttt"           -> FUN_AR1 "\\texttt "
+    | "\\textbf"           -> FUN_AR1 "\\textbf "
+    | "\\textit"           -> FUN_AR1hf ("\\textit ", FONTFORCE_IT)
+    | "\\textrm"           -> FUN_AR1hf ("\\textrm ", FONTFORCE_RM)
+    | "\\rm"               -> DECLh ("\\rm ", FONTFORCE_RM)
+    | "\\it"               -> DECLh ("\\it ", FONTFORCE_IT)
+    | "\\cal"              -> DECL "\\cal "
+    | "\\bf"               -> DECL "\\bf "
+    | "\\big"             -> BIG "\\big "
+    | "\\Big"             -> BIG "\\Big "
+    | "\\bigg"            -> BIG "\\bigg "
+    | "\\Bigg"            -> BIG "\\Bigg "
+    | "\\mathit"           -> (tex_use_ams (); FUN_AR1hf ("\\mathit ", FONTFORCE_IT))
+    | "\\mathrm"           -> (tex_use_ams (); FUN_AR1hf ("\\mathrm ", FONTFORCE_RM))
+    | "\\mathop"           -> (tex_use_ams (); FUN_AR1 "\\mathop ")
+    | "\\boldsymbol"       -> (tex_use_ams (); FUN_AR1 "\\boldsymbol ")
+    | "\\bold"             -> (tex_use_ams (); FUN_AR1 "\\mathbf ")
+    | "\\Bbb"              -> (tex_use_ams (); FUN_AR1 "\\mathbb ")
+    | "\\mathbf"           -> (tex_use_ams (); FUN_AR1 "\\mathbf ")
+    | "\\mathsf"           -> (tex_use_ams (); FUN_AR1 "\\mathsf ")
+    | "\\mathcal"          -> (tex_use_ams (); FUN_AR1 "\\mathcal ")
+    | "\\mathbb"           -> (tex_use_ams (); FUN_AR1 "\\mathbb ")
+    | "\\mathfrak"         -> (tex_use_ams (); FUN_AR1 "\\mathfrak ")
+    | "\\operatorname"     -> (tex_use_ams (); FUN_AR1 "\\operatorname ")
+    | "\\mbox"             -> raise (Failure "malformatted \\mbox")
+    | "\\vbox"             -> raise (Failure "malformatted \\vbox")
+    | "\\hbox"             -> raise (Failure "malformatted \\hbox")
+    | s                    -> raise (Illegal_tex_function s)
diff --git a/math/texutil.mli b/math/texutil.mli
new file mode 100644 (file)
index 0000000..99d0e4e
--- /dev/null
@@ -0,0 +1,11 @@
+val render_tex : Tex.t -> string
+
+val set_encoding : string -> unit
+val tex_use_nonascii: unit -> unit
+val tex_use_ams: unit -> unit
+
+val get_preface : unit -> string
+val get_footer : unit -> string
+
+exception Illegal_tex_function of string
+val find: string -> Parser.token
diff --git a/math/texvc.ml b/math/texvc.ml
new file mode 100644 (file)
index 0000000..abddd3d
--- /dev/null
@@ -0,0 +1,34 @@
+exception LexerException of string
+let lexer_token_safe lexbuf =
+    try Lexer.token lexbuf
+    with Failure s -> raise (LexerException s)
+
+let render tmppath finalpath tree =
+    let outtex = Util.mapjoin Texutil.render_tex tree in
+    let md5 = Digest.to_hex (Digest.string outtex) in
+    begin
+       let mathml = Mathml.render tree
+       and html = Html.render tree
+       in print_string (match (html,!Html.conservativeness,mathml) with
+           None,_,None -> "+" ^ md5 
+         | Some h,Html.CONSERVATIVE,None -> "c" ^ md5  ^ h
+         | Some h,Html.MODERATE,None -> "m" ^ md5  ^ h
+         | Some h,Html.LIBERAL,None -> "l" ^ md5  ^ h
+         | Some h,Html.CONSERVATIVE,Some m -> "C" ^ md5  ^ h ^ "\000" ^ m
+         | Some h,Html.MODERATE,Some m -> "M" ^ md5  ^ h ^ "\000" ^ m
+         | Some h,Html.LIBERAL,Some m -> "L" ^ md5 ^ h ^ "\000" ^ m
+         | None,_,Some m -> "X" ^ md5   ^ m
+       );
+       Render.render tmppath finalpath outtex md5
+    end
+let _ =
+    Texutil.set_encoding (try Sys.argv.(4) with _ -> "UTF-8");
+    try render Sys.argv.(1) Sys.argv.(2) (Parser.tex_expr lexer_token_safe (Lexing.from_string Sys.argv.(3)))
+    with Parsing.Parse_error -> print_string "S"
+       | LexerException _ -> print_string "E"
+       | Texutil.Illegal_tex_function s -> print_string ("F" ^ s)
+       | Util.FileAlreadyExists -> print_string "-"
+       | Invalid_argument _ -> print_string "-"
+       | Failure _ -> print_string "-"
+       | Render.ExternalCommandFailure s -> ()
+       | _ -> print_string "-"
diff --git a/math/texvc_cgi.ml b/math/texvc_cgi.ml
new file mode 100644 (file)
index 0000000..57b4d97
--- /dev/null
@@ -0,0 +1,62 @@
+open Netcgi;;
+open Netcgi_types;;
+open Netcgi_env;;
+open Netchannels;;
+
+let cgi = new Netcgi.std_activation ()
+let out = cgi # output # output_string
+let math = cgi # argument_value ~default:"" "math"
+let tmppath = "/home/taw/public_html/wiki/tmp/"
+let finalpath = "/home/taw/public_html/wiki/math/"
+let finalurl = "http://wroclaw.taw.pl.eu.org/~taw/wiki/math/"
+;;
+
+let h_header = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\""^
+            " \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"^
+            "<html><head><title>texvc</title></head><body>"^
+            "<form method=post action=\"http://wroclaw.taw.pl.eu.org/~taw/cgi-bin/newcodebase/math/texvc_cgi\">"^
+            "<textarea name='math' rows=10 cols=80>"
+let h_middle = "</textarea><br><input type=submit value=\"Preview\" name='preview'></form>"
+let h_footer = "</body></html>\n"
+
+let render tmppath finalpath tree =
+    let outtex = Texutil.mapjoin Texutil.print tree in
+    let md5 = Digest.to_hex (Digest.string outtex) in
+    begin
+       out "<h3>TeX</h3>";
+        out outtex; (* <, &  and > should be protected *)
+       (try out ("<h3>HTML</h3>" ^ (Texutil.html_render tree))
+         with _ -> out "<h3>HTML could not be rendered</h3>");
+       try  Render.render tmppath finalpath outtex md5;
+           out ("<h3>Image:</h3><img src=\""^finalurl^md5^".png\">")
+       with Util.FileAlreadyExists -> out ("<h3>Image:</h3><img src=\""^finalurl^md5^".png\">")
+           | Failure s -> out ("<h3>Other failure: " ^ s ^ "</h3>")
+          | Render.ExternalCommandFailure "latex" -> out "<h3>latex failed</h3>"
+          | Render.ExternalCommandFailure "dvips" -> out "<h3>dvips failed</h3>"
+           | _ ->  out "<h3>Other failure</h3>"
+    end
+;;
+
+cgi#set_header ();;
+
+out h_header;;
+out math;;
+out h_middle;;
+
+exception LexerException of string
+let lexer_token_safe lexbuf =
+    try Lexer.token lexbuf
+    with Failure s -> raise (LexerException s)
+;;
+if math = ""
+then ()
+else try
+       render tmppath finalpath (Parser.tex_expr lexer_token_safe (Lexing.from_string math))
+    with Parsing.Parse_error -> out "<h3>Parse error</h3>"
+       | LexerException s -> out "<h3>Lexing failure</h3>"
+       | Texutil.Illegal_tex_function s -> out ("<h3>Illegal TeX function: " ^ s ^ "</h3>")
+       | Failure s -> out ("<h3>Other failure: " ^ s ^ "</h3>")
+       | _ -> out "<h3>Other failure</h3>"
+;;
+
+out h_footer
diff --git a/math/texvc_test.ml b/math/texvc_test.ml
new file mode 100644 (file)
index 0000000..3bce529
--- /dev/null
@@ -0,0 +1,25 @@
+exception LexerException of string
+let lexer_token_safe lexbuf =
+    try Lexer.token lexbuf
+    with Failure s -> raise (LexerException s)
+
+let rec foo () =
+    try
+       let line = input_line stdin in
+       (try
+           let tree = Parser.tex_expr lexer_token_safe (Lexing.from_string line) in
+           let out = Util.mapjoin Texutil.render_tex tree in
+           (match Html.render tree with
+               Some _ -> print_string "$^\n"
+             | None -> print_string "$_\n";
+           )
+        with
+           Texutil.Illegal_tex_function s -> print_string ("$T" ^ s ^ " " ^ line ^ "\n")
+         | LexerException s               -> print_string ("$L" ^ line ^ "\n")
+         | _                              -> print_string ("$ " ^ line ^ "\n"));
+       flush stdout;
+       foo ();
+    with
+       End_of_file -> ()
+;;
+foo ();;
diff --git a/math/texvc_tex.ml b/math/texvc_tex.ml
new file mode 100644 (file)
index 0000000..30c0f67
--- /dev/null
@@ -0,0 +1,3 @@
+Texutil.set_encoding (try Sys.argv.(2) with _ -> "UTF-8");
+try print_string (Util.mapjoin Texutil.render_tex (Parser.tex_expr Lexer.token (Lexing.from_string Sys.argv.(1))))
+with _ -> ()
diff --git a/math/util.ml b/math/util.ml
new file mode 100644 (file)
index 0000000..f045856
--- /dev/null
@@ -0,0 +1,17 @@
+let mapjoin f l = (List.fold_left (fun a b -> a ^ (f b)) "" l)
+let mapjoine e f = function
+    [] -> ""
+  | h::t -> (List.fold_left (fun a b -> a ^ e ^ (f b)) (f h) t)
+
+exception FileAlreadyExists
+let open_out_unless_exists path =
+    if Sys.file_exists path
+    then raise FileAlreadyExists
+    else open_out path
+
+let run_in_other_directory tmppath cmd =
+    let prevdir = Sys.getcwd () in(
+       Sys.chdir tmppath;
+       let retval = Sys.command cmd in
+           (Sys.chdir prevdir; retval)
+    )
diff --git a/rdf/recent.phtml b/rdf/recent.phtml
new file mode 100644 (file)
index 0000000..de8d1a3
--- /dev/null
@@ -0,0 +1,76 @@
+<?php
+include("Setup.php");
+header("Content-type: text/xml; charset=utf-8");
+echo "<?xml version=\"1.0\"?>";
+
+if( $style == "new" ) {
+       $addl = " - " . wfMsg( "newpages");
+} else {
+       $addl = "";
+}
+
+?>
+
+<rdf:RDF
+xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+xmlns="http://my.netscape.com/rdf/simple/0.9/">
+
+<channel>
+<title><?php echo iconv($wgInputEncoding, "utf-8", wfMsg("sitetitle") . $addl ) ?></title>
+<link><?php echo $wgServer ?></link>
+<description><?php echo iconv($wgInputEncoding, "utf-8", wfMsg("sitesubtitle") ) ?></description>
+</channel>
+
+<?php
+#<image>
+#<title>Wikipedia</title>
+#<url>...</url>
+#<link>http://wikipedia.org/</link>
+#</image>
+
+if(isset($limit)) {
+       if( $limit < 1) $limit = 1;
+       if( $tlimit > 500) $limit = 500;
+}
+if(!isset($limit)) $limit = 10;
+
+if($style == 'new') {
+       # 10 newest articles
+$sql = "SELECT rc_title as cur_title, rc_comment as cur_comment FROM recentchanges,cur
+WHERE rc_cur_id=cur_id AND rc_new=1 AND rc_namespace=0 AND cur_is_redirect=0
+AND LENGTH(cur_text) > 75
+ORDER BY rc_timestamp DESC LIMIT {$limit}";
+} else {
+       # 10 most recently edit articles that aren't frickin tiny
+$sql = "SELECT rc_title as cur_title,rc_comment as cur_comment FROM recentchanges,cur
+WHERE rc_cur_id=cur_id AND rc_namespace=0 AND rc_this_oldid=0 AND cur_is_redirect=0
+AND LENGTH(cur_text) > 150
+ORDER BY rc_timestamp DESC LIMIT {$limit}";
+}
+$res = wfQuery( $sql );
+
+while( $row = wfFetchObject( $res ) ) {
+       $title = htmlspecialchars(
+               iconv($wgInputEncoding, "utf-8",
+               str_replace( "_", " ", $row->cur_title ) ) );
+       $url = wfLocalUrl( wfUrlencode( $row->cur_title ) );
+       $description = "<description>" . iconv($wgInputEncoding, "utf-8",
+               htmlspecialchars( $row->cur_comment )) . "</description>";
+       echo "
+<item>
+<title>{$title}</title>
+<link>{$url}</link>
+{$description}
+</item>
+";
+}
+
+#<textinput>
+#<title>Search Wikipedia</title>
+#<description>Search Wikipedia articles</description>
+#<name>query</name>
+#<link>http://www.wikipedia.org/w/wiki.phtml?search=</link>
+#</textinput>
+?>
+
+</rdf:RDF>
\ No newline at end of file
diff --git a/redirect.phtml b/redirect.phtml
new file mode 100644 (file)
index 0000000..bad253d
--- /dev/null
@@ -0,0 +1,6 @@
+<?
+include_once( "./LocalSettings.php" );
+global $wpDropdown, $wgArticlePath;
+$url = str_replace( "$1", $wpDropdown, $wgArticlePath );
+header( "Location: {$url}" );
+?>
diff --git a/stylesheets/cologneblue.css b/stylesheets/cologneblue.css
new file mode 100644 (file)
index 0000000..5a12a5e
--- /dev/null
@@ -0,0 +1,93 @@
+
+body { margin: 0px; padding: 0px; }
+#specialform { display: inline; }
+#content { position: absolute; top: 0; margin: 0; padding: 0; }
+#topbar { padding: 0px; }
+#powersearch {
+  background: #DDEEFF; border-style: solid; border-width: 1; padding: 2;
+}
+#quickbar {
+ width: 140px; top: 18ex; padding: 2px; visibility: visible; z-index: 99;
+}
+#article, #article td, #article th, #article p {
+ font-family: Verdana, Arial, sans-serif;
+ font-size: 10pt; color: black;
+ padding: 0;
+}
+#article p {
+ padding-top: 0; padding-bottom: 0;
+ margin-top: 1ex; margin-bottom: 0;
+}
+p, pre, td, th, li, dd, dt { line-height: 12pt; }
+
+#footer { padding: 4px; }
+#footer form { display: inline; }
+
+#sitetitle {
+ font-family: Times, serif;
+ color: white;
+ font-weight: normal; font-size: 32pt;
+ line-height: 32pt;
+}
+td.top {
+ background-color: #6688AA; color: white;
+ margin-top: 4px; margin-bottom: 4px;
+ padding-top: 0; padding-bottom: 0;
+ text-transform: uppercase;
+ font-family: Verdana, Arial, sans-serif; font-size: 8pt;
+}
+td.top a {
+ font-family: Verdana, Arial, sans-serif;
+ background-color: #6688AA; color: white;
+ text-decoration: none; font-size: 10pt;
+}
+td.bottom {
+ font-family: Verdana, Arial, sans-serif;
+ font-size: 10pt;
+ padding: 0;
+}
+#pagestats {
+ font-family: Times, serif;
+ color: black;
+ font-size: 9pt;
+}
+#sitesub {
+ font-family: Verdana, Arial, sans-serif;
+ font-size: 9pt; font-weight: bold;
+ color: black;
+ padding-top: 0;
+}
+#quickbar {
+ font-family: Verdana, Arial, sans-serif;
+ font-size: 8pt; font-weight: bold; line-height: 9.5pt;
+ text-decoration: none;
+ color: black;
+ padding: 0; margin-top: 0;
+}
+#quickbar a { color: #446688; }
+
+#quickbar h6 {
+ font-family: Verdana, Arial, sans-serif;
+ font-size: 10pt; font-weight: bold; line-height: 12pt;
+ text-decoration: none;
+ color: #666666;
+ padding: 0; margin-bottom: 2px; margin-top: 6px;
+}
+#quickbar form { padding: 0; margin-top: 0; }
+
+h1 { font-family: Arial, Helvetica, sans-serif;
+ color: #666666;
+ font-family: Verdana, Arial, sans-serif;
+ font-size: 18pt; font-weight: bold; line-height: 21pt;
+}
+h1.pagetitle { padding-bottom: 0; margin-bottom: 0; }
+#article p.subtitle {
+ color: #666666; font-size: 11pt; font-weight: bold;
+ padding-top: 0; margin-top: 0; padding-bottom: 1ex;
+}
+a { color: #223366; }
+a.external { color: #336644; }
+a.printable { text-decoration: underline; }
+a.stub { color:#772233; text-decoration:none; }
+h2, h3, h4, h5, h6 { margin-bottom: 0; }
+a.stub { color:#772233; text-decoration:none; }
diff --git a/stylesheets/nostalgia.css b/stylesheets/nostalgia.css
new file mode 100644 (file)
index 0000000..4e427cf
--- /dev/null
@@ -0,0 +1,12 @@
+#article { }
+#specialform { display: inline; }
+#powersearch {
+  background: #DDEEFF; border-style: solid; border-width: 1; padding: 2;
+}
+.bodytext { }
+a.interwiki, a.external { color: #3366BB; }
+a.printable { text-decoration: underline; }
+a.stub { color:#772233; text-decoration:none; }
+h1.pagetitle { padding-top: 0; margin-top: 0; padding-bottom: 0; margin-bottom: 0; }
+h2, h3, h4, h5, h6 { margin-bottom: 0; }
+p.subtitle { padding-top: 0; margin-top: 0; }
diff --git a/stylesheets/quickbar.css b/stylesheets/quickbar.css
new file mode 100644 (file)
index 0000000..d7930c2
--- /dev/null
@@ -0,0 +1 @@
+#quickbar { position: fixed; padding: 4px; }
diff --git a/stylesheets/sticky.js b/stylesheets/sticky.js
new file mode 100644 (file)
index 0000000..56da81e
--- /dev/null
@@ -0,0 +1,124 @@
+// Make a layer that stays in the same place on screen when scrolling the browser window.
+// Version 1.2
+// See http://www.mark.ac/help for browser support.
+
+var mySticky;
+var theLayer;
+
+// Setup variables for sliding.
+// lastY and staticYOffset should match your CSS top definition.
+
+lastY=10;YOffset=0;staticYOffset=10;refreshMS=25;
+
+
+// Setup function that runs when the page loads.
+       function setup(eID){
+               bw=new checkBrowser;
+               if(bw.ns4||bw.opera){MM_reloadPage(true);}
+               var noFix=bw.ie4||bw.ns4||(bw.ns6&&bw.mac)||(bw.macie50)?true:false;
+               if (window.attachEvent){fix_bind()}
+               else if(noFix){ 
+                       if(bw.ns6){document.getElementById(eID).style.position="absolute";}
+                       if(bw.macie50){document.getElementById(eID).style.position="absolute";document.getElementById(eID).style.backgroundColor="#ccffcc";}
+                       if(bw.ns6&&YOffset==0){YOffset=-15}
+                       mySticky=new makeLayerObj(eID);
+                       layerSlide(eID)}
+               else{
+                       mySticky=new makeLayerObj(eID);
+                       mySticky.css.position="fixed";}
+
+               if(!mySticky){mySticky=new makeLayerObj(eID);}
+               //mySticky.css.visibility="visible";
+       }
+
+
+// -------------------------
+// emulate css 'position: fixed' in IE5+ Win
+// code by aclover@1value.com
+       fix_elements = new Array();
+       
+       function fix_event(){
+               var i;
+               for (i=0; i < fix_elements.length; i++){
+                       fix_elements[i].style.left = parseInt(fix_elements[i].fix_left)+document.getElementsByTagName('html')[0].scrollLeft+document.getElementsByTagName('body')[0].scrollLeft+'px';
+                       fix_elements[i].style.top = parseInt(fix_elements[i].fix_top)+document.getElementsByTagName('html')[0].scrollTop+document.getElementsByTagName('body')[0].scrollTop+'px';
+               }
+       }
+
+       function fix_bind(){
+               var i;
+               for (i=0; i < document.all.length; i++){
+                       if (document.all[i].currentStyle.position=='fixed'){
+                               document.all[i].fix_left = document.all[i].currentStyle.left;
+                               document.all[i].fix_top = document.all[i].currentStyle.top;
+                               document.all[i].style.position = 'absolute';
+                               fix_elements[fix_elements.length] = document.all[i];
+                               window.attachEvent('onscroll', fix_event);
+                               window.attachEvent('onresize', fix_event);
+                       } 
+               }
+       }
+// -------------------------
+
+
+// -------------------------
+// DHTML menu sliding. Requires checkBrowser()
+// Based on source at http://www.simplythebest.net/
+       function layerSlide(layerID) {
+               if(bw.dhtml){
+                       if(!mySticky){mySticky=new makeLayerObj(layerID);}
+                       if (bw.ns) {winY = window.pageYOffset;}
+                       else if (bw.ie) {winY = document.body.scrollTop;}
+                       if (bw.ie||bw.ns) {
+                               if (winY!=lastY&&winY>YOffset-staticYOffset){smooth = .3 * (winY - lastY - YOffset + staticYOffset);}
+                               else if (YOffset-staticYOffset+lastY>YOffset-staticYOffset){smooth = .3 * (winY - lastY - (YOffset-(YOffset-winY)));}
+                               else{smooth=0}
+                               if(smooth > 0) {smooth = Math.ceil(smooth);}
+                               else{smooth = Math.floor(smooth);}
+                               if (bw.ie){mySticky.css.pixelTop+=smooth;}
+                               else if (bw.ns){mySticky.css.top=parseInt(mySticky.css.top)+smooth;}
+                               lastY = lastY+smooth;
+                               top.window.status=new Date()
+                               setTimeout('layerSlide("'+layerID+'")', refreshMS)}}}
+// -------------------------
+
+// Netscape 4.x browser resize fix
+       function MM_reloadPage(init) {
+       if (init==true) with (navigator) {if ((appName=="Netscape")&&(parseInt(appVersion)==4)) {
+       document.MM_pgW=innerWidth; document.MM_pgH=innerHeight; top.onresize=MM_reloadPage; }}
+       else if (innerWidth!=document.MM_pgW || innerHeight!=document.MM_pgH) {location.reload();}}
+
+// Create browser-independent layer and browser objects
+       function makeLayerObj(eID){
+               if(document.getElementById){this.css=document.getElementById(eID).style}
+               else if(document.layers){this.css=document.layers[eID];}
+               else if(document.all){this.css=document.all[eID].style;}
+               return this
+       }
+       
+       function checkBrowser(){
+               this.ver=navigator.appVersion;
+               this.name=navigator.appName;
+               this.mac=(navigator.platform.toLowerCase().indexOf('mac')>-1)?true:false;
+               this.opera=(navigator.userAgent.toLowerCase().indexOf('opera')>-1)?true:false;
+               this.dom=document.getElementById?true:false;
+               this.ns=(this.name=='Netscape');
+               this.ie4=(document.all && !this.dom)?true:false;
+               this.ie=(this.name =='Microsoft Internet Explorer'&&!this.opera)?true:false;
+               this.ie5=(this.ie && (navigator.userAgent.indexOf("MSIE 5")!=-1))?true:false;
+               this.macie50=(this.mac&&this.ie5&&(navigator.userAgent.indexOf("MSIE 5.0")!=-1))?true:false
+               this.ns4=(this.ns && parseInt(this.ver) == 4)?true:false;
+               this.ns6=((this.name=="Netscape")&&(parseInt(this.ver)==5))?true:false
+               this.standards=document.getElementById?true:false;
+               this.dhtml=this.standards||this.ie4||this.ns4;
+       }
+       
+       function showMe(eID){
+               myFloater=new makeLayerObj(eID)
+               myFloater.css.visibility="visible";
+       }
+       
+       function hideMe(eID){
+               myFloater=new makeLayerObj(eID)
+               myFloater.css.visibility="hidden";
+       }
\ No newline at end of file
diff --git a/stylesheets/wikibits.js b/stylesheets/wikibits.js
new file mode 100644 (file)
index 0000000..8886e11
--- /dev/null
@@ -0,0 +1,32 @@
+// Wikipedia JavaScript support functions
+
+// for enhanced RecentChanges
+function toggleVisibility( _levelId, _otherId, _linkId) {
+       var thisLevel = document.getElementById( _levelId );
+       var otherLevel = document.getElementById( _otherId );
+       var linkLevel = document.getElementById( _linkId );
+       if ( thisLevel.style.display == 'none' ) {
+               thisLevel.style.display = 'block';
+               otherLevel.style.display = 'none';
+               linkLevel.style.display = 'inline';
+       } else {
+               thisLevel.style.display = 'none';
+               otherLevel.style.display = 'inline';
+               linkLevel.style.display = 'none';
+               }
+       }
+
+// Timezone stuff
+// tz in format [+-]HHMM
+function checkTimezone( tz, msg ) {
+       var localclock = new Date();
+       // returns negative offset from GMT in minutes
+       var tzRaw = localclock.getTimezoneOffset();
+       var tzHour = Math.floor( Math.abs(tzRaw) / 60);
+       var tzMin = Math.abs(tzRaw) % 60;
+       var tzString = ((tzRaw >= 0) ? "-" : "+") + ((tzHour < 10) ? "0" : "") + tzHour + ((tzMin < 10) ? "0" : "") + tzMin;
+       if( tz != tzString ) {
+               var junk = msg.split( '$1' );
+               document.write( junk[0] + "UTC" + tzString + junk[1] );
+       }
+}
diff --git a/stylesheets/wikiprintable.css b/stylesheets/wikiprintable.css
new file mode 100644 (file)
index 0000000..101cf91
--- /dev/null
@@ -0,0 +1,7 @@
+.bodytext { }
+a.CBlink { color: #0000AA; text-decoration: none; font-size: 12pt; }
+a.interwiki, a.external { color: #3333BB; text-decoration: none; }
+body { color: #000000; background: #ffffff; }
+h1.pagetitle { padding-bottom: 0; margin-bottom: 0; }
+i.link, u.link { color: #000066; }
+p.subtitle { padding-top: 0; margin-top: 0; }
diff --git a/stylesheets/wikistandard.css b/stylesheets/wikistandard.css
new file mode 100644 (file)
index 0000000..30f0997
--- /dev/null
@@ -0,0 +1,27 @@
+#article { padding: 4px; }
+#content { position: absolute; top: 0;  margin: 0; padding: 0; }
+#footer { padding: 4px; }
+#pagestats { font-size: 9pt; }
+#powersearch {
+  background: #DDEEFF; border-style: solid; border-width: 1; padding: 2;
+}
+#quickbar { width: 140px; padding: 4px; visibility: visible; z-index: 99; }
+#topbar { padding: 4px; }
+.bodytext { }
+a.interwiki, a.external { color: #3366BB; }
+a.printable { text-decoration: underline; }
+a.stub { color:#772233; text-decoration:none; }
+a.stub { color:#772233; text-decoration:none; }
+body { margin: 0px; padding: 4px; }
+form.inline { display: inline; }
+h1.pagetitle { padding-top: 0; margin-top: 0; padding-bottom: 0; margin-bottom: 0; }
+h2 { font-size: 125%; }
+h2, h3, h4, h5, h6 { margin-bottom: 0; }
+h3 { font-size: 112.5%; }
+h4 { font-size: 106.25%; }
+h5 { font-size: 103.125%; }
+h6 { font-size: 100%; }
+p.subpages { font-size:small;}
+p.subtitle { padding-top: 0; margin-top: 0; }
+td.bottom { border-top: 2px solid #000000; }
+td.top { border-bottom: 2px solid #000000; }
diff --git a/testsuite/README b/testsuite/README
new file mode 100644 (file)
index 0000000..e3baa5f
--- /dev/null
@@ -0,0 +1,14 @@
+This is a first pass at a unit test and timing suite
+for the Wikipedia software. It is all in Java, using
+"httpunit" (http://httpunit.sourceforge.net/). The
+jars in the jars directory need to be in your classpath
+for compiling and running (it may require others as
+well depending on your JVM, but if you're a Java coder
+you know about all that). Apache's "ant" tool is used
+for building.
+
+I'm personally using generic Sun JDK 1.4 for Linux.
+
+--Lee Daniel Crocker <lee@piclab.com>
+March 4, 2003
+
diff --git a/testsuite/build.xml b/testsuite/build.xml
new file mode 100644 (file)
index 0000000..a2642a3
--- /dev/null
@@ -0,0 +1,27 @@
+<project name="TestSuite" default="compile" basedir=".">
+  <description>Test suite for Wikipedia phase III software</description>
+
+  <property name="src" location="src"/>
+  <property name="build" location="build"/>
+  <property name="dist" location="dist"/>
+
+  <target name="init">
+    <tstamp/>
+    <mkdir dir="${build}"/>
+  </target>
+
+  <target name="compile" depends="init" description="compile the source">
+    <javac srcdir="${src}" destdir="${build}"/>
+  </target>
+
+  <target name="dist" depends="compile" description="generate the jar file" >
+    <mkdir dir="${dist}/lib"/>
+    <jar jarfile="${dist}/lib/TestSuite-${DSTAMP}.jar" basedir="${build}"/>
+  </target>
+
+  <target name="clean" description="clean up">
+    <delete dir="${build}"/>
+    <delete dir="${dist}"/>
+  </target>
+
+</project>
diff --git a/testsuite/data/Agriculture.txt b/testsuite/data/Agriculture.txt
new file mode 100644 (file)
index 0000000..7ae48ff
--- /dev/null
@@ -0,0 +1,49 @@
+'''Agriculture''' is the process of producing [[food]] by cultivation of certain [[plant]]s and the raising of domesticated [[animal]]s.  Agriculture is also known as '''farming'''.   It includes both subsistence agriculture, which is producing enough food to meet the needs of the [[farmer]] and family, but no more) and also (almost universally in the "developed" nations and increasingly so in other areas) the production of financial income from cultivation of the land or commercial raising of animals ([[animal husbandry]]). Agriculture is the ''practice'' -- the ''study'' of these disciplines is called [[Agricultural Science|agricultural science]].
+
+Increasingly, besides food for humans and animal feeds, agriculture produces goods such as cut flowers, ornamental and nursery plants, [[fertilizer]]s, [[animal hides]], [[leather]], industrial chemicals ([[starch]], [[ethanol]], and [[plastic]]s), [[fiber]]s ([[cotton]], [[wool]], [[cannabis|hemp]], and [[flax]]), and fuels (ethanol, methane). Electricity can be generated from [[methane]] gas of animal waste.
+
+In the Western world, greater use of advanced techniques, complex, expensive machinery, and both conventional breeding and genetic engineering has greatly increased yields, releasing most of the populace from intense agricultural labor. The developing world is behind by Western measures of productivity, because of geographic distance, climates and soils commonly viewed as unsuitable (but see [[arid-zone agriculture]]), and lack of [[capital]]. 
+
+Animal husbandry means raising animals for [[slaughter]] or to harvest animal products on a continual basis.  Common farm animals or animal products include [[cattle]], [[dairy product]]s, [[chicken]], [[egg]]s, [[turkey]]s, [[emu]]s, [[horse]]s, [[rabbit]]s, [[sheep]], [[goat]]s, [[pig]]s, [[honey]], and [[silkworm]]s ([[sericulture]]). Fish, shrimp, and algae can also be farmed ([[aquaculture]]).
+
+In recent years, industrial agriculture has been the subject of increasing discussion. Patenting of seeds, the leaching of [[nitrogen]] and pesticides into the ground water and runoff, pesticide use, soil [[erosion]], habitat destruction, genetic manipulation of crops and animals, and concerns about animal welfare have raised public awareness of alternative farming methods such as [[organic farming]].
+
+=== History ===
+Farming is known to have taken place for at least 10,000 years.  Its introduction is often used to distinguish the [[neolithic]] period from earlier parts of the [[stone age]].  The first crops that humans domesticated included [[wheat]] and [[barley]].  The history of farming is obscure because it pre-dates writing, but it is clear that farming was invented at least twice, probably more often: once in the [[Fertile Crescent]], once in [[Mesoamerica|Central America]], and probably once in east Asia. Most likely, there was a gradual transition from a hunter-gatherer economy to an agricultural one, via a lengthy period when some crops were deliberately planted, and other foods were gathered from the wild.  The reasons for the earliest introduction of farming may have included [[climate]] change.  Farming allows a much greater density of population than can be supported by hunting and gathering.
+
+=== Methods ===
+==== [[Tillage]] by [[Plough]] ====
+==== [[Irrigation]] ====
+==== Fertilizers ====
+==== [[Crop rotation]] ====
+==== Weed removal ====
+==== Breeding ====
+==== [[Fence|Fencing]]
+=== Domesticated plants ===
+Domestication of plants is made in order to increase yield and improve the taste and nutritional value. In recent times, [[genetic engineering]] has begun to be employed to enhance certain aspects of the natural plants.
+* <b>[[Wheat]]</b> (aka ''corn''). Has a very long history of domestication, and is thought to be one of the first plants used for farming...
+* <b>[[Rice]]</b>. The chief crop in eastern [[Asia]], and an important foodstuff around the world.
+* <b>[[Maize]]</b> (aka ''corn''). Old domesticated plant, found in countless variations throughout the [[Americas]].
+* <b>[[Potato]]</b>
+* '''[[Yam]]'''
+* '''[[Barley]]'''
+* '''[[Oats]]'''
+* <b>[[Soybean]]</b>
+* <b>[[Lentil]]s</b>
+* <b>[[Apple]]</b>.
+
+<I>Perhaps this section and [[Vegetable farming]] ought to be merged?</i>
+
+=== Domesticated animals ===
+
+=== Environmental effects ===
+[[Nitrogen]] surplus in [[river]]s and [[lake]]s...
+
+Detrimental effects of [[herbicide]]s, [[fungicide]]s, [[pesticide]]s and [[biocide]]s...
+
+Conversion of [[wetland]]s into arable land...
+
+[[Erosion]]
+
+See also [[agricultural science]], [[Agricultural sciences basic topics]], [[aquaculture]], and [[mariculture]], [[Timeline of agriculture and food technology]].
+
diff --git a/testsuite/data/Anthropology.txt b/testsuite/data/Anthropology.txt
new file mode 100644 (file)
index 0000000..4c58c8f
--- /dev/null
@@ -0,0 +1,36 @@
+[[eo:Antropologio]][[nl:Antropologie]][[pl:Antropologia]][[fr:Anthropologie]]
+
+'''Anthropology''' is the study of humankind (see genus [[Hominoid|Homo]]).  It is holistic in two senses: it is concerned with all humans, and with all dimensions of humanity.  Central to modern anthropology is the notion that human nature is "culture"; in other words, that our species has evolved a universal capacity to conceive of the world symbolically, to teach and learn such symbols socially, and to transform the world (and ourselves) based on such symbols.  It is traditionally divided into four fields: [[physical anthropology]], which studies primate behavior, human evolution, and population genetics; [[linguistics]], which studies variation in language across time and space, the social uses of language, and the relationship between language and culture; [[archaeology]], which studies the material remains of human societies; and [[cultural anthropology]], also called socio-cultural anthropology, which studies social behavior and beliefs (among phenomena studied by cultural anthropologists are kinship patterns, social networks, family interactions, language development and exchange, cultural migration, and yes, [[cannibalism]] (which we mention only because we have an article on the subject; please help complete this list)...)
+
+== Anthropology in the Broader Context ==
+
+One anthropologist characterized anthropology as the most scientific of the humanities, and the most humanistic of the social sciences.  In order to see how anthropology does and does not fit into other academic disciplines, one must see how these disciplines developed.
+
+Anthropology is one Western response to one of the greatest paradoxes of modernity: as the world is becoming smaller and more integrated, people's experience of the world is increasingly atomized and dispersed.  As one social theorist has observed, 
+
+:All old-established national industries have been destroyed or are daily being destroyed.  They are dislodged by new industries, whose introduction becomes a life and death question for all civilized nations, by industries that no longer work up indigenous raw material but raw material drawn from the remotest zones; industries whose products are consumed, not only at home, but in every quarter of the globe.  In place of the old wants, satisfied by the production of the country, we find new wants, requiring for their satisfaction the products of distant lands and climes.  In place of the old local and national seclusion and self-sufficiency, we have intercourse in every direction, universal interdependence of nations.
+
+Ironically, this universal interdependence, rather than leading to greater human solidarity, has coincided with increasing racial, ethnic, religious, and class divisions, and new &mdash; and to some confusing or disturbing &mdash; forms of sexuality and notions of gender.  These are the conditions of life with which people today must contend, but they have their origins in processes that began in the 16th century and accelerated in the 19th century.  
+
+In the 19th century numerous scholars grappled with these issues.  The "[[humanities]]" reflected an attempt to consolidate and celebrate different national traditions, in the form of history and the arts, as an attempt to provide people in emerging nation-states with a sense of coherence.  The "[[social sciences]]" emerged at this time as an attempt to develop scientific methods to address social phenomena, in an attempt to provide a universal basis for social knowledge.  
+
+Some scholars gave a name to the dimension of human action in which these problems are most evident, and the concept through which they could be solved: society.  The new discipline of [[sociology]] would study the ties that bind people not only as individuals, but as members of associations, groups, and institutions.  Through such studies sociologists could develop "the antidote to social disintegration."
+
+Nevertheless, this new discipline, in the very process of distinguishing "society" from "the individual", "the state" and "the market", and by placing itself among complementary social sciences such as [[psychology]], [[political science]], and [[economics]] represented in intellectual form the very social divisions it sought to understand and heal.  Moreover, the most obvious sites for the study of modernity, and the most convenient sites for the application of new scientific, quantitative research methods, was in the sociologists' own societies, at the core of the emerging world system.  Consequently, they neglected the study of those societies on or beyond modernity's frontiers.
+
+At the same time that social scientists were defining this new object and method of study, however, a diverse group of scholars &mdash; with training in jurisprudence, psychology, geography, physics, mathematics, and other disciplines, and drawing on the methods of the natural sciences as well as developing new techniques involving not only structured interviews but unstructured "participant-observation" &mdash; dedicated themselves precisely to the study of those people on Europe's colonial frontiers.  Drawing on the new theory of evolution through natural selection, they proposed the scientific study of a new object: "humankind", conceived of as a whole.  Crucial to this study is the concept "culture", which anthropologists defined both as a universal capacity and propensity for social learning, thinking, and acting (which they see as a product of human evolution and something that distinguishes Homo sapiens &mdash; and perhaps all species of genus [[Hominoid|Homo]] &mdash; from other species), and as a particular adaptation to local conditions that takes the form of highly variable beliefs and practices.  Thus, "culture" not only transcends the opposition between nature and nurture; it transcends and absorbs the peculiarly European distinction between politics, religion, kinship, and the economy as autonomous domains.  They consequently organized a new discipline, anthropology, that would transcend the divisions between the natural sciences, social sciences, and humanities to explore the biological, linguistic, material, and symbolic dimensions of humankind in all forms.  
+
+== Anthropological concepts ==
+
+*[[Colonialism]]
+*[[Cultural exchange]]
+*[[Culture]]
+*[[Ethnicity]]
+*[[Gender]]
+*[[Kinship and descent]]
+*[[Marriage]]
+*[[Political system]]s
+*[[Race]]
+*[[Religion]]
+*[[Subsistence]]
+
diff --git a/testsuite/data/Archaeology.txt b/testsuite/data/Archaeology.txt
new file mode 100644 (file)
index 0000000..5ddc993
--- /dev/null
@@ -0,0 +1,104 @@
+[[de:Archäologie]][[fr:Archéologie]][[nl:Archeologie]][[pl:Archeologia]]
+'''Archaeology''' (or ''Archeology'') is the study of human activity, primarily through the study of its material remains. Since most human activity is in the past, and most past human activity occurred before any written record, archaeology is the most important method for the study of human pre-history. Moreover, since the historical (i.e. written) record is incomplete, archaeology provides a vital contribution to the study of human [[history]]. Finally, '''ethnoarcheologists''' contribute to the study of contemporary societies. 
+
+The material remains of human activity often have aesthetic, political, and monetary value.  Consequently, many people identify archaeology with the collection of political or economic treasures. This is promulgated, for example, in popular movies dealing with the exploits of fictional archaeologists e.g. [[Indiana Jones]] or the archaeologists in the recent film [[The Mummy]].
+
+Much of the history of archaeology, however, has been motivated by an attempt to distance itself from pseudo-archeologists and dilettantes, and to establish itself as a science.  In the United States, archaeology is one of four fields of [[anthropology]], the scientific study of humanity as a whole.  A primary goal of these archaeologists is to reconstruct [[culture|cultural]] systems, by studying their material remains in their material context (or "matrix").  Much archaeological theory has been motivated by the attempt to derive models of [[culture | cultural]] systems, processes, and changes based on material remains.  Some schools of archaeology (e.g. processualism) tend to describe the underlying systems, trying to find common ground between cultures; other schools (post-processualism) either believe this impossible or fraught with difficulty, and so examine archaeology in a certain cultural context.
+
+Archaeology has been and remains a cultural, gender and political battlefield.  Many groups have tried to use archaeology to prove some current cultural or political point.  [[Marxism|Marxist]] archaeologists in the USSR often tried to prove the truth of [[historical dialecticalism]].  Some cultural groups have tried, with varying degrees of success, to use archaeology to prove their ancient ownership of an area of land. Many schools of archaeology have been patriarchal, assuming that in prehistory men produced most of the food by hunting, and women produced little nutrition by gathering; more recent studies have exposed the inadequacy of many of these theories.  Some used The Great Ages theory to argue continuous upwards progress by Western civilization.
+
+Given these caveats, there is still a tremendous emphasis in the practice of archaeology on field techniques and methodologies.  These include the tasks of surveying areas in order to find new sites, and digging sites in order to unearth the cultural remains therein, and classification and preservation techiques in order to analyse and keep these remains.  Information can be derived throughout this process.  
+
+Archaeology subdisciplines:
+*[[Archaeometry]] - application of scientific methods to archaeology
+*[[Computational archaeology]] - application of computers, particularly GIS, to archaeology
+*[[Industrial archaeology]]
+*[[Lithics]] - analysis of stone tools
+*[[Museum studies]]
+*[[Maritime archaeology]] 
+*[[Archaeoastronomy]]
+*[[Zooarchaeology]] - the analysis of animal remains
+
+Schools of Theoretical Archaeology:
+
+*[[Great ages archaeology]]
+*[[Functionalism]]
+*[[Processualism]] - a theory of systems as opposed to cultures
+*[[Post processualism]]
+*[[Cognitive archaeology]] 
+*[[Gender/Feminist archaeology]]
+
+Regions within Archaeology:
+
+*[[Prehistoric archaeology]]
+*[[North American archaeology]]
+*[[Australian archaeology]]
+*[[Middle-Eastern archaeology]]
+*[[European archaeology]]
+*[[Classical archaeology]]
+*[[Medieval archaeology]]
+*[[Modern archaeology]]
+*[[Mesoamerican archaeology]]
+
+A brief history of archaeology and archaeological discoveries:
+
+Famous archaeological discoveries (listed):
+
+*[[Boxgrove man]]
+*[[Dead Sea scrolls]]
+*[[Gold mask of Tutakhamen]]
+*[[Linear B]]
+*[[Rosetta Stone]]
+*[[Similaun]]
+*[[Taung child]]
+*[[Terracotta Army]]
+*[[Tollund man]]
+
+Famous archaeological site (listed):
+
+*[[Abydos]]
+*[[Aphrodisias]]
+*[[Armana]]
+*[[Babylon]]
+*[[Easter Island]]
+*[[Fishbourne]]
+*[[Knossos]]
+*[[Machu Picchu]]
+*[[Novgorod]]
+*[[Pompeii]]
+*[[Pylos]]
+*[[Pyramids of Giza]]
+*[[Ur]]
+
+Famous archaeologists:
+
+*[[Gustaf VI Adolf]]
+*[[Lewis Binford]]
+*[[Howard Carter]]
+*[[James Deetz]]
+*[[Arthur Evans|Sir Arthur Evans]]
+*[[William Flinders Petrie]]
+*[[Kathleen Kenyon]]
+*[[Louis Leakey]]
+*[[Pitt Rivers]] (Augustus Lane-Fox)
+*[[Colin Renfrew]]
+*[[Heinrich Schliemann]]
+*[[Chris Tilley]]
+*[[Mortimer Wheeler]]
+*[[Leonard Woolley]]
+*[[Thor Heyerdahl]]
+
+Techniques used in archaeology:
+
+* [[Dendrochronology]]
+* [[Decipherment]]
+* [[Excavation]]
+* [[Geophysical survey]]
+* [[Radiocarbon dating]]
+* [[Reconstruction archaeology]]
+* [[Side scan sonar]]
+
+Ongoing Digs:
+
+*[[Ashkelon]] Ancient [[Canaan|Canaanite]] and [[Philistines|Philistine]] city in [[Israel]].
+
diff --git a/testsuite/data/Architecture.txt b/testsuite/data/Architecture.txt
new file mode 100644 (file)
index 0000000..c8a35b2
--- /dev/null
@@ -0,0 +1,21 @@
+[[nl:Architectuur]][[fr:Architecture]]
+'''Architecture''' is the [[art]] or [[science]] of [[design |designing]] the built environment; including cities, buildings, interiors, landscape, furniture, objects, etc. According to the earliest surviving work on the subject, [[Vitruvius | Vitruvius']] "On Architecture", it is said to rest on three principles: Beauty (''Venustas''), Firmness (''Firmitas'') and Utility (''Utilitas''); architecture can be said to be a balance between these three elements, with no one overpowering the others. 
+
+In [[Vitruvius | Vitruvius']] own words: 
+
+:"Architecture is a science, arising out of many other sciences, and adorned with much and varied learning; by the help of which a judgment is formed of those works which are the result of other arts. Practice and theory are its parents. Practice is the frequent and continued contemplation of the mode of executing any given work, or of the mere operation of the hands, for the conversion of the material in the best and readiest way. Theory is the result of that reasoning which demonstrates and explains that the material wrought has been so converted as to answer the end proposed.  Wherefore the mere practical architect is not able to assign sufficient reasons for the forms he adopts; and the theoretic architect also fails, grasping the shadow instead of the substance. He who is theoretic as well as practical, is therefore doubly armed; able not only to prove the propriety of his design, but equally so to carry it into execution."
+
+The word ''architecture'' is also used for the design or act of designing other complex systems. For example [[computer architecture]], [[software architecture]], [[information architecture]]. In this case, it tends to refer to the overall structure of the system.
+
+Architecture in general spans a great many ideas and places, including the act of designing and building simple carpentry pieces for a home, to residential housing to large-scale projects such as hospitals, airports, cities, regions, etc.  Because of the wide ranging nature of architecture there are many ways to look at it. A simple way would be to break it into segments that can be then cross-referenced.  The list below moves from the individual to the holistic in approach. 
+
+=== [[Architect |Architects]] ===
+
+=== [[Forms in Architecture]] ===
+
+=== [[Periods of Architecture]] ===
+
+External links:
+* [http://www.ukans.edu/history/index/europe/ancient_rome/E/Roman/Texts/Vitruvius/home.html Vitruvius' "Ten Books of Architecture" online]
+
+
diff --git a/testsuite/data/Astronomy_and_astrophysics.txt b/testsuite/data/Astronomy_and_astrophysics.txt
new file mode 100644 (file)
index 0000000..0f1bcef
--- /dev/null
@@ -0,0 +1,151 @@
+[[de:Astronomie]][[eo:Astronomio kaj Astrofiziko]][[fr:Astronomie]][[nl:Astronomie en Astrofysica]][[pl:Astronomia]][[pt:Astronomia e Astrofísica]]
+'''Astronomy''', which etymologically means ''laws of the [[star|stars]]'', is the science whose subject is the observation and explanation of events outside the earth. '''Astrophysics'''
+was born as the application of physics to the phenomena observed
+by astronomy, this was only possible once it was understood that the elements that made up the "celestial objects" were the same that made up the [[Earth]], and that the same [[laws of physics]] applied. Nearly all astronomers now have a strong background in physics, and the results of observations are always put in an astrophysical context, so the distinction between astronomy and astrophysics almost doesn't exist anymore.
+
+In the early part of its history, astronomy involved only the
+observation and predictions of the motions of the objects in the sky that could be seen with the naked eye. 
+Greeks made some important contributions to astronomy, but
+the progress almost stopped during the middle ages, except for
+the work of some Arabic astronomers. The renaissance came to
+astronomy with the work of [[Copernicus]], who proposed a
+heliocentric system. His work was defended, expanded and corrected by the likes of [[Galileo Galilei]] and [[Kepler]]. The latter of these was the first to provide a system which described correctly the details of the motion of the planets with the Sun at the centre. He didn't understand the reasons behind the laws he wrote down, however, and it was left to Newton's invention of [[celestial dynamics]] and his [[law of gravitation]],
+the final explanation of the motions of the planets. Stars were
+found much later to be far away objects, and with the advent of
+spectroscopy it was proved that they were similar to our own sun,
+but with a range of temperatures, masses and sizes. The existence
+of our Galaxy, the Milky Way, as a separate group of stars was only proven in the 20th century, along with the existence of
+"external" galaxies, and soon after, the expansion of the universe seen in the recession of most galaxies from us.
+Cosmology, a discipline that has a large intersection with
+astronomy, made huge advances during the 20th century, 
+with the model of the hot [[big bang]] heavily supported by the
+evidence provided by astronomy and physics, such as the [[cosmic microwave background radiation]] ,[[Hubble's Law]] and 
+[[big bang nucleosynthesis|cosmological abundances of elements]].
+
+For a more detailed history of astronomy, see the [[history of astronomy]].
+
+== Division by way of obtaining information ==
+
+Given its huge scope, astronomy is divided into different branches.
+The divisions are not unique, however, and the intersections, as
+well as astronomers who work in several areas, are the rule more 
+than the exception.
+
+In astronomy, the main way of obtaining information is through
+the detection and analysis of [[electromagnetic radiation]].
+A traditional division of astronomy is given by the region of
+the [[electromagnetic spectrum]] observed:
+
+*[[Optical astronomy]] refers to the techniques used to detect and analyze light in and slightly around the [[wavelength]]s than can be detected with the [[eye]]s (about 400 - 800 nm).  The most common tool is the [[telescope]].
+*[[Infrared astronomy]] deals with using infrared radiation (wavelengths longer than the red light).  Again, the most common tool is the [[telescope]], but optimized for use at longer wavelengths.  Space telescopes are also used to eliminate noise ( electromagnetic interference) from the atmosphere.
+*[[Radio astronomy]] uses completely different instruments to detect radiation of wavelengths of mm to cm. The receivers are similar to those used in radio broadcast transmission (which uses those wavelengths of radiation).  See also [[Radio telescope]]s.
+*[[High-energy astronomy]]
+
+Optical and radio astronomy can be done using ground-based observatories, because the [[atmosphere]] is transparent at those wavelengths. Infrared light is heavily absorbed by
+[[water vapor]], so infrared observatories have to be located in high, dry places or in space.
+
+The [[atmosphere]] is opaque at the wavelengths used by [[X-ray astronomy]], [[gamma-ray astronomy]], [[UV astronomy]] and, except for a few wavelength "windows", [[Far infrared astronomy]] , and so observations
+can be carried out only from balloons or [[space observatory|space observatories]].
+
+All the previous disciplines are based on the detection of [[photon|photons]], but we also receive information from outside the earth carried by [[cosmic rays]], [[neutrino|neutrinos]], and, in the near future, [[gravitational wave|gravitational waves]] (see [[LIGO]] and [[LISA]]).
+
+== Division by subject ==
+
+Astronomers study many objects including [[planet|planets]], [[star|stars]], [[nova|novae]], [[star cluster|star clusters]], [[galaxy|galaxies]], [[nebula|nebulae]], etc. but not every astronomer observes every kind of object.  A different division can be made using the regions of space and problems addressed; among them
+
+*[[Galactic astronomy]]
+*[[Extragalactic astronomy]]
+*[[Galaxy formation and evolution]]
+*[[Star formation]]
+*[[Stellar evolution]]
+*[[Stellar astronomy]]
+*[[Astrometry]]
+
+The study of the [[planet|planets]] of the [[solar system]] is (in recent times)
+sometimes considered a different discipline, called [[Planetary Sciences]] or Planetology
+
+Also, there are other disciplines that may be considered part
+of astronomy, or are interdisciplinary sciences with astronomy
+one of the disciplines:
+
+*[[Archeoastronomy]]
+*[[Astrobiology]]
+*[[Astrochemistry]]
+*[[Planetary sciences]]
+*[[Cosmology]]
+
+Astronomy is one of the few sciences where amateurs still play 
+an active role.
+
+If your favorite area of research is not mentioned, feel free to
+add it.
+
+== Organizations ==
+
+*[[International Astronomical Union]]
+*[[American Astronomical Society]]
+*[[National Optical Astronomy Observatories]]
+*[[European Southern Observatory]]
+*[http://www.rasc.ca Royal Astronomical Society of Canada]
+*[http://www.ras.org.uk Royal Astronomical Society (UK)]
+
+== Amateur astronomy ==
+
+Amateur astronomy is one of the oldest and most popular of hobbies. From the occasional stargazer to the most hardened deep sky object hunter, thousands of amateurs are involved in this branch of astronomy. Some topics in amateur astronomy include:
+*[[Amateur astronomy]]
+*[[Deep sky objects]]
+*[[Telescope]]s
+*[[Telescope making]]
+*[[Observing]]
+
+''This section is still in its infancy, please add articles''
+
+----
+
+See also [[Astronomer|Astronomers and Astrophysicists]], [[Amateur Astronomy]], [[History of astronomy]].
+
+== Basic Concepts ==
+
+*[[astronomical distances]]
+*[[celestial sphere]]
+*[[right ascension]]
+*[[precession]]
+*[[obliquity of the ecliptic]]
+*[[orbit]]
+**retrograde orbit
+**prograde orbit
+*[[rotation]]
+*[[phases]]
+*[[eclipse]]
+*[[Lagrangian Point|Lagrangian points]]
+*[[solar system]]
+*[[apparent magnitude]]
+*[[absolute magnitude]]
+*[[orbital revolution]]
+*[[H-R diagram]]
+*[[Stellar classification]]
+*[[planetary nomenclature]]
+
+See also:
+* [[space science]]...
+* [[Timeline of black hole physics]]
+* [[Timeline of cosmology]]
+* [[Timeline of cosmic microwave background astronomy]]
+* [[Timeline of other background radiation fields]]
+* [[Timeline of galaxies, clusters of galaxies, and large scale structure]]
+* [[Timeline of the interstellar medium and intergalactic medium]]
+* [[Timeline of white dwarfs, neutron stars, and supernovae]]
+* [[Timeline of stellar astronomy]]
+* [[Timeline of solar astronomy]]
+* [[Timeline of solar system astronomy]]
+* [[Timeline of astronomical maps, catalogs, and surveys]]
+* [[Timeline of telescopes, observatories, and observing technology]]
+* [[Timeline of artificial satellites and space probes]]
+
+----
+
+External links:
+* [http://www.ency-astro.com/ Encyclopedia of Astronomy and Astrophysics] 
+* [http://xxx.lanl.gov Los Alamos Astrophysics e-Print Database]
+* [http://antwrp.gsfc.nasa.gov/apod/ Astronomy Picture of the Day]
+
diff --git a/testsuite/data/Biology.txt b/testsuite/data/Biology.txt
new file mode 100644 (file)
index 0000000..9c6572c
--- /dev/null
@@ -0,0 +1,42 @@
+[[dk:Biologi]][[de:Biologie]][[eo:Biologio]][[fr:Biologie]][[nl:Biologie]][[pl:Biologia]][[pt:Biologia]]
+
+Testing...
+
+'''Biology''' is the study of [[life]] and its processes. The term biology was coined in the late [[1700s]] by the French naturalist Pierre-Antoine de Monet, Jean-Baptiste de [[Lamarck]].
+
+[[Biologist]]s study general principles of how living things work in [[biochemistry]], [[genetics]], and [[physiology]]. They investigate [[organism]]s' [[morphology]], [[anatomy]], [[behavior]], and [[ontogeny]] to learn about function and identity. To find out how organisms interact among each other and with the [[environment]], biologists investigate their [[ecology]]. At the [[microscopy|microscopic]] level, biologists study their [[cell biology]].
+
+One of the central concepts in biology is the principle of [[evolution]]. The evolutionary history of an organism, i.e., the sequence of ancestral [[species]], is called its [[phylogeny]]; it is studied using methods of [[molecular biology]] by analyzing biopolymer sequences of [[gene]]s and [[protein]]s, and by investigating ancient forms of life in [[paleontology]]. Various methodologies have been developed, including [[phylogenetics]], [[phenetics]], and [[cladistics]]. An [[evolutionary timeline]] outlining the major events in the evolution of life on Earth is available.
+
+The classification of living things is called [[systematics]], or [[taxonomy]], and should reflect the evolutionary trees ([[phylogenetic tree]]s) of the different organisms.  Taxonomy piles up organisms in groups called [[taxa]], while systematics seeks their relationships. The dominant system is called [[Linnaean taxonomy]], which includes ranks and [[binomial nomenclature]]. How organisms are named is governed by international agreements such as the [[International Code of Botanical Nomenclature]] (ICBN), the [[International Code of Zoological Nomenclature]] (ICZN), and the [[International Code of Nomenclature of Bacteria]] (ICNB). A fourth Draft BioCode was published in 1997 in an attempt to standardize naming in the three areas, but it does not appear to have yet been formally adopted.  A text of the draft may be found athttp://www.rom.on.ca/biodiversity/biocode/biocode1997.html  The [[International Code of Virus Classification and Nomenclature]] (ICVCN) remains outside the BioCode.
+
+Typically, living things were divided into five kingdoms:
+
+:[[Monera]] -- [[Protista]] -- [[Fungi]] -- [[Plantae]] -- [[Animalia]] 
+
+However, this five-kingdom system is now considered by many to be outdated, and if one does not want to hyperinflate the number of kingdoms, one can use the [[three domain system]]. These domains reflect whether cells have nuclei or not, and differences in cell membranes / cell walls.
+
+:[[Archaea]] -- [[Eubacteria]] -- [[Eukaryota]]
+
+The distinction between life and non-life is difficult, there is also a series of intracellular "[[parasites]]" that are progressively less alive in terms of being [[metabolism|metabolically]] active:
+
+:[[virus (biology)|viruses]] -- [[Viroid]]s -- [[Prion]]s
+
+== Major Branches of Biology ==
+
+:[[Aerobiology]] -- [[Anatomy]] -- [[Anthropology]] -- [[Astrobiology]] -- [[Biochemistry]] -- [[Bionics]] -- [[Biogeography]] -- [[Biophysics]]-- [[Biotechnology]] -- [[Botany]] -- [[Cell biology]] -- [[Chorology]] -- [[Cladistics]] -- [[Cytology]] -- [[Developmental biology]] -- [[Ecology]] ([[Symbiology]], [[Autecology]])-- [[Ethology]] -- [[Evolution]] (Evolutionary biology) --[[Evo-devo]] (Evolution of Development)-- [[Genetics]] ([[Genomics]], [[Proteomics]]) -- [[Histology]] -- [[Immunology]] -- [[Infectious disease]] ([[Pathology]], [[Epidemiology]])-- [[Limnology]] -- [[Marine biology]] -- [[Microbiology]] ([[Bacteriology]]) -- [[Molecular Biology]] -- [[Mycology]] / [[Lichenology]] -- [[Neuroscience]] -- [[Oncology]] (the study of cancer) -- [[Ontogeny]] -- [[Paleontology]] ([[Palaeobotany]], [[Palaezoology]])-- [[Phycology]] (Algology) -- [[Phylogeny]] ([[Phylogenetics]], [[Phylogeography]]) -- [[Physiology]] -- [[Phytopathology]] -- [[Structural biology]] -- [[Taxonomy]] -- [[Toxicology]] (the study of poisons and [[pollution]]) -- [[Virology]] -- [[Zoology]]; related: [[medicine]]
+
+== People and History ==
+
+:[[List_of_biologists|Famous biologists]] -- [[History of biology]] -- [[Nobel_Prize/Physiology_or_medicine|Nobel prize in physiology or medicine]] -- [[Timeline of biology and organic chemistry]]
+
+What are our priorities for writing in this area?  To help develop a list of the most basic topics in Biology, please see [[Biology basic topics]].
+
+== Resources ==
+
+* David R. Maddison: ''The Tree of Life'', http://phylogeny.arizona.edu/. A multi-authored, distributed Internet project containing information about phylogeny and biodiversity.
+* Lynn Margulis: ''Five Kingdoms: An Illustrated Guide to the Phyla of Life on Earth, 3rd ed.'', W H Freeman &amp; Co 1998. 
+* Neil Campbell: ''Biology: Concepts and Connections, 3rd ed.'', Benjamin/Cummings 2000. A college-level textbook.
+* John W. Kimball: ''Kimball's Biology Pages'', http://www.ultranet.com/~jkimball/BiologyPages/. A searchable online textbook.
+* Charles Darwin: ''The Origin of Species''
+
diff --git a/testsuite/data/Blocklevels.txt b/testsuite/data/Blocklevels.txt
new file mode 100644 (file)
index 0000000..bc2fb03
--- /dev/null
@@ -0,0 +1,107 @@
+
+Wikipedia block-level elements test:
+
+(1)
+
+* List item 1
+* List item 2
+* List item 3
+
+(2)
+
+# Numbered item 1
+# Numbered item 2
+# Numbered item 3
+
+(3)
+
+* List item 1
+Paragraph
+
+(4)
+
+# Numbered item 1
+# Numbered item 2
+Paragraph
+
+(5)
+
+ Fixed-font paragraph
+ More fixed-font text
+
+(6)
+
+Paragraph
+# Numbered item 1
+
+(7)
+
+ Fixed-font paragraph
+* List item 1
+
+(8)
+
+* Level 1
+* Level 1
+** Level 2
+** Level 2
+*** Level 3
+** Level 2
+* Level 1
+** Level 2
+*** Level 3
+**** Level 4
+* Level 1
+
+(9)
+
+# Level 1
+# Level 1
+## Level 2
+## Level 2
+### Level 3
+## Level 2
+# Level 1
+## Level 2
+### Level 3
+#### Level 4
+# Level 1
+
+(10)
+
+* Level 1
+* Level 1
+*# Level 2
+*# Level 2
+*#* Level 3
+*# Level 2
+* Level 1
+*# Level 2
+*#* Level 3
+*#*# Level 4
+* Level 1
+
+(11)
+
+; Word : Definition
+
+(12)
+
+; Word
+: Definition
+
+(13)
+
+; Word
+:# First def
+:# Second def
+
+(14)
+
+:: Double indent
+
+(15)
+
+::: Triple indent
+Paragraph
+
diff --git a/testsuite/data/Bracketvars.txt b/testsuite/data/Bracketvars.txt
new file mode 100644 (file)
index 0000000..bcba54d
--- /dev/null
@@ -0,0 +1,17 @@
+
+Wikipedia bracket variables test:
+
+Month: {{CURRENTMONTH}}
+
+Month name: {{CURRENTMONTHNAME}}
+
+Day: {{CURRENTDAY}}
+                               
+Day name: {{CURRENTDAYNAME}}
+
+Year: {{CURRENTYEAR}}
+
+Time: {{CURRENTTIME}}
+
+Number of articles: {{NUMBEROFARTICLES}}
+
diff --git a/testsuite/data/Business_and_industry.txt b/testsuite/data/Business_and_industry.txt
new file mode 100644 (file)
index 0000000..7065ee4
--- /dev/null
@@ -0,0 +1,56 @@
+Business and Industry
+
+* [[Accounting]]
+
+* [[Banking]]
+* [[Business]]
+* [[Business Schools]]
+
+* [[Capitalism]]
+
+* [[Commerce]]
+* [[Companies]]
+* [[consumer electronics|Consumer electronics]]
+
+* [[Domestic organization]]
+
+* [[Education]]
+* [[Electronic commerce]]
+* [[Entrepreneur]]
+* [[Ethics]]
+
+* [[Finance and investment]]
+* [[Fundamental business concepts]]
+
+* [[Home economics]]
+* [[Finishing school|Home economics education]]
+* [[History]]
+
+* [[Industry]]
+* [[Insurance]]
+
+* [[Law]]
+** [[Copyright]]
+** [[Corporation]]
+** [[Intellectual property]]
+*** [[Trade secret]]
+** [[Patent|patents]] and [[Trademark|trademarks]]
+
+* [[Management science]]
+* [[Manufacturing]]
+* [[Marketing and advertising]]
+* [[media|Media]]
+
+* [[Network Marketing]]
+** [[Network_Marketing_Facts|Facts]] and [[Network_Marketing_Myths|Myths]]
+
+* [[Real Estate]]
+** [[Real_Estate_Agencies|Agencies]]
+* [[Retailer]]
+
+* [[tax|Taxation]]
+* [[Trade]]
+
+* [[Wholesaler]]
+
+See also: [[economics]]
diff --git a/testsuite/data/Card_game.txt b/testsuite/data/Card_game.txt
new file mode 100644 (file)
index 0000000..39a6d97
--- /dev/null
@@ -0,0 +1,70 @@
+The term '''card game''' refers to any [[game]] using [[playing card]]s, either traditional or specialized.  
+
+Other games using cards include [[trading card game]]s and [[combination games]] with use cards in addition to other playing equipment.  
+
+[[Trick-taking game]]s: 
+* [[500 Card Game|500]]
+* [[9-5-2]]
+* [[Bridge game|Bridge]]
+* [[Euchre]]
+* [[Hearts]]
+* [[Napoleon]]
+* [[Sheepshead]]
+* [[Skat]]
+* [[Spades]]
+* [[Tarocchi]]
+* [[Whist]]
+* [[Pinochle]]
+* [[Oh Hell]]
+* [[Tarock]] (played with a Tarot deck)
+
+[[Matching game]]s: (also referred to as the Rummy family)
+* [[Canasta]]
+* [[Gin Rummy| Gin (Gin Rummy)]]
+* [[500 Rum]]
+* [[Go Fish]]
+
+[[Gambling]] games:
+* [[Blackjack]]
+* [[Boure|Bour&eacute;]]
+* [[Panguingue]]
+* [[Poker]]
+* [[Red Dog]]
+* [[3 card brag]]
+
+[[Solitaire]] or Patience games: 
+* [[Klondike solitaire|Klondike]]
+* [[FreeCell]]
+(see a guide to [[Solitaire/Terminology]])
+
+Shedding games: (also referred to as the Stops family)
+* [[Uno]]
+* [[Macau]]
+* [[Mao (game)|Mao]]
+* [[Crazy Eights]]
+* [[Fan Tan]]
+* [[Michigan Rummy]]
+* [[President (game)|President]] (Asshole; The Great Dalmuti)
+* [[Old Maid]]
+* [[Shichi Narabe]]
+* [[Bullshit]] (aka Cheat / I Doubt It)
+
+Accumulating games:
+* [[Spit]]
+* [[War (card game)|War]]
+* [[Egyptian Ratscrew]]
+* [[Beggar-My-Neighbour]]
+
+Special decks: 
+* [[Grass card game|Grass]]
+* [[Mille Bournes]]
+* [[Set game]]
+* [[Karuta]]
+
+See also: [[Board game]]
+
+== External links ==
+
+*http://www.pagat.com has information about many different card games.
+*[http://www.funagain.com Funagain Games] includes short profiles of many proprietary games
+
diff --git a/testsuite/data/Chemistry.txt b/testsuite/data/Chemistry.txt
new file mode 100644 (file)
index 0000000..f40ae92
--- /dev/null
@@ -0,0 +1,28 @@
+[[de:Chemie]][[eo:Kemio]][[fr:Chimie]][[nl:Scheikunde]][[pl:Chemia]][[pt:Química]]
+'''Chemistry''' is the study of the basic [[atomic]] building-blocks of nature and how they combine to form the [[solid]]s, [[liquid]]s, and [[gas]]es that make up life and everything else we know.  For the many different [[chemical element]]s and compounds, see:
+
+* The [[Periodic table]]
+* [[Inorganic chemistry]], including [[solid state chemistry]], which studies the basic principles that are applied in  [[mineralogy]] and [[Materials Science]] 
+* [[Organic chemistry]], which underlies [[biochemistry]] and [[polymer]] chemistry
+* [[Physical chemistry]], which includes [[computational chemistry]], [[quantum chemistry]] and [[surface chemistry]]
+* [[Analytical chemistry]], the basis of [[environmental chemistry]]
+
+For some basic concepts see:
+
+* [[Orbitals]]
+* [[Kinetics]]
+* [[Thermochemistry]]
+* [[Electrochemistry]]
+* [[chemical bond|Chemical bonding]]
+* [[isomer|Isomerism]]
+
+History of Chemistry:
+*[[Alchemy]]
+*[[Discovery of the chemical elements]]
+
+[[International Union of Pure and Applied Chemistry]]
+
+[http://www.chem.qmw.ac.uk/iupac/ IUPAC Nomenclature Home Page]
+
+See also [[Chemistry basic topics]], [[Chemist]].
+
diff --git a/testsuite/data/Classics.txt b/testsuite/data/Classics.txt
new file mode 100644 (file)
index 0000000..5b5a46b
--- /dev/null
@@ -0,0 +1,20 @@
+[[nl:De klassieken]]
+In its classic sense, ''classics'' means the study of the language, literature, history, art, and other aspects of ancient Greece and Rome.
+
+*Ancient Greece
+::[[Greek language]]
+::[[Greek mythology]]
+::[[Greek literature]]
+::[[Greek architecture]]
+
+*Ancient Rome
+::[[Latin]]
+::[[Roman mythology]]
+::[[Latin literature]]
+::[[Rhetoric]]
+
+*Post-Classical Scholarship
+::[[Humanism]]
+::[[Philology]]
+
+Classics can also mean (typically in non-academic contexts) [[classic book]]s.
diff --git a/testsuite/data/Communication.txt b/testsuite/data/Communication.txt
new file mode 100644 (file)
index 0000000..25a1a28
--- /dev/null
@@ -0,0 +1,37 @@
+'''Communication'''  means the exchange of ideas with a [[community]], and as such can include both technical topics like [[telecommunication]] and societal issues like [[mass media]].  Several [[scientific journal]]s have this word in their title, for example [[Communications of the ACM]].
+----
+We can treat ''Communication'' like a language and a subject unto itself, or as the name of a field of study.
+
+"Communication" implies two different, and sometimes conflicting, things.
+On one hand, it means to have a thoughtful exchange of views with a small number of people, perhaps just one.  But it can also mean to disseminate broadly a simple message, without deep thought or appeals for feedback.  The Latin root is ''communicare'' and means "to make common". 
+
+''Communication'' as a field of study is relatively new.  Arguably, it encompasses [[journalism]], [[public relations]], [[media studies]] (which might include the study of [[television]], [[radio]], and [[film]]), and [[rhetoric]], among other fields.
+
+In a more technical sense, see also [[telegraphy]], [[telephone]], [[computer network]].
+
+We might divide these diverse fields into those which cultivate a thoughtful exchange between a small number of people (debate, talk radio, e-mail, personal letters) on the one hand; and those which disseminate broadly a simple message (public relations, television, Hollywood films.)
+
+Under communication one might also classify the [[postal system]].
+
+In [[virtual management]] an important issue is [[computer mediated communication]].
+----
+=== Overview ===
+*Definitions of communication
+*Overview of debate: what is and isn't communication?
+
+=== Communication Models ===
+*encoding, sending and receiving messages
+*symbols, language
+*verbal, nonverbal
+
+=== Communication Technology ===
+*general overview of changes and advances
+*effects of communication technology on culture and society
+*systems of communication
+* [[Timeline of communication technology]]
+* The [[United States]] [[Federal Communications Commission]]
+
+=== The Study of Communication ===
+*historical sketch
+*important people, theories
+
diff --git a/testsuite/data/Computer_Science.txt b/testsuite/data/Computer_Science.txt
new file mode 100644 (file)
index 0000000..051d94d
--- /dev/null
@@ -0,0 +1,63 @@
+[[ca:Informàtica]][[de:Informatik]][[eo:Komputiko]][[fr:Informatique]][[it:Informatica]][[nl:Informatica]][[no:Informatikk]][[pl:Informatyka]][[pt:Computação]]
+'''Computer science''' is the study of the design, use, and properties of [[computer|computers]].  See also [[computing]].
+
+Computer science is a relatively new field with roots in [[electrical engineering]], [[mathematics]] and [[linguistics]]. Only in the last third of the [[20th century]] has it begun to be recognized as a separate discipline and developed its own methods and terminology.
+
+See [[computer scientist]] for a list of famous computer scientists.
+
+Major subfields include
+
+* Mathematical foundations
+** [[Discrete mathematics]]
+** [[Symbolic logic]]
+
+* Theoretical computer science
+** [[Algorithmic information theory]]
+** [[computational complexity theory|Complexity theory]]
+** [[Computability theory]]
+** [[Information theory]]
+** [[Theory of computation]] (or ''theoretical computer science'')
+** [[Type theory]]
+
+* Algorithms
+** [[Algorithm|Algorithms]]
+** [[Compiler|Compilers]]
+** [[Lexical Analysis]]
+** [[microprogram|Microprogramming]]
+** [[Operating system|Operating systems]]
+
+* Applied computer science 
+** [[Artificial intelligence]]
+** [[Computer architecture]]
+** [[Computer graphics]]
+** [[Computer network|Computer networks]]
+** [[Computer security]]
+** [[Database|Databases]]
+** [[Distributed computing]]
+** [[Information retrieval]]
+** [[Programming language|Programming languages]]
+** [[Program specification]]
+** [[Program verification]]
+** [[Software engineering]]
+
+* Specific techniques
+** [[Benchmark]]
+** [[Computer vision]]
+** [[Data compression]]
+** [[Data structure|Data structures]]
+** [[Design pattern|Design patterns]]
+** [[Digital signal processing]]
+** [[File format|File formats]]
+** [[Human-computer interaction]]
+** [[Information security]]
+** [[Internet]]
+** [[Online computations and algorithms]]
+** [[Software optimization|Optimization]]
+** [[Very Large System Integration|VLSI design]]
+
+Related articles:
+* [[Turing Award]]
+* [[IEEE John von Neumann Medal]]
+* [[Computer jargon]]
+* [[jargon file|Computer slang]]
+
diff --git a/testsuite/data/Cooking.txt b/testsuite/data/Cooking.txt
new file mode 100644 (file)
index 0000000..0df997c
--- /dev/null
@@ -0,0 +1,47 @@
+[[eo:Kuireco]][[fr:Cuisine]][[nl:Kookkunst]][[pl:Kulinaria]]
+'''Cooking''' is the [[art]], [[science]], [[profession]], and [[hobby]] of preparing [[food]] for human consumption.  The term is often used in the narrower sense of applying heat to chemically transform a food to change its flavor, texture, appearance, or nutritional properties.
+Heating food has several uses.  
+It can sterilize the food (depending on temperature, cooking time, and technique used), in addition to softening the food by turning [[collagen]] into [[gelatin]]. 
+
+Because eating is a universal human drive, cooking is a nearly universal cultural feature. Specific techniques and ingredients are often regional. See [[Cuisine]] for information about the many regional and ethnic food traditions.  Please see [[food writing]] for some authors of books on cookery, food, and the history of food.  
+
+Some major cooking (in the sense of transforming raw food with heat) techniques:
+
+* [[Baking]]
+** [[High tech baking]]
+* [[Barbecuing]]
+* [[Boiling]]
+** [[Blanching]]
+* [[Braising]]
+* [[Broiling]]
+* [[Frying]]
+** [[Deep frying]]
+** [[Hot salt frying]]
+** [[Hot sand frying]]
+** [[Pan frying]]
+** [[Sauteeing]]
+** [[Stir frying]]
+* [[Grilling]]
+* [[Poaching (cooking)|Poaching]]
+* [[Pressure cooking]]
+* [[Roasting]]
+* [[Smoking (food)|Smoking]]
+* [[Steaming]]
+** [[Double steaming]]
+* [[Vacuum flask cooking]]
+
+Other preparation techniques:
+* [[Brining]]
+* [[Marination]]
+* [[Seasoning]]
+* [[Pickling]]
+* [[Microwaving]] (also known as &quot;nuking&quot;)
+
+Other information:
+
+* [[Food and cooking hygiene]]
+
+* [[Cooking weights and measures]] (includes conversions and equivalencies common in cooking)
+
+For recipes, see the [[Wikipedia Cookbook]].
+
diff --git a/testsuite/data/Critical_theory.txt b/testsuite/data/Critical_theory.txt
new file mode 100644 (file)
index 0000000..0662ee2
--- /dev/null
@@ -0,0 +1,10 @@
+'''Critical theory''' began as a label used by members of the Institute for Social Research of [[Frankfurt University]] to describe their own work. The Institute was founded in [[1923]] by [[Max Horkheimer]] and closed in [[1934]]; many of its members emigrated to New York City and helped found the New School for Social Research there. The original [[Frankfurt am Main|Frankfurt]] school re-opened in the [[1950s]] and its chief modern representative is probably [[Jurgen Habermas|J&uuml;rgen Habermas]].
+
+The Frankfurt school were dissident [[Marxism | Marxists]], severe critics of capitalism who believed that a narrow selection of [[Karl Marx | Marx's]] ideas were being parroted by those who claimed to follow his lead, usually in defense of the Communist Party. They took up the task of choosing what parts of Marx's thought might serve to clarify social conditions he had never seen. They drew on other schools of thought to fill in perceived omissions in Marx's. [[Max Weber]] was a principal influence, but [[Herbert Marcuse]], for example, sought to combine the views of [[Karl Marx | Marx]] and [[Freud]].
+
+The Frankfurt school was literally a school, a place where individuals taught and learned. There is no one method, ambition, or conclusion shared by all of them.  However, there is a broad emphasis on criticizing the ''culture'' of capitalism (and orthodox communism). The title of one book, Leo Lowenthal's ''Literature, Popular Culture, and Society'', suggests their interests. In [[Habermas]], the work focuses on the question of what cultural conditions are needed to make good intellectual work possible -- or, more pessimistically, how far economic interests and political dogma can corrupt science and philosophy.
+
+This general emphasis on culture as a product of economic systems has shaped literary historians, film critics, historians of science, and others. The search for useful ideas from other fields has also been imitated. Therefore, the term "critical theory" now is used loosely to group all sorts of work--[[Structuralism]], the anti-structuralist views known as [[Postmodernism]], and so on.  See [[Cultural movement]].
+
+See [[Walter Benjamin]], [[Theodor Adorno]], [[Herbert Marcuse]], [[Max Horkheimer]], [[Jurgen Habermas]], [[Max Weber]].
+
diff --git a/testsuite/data/Dance.txt b/testsuite/data/Dance.txt
new file mode 100644 (file)
index 0000000..37e8191
--- /dev/null
@@ -0,0 +1,17 @@
+[[de:Tanz]]
+Dance is a rhythmic movement of the human body to music.  There are an almost infinite number of dances, in hundreds of different cultures.
+
+Dance may be divided into two main categories.  One type is that performed mainly for the amusement of the dancer - a form of [[recreation]] and, often, an opportunity to get to meet and interact with potential partners.  In the present, many styles of recreational dancing are fairly loose and improvised.  However, many others are quite formalized and are [[ritual]]ized, such as [[folk dance]].
+
+The other form is that performed on stage for the entertainment of a non-participating audience - dance as [[theatre]].  Both styles of dance inform the other, and there is considerable overlap between the two.
+
+Some dance styles include:
+
+[[Ballroom Dance]] -- [[Belly Dance]] -- [[Classical Dance]] -- [[Country Dance]] -- [[Square Dance]] -- [[Swing Dance]] -- [[Jazz dance]] -- [[Modern dance]] -- [[Folk dance]] -- [[Ballet dance|Ballet]] -- [[Tap Dance]]
+
+Ethnic dance styles: [[Bharata Natyam]] (from India)
+
+Historical dance forms: [[Medieval dance]] -- [[Renaissance dance]] -- [[Baroque dance]] -- [[18th century dance]] -- [[Regency dance]] -- [[Vintage dance]]
+
+See also: [[Dance music]]
+
diff --git a/testsuite/data/Earth_science.txt b/testsuite/data/Earth_science.txt
new file mode 100644 (file)
index 0000000..5942ea1
--- /dev/null
@@ -0,0 +1,50 @@
+[[eo:Tersciencoj]][[nl:Aardwetenschappen]][[pl:Nauki o Ziemi]][[pt:Ciências da Terra]]
+'''Earth science''' is the the study of the [[Earth]] and its processes. This disipline includes [[geology]], [[geophysics]], [[meteorology]], [[physical geography]] (as opposed to [[human geography]]), [[mineralogy]], [[paleontology]] (also known as paleobiology), [[geodesy]] and other sciences.  [[Marine science]] and [[environmental science]] are highly interdisciplinary branches of earth sciences.
+Arguably, earth science can be regarded as a branch of [[planetary science]].
+
+=== List of the earth science topics === 
+
+* [[Astronomy]]
+* [[Atmosphere]]
+
+* [[Cretaceous extinction event]]
+* [[Dinosaur]]
+
+* [[Earthquake]]
+* [[Environmental geology]]
+
+* [[Fossil]]
+
+* [[Geomorphology]]
+* [[Geochemistry]]
+* [[Geologic event]]s
+* [[Geologic hazard]]s
+* [[Geologic time]]
+
+* [[Glaciation]]
+
+* [[Historical geology]]
+* [[Hutton]]
+
+* [[Impact event]]s
+
+* [[Meteorology]]
+* [[Mineral]]  
+* [[Mudslide]]
+
+* [[Oceanography]]
+
+* [[Plate tectonics]]
+* [[Physical geology]]
+* [[Petroleum geology]]
+
+* [[Rock|Rocks]]
+
+* [[Stratigraphy]]
+* [[Structural geology]]
+
+* [[Volcano]]
+
+* [[Wind erosion]]
+* [[Wind deposition]]
+
diff --git a/testsuite/data/Economics.txt b/testsuite/data/Economics.txt
new file mode 100644 (file)
index 0000000..59cc6b6
--- /dev/null
@@ -0,0 +1,59 @@
+[[fr:Économie]][[nl:Economie]][[pl:Ekonomia]][[pt:Economia]]
+'''Economics''' is a [[Social sciences|social science]] that studies society's allocation of [[scarcity|scarce]] resources to meet desires and wants. Economics therefore starts from the premise that resources are in limited supply and that it is necessary to choose between competing alternatives. With scarcity, choosing one alternative implies foregoing another alternative; economists refer to this as [[opportunity cost]].
+
+A further aspect is how incentives (the consequences of different courses of action) affect individual or group behavior. Economists tend to think that incentives and [[Utility|preferences]] (tastes) together play an important role in shaping decision making.
+
+Economics is ''positive'' when it attempts to explain the consequences of different choices and ''normative'' when it prescribes a certain route of action. Aspects receiving particular attention in economics are trade, resource allocation and competition.
+
+Unlike most social sciences, economics has widely adopted formal mathematical modelling.  This can involve advanced mathematical methods, but often only relatively straightforward algebra is used. Economists often believe that mathematical methods encourage researchers to focus on essentials and makes exposition less prone to ambiguity.  However, the basic ideas of economics can be taught with no more than simple arithmetic and graphs, without knowledge of the underlying formal mathematical theory. 
+
+=== Areas of study in economics ===
+Economics is usually divided into two main categories:
+*[[Microeconomics]], which deals with the behaviour and interaction of individual agents and firms.
+*[[Macroeconomics]], which examines an economy as a whole with a view to understanding the interaction between economic aggregates such as income, employment and inflation. 
+
+Attempts to join these two branches or to refute the distinction between them have been important motivators in much of recent economic thought, especially in the late 1970s and early 1980s. Today, the consensus view is arguably that good macroeconomics has solid microeconomic foundations. That is, its premises have support in microeconomics.
+
+Within these major divisions there are specialized areas of study that try to answer questions on a broad spectrum of human economic activity (see below). There are also methodologies used by economists whose underlying theories are important. The most significant example may be [[econometrics]], which is applies statistical techniques to the study of economic data. 
+
+There has been an increasing trend for ideas from economics to be applied in wider contexts.  There is an economic aspect to any field where people are faced with alternatives - education, marriage, public policy, etc.  [[Public Choice Theory]] studies how economic analysis can apply to those fields traditionally considered outside of economics. The areas of investigation in Economics therefore overlap with other social sciences, including [[political science]] and [[sociology]]. 
+
+=== Development of economic thought ===
+
+Modern economic thought is usually said to have begun with [[Adam Smith]] in the late 18th century. For an overview of precursors to Smith as well as an overview of schools that have developed later, see [[History of Economic Thought|history of economic thought]]. Modern mainstream economics is primarily a further refinment of [[neoclassical economics]]. 
+
+Macroeconomics began with [[John Maynard Keynes|Keynes]] in the 1930s. For an overview of a number of competing schools, see [[macroeconomics]]. 
+
+Many economists use a combination of Neoclassical microeconomics and Keynesian macroeconomics.  This combination, sometimes known as the ''Neoclassical synthesis'', was dominant in Western teaching and public policy in the years following [[World War II]] and up to the late 1970s.
+
+In priniciple, economics can be applied to any type of economic organization. However, it developed historically in [[market]] societies, and its most detailed and precise work has dealt with the institutions belonging to them. To what extent economics must be adjusted to be applied to earlier forms of social organization has been the source of discussion. Generally, mainstream economists mostly feel that the basic framework of economics is relevant and flexible enough to be applied to virtually any form of society. Marxist economists, who were more influential a few decades ago, often feel that each era of history obeys its very own set of laws, and that contemporary economics can only be applied to industrialized societies.
+
+=== Branches of economics and related subjects ===
+Economics may be broken down as follows:
+
+:''[[Microeconomics]]''
+
+:[[General equilibrium]] -- [[Industrial organization]] -- [[Financial economics]] -- [[Public finance]] -- [[International trade]] -- [[Labor market|Labor economics]] -- [[Development economics]] -- [[Environmental economics]] -- [[Evolutionary economics]] -- [[Public choice theory]] -- [[Economic geography]] -- [[Network effect]] -- [[Transport economics]]
+
+:''[[Macroeconomics]]''
+:[[Stabilisation policy]] -- [[Economic growth]] -- [[Purchasing power parity]]
+
+:''Methodology''
+:[[Econometrics]] -- [[Game Theory]] -- [[Mathematical economics]]
+
+Related fields and topics:
+
+:''Related fields''
+:[[History of Economic Thought|History of economic thought]] -- [[Political economy]] -- [[Political science]] -- [[Accounting]] -- [[Finance and investment]] -- [[Operations research]]
+
+:''Selected topics''
+:[[Economists]] -- [[Nobel Prize in Economics]] -- [[Communism]] -- [[Capitalism]] -- [[Market economy]] -- [[Informal economy]] -- [[Natural capitalism]] -- [[Stock exchange]]
+
+=== Economics and political economy ===
+
+The term economics was coined in around 1870, and popularised by influential neoclassical economists such as [[Alfred Marshall]].  Prior to this the subject had been known as political economy.  This term is still often used instead of economics, especially by radical economists such as [[Marxists]].
+
+===Links===
+* [http://www.oswego.edu/~economic/newbooks.htm]A guide to several online economics textbooks
+* [http://www.econlib.org/index.html] ''The library of economics and liberty'', a site with numerous articles and essays written by well-known economists
+
diff --git a/testsuite/data/Education.txt b/testsuite/data/Education.txt
new file mode 100644 (file)
index 0000000..d7f14d5
--- /dev/null
@@ -0,0 +1,34 @@
+[[nl:Onderwijs]]
+'''Education''' is a term which encompasses the teaching of specific [[skill]]s, and also something less tangible but more profound: the imparting of [[knowledge]], good [[judgement]] and [[wisdom]].
+
+Education begins the minute a baby is born and is life-long. For some, the struggles and triumphs of daily life are far more instructive than formal schooling (Thus Mark Twain: "I never let school interfere with my education.") [[Family]] members have an educational effect which is quite profound -- often more profound than they realize -- though family teaching techniques may be highly informal.
+
+Formal education occurs when society makes a commitment to educate people, usually the young.  Formal education has the advantage of being fairly systematic and thorough; but critics have always noted that whoever sponsors formal education, be it a church, the state or some other group, that group will almost always seek to shape its impressionable scholars in that image.
+
+In recent years, life-long education has become far more widespread, and many adults have given up their notion that only children belong in school. However - the recent years of technology developments with portable computing devices may change some of the classical places where we do learn - OR where we find knowledge. In some places the learning can happen in real time as we need the knowledge itself. This is the computer based / networked learning stucture, where people contribute to each other's education.
+
+:Categories
+:[[Classical Education]] -- [[Reading]] -- [[Education/Math|Math]] -- [[Language education|Language]] -- [[Science education|Science]] -- [[Ethics]] -- [[Physical education]] -- [[Religious education]]
+
+:Formal education
+:[[Elementary education]] -- [[Secondary education]] -- [[Vocational education]] -- [[College education]] -- [[Graduate education]] -- [[Colleges and universities]] -- [[School choice]]
+
+:Educational policy
+:[[Literacy]] -- [[Standardized testing]] -- [[Education reform]] -- [[School choice]]
+
+:Informal education
+:[[Early instruction]] -- [[Home schooling]]
+
+:Theory and Methodology
+:[[Philosophy of education]]--[[Teaching method]] -- [[Instructional theory]]-- [[Learning theory]] -- [[Learning disability]] -- [[Instructional technology]]
+
+:Biographies
+:[[F. Matthias Alexander]]
+:[[John Dewey]]
+:[[Hermann Ebbinghaus]]
+:[[Maria Montessori]]
+:[[Ivan Pavlov]]
+:[[Plato]]
+:[[Jean-Jacques Rousseau]]
+:[[B.F. Skinner]]
+
diff --git a/testsuite/data/Engineering.txt b/testsuite/data/Engineering.txt
new file mode 100644 (file)
index 0000000..2eb6ad9
--- /dev/null
@@ -0,0 +1,60 @@
+[[pt:Engenharia]]
+'''Engineering''' provides the building plans to (re)produce, process or control an artifact.  Its practitioners are called engineers.
+
+At the start of an engineering project, engineers must find the constraints placed on the construction of an artifact.  Constraints can include the money available, the wishes of future users of the artifact, and physical or technical limits.  These constraints we call specifications or requirements.
+
+Engineers borrow from [[physics]] and [[mathematics]] to find suitable solutions to the problem at hand.  They apply [[statistics]] and the [[scientific method]] in deriving their solutions.  If multiple options exist, engineers weigh different design choices on their merits and choose the solution that best matches the requirements.
+
+Engineers try to project how an artifact will perform to its specification.  They use, among other things: computer simulations, destructive tests and stress tests.  Testing ensures the artifact will act as predicted.
+
+It is a myth that ''engineer'' originated to describe those who built [[engine|engines]].  In fact, the word derives from the Latin ''ingeniosus'', the root of the modern English word "ingenious".  An engineer was thus a clever, practical, problem solver.  The term later evolved to include all fields where the skills of application of the [[scientific method]] are used. 
+
+The main difference between [[technology]] and [[science]] is that the former is well understood and yields practical results while the latter tries to explain new and unexplained phenomena.  Engineers work on technology while scientists work on science.
+
+
+Fields of engineering 
+
+*[[Aerospace engineering]]
+*[[Agricultural engineering]]
+*[[Architectural engineering]]
+*[[Astronautical engineering]]
+*[[Bioresource engineering]]
+*[[Biomedical engineering]]
+*[[Chemical engineering]]
+*[[Civil engineering]]
+*[[Computer engineering]]
+*[[Control engineering]]
+*[[Electrical engineering]]
+*[[Environmental engineering]]
+*[[Food process engineering]]
+*[[Geotechnical engineering]]
+*[[Genetic engineering]]
+*[[Industrial and manufacturing engineering]]
+*[[Marine engineering]]
+*[[Mechanical engineering]]
+*[[Nanoengineering]]
+*[[Naval Architecture]]
+*[[Nuclear engineering]]
+*[[Petroleum engineering]]
+*[[Safety engineering]]
+*[[Software engineering]]
+*[[Structural engineering]]
+*[[Systems engineering]]
+*[[Transport engineering]]
+
+Some engineering related topics are:
+
+*[[Computer Aided Design]] (CAD)
+*[[Dimensionless Number|Dimensionless numbers]]
+*[[Electromagnetism]] governed by [[Maxwell's equations|Maxwell's Equations]]
+*[[Electrical network|Electrical Circuit Fundamentals]]
+*[[engineering life cycle cost analysis|Engineering Economics]]
+*[[Ethics]]
+*[[Liability]]  
+*[[Mathematical model]]
+*[[Engineering statistics]]
+*[[Reverse engineering]]
+*[[Rheology]]
+*[[SI unit]]
+*[[Thermodynamics]]
+
diff --git a/testsuite/data/Entertainment.txt b/testsuite/data/Entertainment.txt
new file mode 100644 (file)
index 0000000..3d82d75
--- /dev/null
@@ -0,0 +1,30 @@
+Some forms of entertainment:
+*[[Television]]
+*[[Movies]]
+*[[Anime]]
+*[[Theatre]]
+*[[Sports]]
+*[[Chat]]
+*[[Eating Out]]
+*[[Drinking]]
+*[[Music]]
+*[[Show business]]
+*[[Sex business]]
+*[[Shooting]]
+*[[Celebrity|Celebrities]]
+*[[Humor]]
+**[[Clown]]s
+**[[Comedy]] and [[Comedian]]s
+**[[Internet humor]]
+**[[Illusion]]
+*[[Magic]]
+
+See also [[Game]]s.
+
+You might also find this page to be morbidly fascinating:
+
+[[Recent celebrity deaths]]
+
+And for the intellectually challenged:
+
+[[Cow tipping]] (although the cows probably don't see the funny side)
diff --git a/testsuite/data/Equations.txt b/testsuite/data/Equations.txt
new file mode 100644 (file)
index 0000000..ff5c9d5
--- /dev/null
@@ -0,0 +1,14 @@
+Some equations for testing TeX function:
+
+(1) <math>\phi = \frac{1}{1 + \frac{1}{1 + \frac{1}{1 + \frac{1}{1 + ...}}}}</math>
+
+(2) <math>\phi = \frac{1}{1 + \phi}</math>
+
+(3) <math>\phi + \phi^2 = 1</math>
+
+(4) <math>\phi^2 + \phi - 1 = 0</math>
+
+(5) <math>\phi = \frac{1 \plusmn \sqrt{5}}{2}</math>
+
+(6) <math>\phi \approx 1.61804, -0.61804 </math>
+
diff --git a/testsuite/data/ExternalLinks.txt b/testsuite/data/ExternalLinks.txt
new file mode 100644 (file)
index 0000000..59ab7dd
--- /dev/null
@@ -0,0 +1,32 @@
+Wiki external links test:
+
+(1) [http://a/b/c ABC]
+
+(2) [https://d/e/f DEF]
+
+(3) [ftp://g/h/i GHI]
+
+(4) [gopher://j/k/l JKL]
+
+(5) [news:a.b.c A.B.C]
+
+(6) [mailto:a@b.c A@B.C]
+
+(7) [http://m/n/o]
+
+(8) [http://p/q/r]
+
+(9) [http://a/b/c.png]
+
+(10) [http://d/e/f.jpg]
+
+(11) http://a/b/c
+
+(12) http://a/b/c.png
+
+(13) http://d/e/f.jpg
+
+(14) http://a/b/c. More text.
+
+(15) http://d/e/f, More text.
+
diff --git a/testsuite/data/Family_and_consumer_science.txt b/testsuite/data/Family_and_consumer_science.txt
new file mode 100644 (file)
index 0000000..0dbdcaf
--- /dev/null
@@ -0,0 +1,6 @@
+'''Family and consumer science''', or '''home economics''', involves the study of [[nutrition]], [[cooking]], [[parenting]], [[interior decoration]], [[textiles]], and other useful aspects of [[home management]].
+
+Keeping the home in good working order remains a demanding, time-consuming task.  Today, societies are arguably underrating the skill involved in keeping the home.
+
+Most of the best, most highly skilled [[housewife|homemakers]] never studied &quot;family and consumer science&quot; or even knew it by that name. Some have developed their skills at a [[finishing school]].
+
diff --git a/testsuite/data/Film.txt b/testsuite/data/Film.txt
new file mode 100644 (file)
index 0000000..3e33021
--- /dev/null
@@ -0,0 +1,40 @@
+[[de:Film]][[eo:Kino]][[fr:Cinéma]][[nl:Film]][[pl:Film]]
+Initially, '''moving pictures''' meant only the movement that is perceived when a string of celluloid-recorded images are projected at a rate of 16 frames per second or more (see [[persistence of vision]]). Today, '''motion pictures''' (or '''movies''') are an art form, as well as one of the most popular forms of entertainment.  
+
+=== History of Cinema ===
+
+* [[Eadweard Muybridge]]
+* [[William Friese-Greene]] 
+* [[Augustin Le Prince|Louis Aimé Augustin Le Prince]]
+* [[George Eastman]]
+* [[Thomas Edison]]
+* [[Auguste and Louis Lumiere|Auguste and Louis Lumière]]
+* [[Georges Méliès]]
+* Cinema pre-history: the [[zoetrope]], etc.
+
+Originally moving picture film was shot at a nominal 16 frames per second, but was changed to 24 frames per second with the introduction of sound.  Other improvements since the late 1800s include the mechanization of cameras, allowing them to record at a consistent speed, and the invention of more sophisticated filmstocks, allowing directors to film in increasingly dim conditions.  Since the advent of many other media technologies, film may include a broad range of media--both linear and non-linear, dramatic and informational, motion and still (though progressive).
+
+:[[Academy Awards]]
+:[[Motion picture terminology|Common terms]]
+:[[Digital cinema]]
+:[[Individual Movies]]
+:[[Film criticism]]
+:[[Film festival]]s
+:[[Film genres]]
+
+:[[Film history]]
+:[[Film institutes]]
+:[[Film technique]]
+:[[Film theory]]
+:[[Special effect]]s
+:[[Top grossing movie]]s
+:[[Top grossing movies US]]
+
+Film people:
+:[[Actors]]
+:[[Film crew]]
+:[[film criticism]]
+:[[Film directors]]
+:[[Screenwriter]]
+:[[Movie studio]]
diff --git a/testsuite/data/Game.txt b/testsuite/data/Game.txt
new file mode 100644 (file)
index 0000000..b957855
--- /dev/null
@@ -0,0 +1,33 @@
+[[eo:Ludoj]][[fr:Jeux]]
+All through human history, people have played '''games'''.  They've done so mostly to entertain themselves and others.  But games are also a form of self-expression, and a means of training young people, and reminding adults, of the preferred values of the society in which they live.
+
+Games can involve one person acting alone, but more often involve competition among two or more persons with differing goals.  Philosopher [[David Kelley]], in his popular introductory reasoning text [[The Art of Reasoning]], defines the concept "game" as "a form of recreation constituted by a set of rules that specify an object to be attained and the permissible means of attaining it."
+
+This covers most cases well, but does not quite fit with things like war games and sports that are often done not for entertainment but to build skills for later use.  In [[Philosophical Investigations]], philosopher [[Ludwig Wittgenstein]] argued that the concept "game" could not be defined.  [[Stephen Linhart]] said, "People say you have to choose between games and real life.  I think this claim that there's a dichotomy is very dangerous."
+
+Many technical fields are often applied to the study of games, including [[probability]], [[statistics]], [[economics]], and [[game theory]].
+
+== Types of Games ==
+
+*[[Board game|Board games]]
+*[[Card game|Card games]]
+*[[Casino game|Casino games]]
+*[[Video game|Computer and Video games]]
+*[[Mathematical game|Mathematical games]]
+*[[Letter game|Letter games]]
+*[[Role-playing game|Role-playing games]]
+*[[Tile-based game|Tile-based games]]
+*[[Sport|Sports]]
+*[[Guessing game|Guessing games]]
+*[[Pencil and paper game|Pencil and paper games]]
+*[[Counting-out game|Counting-out games]]
+*[[Drinking game|Drinking games]]
+*[[Play by mail game|Play by mail games]]
+*[[Game show|Game shows]]
+*[[Unclassified game|Unclassified games]]
+*[[Table-top game]]s
+*[[Spoken game]]s
+*[[Games of physical skill]]
+
+See also: [[Sport]].
+
diff --git a/testsuite/data/Geography.txt b/testsuite/data/Geography.txt
new file mode 100644 (file)
index 0000000..c53ff1e
--- /dev/null
@@ -0,0 +1,45 @@
+[[eo:Geografio]][[nl:Geografie]]
+'''Geography''' is the study of the surface of the [[Earth]]. The word derives from the [[Greek language|Greek]] words ''h&ecirc;g&ecirc;'' ("the Earth") and ''graphein'' ("to write").
+
+Geography is much more than [[Cartography]], the study of maps.  It not only investigates what is where on the Earth, but also why it's there not somewhere else, sometimes referred to as "location in space".  It studies this whether the cause is natural or human. It also studies the consequences of those differences.  
+
+'''Methods'''
+
+Spatial interrelationships are key to this [[synoptic science]], and it uses [[map|maps]] as a key tool.  Geographers use four interrelated approaches:  
+* Systematic - Groups geographical knowledge into categories that can be explored globally
+* Regional - Examines systematic relationships between categories for a specific region or location on the [[planet]].
+* Descriptive - Simply specifies the locations of features and populations.
+* Analytical - Asks ''why'' we find features and populations in a specific geographic area.
+
+'''Physical geography'''
+
+This branch focuses on Geography as an [[Earth science]], making use of biology to understand global [[flora]] and [[fauna]] patterns, and [[mathematics]] and [[physics]] to understand the motion of the earth and relationship with other bodies in the [[solar system]].  It also covers [[mapmaking]] and [[navigation]].
+
+[[atmosphere]] -- [[archipelago]] -- [[city]] -- [[continent]] -- [[desert]] -- [[gulf]] -- [[island]] -- [[lake]] -- -- [[mountain range]] -- [[ocean]] -- [[peninsula]] -- [[plain]] -- [[river]] -- [[sea]] -- [[valley]] -- [[Ecology]] -- [[Climate]] -- [[soil]] -- [[geomorphology]] -- [[biogeography]] - [[Timeline of geography, meteorology, paleontology]]
+
+'''Human geography'''
+
+The [[human]], or political/cultural, branch of geography - also called [[anthropogeography]] focuses on the [[social science]], non-physical aspects of the way the world is arranged.  It examines how humans adapt themselves to the land and to other people, and in macroscopic transformations they enact on the world.  It can be divided into the following broad categories: [[economic geography]], [[political geography]] (including [[geopolitics]]), [[social geography]] (including [[urban geography]]), [[environmentalism]], [[cartography]], and [[military geography]].
+
+[[Countries of the world]] -- [[country]] -- [[city]] -- [[nation]] -- [[state]] -- [[union]]
+
+'''Historical geography'''
+----
+This branch seeks to determine how physical and cultural features of the planet evolved and came into being.  
+
+'''Urban and Regional Planning'''
+
+[[Urban planning]] and [[regional planning]] use the science of geography to assist in determining how to develop (or not develop) the land to meet particular criteria, such as safety, beauty, economic opportunities, the preservation of the built or natural heritage, etcetera. The planning of towns, cities and rural areas may be seen as applied geography although it also draws heavily upon the arts, the sciences and lessons of history. Some of the issues facing planning are considered briefly under the headings of [[Rural Exodus]], [[Urban Exodus]] and [[Smart Growth]].
+
+'''History of Geography'''
+
+The [[Greek]]s are the first known culture to actively explore geography as a [[science]] and [[philosophy]], with major contributors including [[Thales]] of Miletus, [[Herodotus]], [[Eratosthenes]], [[Hipparchus]], [[Aristotle]], [[Dicaearchus]] of Messana, [[Strabo]], and [[Ptolemy]].  Mapping by the [[Roman]]s as they explored new lands added new techniques.  
+
+During the [[Middle Ages]], [[Arab]]s such as [[Idrisi]], [[Ibn Battutah]], and [[Ibn Khaldun]] built on and maintained the Greek and Roman learnings.  Following the journeys of [[Marco Polo]], interest in geography spread throughout [[Europe]]. During the [[Renaissance]] and into the [[16th century|16th]] and [[17th century|17th centuries]] the great voyages of exploration revived a desire for solid theoretical foundations and accurate detail.  The [[Geographia Generalis]] by [[Bernhardus Varenius]] and [[Gerardus Mercator]]'s world map are prime examples.  
+
+By the [[18th century]], geography had become recognized as a discrete discipline and became part of a typical [[university]] curriculum.  Over the past two centuries the quantity of knowledge and the number of tools has exploded. There are strong links between geography and the sciences of [[geology]] and [[botany]].
+
+'''Regional Science'''
+
+In the [[1950s]] the [[regional science]] movement arose, led by [[Walter Isard]] to provide a more quantitative and analytical base to geographical questions, in contrast to the more qualitative tendencies of traditional geography programs.  Regional Science comprises the body of knowledge in which the spatial dimension plays a fundamental role, such as [[regional economics]], [[resource management]], [[location theory]], [[urban planning|urban]] and [[regional planning]], [[transportation]] and [[communication]], [[human geography]], [[population distribution]] and environmental quality.
+
diff --git a/testsuite/data/Handicraft.txt b/testsuite/data/Handicraft.txt
new file mode 100644 (file)
index 0000000..f4dd837
--- /dev/null
@@ -0,0 +1,28 @@
+'''Handicraft''', also known as '''craftwork''' or simply '''craft''', is a type of work where useful and decorative devices are made completely by hand or using only simple tools. Usually the term is applied to traditional means of making goods. The individual artisanship of the items is a paramount criterion, such items often have cultural and/or religious significance. Items made by [[mass production]] or machines are not handicrafts. 
+
+Usually, what distinguishes the term '''handicraft''' from the frequently used category [[Arts and Crafts]] is a matter of intent: handicrafted items are intended to be used, worn, etcetera, having a purpose beyond simple decoration. Handicrafts are generally considered more traditional work, created as a necessary part of daily life, whilst "Arts and Crafts" implies more of a hobby pursuit and a demonstration/perfection of a creative technique. In practical terms, the categories have a great deal of overlap.
+
+Handicrafts include:
+* [[assemblage]] - collage in three dimensions
+* [[beadwork]]
+* [[collage]] possibly involving seeds, fabric, paper, photographs and/or found objects
+* [[cooking]]
+* [[gardening]]
+* [[marquetry]]
+* [[metalwork]]
+* [[needlework]]
+** [[cross-stitch]]
+** [[embroidery]]
+** [[quilting]]
+** [[patchwork]]
+** [[crochet]]
+** [[knitting]]
+** [[tatting]]
+* [[pottery]] and [[ceramics]]
+* [[spinning]] 
+* [[woodworking]]
+** [[chip carving]]
+** [[wood burning]]
+
+See also [[Arts and crafts]].
+
diff --git a/testsuite/data/Headings.txt b/testsuite/data/Headings.txt
new file mode 100644 (file)
index 0000000..ce58e7f
--- /dev/null
@@ -0,0 +1,46 @@
+
+Wikipedia headings test:
+
+== AAA 2 ==
+
+=== BBB 3 ===
+
+== CCC 2 ==
+=== DDD 3 ===
+==== EEE 4 ====
+
+==== FFF 4 ====
+
+=== GGG 3 === Extra text.
+
+==== HHH 4 ====
+Paragraph
+
+==== III 4 ====
+
+Paragraph
+
+(1)
+
+---
+
+(2)
+
+----
+
+(3)
+
+-----
+
+(4)
+
+----XXX
+
+===== JJJ 5 =====
+
+====== KKK 6 ======
+
+===LLL 3 ===
+
+== MMM 2==
+
diff --git a/testsuite/data/Health_science.txt b/testsuite/data/Health_science.txt
new file mode 100644 (file)
index 0000000..9240ffe
--- /dev/null
@@ -0,0 +1,7 @@
+[[de:Gesundheit]][[eo:Sansciencoj]][[nl:Gezondheidszorg]][[pl:Medycyna]]
+The disipline of '''health science''' includes not only traditional [[first aid]], [[triage]], [[medicine]] and [[surgery]], but also [[dentistry]], [[psychiatry]], [[disease]] and [[counselling]], [[veterinary science]], [[nursing]], [[therapy/Physical|physical therapy]] and other kinds of [[therapy]], like [[therapy/Occupational|occupational therapy]], [[therapy/Speech-Language|speech-language therapy]],  [[therapy/Respiratory|respiratory therapy]] and [[therapy/Recreational|recreational therapy]], as well as [[midwifery]], [[hospice care]], [[home care]], [[nutrition]], and [[alternative medicine]], [[pharmacology]], [[toxicology]].
+----
+We might distinguish among the health sciences between those which merely analyze a field or diagnose a problem; and those which also present a specific treatment for that problem.
+See also:
+*[http://www.HavenWorks.com/health Health News and Links:] http://www.HavenWorks.com/health
+
diff --git a/testsuite/data/History.txt b/testsuite/data/History.txt
new file mode 100644 (file)
index 0000000..4066248
--- /dev/null
@@ -0,0 +1,87 @@
+[[dk:Historie]][[de:Geschichte]][[eo:Historio]][[fr:Histoire]][[pl:Historia]][[pt:História]][[nl:Geschiedenis]]
+'''History''' is often used as a generic term for information about the past, e.g., as in "geologic history of the Earth".  When used as a field of study, history refers to human history, which is the recorded past of human societies.  
+
+The term "history" comes from the Greek ''historia'', "an account of one's inquiries", and  shares that [[etymology]] with the English word "story".
+
+Historians use many types of sources, including written or printed records, interviews ([[oral history]]), and [[archaeology]].    Different approaches may be more common in some periods than others, and the study of history has its fads and fashions (see [[historiography]], the history of history).  The events that occurred prior to human records are known as [[prehistory]].
+
+There is a very large amount of historical information available in Wikipedia, and several different ways of classifying it are given below.
+
+History classified by location:
+
+* [[History of Africa|Africa]]
+* [[History of the Americas|Americas]]
+* [[History of Asia|Asia]]
+* [[History of Europe|Europe]]
+* [[History of Oceania|Oceania]]
+* [[History of Antarctica|Antarctica]]
+
+----
+
+History classified by date:
+
+* [[Millennia]]
+* [[Centuries]]
+* [[Decades]]
+* [[Year in Review]]
+* [[Periodization]]
+* [[List of timelines]]
+----
+
+Miscellaneous classifications, not necessarily part of academic history studies:
+
+* [[History of present-day nations and states]]
+* [[Extinct_countries,_empires,_etc.|History of extinct nations and states]]
+* [[Economic history]]
+* [[Military history]]
+* [[Diaspora studies]]
+
+* [[Biography|History of individuals]] (biography)
+
+* [[History of mathematics]]
+* [[History of philosophy]]
+* [[History of science and technology]]
+* [[History of medicine]]
+* [[History of economic thought]]
+
+* [[History of religions]]
+* [[Cultural movement]]s
+* [[History of art]]
+* [[History of literature]]
+* [[History of theater]]
+* [[Film history]]
+* [[Intellectual history]]
+* [[Psychohistory]]
+
+----
+
+A typical acedemic classification:
+
+* [[Prehistory]]
+* [[Ancient history]]
+* [[East Asian history]]
+* [[Pre-Columbian history of the Americas]]
+* [[Medieval European history]]
+* [[Islamic history]]
+* [[South Asian history]]
+* [[African history]]
+* [[Russian history]]
+* [[Byzantine history]]
+* [[Southeast Asian history]]
+* [[Latin American history]]
+* [[Anglo-American history]]
+* [[Jewish history]]
+* [[Nordic history]]
+* [[Central Asian history]]
+* [[Iranian history]]
+* [[History of Australasia]] (Australia, New Guinea, Micronesia, Melanesia, Polynesia)
+
+----
+
+You may also want to see [[dubious historical resources]] and [[historical myths]] for a list of false beliefs and histories which were once or are now popular and widespread, but which are proven to be false or dubious.
+
+----
+See also [[Archaeology]], [[Historian]].
+
+A guideline for contributions to Wikipedia in the field of history can be found at [[Wikipedia History standards]].
+
diff --git a/testsuite/data/History_of_science_and_technology.txt b/testsuite/data/History_of_science_and_technology.txt
new file mode 100644 (file)
index 0000000..b00f2e4
--- /dev/null
@@ -0,0 +1,115 @@
+[[eo:Historio de Scienco kaj Teknologio]]
+The '''history of science and technology''' (HST) is a field of [[history]] which examines how humanity's understanding of the natural world has changed over the millennia, and how this understanding has allowed us to generate technologies which have modified that world. Sayings such as, "Water runs downhill" are attempts to formulate rules that describe the workings of nature.
+
+From the philosophers of ancient times to the 21st century, science and technology advanced in fits and starts, bringing an ever-more comprehensive view of the world. Discoveries such as those of [[natural selection]], the structure of [[gene]]s and [[DNA]], and within [[psychology]] have radically altered how we humans see ourselves, often  conflicting with [[religion|religious]] views.
+New technologies let us visit other planets, travel faster than sound, and kill each other with greater efficiency. 
+
+HST aims to understand how [[science]] and [[technology]] progress and how we form theories by studying the lessons of the past, while also exploring the socio-political and cultural environment within which scientists and technologists work.
+
+==== Challenge to orthodoxy ====
+A minor but persistent theme in the history of science and technology has been the poor reception often given to men who espouse ideas contrary to the prevailing orthodoxy. The story of [[Galileo]] is a case in point. Other natural philosophers and astronomers, especially in Italy, were loathe to "check" their theories by looking through the newly-invented telescope. Even in modern times, with the near-univeral acceptance of the [[scientific method]] and huge research budgets from government, academia and industry, unpopular or offensive ideas are often given short shrift. 
+
+There is controversy over what the lesson of the Galileo story is. While some see Galileo's saga as an example of the arrogance of authority, others argue that today's rejection of such ideas can not be directly compared with examples such as Galileo. Theories which do follow the the principles of science closely, as Galileo did, are generally accepted however surprising they may be, whereas ideas that make yet unproven and seemingly unjustified assumptions are termed pseudoscience. 
+
+==== Contribution to knowledge ====
+
+Be that as it may, after a lapse of time even the most unpopular idea can become the new orthodoxy, if proven satisfactorily. The germ theory of disease has become so prevalent that [[pasteurization]] and [[Listerine]] are household words, even if [[Louis Pasteur]] and [[Joseph Lister]] are no longer remembered.
+
+==== Major areas/Sub-fields ====
+
+=== [[Science]] ===
+*Life Sciences
+**[[Biology]]
+***[[History of anatomy]]
+***[[Theory of evolution]]
+****[[Charles Darwin]] and the [[Origin of Species]]
+***[[Genetics]]
+****[[DNA]] 
+**[[Paleontology]]
+**[[Biochemistry]]
+*Physical Science
+**[[Chemistry]]
+**[[Physics]]
+**[[History of astronomy]]
+**[[Geology]] and [[Earth science]]
+
+*[[Mathematics]] and [[Statistics]]
+*[[Philosophy]] and [[Logic]]
+
+=== [[Social science]] ===
+* [[Anthropology]] 
+* [[Archaeology]]
+* [[Economics]], [[business]] and [[industry]] 
+* [[Industrial organization]] and [[labor]]
+* [[Geography]] 
+* [[Language]] and [[Linguistics]] 
+* [[Political science]] 
+* [[Psychology]] 
+* [[Sociology]]
+
+=== [[Technology]] ===
+
+* [[Civil engineering]]
+** [[Architecture]] and building construction
+** [[Bridge]]s, [[harbor]]s, [[tunnel]]s, [[dam]]s
+** [[Surveying]], instruments and [[map]]s, [[cartography]], urban engineering, [[water]] supply and [[sewer]]age
+* [[Transport]]ation
+* [[Energy]] conversion
+* [[Material]]s and processing
+** [[Metal]]s, [[mining]],  [[metallurgy]]
+***[[History of the Petroleum Industry]] 
+***[[gas]] 
+***[[coal]] 
+***[[rubber]] 
+***[[plastic]]
+***[[ceramics]] 
+***[[glass]] 
+***[[cement]] 
+***[[stone]] 
+***[[salt]]
+***[[paper]] 
+***[[lumber]] 
+***[[textiles]] 
+***[[leather]] 
+***[[bone]]
+
+* [[Electricity]]
+**[[Light bulb]]
+**[[Electronics]]; mechanical and electro-mechanical technology
+**[[Refrigeration]]
+
+*[[Communication]]s 
+**[[Television]] 
+**[[Cable TV]]
+**[[History of radio]]
+**[[Library and information science]]
+**[[History of computers]]
+
+* [[Health science]]
+* [[History of medicine]]
+* [[Biotechnology]]
+* [[Agriculture]]  
+* [[Family and consumer science]]
+
+* [[Military technology]]
+
+=== General Science and Technology ===
+*[[Biography]] of [[inventor]]s, [[explorers]], and [[scientist]]s 
+* [[Scientists and inventors]]
+* [[List of timelines|Timelines]] of Science and Technology 
+* Technical societies, technical education
+* Economic, political, and social history
+* General relationships between technology and culture; philosophy of technology
+
+* [[Historiography]] of Science and Technology
+** [[Kranzberg's Laws of Technology]]
+
+* Historians of Science and Technology:
+** [[Thomas P. Hughes]] 
+** [[Arne Kaijser]]
+** [[Thomas Kuhn]]
+
+----
+As History of X articles are written, please add them above, redirecting away from broader article.
+
diff --git a/testsuite/data/Hobby.txt b/testsuite/data/Hobby.txt
new file mode 100644 (file)
index 0000000..b12247f
--- /dev/null
@@ -0,0 +1,87 @@
+[[eo:Hobioj]][[nl:Hobby]]
+A '''hobby''' is a spare-time pursuit (see [[recreation]]) practiced for interest and enjoyment rather than as paid work.  Examples include collecting, making, tinkering, sports and adult education.  Engaging in a hobby can lead to acquiring substantial skill, knowledge, and experience.
+But personal fulfillment is the aim.
+
+What are hobbies for some people are professions for others: a computer game tester may enjoy cooking as a hobby, while a professional chef might enjoy playing (and helping to debug) computer games.  Generally speaking, the person who does something for fun, not remuneration, is called an ''amateur'' (or ''hobbyist''), as distinct from ''[[profession|professional]].''
+
+An important determinant of what is considered a hobby, as distinct from a profession, is probably how easy it is to make a living at the activity.  Almost no one can make a living at [[stamp collecting]], but many people find it enjoyable; so it is commonly regarded as a hobby.
+
+While some hobbies strike most people as trivial and boring, the hobbyist has found something compelling and entertaining about them.  Much early scientific research was, in effect, a hobby of the wealthy; in our own time, [[Linux]] began as a student's hobby.
+
+Pursuit of a hobby often has calming or helpful therapeutic side effects.
+
+Hobbies include:
+* [[Amateur astronomy]]
+* [[Amateur radio]]
+* [[Animal]]
+** [[Dog breeding]]
+**Keeping [[pet]] animals
+
+* [[Arts and Crafts]]
+** Drawing
+** Sculpture
+** Painting
+
+* [[Automotive]]
+** [Antique]
+** [Trucks]
+** [Motorcycles]
+
+* [[Collecting]] (stamps, books, postcards, antique automobiles etc.)
+
+* [[Computer programming]]
+** [[Linux]]
+** [[Open source]]
+** [[Free software movement]]
+
+* [[Cooking]]
+* [[Electronics]]
+** [[amateur radio]]
+
+* [[DIY]]
+
+* [[Game]]s
+** [[Miniature wargaming]]
+** [[Wargaming]]
+** [[Role-playing game]]s
+** [[Jigsaw puzzle]]
+** [[Crossword puzzle]]s
+** [[Chess]]
+
+* [[Gardening]]
+* [[Genealogy]]
+* [[Historical reenactment]]
+
+*[[Literature]]
+**Reading
+**Writing
+**Learning foreign languages
+
+* Machining
+
+* [[Model-building]]
+** [[Model airplane]]s
+** [[Model car]]s
+** [[Model house]]s
+** [[Model ship]]s
+** [[Model railway]]s
+** [[Model rocket]]s
+** [[Flying Kites]] 
+
+* [[Music-making]]
+** [[Musical composition]]
+**   [[MIDI compostion]]
+
+* [[Observation]]
+** [[Aircraft spotting]]
+** [[Bird watching]]
+** [[Butterfly watching]]
+** [[Trainspotting]]
+* [[Sport]]s
+
+* [[Restoration of highly entropic artifacts]]
+* [[Wikipedian Participation]] 
+* [[Walking]]
+
+'''Please add to this list'''
+
diff --git a/testsuite/data/InternalLinks.txt b/testsuite/data/InternalLinks.txt
new file mode 100644 (file)
index 0000000..315d3a0
--- /dev/null
@@ -0,0 +1,24 @@
+Wiki internal links test:
+
+(1) [[Mathematics]]
+
+(2) [[Non-existing article]]
+
+(3) [[Cooking|Burning]]
+
+(4) [[User:Fred|Fred]]
+
+(5) [[Talk:Language]]
+
+(6) [[image:foo.png]]
+
+(7) [[media:bar.ogg]]
+
+(8) [[de:German|German article]]
+
+(9) [[image:bar.jpg|Alt text]]
+
+(10) [[Game]]s
+
+Need to add some more tests of interwiki links here...
+
diff --git a/testsuite/data/Language.txt b/testsuite/data/Language.txt
new file mode 100644 (file)
index 0000000..29e6c25
--- /dev/null
@@ -0,0 +1,31 @@
+[[eo:Lingvo]][[fr:Langue]][[nl:Taal]][[pl:J%EAzyk]]
+'''Languages''' are ways to represent things, actions, and ideas. Most often, the term refers to vocal languages, the languages [[human]]s or [[animals]] create through vocal sounds in meaningful patterns. Animal languages can be quite complex; but among the animals, humans alone have a [[literature]], a body of written or oral language.
+
+[[Mathematics]] and [[computer science]] use artificial languages called [[formal language]]s, (including [[programming language]]s). 
+
+The study of languages makes up [[linguistics]] and [[philology]].  Other important concepts:
+
+* [[Philosophy of language]]
+* [[Sapir-Whorf hypothesis]]
+* [[Orthography]]
+* [[Psycholinguistics]]
+* [[Semantics]]
+* [[Naming]]
+* [[Phonology]]
+* [[Speech therapy]]
+* [[Profanity]]
+* [[Philology|Historical Linguistics or Philology]]
+
+List of [[language families and languages]]:
+
+A useful listing of 4000 languages and dialects (grouped by their relationships), with the numbers one through ten in each language can be found at [[Mark Rosenfelder]]'s Metaverse website (see external links).
+
+A fairly complete list of all languages, locations, population, and genetic affiliation can be found in the [[Ethnologue]].
+
+See also [[Common phrases in different languages]], [[Tongue twister]].
+
+----
+'''External links:'''
+* [http://www.zompist.com/ Mark Rosenfelder's Metaverse]
+* [http://www.geocities.com/agihard/mohl/mohl_languages.html Museum of Languages]
+
diff --git a/testsuite/data/Law.txt b/testsuite/data/Law.txt
new file mode 100644 (file)
index 0000000..09be928
--- /dev/null
@@ -0,0 +1,177 @@
+[[de:Rechtswissenschaft]][[eo:Juro]][[es:Derecho]][[fr:Droit]][[nl:Recht]][[pl:Prawo]]
+'''Law''' concerns the set of rules a [[society]] adopts to regulate behavior, to order life in its territory and to resolve disputes.
+
+Each [[jurisdiction]] has its own laws; but laws are often quite similar, arising from similar values and similar social, economic and political conditions. 
+
+There are several distinct legal traditions; these differ less in the substantive content of the law than in their [[jargon]] and procedures.
+
+The several different levels of [[government]] each produce their own laws (though the extent to which law is centralized varies); thus at any one place there can be laws in force established at the local, regional, state, national or international levels.
+
+== Legal systems ==
+
+[[Common law]] -- [[civil law]] -- [[Roman law]] -- [[international law]] -- [[European community law]] -- [[socialist law]] -- [[Canon law]]
+
+== Legal subject areas ==
+
+[[Constitutional law]] -- [[Criminal law]] -- [[Civil law]] -- [[Administrative law]] -- [[Evidence|Law of Evidence]] _ [[Procedural law]] -- [[Private law]] -- [[Family law]] -- [[Labor law]] -- [[Corporations law]] -- [[Property law]] -- [[Human rights law]] -- [[Intellectual Property law]] -- [[Environmental law]] -- [[Land use]] -- [[consuetudinary law]]
+
+== Law of particular countries ==
+
+*[[United Kingdom]]: [[British Nationality Law]], [[Judicial Committee of the Privy Council]], [[House of Lords]], [[Human Rights Act 1998]]
+*[[United States]]: [[US Constitutional Law]], [[United States Constitution]],  [[False Claims Law]], [[Controlled Substances Act]], [[Digital Millennium Copyright Act]], [[Sonny Bono Copyright Term Extension Act]]
+*[[Australia]]: [[Australian Constitutional History]]
+
+== Subjects Auxillary to Law ==
+
+[[Jurisprudence]] -- [[Practice of law]] -- [[philosophy of law]] -- [[comparative law]] -- [[legal history]] -- [[law and literature]] -- [[dispute resolution]] (aka, [[alternative dispute resolution]])
+
+== Other ==
+(To be arranged into the above categories)
+
+* [[abandonment]] 
+* [[abatement]] 
+* [[abduction]] 
+* [[acquittal]]
+* [[adversary system]] 
+* [[affidavit]] 
+* [[age of consent]] 
+* [[allocute]] 
+* [[animus nocendi]]
+* [[answer]] 
+* [[appeal]] 
+* [[appellate court]]  
+* [[at bar]] 
+* [[bar]] 
+* [[barratry]] 
+* [[black letter law]] 
+* [[blue law]] 
+* [[brocard]]
+* [[case law]] 
+* [[cause of action]] 
+* [[civil law]] 
+* [[class action]] 
+* [[common law]]
+* [[constitution]] 
+* [[contract]]
+* [[contempt of court]] 
+* [[copyright]] 
+* [[Corpus Juris Civilis]]
+* [[corroborating evidence]] 
+* [[Court of Appeals]] 
+* [[criminal law]]  
+* [[cross-examination]] 
+* [[damages]] 
+* [[defendant]] 
+* [[deponent]] 
+* [[depose]] 
+* [[deposition]] 
+* [[direct examination]] 
+* [[disbarment]] 
+* [[double jeopardy]] 
+* [[environmental agreements]]
+* [[expert witness]] 
+* [[family law]] 
+* [[False Claims Law|false claims law]]
+* [[felony]] 
+* [[fifth amendment rights of witness]] 
+* [[fraud]]
+* [[frivolous lawsuit]] 
+* [[good faith]] (''bona fide'')
+* [[grand jury]] 
+* [[guilt]]
+* [[hostile witness]] 
+* [[immunity]] 
+* [[incest]] 
+* [[indictment]] 
+* [[inquest]] 
+* [[intellectual property]] 
+* [[judicial economy]]
+* [[jurisdiction]] 
+* [[jurisprudence]] 
+* [[jurist]]
+* [[jury instructions]] 
+* [[jury trial]] 
+* [[jus sanguinis]]
+* [[jus soli]]
+* [[justice]] 
+* [[laches]] 
+* [[lawyer]] 
+* [[leading question]] 
+* [[legal aspects of transsexualism]]
+* [[legal technicality]] 
+* [[Lettre de cachet]] 
+* [[litigant]] 
+* [[loss of consortium]] 
+* [[malpractice]]
+* [[mens rea]]
+* [[misdemeanor]] 
+* [[motion]] 
+* [[Napoleonic Code]] 
+* [[nationality]] 
+* [[negligence per se]] 
+* [[negligence]]
+* [[non-disclosure agreement]]
+* [[notary public]] 
+* [[notitia criminis]]
+* [[Oral law]]
+* [[patent]] 
+* [[personal property]] 
+* [[philosophy of law]] 
+* [[plaintiff]] 
+* [[plea bargain]]  
+* [[plea of nolo contendere]]
+* [[plea of temporary insanity]] 
+* [[plea]]
+* [[precedent]]
+* [[prima facie]]  
+* [[product liability]] 
+* [[property]] 
+* [[proximate cause]] 
+* [[False Claims Law|qui tam]]
+* [[real property]] 
+* [[rebuttal]]  
+* [[redirect examination]] 
+* [[remedy]]
+* [[res ipsa loquitur]]
+* [[reus]]
+* [[reversible error]]  
+* [[sanctions]] 
+* [[senatusconsultus]]
+* [[sentence]]
+* [[sodomy law]]
+* [[standing]]
+* [[statute of limitations]] 
+* [[statute]] 
+* [[statutory law]]
+* [[SLAPP|Strategic lawsuits agains public participation]]
+* [[strike from the record]] 
+* [[Supreme court]] 
+* [[tax law]] 
+* [[terrorism]] 
+* [[time constraints]] 
+* [[tort]] 
+* [[trade secret]] 
+* [[trademark]] 
+* [[trial de novo]] 
+* [[Unidroit]]
+* [[usucaption]]
+* [[usufruct]]
+* [[vexatious litigation]] 
+* [[voluntas necandi]]
+* [[will]]
+* [[with prejudice]] 
+* [[witness]]
+* [[writ of certiorari]]
+* [[writ of mandamus]]
+* [[Habeas corpus|writ of habeas corpus]] 
+
+Legal books:
+* [[Black's Law Dictionary]]
+* [[Halsbury's Statutes]]
+
+See also [[Crime]].
+*[http://www.HavenWorks.com/law Law &amp; Legal News &amp; Reference:] http://www.HavenWorks.com/law
+----
+
+Not quite law: [[Law of nature]] -- [[Murphy's law]] -- [[Finagle's law]] -- [[Hanlon's Razor]] -- [[Sturgeon's law]] -- [[Parkinson's law]] -- [[Occam's razor]]
+
diff --git a/testsuite/data/Library_and_information_science.txt b/testsuite/data/Library_and_information_science.txt
new file mode 100644 (file)
index 0000000..44019c8
--- /dev/null
@@ -0,0 +1,38 @@
+[[nl:Bibliotheekwezen]]
+'''Library and information science''' (LIS) (as distinct from [[information theory]]) is the "study of stuff having to do with [[library|libraries]]".  Strictly speaking, LIS consists of academic studies (most often surveys) about how library resources are used and how people interact with library systems. These studies tend to be specific to certain libraries at certain times. Generally speaking, LIS is about the organization of knowledge for retrieval of relevant information.
+
+Library Science is distinct from Librarianship, which is the practical ''service'' rendered by librarians in their day-to-day attempt to meet the needs of library patrons. Librarianship tends not to generate new knowledge, nor to strive to advance any field or discipline. Librarians only rarely engage in Library Science, and then usually outside their jobs as librarians. But the study of Library Science is part of the requisite training of librarians.  "Information" and "documentation" means non-[[book]] stuff that university libraries deal with, such as magazines, scientific journals, technical reports, and access to online databases.
+
+The term "Library and Information Science" should not be broken into these separate pieces. Library and Information Science is a hybrid academic field that grew from library schools' fight for survival in the electronic age. The politics of academia, issues of status and prestige, issues of perceived obsolescence and other forces created these programs. Programs in Library and Information Science are interdisciplinary, overlapping with the fields of systems' analysis, [[computer science]], [[statistics]] and various parts of the [[social sciences]].
+
+The field of Library and Information Science is not defined by its output of information specialists, but by the "information specialists" who remain in academia teaching and doing research, by its literature, its journals and all the other ways in which an academic discipline is defined, the study of which, by the way, falls within the scope of Library and Information Science!
+
+Basic topics in Library science include the acquisition, [[library classification|classification]] and preservation of Library materials. In a more present-day view, a fervent outgrowth of library science is information architecture.
+
+Important LIS institutions and resources:
+* Indiana University SLIS, http://www.slis.indiana.edu/
+* Syracuse University School of Information Studies, http://istweb.syr.edu/
+* [[University of Michigan]] School of Information, http://www.si.umich.edu/
+* University of Pittsburgh School of Information Sciences, http://www2.sis.pitt.edu/
+* University of Washington Information School, http://www.ischool.washington.edu/
+* University of North Carolina at Chapel Hill School of Information and Library Science, http://www.ils.unc.edu/
+
+* OCLC (Online Computer Library Center), http://www.oclc.org/
+* American Library Association, http://www.ala.org/
+* Canadian Library Association, http://www.cla.ca/
+* Australian Library and Information Association, http://www.alia.org.au/
+* American Society for Information Science and Technology, http://www.asis.org/
+
+Some current LIS issues:
+* [[information explosion]]
+* [[information retrieval]]
+* knowledge management
+* reference sources
+* information storage
+* [[slow fires]]
+* [[mass deacidification]]
+* [[information architecture]]
+
+See also:
+*[http://www.LISNews.com Library and Information Science News ;-)] http://www.LISNews.com 
+
diff --git a/testsuite/data/Linguistics.txt b/testsuite/data/Linguistics.txt
new file mode 100644 (file)
index 0000000..059e72d
--- /dev/null
@@ -0,0 +1,52 @@
+[[de:Linguistik]]
+[[eo:Lingvistiko]]
+[[fr:Linguistique]]
+[[nl:Taalkunde]]
+[[pl:Lingwistyka]]
+
+'''Linguistics''' is the study of [[language]]. One who engages in this study is called a [[linguist]].
+
+Note that, at least in the United States, those who identify themselves as linguists tend to use the term "linguistics" to refer to a fairly technical subset of language study. "Linguistics", for them, does not include learning to speak foreign languages (except insofar as this helps to perform more technical analysis) or to literary analysis, for example. Nor is linguistics usually meant to include such proscriptive efforts as found in Strunk and White's ''The Elements of Style''; linguistics usually seeks to study what people do, not what they ''should'' do.
+
+----
+Research areas of linguistics:
+
+[[phonetics]], [[phonology]], [[syntax]], [[semantics]], [[pragmatics]], [[etymology]], [[lexicology]], [[lexicography]], [[theoretical linguistics]], [[historical-comparative linguistics]] and [[descriptive linguistics]], [[pragmatics]], [[etymology]], [[computational linguistics]], [[corpus linguistics]],  [[semiotics]]. 
+
+----
+Inter-disciplinary linguistic research:
+
+[[historical linguistics]], [[Orthography]], [[Writing Systems]], [[comparative linguistics]],  [[cryptanalysis]], [[decipherment]], [[sociolinguistics]], [[psycholinguistics]], [[language acquisition]], [[evolutionary linguistics]], [[anthropological linguistics]], [[stratificational linguistics]], [[cognitive science]], [[neurolinguistics]], automated [[speech recognition|speech]] and [[speaker recognition]], or more generally, [[speech processing]]
+
+----
+
+Linguists generally see language as having several [[linguistics layers]], and assume that all natural languages have the same number of layers.
+
+
+A speaker of English recognizes that "make" is a different word from "makes", so the s-suffix is a distinct morpheme.  This example also illustrates the two kinds of morphemes, unbound (which are meaningful on their own) and bound (which have meaning when combined with another morpheme).  Thus, the word "schoolyard" consists of two unbound morphemes ("school" and "yard"), while the word "morpheme" consists, or traditionally consisted, of two bound morphemes ("morph" and "eme").  As the example of "morpheme" reveals, bounded morphemes may become unbounded: "morph" has been adopted in linguistics for the phonological realization of a morpheme, and the verb "morph" was coined to describe a type of visual effect done with computers.
+
+
+A morpheme may have different realizations (morphs) in different contexts. For example, the verb morpheme "do" of English has three quite distinct pronunciations in the words "do", "does", (with suffix "-s"), and "don't" (with "-n't"). Such alternating morphs of a morpheme are called its allomorphs.
+
+Patterns of combinations of words of a language are known as [[syntax]]. The term grammar usually covers syntax plus [[Morphology in linguistics |morphology]], the study of word formation.
+
+[[Semantics]] is the study of the meanings of words and of syntactic constructions.
+
+
+[[Noam Chomsky|Noam Chomsky's]] formal model of language, [[transformational-generative grammar]], developed under the influence of his teacher [[Zellig Harris]], who was in turn strongly influenced by Bloomfield, has been the dominant one from the [[1960s]].
+* [[Transformational-generative grammar]]
+
+* [[cognitive linguistics]]
+
+A few of the important figures in this movement are [[Michael Halliday]], whose [[systemic-functional grammar]] is pursued widely in the [[United Kingdom|U.K.]], [[Canada]], [[Australia]], [[China]], and [[Japan]]; [[Dell Hymes]], who developed a pragmatic approach called The Ethnography of Speaking; [[George Lakoff]], [[Len Talmy]], and [[Ronald Langacker]], who were pioneers in cognitive linguistics; [[Charles Fillmore]] and [[Adele Goldberg]], who are associated with [[construction grammar]]; and linguists developing several varieties of what they call functional grammar, including [[Talmy Givon]] and [[Robert Van Valin, Jr.]]
+
+One speaks also of [[philology]].
+
+Representation of speech:
+
+* [[International Phonetic Alphabet]] (IPA), a system used to write down and reproduce the sounds of human speech.
+* [[SAMPA]], an [[ASCII]]-only transcription for the IPA used by some authors. See also http://www.phon.ucl.ac.uk/home/sampa/home.htm
+
+----
+See also: [[famous linguists]], [[history of linguistics]], [[linguist]], [[structuralism]]
+
diff --git a/testsuite/data/Literature.txt b/testsuite/data/Literature.txt
new file mode 100644 (file)
index 0000000..f19bf30
--- /dev/null
@@ -0,0 +1,68 @@
+[[de:Literatur]][[eo:Literaturo]][[fr:Littérature]][[nl:Literatuur]][[pl:Literatura]][[pt:Literatura]][[es:literatura]]
+'''Literature''' is literally "an acquaintance with letters" (as in the first sense given in the [[Oxford English Dictionary]]), but has generally come to identify a collection of [[text]]s. Nations can have literatures, as can corporations, philosophical schools or historical periods. It is commonly held that a literature of a nation, for example, is the collection of texts which make it a whole nation. The [[Hebrew]] [[Bible]], [[Beowulf]], the [[Iliad]] and the [[Odyssey]] and the [[American]] [[Constitution]] all fall within this definition of a kind of literature. More generally, a literature is equated with a collection of stories, poems and plays that revolve around a particular topic. In this case, the stories, poems and plays may or may not have nationalistic implications. The [[Western Canon]] is one such literature.
+
+Classifying a specific item as being part of a literature (be it [[American literature]], advertising literature, [[gay and lesbian literature]] or [[Roman literature]]) is very difficult. To some people, "literature" can be broadly applied to any symbolic record which can include images, [[sculpture]]s, as well as letters. To others, a literature must only include examples of text composed of letters, or other narrowly defined examples of symbolic written language ([[hieroglyph]]s, for example). Even more conservative  interpreters of the concept would demand that the text have a physical form, usually on paper or some other portable form, to the exclusion of inscriptions or digital media.
+
+Frequently, these boundaries are crossed by the texts that make up literature. Illustrated stories, [[hypertext]]s, cave paintings and inscribed monuments have all at one time or another pressed the boundaries of what is and is not literature.
+
+=== Forms of literature ===
+A [[short story]] is prose writing of less than 20,000 words (and usually more than 500 words) which may or may not have a narrative arc.  If a fiction story is more than 20,000 (appox.) words it is called a [[novella]].  Beyond that, say into the 50,000 (approx.) word range and above, a fiction text is called a [[novel]].
+
+An [[essay]] is a discussion of a topic from an author's personal point of view.  A [[memoir]] is the story of an author's life from his personal point of view.  An [[epistle]] is reserved for formal, didactic, or elegant [[letter]]s.
+
+[[Comic]]s are generally illustrated pictures with explanatory text added for character lines and story commentary.
+
+A [[poem]] is a metrical composition; a composition in verse written in certain measures, whether in blank verse or in rhyme, and characterized by imagination and poetic diction.
+
+A [[play]] is a common literary form comprised chiefly of dialog between characters, usually intendeded for [[theatre]] performance rather than reading.
+
+=== Genres of literature ===
+:[[Alternate history]]
+:[[Autobiography]]
+:[[Bildungsroman]]
+:[[Biography]]
+:[[Children's literature]]
+:[[Constrained writing]] 
+:[[diary|Diaries and Journals]]
+: FICTION:
+:[[Detective fiction|Detective]]
+:[[Family Saga]]
+:[[Fantasy fiction|Fantasy]]
+:[[Gothic Literature|Gothic]]
+:[[Historic fiction|Historic]] 
+:[[Horror fiction|Horror]]
+:[[Legal Drama]]
+:[[Mystery fiction|Mystery]]
+:[[Romance fiction|Romance]]
+:[[Satire]]
+:[[Science fiction]]
+:The [[Slave narrative]]
+:[[Spy/political]]
+:[[Western]]
+
+=== Literary techniques ===
+:[[Epistolary novel]]
+:[[First-person narrative]]
+:[[Omniscient narrator]]
+:[[Story within a story]]
+:[[Flashback]]
+:[[Fictional guidebook]]
+:[[False document]]
+:[[Lipogram]]
+
+=== Literary figures ===
+:[[Critic]]s
+:[[Dramatist]]s
+:[[Essayist]]s
+:[[Journalist]]
+:[[Novelist]]s
+:[[Poet]]s
+:[[Short story author]]s
+
+'''Literary movements'''
+
+Also see [[Cultural movement]] for literary movements.
+
+See also:
+*[http://www.HavenWorks.com/books Free Books &amp; Book Reviews Online:] http://www.HavenWorks.com/books
+
diff --git a/testsuite/data/Magics.txt b/testsuite/data/Magics.txt
new file mode 100644 (file)
index 0000000..1bfe734
--- /dev/null
@@ -0,0 +1,6 @@
+Wiki magic links test:
+
+(1) ISBN 1234567890
+
+(2) RFC 2822
+
diff --git a/testsuite/data/Main_Page.txt b/testsuite/data/Main_Page.txt
new file mode 100644 (file)
index 0000000..9b3f4e8
--- /dev/null
@@ -0,0 +1,20 @@
+[[en:Main Page]]  [[eo:Hejmpagxo]] [[es:Portada]] [[fr:HomePage]] [[it:HomePage]] [[nl:Hoofdpagina]] [[pl:Polska Wikipedia]] [[pt:HomePage]]
+== Testing ... ==
+
+This is a test site for Wiki software.
+The real Wikipedia is at http://www.wikipedia.org .
+
+----
+
+:'''Philosophy, Mathematics, and Natural Science'''
+:[[Astronomy and astrophysics]] - [[Biology]] - [[Chemistry]] - [[Earth science]] - [[Mathematics]] - [[Philosophy]] - [[Physics]] - [[Statistics]]
+
+:'''Social Sciences'''
+:[[Anthropology]] - [[Archaeology]] - [[Economics]] - [[Geography]] - [[History]] - [[History of science and technology]] - [[Language]] - [[Linguistics]] - [[Political science]] - [[Psychology]] - [[Sociology]]
+
+:'''Applied Arts and Sciences'''
+:[[Agriculture]] - [[Architecture]] - [[Business and industry]] - [[Communication]] - [[Computer science|Computer Science]] - [[Education]] - [[Engineering]] - [[Family and consumer science]] - [[Health science]] - [[Law]] - [[Library and information science]] - [[Public affairs]] - [[Technology]] - [[Transport]]
+
+:'''Culture'''
+:[[Classics]] - [[Cooking]] - [[Critical theory]] - [[Dance]] - [[Entertainment]] - [[Film]] - [[Game]]s - [[Handicraft]] - [[Hobby|Hobbies]] -  [[Literature]] - [[Music]] - [[Opera]] - [[Painting]] - [[Recreation]] - [[Religion]] - [[Sculpture]] - [[Sport]]s - [[Theater]] - [[Tourism]] - [[Visual arts and design]]
+
diff --git a/testsuite/data/Mathematics.txt b/testsuite/data/Mathematics.txt
new file mode 100644 (file)
index 0000000..b3a3003
--- /dev/null
@@ -0,0 +1,59 @@
+[[de:Mathematik]][[eo:Matematiko]][[fr:Mathématiques]][[nl:Wiskunde]][[no:Matematikk]][[pl:Matematyka]][[pt:Matemática]][[sh:Matematika]][[sl:Matematika]]
+'''Mathematics''' ([[Greek language|Greek]] ''mathema'': science, learning; ''mathematikos'': fond of learning) is the study of patterns of quantity, structure, change and space. In the modern view, it is the investigation of [[axiom]]atically defined abstract structures using formal [[symbolic logic|logic]] as the common framework. The specific structures investigated often have their origin in the natural sciences, most commonly in [[physics]], but mathematicians also define and investigate structures for reasons purely internal to mathematics, for instance because they realize that the structure provides a unifying generalization for several subfields or a helpful tool in common calculations.
+
+Historically, mathematics arose out of the need to do calculations in commerce, to measure land and to predict astronomical events. These three needs can be roughly related to the broad subdivision of mathematics into the study of structure, space and change.
+
+The study of structure starts with [[number]]s, initially the familiar [[natural number]]s and [[integer]]s. The rules governing arithmetical operations are recorded in [[elementary algebra]], and the deeper properties of whole numbers are studied in [[number theory]]. The investigation of methods to solve equations leads to the field of [[abstract algebra]], which, among other things, studies [[ring (algebra)|rings]] and [[field]]s, structures that generalize the properties possessed by the familiar numbers. The physically important concept of [[vector]], generalized to [[vector space]]s and studied in [[linear algebra]], belongs to the two branches of structure and space.
+
+The study of space originates with [[geometry]], first the [[Euclidean geometry]] and [[trigonometry]] of familiar three-dimensional space, but later also generalized to [[Non-euclidean geometry|non-Euclidean geometries]] which play a central role in [[general relativity]]. The modern fields of [[differential geometry]] and [[algebraic geometry]] generalize geometry in different directions: differential geometry emphasizes the concepts of coordinate system, smoothness and direction, while in algebraic geometry geometrical objects are described as solution sets of equations. [[Mathematical group|Group theory]] investigates the concept of symmetry abstractly and provides a link between the studies of space and structure. [[Topology]] connects the study of space and the study of change by focusing on the concept of [[continuous|continuity]]. 
+
+Understanding and describing the change in measurable quantities is the central topic of the natural sciences, and [[calculus]] was developed as a most useful tool for doing just that. The central concept used to describe a changing variable is that of a [[function]]. Many problems lead quite naturally to relations between a quantity and its rate of change, and the methods to solve these are studied in the field of [[differential equations]]. The numbers used to represent continuous quantities are the [[real numbers]], and the detailed study of their properties and the properties of real-valued functions is known as [[real analysis]]. For several reasons, it is convenient to generalise to the [[complex number]]s which are studied in [[complex analysis]]. [[Functional analysis]] focuses attention on (typically infinite-dimensional) spaces of functions, laying the groundwork for [[quantum mechanics]] among many other things.
+
+In order to clarify and investigate the foundations of mathematics, the fields of [[set theory]], [[mathematical logic]] and [[model theory]] were developed. 
+
+When [[computer]]s were first conceived, several surrounding theoretical questions were tackled by mathematicians, leading to the fields of [[computability theory]], [[computational complexity theory]], [[information theory]] and [[algorithmic information theory]]. Many of these questions are now investigated in theoretical [[computer science]].
+
+Computers also aided the new field of [[chaos theory]], which deals with the fact that many [[dynamical systems]] in nature obey laws that cause their behaviour to become unpredictable in practice, though deterministic in theory.
+Chaos theory is closely related to [[fractal]] geometry.
+
+An important field in applied mathematics is [[probability and statistics]], which allows the description, analysis and prediction of random phenomena and is used in all sciences. [[Numerical analysis]] investigates the methods for performing calculations on computers and [[discrete mathematics]] is the common name for those fields of mathematics useful in computer science.
+
+This following list of subfields and topics reflects one organizational view of mathematics:
+
+:'''Quantity'''
+:[[Number]]s -- [[Natural number]]s -- [[Integer]]s -- [[Rational number]]s -- [[Real number]]s -- [[Complex number]]s -- [[Quaternion]]s -- [[Octonion]]s -- [[Sedenion]]s -- [[Hyperreal number]]s -- [[Surreal number]]s -- [[Ordinal number]]s -- [[Cardinal number]]s -- [[p-adic number]]s -- [[Integer sequence]]s -- [[Mathematical constant]]s -- [[Number names]] -- [[Infinity]]
+
+:'''Change'''
+:[[Calculus]] -- [[Vector Calculus|Vector calculus]] -- [[Mathematical analysis|Analysis]] -- [[Differential equation]] -- [[Dynamical systems and chaos theory]] -- [[List of functions]]
+
+:'''Structure'''
+:[[Abstract algebra]] -- [[Number theory]] -- [[Algebraic geometry]] -- [[Mathematical group|Group theory]] -- [[Monoid]]s -- [[Mathematical analysis|Analysis]] -- [[Topology]] -- [[Linear algebra]] -- [[Graph theory]] -- [[Universal algebra]] -- [[Category theory]]
+
+:'''Space'''
+:[[Topology]] -- [[Geometry]] -- [[Trigonometry]] -- [[Algebraic geometry]] -- [[Differential geometry]] -- [[Differential topology]] -- [[Algebraic topology]] -- [[Linear algebra]]
+
+:'''[[Discrete mathematics|Finite Mathematics]]'''
+:[[Combinatorics]] -- [[Basic set theory]] -- [[Probability and statistics]] -- [[Computation|Theory of computation]] -- [[Discrete mathematics]] -- [[Cryptography]] -- [[Graph theory]] -- [[Game theory]]
+
+:'''[[Applied mathematics|Applied Mathematics]]'''
+:[[Mechanics]] -- [[Numerical analysis]] -- [[Optimization (mathematics)|Optimization]] -- [[Probability and statistics]] 
+
+:'''Famous Theorems and Conjectures'''
+:[[Fermats Last Theorem|Fermat's last theorem]] -- [[Riemann hypothesis]] -- [[Continuum hypothesis]] -- [[Complexity classes P and NP|P=NP]] -- [[Goldbachs conjecture|Goldbach's conjecture]] -- [[Twin Prime Conjecture]] -- [[Goedel's incompleteness theorem|G&ouml;del's incompleteness theorems]] -- [[Poincare conjecture|Poincar&eacute; conjecture]] -- [[Cantor's diagonal argument]] -- [[Pythagorean Theorem|Pythagorean theorem]] -- [[Central limit theorem]] -- [[Fundamental Theorem of Calculus|Fundamental theorem of calculus]] -- [[Fundamental Theorem of Algebra|Fundamental theorem of algebra]] -- [[Four color theorem]] -- [[Zorns lemma|Zorn's lemma]] -- [[The most remarkable formula in the world|"The most remarkable formula in the world"]]
+
+:'''Foundations and Methods'''
+:[[Philosophy of mathematics]] -- [[Mathematical intuitionism]] -- [[Mathematical constructivism]] -- [[Foundations of mathematics]] -- [[Set theory]] -- [[Symbolic logic]] -- [[Model theory]] -- [[Category theory]] -- [[Theorem-proving]]
+
+:'''History and the World of Mathematicians'''
+
+:[[History of mathematics]] -- [[Timeline of mathematics]] -- [[Mathematician|Mathematicians]] -- [[Fields Medal|Fields medal]] -- [[Millennium Prize Problems|Millennium Prize Problems (Clay Math Prize)]] -- [[International Mathematical Union]] -- [[Mathematics Competitions|Mathematics competitions]]
+
+----
+'''Further Reading:'''
+* Davis, Philip J.; Hersh, Reuben: ''The Mathematical Experience''. Birkhäuser, Boston, Mass., 1980. A gentle introduction to the world of mathematics.
+* Rusin, Dave: ''The Mathematical Atlas'', http://www.math-atlas.org. A tour through the various branches of modern mathematics.
+* Weisstein, Eric: ''World of Mathematics'', http://www.mathworld.com. An online encyclopedia of mathematics.
+* ''Planet Math'', http://planetmath.org. An online math encyclopedia under construction. Uses the [[GFDL]] license, allowing article exchange with Wikpedia. Uses [[TeX]] markup.
+* Mathematical Society of Japan: ''Encyclopedic Dictionary of Mathematics, 2nd ed.''. MIT Press, Cambridge, Mass., 1993. Definitions, theorems and references.
+* Michiel Hazewinkel (ed.): ''Encyclopaedia of Mathematics''. Kluwer Academic Publishers 2000. A translated and expanded version of a Soviet math encyclopedia, in ten (expensive) volumes, the most complete and authorative work available. Also in paperback and on CD-ROM.
+
diff --git a/testsuite/data/Music.txt b/testsuite/data/Music.txt
new file mode 100644 (file)
index 0000000..64913f2
--- /dev/null
@@ -0,0 +1,19 @@
+[[de:Musik]][[eo:Muziko]][[fr:Musique]][[nl:Muziek]][[pl:Muzyka]][[pt:Música]]
+Broadly speaking, '''music''' is any artful or entertaining arrangement of [[sound|sounds]], deliberate or otherwise. The actual [[definition of music]] is hotly contested.
+
+We can define "music" more formally as a series of organized sounds and silences temporal in nature, which those who know it can reproduce.
+
+All music also has some varying degree of [[rhythm]] and [[melody]]. [[Harmony]] is often added.
+The following are [[Music basic topics|music-related topics]]:
+
+* [[Musician]]
+* [[Musical ensemble]]
+* [[Musical instrument]]
+* [[Musical genre]]
+* [[Music theory]]
+* [[Music history]]
+* [[Musical tuning]]
+* [[Sound reproduction]]
+
+The academic study of music is called [[Musicology]].
+
diff --git a/testsuite/data/Opera.txt b/testsuite/data/Opera.txt
new file mode 100644 (file)
index 0000000..0cb9e27
--- /dev/null
@@ -0,0 +1,44 @@
+'''Opera''' (or '''Melodramma''') is an [[art]] form that consists of a stage performance of a [[drama]] (whose text is called the "[[libretto]]").
+
+The drama is presented utilizing [[scenery]], [[costume]]s, [[acting]].  Much of the [[dialogue]] is presented through [[singing]]:  [[Recitative]] is singing in much the form of speaking, [[aria]] is an extended solo passage. Arioso is a smaller, more limited in subject matter aria. 
+
+In opera, [[Voice]]s represent perhaps the most important (or the more famous) [[musical instrument|instruments]], and [[singers]] (and roles) are classified depending on their respective pitches.
+
+Opera draws from many other art forms. Its backbone is certainly [[music]], it is performed with dialoges, so it is a [[drama]] with music, on a stage, so [[decorative art]]s are important, as is [[dance]], which sometimes appears in it. [[Giuseppe Verdi]] used to call it: the art of ''recitar cantando''.
+
+----
+
+==== History ====
+Opera began in [[Italy]] in the [[Renaissance]], as an attempt to revive Classical Greek drama. Opera means simply "work" in [[Italian]]. The first opera was written around [[1597]] in Northern Italy, sources differ on the exact date and place.
+
+For centuries, Italian opera was the standard form, and many operas written by English- or German-speaking composers, [[Wolfgang Amadeus Mozart|Mozart]], for example, are in [[Italian]]. A separate French tradition, sung in [[French]], was founded by [[Jean-Baptiste Lully]], and well into the middle of the nineteenth century, operas performed in [[France]] were usually written or translated into French. [[Spain]] produced its own distinctive form: [[zarzuela]].
+
+The form of the opera consists of several sung pieces, ([[aria]]s), separated by recitation over accompaniment. Recitation in opera is a form of singing intermediate between ordinary [[melody|melodic]] singing and formal spoken [[recitation]].
+
+Early operas consisted of recitative accompanied only by [[basso continuo]] and arias accompanied by full [[orchestra]]. Later operas involved the full orchestra throughout the opera to provide a smoother transition between parts. 
+
+This change reached a climax when [[Richard Wagner]] introduced the idea of the ''Gesamtkunstwerk'' or the ''Total Work of Art'', where the action is continued, with no stops or repetitions, and the music is a continuous flux, not a few pieces separated
+by recitatives. Wagner also introduced [[leitmotif]], where each character or idea in the story is represented by a musical line that appears whenever they appear or are mentioned.
+
+The themes of the opera at the beginning were mythological or historical, usually tragic and moral.  Later, composers introduced more everyday themes.  
+
+==== Famous Opera Composers ====
+See [[List of opera composers]]
+==== Famous Operas ====
+See [[List of famous operas]]
+
+==== Famous Theatres ====
+
+*[[La Scala, theatre|La Scala, Milan]]
+*[[La Fenice, Venice]]
+*[[San Carlo, Naples]]
+*[[Teatro Regio, Parma]]
+*[[Arena, Verona]]
+*[[Sydney Opera House]]
+
+----
+See also [[operetta]], [[musical]], [[singspiel]], [[zarzuela]].
+----
+
+''Opera'' is also the name of a popular alternative [[web browser]]; see '''[[Opera browser]]'''
+
diff --git a/testsuite/data/Painting.txt b/testsuite/data/Painting.txt
new file mode 100644 (file)
index 0000000..955c799
--- /dev/null
@@ -0,0 +1,60 @@
+[[Painting techniques]] include: 
+:[[Impasto]]
+:[[Wash]], drip
+:[[Glaze]]
+:[[Encaustic painting|Encaustic]]
+:[[Fresco]]
+:scumble and stipple
+The [[medium]] is the vehicle that the pigment is suspended or embedded in.  Examples include: 
+:[[Oil painting]]
+:Water-miscible oils
+:Heat-set oils
+:[[Acrylic paint]]
+:[[Colored pencil]]
+:[[Gouache]]
+:[[Ink]]
+:[[Pastel]]
+:[[Tempera]]
+:[[Encaustic painting|wax]]
+:[[Watermedia painting]]
+[[Painting styles]] can be characterized by the method of application (loose or tight) or by the predominant characteristics that the painting expresses.
+:[[Painting tools]] include the various types of:
+:[[Artists brush]]
+:[[Palette knife]]
+:sponge
+:fingers
+:[[Paint]] is made up of [[pigment]] and [[Painting medium|media]], with perhaps drying accelerants, texture enhancers, and other modifiers added.
+''(What's this list supposed to be listing?)''
+:[[Mural]]
+:[[New materials (painting)]]
+:[[Tempera]]
+:[[Oil painting]]
+:[[Panel painting]]
+
+For historical and contemporary movements in painting, see [[History of painting]].
+
+You can also see a list of artistic [[Painters]].
+
+Recently, [[computer painting]] is rapidly becoming a tool of modern painters.
+
+A proposed and yet-unrealised development in painting is [[four dimensional painting]].
+----
+External links to art-related sites (sources of information for writing Wikipedia articles):
+:http://www.metmuseum.org/
+:http://www.moma.org/docs/menu/index.htm
+:http://www.artchive.com/
+:http://www.rmn.fr/US/index2.html
+:http://www.sensable.com/
+:http://www.virtualberet.org/
+:http://www.bostoncyberarts.org/splash.html
+:http://www.walkerart.org/
+:http://www.stunned.org/
+:http://www.NextMonet.com/
+:http://www.internationalposter.com/
+:http://www.bertimosaici.com/
+:http://www.musee-orsay.fr:8081/ORSAY/ORSAYGB/HTML
+:http://frick.org/
+:http://artmuseum.net/
+:http://www.groveart.com/
+
+
diff --git a/testsuite/data/Philosophy.txt b/testsuite/data/Philosophy.txt
new file mode 100644 (file)
index 0000000..c48ed98
--- /dev/null
@@ -0,0 +1,206 @@
+[[de:Philosophie]][[eo:Filozofio]][[nl:Filosofie]][[pl:Filozofia]][[it:filosofia]]
+The definition of '''philosophy''' is a philosophical question in its own right. But for purposes of introducing the concept, we can say that, approximately, it is the study of the meaning and justification of beliefs about the most general, or universal, aspects of things--a study which is carried out not by experimentation or careful observation, but instead typically by formulating problems carefully, offering solutions to them, giving arguments for the solutions, and engaging in the [[dialectic]] about all of the above.  Philosophy studies such concepts as [[existence]], [[goodness]], [[knowledge]], and [[beauty]].  It asks questions such as "What is goodness, in general?" and "Is knowledge even possible?" Famous philosophers include [[Plato]], [[Aristotle]], [[Rene Descartes]], [[John Locke]], and [[Immanuel Kant]].
+
+Popularly, the word "philosophy" is often used to mean any form of wisdom, or any person's perspective on life (as in "philosophy of life") or basic principles behind or method of achieving something (as in "my philosophy about driving on highways").  That is different from the academic meaning, and it is the academic meaning which is used here. 
+
+Originally, "philosophy" meant simply "the love of wisdom".  Philo- comes from the Greek word ''philein'', meaning to love, and -sophy comes from the Greek ''sophia'', or wisdom. "Philosopher" replaced the word "sophist" (from ''sophoi''), which was used to describe "wise men", teachers of [[rhetoric]], which were important in [[Athenian democracy]].  Some of the first ''[[sophist]]s'' were what we would now call philosophers.
+
+Originally the scope of philosophy was all intellectual endeavor.  It has long since come to mean the study of an especially abstract, nonexperimental intellectual endeavor.  In fact, ''philosophy'' is itself a notoriously difficult word to define; the question "What is philosophy?" is itself, famously, a vexed philosophical question.  It is often observed that philosophers are unique in the extent to which they disagree about what their field even ''is''.
+
+The introduction of the term philosophy was ascribed to the Greek thinker [[Pythagoras]] (see [[Diogenes Laertius]]: "De vita et moribus philosophorum", I, 12; [[Cicero]]: "Tusculanae disputationes", V, 8-9).  This ascription is certainly based on a passage in a lost work of [[Herakleides Pontikos]], a disciple of [[Aristotle]].  It is considered to be part of the widespread Pythagoras legends of this time.  In fact the term philosophy was not in use long before [[Plato]].
+
+For further considerations about the very notion of philosophy, please see [[definition of philosophy]].
+
+=== [[History of philosophy]] ===
+
+Philosophers divide the long history of Western philosophy into [[ancient philosophy]], [[medieval philosophy]], [[modern philosophy]], and [[contemporary philosophy]].  [[Ancient philosophy]] was dominated by the trio of [[Socrates]], [[Plato]], and [[Aristotle]].  In [[medieval philosophy]], topics in metaphysics and philosophy of religion held sway, and the most important names included [[Duns Scotus]], [[Peter Abelard]], and [[Aquinas]].  [[Modern philosophy]] generally means philosophy from 1600 until about 1900, and which includes many distinguished [[Early modern philosophy|early modern philosophers]], such as [[Rene Descartes|Ren&eacute; Descartes]], [[Thomas Hobbes]], [[John Locke]], [[David Hume]], and [[Immanuel Kant]].  [[Nineteenth-century philosophy]] is often treated as its own period, as it was dominated by [[post-Kantian philosophy|post-Kantian]] German and idealist philosophers like [[Georg Wilhelm Friedrich Hegel|G. W. F Hegel]], [[Karl Marx]], and [[F. H. Bradley]]; two other important thinkers were [[John Stuart Mill]] and [[Friedrich Nietzsche]].
+
+In the [[twentieth-century philosophy|twentieth century]], philosophers in Europe and the United States took diverging paths.  The so-called [[analytic philosophy|analytic philosophers]], including [[Bertrand Russell]], [[G. E. Moore]], and [[Ludwig Wittgenstein]], were centered in [[Oxford]] and [[Cambridge]], and were joined by logical empiricists emigrating from Austria and Germany (for example, [[Rudolf Carnap]]) and their students and others in the United States (such as, [[W. V. Quine]], [[Donald Davidson]], and [[Saul Kripke]], and other English-speaking countries (for example, [[A. J. Ayer]]).
+
+On the [[Continental philosophy|continent of Europe]] (especially Germany and France), the [[phenomenology|phenomenologist]] Germans [[Edmund Husserl]] and [[Martin Heidegger]] led the way, followed soon by [[Jean-Paul Sartre]] and other [[existentialism|existentialists]]; this led via other "[[isms]]" to [[postmodernism]], which dominates schools of [[critical theory]] as well as philosophy departments in France and Germany, which continue the projects that these philosophers have pursued. 
+
+Please see our more exhaustive list of [[Philosopher|philosophers]] as well as the [[history of philosophy]] article, from which the above was taken.
+
+=== [[Philosophical subdisciplines]] ===
+
+As with any field of academic study, philosophy has a number of subdisciplines.  Philosophy in fact seems to have a huge number of subdisciplines, in no small part due to the fact that there tends to be a "philosophy of" nearly everything else that is studied.  Those new to philosophy are usually invited particularly to pay attention to [[logic]], [[metaphysics]], [[philosophy of mind]], [[philosophy of language]], [[epistemology]], [[philosophy of science]], [[ethics]], and [[political philosophy]] as--arguably, of course--the "central disciplines" of philosophy.
+
+*[[Aesthetics]]: the study of basic philosophical questions about [[art]] and [[beauty]].  Sometimes [[philosophy of art]] is used to describe only questions about art, with "aesthetics" the more general term.
+*[[Epistemology]]: the study of [[knowledge]], its nature, [[skepticism|possibility]], and [[epistemic justification|justification]].
+*[[Ethics]]: the study of what makes actions right or wrong, and of how theories of [[right action]] can be applied to special moral problems.  Subdisciplines include [[meta-ethics]], [[value theory]], [[theory of conduct]], and [[applied ethics]].
+*[[History of philosophy]]: the study of what philosophers up until recent times have written, its interpretation, who influenced whom, and so forth.  The bulk of questions in history of philosophy are interpretive questions.
+*[[Logic]]: the study of the standards of correct [[argument|argumentation]]. Includes [[formal logic]], such as [[Aristotelian Syllogisms]] and [[propositional logic]].
+*[[Meta-philosophy]]: the study of [[philosophical method]] and the goals of philosophy.  The term "philosophy of philosophy" is sometimes used more or less as a synonym.
+*[[Metaphysics]] (which includes [[ontology]]): the study of the most basic [[category|categories]] of things, such as [[existence]], [[object]]s, [[property|properties]], [[causality]], and so forth.  Metaphysics often is taken to include questions now studied by other philosophical subdisciplines, such as [[the mind-body problem]] and [[free will and determinism]].
+*[[Philosophy of biology]]: the philosophical study of some basic concepts of biology, including the notion of a [[species]] and whether biological concepts are reducible to nonbiological concepts.
+*[[Philosophy of education]]: the study of the purpose and most basic methods of education or learning.
+*[[Philosophy of language]]: the study of the concepts of [[meaning]] and [[truth]].
+*[[Philosophy of mathematics]]: the study of philosophical questions raised by mathematics, such as, what numbers are, and what the nature and origins of our [[mathematics|mathematical]] knowledge are.
+*[[Philosophy of mind]]: the philosophical study of the nature of the [[mind]], and its relation to the [[body]] and the rest of the world.
+*[[Philosophy of perception]]: the philosophical study of topics related to perception; the question what the "immediate objects" of perception are has been especially important.
+*[[Philosophy of physics]]: the philosophical study of some basic concepts of physics, including [[space]], [[time]], and [[force]].
+*[[Philosophy of psychology]]: the study of some fundamental questions about the methods and concepts of psychology and psychiatry, such as the meaningfulness of [[Sigmund Freud|Freudian]] concepts; this is sometimes treated as including philosophy of mind.
+*[[Philosophy of religion]]: the study of the meaning of the concept of [[God]] and of the rationality of belief in the existence of God.
+*[[Philosophy of science]]: includes not only, as subdisciplines, the "philosophies of" the special sciences (i.e., physics, biology, etc.), but also questions about induction, [[scientific method]], scientific progress, etc.
+*[[Philosophy of social sciences]]: the philosophical study of some basic concepts, methods, and presuppositions of social sciences such as sociology and economics.
+*[[Political philosophy]]: the study of basic topics concerning [[government]], including the purpose of [[the state]], political [[justice]], [[political freedom]], the nature of law, and [[the justification of punishment]].
+* [[Value theory]]: the study of the concept [[value]].  Also called [[theory of value]].  Sometimes this is taken to be equivalent to [[axiology]] (a term not in as much currency in the English-speaking world as it once was), and sometimes is taken to be, instead of a foundational field, an overarching field including ethics, aesthetics, and political philosophy, i.e., the philosophical subdisciplines that crucially depend on questions of value.
+
+=== How to get started in philosophy ===
+
+It is a platitude (at least among people who write introductions to philosophy) that everybody has a philosophy, though they might not all realize it or be able to defend it.  If you're already interested in studying philosophy, your reason might be to improve the way you live or think somehow, or you simply wish to get acquainted with one of the most ancient areas of human thought.  On the other hand, if you don't see what all the fuss is about, it might help to read [[the motivation to philosophize]], which explains what motivates many people to "do philosophy", and get an [[Philosophical method/Introduction|introduction to philosophical method]], which is important to understanding how philosophers think.  It might also help to acquaint yourself with some considerations about [[definition of philosophy|just what philosophy is]].
+
+=== Applied philosophy ===
+
+Philosophy has applications.  The most obvious applications are those in [[ethics]]--[[applied ethics]] in particular--and in [[political philosophy]].  The political philosophies of [[John Locke]], [[Jean-Jacques Rousseau]], [[Karl Marx]], and [[John Stuart Mill]] have shaped and been used to justify governments and their actions.  [[Philosophy of education]] deserves special mention, as well; [[progressive education]] as championed by [[John Dewey]] has had a profound impact on educational practices in the United States in the twentieth century.
+
+Other important, but less immediate applications can be found in [[epistemology]], which might help one to regulate one's notions of what knowledge, evidence, and justified belief are.  [[Philosophy of science]] discusses the underpinnings of the [[scientific method]], among other topics sometimes useful to scientists.  [[Aesthetics]] can help to interpret discussions of art.  Even [[ontology]], surely the most abstract and least practical-seeming branch of philosophy, has had important consequences for [[logic]] and [[computer science]].  In general, the various "philosophies of", such as [[philosophy of law]], can provide workers in their respective fields with a deeper understanding of the theoretical or conceptual underpinnings of their fields.  
+
+Moreover, recently, there has been developing a burgeoning profession devoted to applying philosophy to the problems of ordinary life: [[philosophical counseling]].
+
+=== Philosophy vs. natural science ===
+
+On the view of some in the (loosely described) [[Anglo-American philosophy|Anglo-American philosophical tradition]] and the closely-related tradition of the [[Vienna Circle]], philosophy ought to emulate the exact methods of [[science]] and [[mathematics]].  But strictly speaking, philosophy is to be distinguished from science.  It is not, at least, part of philosophy to do [[experiment]]s.  Experiments play little, if any, role in the solution of [[philosophical problems]].  Someone might object to this, if he knows much about the intersection of philosophy and science.  Philosophers are often referring to and interpreting the scientific work of [[physics|physicists]], who do experiments about [[space and time]] and [[quantum mechanics]] (see [[philosophy of physics]]).  They are often referring to experimental work done in [[psychology]] when they discuss philosophy of psychology (see [[philosophy of psychology]]).  In general, many philosophers who study [[philosophy of science]] are trained scientists.
+
+There is no doubting that philosophers sometimes ''interpret'' and ''refer to'' experimental work of various kinds--especially in the philosophies of the so-called "[[special sciences]]", as in philosophy of physics and philosophy of psychology.  But this is not surprising: the purpose of those branches of philosophy, branches like philosophy of physics, is to help interpret the ''philosophical'' aspects of experimental work.  It is not the philosophers, in their capacities as philosophers, who do the experiments and who formulate explanatory theories of experimentally-tabulated facts.
+
+There is a basic historical reason why philosophy is not experimental.  Originally, the scope of philosophy was all abstract intellectual endeavor.  Even up to early modern times, the people we now call "scientists" were referred to as "natural philosophers", i.e., philosophers who study nature.  Over the years--it is very commonly observed--the scope of philosophy has gotten smaller and smaller, as different sciences have spun off and become independent disciplines in their own right.  Some relatively early "spin-offs" were physics and chemistry; more recently, psychology has spun off.
+
+One might wonder why scholars began to treat various special sciences as independent from philosophy.  The answer for any given branched-off science is that it began to be prosecuted using rigorous, agreed-upon methods of observation and experimentation.  Philosophy in its core sense, the sense that remains today, is essentially something that one should be able to do from one's armchair, surrounded, at most, by some books and articles that scientists (but certainly other philosophers) write.
+
+Of course, philosophy is far from being totally non-observational or non-empirical.  Certainly philosophy makes essential use of observations about the world.  But they are, we might say, very ''general'' observations, observations like "It seems to me I make free choices" and "It seems to me that killing another person, if ever necessary, requires a really good excuse".  Observations like this ''can'' require careful attention.  But most (not all) philosophical topics require no more ''specialized'' knowledge than the average educated person has, except for specialized knowledge about philosophy itself (such as [[philosophical jargon]]).
+
+Some beginners confuse philosophy and [[psychology]], yet these are different fields.  Philosophy does study the [[mind]], just as psychology does, but it also studies other things ''besides'' the mind, too, about which psychology has nothing to say.  The ways philosophers and psychologists study the mind differ, as well.  The study of the mind involved in doing psychology involves careful, specific observation of particular mental phenomena, and experimentation; by contrast, philosophers think about more general aspects of the mind, questions like, "What is [[consciousness]]?" and "What is the relation between mind and body?"
+
+=== Philosophy vs. religious studies and classics ===
+
+What distinguishes philosophy from religious studies, most of which also is not experimental?  Parts of theology, those which ask about what [[God]] is and how to prove that God exists, clearly overlap with what philosophers call "[[philosophy of religion]]".  That is not a problem.  Similarly, classics, or study of ancient Greece and Rome, studies the Greek philosophers Socrates and Plato, and so classics overlaps with an area of philosophy, namely history of [[Greek philosophy]], to that extent.  That is not a problem either.  Neither of these overlaps muddies the concepts of philosophy, of religious studies, or of classics.
+
+But consider that other part of religious studies, the ''empirical'' part, which often focuses on comparative study of different world religions.  That part of religious studies can be distinguished from philosophy in just the way that any other social science can be distinguished from philosophy.  Namely, it involves specific observations of particular phenomena, here particular religious practices, and philosophy does not.
+
+=== Philosophy vs. mathematics ===
+
+[[Mathematics]] differs from philosophy for other reasons.  It uses some very specific, rigorous methods of proof that philosophers sometimes (only rarely) try to emulate, but rarely, if ever, duplicate with the same degree of rigor.  As a result, mathematicians hardly ever disagree about results, while philosophers of course do disagree about theirs.  Besides, most philosophers do not even try to make their work rigorous in a mathematical sense.  Unlike mathematicians, philosophers disagree about their [[philosophical method|methods]], and their methodological differences can often be used account for their different conclusions.
+
+Another way to distinguish philosophy from mathematics is this.  Math, beyond a certain basic level, requires some ''extremely'' specialized knowledge, which can be obtained only by dint of extremely hard labor and concentration.  It is not the sort of discipline that can be pursued with the knowledge that the average educated person has.  Philosophy usually does require hard labor and concentration, but at least a philosopher can often explain his question, with not ''too'' much difficulty, to an intelligent nonphilosopher in under ten minutes.
+
+=== Some tentative generalizations about what philosophy is ===
+
+So philosophy, it seems, is a discipline that draws on knowledge that the average educated person has, and it does not make use of experimentation and careful observation, though it may interpret philosophical aspects of experiment and observation.
+
+More positively, one might say that philosophy is a discipline that examines the meaning and justification of certain of our most basic, fundamental beliefs, according to a [[philosophical method/Introduction|loose set of general methods]].  But what we might mean by the words "basic, fundamental beliefs"?
+
+A belief is fundamental if it concerns those aspects of the [[universe]] which are ''most commonly'' found, which are found everywhere: the ''universal'' aspects of things.  Philosophy studies, for example, what [[existence]] itself is.  It also studies [[value]]--the [[good]]ness of things--in general.  Surely in human life we find the relevance of value or goodness everywhere, not just moral goodness, though that might be very important, but even more generally, goodness in the sense of anything that is actually desirable, the sense, for example, in which an apple, a painting, and a person can all be good.  (If indeed there is a single sense in which they are all called "good".)
+
+Of course, physics and the other sciences study some very universal aspects of things; but it does so experimentally.  Philosophy studies those aspects that can be studied without experimentation.  Those are aspects of things that are very general indeed; to take yet another example, philosophers ask what physical objects as such are, as distinguished from properties of objects and relations between objects, and perhaps also as distinguished from minds or souls.  Physicists proceed as though the notion of a physical body is quite clear and straightforward--which perhaps in the end it will found to be--but at any rate, physics ''assumes'' that, and then asks questions about how all physical bodies behave, and then does experiments to find out the answers.
+
+----
+
+''Eventually, we would like the following lists introduced properly as separate sections of this article (which is an article-in-progress, of course!).''
+
+'''[[Philosophical theories]]'''
+
+[[altruism]] --
+[[anti-realism]] --
+[[Buddhist philosophy]] --
+[[coherentism]] --
+[[Confucianism]] --
+[[consequentialism]] --
+[[constructivism]] --
+[[deconstructionism]]-- [[Discordianism]] --
+[[egoism]] --
+[[eudaimonism]] --
+[[foundationalism]] --
+[[hedonism]] --
+[[historical materialism]] --
+[[historicism]] --
+[[idealism]] --
+[[irrealism]] --
+[[justified true belief]] --
+[[logical positivism]] --
+[[nominalism]] --
+[[Objectivism]] --
+[[philosophical pessimism]] --
+[[psychological egoism]] --
+[[Platonism]] --
+[[rationalism]] --
+[[realism]] --
+[[reality enforcement]] --
+[[reliabilism]] --
+[[Taoism]] --
+[[Transcendentalism]] --
+[[utilitarianism]] --
+[[Populism and Nationalism]] --
+[[Irrationalism and Aestheticism]] --
+[[Stoicism]] --
+[[Vedic]] --
+[[Epicureanism]] --
+[etc. continue the list please]
+
+:''A long list of unsorted terms culled from [[existentialism]] article -- please sort, arrange, remove duplicates''
+
+[[aesthetic]] 
+[[Aristotelianism]] 
+[[conceptualism]] 
+[[Confucianism]] 
+[[Daoism]] 
+[[deconstruction]] 
+[[deconstructionism]] 
+[[determinism]] 
+[[emic]]
+[[empiricism]] 
+[[empiricist philosophy]]  
+[[esthetic]] 
+[[etic]]
+[[existentialism]] 
+[[existentialist philosophy]] 
+[[formalism]] 
+[[idealism]] 
+[[intuitionism]] 
+[[logicism]] 
+[[materialism]] 
+[[mechanism]] 
+[[mentalism]] 
+[[naive realism]] 
+[[nativism]] 
+[[naturalism]] 
+[[nominalism]] 
+[[operationalism]] 
+[[physicalism]] 
+[[Platonism]] 
+[[pragmatism]] 
+[[probabilism]] 
+[[realism]] 
+[[relativism]] 
+[[scholasticism]] 
+[[semiotics]] 
+[[sensationalism]] 
+[[sensationalism]] 
+[[sensualism]] 
+[[solipsism]] 
+[[Stoicism]] 
+[[subjectivism]] 
+[[Taoism]] 
+[[teleology]] 
+[[traditionalism]] 
+[[vitalism]] 
+
+=== [[Philosophical issues and problems]] ===
+
+[[free will and determinism]] --
+[[faith and rationality]] --
+[[the problem of other minds]] --
+[[problem of the criterion]]
+
+=== [[Philosophical Movements]] ===
+
+[[French materialism]] --
+[[German idealism]] --
+[[Critical philosophy]] --
+[[General Semantics]] --
+[[Existentialism]]
+
+===External Links===
+* [http://plato.stanford.edu/ The Stanford Encyclopedia of Philosophy]
+* [http://www.utm.edu/research/iep/ The Internet Encyclopedia of Philosophy]
+
diff --git a/testsuite/data/Physics.txt b/testsuite/data/Physics.txt
new file mode 100644 (file)
index 0000000..b9d63d6
--- /dev/null
@@ -0,0 +1,87 @@
+[[de:Physik]][[eo:Fiziko]][[fr:Physique]][[nl:Natuurkunde]][[pl:Fizyka]][[pt:Física]][[sl:fizika]]
+'''Physics''' ([[Greek language|Greek]] ''phusis'': nature) is the [[science]] of Nature in the broadest sense. [[physicist|Physicists]] study the behavior and interactions of [[matter]] across [[space]] and [[time]], which are referred to as [[physical phenomenon|physical phenomena]]. [[theory|Theories]] of physics are generally expressed as [[mathematics|mathematical]] relations. Well-established theories are often referred to as ''physical laws'' or [[law of physics|laws of physics]]; however, like all [[scientific method|scientific theories]], they are ultimately provisional.
+
+Physics is closely related to the other [[Natural Sciences|natural sciences]], particularly [[chemistry]], the science of [[molecule|molecules]] and the chemical compounds that they form in bulk. Chemistry draws on many fields of physics, particularly [[quantum mechanics]], [[thermodynamics]] and [[electromagnetism]]. However, chemical phenomena are sufficiently varied and complex that chemistry is usually regarded as a separate discipline. 
+
+Below is an overview of the major subfields and concepts in physics, followed by a brief outline of the history of physics and its subfields.
+
+:'''Central Theories'''
+:[[Classical Mechanics|Classical mechanics]]&nbsp;-- [[Thermodynamics]]&nbsp;-- [[Statistical Mechanics|Statistical mechanics]]&nbsp;--  [[Electromagnetism]]&nbsp;-- [[Special relativity]]&nbsp;-- [[General relativity]]&nbsp;-- [[Quantum mechanics]]&nbsp;-- [[Quantum field theory]] -- [[Standard Model]]
+
+:'''Proposed Theories'''
+:[[Theory of everything]]&nbsp;-- [[Grand unification theory|Grand unified theory]]&nbsp;-- [[M-theory]] -- [[emergent complexity]] -- [[Interpretation of quantum mechanics]]
+
+:'''Concepts'''
+:[[Matter]]&nbsp;-- [[Antimatter]] -- [[Particle|Elementary particle]] -- [[Boson]] -- [[Fermion]]
+
+:[[Symmetry]] -- [[Conservation law]] -- [[Mass]]&nbsp;-- [[Energy]]&nbsp;--[[Momentum]]&nbsp;-- [[Angular momentum]]&nbsp;-- [[Spin (physics)|Spin]]
+
+:[[Time]]&nbsp;-- [[Space]] -- [[Dimension]] -- [[Spacetime]] -- [[Length]]&nbsp;-- [[Velocity]]&nbsp;-- [[Force]]&nbsp;-- [[Torque]]
+
+:[[Wave]]&nbsp;-- [[Wavefunction]] -- [[Quantum entanglement]] -- [[Harmonic oscillator]]&nbsp;-- [[Magnetism]]&nbsp;-- [[Electricity]]&nbsp;-- [[Electromagnetic radiation]]&nbsp;-- [[Temperature]]&nbsp;-- [[Entropy]] -- [[Physical information]]
+
+:'''[[fundamental force|Fundamental Forces]]'''
+:[[Gravity|Gravitational]]&nbsp;-- [[Electromagnetism|Electromagnetic]]&nbsp;-- [[Weak interaction|Weak]]&nbsp;-- [[Strong interaction|Strong]]
+
+:'''[[Particle physics|Particles]]'''
+:[[Atom]]&nbsp;-- [[Proton]]&nbsp;-- [[Neutron]]&nbsp;-- [[Electron]]&nbsp;-- [[Quark]]&nbsp;-- [[Photon]]&nbsp;-- [[Gluon]]&nbsp;-- [[W boson]]&nbsp;-- [[Z boson]]&nbsp;-- [[Graviton]]&nbsp;-- [[Neutrino]]&nbsp;-- [[Particle radiation]]
+
+
+:'''Subfields of Physics'''
+:[[Astrophysics]]&nbsp;-- [[Atomic, Molecular, and Optical physics]]&nbsp;--  [[Computational physics]]&nbsp;-- [[Condensed matter physics]]&nbsp;-- [[Cryogenics]]&nbsp;-- [[Fluid dynamics]]&nbsp;-- [[Polymer physics]]&nbsp;-- [[Optics]]&nbsp;-- [[Materials physics]]&nbsp;-- [[Nuclear physics]]&nbsp;-- [[Plasma physics]]&nbsp;-- [[Particle physics]] (or High Energy Physics) -- [[Solid state physics]]
+
+:'''Methods'''
+:[[Scientific method]]&nbsp;-- [[Physical quantity]]&nbsp;-- [[Measurement]]&nbsp;-- [[Measuring instruments]]&nbsp;-- [[Dimensional analysis]]&nbsp;-- [[Probability and Statistics]]
+
+:'''Tables'''
+:[[Physical constants]]&nbsp;-- [[SI base unit|SI base units]]&nbsp;-- [[SI derived unit|SI derived units]]&nbsp;-- [[SI prefix|SI prefixes]]&nbsp;-- [[Conversion of units|Unit conversions]]
+
+:'''History'''
+:[[History of Physics]]&nbsp;-- [[Famous Physicists]]&nbsp;-- [[Nobel Prize in physics]]
+
+:'''Related Fields'''
+:[[Mathematical physics]]&nbsp;-- [[Astronomy and Astrophysics]]&nbsp;-- [[Materials science]]&nbsp;-- [[Electronics]]&nbsp;-- [[Engineering]]
+
+
+(''To help develop a list of the most basic topics in Physics, please see [[Physics basic topics]].'')
+
+=== A Ridiculously Brief History of Physics ===
+
+''Note: A more detailed history of physics article is in development at [[History of Physics]]. Currently, this contains little more than is written here. Please add to the History of Physics article, and keep this a summary only''
+
+Since antiquity, people have tried to understand the behavior of matter: why unsupported objects drop to the ground, why different materials have different properties, and so forth. Also a mystery was the character of the [[universe]], such as the form of the [[Earth]] and the behavior of celestial objects such as the [[Sun]] and the [[Luna|Moon]]. Several theories were proposed, most of them were wrong. These theories were largely couched in [[philosophy|philosophical]] terms, and never verified by systematic experimental testing. There were exceptions: for example, the [[Hellenic civilization|Greek]] thinker [[Archimedes]] derived many correct quantitative descriptions of mechanics and hydrostatics.
+
+During the late [[16th century]], [[Galileo Galilei|Galileo]] pioneered the use of experiment to validate physical theories, which is the key idea in the [[scientific method]]. Galileo formulated and successfully tested several results in [[dynamics]], in particular the Law of [[Inertia]]. In [[1687]], [[Newton]] published the [[Principia Mathematica]], detailing two comprehensive and successful physical theories: the [[Newton's laws of motion]], from which arise [[classical mechanics]]; and [[gravity|Newton's Law of Gravitation]], which describes the [[fundamental force]] of [[gravity]]. Both theories agreed well with experiment. Classical mechanics would be exhaustively extended by [[Joseph-Louis de Lagrange|Lagrange]], [[William Rowan Hamilton|Hamilton]], and others, who produced new formulations, principles, and results. The Law of Gravitation initiated the field of [[astrophysics]], which describes [[astronomy|astronomical]] phenomena using physical theories.
+
+From the [[18th century]] onwards, [[thermodynamics]] was developed by [[Robert Boyle|Boyle]], [[Thomas Young|Young]], and many others. In [[1733]], [[Daniel Bernoulli|Bernoulli]] used statistical arguments with classical mechanics to derive thermodynamic results, initiating the field of [[statistical mechanics]]. In [[1798]], [[Benjamin Thompson|Thompson]] demonstrated the conversion of mechanical work into heat, and in [[1847]] [[James Joule|Joule]] stated the law of conservation of [[energy]], in the form of heat as well as mechanical energy.
+
+The behavior of [[electricity]] and [[magnetism]] was studied by [[Michael Faraday|Faraday]], [[Georg Ohm|Ohm]], and others. In [[1855]], [[James Maxwell|Maxwell]] unified the two phenomena into a single theory of [[electromagnetism]], described by [[Maxwells equations|Maxwell's equations]]. A prediction of this theory was that [[light]] is an [[electromagnetic radiation|electromagnetic wave]].
+
+In [[1895]], [[Wilhelm Conrad Röntgen|Roentgen]] discovered [[X-ray|X-rays]], which turned out to be high-frequency electromagnetic radiation. [[Radioactivity]] was discovered in [[1896]] by [[Henri Becquerel]], and further studied by [[Pierre Curie]] and [[Marie Curie]] and others. This initiated the field of [[nuclear physics]].
+
+In [[1897]], [[J.J. Thomson|Thomson]] discovered the [[electron]], the elementary particle which carries electrical current in circuits. In [[1904]], he proposed the first model of the [[atom]], known as the [[atom/plum pudding|plum pudding model]]. (The existence of the atom had been proposed in [[1808]] by [[John Dalton|Dalton]].)
+
+In [[1905]], Einstein formulated the theory of [[special relativity]], unifying space and time into a single entity, [[spacetime]]. Relativity prescribes a different transformation between [[inertial frame of reference|reference frames]] than classical mechanics; this necessitated the development of relativistic mechanics as a replacement for classical mechanics. In the regime of low (relative) velocities, the two theories agree. In [[1915]], Einstein extended special relativity to explain gravity with the [[general relativity|general theory of relativity]], which replaces Newton's law of gravitation. In the regime of low masses and energies, the two theories agree.
+
+In [[1911]], [[Ernest Rutherford|Rutherford]] deduced from [[rutherford scattering|scattering experiments]] the existence of a compact atomic nucleus, with positively charged constituents dubbed [[proton|protons]]. [[neutron|Neutrons]], the neutral nuclear constituents, were discovered in [[1932]] by [[James Chadwick|Chadwick]].
+
+Beginning in [[1900]], [[Max Planck|Planck]], [[Albert Einstein|Einstein]], [[Niels Bohr|Bohr]], and others developed [[quantum]] theories to explain various anomalous experimental results by introducing discrete energy levels. In [[1925]], [[Werner Heisenberg|Heisenberg]] and [[Erwin Schrodinger|Schrodinger]] formulated [[quantum mechanics]], which explained the preceding quantum theories. In quantum mechanics, the outcomes of physical measurements are inherently [[probability|probabilistic]]; the theory describes the calculation of these probabilities. It successfully describes the behavior of matter at small distance scales.
+
+Quantum mechanics also provided the theoretical tools for [[condensed matter physics]], which studies the physical behavior of solids and liquids, including phenomena such as [[crystal|crystal structures]], [[semiconductor|semiconductivity]], and [[superconductor|superconductivity]]. The pioneers of condensed matter physics include [[Felix Bloch|Bloch]], who created a quantum mechanical description of the behavior of electrons in crystal structures in [[1928]].
+
+During [[World War II]], research was conducted by each side into [[nuclear physics]], for the purpose of creating a [[nuclear weapon|nuclear bomb]]. The German effort, led by Heisenberg, did not succeed, but the Allied [[Manhattan Project]] reached its goal. In America, a team led by [[Enrico Fermi|Fermi]] achieved the first man-made [[nuclear chain reaction]] in [[1942]], and in [[1945]] the world's first nuclear explosive was detonated in [[Alamagordo]], [[New Mexico]].
+
+[[Quantum field theory]] was formulated in order to extend quantum mechanics to be consistent with special relativity. It achieved its modern form in the late [[1940s]] with work by [[Richard Feynman|Feynman]], [[Julian Schwinger|Schwinger]], [[Tomonaga]], and [[Freeman Dyson|Dyson]]. They formulated the theory of [[quantum electrodynamics]], which describes the electromagnetic interaction.
+
+Quantum field theory provided the framework for modern [[particle physics]], which studies [[fundamental force|fundamental forces]] and elementary particles. In [[1954]], [[Yang Chen Ning|Yang]] and [[Robert Mills|Mills]] developed a class of [[gauge theory|gauge theories]], which provided the framework for the [[Standard Model]]. The Standard Model, which was completed in the [[1970s]], successfully describes almost all elementary particles observed to date.
+
+''A more detailed history of physics article is in development at [[History of Physics]].''
+
+----
+
+'''Suggested Reading:'''
+* [[Richard Feynman|Feynman]], ''The Character of Physical Law'', MIT Press, 1965
+* [[Richard Feynman|Feynman]], Leighton, Sands, ''The Feynman Lectures on Physics'', Reading Mass., Addison-Wesley 1963
+* Eric Weisstein, ''Treasure Troves of Physics'', http://www.treasure-troves.com/physics/. Online Physics encyclopedic dictionary.
+* Carl R. Nave, ''HyperPhysics'', http://hyperphysics.phy-astr.gsu.edu/hbase/hph.html. Online crosslinked physics concept maps.
+
diff --git a/testsuite/data/Poker.txt b/testsuite/data/Poker.txt
new file mode 100644 (file)
index 0000000..52d031d
--- /dev/null
@@ -0,0 +1,51 @@
+:''Poker is a microcosm of all we admire and disdain about capitalism and democracy.  It can be rough-hewn or polished, warm or cold, charitable and caring or hard and impersonal.  It is fickle and elusive, but ultimately it is fair, and right, and just.'' -- Lou Krieger
+
+The [[card game]] '''poker''' is the most popular of a class of games called '''vying''' games, in which players with fully or partially concealed cards make wagers into a central '''pot''', after which the pot is awarded to the remaining player or players with the best combination of cards.
+
+In order to play, one must learn the basic rules and procedures of the game (see [[Poker/Game play|Game play]]), the values of the various combinations of cards (see [[Poker/Hands|Hands]]), and the rules about betting limits (see [[Poker/Betting structure|Betting structure]]).  Some knowledge of the [[Poker/Equipment|Equipment]] used to play is useful.  There are also many [[Poker/Variants|Variants]] of poker, loosely categorized as [[Draw poker]], [[Stud poker]], [[Community card poker]], and [[Miscellaneous poker]] games.  The most commonly played games of the first three categories are [[Five-card draw]], [[Seven-card stud]], and [[Texas holdem|Texas hold'em]]; each of these makes a good starting point for learning games of the type.
+
+The history of poker is a matter of some debate.  The name of the game likely descended from the [[French]] '''poque''', which descended from the [[German]] '''pochen''', but it is not clear that the games named by those terms were the real origins of poker.  It closely resembles the [[Persian]] game of '''as nas''', and may have been taught to French settlers in [[New Orleans]] by Persian sailors.  Some claim it descended from the [[Italian]] game of '''primero''' and the French '''brelan'''.  The [[English]] game '''bragg''' clearly descended from '''brelan''' and incorporated bluffing (though the concept was known in other games by that time).  It is quite possible that all of these earlier games influenced the development of poker as it exists now.
+
+English actor Joseph Crowell described the game as played in New Orleans in 1829: played with a deck of 20 cards, four players bet on which player's hand of cards was the most valuable.  Jonathan H. Green's book ''An Exposure of the Arts and Miseries of Gambling'' (G. B. Zieber, Philadelphia, 1843) described spread of the game from there to the rest of the country by [[Mississippi river|Mississippi]] riverboats, on which gambling was a common pastime.
+
+Soon after this spread, the full 52-card English deck was used, and the [[Poker/Flush|Flush]] was introduced.  During the [[American Civil War]], many additions were made, including [[draw poker]], [[stud poker]] (the five-card variant), and the [[Poker/Straight|Straight]].  Further American developments followed, such as the [[Poker/Wild card|Wild card]] (around 1875), [[lowball]] and split-pot poker (around 1900), and [[Community card poker]] games (around 1940).  Spread of the game to other countries, particularly in Asia, is often attributed to the American military.
+
+The game and [[Poker Jargon|jargon]] of poker have become important parts of American culture.  Such phrases as ''ace in the hole'', ''ante up'', ''beats me'', ''blue chip'', ''call the bluff'', ''cash in'', ''pass the buck'', ''poker face'', ''stack up'', ''when the chips are down'', ''wild card'', and others are used in everyday conversation even by those unaware of their origins at the poker table.
+
+Modern [[Poker/Tournament|Tournament]] play became popular in American casinos after the [[World Series of Poker]] began in 1970.  It was also during that decade that the first serious strategy books appeared, notably ''The Theory of Poker'' by David Sklansky (ISBN 1880685000), ''Super System'' by Doyle Brunson (ISBN 0931444014),  and ''The Book of Tells'' by Mike Caro (ISBN 0897461002).
+
+<h2>Overview</h2>
+
+* Rules of the game
+** [[Poker/Game play|Game play]], with sample deals.
+** [[Poker/Hands|Hands]] (including [[Poker/Low hand|Low hand]]s and [[Poker/High hand|High hand]]s)
+** [[Poker/Betting structure|Betting structure]]
+** [[Poker/Variants|Variants]]
+*** [[Draw poker]] (including [[Five-card draw]] and [[Deuce-to-seven low]])
+*** [[Stud poker]] (including [[Five-card stud]] and [[Seven-card stud]])
+*** [[Community card poker]] (including [[Texas holdem|Texas hold'em]])
+*** [[Miscellaneous poker]]
+* [[Poker strategy]]
+** [[Poker/Probability|Probability]]
+** [[Poker/Bluffing|Bluffing]] and semi-bluffing
+** [[Poker/Sandbagging|Sandbagging]] and slow play
+** [[Poker/Game theory|Game theory]]
+** [[Poker/Psychology|Psychology]] (including [[Poker/Tell|Tell]]s)
+* [[Poker/Cheating|Cheating]]
+** [[Poker/Mechanics|Mechanics]]
+** [[Poker/Collusion|Collusion]]
+* Casino play
+** [[Poker/Public cardroom rules|Public cardroom rules]]
+** [[Poker/Public cardroom etiquette|Public cardroom etiquette]]
+* [[Poker/Tournament|Tournament]]s
+** [[Poker tournament strategy]]
+** [[World Series of Poker]]
+* [[Poker jargon]]
+* [[Poker/Law|Law]] and [[Poker/Culture|Culture]]
+* Famous players: [[Bobby Baldwin]], [[Billy Baxter]], [[Benny Binion]], [[Doyle Brunson]], [[Mike Caro]], [[Johnny Chan]], [[Bob Ciaffone]], [[T. J. Cloutier]], [[Nick Dandalos|Nick "The Greek" Dandolos]], [[Phil Hellmuth]], [[Bill Hickock|"Wild Bill" Hickock]], [[Lou Krieger]], [[Mason Malmuth]], [[Tom McEvoy]], [[Johnny Moss]], [[Puggy Pearson]], [[Amarillo Slim|"Amarillo Slim" Preston]], [[David Sklansky]], [[Jack Strauss]], [[Stu Ungar]]
+
+----
+:''See also :'' [[Poker/Dead money|Dead money]] -- [[Poker/Freeroll|Freeroll]] -- [[Poker/Jargon|Poker jargon]] -- [[Poker/Rule variation|rule variations]] -- [[Poker/Miscellaneous game]]
+----
+
+[[Poker-related game]]s include non-poker vying games commonly played along with poker such as [[Seven twenty-seven]], [[Zero fifty-five]], [[Boure|Bouré]], and [[Caro Dots]], and unrelated games that use poker hands in various ways such as [[Dollar bill poker]], [[Pai Gow poker]], [[Caribbean stud]], [[Mambo stud]], and [[Chinese poker]].
diff --git a/testsuite/data/Political_science.txt b/testsuite/data/Political_science.txt
new file mode 100644 (file)
index 0000000..7a83649
--- /dev/null
@@ -0,0 +1,98 @@
+'''Political science''' is the formal academic study of [[politics]].  It involves the study of structure and process in [[government]] - or any equivalent system that assures safety, fairness, and closure across a broad range of risks and access to a broad range of commons for its human charges.  Accordingly, political scientists often study trade unions, corporations, churches or other forms of [[collective intelligence]] that are not "political" in the sense of influencing law or executive decisions - but have structure and process approaching that of government in complexity and interconnection.
+
+Political scientists also study the allocation and transfer of power in decision making.  Because of the complex interaction of often conflicting interests, political science is often an applied instance of [[game theory]].
+
+Political processes are often associated with the possibility or the prevention of [[violence]].
+
+One thing that complicates the study of political science is that political scientists are themselves part of the political process, since their teachings provide the frameworks within which other commentators, such as journalists, pressure-groups, politicians and the electorate select what they see as the most viable options. 
+
+The complex interplay of economic and political choices is reflected in the field of [[political economy]], where economics and political science overlap.
+
+In the United States, political scientists look at a variety of data including elections, public opinion (on matters ranging from Social Security reform to foreign policy), institutional roles (how the U.S. Congress acts, where congressional power gravitates, how and when the Supreme Court acts, or does not act, etc.). 
+
+While historians look backward, seeking to explain the past, political scientists try to illuminate the politics of the present and predict those of the future.
+
+----
+'''Topics''':
+* [[Political science]] (General)
+** [[Political scientist]]s
+** [[Politics]]
+* [[Political theory]]
+** Theories of state
+*** [[Anarchism]] 
+*** [[Anarcho-capitalism]]
+*** [[Capitalism]]
+*** [[Communism]]
+*** [[Conservatism]]
+*** [[Corporocracy]]  
+*** [[Democracy]]
+*** [[Fascism]]
+*** [[Political liberalism|Liberalism]]
+*** [[Libertarianism]]
+*** [[Libertarian socialism]]
+*** [[Marxism]]
+*** [[Minarchism]]
+*** [[Nationalism]]
+*** [[National Socialism]]
+*** [[Oligarchy]]
+*** [[Patriotism]]
+*** [[Republicanism]]
+*** [[Socialism]]
+*** [[Sovereignty]]
+** Sector-Based Ideologies
+*** [[Masculism]]
+*** [[Feminism]]
+** [[Political philosophy]]
+*** [[The justification of the state]]
+*** [[Anarchism and natural law theory]]
+*** [[Social contract theories]]
+*** [[Consequentialist justifications of the state]]
+*** [[The purpose of government]]
+***[[Forms of state]]
+** [[Theories of Political Behavior]]
+*** [[Game theory]]
+*** [[Stress and political decision-making|Psychodynamics of Decision-making]]
+** [[Political theorist|Political Theorists]]
+* [[State]]
+** [[Forms of government]]
+** Political Entities
+*** [[City]]
+*** [[Country]]
+*** [[Government]]
+*** [[Republic]]
+*** [[State]]
+** [[Three powers of the State]]
+*** [[Executive power]]
+*** [[Legislative power]]
+*** [[Judicial power]]
+** Three branches of government
+*** [[Executive branch]]
+*** [[Legislative branch]]
+*** [[Judicial branch]]
+** [[Political parties]]
+* [[Law]]
+** [[International law]]
+* [[Election|Elections]]
+** [[Voting system]]s
+** [[Electoral Reform]]
+** [[Bioregional democracy]]
+** [[Proportional representation]]
+** [[Tactical voting]]
+* Miscellaneous
+** [[International organization]]
+** [[Corporate police state]]
+** [[Crony capitalism]]
+** [[European Union]]
+** [[NGO|Non-Governmental Organizations]]
+** [[Police]]
+** [[Propaganda]]
+** [[U.S. Politics]]
+** [[Political spectrum]] 
+** [[Party|Political Party]]
+** [[Political parties of the world]]
+** [[Techno-democracy]]
+
+** [[Techno-oligarchy]]
+** [[collective intelligence]]
+** [[anti-globalization movement]]
+
diff --git a/testsuite/data/Psychology.txt b/testsuite/data/Psychology.txt
new file mode 100644 (file)
index 0000000..c599535
--- /dev/null
@@ -0,0 +1,143 @@
+[[nl:Psychologie]][[pl:Psychologia]]
+'''Psychology''' is an academic discipline and applied profession concerned with the study of and intervention in mental states, processes, and behavioral patterns of humans and, to an extent, of animals (though the study of animal behavior, [[ethology]], is more often regarded a branch of [[biology]] than of psychology).  Psychologists also study interactions between individuals and groups of individuals, and between individuals, groups and their environment.  Disciplines that are traditionally considered to intersect with psychology are [[sociology]], [[anthropology]], [[biology]], and [[philosophy]], but more recently fields such as [[political science]], [[media studies]] and [[gender studies]] have also come to be seen as closely related to psychology.
+
+Psychologists work in co-operation (and sometimes in competition) with psychiatrists (who are medical doctors who specialise in mental health issues), social workers (most of whom are qualified in various forms of psychological intervention), psychiatric nurses and 'lay' counsellors. Services similar to those provided by psychologists are also often provided by traditional healers and religious counsellors.
+
+The root of the word psychology (psyche) means "soul" in Greek, and psychology was sometimes considered a study of the soul (in a religious sense of this term), though its emergence as a medical discipline can be seen in [[Thomas Willis]]'s reference to psychology (the "Doctrine of the Soul") in terms of brain function, as part of his 1672 anatomical treatise "De Anima Brutorum" ("Two Discourses on the Souls of Brutes"). 
+
+[[Experimental psychology]], as introduced by [[Wilhelm Wundt]] in 1879 at Leipzig University in Germany, eliminated religious implications from psychology entirely.  Today, experimental psychology focuses on observable behavior and the evidence it gives about mental processes.  It therefore has little specific to say about such notions as an immaterial, immortal soul.  Modern psychology is often called the scientific study of behavior, though (as in [[cognitive psychology]]) its purported object is often not behavior but various [[mental event]]s. There are also now many psychological approaches that attempt to take spiritual and religious issues seriously.
+
+Until about the beginning of the twentieth century, psychology was regarded as a branch of philosophy.  With the work of Wundt and of his contemporary experimental psychologist [[William James]] (who, himself, questioned the veracity of materialistic psychology in his later work), the field of psychology was slowly but steadily established as a science independent of philosophy.  Of course, like all sciences which have broken off from philosophy, purely philosophical questions about the mind are still studied by philosophers; the name of the philosophical subdiscipline which studies those questions is ''[[philosophy of mind]].''  Few universities, journals, or researchers today treat psychology as a branch of philosophy, but there is much disagreement as to whether it should be considered an experimental science. Some academic psychologists are still of the opinion that psychological understanding can only progress through rigorously controlled laboratory experiments, but most now accept that less carefully controlled quantitative methods (such as survey research) as well as qualitative research or equally valuable.
+
+Both psychology and its sister [[psychiatry]] (whose practitioners are medical doctors with a specialty in psychiatry) are criticized by a vocal and well-credentialed (if small) minority in medical and academic circles. These critics call them [[pseudo-science]]s, arguing that their theories, diagnoses and treatments don't hold up under the rigor of the scientific method and that they are not reproducable; others question the appropriateness of applying the scientific method to the study of the human mind and human behavior.  A related view is promulgated by some philosophers under the label [[eliminative materialism]].  These challenges to the discipline are, in large part, legitimate and needed, especially when one considers the discipline's growing influence in Western culture and how easy it can be to construct psychological models that are entirely untestable (e.g., Freud's model of the psyche).  These concerns seek not to subvert psychology but to strengthen it by the same rigorous inquiry present in other sciences.
+
+Topics in Psychology
+* [[research methods]]
+* the [[brain]] and [[nervous system]]
+* [[the senses]]
+* [[perception]]
+* [[consciousness]]
+* [[learning]]
+* [[memory]]
+* [[cognition]]
+* [[language]] and [[language acquisition]]
+* [[emotion]]
+* [[developmental psychology]]
+* [[personality]]
+* [[sexuality]] and [[gender]]
+* [[psychological testing]]
+* [[motivation]]
+* [[attitude]] and [[social influence]]
+* [[abnormal psychology]]
+* [[psychotherapy]]
+* [[psychopharmacology]]
+* [[applied psychology]]
+* [[mental health disorders]]
+
+Major Nineteenth and Twentieth Century Schools of Thought
+* [[psychoanalysis]]
+* [[behaviorism]]
+* [[Gestalt]]
+* [[introspective]]
+* [[humanism]]
+* [[functionalism]]
+
+Famous Psychologists and Contributors to Psychology
+* [[Alfred Adler]]
+* [[Aristotelis]]
+* [[Aushra Augustinavichute]]
+* [[Albert Bandura]]
+* [[Alfred Binet]]
+* [[John Bradshaw]]
+* [[Jean-Martin Charcot]]
+* [[Erik Erickson]]
+* [[Hans Eysenck]]
+* [[Viktor Frankl]]
+* [[Anna Freud]]
+* [[Sigmund Freud]] 
+* [[Erich Fromm]]
+* [[Karen Horney]]
+* [[William James]]
+* [[Arthur Janov]]
+* [[Carl Jung]]
+* [[Alfred Kinsey]]
+* [[Melanie Klein]]
+* [[Wolfgang Köhler]]
+* [[Emil Kraepelin]]
+* [[Elizabeth Kübler-Ross]]
+* [[Jacques Lacan]]
+* [[Abraham Maslow]]
+* [[William Masters and Virginia Johnson]]
+* [[Lloyd deMause]]
+* [[Alice Miller]]
+* [[Ivan Pavlov]]
+* [[Fritz Perls]]
+* [[Jean Piaget]]
+* [[James W. Prescott]]
+* [[Otto Rank]]
+* [[Hermann Rorschach]]
+* [[Virginia Satir]]
+* [[Morita Shoma]]
+* [[B. F. Skinner]]
+* [[Robert Sternberg]]
+* [[Carl Rogers]]
+* [[Liev S. Vygotski]]
+* [[Wilhelm Wundt]]
+
+Divisions and Approaches in Psychology (these might be overlapping, of course)
+* [[analytical psychology]]
+* [[behavioral psychology]]
+* [[cognitive psychology]]
+* [[clinical psychology]] and [[counseling psychology]]
+* [[critical psychology]]
+* [[developmental psychology]]
+* [[educational psychology]]
+* [[evolutionary psychology]]
+* [[experimental psychology]]
+* [[health psychology]]
+* [[individual differences psychology]]
+* [[industrial and organizational psychology]]
+* [[medicinal psychology]]
+* [[personality psychology]]
+* [[pop psychology]], [[self-help]], and [[alternative therapy]]
+* [[positive psychology]]
+* [[psychoanalysis]]
+* [[psychohistory]]
+* [[psychometrics]]
+* [[psychotherapy]] a branch of [[psychiatry]] as well.
+* [[social psychology]]
+
+Some related disciplines:
+* [[psychometrics]]
+* [[cognitive science]]
+* [[computer science]]
+* [[ethology]]
+* [[linguistics]] and especially [[psycholinguistics]]
+* [[literature]], [[literary theory]], and [[critical theory]]
+* [[neuroscience]]
+* [[parapsychology]]
+* [[philosophy of mind]]
+* [[philosophy of psychology]]
+* [[game theory]]
+* [[hypnotherapy]]
+* [[system theory]]
+* [[simplicity theory]]
+* [[complexity theory]]
+* [[artifical consciousness]]
+* [[sociology]]
+* [[economics]] and [[marketing]]
+* [[history]]
+* [[Neurolinguistic Programming ]]
+* [[Socionics]]
+
+
+External links:
+* [http://www.sonoma.edu/psychology/psychart.html Pictures of famous psychologists]
+* [http://www.psychology.org/ Encyclopedia of Psychology]
+
+* [http://www.apa.org American Psychological Association]
+* [http://www.psych.org American Psychiatric Association]
+
+* [http://www.apa.org/monitor/dec99/toc.html A Century of Psychology (APA)]
+* [http://www.psipesquisa.com.br PsiPesquisa Search Engime in Portuguese]
+
diff --git a/testsuite/data/Public_affairs.txt b/testsuite/data/Public_affairs.txt
new file mode 100644 (file)
index 0000000..03c49e5
--- /dev/null
@@ -0,0 +1,9 @@
+[[eo:Publikaferoj]]
+''Public affairs'' is a catch-all term that includes [[public policy]] as well as [[public administration]], both of which are closely related to and draw upon the fields of [[political science]] as well as [[economics]].
+
+Public policy discussions are generally and consciously partisan, and we assume that participants in public policy discussion have a specific point of view which they seek to advance in the discussion.
+
+Public affairs, on the other hand, generally claims to be non-partisan.
+It focuses on providing news and information without a conscious point of view.
+
+[[Social activism]] involves popular action and commentary on public affairs, as well as [[civil defense]], and [[community emergency response team]]s.
diff --git a/testsuite/data/Quotes.txt b/testsuite/data/Quotes.txt
new file mode 100644 (file)
index 0000000..5eaf647
--- /dev/null
@@ -0,0 +1,40 @@
+
+Wikipedia quoting tests:
+
+(1) normal '''bold''' normal
+
+(2) normal ''italic'' normal
+
+(3) normal '''''bold italic''''' normal
+
+(4) normal '''bold ''bold italic'' bold''' normal
+
+(5) normal ''italic '''bold italic''' italic'' normal
+
+(6) normal '''''bold italic'' bold''' normal
+
+(7) normal '''''bold italic''' italic'' normal
+
+(8) normal ''italic '''bold italic''''' normal
+
+(9) normal '''bold ''bold italic''''' normal
+
+(10) normal '''bold's''' normal
+
+(11) normal ''italic's'' normal
+
+(12) normal ''italic's '''bold's italic''' italic's'' normal
+
+(13) normal '''''bold's italic'' bold's''' normal
+
+(14) normal ''italic''' normal
+
+(15) normal ''''bold''' normal
+
+(16) normal ''italic'' normal ''italic'' normal
+
+(17) normal ''italic'' normal '''bold''' normal
+
+(18) normal '''bold''' normal '''bold''' normal
+
+(19) normal '''bold''' normal ''italic'' normal
diff --git a/testsuite/data/Recreation.txt b/testsuite/data/Recreation.txt
new file mode 100644 (file)
index 0000000..5350779
--- /dev/null
@@ -0,0 +1,8 @@
+'''Recreation''' is refreshment of one's body or mind.  Recreation is often distinguished from [[leisure]].  Where leisure is, or ought to be, restful, recreation is refreshing and diverting.
+
+[[Music]] and [[dance]] serve as recreation in many cultures, as do [[sports]] and [[hobbies]] and sometimes [[food and drink]].
+
+We sometimes use drugs as a form of recreation (see [[recreational drug use]])--and, like dancing, [[sex]], [[nudism]], and other forms of recreation which many people treat as illicit.
+
+The [[weekend]] is typically a time for recreation, perhaps (in [[Judeo-Christian_tradition|Judeo-Christian]] and Muslim cultures) because the [[Sabbath]] falls on the weekend and the Sabbath is &quot;the day of rest.&quot;  [[Holiday]]s are also a common time for recreation.
+
diff --git a/testsuite/data/Religion.txt b/testsuite/data/Religion.txt
new file mode 100644 (file)
index 0000000..bfe25f0
--- /dev/null
@@ -0,0 +1,65 @@
+[[af:Religie]][[ca:Religió]][[de:Religion]][[eo:Religio]][[es:Religión]][[fr:Religion]][[nl:Religie]][[pl:Religia]][[pt:Religião]]
+The word '''religion''' comes from the [[latin]] word ''ligare'': to join, or link, classically understood to mean the linking of human and divine.  What constitutes a religion is subject to much dispute in the field of [[theology]] and among ordinary people.  We might begin by defining religion as a system of [[belief]]s based on humanity's attempt to explain the [[universe]] and [[natural phenomenon|natural phenomena]], often involving one or more [[deity|deities]] or other [[supernatural]] forces.  Religious adherents tend to gather together to celebrate holy days and to [[pray]], but solitary practice is also usually just as important. Most religions also have a code of [[law]]s to be followed, like the [[Ten Commandments]] of [[Old Testament]], and some have specific texts they hold as sacred, and totally different from other writings.
+
+Two identifying features of all religions are that to some extent they all (a) require [[faith]] and (b) seek to organise and guide the thoughts and actions of their adherents.   Because of this, some people contend that all religions are to some degree both irrational and dogmatic, and are therefore to be distrusted.  As they see it, a system of thought that is purely rational would be a [[science]] rather than a religion, and a system that is not in the least dogmatic would be unable to guide its adherents in any way.
+
+Many Western people nowadays prefer to use the term '[[spirituality]]' for their position. This reflects a disillusion with organised religion which unless it stays small scale, must grapple with worldly pressures of power and economics where ideals so often become corrupted. [[Priest|Priesthoods]] and [[monastery|monasteries]] frequently show increasingly low recruitment. Studies in the [[UK]] show a fast diminishing attendance at [[church|churches]], [[synagogue]]s etc (except among charismatics) and throw up worried media articles on the decline of religion today. However, studies that look further and examine people's beliefs and practices without defining religion strictly in terms of organisation membership, find that spiritual beliefs are flourishing, and often extend to cherished family and community customs. New variations of religions are being constantly generated, showing that the religious impulse is not dying, but taking new forms.
+
+There are several scientific approaches to religion to answer questions such as why religious belief is ubiquitous in every society.  In [[neurology]], work by scientists such as Ramachandran and his colleagues from the [[University of California]] at [[San Diego]] [http://serendip.brynmawr.edu/bb/neuro/neuro01/web2/Eguae.html] has found evidence of brain circuitry in the temporal lobe that gives rises to religious experiences.  In [[sociology]], [[Rodney Stark]] has looked at the social forces that have caused religions to grow and the features of religions that have been most successful.  In [[evolutionary psychology]], scientists consider the survival advantages that religion might have had in the hunter-gatherer societies.
+
+Religions are systems of belief which typically deal with
+*the divine, the sacred and the [[supernatural]],
+*our purpose as beings, on earth, in this life and possible other states of being,
+*what happens to us when we die and how to prepare for that,
+*the nature of [[Deity]] (or Deities) (cf [[God]]) and what She, He, They, It wants from us,
+*our relationships with Deity(-ies), the sacred, ancestors, other people, and the world around us, that is, how to behave well in relationship. 
+
+The following three types of religion are helpful, but should not be read as completely distinct as they do share in each other's characteristics.
+*[[Theism|Theistic]] religions are primarily focused on a Deity(-ies) and begin when Deity intervenes in the lives of a person or group, enlightening them and establishing a superior way of life leading to internal peace in this life, and qualification for some kind of [[Heaven]] after this life. Examples of monotheisms (one Deity religions): [[Judaism]], [[Christianity]] and [[Islam]].
+*Some faiths, perhaps "Spiritual Philosophies" begin with practical teachings on achieving human happiness or equanimity in the context of both earthly and other dimensions. Examples: [[Buddhism]],[[Taoism]], and [[Confucianism]].
+*A third type, perhaps "Traditional Religions" which seems to involve the oldest religions, evolves slowly over long millennia, and is centered more on [[symbol]], [[icon]], sacred story and customs. These sorts of sources can be interpreted very differently at different times and places: an image can even mean contradictory things to different interpreters. [[Hinduism]] is one example of this type, although most Hinduisms are theistic. Further examples are the many kinds of [[Shamanism]] and [[Ancestor religion]]s.
+
+Religions deal with the (more or less) divergent [[lifestyle|lifestyles]] espoused by other religions in several ways.  Religions with a duty to convert, or with more closed sets of beliefs typically label all others wrong, corruptions or counterfeits of the true faith. More open religions praise all belief systems as beneficial, and among open religions it is often possible to practice more than one faith together with integrity, as occurs commonly in [[Asia]] and [[Africa]].
+
+Some religions have [[charismatic]] leaders, such as [[Jesus Christ]], [[Martin Luther]], [[Billy Graham]], [[Mohandas Gandhi]], [[Joseph Smith]], [[Muhammad]], the [[Buddha]], etc. These '''leaders''' may be the central figure in the religion, like Muhammad, Jesus or Buddha. Or they might be founders, like Martin Luther. Or they may be merely prominent persons like Billy Graham--who is an influential speaker but not the head of a large organization or movement.
+
+=== Origin of religion ===
+
+The origin of religion in general and for particular religions is usually controversial, since religions often claim to have been derived directly from information supplied by god(s) to chosen human messenger(s).  Followers of the religion (by definition) accept the claims, either literally or in a metaphorical, or partial fashion.  Although followers of a religion, although they may hold strong belief, may also be interested in looking at possible human origins for religious events, together with non-religious enquirers.
+
+Religion was practiced long before the [[invention]] of writing, as paintings and pottery shows in images. Indeed, heavy deposits of pollen in [[Neanderthal]] graves suggest that even these early humans buried their dead along with flowers. Stories ('texts') passed orally between people and from one generation to the next. Religion may well have originated in stories created to account for the great questions of life, for comfort, to keep records of a people's history, and for entertainment. Stories in traditional societies unite adults and children in community, although it is possible that [[atheism|atheists]] (those who believe there is no Deity) or [[agnosticism|agnostics]] (those who believe we cannot know if there is a Deity) always existed as well. Evidence of very early human prehistory is scanty and it is best not to over interpret [[archaeology|archaeological]] remains: for example it is generally thought that bones painted with red ochre (a red mud thay may link to blood colour to symbolize life) and buried with personal possessions, suggest a belief in an [[afterlife]]. It could also be because using the dead person's possessions was believed to be bad luck.  For a more contemporary example, consider a future archaeologist digging the remains of a [[Star Wars]] fan's bedroom and the possible erroneous interpretations of such a find.
+
+Evidence for early civilisation's religious ideas can be found similarly in elaborate burial practices in which valuable objects were left with the deceased, intended for use in an afterlife or to appease the gods.  This custom has clearer motives as it is usually accompanied by tomb paintings showing a belief of [[afterlife]]. It reached a spectacular form with the creation of the [[pyramids of Giza]] and the other great tombs of ancient [[Egypt]]; the [[Sumeria|Sumerian]] royal burials, and other prehistoric (pre-written records) monument builders.  
+
+Religions created in modern times are often reasonably well documented (e.g., [[Scientology]].) Minor religions have been called '[[cult|cults]]' and still are, while many scholars use the term [[New Religious Movement]] (NRM). Reasons for the creation of religions are many, including a range from [[idealism]] to a desire to obtain wealth and power over others; the two may combine in interesting ways.  It's easy to speculate that similar forces were at work in the creation of earlier religions. Once a religious community increases in size and gains widespread recognition, it has to negotiate with the governing social group, the [[State]]. At this point material or political ambitions are more likely to be dominant. 
+
+Hostility to religion can have various reasons. [[Karl Marx]] famously defined religion as a social opiate, and from outside it certainly appears to operate as such, but wholesale condemnation overlooks the great numbers and scale of visionary inspirations that religions provide for compassion, practical charity and moral restraint. 
+When [[war|wars]] are aggravated or caused by religious issues they tend to be worse in their atrocities. Yet [[Abram Maslow|Abram Maslow's]] research after [[World War II]] showed that [[Holocaust]] survivors tended to be those who held strong religious beliefs (not necessarily temple attendance etc). Humanistic [[Psychology]] went on to investigate how religious or spiritual identity links with longer lifespan and better health. Humans may particularly need religious ideas because they serve various emotional needs such as the need to feel loved, the need to belong to homogenous groups, the need for understandable explanations or the need for justice.
+
+=== Religion vs. Mythology ===
+
+Ancient [[polytheism|polytheistic]] religions, such as those of [[Greek mythology|ancient Greece]], [[Roman mythology|ancient Rome]], [[Norse mythology|the Vikings]], etc., are often studied under the heading of ''[[mythology]].''  Religions of pre-industrial peoples, or [[culture|cultures]] in development to industrial conditions, are similarly observed by the [[anthropology]] of religions. Mythology can be a term used pejoratively by religious and non-religious people both (the religious person will in this case define another religion's stories as mythology). Here myths are treated as fantasies, or 'mere' stories. But the study of religions, and the investigation of myths by psychology, not to mention how some myths turn out to have historical verification, has brought about a mixed, almost contradictory use of the term: some NRMs (New Religious Movements) such as  [[Neopaganism]] actively research and use myths from older religions, both those that still exist and those that have disappeared.
+
+=== Monotheism vs. Polytheism ===
+
+The dominance of [[monotheism]] among influential Western scholars of religion, and theologians, proposed a division into monotheistic and [[polytheism|polytheistic]] faiths. The classification fails with a religion that has no concept of "god" (like [[Theravada]] [[Buddhism]]). Many people both inside and outside of [[Christianity]] find its claim to be monotheistic problematic since it has more than one god form, (God as Father, Son and [[Holy Spirit]]), explained in the doctrine of the [[Trinity]]. This has resulted in much ingenious Christian theology. The monotheism of [[Islam]] and [[Judaism]] is much more clearcut, although very early sources for both [[Allah]] and [[Yahweh]] show signs of polytheistic origins or forerunners, which does not at all deny or contradict their sole Deity status once the religion became established. [[Neopaganism]], a religion generally considered to be polytheistic, is also difficult to classify neatly. While adherents worship a diverse pantheon of gods and goddesses, a great many of them believe those personalities to be facets of a single Divine entity.
+
+Some religions have secondary deities, which is straightforward in eg Hinduism, but less so for those Christians who venerate [[The Virgin Mary|Mary]] as Theotokos (Mother of God). Mary has often attracted such a massive devotion by the faithful that the Church has been careful to clearly define her status: Christians in the Catholic and Orthodox traditions are instructed that she is to be venerated but not worshipped, and that [[Jesus Christ]] is eternally begotten of the Father, and the Creator of his strictly human mother. (see also: [[Third Ecumenical Council]], [[Seventh Ecumenical Council]].) Many [[mysticism|mystics]] have asserted the female aspect of Deity but apart from Hinduism this has not been regarded as mainstream by major world religions for several centuries. Goddess is routinely recognised in Hindu Mahadevi, Mahayana Buddhism, Western Paganism and Goddess Spirituality. 
+
+Orthodox and Roman Catholic Christianity, [[Mahayana]] Buddhism, and most Hinduisms, also recognize the existence of lesser spiritual beings: angels and demons, but they are not worshipped as gods. In Christian [[Catholicism]] and [[Eastern Orthodoxy]], Mary and the [[saint|saints]] have especially important roles as intermediaries and personal guardians. They are divine only in that they have been reunited with God. Mahayana Buddhism's lesser deities embody psychological forces, whether as guides, examples or antagonists with whom to learn power and skill. The division between Deity, deity, minor deity, angel, demon, nature spirit, ancestor or hero, is not clearcut, but developed pragmatically.
+
+=== Non-religious religion ===
+
+Deities both great and lesser are part of practices like transcendental psychology (which looks at the psychology of the spiritual) and [[therapy|therapies]] like Jungianism. [[Jung]] found an underworld of mythological drama in the backstage areas of the mind: in particular, he proposed that our ideas and feelings are shaped by spiritual [[archetype]]s, eternal models such as God, the Old Man, or the Mother. The [[New Age Movement]], a late [[20th century]] culture of eclectic beliefs in millennial change, healing traditions, alternative realities, also draws on these mythological images. 
+
+But it is important to distinguish a spiritual psychology that explores a map of the self, which goes so deep and far that it recognises divine shapes, from a religion or spirituality that explores a ''relationship'' between human self and an Other, the divine. The distinction asks whether there is dialogue between two or more with genuine voice and influence coming from the other (Martin [[Buber]]'s ''I and Thou''), or whether there is a journey in which the self encounters profound symbolic experiences. As the opening definition tells us, religion is about linking.
+----
+See also:  [[Goddess]] - [[God]] - [[interfaith organizations]] [[names given to the divine]] - [[Religion index]] - [[Philosophy of religion]] - [[Sociology of Religion]] - [[Theology]] - [[Feminist theology]] - [[Thealogy]] - [[History of religions]] - [[Definition of religion]] - [[Charismatics]] - [[Religious pluralism]] - [[Tolerance]] - [[freedom of religion]] - [[Afterlife]], [[Angel]], [[Demon]], [[Demonolatry]] - [[History of religions]] - [[Henks Comparative Sacred Reading]] - [[Mystery religion]]
+
+See also this listing of various religions: [[religions of the world]]
+
+=== External Links ===
+
+* [http://www.adherents.com/ Statistics on Religions]
+* [http://www.religioustolerance.org/ Religious Tolerance]
+
diff --git a/testsuite/data/Sculpture.txt b/testsuite/data/Sculpture.txt
new file mode 100644 (file)
index 0000000..c625c34
--- /dev/null
@@ -0,0 +1,18 @@
+'''Sculpture''' is any three-dimensional form created as an artistic expression. 
+''Sculpting'' is the [[art]] of assembling or shaping an object. It may be of any size and of any suitable material. Traditional sculpting materials are: stone (e.g. marble, limestone, granite), clay (e.g. porcelain, terracotta), metal (e.g. bronze, iron, [[aluminum]]), and [[wood,as a medium|wood]]. [[modern art|Modern]] and Contemporary materials include the environment, textiles, [[glass]], [[sand]], water, liquid crystals, many other man-made materials, as well as any found-objects.  (In his late writings [[Joan Miro]] even proposed that some day sculptures might be made of gases (see [[gas sculpture]]).)
+
+Some of the forms of sculpture are:
+*[[Relief]] - sculpture still attached to a background, standing out from that ground in &quot;High Relief&quot; or &quot;Low Relief&quot; (bas-relief)
+*Free-standing sculpture
+*[[Mobile]] (See also [[Alexander Calder|Calder]]'s Stabiles.)
+*[[Statue]]
+*[[Bust]]
+*[[Site-Specific]]
+
+[[Famous Sculptors]]
+
+'''External links:'''
+*http://www.sculptor.org
+*http://www.sculpture.org
+* Unique mediums: (Sand) http://www.teamsandtastic.com
+* http://www.greenmuseum.org The online museum of environmental art.
diff --git a/testsuite/data/Sociology.txt b/testsuite/data/Sociology.txt
new file mode 100644 (file)
index 0000000..8683932
--- /dev/null
@@ -0,0 +1,17 @@
+[[de:Soziologie]][[eo:Sociologio]][[fr:Sociologie]][[nl:Sociologie]][[pl:Socjologia]]
+'''Sociology''' is the study of human beings in their social context. For much more, please link to:
+http://www.angelfire.com/or/sociologyshop/socsnip.html
+
+The term was coined by [[Auguste Comte]], who hoped to unify all studies of humankind--including history, psychology and economics. His own sociological scheme was typical of the [[18th century]]; he believed all human life had passed through the same distinct historical stages and that, if one could grasp  this progress, one could prescribe the remedies for social ills.
+
+The Sociology of today is often far less grand. It is the study of humankind's organizations and social institutions, largely by a comparative method. It has concentrated on the organization of complex [[Industry|industrial]] societies (in the early 20th century, sociologists and psychologists who conducted research in non-industrial societies contributed to the development of [[anthropology]].  It should be noted, however, that anthropologists also conducted research in industrial societies.  Today sociology and anthropology are better contrasted according to different theoretical concerns and methods rather than objects of study).
+
+A distinction should be made between these and forensic studies within these disciplines, particularly where anatomy is involved. These latter studies might be better named as Forensic psychology.
+
+See also: [[criminology]], [[disabilities]], [[media studies]], [[Milgram experiment]], [[sociobiology]], [[sociologist]] [[culture]] [[political economy]] [[social change]]
+
+Influential sociologists: [[Auguste Comte]], [[Emile Durkheim]], [[Max Weber]], [[Georg Simmel]], [[Alfred Schutz]], [[George Herbert Mead]], [[W. I. Thomas]], [[Talcott Parsons]], [[Robert K. Merton]], [[Erving Goffman]], [[C. Wright Mills]] [[Thorstein Veblen]] [[Anthony Giddens]]
+
+Influences on sociology: [[Karl Marx]], [[Henry Maine]], [[Sigmund Freud]], [[Ferdinand Saussure]], [[Claude Levi-Strauss]], [[Michel Foucault]], [[Theodor Adorno]], [[Max Horkheimer]], [[Jurgen Habermas]]
+
+Branches of sociology: [[Sociology of Religion]], [[Industrial Sociology]] [[Mass Media]] [[Revolution]] [[Social Movements]] [[Social Change]] [[Environmental Sociology]] [[Economic Sociology]] [[Political Sociology]] [[Gender &amp; Sexuality]] [[Education]] [[Theory]] [[Culture]] [[Deviance]] [[Comparative Historical]] [[Race &amp; Ethnicity]] [[Work]]
diff --git a/testsuite/data/Sport.txt b/testsuite/data/Sport.txt
new file mode 100644 (file)
index 0000000..fcd689b
--- /dev/null
@@ -0,0 +1,272 @@
+[[ca:Esports]][[de:Sport]][[eo:Sporto]][[fr:Sport]][[nl:Sport]][[pl:Sport]]
+
+Defining '''sport''' is difficult; the term constantly evolves to cover new ranges of human behavior.  Indeed, the well-known philosopher [[Ludwig Wittgenstein]] argues that sports are defined, not by a set of common characteristics, but by new activities sharing some common aspects with existing sports, but not necessarily sharing any common characteristics with all.  Credence to this comment may be taken from the ever-more-diverse set of activities that are at least claimed by some as sports - from [[chess]] to [[cheerleading]], from [[sheepdog trials]] to [[ballroom dancing]].  What do all of those activities have in common?  
+
+However, many of the above would not be recognised as sports by fans of more traditionally-recognised sports, and using Wittgenstein's "extension" approach it would be quite reasonable to claim a "battle of the bands" competition as a sporting event and thus playing [[rock and roll]] as a sport, a definition which makes "sport" so broad as to be potentially useless and quite different to the common understanding, fuzzy though that may be.
+
+A more pragmatic approach to defining sport may be to look at common usage of the term.  It was originally used to describe the  animal and bird-killing activities (such as shooting, fishing and [[fox hunting]]) of the English aristocracy, whereas the precursors of modern team sports played by the lower classes were termed "games".  However, as time progressed, perhaps with the beginnings of the modern Olympic movement in the late 19th century, "sport" began to be used to describe a wide range of athletic pursuits.  However, sport retained, and still retains an implication of respectability and seriousness that a mere "game" or "hobby" does not, and organisations responsible for leisure activities continually seek recognition as sports by joining sports federations such as the [[IOC]].  These bodies are seemingly fairly inclusive as to what they are prepared to accept as sports, and thus the activities listed above, amongst others, have been accepted.
+
+However, it is possible to make a reasonable operational definition of sport using characteristics most sports do have in common.  Such an operational definition can be found below:
+
+* Sports are activities based around physical activity, involving use of characteristics such as strength, stamina, speed, and dexterity.
+* A sport has codified rules known to all players.  These vary somewhat depending on the location, timing, and specific event (for instances, [[golf]] courses have specific local bylaws, and each tournament may have its own special conditions), but there are a core of relatively invariant, agreed rules.
+* A sport involves a competitive aspect, either explicitly by competing against other participants, or by means of an ordinal (usually numeric) scoring system.  There are organised competitions for the sport, rather than purely ad-hoc, casual competitions.
+* Sport is performed primarily for the enjoyment of either or both of the participants and/or any audience watching.
+* The primary goal of competition is to win according to the rules of the competition, rather than as a subsidiary to esthetic, artistic, or financial achievements in the performance of the sport (thus excluding the "battle of the bands" or a sheep-shearing competition).
+* Sport is unscripted and the results of competitions not prearranged.  Sports such as [[gymnastics]] involve set routines, but the scoring of those routines is judged entirely on the performance of that day.
+
+[[Sport/What is a sport|What is a sport]]
+
+[[History of Sport]]
+
+* Paleontological evidence for prehistoric sports (is there any)?
+* The sports of ancient civilizations:
+** Egyptian
+** Greek (Olympics, etc.)
+** Mayan
+** Australian Aboriginal (Aussie rules believed to be derived from Aboriginal game)
+** Roman
+** Chinese
+** Any others?
+* Medieval sports - the aristocracy and the plebs
+* The great rule codification of the 19th century and the rise of spectator sports
+* 20th century and the electronic media and the growth of professional sport
+* The recent rise in "extreme"/adventure sports, growth of divergent participant and spectator sports.
+
+Feel free to fill these in, or add more dot points, or reorganise totally.
+
+=== Aspects of Sport ===
+
+* [[Sports/Events]]
+* [[Sport/Governing bodies]] 
+* [[Sporting venues]]
+* [[sponsorship]]
+* [[sports equipment]]
+* [[sports injuries]]
+* [[sports marketing]]
+* [[spectator sport]]
+* [[multi-sport events]]
+* [[sports art]]
+* [[sport in film]]
+* [[sporting club]]
+* [[Disabled sports]]
+* [[Sports history organizations]]
+* [[Fantasy sports]]
+
+=== Sports ===
+
+An attempt to list the most important sports, divided by category. (Many more sports to be added). Note that some sports may fit in more than one category, but are only listed in one.
+
+==== Athletics ====
+Track and field [[athletics]].
+* [[Jumping]]
+** [[Triple jump]]
+** [[Long jump]]
+** [[High jump]]
+* [[Running]]
+* [[Throwing]]
+** [[Discus]]
+** [[Hammer throw]]
+** [[Javelin]]
+** [[shotput]]
+* [[Walking]]
+
+==== Animal Sports ====
+Sports in which animals play a role.
+* [[Camel racing]]
+* [[Equestrianism]]
+* [[Greyhound racing]]
+* [[Pigeon sport]]
+
+==== Combat Sports ====
+Sport in which the athletes fight each other.
+* [[Aikido]]
+* [[Boxing]]
+* [[Fencing]]
+* [[Judo]]
+* [[Ju-jitsu]]
+* [[Karate]]
+* [[Sambo]]
+* [[Sumo]]
+* [[Taekwondo]]
+* [[Wrestling]]
+* [[Wushu]]
+
+==== Cycling ====
+Sports using [[bicycle]]s.
+* [[BMX]]
+* [[Cycloball]]
+* [[Cyclocross]]
+* [[Mountain bicycling]]
+* [[Road cycling]]
+* [[Track cycling]]
+
+==== [[Extreme sports]] ====
+* [[Skateboarding]]
+* [[Wakeboarding]]
+
+==== Gymnastics ====
+Gymnastic sports.
+* [[Aerobics]]
+* [[Acrobatics]]
+* [[Artistic gymnastics]]
+* [[Rhythmic gymnastics]]
+* [[Trampolining]]
+
+==== Motorized Sports ====
+Sports based on motorized vehicles.
+* [[Autosport]]
+* [[Motorboat racing]]
+* [[Motorcycle racing]]
+
+==== Other ====
+Sports not in any of the other categories.
+* [[BASE jumping]]
+* [[Bungee jumping]]
+* [[Dance sport]]
+* [[Disabled sports]]
+* [[Foosball]]
+* [[Modern pentathlon]]
+* [[Triathlon]]
+
+==== Outdoor Sports ====
+Sports not based on a specific field.
+* [[Aerobatics]]
+* [[Aeromodelling]]
+* [[Ballooning]]
+* [[Casting (sport)|Casting]]
+* [[Flying disc]]
+* [[Gliding]]
+* [[Hang gliding]]
+* [[Mountaineering]]
+* [[Orienteering]]
+* [[Parachuting]]
+* [[Paragliding]]
+* [[Skydiving]]
+* [[Sled-dog sports]]
+* [[Sport fishing]]
+
+==== Power Sports ====
+Sports mainly based on sheer power.
+* [[Bodybuilding]]
+* [[Powerlifting]]
+* [[Tug of war]]
+* [[Weightlifting]]
+
+==== Racket Sports ====
+Sports where players use rackets to hit a ball or other object.
+* [[Badminton]]
+* [[Racquetball]]
+* [[Royal tennis]]
+* [[Soft tennis]]
+* [[Squash]]
+* [[Table tennis]]
+* [[Tennis]]
+
+==== Skating ====
+Sports in which skates are used.
+* [[Figure skating]]
+* [[Roller hockey]]
+* [[Roller skating]]
+* [[Short-track speed skating]]
+* [[Speed skating]]
+* [[Synchronized skating]]
+
+==== Skiing ====
+Sports in which [[Ski|skis]] or [[Snowboard|snowboards]] are used.
+* [[Alpine skiing]]
+* [[Back-country skiing]]
+* [[Biathlon]]
+* [[Cross country skiing]]
+* [[Firngleiten]]
+* [[Freestyle skiing]]
+* [[Grass skiing]]
+* [[Nordic combined]]
+* [[Roller skiing]]
+* [[Skibob]]
+* [[Skijoring]]
+* [[Ski jumping]]
+* [[Ski touring]]
+* [[Snowboarding]]
+* [[Speed skiing]]
+* [[Telemark skiing]]
+
+==== Sleighing ====
+Sports that use sleighs.
+* [[Bobsleigh]]
+* [[Land luge]]
+* [[Luge]]
+* [[Skeleton]]
+
+==== Target Sports ====
+Sports where the main objective is to hit a certain target.
+* [[Archery]]
+* [[Billiards]]
+* [[Bocce]]
+* [[Bowling]]
+* [[Croquet]]
+* [[Curling]]
+* [[Darts]]
+* [[Golf]]
+* [[Disc golf]]
+* [[Horseshoe throwing]]
+* [[Petanque]]
+* [[Shooting]]
+
+==== Team Sports ====
+Sports that involve teams.
+* [[American football]]
+* [[Australian rules football]]
+* [[Bandy]]
+* [[Baseball]]
+* [[Basketball]]
+* [[Basque pelota]]
+* [[Cricket]]
+* [[Curling]]
+* [[Faustball]]
+* [[Floorball]]
+* [[Football]]
+* [[Gaelic football]]
+* [[Handball]]
+* [[Hockey]]
+* [[Hurling]]
+* [[Ice hockey]]
+* [[Kabaddi]]
+* [[Korfball]]
+* [[Lacrosse]]
+* [[Netball]]
+* [[Petanque]]
+* [[Polo]]
+* [[Roller Hockey]]
+* [[Rugby]]
+* [[Sepak Takraw]]
+* [[Softball]]
+* [[Volleyball]]
+* [[Ultimate]] ([[frisbee]])
+
+==== [[Mind sport|Mind Sports]] ====
+Sports that involve no physical abilities, only mental.
+* [[Bridge game|Bridge]]
+* [[Chess]]
+* [[Poker]]
+* [[Go (board game)|Go]]
+* [[Scrabble]]
+* [[Shogi]]
+
+==== Water Sports ====
+Sports that happen in or on the water.
+* [[Canoeing]]
+* [[Diving]]
+* [[Dragon Boat]]
+* [[Offshore Powerboat racing]]
+* [[Surf lifesaving]]
+* [[Rowing]]
+* [[Subaquatics]]
+* [[Surfing]]
+* [[Swimming]]
+* [[Synchronized swimming]]
+* [[Wakeboarding]]
+* [[Water polo]]
+* [[Water skiing]]
+* [[Yachting]]
+
diff --git a/testsuite/data/Statistics.txt b/testsuite/data/Statistics.txt
new file mode 100644 (file)
index 0000000..267d99b
--- /dev/null
@@ -0,0 +1,16 @@
+[[nl:Statistiek]][[pl:Statystyka]]
+:"There are lies, damn lies, and then there are Statistics." - Mark Twain
+
+'''Statistics''' is the science of 
+#[[Planning Research|planning observations]], 
+#[[Descriptive statistics|summarizing statistical data]], and 
+#[[Statistical inference|interpreting statistical data]]. 
+
+'''Topics:'''
+:[[Statistical theory|Theory]] -- [[Applied statistics|Applied]] -- [[Descriptive statistics|Descriptive]] -- [[statistical inference|Inference]] -- [[Probability and statistics]] --  [[Analysis of variance]] (ANOVA) -- [[Multivariate statistics|Multivariate]]
+
+'''External links'''
+[http://www.r-project.org/ The R Project for Statistical Computing]
+
+'''See also:'''
+* [[Extreme value theory]] -- [[Data mining]] 
diff --git a/testsuite/data/Technology.txt b/testsuite/data/Technology.txt
new file mode 100644 (file)
index 0000000..15be268
--- /dev/null
@@ -0,0 +1,174 @@
+[[eo:Teknologio]][[fr:Technologie]][[nl:Technologie]]
+'''Technology''' is the field that applies science to solve problems with an industrial and/or commercial end in mind.  '''Engineering''' applies human traits such as [[imagination]], [[judgement]], [[integrity]], and [[intellectual discipline]] to existing human [[knowledgebase]]s to [[create]] or [[utilize]] technology [[safely]] and [[efficiently]].
+
+For example:  All buildings require the use of technology of some sort.
+A persistent [[Art|artistic]] expression requires materials to be formed, and exactly how to create those materials requires some rudimentary understanding of their chemical and physical properties. [[Architecture]] requires an understanding of the effects of [[weather]] and other natural forces, in addition to some knowledge of the strengths of the materials used.
+
+The term ''technology'' is usually used to explain new inventions and gadgets using recently derived scientific principles and processes. However, even very old inventions such as the [[wheel]] are, technically speaking, technology.
+
+Early or prehistoric advances in technology or fundamental tools.
+
+* [[Agriculture]]
+* [[Astronomy]]
+* [[Animal husbandry]]
+* [[Cattle breeding]]
+* [[Cooking]]
+* [[Clothing]]
+* [[Fire]]
+* [[Inclined plane]]
+* [[Metal mining]]
+* [[Lever]]
+* [[Pottery]]
+* [[Pulley]]
+* [[Screw]]
+* [[Wedge]]
+* [[Wheel]]
+* [[Writing]]
+
+More recent tools that are fundamental to modern technology
+* [[Clock]]
+* [[Compass]]
+* [[Sextant]]
+
+Modern major fields of technology.
+
+* [[Acoustics]]
+** [[Analog recording]]
+** [[Digital recording]]
+
+* [[Biotechnology]]
+
+* [[Computing]]
+** [[Computer hardware]]
+*** [[Home computers]]
+*** [[Routing]]
+** [[Software]]
+*** [[Geographic Information System]]
+*** [[Invention machine]]
+*** [[Speech recognition]]
+** [[Computer network]]
+** [[Programmable logic controller]] or PLC
+** [[Calculators]]
+
+*[[Cryptology]]
+*[[Cryptography]]
+
+* [[Electricity]]
+** [[Electricity generation]]
+** [[Power transmission]]
+** [[Power control]]
+** [[Electric motor]]
+** [[Resistance]]
+** [[Inductance]]
+** [[Capacitance]]
+** [[Electric light bulb]]
+
+* [[Electronics]]
+** [[Relay]]
+** [[Vacuum tube]]
+** [[Semiconductor]]
+*** [[Diode]]
+*** [[Transistor]]
+*** [[Integrated circuit]]s or IC's
+**** [[Very Large System Integration]] or VLSI integration
+**** [[System-on-a-chip]]
+
+* [[energy storage|Energy storage]]
+
+* [[Instrumentation]]
+
+* [[Measuring instrument]]
+
+* [[Metallurgy]]
+
+
+* [[Microtechnology]]
+** [[Microfluidics]]
+** [[Microphotonics]]
+
+* [[machine|Machinery]] and [[mechanism|Mechanisms]]
+** [[Clock]]
+*** [[chronometer]]
+*** [[Pendulum clock]]
+*** [[Quartz clock]]
+*** [[Atomic clock]]
+** [[Wedge]]
+** [[Lever]]
+** [[Screw]]
+** [[Steam engine]]
+** [[Internal combustion engine]]
+*** [[Gasoline/Petrol engine]]
+*** [[Diesel engine]]
+*** [[Four stroke cycle]]
+*** [[Two stroke cycle]]
+*** [[Wankel engine]]
+** [[Turbine]]
+*** [[jet engine]]
+*** [[Steam turbine]]
+*** [[Gas turbine]]
+*** [[Water turbine]]
+*** [[Air turbine]]
+** [[compressor|Compressors]] and [[pump|Pumps]]
+*** [[Archimedes screw]]
+*** [[Hydraulic ram]]
+*** [[Vacuum pump]]
+*** [[Eductor-jet pump]]
+*** [[Tuyau]]
+
+* [[Nanotechnology]]
+* [[nuclear reactor|Nuclear reactor]]
+
+* [[Space Technology]]  Introduction and index of further specific topics in this field.
+
+* [[Transport]]
+* [[Telecommunication]]
+** [[Telegraph]]
+** [[Telephone]]
+** [[Radio]]
+** [[Television]]
+** [[Submarine cable]]
+** [[Communication satellite]]
+* [[Telemetry]]
+
+* [[Cooking technology]]
+** [[Oven]]
+*** [[Microwave oven]]
+* [[Blender]]
+* [[Food processor]]
+* [[Mixer]]
+* [[Barbeque]]
+* [[Refrigerator]]
+** [[freezer]]
+* [[Can]]
+
+* Domestic technology
+** [[Vacuum cleaner]]
+** [[Mop]]
+** [[Broom]]
+** [[Mower]]
+
+* [[Nuclear technology]]
+
+** Nuclear Power
+***  Fission
+***  Fusion
+***  Antimatter
+***  Radioisotope Thermal Electric
+
+** [[Nuclear weapon]]
+** Nuclear Medicine
+** X-Rays
+
+* [[weapon|Weapons]] 
+**[[Nuclear weapon]]
+
+* [[Visual technology]]
+** [[Photography]]
+** [[Video]]
+** [[Printing]]
+
+'''[[Concepts in Technology]]'''
+* [[The Singularity]]
+* [[Emergent Philosophies]]
+* [[Transhumanism]]
+* [[Posthumanism]]
diff --git a/testsuite/data/Theater.txt b/testsuite/data/Theater.txt
new file mode 100644 (file)
index 0000000..849e8c1
--- /dev/null
@@ -0,0 +1,61 @@
+[[de:Spiele]][[eo:Teatro]][[nl:Kleinkunst]]
+'''Theater''' is that branch of the [[performing arts]] concerned with acting out stories using combinations of speech, gesture, music, sound and spectacle - indeed any one or more elements of the other performing arts. Theater takes such forms as [[opera]], [[ballet]], [[mime]], [[pantomime]]. "[[Drama]]" is that branch of theater in which speech, from written text ([[Theatre/play|plays]] or "[[dramatic literature]]") or improvised, is paramount. 
+[[Theatre Techniques]]
+20th Century American Theater:
+: [[Eugene O'Neill|Eugene O'Neill]]
+: [[Arthur Miller]]
+: [[David Mamet]]
+: [[Edward Albee]]
+: [[Neil Simon]]
+: [[George S Kaufmann]]
+: [[Tennessee Williams]]
+: [[Thorton Wilder]]
+: [[Lorraine Hansberry]]
+
+20th Century British Theatre:
+: [[Alan Ayckbourn]]
+: [[John Galsworthy]]
+: [[John Osborne]]
+: [[Harold Pinter]]
+: [[J.B. Priestley]]
+: [[Tom Stoppard]]
+: [[Peter Barnes]]
+
+Most of the above styles have been performed in [[Repertory]]
+
+20th Century German Language Theater Authors:
+: [[Heiner Mueller]]
+: [[Bertolt Brecht]]
+: [[Thomas Bernhardt]]
+: [[Elfriede Jelinek]]
+: [[Friederich Durrenmatt]]
+: [[Wolfgang Hildesheimer]]
+
+20th Century German Language Theater Directors:
+: [[Fritz Kortner]]
+: [[Peter Stein]]
+: [[Peter Zadek]]
+: [[Frank Castorf]]
+: [[August Everding]]
+: [[Max Reinhardt]]
+
+20th Century Irish Theatre
+: [[George Bernard Shaw]]
+: [[Samuel Beckett]]
+
+Other 20th Century English-language playwrights:
+: [[Athol Fugard]]
+
+
+This gives a brief outline of some of the better-known playwrights; but theater does not operate on playwrights alone.  Plays are often produced by a [[production team]]: various technical, support, and design staff.  Among these are the [[scenic designer]], the [[lighting designer]], the [[costume designer]], the [[Theatre/director|director]], the [[dramaturg]] and the [[stage manager]].  This is not an all inclusive list, and may include other personnel from the world of [[technical theatre]].
+
+See also: [[dramatist]], [[history of theater]], [[improvisational theater]], [[radio and television drama]], [[cinematic drama]]
+
+----
+
+'''Theatre''' is also the building in which works and plays are performed. Some of these buildings are masterpieces of [[architecture]]. Others, as for those mainly known for [[opera]], became cultural references and symbols.
+
+The original [[Greek theatre]] was semicircular in form and was normally built on a hillside, often overlooking the sea.  Such theatres were constructed with faultless acoustics, so that a player standing centre stage could be clearly heard throughout the auditorium.  The [[Roman]]s copied this style of building, but tended not to be so concerned about the location, being prepared to build walls and terraces instead of looking for a naturally-occurring site.
+
+During the [[Elizabethan era]] in [[England]], theatres were constructed of wood and were circular in form, like the [[Globe Theatre]] in [[London]], home to [[William Shakespeare]]'s troupe of actors.  The Globe has now been rebuilt as a fully working and producing theatre near its original site (largely thanks to the efforts of film director [[Sam Wanamaker]]) to give modern audiences an idea of the environment for which Shakespeare and other playwrights of the period were writing.
+
diff --git a/testsuite/data/Tourism.txt b/testsuite/data/Tourism.txt
new file mode 100644 (file)
index 0000000..41157fa
--- /dev/null
@@ -0,0 +1,67 @@
+[[eo:Turismo]][[fr:Tourisme]][[nl:Toerisme]]
+'''Tourism''' is an industry that came about when large numbers of middle-class people began to travel as well.  As societies became wealthier, and people longer-lived, it became not only possible but probable that lower-middle and middle-class people steadily employed would retire in good health and with some significant savings. 
+
+To be a '''tourist''' is to travel and stay in places apart from your usual place of residence, as an end in itself. A tourist can usually be seen as clearly "out of place" with his current surroundings, therefore not to be confused with a traveller. The term tourist is tied to the activity of taking a [[tour]] or [[sightseeing]]. It is not limited to travelling, but used as a description of a person who enters a situation or culture, for a brief time, requiring knowledge that he does not have. 
+
+The tourist can be interested (among other things) in the new place's [[culture]] or its [[nature]].  Wealthy people have always traveled to distant parts of the world, not incidentally to some other purpose, but as an end in itself: to see great buildings or other works of art; to learn new languages; or to taste new cuisines.
+
+Organised tourism is now a major [[Industry/Tertiary sector|industry]] around the world. Many national economies are now heavily reliant on tourism.
+
+== History ==
+The words ''tourist'' and ''tourism'' were first used as official terms in 1937 by the [[League of Nations]] to, define people travelling abroad for periods of over 24 hrs. But the tourism industry is much older than that.
+
+Basically, "tourism", like any other form of economic activity, occurs when the essential parameters come together to make it happen. In this case there are three essential parameters:
+
+# [[Disposable income]], i.e. money, to spend on non-essentials
+# [[Time]] in which to do so.
+# [[Infrastructure]] in the form of accommodation facilities and means of transport.
+
+The word ''tour'' gained common acceptance in the eighteenth century, when the [[Grand Tour of Europe]] became part of the upbringing of the educated and wealthy British nobleman or cultured gentleman. Grand tours were taken in particular by young people to complete their education. They travelled all over [[Europe]], but notably to places of cultural and aesthetic interest, such as [[Rome]], [[Tuscany]] and the [[Alps]]. Most major British artists of the eighteenth century did the Grand tour, as did their great European contemporaries such as [[Claude Lorrain]]. Classical literature and art had always drawn visitors to Rome, [[Naples]], [[Florence, Italy|Florence]]. The Romantic movement (inspired throughout Europe by the English poets [[William Blake]] and [[Lord Byron]], among others), extended this to ''gothick'' countryside, the Alps, fast flowing rivers, mountain gorges, etc.
+
+The British Aristocracy were particularly keen on the Grand Tour, using the occasion to gather art treasures from all over Europe to add to their collections. The volume of art treasures going to Britain in this way was unequalled anywhere else in Europe, and explains the richness of many private collections and public collections in Britain today. Yet tourism in those days, aimed essentially at the very top of the social ladder and at the well educated, was fundamentally a cultural activity. These first tourists, though undertaking their Grand Tour, were more travellers than tourists.
+
+Tourism in the modern sense of the word did not develop until the nineteenth century; that was leisure travel, which today forms the larger part of the tourist industry.
+
+Again the leisure industry was a British invention, for sociological reasons. Britain was the first European country to industrialize, and the industrial society was the first society to offer time for leisure to a growing number of people. Not the working masses in the first place, but the owners of the machinery of production, the economic oligarchy, the factory owners, the traders, the new middle class.
+
+Leisure travel had of course developed as an offshoot of [[cultural tourism]], partly as [[health tourism]]. Some English travellers, after visiting the warm lands of the South of Europe, decided to stay there either for the cold season or for the rest of their lives, but this was a very minor development. It was not until the nineteenth century that leisure tourism really began to develop, as people began to "winter" in warmer climates, or to visit places with health-giving mineral waters, in order to cure a whole variety of diseases from gout to liver disorders and bronchitis. 
+
+The British origin of this new industry can be recognized in the many names: At Nice, one of the first and most well established holiday resorts on the French [[Riviera]], the long esplanade along the sea front is known to this day as the ''Promenade des Anglais''; and in many other historic resorts in continental Europe, old well established palace hotels have names like  the  ''Hotel Bristol'', ''Hotel Carlton'' or ''Hotel Majestic'' - reflecting the largely English customers for whom these resorts catered in the early years.
+
+Even [[winter sport|winter sports]], as a leisure activity rather than as a means of transport, were largely invented by the British leisured classes. It was English tourists who invented winter sports at the Swiss village of [[Zermatt]]. Until the first tourists appeared, the villagers of Zermatt just thought of the long snowy winter as being a time when the best thing to do was to stay indoors and make cuckoo clocks or other small mechanical items.
+
+Organized sport was already well established in Britain long before it reached other countries. The vocabulary of sport bears witness to this: rugby, football are both British games, and even [[Tennis]], originally a French sport, was formalized and codified by the British, who invented the first national championship in the nineteenth century, at [[Wimbledon]]. Winter sports were a natural answer for a leisured class, looking for amusement in Winter..
+
+[[Mass tourism]] did not really begin to develop, however, until two things had occurred. a) improvements in communications allowed the transport of large numbers of people in a short space of time to places of leisure interest, and b) greater numbers of people began to enjoy the benefits of leisure time. The biggest development of all was the invention of the [[railway|railways]], which brought Britain's seaside within easy distance of Britain's large urban centres. 
+
+The father of modern mass tourism was [[Thomas Cook]] who, on [[July 5th]] [[1841]], organised the first [[package tour]] in history, by chartering a train to take a group of teetotalers from [[Leicester]] to a rally in [[Loughborough]], some twenty miles away. Cook immediately saw the potential for business development in the sector, and became the world's first tour operator.
+
+He was soon followed by others, with the result that the tourist industry developed rapidly in early Victorian Britain.
+Initially it was supported by the growing middle classes, who had time off from their work, and who could afford the luxury of travel and possibly even staying for periods of time in [[boarding house|boarding houses]]. However, the Bank Holiday Act of 1871 introduced, for the first time, a statutory right for workers to take holidays, even if they were not paid at the time. 
+
+The combination of short holiday periods, travel facilities and distances meant that the first holiday resorts to develop in Britain were towns on the seaside, situated as close as possible to the growing industrial connurbations. For those in the industrial north, there were [[Blackpool]] and [[Scarborough]]. For those in the [[Midlands]], there was Weston Super Mare, for those in [[London]] there were Southend on Sea, Broadstairs, [[Brighton]], Eastbourne, and a whole collection of other lesser known places. But for a century, tourism remained a national industry, with foreign travel being reserved, as before, for the rich or the culturally curious.
+
+Similar processes occurred in other countries, though at a slower rate, given that nineteenth century Britain was far ahead of any other nation in the world in the process of industrialisation. In the USA, the first great seaside resort, in the European style, was [[Atlantic City]], New Jersey. In Europe, early resorts included Oostende (for the people of [[Brussels]]), and Boulogne and Deauville (for Parisians).
+
+Even so, increasing speed on railways meant that the tourist industry could develop slowly, even internationally. By 1901, the number of people crossing the [[Channel]] from England to [[France]] or [[Belgium]] had already passed 0.5 million per year.  
+
+Other phenomena that helped develop the travel industry were paid holidays: 
+* 1.5 million manual workers in Britain had paid holidays by 1925
+* 11 million by 1939 (30% of the population in families with paid holidays)
+
+What the railway did for [[domestic tourism]] in the nineteenth century, the aeroplane and the package tour have done for [[international tourism]] in the last 30 years. For the worker living in greater London, Brindisi today is hardly less accessible than Brighton was 100 years ago,. Tourism has become a multi-billion pound international industry, and one that is growing in developed countries (source countries) at a rate considerably faster than annual growth levels. [[Receptive tourism]] is also growing at a very rapid rate in many developing countries, where it is often the most important economic activity in local GDP.
+
+See also: 
+*[[Popular tourist regions]]
+*[[History of tourism]]
+*[[Hotel]]
+*[[Types of tourism]]
+*[[Agriturismo]]
+*[[Travelling]]
+*[[Backpacking]]
+
+External links:
+* [http://www.lonelyplanet.com/destinations/ Lonely Planet Destinations Guide]--a great resource for finding information about a particular location.
+
+* [http://www.stateguide.com StateGuide]--destination 'cheat sheet' for researching vacation, relocation, retirement, and military sites in the US. Approx. 4500 towns.
+
diff --git a/testsuite/data/Transport.txt b/testsuite/data/Transport.txt
new file mode 100644 (file)
index 0000000..189b282
--- /dev/null
@@ -0,0 +1,161 @@
+'''Transport''', or '''transportation''' (as it is called in the United States), is the movement of people and goods from one place to another. The term is derived from the [[Latin]] ''Trans'' meaning ''across'' and ''Portare'' meaning ''carrying'' . Motor Vehicles, Trains, Airplanes, and Ships are the most common modes of modern transport.  Transport and [[communication]] are both substitutes and complements, the growth in transport would be impossible without communication, and the increase of one generally leads to more of the other.
+
+* General
+** [[Civil engineering]]
+** [[Department of Transportation]]
+** [[Engineering]]
+** [[Highway engineering]]
+** [[Intelligent transportation system]]
+** [[Logistics]]
+** [[Public transport]] (also called public transit)
+** [[Queueing theory]]
+** [[Timeline of transportation technology]]
+** [[Traffic engineering]]
+** [[Transport finance]]
+** [[Transport economics]]
+** [[Transport engineering]]
+** [[Transport planning]]
+** [[Travel behavior]]
+** [[Urban planning]]
+** [[Vehicle]]
+
+* [[Technology|Technologies]]
+** [[Containerization]]
+** [[Engine]]
+** [[Jet engine]]
+** [[Motor]]
+** [[Saddle]]
+** [[Shoe]]
+** [[Stirrup]]
+** [[Wheel]]
+
+* [[Network]]s
+** [[Airlines]]
+** [[Canal]]
+** [[Freeway]]
+** [[Highway]]
+** [[Pipeline transport|Pipeline]]
+** [[Railway]]
+** [[River]]
+** [[Road]], [[List of roads and highways]]
+** [[Sidewalk]]
+** [[Skyway]]
+
+* Nodes
+** [[Airport]], [[IATA airport code]]
+** [[Air traffic control]]
+** [[Harbor]]
+** [[Port]]
+** [[Terminal]]
+
+'''Modes'''
+* [[Air transport]]
+** [[Aircraft]] (Airplane)
+** [[Autogyro]]
+** [[Balloon]]
+** [[Blimp]] (Airship)
+** [[Dirigible]]
+** [[Flying car]]
+** [[Helicopter]]
+** [[Hovercraft]]
+** [[Zeppelin]]
+
+* [[Animal-powered transport]]
+** [[Burro]]
+** [[Camel]]
+** [[Dog]]
+** [[Donkey]]
+** [[Elephant]]
+** [[Horse]]
+** [[Mule]]
+** [[Llama]]
+** [[Ox]]
+** [[Reindeer]]
+** [[Yak]]
+
+
+* [[Cable transport]]
+** [[Cable car]]
+** [[Elevator]]
+** [[Funicular]]
+
+* [[Conveyor transport]]
+** [[Conveyor belt]]
+** [[Escalator]]
+** [[Moving sidewalk]]
+
+* [[Human-powered transport]]
+** [[Bicycle]]
+** [[Ice skate]]
+** [[Rickshaw]]
+** [[Rowing]]
+** [[Roller skate]]
+** [[Scooter]]
+** [[Skateboard]]
+** [[Swimming]]
+** [[Punting]]
+** [[Walking]]
+** [[Wheelchair]]
+
+* [[Hybrid transport]]
+** [[Moped]]
+** [[Segway HT]]
+
+* Motorized [[road transport]]
+** [[Automobile]]
+** [[Bus]]
+** [[Electric trolleybus]]
+** [[Motorcycle]]
+** [[Truck]]
+
+* Motorized off-road transport
+** [[SUV|sports-utility/four-wheel-drive vehicles]]
+** [[Tank]]
+** [[Tractor]]
+
+* [[Pipeline transport]]
+** [[Natural gas]]
+** [[Oil]]
+** [[Pneumatic tube]]
+** [[Sewer]]
+** [[Slurry]]
+** [[Water]]
+
+* [[Rail transport]]
+** [[High speed rail]]
+** [[Light rail]] [[Light rail listing]] (Streetcar or Trolley)
+** [[Maglev]]s 
+** [[Monorail]]
+** [[People mover]]
+** [[Personal rapid transit]]
+** [[Train]]
+** [[Tram]]
+** [[Underground]], [[Underground listing]] (Subway)
+
+* [[Ship transport]]
+** [[Barge]]
+** [[Boat]]
+** [[Ferry]]
+** [[Hydrofoil]]
+** [[Sailing]]
+** [[Ship]]
+** [[Shipping]]
+** [[Tanker]]
+
+* [[Space transport]]
+** [[Interplanetary travel]]
+** [[Propulsion method]]
+** [[Rocket]]
+** [[Space shuttle]]
+** [[Space station]]
+** [[Spacecraft propulsion]]
+
+*  [[Future transport]] (Proposed future, science fiction, or literary transport)
+** [[Interstellar travel]]
+** [[Skycar]]
+** [[Space elevator]]
+** [[Teleportation]]
+** [[Starship]]
+
+(STILL NEEDS MUCH WORK)
+
diff --git a/testsuite/data/Visual_arts_and_design.txt b/testsuite/data/Visual_arts_and_design.txt
new file mode 100644 (file)
index 0000000..abe988c
--- /dev/null
@@ -0,0 +1,57 @@
+Traditional visual arts (commonly called "fine arts"):
+:[[Painting]]
+:[[Ceramics]]
+:[[Sculpture]]
+:[[Textiles]]
+:[[Drawing]]
+:[[Printmaking]] and [[Photography]]
+:Motion Pictures/[[Film]]
+
+[[Design]]:
+:[[Commercial Art]]
+:[[Fashion design]]
+**[[Fashion designers]]:
+***[[Hattie Carnegie]]
+***[[Coco Chanel]]
+***[[John Galliano]]
+:[[Graphic design]]
+:[[Illustration]]
+:[[Industrial design]]
+:[[Interior decoration]]
+:[[Industrial design]]
+:[[Architecture]]
+
+[[History of the Visual Arts]]
+:[[History of painting]]
+:[[History of sculpture]]
+:[[History of photography]]
+:[[History of design]]
+::[[History of fashion]]
+:[[Cultural movement]]
+:[[Renaissance Classicism]]
+:[[Mannerism/Art|Mannerism]]
+:[[Baroque_Art|Baroque]]
+:[[New directions and movements]]
+[[Aesthetics]]
+
+[[Art conservation]]
+
+[[Pop Art]] and [[Contemporary art]]:
+:[[Comic books and strips]]
+:[[Computer-generated art]] / [[Digital art]]
+:[[Found art]] ([[Museum of Contemporary Art]], Los Angeles, public relations campaign)
+:[[Installation art]]
+:[[Interactive art]]
+:[[Graffiti art]]
+:[[Performance Art]]
+
+[[Body art]]:
+:[[Tattoo]]
+:[[Body piercing]]
+:[[Scarification]]
+:[[Tattoo]]
+:[[Body Modification]]
+
+New Materials
+:[[Plastics in art]]
+:[[Body fluids in art]]
diff --git a/testsuite/data/World_Series_of_Poker.txt b/testsuite/data/World_Series_of_Poker.txt
new file mode 100644 (file)
index 0000000..36b3015
--- /dev/null
@@ -0,0 +1,53 @@
+The richest and most prestigious [[poker]] tournament in the world is the '''World Series of Poker''', held annually at [[Binions Horseshoe|Binion's Horseshoe]] [[casino]] in [[Las Vegas]], Nevada.  It has been held every year since 1970 (when it had seven entrants), and has grown in popularity since, the year 2000 series having 4780 entrants in various events.
+
+The series consists of many events of different [[poker variant]]s, each of which awards the winner a gold bracelet signifying the world championship of that event.  The 2001 series had 25 events held from April 20 to May 18.  The final event of the series, widely considered the world championship of the game of poker, is the $10,000 entry no-limit [[Texas holdem|Texas hold'em]] championship, a four-day event with a top prize of $1,500,000.  The winner of this event also has his picture installed in the "Gallery of Champions" at Binion's.
+
+== History ==
+
+Until 2001, the leading money winner in World Series history is T. J. Cloutier, who finished "in the money" in 33 events, including four gold bracelets in various events, a fifth-place, a third-place, and two second-place finishes in the main event, but who has never won the "big dance".  In 2001, Phil Hellmuth's 7th bracelet and 5th place finish in the final event moved him ahead of Cloutier.
+
+Other historical highlights include Jack Strauss's win, which was a comback after having lost all but one chip of his stake early in the tournament, and Stu Ungar's third win 17 years after his repeat, having spent many of the intervening years out of competition and addicted to cocaine.
+
+Billy Baxter dominated the Deuce-to-seven draw poker event for many years, winning five bracelets and twice finishing second.  He has a sixth bracelet in Ace-to-five draw.
+
+Players who have won bracelets in a [[draw poker]] event, a [[stud poker]] game, and a [[community card poker]] game are Mickey Appleman, Bobby Baldwin, Doyle Brunson (who has a total of eight bracelets in six different events, and a second place finish in 13-card [[Chinese poker]]), Johnny Chan, Johnny Moss, and Stu Ungar.
+
+See [http://www.binions.com/wsop/main.html Binion's WSOP Site]
+
+== Champions ==
+
+These are the winners of the final "championship" event, which is now No-limit Texas Hold'em.
+
+* 2002 Robert Varkonyi ($2 million) 
+* 2001 Carlos Mortenson
+* 2000 Chris "Jesus" Ferguson (The first time that first prize was $1.5 million)
+* 1999 Noel Furlong
+* 1998 Scotty Nguyen
+* 1997 Stu Ungar
+* 1996 Huck Seed
+* 1995 Dan Harrington
+* 1994 Russ Hamilton (Also won his weight in silver as a "WSOP Silver Anniversary" bonus)
+* 1993 Jim Bechtel
+* 1992 Hamid Dastmalchi
+* 1991 Brad Daugherty (The first time that first prize was $1 million)
+* 1990 Mansour Matloubi
+* 1989 Phil Hellmuth, Jr. (Youngest ever winner)
+* 1988 Johnny Chan
+* 1987 Johnny Chan
+* 1986 Berry Johnston
+* 1985 Bill Smith
+* 1984 Jack Kellar
+* 1983 Tom <nowiki>McEvoy</nowiki>
+* 1982 Jack "Treetop" Strauss
+* 1981 Stu Ungar
+* 1980 Stu Ungar
+* 1979 Hal Fowler
+* 1978 Bobby Baldwin
+* 1977 Doyle Brunson
+* 1976 Doyle Brunson
+* 1975 Sailor Roberts
+* 1974 Johnny Moss
+* 1973 Puggy Pearson
+* 1972 "Amarillo Slim" Preston
+* 1971 Johnny Moss (Won in competition, as are all subsequent)
+* 1970 Johnny Moss (Awarded by peer vote)
diff --git a/testsuite/data/startrek.png b/testsuite/data/startrek.png
new file mode 100644 (file)
index 0000000..d3a1053
Binary files /dev/null and b/testsuite/data/startrek.png differ
diff --git a/testsuite/jars/httpunit.jar b/testsuite/jars/httpunit.jar
new file mode 100755 (executable)
index 0000000..7b82e23
Binary files /dev/null and b/testsuite/jars/httpunit.jar differ
diff --git a/testsuite/jars/js.jar b/testsuite/jars/js.jar
new file mode 100755 (executable)
index 0000000..a34d599
Binary files /dev/null and b/testsuite/jars/js.jar differ
diff --git a/testsuite/jars/nekohtml.jar b/testsuite/jars/nekohtml.jar
new file mode 100755 (executable)
index 0000000..63f39fc
Binary files /dev/null and b/testsuite/jars/nekohtml.jar differ
diff --git a/testsuite/jars/xercesImpl.jar b/testsuite/jars/xercesImpl.jar
new file mode 100755 (executable)
index 0000000..d41cf97
Binary files /dev/null and b/testsuite/jars/xercesImpl.jar differ
diff --git a/testsuite/jars/xml-apis.jar b/testsuite/jars/xml-apis.jar
new file mode 100755 (executable)
index 0000000..8331d27
Binary files /dev/null and b/testsuite/jars/xml-apis.jar differ
diff --git a/testsuite/run b/testsuite/run
new file mode 100755 (executable)
index 0000000..498ef99
--- /dev/null
@@ -0,0 +1,12 @@
+#!/bin/sh
+#
+# This script drives the wiki test suite: if run without arguments, it runs
+# the main suite with standard settings. If You specify the name of a test
+# as the first argument (e.g. "./run EditTest"), it will run only that test.
+# Other arguments (like "-v" for verbose mode) are passed to the test. If
+# you want to pass arguments to the main suite, you'll have to name it
+# explicitly, (e.g. "./run WikiSuite -v -n")
+#
+
+if [[ "$1" == "" ]]; then CLASS=WikiSuite; else CLASS=$1; fi
+java -classpath ./build:jars/httpunit.jar:jars/nekohtml.jar:jars/xercesImpl.jar:jars/xml-apis.jar com.piclab.wikitest.$CLASS $2 $3 $4 $5 $6 $7 $8 $9
diff --git a/testsuite/src/com/piclab/wikitest/DBLoader.java b/testsuite/src/com/piclab/wikitest/DBLoader.java
new file mode 100644 (file)
index 0000000..50bc825
--- /dev/null
@@ -0,0 +1,90 @@
+
+/*
+ * Special "test" for initial loading of the database.
+ * It doesn't do the normal run-and-report thing, but it
+ * it inherits from WikiTest because it needs to do the
+ * same kinds of things that tests do, i.e., interacting
+ * with the wiki.
+ */
+
+package com.piclab.wikitest;
+import com.meterware.httpunit.*;
+
+public class DBLoader extends WikiTest {
+
+private WebResponse loadPageFromFile( String title )
+throws WikiSuiteFailureException {
+       StringBuffer url = new StringBuffer(200);
+       String t = WikiTest.titleToUrl( title );
+
+       url.append( "data/" ).append( t ).append( ".txt" );
+       String text = WikiSuite.loadText( url.toString() );
+
+       WebResponse wr = replacePage( title, text );
+       WikiSuite.fine( "Loaded \"" + title + "\"" );
+       return wr;
+}
+
+/*
+ * Load database with initial set of pages for testing.
+ */
+
+public void initializeDatabase( WikiSuite ws, boolean f_overwrite ) {
+       WebResponse wr = null;
+       String text = null;
+
+       m_suite = ws;
+       try {
+               wr = viewPage( "" );
+       } catch ( WikiSuiteFailureException e ) {
+               WikiSuite.error( "Can't find Wikipedia installation." );
+               return;
+       }
+       if ( ! f_overwrite ) {
+               try {
+                       text = getArticle( wr );
+                       if ( text.indexOf( "no text in this page" ) < 0 ) {
+                               WikiSuite.error( "Target wiki is not empty." );
+                               return;
+                       }
+               } catch( WikiSuiteFailureException e ) {
+                       WikiSuite.error( "Can't access target wiki." );
+                       return;
+               }
+       }
+       WikiSuite.info( "Preloading database with test pages." );
+
+       for (int i = 0; i < WikiSuite.preloadedPages.length; ++i) {
+               try {
+                       wr = loadPageFromFile( WikiSuite.preloadedPages[i] );
+               } catch (WikiSuiteFailureException e) {
+                       WikiSuite.warning( "Failed to load \"" +
+                         WikiSuite.preloadedPages[i] + "\"" );
+               }
+       }
+
+       WikiSuite.info( "Creating test users." );
+       try {
+               wr = viewPage( "Special:Userlogin" );
+               WebForm loginform = getFormByName( wr, "userlogin" );
+               WebRequest req = loginform.getRequest( "wpCreateaccount" );
+               req.setParameter( "wpName", "Fred" );
+               req.setParameter( "wpPassword", "Fred" );
+               req.setParameter( "wpRetype", "Fred" );
+               wr = getResponse( req );
+
+               wr = viewPage( "Special:Userlogin" );
+               loginform = getFormByName( wr, "userlogin" );
+               req = loginform.getRequest( "wpCreateaccount" );
+               req.setParameter( "wpName", "Barney" );
+               req.setParameter( "wpPassword", "Barney" );
+               req.setParameter( "wpRetype", "Barney" );
+               wr = getResponse( req );
+
+               logout();
+       } catch ( Exception e ) {
+               WikiSuite.error( "Exception (" + e + ") parsing login form." );
+       }
+}
+
+}
diff --git a/testsuite/src/com/piclab/wikitest/EditTest.java b/testsuite/src/com/piclab/wikitest/EditTest.java
new file mode 100644 (file)
index 0000000..62819c2
--- /dev/null
@@ -0,0 +1,219 @@
+/*
+ * Test that basic page editing is working.
+ */
+
+package com.piclab.wikitest;
+
+import com.meterware.httpunit.*;
+import java.io.*;
+
+public class EditTest extends WikiTest {
+
+public String testName() { return "Editing"; }
+
+protected int initTest() throws Exception {
+       WebResponse wr = deletePage( "Omaha" );
+       wr = deletePage( "Math" );
+       /* deletePage will always logout */
+       return 0;
+}
+
+protected int runTest() throws Exception {
+       int c = 0;
+
+       if ( 0 != ( c = part1() ) ) { return fail( c ); }
+       if ( 0 != ( c = part2() ) ) { return fail( c ); }
+       if ( 0 != ( c = part3() ) ) { return fail( c ); }
+       if ( 0 != ( c = part4() ) ) { return fail( c ); }
+       if ( 0 != ( c = part5() ) ) { return fail( c ); }
+       return 0;
+}
+
+private int part1() throws Exception {
+       /*
+        * Add a line to some pages.  See that the change
+        * shows up in Recent Changes, and the new text appears.
+        */
+       WebResponse wr = addText( "Agriculture",
+         "Edited for testing: 85769476243364759655." );
+
+       wr = viewPage( "Special:Recentchanges" );
+       String text = getArticle( wr );
+       if ( text.indexOf( "Agriculture" ) < 0 ) { return 101; }
+
+       wr = viewPage( "Agriculture" );
+       text = getArticle( wr );
+       if ( text.indexOf( "85769476243364759655" ) < 0 ) { return 102; }
+
+       wr = addText( "Talk:Physics", "Edited for testing: 98762415237651243634" );
+       wr = addText( "User:Fred", "Edited for testing: 54637465888374655394" );
+
+       wr = viewPage( "Special:Recentchanges" );
+       text = getArticle( wr );
+       if ( text.indexOf( "Talk:Physics" ) < 0 ) { return 103; }
+       if ( text.indexOf( "User:Fred" ) < 0 ) { return 104; }
+       if ( text.indexOf( "Wikitest addition" ) < 0 ) { return 105; }
+
+       wr = viewPage( "Talk:Physics" );
+       text = getArticle( wr );
+       if ( text.indexOf( "98762415237651243634" ) < 0 ) { return 106; }
+       if ( text.indexOf( "54637465888374655394" ) >= 0 ) { return 107; }
+
+       wr = viewPage( "User:Fred" );
+       text = getArticle( wr );
+       if ( text.indexOf( "54637465888374655394" ) < 0 ) { return 108; }
+       if ( text.indexOf( "98762415237651243634" ) >= 0 ) { return 109; }
+
+       return 0;
+}
+
+private int part2() throws Exception {
+       /*
+        * Create a new page, verify it, add to it, replace it.
+        */
+       WebResponse wr = viewPage( "Omaha" );
+       /* Should have been deleted in initTest() */
+
+       String text = getArticle( wr );
+       if ( text.indexOf( "no text in this page" ) < 0 ) { return 201; }
+
+       wr = addText( "Omaha", "'''Omaha''' is a city in [[Florida]]" );
+       wr = viewPage( "Omaha" );
+       text = getArticle( wr );
+
+       if ( text.indexOf( "no text in this page" ) >= 0 ) { return 202; }
+       if ( text.indexOf( "Florida" ) < 0 ) { return 203; }
+
+       wr = addText( "Omaha", "And a [[poker]] game for masochists." );
+       wr = viewPage( "Special:Recentchanges" );
+       text = getArticle( wr );
+       if ( text.indexOf( "Omaha" ) < 0 ) { return 204; }
+       if ( text.indexOf( "Wikitest addition to Omaha" ) < 0 ) { return 205; }
+
+       wr = viewPage( "Omaha" );
+       text = getArticle( wr );
+       if ( text.indexOf( "Florida" ) < 0 ) { return 206; }
+       if ( text.indexOf( "poker" ) < 0 ) { return 207; }
+
+       wr = editPage( "Omaha" );
+       WebForm editform = getFormByName( wr, "editform" );
+       WebRequest req = editform.getRequest( "wpSave" );
+       req.setParameter( "wpTextbox1", "See: \n" +
+         "* [[Omaha, Nebraska]]\n* [[Omaha holdem|Omaha hold'em]]" );
+       wr = getResponse( req );
+
+       text = getArticle( wr );
+       if ( text.indexOf( "Florida" ) >= 0 ) { return 208; }
+       if ( text.indexOf( "poker" ) >= 0 ) { return 209; }
+       if ( text.indexOf( "Nebraska" ) < 0 ) { return 210; }
+       if ( text.indexOf( "holdem" ) < 0 ) { return 211; }
+
+       return 0;
+}
+
+private int part3() throws Exception {
+       /*
+        * Log in and make some edits as a user.
+        */
+       WebResponse wr = loginAs( "Fred", "Fred" );
+       wr = addText( "Talk:Language", "This page sucks!" );
+
+       wr = viewPage( "Special:Recentchanges" );
+       String text = getArticle( wr );
+       if ( text.indexOf( "Fred" ) < 0 ) { return 301; }
+
+       wr = loginAs( "Barney", "Barney" );
+       wr = addText( "Talk:Language", "No it doesn't" );
+
+       wr = viewPage( "Special:Recentchanges" );
+       text = getArticle( wr );
+       if ( text.indexOf( "Barney" ) < 0 ) { return 302; }
+       if ( text.indexOf( "Wikitest addition to Talk:Language" ) < 0 ) { return 303; }
+
+       wr = viewPage( "Talk:Language" );
+       text = getArticle( wr );
+       if ( text.indexOf( "sucks" ) < 0 ) { return 304; }
+       if ( text.indexOf( "doesn't" ) < 0 ) { return 305; }
+
+       WebLink l = wr.getFirstMatchingLink( WebLink.MATCH_CONTAINED_TEXT, "Older versions" );
+       wr = l.click();
+       text = getArticle( wr );
+       if ( text.indexOf( "Fred" ) < 0 ) { return 306; }
+       if ( text.indexOf( "Barney" ) < 0 ) { return 307; }
+
+       return 0;
+}
+
+private int part4() throws Exception {
+       /*
+        * Verify edit conflict handling. We have to create a separate
+        * conversation here and handle the forms manually rather than
+        * relying on the WikiSuite stuff.
+        */
+       WebConversation fredc = new WebConversation();
+       WebResponse wr = fredc.getResponse( viewUrl( "Special:Userlogin" ) );
+       WebForm loginform = getFormByName( wr, "userlogin" );
+       WebRequest req = loginform.getRequest( "wpLoginattempt" );
+       req.setParameter( "wpName", "Fred" );
+    req.setParameter( "wpPassword", "Fred" );
+    wr = fredc.getResponse( req );
+
+       wr = fredc.getResponse( viewUrl( "Dance", "action=edit" ) );
+
+       WebForm editform = getFormByName( wr, "editform" );
+       req = editform.getRequest( "wpSave" );
+       String old = req.getParameter( "wpTextbox1" );
+       req.setParameter( "wpTextbox1", old + "\nFred's edit" );
+
+       loginAs( "Barney", "Barney" );
+       wr = addText( "Dance", "\nBarney's edit" );
+
+       wr = fredc.getResponse( req );
+       String text = getArticle( wr );
+       String title = wr.getTitle();
+
+       if ( title.indexOf( "conflict" ) < 0 ) { return 401; }
+       if ( text.indexOf( "Your changes are shown" ) < 0 ) { return 402; }
+
+       return 0;
+}
+
+private int part5() throws Exception {
+       /*
+        * Verify page protection, preview, redirect.
+        */
+       WebResponse wr = logout();
+       wr = viewPage( "Wikipedia:Upload_log" );
+       String text = wr.getText();
+       if ( text.indexOf( "Protected page" ) < 0 ) { return 501; }
+       if ( text.indexOf( "Edit this page" ) >= 0 ) { return 502; }
+
+       wr = editPage( "Sociology" );
+       WebForm editform = getFormByName( wr, "editform" );
+       WebRequest req = editform.getRequest( "wpPreview" );
+
+       String old = req.getParameter( "wpTextbox1" );
+       req.setParameter( "wpTextbox1", old + "\n" + "''Preview test''" );
+       wr = getResponse( req );
+
+       text = getArticle( wr );
+       if ( text.indexOf( "<h2>Preview</h2>" ) < 0 ) { return 503; }
+       if ( text.indexOf( "<em>Preview test</em>" ) < 0 ) { return 504; }
+
+       wr = replacePage( "Math", "#REDIRECT [[Mathematics]]\n" );
+       wr = viewPage( "Math" );
+
+       text = wr.getTitle();
+       if ( text.indexOf( "Mathematics" ) < 0 ) { return 505; }
+       text = getArticle( wr );
+       if ( text.indexOf( "(Redirected from" ) < 0 ) { return 506; }
+       if ( text.indexOf( "<strong>Mathematics</strong>" ) < 0 ) { return 507; }
+
+       return 0;
+}
+
+public static void main( String[] params ) {
+       (new EditTest()).runSingle( params );
+}
+
+}
diff --git a/testsuite/src/com/piclab/wikitest/HTMLTest.java b/testsuite/src/com/piclab/wikitest/HTMLTest.java
new file mode 100644 (file)
index 0000000..288f988
--- /dev/null
@@ -0,0 +1,202 @@
+
+/*
+ * View pages with various skins and make sure they're basically
+ * valid HTML structured the way we expect.  For now we're just
+ * using regexes, which should be fine for the sample pages.  They
+ * would probably fail on pages about HTML markup and such, though.
+ * Eventualy, we should be scanning the DOM for these tests.
+ */
+
+package com.piclab.wikitest;
+
+import com.meterware.httpunit.*;
+import java.util.regex.*;
+import java.io.*;
+import org.w3c.dom.*;
+
+public class HTMLTest extends WikiTest {
+
+/* Regex patterns to look for on every page; "good" patterns should
+ * be found, "bad" patterns should be absent.
+ */
+
+private String[] m_goodpats = {
+       "\\A\\s*<!doctype html", "<meta\\s+[^>]*name\\s*=\\s*.robots",
+       "<head[^>]*>.*<title[^>]*>.*</title>.*</head>\\s*<body",
+       "<link\\s+[^>]*rel\\s*=\\s*.stylesheet", "<h1\\s+[^>]*class\\s*=.pagetitle",
+       "<form\\s+[^>]*id\\s*=\\s*.search", 
+       "<div\\s+[^>]*id\\s*=.content.*<div\\s+[^>]*id\\s*=.article",
+};
+private Pattern[] m_cgoodpats;
+
+private String[] m_badpats = {
+       "<[^>]*onclick\\s*=", "<applet", "<object", "<body.*<script.*</body"
+};
+private Pattern[] m_cbadpats;
+
+/* TODO: figure out some way to check for unbalanced <ul>, etc. */
+
+public String testName() { return "HTML"; }
+
+
+protected int initTest() throws Exception {
+       logout();
+       /*
+        * Pre-compile the regexes.
+        */
+       m_cgoodpats = new Pattern[m_goodpats.length];
+       for (int i = 0; i < m_goodpats.length; ++i) {
+               m_cgoodpats[i] = Pattern.compile( m_goodpats[i],
+                 Pattern.CASE_INSENSITIVE | Pattern.DOTALL );
+       }
+       m_cbadpats = new Pattern[m_badpats.length];
+       for (int i = 0; i < m_badpats.length; ++i) {
+               m_cbadpats[i] = Pattern.compile( m_badpats[i],
+                 Pattern.CASE_INSENSITIVE | Pattern.DOTALL );
+       }
+       return 0;
+}
+
+protected int runTest() throws Exception {
+       int c = 0;
+
+       if ( 0 != ( c = part1() ) ) { return fail(c); }
+       if ( 0 != ( c = part2() ) ) { return fail(c); }
+       return 0;
+}
+
+private int part1() throws Exception {
+       WebResponse wr = loginAs( "Fred", "Fred" );
+       Document doc = wr.getDOM();
+       if ( ! matchesAll( wr.getText() ) ) { return 101; }
+
+       WebRequest req = openPrefs();
+       req.removeParameter( "wpOpnumberheadings" );
+       req.setParameter( "wpOphighlightbroken", "1" );
+       wr = getResponse( req );
+       WikiSuite.fine( "Standard settings" );
+
+       int c = 0;
+       if ( 0 != ( c = part1inner() ) ) { return 110 + c; }
+
+       req = openPrefs();
+       req.setParameter( "wpOpnumberheadings", "1" );
+       wr = getResponse( req );
+       WikiSuite.fine( "Numbered headings" );
+
+       if ( 0 != ( c = part1inner() ) ) { return 120 + c; }
+
+       req = openPrefs();
+       req.setParameter( "wpOphighlightbroken", "1" );
+       wr = getResponse( req );
+       WikiSuite.fine( "Question-mark links" );
+
+       if ( 0 != ( c = part1inner() ) ) { return 130 + c; }
+       return 0;
+}
+
+private int part1inner() throws Exception {
+       WebResponse wr = viewPage( "" );
+       /*
+        * Will throw exception if not parseable:
+        */
+       Document doc = wr.getDOM();
+       if ( ! matchesAll( wr.getText() ) ) { return 1; }
+
+       wr = viewPage( "Opera" );
+       doc = wr.getDOM();
+       if ( ! matchesAll( wr.getText() ) ) { return 2; }
+
+       wr = viewPage( "User:Fred" );
+       doc = wr.getDOM();
+       if ( ! matchesAll( wr.getText() ) ) { return 3; }
+
+       wr = viewPage( "Special:Recentchanges" );
+       doc = wr.getDOM();
+       if ( ! matchesAll( wr.getText() ) ) { return 4; }
+
+       wr = viewPage( "Talk:Poker" );
+       doc = wr.getDOM();
+       if ( ! matchesAll( wr.getText() ) ) { return 5; }
+
+       wr = viewPage( "Wikipedia:Upload_log" );
+       doc = wr.getDOM();
+       if ( ! matchesAll( wr.getText() ) ) { return 6; }
+
+       return 0;
+}
+
+private int part2() throws Exception {
+       WebResponse wr = loginAs( "Barney", "Barney" );
+       Document doc = wr.getDOM();
+       if ( ! matchesAll( wr.getText() ) ) { return 201; }
+
+       WebRequest req = openPrefs();
+       req.removeParameter( "wpOpnumberheadings" );
+       req.setParameter( "wpOphighlightbroken", "1" );
+       wr = getResponse( req );
+
+       for (int q = 0; q < 4; ++q) {
+               req = openPrefs();
+               req.setParameter( "wpQuickbar", String.valueOf( q ) );
+               wr = getResponse( req );
+
+               doc = wr.getDOM();
+               if ( ! matchesAll( wr.getText() ) ) { return 200 + 10 * q; }
+               WikiSuite.finer( "Set quickbar to " + q );
+
+               for (int s = 0; s < 3; ++s) {
+                       req = openPrefs();
+                       req.setParameter( "wpSkin", String.valueOf( s ) );
+                       wr = getResponse( req );
+                       WikiSuite.finer( "Set skin to " + s );
+
+                       double r = Math.random();
+                       if ( r < .5 ) {
+                               wr = viewPage( WikiSuite.preloadedPages[
+                                 (int)(r * 100.0)] );
+                       } else if ( r < .6 ) {
+                               wr = viewPage( "User:Fred" );
+                       } else if ( r < .7 ) {
+                               wr = viewPage( "Special:Recentchanges" );
+                       } else if ( r < .8 ) {
+                               wr = editPage( "Talk:Sport" );
+                       } else if ( r < .9 ) {
+                               wr = editPage( "Wikipedia:Upload_log" );
+                       } else {
+                               wr = viewPage( "" );
+                       }
+                       doc = wr.getDOM();
+                       if ( ! matchesAll( wr.getText() ) ) { return 201 + 10 * q + s; }
+               }
+       }
+       return 0;
+}
+
+private boolean matchesAll( String text ) {
+       if ( m_cgoodpats[0] == null ) {
+               WikiSuite.error( "Patterns not compiled." );
+               return false;
+       }
+       for (int i = 0; i < m_goodpats.length; ++i) {
+               Matcher m = m_cgoodpats[i].matcher( text );
+               if ( ! m.find() ) {
+                       WikiSuite.error( "Failed to match pattern \"" + m_goodpats[i] + "\"" );
+                       return false;
+               }
+       }
+       for (int i = 0; i < m_badpats.length; ++i) {
+               Matcher m = m_cbadpats[i].matcher( text );
+               if ( m.find() ) {
+                       WikiSuite.error( "Matched pattern \"" + m_badpats[i] + "\"" );
+                       return false;
+               }
+       }
+       return true;
+}
+
+public static void main( String[] params ) {
+       (new HTMLTest()).runSingle( params );
+}
+
+}
diff --git a/testsuite/src/com/piclab/wikitest/LinkTest.java b/testsuite/src/com/piclab/wikitest/LinkTest.java
new file mode 100644 (file)
index 0000000..afd0535
--- /dev/null
@@ -0,0 +1,205 @@
+
+/*
+ * Test that basic navigation around the wiki with
+ * internal links is working.
+ */
+
+package com.piclab.wikitest;
+
+import com.meterware.httpunit.*;
+
+public class LinkTest extends WikiTest {
+
+public String testName() { return "Links"; }
+
+protected int initTest() throws Exception {
+       WebResponse wr = deletePage( "Talk:Poker" ); /* Will logout */
+       return 0;
+}
+
+protected int runTest() throws Exception {
+       int c = 0;
+
+       if ( 0 != ( c = part1() ) ) { return fail( c ); }
+       if ( 0 != ( c = part2() ) ) { return fail( c ); }
+       if ( 0 != ( c = part3() ) ) { return fail( c ); }
+       if ( 0 != ( c = part4() ) ) { return fail( c ); }
+       if ( 0 != ( c = part5() ) ) { return fail( c ); }
+       return 0;
+}
+
+private int part1() throws Exception {
+       /*
+        * Check that we can click through from main page to games,
+        * card games, poker, world series.
+        */
+       WebResponse wr = viewPage( "" ); /* Main page */
+       WebLink l = wr.getFirstMatchingLink( WebLink.MATCH_CONTAINED_TEXT, "Game" );
+       if ( l == null ) { return 101; }
+       wr = l.click();
+
+       l = wr.getFirstMatchingLink( WebLink.MATCH_CONTAINED_TEXT, "Card" );
+       if ( l == null ) { return 102; }
+       wr = l.click();
+
+       l = wr.getFirstMatchingLink( WebLink.MATCH_CONTAINED_TEXT, "Poker" );
+       if ( l == null ) { return 103; }
+       wr = l.click();
+
+       l = wr.getFirstMatchingLink( WebLink.MATCH_CONTAINED_TEXT, "World Series" );
+       if ( l == null ) { return 104; }
+       wr = l.click();
+
+       return 0;
+}
+
+private int part2() throws Exception {
+       /* 
+        * Poker page should have some standard links on it, and should
+        * _not_ have an upload link or user stat links on it because we
+        * aren't logged in.
+        */
+       WebResponse wr = viewPage( "Poker" );
+       WebLink l = wr.getFirstMatchingLink( WebLink.MATCH_CONTAINED_TEXT, "Printable version" );
+       if ( l == null ) { return 201; }
+       l = wr.getFirstMatchingLink( WebLink.MATCH_CONTAINED_TEXT, "Related changes" );
+       if ( l == null ) { return 202; }
+
+       l = wr.getFirstMatchingLink( WebLink.MATCH_CONTAINED_TEXT, "Upload file" );
+       if ( l != null ) { return 203; }
+       l = wr.getFirstMatchingLink( WebLink.MATCH_CONTAINED_TEXT, "My watchlist" );
+       if ( l != null ) { return 204; }
+       l = wr.getFirstMatchingLink( WebLink.MATCH_CONTAINED_TEXT, "My contributions" );
+       if ( l != null ) { return 205; }
+
+       return 0;
+}
+
+private int part3() throws Exception {
+       /*
+        * Talk:Poker was not preloaded, so we should be on an edit form
+        * when we click that link from the Poker page.  Add a comment,
+        * then check for some standard links on the new talk page and
+        * the resulting history page.
+        */
+       WebResponse wr = viewPage( "Poker" );
+       WebLink l = wr.getFirstMatchingLink( WebLink.MATCH_CONTAINED_TEXT, "Discuss this page" );
+       if ( l == null ) { return 301; }
+       wr = l.click();
+
+       WebForm editform = getFormByName( wr, "editform" );
+    WebRequest req = editform.getRequest( "wpSave" );
+    req.setParameter( "wpTextbox1", "Great article!" );
+    wr = getResponse( req );
+
+       l = wr.getFirstMatchingLink( WebLink.MATCH_CONTAINED_TEXT, "View article" );
+       l = wr.getFirstMatchingLink( WebLink.MATCH_CONTAINED_TEXT, "Older versions" );
+       if ( l == null ) { return 302; }
+       wr = l.click();
+
+       l = wr.getFirstMatchingLink( WebLink.MATCH_CONTAINED_TEXT, "Current revision" );
+       if ( l == null ) { return 303; }
+       l = wr.getFirstMatchingLink( WebLink.MATCH_CONTAINED_TEXT, "View discussion" );
+       if ( l == null ) { return 304; }
+       l = wr.getFirstMatchingLink( WebLink.MATCH_CONTAINED_TEXT, "View article" );
+       if ( l == null ) { return 305; }
+       wr = l.click();
+
+       return 0;
+}
+
+private int part4() throws Exception {
+       /*
+        * Let's log in now and verify that things are changed.
+        */
+       WebResponse wr = viewPage( "Poker" );
+       WebLink l = wr.getFirstMatchingLink( WebLink.MATCH_CONTAINED_TEXT, "Log in" );
+       if ( l == null ) { return 401; }
+       wr = l.click();
+
+       wr = loginAs( "Fred", "Fred" );
+       wr = viewPage( "Poker" );
+
+       l = wr.getFirstMatchingLink( WebLink.MATCH_CONTAINED_TEXT, "My watchlist" );
+       if ( l == null ) { return 402; }
+       l = wr.getFirstMatchingLink( WebLink.MATCH_CONTAINED_TEXT, "My contributions" );
+       if ( l == null ) { return 403; }
+       l = wr.getFirstMatchingLink( WebLink.MATCH_CONTAINED_TEXT, "new messages" );
+       if ( l != null ) { return 404; }
+       l = wr.getFirstMatchingLink( WebLink.MATCH_CONTAINED_TEXT, "Upload file" );
+       if ( l == null ) { return 405; }
+       wr = l.click();
+
+       l = wr.getFirstMatchingLink( WebLink.MATCH_CONTAINED_TEXT, "list of uploaded images" );
+       if ( l == null ) { return 406; }
+       l = wr.getFirstMatchingLink( WebLink.MATCH_CONTAINED_TEXT, "upload log" );
+       if ( l == null ) { return 407; }
+
+       return 0;
+}
+
+private int part5() throws Exception {
+       /*
+        * Verify that the user page and user talk page are OK.
+        */
+       WebResponse wr = viewPage( "" );
+       WebLink l = wr.getFirstMatchingLink( WebLink.MATCH_CONTAINED_TEXT, "Fred" );
+       if ( l == null ) { return 501; }
+       wr = l.click();
+
+       l = wr.getFirstMatchingLink( WebLink.MATCH_CONTAINED_TEXT, "User contributions" );
+       if ( l == null ) { return 502; }
+       wr = l.click();
+
+       l = wr.getFirstMatchingLink( WebLink.MATCH_CONTAINED_TEXT, "Talk" );
+       if ( l == null ) { return 503; }
+       wr = l.click();
+
+       /*
+        * Log out, clear cookies, edit talk page, then log back in and
+        * verify "new messages" link.
+        */
+       l = wr.getFirstMatchingLink( WebLink.MATCH_CONTAINED_TEXT, "Log out" );
+       if ( l == null ) { return 504; }
+       wr = l.click();
+       clearCookies();
+
+       wr = editPage( "User talk:Fred" );
+       WebForm editform = getFormByName( wr, "editform" );
+    WebRequest req = editform.getRequest( "wpSave" );
+    req.setParameter( "wpTextbox1", "Wake up!" );
+    wr = getResponse( req );
+
+       l = wr.getFirstMatchingLink( WebLink.MATCH_CONTAINED_TEXT, "Main Page" );
+       if ( l == null ) { return 505; }
+       wr = l.click();
+
+       l = wr.getFirstMatchingLink( WebLink.MATCH_CONTAINED_TEXT, "Log in" );
+       if ( l == null ) { return 506; }
+       wr = l.click();
+
+       WebForm loginform = getFormByName( wr, "userlogin" );
+       req = loginform.getRequest( "wpLoginattempt" );
+       req.setParameter( "wpName", "Fred" );
+       req.setParameter( "wpPassword", "Fred" );
+       wr = getResponse( req );
+
+       l = wr.getFirstMatchingLink( WebLink.MATCH_CONTAINED_TEXT, "new messages" );
+       if ( l == null ) { return 507; }
+       wr = l.click();
+
+       l = wr.getFirstMatchingLink( WebLink.MATCH_CONTAINED_TEXT, "Main Page" );
+       if ( l == null ) { return 508; }
+       wr = l.click();
+
+       l = wr.getFirstMatchingLink( WebLink.MATCH_CONTAINED_TEXT, "new messages" );
+       if ( l != null ) { return 509; }
+
+       return 0;
+}
+
+public static void main( String[] params ) {
+       (new LinkTest()).runSingle( params );
+}
+
+}
diff --git a/testsuite/src/com/piclab/wikitest/MathTest.java b/testsuite/src/com/piclab/wikitest/MathTest.java
new file mode 100644 (file)
index 0000000..58bb711
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * Test functioning of texvc math functions.
+ */
+
+package com.piclab.wikitest;
+import com.meterware.httpunit.*;
+
+public class MathTest extends WikiTest {
+
+public String testName() { return "Math"; }
+
+protected int initTest() throws Exception {
+       logout();
+       return 0;
+}
+
+protected int runTest() throws Exception {
+       int c = 0;
+
+       if ( 0 != ( c = part1() ) ) { return fail( c ); }
+       return 0;
+}
+
+private int part1() throws Exception {
+       String[] goodpats = {
+         "\\(1\\)\\s+<img\\s[^>]*\\salt\\s*=\\s*.?\\\\phi\\s+=\\s+\\\\frac",
+         "\\(2\\)\\s+<img\\s[^>]*\\salt\\s*=\\s*.?\\\\phi\\s+=\\s+\\\\frac",
+         "\\(3\\)\\s+&phi;\\s+\\+",
+         "\\(4\\)\\s+&phi;\\s*<sup>\\s*2",
+         "\\(5\\)\\s+<img\\s[^>]*\\salt\\s*=\\s*.?\\\\phi\\s+=\\s+\\\\frac",
+         "\\(6\\)\\s+<img\\s[^>]*\\salt\\s*=\\s*.?\\\\phi\\s+\\\\approx"
+       };
+
+       WebResponse wr = viewPage( "Equations" );
+       String text = getArticle( wr );
+
+       int ret;
+       if ( 0 != ( ret = checkGoodPatterns( text, goodpats ) ) ) {
+               return 100 + ret;
+       }
+
+       wr = loginAs( "Barney", "Barney" );
+       WebRequest req = openPrefs();
+       req.setParameter( "wpMath", "0" );
+       wr = getResponse( req );
+
+       String[] goodpats0 = {
+         "\\(1\\)\\s+<img\\s[^>]*\\salt\\s*=\\s*.?\\\\phi\\s+=\\s+\\\\frac",
+         "\\(2\\)\\s+<img\\s[^>]*\\salt\\s*=\\s*.?\\\\phi\\s+=\\s+\\\\frac",
+         "\\(3\\)\\s+<img\\s[^>]*\\salt\\s*=\\s*.?\\\\phi\\s+\\+",
+         "\\(4\\)\\s+<img\\s[^>]*\\salt\\s*=\\s*.?\\\\phi\\s*\\^\\s*2",
+         "\\(5\\)\\s+<img\\s[^>]*\\salt\\s*=\\s*.?\\\\phi\\s+=\\s+\\\\frac",
+         "\\(6\\)\\s+<img\\s[^>]*\\salt\\s*=\\s*.?\\\\phi\\s+\\\\approx"
+       };
+
+       wr = viewPage( "Equations" );
+       text = getArticle( wr );
+       if ( 0 != ( ret = checkGoodPatterns( text, goodpats0 ) ) ) {
+               return 110 + ret;
+       }
+
+       wr = loginAs( "Barney", "Barney" );
+       req = openPrefs();
+       req.setParameter( "wpMath", "2" );
+       wr = getResponse( req );
+
+       String[] goodpats2 = {
+         "\\(1\\)\\s+<table",
+         "\\(2\\)\\s+<table",
+         "\\(3\\)\\s+&phi;\\s+\\+",
+         "\\(4\\)\\s+&phi;\\s*<sup>\\s*2",
+         "\\(5\\)\\s+<img\\s[^>]*\\salt\\s*=\\s*.?\\\\phi\\s+=\\s+\\\\frac",
+         "\\(6\\)\\s+<img\\s[^>]*\\salt\\s*=\\s*.?\\\\phi\\s+\\\\approx"
+       };
+
+       wr = viewPage( "Equations" );
+       text = getArticle( wr );
+       if ( 0 != ( ret = checkGoodPatterns( text, goodpats2 ) ) ) {
+               return 120 + ret;
+       }
+
+       wr = loginAs( "Barney", "Barney" );
+       req = openPrefs();
+       req.setParameter( "wpMath", "3" );
+       wr = getResponse( req );
+
+       String[] goodpats3 = {
+         "\\(1\\)\\s+\\$\\s+\\\\phi\\s+=\\s+\\\\frac",
+         "\\(2\\)\\s+\\$\\s+\\\\phi\\s+=\\s+\\\\frac",
+         "\\(3\\)\\s+\\$\\s+\\\\phi\\s+\\+\\s+\\\\phi\\s*\\^\\s*2",
+         "\\(4\\)\\s+\\$\\s+\\\\phi\\s*\\^\\s*2\\s+\\+\\s+\\\\phi",
+         "\\(5\\)\\s+\\$\\s+\\\\phi\\s+=\\s+\\\\frac",
+         "\\(6\\)\\s+\\$\\s+\\\\phi\\s+\\\\approx"
+       };
+
+       wr = viewPage( "Equations" );
+       text = getArticle( wr );
+       if ( 0 != ( ret = checkGoodPatterns( text, goodpats3 ) ) ) {
+               return 130 + ret;
+       }
+
+       wr = loginAs( "Barney", "Barney" );
+       req = openPrefs();
+       req.setParameter( "wpMath", "4" );
+       wr = getResponse( req );
+
+       String[] goodpats4 = {
+         "\\(1\\)\\s+<img\\s[^>]*\\salt\\s*=\\s*.?\\\\phi\\s+=\\s+\\\\frac",
+         "\\(2\\)\\s+<img\\s[^>]*\\salt\\s*=\\s*.?\\\\phi\\s+=\\s+\\\\frac",
+         "\\(3\\)\\s+&phi;\\s+\\+",
+         "\\(4\\)\\s+&phi;\\s*<sup>\\s*2",
+         "\\(5\\)\\s+<img\\s[^>]*\\salt\\s*=\\s*.?\\\\phi\\s+=\\s+\\\\frac",
+         "\\(6\\)\\s+<img\\s[^>]*\\salt\\s*=\\s*.?\\\\phi\\s+\\\\approx"
+       };
+
+       wr = viewPage( "Equations" );
+       text = getArticle( wr );
+       if ( 0 != ( ret = checkGoodPatterns( text, goodpats4 ) ) ) {
+               return 140 + ret;
+       }
+       return 0;
+}
+
+public static void main( String[] params ) {
+       (new MathTest()).runSingle( params );
+}
+
+}
diff --git a/testsuite/src/com/piclab/wikitest/ParserTest.java b/testsuite/src/com/piclab/wikitest/ParserTest.java
new file mode 100644 (file)
index 0000000..f8466b0
--- /dev/null
@@ -0,0 +1,278 @@
+
+/*
+ * Test parsing of WikiText into HTML.
+ */
+
+package com.piclab.wikitest;
+import com.meterware.httpunit.*;
+import java.util.regex.*;
+
+public class ParserTest extends WikiTest {
+
+public String testName() { return "Parsing"; }
+
+protected int initTest() throws Exception {
+       logout();
+       return 0;
+}
+
+protected int runTest() throws Exception {
+       int c = 0;
+
+       if ( 0 != ( c = part1() ) ) { return fail( c ); }
+       if ( 0 != ( c = part2() ) ) { return fail( c ); }
+       if ( 0 != ( c = part3() ) ) { return fail( c ); }
+       if ( 0 != ( c = part4() ) ) { return fail( c ); }
+       if ( 0 != ( c = part5() ) ) { return fail( c ); }
+       if ( 0 != ( c = part6() ) ) { return fail( c ); }
+       if ( 0 != ( c = part7() ) ) { return fail( c ); }
+       return 0;
+}
+
+/*
+ * Check replacement of variables like {{NUMBEROFARTICLES}}
+ */
+private int part1() throws Exception {
+       String[] pats = {
+         "Month: \\d+", "Month name: [A-Z][a-z]+", "Day: \\d+",
+         "Day name: [A-Z][a-z]+day", "Year: \\d\\d\\d\\d",
+         "Time: \\d\\d:\\d\\d", "Number of articles: \\d+"
+       };
+
+       WebResponse wr = viewPage( "Bracketvars" );
+       String text = getArticle( wr );
+
+       int ret;
+       if ( 0 != ( ret = checkGoodPatterns( text, pats ) ) ) {
+               return 100 + ret;
+       }
+       return 0;
+}
+
+/*
+ * Check block-level elements like bullet lists and pre sections.
+ */
+private int part2() throws Exception {
+       String[] pats = {
+         "\\(1\\)[^(]*<ul>\\s*<li>[^<]*</li>\\s*<li>[^<]*</li>\\s*<li>[^<]*</li>\\s*</ul>",
+         "\\(2\\)[^(]*<ol>\\s*<li>[^<]*</li>\\s*<li>[^<]*</li>\\s*<li>[^<]*</li>\\s*</ol>",
+         "\\(3\\)[^(]*<ul>\\s*<li>[^<]*</li>\\s*</ul>[^<]*Par",
+         "\\(4\\)[^(]*<ol>\\s*<li>[^<]*</li>\\s*<li>[^<]*</li>\\s*</ol>[^<]*Par",
+         "\\(5\\)[^(]*<pre>\\s*Fixed[^<]*</pre>",
+         "\\(6\\)[^(]*Par[^<]*<ol>\\s*<li>[^<]*</li>\\s*</ol>",
+         "\\(7\\)[^(]*<pre>\\s*Fixed[^<]*</pre>\\s*<ul>\\s*<li>[^<]*</li>\\s*</ul>",
+         "\\(8\\)[^(]*<ul>\\s*<li>\\s*Level 1\\s*</li>\\s*<li>\\s*Level 1\\s*" +
+           "<ul>\\s*<li>\\s*Level 2\\s*</li>\\s*<li>\\s*Level 2\\s*<ul>\\s*" +
+               "<li>\\s*Level 3\\s*</li>\\s*</ul>\\s*</li>\\s*<li>\\s*Level 2\\s*" +
+               "</li>\\s*</ul>\\s*</li>\\s*<li>\\s*Level 1\\s*<ul>\\s*<li>\\s*" +
+               "Level 2\\s*<ul>\\s*<li>\\s*Level 3\\s*<ul>\\s*<li>\\s*Level 4\\s*" +
+               "</li>\\s*</ul>\\s*</li>\\s*</ul>\\s*</li>\\s*</ul>\\s*</li>\\s*" +
+               "<li>\\s*Level 1\\s*</li>\\s*</ul>",
+         "\\(9\\)[^(]*<ol>\\s*<li>\\s*Level 1\\s*</li>\\s*<li>\\s*Level 1\\s*" +
+           "<ol>\\s*<li>\\s*Level 2\\s*</li>\\s*<li>\\s*Level 2\\s*<ol>\\s*" +
+               "<li>\\s*Level 3\\s*</li>\\s*</ol>\\s*</li>\\s*<li>\\s*Level 2\\s*" +
+               "</li>\\s*</ol>\\s*</li>\\s*<li>\\s*Level 1\\s*<ol>\\s*<li>\\s*" +
+               "Level 2\\s*<ol>\\s*<li>\\s*Level 3\\s*<ol>\\s*<li>\\s*Level 4\\s*" +
+               "</li>\\s*</ol>\\s*</li>\\s*</ol>\\s*</li>\\s*</ol>\\s*</li>\\s*" +
+               "<li>\\s*Level 1\\s*</li>\\s*</ol>",
+         "\\(10\\)[^(]*<ul>\\s*<li>\\s*Level 1\\s*</li>\\s*<li>\\s*Level 1\\s*" +
+           "<ol>\\s*<li>\\s*Level 2\\s*</li>\\s*<li>\\s*Level 2\\s*<ul>\\s*" +
+               "<li>\\s*Level 3\\s*</li>\\s*</ul>\\s*</li>\\s*<li>\\s*Level 2\\s*" +
+               "</li>\\s*</ol>\\s*</li>\\s*<li>\\s*Level 1\\s*<ol>\\s*<li>\\s*" +
+               "Level 2\\s*<ul>\\s*<li>\\s*Level 3\\s*<ol>\\s*<li>\\s*Level 4\\s*" +
+               "</li>\\s*</ol>\\s*</li>\\s*</ul>\\s*</li>\\s*</ol>\\s*</li>\\s*" +
+               "<li>\\s*Level 1\\s*</li>\\s*</ul>",
+         "\\(11\\)[^(]*<dl>\\s*<dt>\\s*Word\\s*</dt>\\s*<dd>\\s*Definition\\s*</dd>\\s*</dl>",
+         "\\(12\\)[^(]*<dl>\\s*<dt>\\s*Word\\s*</dt>\\s*<dd>\\s*Definition\\s*</dd>\\s*</dl>",
+         "\\(13\\)[^(]*<dl>\\s*<dt>\\s*Word\\s*<ol>\\s*<li>\\s*First[^<]*</li>" +
+           "\\s*<li>\\s*Second[^<]*</li>\\s*</ol>\\s*</dt>\\s*</dl>",
+         "\\(14\\)[^(]*<dl>\\s*<dd>\\s*<dl>\\s*<dd>\\s*Double[^<]*</dd>\\s*</dl>" +
+           "\\s*</dd>\\s*</dl>",
+         "\\(15\\)[^(]*<dl>\\s*<dd>\\s*<dl>\\s*<dd>\\s*<dl>\\s*<dd>\\s*Triple" +
+           "[^<]*</dd>\\s*</dl>\\s*</dd>\\s*</dl>\\s*</dd>\\s*</dl>\\s*Par"
+       };
+
+       WebResponse wr = viewPage( "Blocklevels" );
+       String text = getArticle( wr );
+
+       int ret;
+       if ( 0 != ( ret = checkGoodPatterns( text, pats ) ) ) {
+               return 200 + ret;
+       }
+       return 0;
+}
+
+/*
+ * Check translation of quotes to bold/italic
+ */
+private int part3() throws Exception {
+       String[] pats = {
+         "\\(1\\) normal <strong>bold</strong> normal",
+         "\\(2\\) normal <em>italic</em> normal",
+       /*"\\(3\\) normal <strong><em>bold italic</em></strong> normal",*/
+         "\\(4\\) normal <strong>bold <em>bold italic</em> bold</strong> normal",
+         "\\(5\\) normal <em>italic <strong>bold italic</strong> italic</em> normal",
+         "\\(6\\) normal <strong><em>bold italic</em> bold</strong> normal",
+       /*"\\(7\\) normal <em><strong>bold italic</strong> italic</em> normal",*/
+         "\\(8\\) normal <em>italic <strong>bold italic</strong></em> normal",
+       /*"\\(9\\) normal <strong>bold <em>bold italic</em></strong> normal",*/
+         "\\(10\\) normal <strong>bold's</strong> normal",
+         "\\(11\\) normal <em>italic's</em> normal",
+         "\\(12\\) normal <em>italic's <strong>bold's italic</strong> italic's</em> normal",
+         "\\(13\\) normal <strong><em>bold's italic</em> bold's</strong> normal",
+       /*"\\(14\\) normal <em>italic</em>' normal", */
+       /*"\\(15\\) normal '<strong>bold</strong> normal", */
+         "\\(16\\) normal <em>italic</em> normal <em>italic</em> normal",
+         "\\(17\\) normal <em>italic</em> normal <strong>bold</strong> normal",
+         "\\(18\\) normal <strong>bold</strong> normal <strong>bold</strong> normal",
+         "\\(19\\) normal <strong>bold</strong> normal <em>italic</em> normal"
+       };
+
+       WebResponse wr = viewPage( "Quotes" );
+       String text = getArticle( wr );
+
+       int ret;
+       if ( 0 != ( ret = checkGoodPatterns( text, pats ) ) ) {
+               return 300 + ret;
+       }
+       return 0;
+}
+
+/*
+ * Check rendering of external links
+ */
+private int part4() throws Exception {
+       String[] pats = {
+         "\\(1\\) <a\\s[^>]*href\\s*=\\s*.http://a/b/c",
+         "\\(1\\) <a\\s[^>]*class\\s*=\\s*.external.[^>]*>ABC</a",
+         "\\(2\\) <a\\s[^>]*href\\s*=\\s*.https://d/e/f",
+         "\\(2\\) <a\\s[^>]*class\\s*=\\s*.external.[^>]*>DEF</a",
+         "\\(3\\) <a\\s[^>]*href\\s*=\\s*.ftp://g/h/i",
+         "\\(3\\) <a\\s[^>]*class\\s*=\\s*.external.[^>]*>GHI</a",
+         "\\(4\\) <a\\s[^>]*href\\s*=\\s*.gopher://j/k/l",
+         "\\(4\\) <a\\s[^>]*class\\s*=\\s*.external.[^>]*>JKL</a",
+         "\\(5\\) <a\\s[^>]*href\\s*=\\s*.news:a\\.b\\.c",
+         "\\(5\\) <a\\s[^>]*class\\s*=\\s*.external.[^>]*>A\\.B\\.C</a",
+         "\\(6\\) <a\\s[^>]*href\\s*=\\s*.mailto:a@b\\.c",
+         "\\(6\\) <a\\s[^>]*class\\s*=\\s*.external.[^>]*>A@B\\.C</a",
+         "\\(7\\) <a\\s[^>]*href\\s*=\\s*.http://m/n/o",
+         "\\(7\\) <a\\s[^>]*class\\s*=\\s*.external.[^>]*>\\[1\\]</a",
+         "\\(8\\) <a\\s[^>]*href\\s*=\\s*.http://p/q/r",
+         "\\(8\\) <a\\s[^>]*class\\s*=\\s*.external.[^>]*>\\[2\\]</a",
+         "\\(9\\) <a\\s[^>]*href\\s*=\\s*.http://a/b/c\\.png",
+         "\\(9\\) <a\\s[^>]*class\\s*=\\s*.external.[^>]*>\\[3\\]</a",
+         "\\(10\\) <a\\s[^>]*href\\s*=\\s*.http://d/e/f\\.jpg",
+         "\\(10\\) <a\\s[^>]*class\\s*=\\s*.external.[^>]*>\\[4\\]</a",
+         "\\(11\\) <a\\s[^>]*href\\s*=\\s*.http://a/b/c",
+         "\\(11\\) <a\\s[^>]*class\\s*=\\s*.external.[^>]*>http://a/b/c</a",
+         "\\(12\\) <img\\s[^>]*src\\s*=\\s*.http://a/b/c\\.png",
+         "\\(12\\) <img\\s[^>]*alt\\s*=\\s*.c\\.png",
+         "\\(13\\) <img\\s[^>]*src\\s*=\\s*.http://d/e/f\\.jpg",
+         "\\(13\\) <img\\s[^>]*alt\\s*=\\s*.f\\.jpg",
+         "\\(14\\) <a\\s[^>]*href\\s*=\\s*.http://a/b/c",
+         "\\(14\\) <a\\s[^>]*class\\s*=\\s*.external.[^>]*>http://a/b/c</a[^>]*>\\. More",
+         "\\(15\\) <a\\s[^>]*href\\s*=\\s*.http://d/e/f",
+         "\\(15\\) <a\\s[^>]*class\\s*=\\s*.external.[^>]*>http://d/e/f</a[^>]*>, More"
+       };
+
+       WebResponse wr = viewPage( "ExternalLinks" );
+       String text = getArticle( wr );
+
+       int ret;
+       if ( 0 != ( ret = checkGoodPatterns( text, pats ) ) ) {
+               return 400 + ret;
+       }
+       return 0;
+}
+
+/*
+ * Check rendering of internal links
+ */
+private int part5() throws Exception {
+       String[] pats = {
+         "\\(1\\) <a\\s[^>]*class\\s*=\\s*.internal",
+         "\\(1\\) <a\\s[^>]*href\\s*=[^>]*Mathematics[^>]*>Mathematics</a",
+         "\\(2\\) <a\\s[^>]*class\\s*=\\s*.new",
+         "\\(2\\) <a\\s[^>]*href\\s*=[^>]*Non-existing_article[^>]*action=edit",
+         "\\(3\\) <a\\s[^>]*class\\s*=\\s*.internal",
+         "\\(3\\) <a\\s[^>]*href\\s*=[^>]*Cooking[^>]*>Burning</a",
+         "\\(4\\) <a\\s[^>]*class\\s*=\\s*.internal",
+         "\\(4\\) <a\\s[^>]*href\\s*=[^>]*User:Fred[^>]*>Fred</a",
+         "\\(5\\) <a\\s[^>]*class\\s*=\\s*.internal",
+         "\\(5\\) <a\\s[^>]*href\\s*=[^>]*Talk:Language[^>]*>Talk:Language</a",
+         "\\(6\\) <a\\s[^>]*class\\s*=\\s*.image",
+         "\\(6\\) <a\\s[^>]*href\\s*=[^>]*Image:Foo.png",
+         "\\(6\\) <a\\s[^>]*>\\s*<img\\s[^>]*src\\s*=[^>]*Foo.png",
+         "\\(6\\) <a\\s[^>]*>\\s*<img\\s[^>]*alt\\s*=[^>]*Foo.png[^>]*>\\s*</a",
+         "\\(7\\) <a\\s[^>]*class\\s*=\\s*.media",
+         "\\(7\\) <a\\s[^>]*href\\s*=[^>]*Bar.ogg[^>]*>Bar.ogg</a",
+       /* International stuff is changing */
+         "\\(9\\) <a\\s[^>]*class\\s*=\\s*.image",
+         "\\(9\\) <a\\s[^>]*href\\s*=[^>]*Image:Bar.jpg",
+         "\\(9\\) <a\\s[^>]*>\\s*<img\\s[^>]*src\\s*=[^>]*Bar.jpg",
+         "\\(9\\) <a\\s[^>]*>\\s*<img\\s[^>]*alt\\s*=[^>]*Alt text[^>]*>\\s*</a",
+         "\\(10\\) <a\\s[^>]*class\\s*=\\s*.internal",
+         "\\(10\\) <a\\s[^>]*href\\s*=[^>]*Game[^s][^>]*>Games</a"
+       };
+
+       WebResponse wr = viewPage( "InternalLinks" );
+       String text = getArticle( wr );
+
+
+       int ret;
+       if ( 0 != ( ret = checkGoodPatterns( text, pats ) ) ) {
+               return 500 + ret;
+       }
+       return 0;
+}
+
+/*
+ * Check headings and horizontal rules
+ */
+private int part6() throws Exception {
+       String[] pats = {
+         "<h2>\\s*AAA 2\\s*</h2>", "<h3>\\s*BBB 3\\s*</h3>",
+         "<h2>\\s*CCC 2\\s*</h2>", "<h3>\\s*DDD 3\\s*</h3>",
+         "<h4>\\s*FFF 4\\s*</h4>", "<h3>\\s*GGG 3\\s*</h3>\\s*Extra",
+       /*"<h4>\\s*HHH 4\\s*</h4>\\s*Par", "<h4>\\s*III 4\\s*</h4>\\s*<p>\\s*Par",*/
+         "\\(1\\)[^(]*---\\s", "\\(2\\)[^(]*[^-]<hr>[^-]", "\\(3\\)[^(]*[^-]<hr>[^-]",
+         "\\(4\\)[^(]*<hr>\\s*XXX", "<h5>\\s*JJJ 5\\s*</h5>",
+         "<h6>\\s*KKK 6\\s*</h6>", "<h3>\\s*LLL 3\\s*</h3>",
+         "<h2>\\s*MMM 2\\s*</h2>"
+       };
+
+       WebResponse wr = viewPage( "Headings" );
+       String text = getArticle( wr );
+
+       int ret;
+       if ( 0 != ( ret = checkGoodPatterns( text, pats ) ) ) {
+               return 600 + ret;
+       }
+       return 0;
+}
+
+/*
+ * Check magic text replacements like ISBNs, RFCs
+ */
+private int part7() throws Exception {
+       String[] pats = {
+         "\\(1\\)\\s*<a\\s[^>]*Special:Booksources[^>]*1234567890[^>]*>\\s*ISBN 1234567890\\s*</a",
+       /*RFC not implemented*/
+       };
+
+       WebResponse wr = viewPage( "Magics" );
+       String text = getArticle( wr );
+
+       int ret;
+       if ( 0 != ( ret = checkGoodPatterns( text, pats ) ) ) {
+               return 700 + ret;
+       }
+       return 0;
+}
+
+
+public static void main( String[] params ) {
+       (new ParserTest()).runSingle( params );
+}
+
+}
diff --git a/testsuite/src/com/piclab/wikitest/SearchTest.java b/testsuite/src/com/piclab/wikitest/SearchTest.java
new file mode 100644 (file)
index 0000000..e4701fd
--- /dev/null
@@ -0,0 +1,204 @@
+
+/*
+ * Test basic searching functions.
+ */
+
+package com.piclab.wikitest;
+import com.meterware.httpunit.*;
+
+public class SearchTest extends WikiTest {
+
+public String testName() { return "Search"; }
+
+protected int initTest() throws Exception {
+       logout();
+       return 0;
+}
+
+protected int runTest() throws Exception {
+       int c = 0;
+
+       if ( 0 != ( c = part1() ) ) { return fail( c ); }
+       if ( 0 != ( c = part2() ) ) { return fail( c ); }
+       if ( 0 != ( c = part3() ) ) { return fail( c ); }
+       return 0;
+}
+
+private int part1() throws Exception {
+       String[] goodpats = {
+         "<h2>Article title matches</h2>\\s*<ol [^>]*>",
+         "<li><a [^>]+Cooking[^>]+>Cooking</a> \\(\\d+ bytes\\)\\s*<br>\\s*" +
+               "<small>\\d+:",
+         "<h2>Article text matches</h2>\\s*<ol [^>]*>\\s*<li><a " +
+               "[^>]*>[^<]+</a> \\(\\d+ bytes\\)\\s*<br>\\s*<small>\\d+:",
+         "<font [^>]*color\\s*=\\s*.red",
+         "<form [^>]*id\\s*=\\s*.?powersearch",
+         "<input [^>]*name\\s*=\\s*.?ns0[^>]*checked[^>]*>\\s*\\(",
+         "<input [^>]*type\\s*=\\s*.?checkbox",
+         "<input [^>]*name\\s*=\\s*.?redirs[^>]*checked[^>]*>",
+         "<input [^>]*name\\s*=\\s*.?searchx"
+       };
+       String[] badpats = {
+         "<input [^>]*name\\s*=\\s*.ns1[^>]*checked[^>]*>"
+       };
+
+       WebResponse wr = searchFor( "cooking" );
+       String text = getArticle( wr );
+
+       int ret = 0;
+       if ( 0 != ( ret = checkGoodPatterns( text, goodpats ) ) ) {
+               return 100 + ret;
+       }
+       if ( 0 != ( ret = checkBadPatterns( text, badpats ) ) ) {
+               return 110 + ret;
+       }
+
+       String[] goodpats2 = {
+         "<h2>No article title matches</h2>",
+         "<h2>No article text matches</h2>",
+         "<strong>\\s*Note",
+         "<form [^>]*id\\s*=\\s*.?powersearch",
+         "<input [^>]*name\\s*=\\s*.?ns0[^>]*checked[^>]*>\\s*\\("
+       };
+       String[] badpats2 = {
+         "<font [^>]*color\\s*=\\s*.red"
+       };
+       wr = searchFor( "oyaABiJxTWMISmfE" );
+       text = getArticle( wr );
+
+       if ( 0 != ( ret = checkGoodPatterns( text, goodpats2 ) ) ) {
+               return 120 + ret;
+       }
+       if ( 0 != ( ret = checkBadPatterns( text, badpats2 ) ) ) {
+               return 130 + ret;
+       }
+
+       wr = searchFor( "cooking OR sewing" );
+       text = getArticle( wr );
+
+       if ( 0 != ( ret = checkGoodPatterns( text, goodpats ) ) ) {
+               return 140 + ret;
+       }
+       if ( 0 != ( ret = checkBadPatterns( text, badpats ) ) ) {
+               return 150 + ret;
+       }
+
+       /*
+        * If boolean searches are disabled, the following will
+        * fail, so comment it out.
+        */
+       wr = searchFor( "cooking AND oyaABiJxTWMISmfE" );
+       text = getArticle( wr );
+
+       if ( 0 != ( ret = checkGoodPatterns( text, goodpats2 ) ) ) {
+               return 160 + ret;
+       }
+       if ( 0 != ( ret = checkBadPatterns( text, badpats2 ) ) ) {
+               return 170 + ret;
+       }
+
+       wr = searchFor( "cooking OR oyaABiJxTWMISmfE" );
+       text = getArticle( wr );
+
+       if ( 0 != ( ret = checkGoodPatterns( text, goodpats ) ) ) {
+               return 180 + ret;
+       }
+       if ( 0 != ( ret = checkBadPatterns( text, badpats ) ) ) {
+               return 190 + ret;
+       }
+       return 0;
+}
+
+/*
+ * Test "powersearch" in other namespaces.
+ */
+
+private int part2() throws Exception {
+       String[] goodpats = {
+         "<h2>No article title matches</h2>",
+         "<form [^>]*id\\s*=\\s*.powersearch",
+         "<input [^>]*name\\s*=\\s*.ns0[^>]*checked[^>]*>\\s*\\(",
+         "<input [^>]*value\\s*=\\s*.?Barney",
+         "<input [^>]*name\\s*=\\s*.searchx"
+       };
+       String[] badpats = {
+         "<input [^>]*name\\s*=\\s*.ns1[^>]*checked[^>]*>"
+       };
+
+       WebResponse wr = addText( "User:Barney",
+         "Some text added just to make sure page exists..." );
+       wr = searchFor( "Barney" );
+       String text = getArticle( wr );
+
+       int ret = 0;
+       if ( 0 != ( ret = checkGoodPatterns( text, goodpats ) ) ) {
+               return 200 + ret;
+       }
+       if ( 0 != ( ret = checkBadPatterns( text, badpats ) ) ) {
+               return 210 + ret;
+       }
+
+       WebForm psform = getFormByName( wr, "powersearch" );
+       WebRequest req = psform.getRequest( "searchx" );
+
+       req.setParameter( "ns2", "1" );
+       wr = getResponse( req );
+       text = getArticle( wr );
+
+       String[] goodpats2 = {
+         "<h2>Article title matches</h2>",
+         "<form [^>]*id\\s*=\\s*.?powersearch",
+         "<input [^>]*name\\s*=\\s*.?ns0[^>]*checked[^>]*>\\s*\\(",
+         "<input [^>]*name\\s*=\\s*.?ns2[^>]*checked[^>]*>",
+         "<input [^>]*value\\s*=\\s*.?Barney",
+         "<input [^>]*name\\s*=\\s*.?searchx"
+       };
+       String[] badpats2 = {
+         "<input [^>]*name\\s*=\\s*.ns1[^>]*checked[^>]*>"
+       };
+
+       if ( 0 != ( ret = checkGoodPatterns( text, goodpats2 ) ) ) {
+               return 220 + ret;
+       }
+       if ( 0 != ( ret = checkBadPatterns( text, badpats2 ) ) ) {
+               return 230 + ret;
+       }
+       return 0;
+}
+
+/*
+ * Test "Go" search.
+ */
+
+private int part3() throws Exception {
+       String[] pagepat = { "<h1\\s[^>]*>\\s*Geography\\s*</h1>" };
+       String[] srpat = { "<h1\\s[^>]*>\\s*Search results\\s*</h1>" };
+
+       WebResponse wr = searchFor( "Geography", "go=Go" );
+       String text = getArticle( wr );
+
+       int ret = 0;
+       if ( 0 != ( ret = checkGoodPatterns( text, pagepat ) ) ) {
+               return 300 + ret;
+       }
+       if ( 0 != ( ret = checkBadPatterns( text, srpat ) ) ) {
+               return 310 + ret;
+       }
+
+       wr = searchFor( "oyaABiJxTWMISmfE", "go=Go" );
+       text = getArticle( wr );
+
+       if ( 0 != ( ret = checkGoodPatterns( text, srpat ) ) ) {
+               return 320 + ret;
+       }
+       if ( 0 != ( ret = checkBadPatterns( text, pagepat ) ) ) {
+               return 330 + ret;
+       }
+       return 0;
+}
+
+public static void main( String[] params ) {
+       (new SearchTest()).runSingle( params );
+}
+
+}
diff --git a/testsuite/src/com/piclab/wikitest/SpecialTest.java b/testsuite/src/com/piclab/wikitest/SpecialTest.java
new file mode 100644 (file)
index 0000000..71ba54e
--- /dev/null
@@ -0,0 +1,358 @@
+/*
+ * Test functioning of various special pages. Does not bother with
+ * some pages like Recentchanges and Userlogin that are adequately
+ * exercised by other test, or with developer-only stuff.
+ */
+
+package com.piclab.wikitest;
+import com.meterware.httpunit.*;
+import java.util.regex.*;
+
+public class SpecialTest extends WikiTest {
+
+public String testName() { return "Special"; }
+
+protected int initTest() throws Exception {
+       WebResponse wr = deletePage( "Newly created test page" );
+       wr = deletePage( "Nonsense" );
+       wr = deletePage( "Religion" );
+
+    String text = WikiSuite.loadText( "data/Religion.txt" );
+       wr = replacePage( "Religion", text );
+       return 0;
+}
+
+protected int runTest() throws Exception {
+       int c = 0;
+
+       if ( 0 != ( c = part1() ) ) { return fail( c ); }
+       if ( 0 != ( c = part2() ) ) { return fail( c ); }
+       if ( 0 != ( c = part3() ) ) { return fail( c ); }
+       if ( 0 != ( c = part4() ) ) { return fail( c ); }
+       if ( 0 != ( c = part5() ) ) { return fail( c ); }
+       if ( 0 != ( c = part6() ) ) { return fail( c ); }
+       if ( 0 != ( c = part7() ) ) { return fail( c ); }
+       if ( 0 != ( c = part8() ) ) { return fail( c ); }
+       if ( 0 != ( c = part9() ) ) { return fail( c ); }
+       if ( 0 != ( c = part10() ) ) { return fail( c ); }
+       if ( 0 != ( c = part11() ) ) { return fail( c ); }
+       if ( 0 != ( c = part12() ) ) { return fail( c ); }
+       if ( 0 != ( c = part13() ) ) { return fail( c ); }
+       if ( 0 != ( c = part14() ) ) { return fail( c ); }
+       if ( 0 != ( c = part15() ) ) { return fail( c ); }
+       if ( 0 != ( c = part16() ) ) { return fail( c ); }
+       if ( 0 != ( c = part17() ) ) { return fail( c ); }
+       if ( 0 != ( c = part18() ) ) { return fail( c ); }
+       if ( 0 != ( c = part19() ) ) { return fail( c ); }
+       if ( 0 != ( c = part20() ) ) { return fail( c ); }
+       return 0;
+}
+
+private String[] listHeadings = {
+  "Showing below.*results starting with",
+  "View \\(previous[^(]*\\(<a\\s[^>]*>next",
+  "\\(<a [^>]*>20</a> | <a [^>]*>50</a> | <a [^>]*>100</a>"
+};
+
+private int part1() throws Exception {
+       /*
+        * This one is in the process of changing.
+        */
+       WebResponse wr = viewPage( "Special:Allpages" );
+       return 0;
+}
+
+private int part2() throws Exception {
+       WebResponse wr = viewPage( "Special:Booksources", "isbn=0123456789" );
+
+       WebLink l = wr.getFirstMatchingLink( WebLink.MATCH_CONTAINED_TEXT, "AddALL" );
+       if ( l == null ) return 201;
+       l = wr.getFirstMatchingLink( WebLink.MATCH_CONTAINED_TEXT, "PriceSCAN" );
+       if ( l == null ) return 202;
+       l = wr.getFirstMatchingLink( WebLink.MATCH_CONTAINED_TEXT, "Barnes" );
+       if ( l == null ) return 203;
+       l = wr.getFirstMatchingLink( WebLink.MATCH_CONTAINED_TEXT, "Amazon" );
+       if ( l == null ) return 204;
+
+       return 0;
+}
+
+private int part3() throws Exception {
+       WebResponse wr = loginAs( "Fred", "Fred" );
+       wr = editPage( "Painting" );
+
+       WebForm editform = getFormByName( wr, "editform" );
+       WebRequest req = editform.getRequest( "wpSave" );
+
+       String old = req.getParameter( "wpTextbox1" );
+       req.setParameter( "wpTextbox1", old + "\n" + "Fred's edit." );
+       req.setParameter( "wpSummary", "Wikitest addition" );
+       wr = getResponse( req );
+
+       wr = viewPage( "Special:Contributions", "target=Fred" );
+       String text = getArticle( wr );
+
+       String[] pats = {
+         "<p\\s[^>]*subtitle[^>]*>\\s*For\\s*<a\\s[^>]*User:Fred[^>]*>\\s*Fred",
+         "<ul>\\s*<li>[^<]*<a\\s[^>]*>Painting</a>\\s*<em>\\s*\\(Wikitest"
+       };
+
+       int ret = 0;
+       if ( 0 != ( ret = checkGoodPatterns( text, pats ) ) ) {
+               return 300 + ret;
+       }
+       if ( 0 != ( ret = checkGoodPatterns( text, listHeadings ) ) ) {
+               return 310 + ret;
+       }
+       wr = logout();
+       return 0;
+}
+
+private int part4() throws Exception {
+       WebResponse wr = loginAs( "Fred", "Fred" );
+       WebRequest req = openPrefs();
+       req.setParameter( "wpEmail", "fred@nowhere.invalid" );
+       wr = getResponse( req );
+
+       wr = loginAs( "Barney", "Barney" );
+       req = openPrefs();
+       req.setParameter( "wpEmail", "barney@nowhere.invalid" );
+       wr = getResponse( req );
+
+       wr = viewPage( "Special:Emailuser", "target=Fred" );
+       String text = getArticle( wr );
+       WebForm emailform = getFormByName( wr, "emailuser" );
+
+       if ( ! emailform.hasParameterNamed( "wpSubject" ) ) {
+               return 401;
+       }
+       /*
+        * Actual addresses should not appear on form anywhere
+        */
+       String[] badpats = {
+               "fred@nowhere.invalid", "barney@nowhere.invalid"
+       };
+       int ret = 0;
+       if ( 0 != ( ret = checkBadPatterns( text, badpats ) ) ) {
+               return 401 + ret;
+       }
+       wr = logout();
+       return 0;
+}
+
+private int part5() throws Exception {
+       WebResponse wr = viewPage( "Special:Listusers" );
+       String text = getArticle( wr );
+
+       String[] pats = {
+         "<ol [^>]*start[^>]*>\\s*<li>\\s*<a [^>]*User:([^ ]+)[^>]*>\\s*\\1"
+       };
+
+       int ret = 0;
+       if ( 0 != ( ret = checkGoodPatterns( text, pats ) ) ) {
+               return 500 + ret;
+       }
+       if ( 0 != ( ret = checkGoodPatterns( text, listHeadings ) ) ) {
+               return 510 + ret;
+       }
+       return 0;
+}
+
+private int part6() throws Exception {
+       WebResponse wr = viewPage( "Special:Lonelypages" );
+       String text = getArticle( wr );
+
+       String[] pats = {
+         "<ol [^>]*start[^>]*>\\s*<li>\\s*<a [^>]*\\?title=([^ ]+)[^>]*>\\s*\\1"
+       };
+
+       int ret = 0;
+       if ( 0 != ( ret = checkGoodPatterns( text, pats ) ) ) {
+               return 600 + ret;
+       }
+       if ( 0 != ( ret = checkGoodPatterns( text, listHeadings ) ) ) {
+               return 610 + ret;
+       }
+       return 0;
+}
+
+private int part7() throws Exception {
+       WebResponse wr = viewPage( "Special:Longpages" );
+       String text = getArticle( wr );
+
+       String[] pats = {
+         "<ol [^>]*start[^>]*>\\s*<li>\\s*<a [^>]*\\?title=([^\"])[^\"]*\"[^>]*>" +
+           "\\s*\\1[^<]*</a>\\s*\\(\\d+\\s+bytes\\)"
+       };
+
+       int ret = 0;
+       if ( 0 != ( ret = checkGoodPatterns( text, pats ) ) ) {
+               return 600 + ret;
+       }
+       if ( 0 != ( ret = checkGoodPatterns( text, listHeadings ) ) ) {
+               return 610 + ret;
+       }
+       return 0;
+}
+
+private int part8() throws Exception {
+       WebResponse wr = loginAs( "Fred", "Fred" );
+       wr = viewPage( "Religion" );
+       String text = getArticle( wr );
+
+       if ( text.indexOf( "<strong>religion</strong>" ) < 0 ) {
+               return 801;
+       }
+       wr = viewPage( "Special:Movepage", "target=Religion" );
+       text = getArticle( wr );
+       if ( text.indexOf( "WARNING" ) < 0 ) { return 802; }
+
+       WebForm moveform = getFormByName( wr, "movepage" );
+       WebRequest req = moveform.getRequest( "wpMove" );
+       req.setParameter( "wpNewTitle", "Nonsense" );
+       wr = getResponse( req );
+
+       text = getArticle( wr );
+       if ( text.indexOf( ">Religion<" ) < 0 ||
+         text.indexOf( "moved to" ) < 0 ||
+         text.indexOf( ">Nonsense<" ) < 0 ) {
+               return 803;
+       }
+       wr = viewPage( "Nonsense" );
+       text = getArticle( wr );
+       if ( text.indexOf( "<strong>religion</strong>" ) < 0 ) {
+               return 804;
+       }
+       wr = viewPage( "Religion" );
+       text = getArticle( wr );
+       if ( text.indexOf( "<strong>religion</strong>" ) < 0 ||
+         text.indexOf( "(Redirected from" ) < 0 ) {
+               return 805;
+       }
+       wr = viewPage( "Religion", "action=edit&redirect=no" );
+       text = getArticle( wr );
+       if ( text.indexOf( "#REDIRECT [[Nonsense]]" ) < 0 ) {
+               return 806;
+       }
+       wr = logout();
+       return 0;
+}
+
+private int part9() throws Exception {
+       /*
+        * Not yet implemented
+        *
+       WebResponse wr = viewPage( "Special:Neglectedpages" );
+        */
+
+       return 0;
+}
+
+private int part10() throws Exception {
+       WebResponse wr = loginAs( "Barney", "Barney" );
+       wr = addText( "Newly created test page", "New stuff..." );
+
+       wr = viewPage( "Special:Newpages" );
+       String text = getArticle( wr );
+
+       String[] pats = {
+         "<ol [^>]*start[^>]*>\\s*<li>\\s*\\d\\d:\\d\\d[^<]*<a [^>]*>Newly" +
+           "[^<]*</a> \\. \\. <a [^>]*>Barney</a>"
+       };
+
+       int ret = 0;
+       if ( 0 != ( ret = checkGoodPatterns( text, pats ) ) ) {
+               return 1000 + ret;
+       }
+       if ( 0 != ( ret = checkGoodPatterns( text, listHeadings ) ) ) {
+               return 1010 + ret;
+       }
+       return 0;
+}
+
+private int part11() throws Exception {
+       WebResponse wr = viewPage( "Special:Popularpages" );
+       String text = getArticle( wr );
+
+       String[] pats = {
+         "<ol [^>]*start[^>]*>\\s*<li>\\s*<a [^>]*\\?title=([^\"])[^\"]*\"[^>]*>" +
+           "\\s*\\1[^<]*</a>\\s*\\(\\d+\\s+views\\)"
+       };
+
+       int ret = 0;
+       if ( 0 != ( ret = checkGoodPatterns( text, pats ) ) ) {
+               return 1100 + ret;
+       }
+       if ( 0 != ( ret = checkGoodPatterns( text, listHeadings ) ) ) {
+               return 1110 + ret;
+       }
+       return 0;
+}
+
+private int part12() throws Exception {
+       WebResponse wr = viewPage( "Special:Randompage" );
+       return 0;
+}
+
+private int part13() throws Exception {
+       /* WebResponse wr = viewPage( "Special:Recentchangeslinked" ); */
+       return 0;
+}
+
+private int part14() throws Exception {
+       WebResponse wr = viewPage( "Special:Shortpages" );
+       String text = getArticle( wr );
+
+       String[] pats = {
+         "<ol [^>]*start[^>]*>\\s*<li>\\s*<a [^>]*\\?title=([^\"])[^\"]*\"[^>]*>" +
+           "\\s*\\1[^<]*</a>\\s*\\(\\d+\\s+bytes\\)"
+       };
+
+       int ret = 0;
+       if ( 0 != ( ret = checkGoodPatterns( text, pats ) ) ) {
+               return 1400 + ret;
+       }
+       if ( 0 != ( ret = checkGoodPatterns( text, listHeadings ) ) ) {
+               return 1410 + ret;
+       }
+       return 0;
+}
+
+private int part15() throws Exception {
+       viewPage( "Special:Specialpages" );
+       return 0;
+}
+
+private int part16() throws Exception {
+       WebResponse wr = viewPage( "Special:Statistics" );
+       String text = getArticle( wr );
+       return 0;
+}
+
+private int part17() throws Exception {
+       WebResponse wr = viewPage( "Special:Unusedimages" );
+       String text = getArticle( wr );
+       return 0;
+}
+
+private int part18() throws Exception {
+       WebResponse wr = viewPage( "Special:Wantedpages" );
+       String text = getArticle( wr );
+       return 0;
+}
+
+private int part19() throws Exception {
+       /* WebResponse wr = viewPage( "Special:Watchlist" ); */
+       return 0;
+}
+
+private int part20() throws Exception {
+       /* WebResponse wr = viewPage( "Special:Whatlinkshere" ); */
+       return 0;
+}
+
+public static void main( String[] params ) {
+       (new SpecialTest()).runSingle( params );
+}
+
+}
diff --git a/testsuite/src/com/piclab/wikitest/Test.template b/testsuite/src/com/piclab/wikitest/Test.template
new file mode 100644 (file)
index 0000000..1b9c1f2
--- /dev/null
@@ -0,0 +1,38 @@
+
+/*
+ * Template for adding new tests.
+ */
+
+package com.piclab.wikitest;
+import com.meterware.httpunit.*;
+
+public class FooTest extends WikiTest {
+
+public String testName() { return "Foo"; }
+
+protected int initTest() throws Exception {
+       m_suite.logout();
+       return 0;
+}
+
+protected int runTest() throws Exception {
+       int c = 0;
+
+       if ( 0 != ( c = part1() ) ) { return fail( c ); }
+       if ( 0 != ( c = part2() ) ) { return fail( c ); }
+       return 0;
+}
+
+private int part1() throws Exception {
+       return 0;
+}
+
+private int part2() throws Exception {
+       return 0;
+}
+
+public static void main( String[] params ) {
+       (new FooTest()).runSingle( params );
+}
+
+}
diff --git a/testsuite/src/com/piclab/wikitest/UploadTest.java b/testsuite/src/com/piclab/wikitest/UploadTest.java
new file mode 100644 (file)
index 0000000..bdf0dc5
--- /dev/null
@@ -0,0 +1,38 @@
+
+/*
+ * Test image uploading and linking.
+ */
+
+package com.piclab.wikitest;
+import com.meterware.httpunit.*;
+
+public class UploadTest extends WikiTest {
+
+public String testName() { return "Uploads"; }
+
+protected int initTest() throws Exception {
+       logout();
+       return 0;
+}
+
+protected int runTest() throws Exception {
+       int c = 0;
+
+       if ( 0 != ( c = part1() ) ) { return fail( c ); }
+       if ( 0 != ( c = part2() ) ) { return fail( c ); }
+       return 0;
+}
+
+private int part1() throws Exception {
+       return 0;
+}
+
+private int part2() throws Exception {
+       return 0;
+}
+
+public static void main( String[] params ) {
+       (new UploadTest()).runSingle( params );
+}
+
+}
diff --git a/testsuite/src/com/piclab/wikitest/WikiFetchThread.java b/testsuite/src/com/piclab/wikitest/WikiFetchThread.java
new file mode 100644 (file)
index 0000000..000d31c
--- /dev/null
@@ -0,0 +1,74 @@
+
+/*
+ * WikiFetchThread is a background thread that fetches
+ * pages from the preload list until the suite is done.
+ */
+
+package com.piclab.wikitest;
+import com.meterware.httpunit.*;
+
+public class WikiFetchThread extends Thread {
+
+private WebConversation m_conv;
+private int m_totalfetches;
+private long m_totaltime;
+private volatile boolean m_running;
+
+
+public WikiFetchThread() {
+       m_conv = new WebConversation();
+       m_totalfetches = 0;
+       m_totaltime = 0;
+}
+
+public int getFetches() { return m_totalfetches; }
+public long getTime() { return m_totaltime; }
+public void requestStop() { m_running = false; }
+
+
+public void run() {
+       int index = 0;
+       String url;
+       double r;
+       long start, end;
+
+       m_running = true;
+       while ( m_running ) {
+               r = Math.random();
+               if ( r < 0.1 ) {
+                       url = WikiTest.viewUrl( "" ); /* Main page */
+               } else if ( r < 0.15 ) {
+                       url = WikiTest.viewUrl( "Special:Recentchanges" );
+               } else {
+                       if ( ++index >= WikiSuite.preloadedPages.length ) { index = 0; }
+                       url = WikiTest.viewUrl( WikiSuite.preloadedPages[index] );
+               }
+
+               start = System.currentTimeMillis();
+               try {
+                       WebResponse wr = m_conv.getResponse( url );
+               } catch (Exception e) {
+                       WikiSuite.warning( "Error (" + e + ") fetching \"" + url + "\"" );
+               }
+               end = System.currentTimeMillis();
+
+               WikiSuite.finer( "Fetched \"" + url + "\"" );
+               ++m_totalfetches;
+               m_totaltime += ( end - start );
+
+               try {
+                       Thread.sleep( 1000 );
+               } catch( InterruptedException e ) {
+                       break;
+               }
+       }
+       /*
+        * The main suite tells us to stop, but we wait until the
+        * current fetch is done. So we have the suite wait for us
+        * to actually stop before continuing with its final report,
+        * and we wake it up here.
+        */
+       synchronized (this) { notify(); }
+}
+
+}
diff --git a/testsuite/src/com/piclab/wikitest/WikiLogFormatter.java b/testsuite/src/com/piclab/wikitest/WikiLogFormatter.java
new file mode 100644 (file)
index 0000000..09d17e6
--- /dev/null
@@ -0,0 +1,38 @@
+
+package com.piclab.wikitest;
+
+import java.util.logging.*;
+
+class WikiLogFormatter extends Formatter {
+
+java.text.DateFormat m_df;
+
+public WikiLogFormatter() {
+       m_df = new java.text.SimpleDateFormat( "HH:mm:ss " );
+}
+
+public String format( LogRecord rec ) {
+       StringBuffer sb = new StringBuffer( 200 );
+
+       sb.append( m_df.format( new java.util.Date() ) );
+
+       Level l = rec.getLevel();
+       if ( l == Level.SEVERE ) {
+               sb.append( "ERROR: " );
+       } else if ( l == Level.WARNING ) {
+               sb.append( " WARN: " );
+       } else if ( l == Level.CONFIG ) {
+               sb.append( " CONF: " );
+       } else if ( l == Level.INFO || l == Level.FINE ||
+         l == Level.FINER || l == Level.FINEST ) {
+               sb.append( " INFO: " );
+       } else {
+               sb.append( "       " );
+       }
+       sb.append( rec.getMessage() ).append( "\n" );
+
+       return sb.toString();
+}
+
+}
+
diff --git a/testsuite/src/com/piclab/wikitest/WikiSearchThread.java b/testsuite/src/com/piclab/wikitest/WikiSearchThread.java
new file mode 100644 (file)
index 0000000..8810721
--- /dev/null
@@ -0,0 +1,175 @@
+
+/*
+ * WikiSearchThread is a background thread that does searches.
+ * See WikiFetchThread for more details on design.
+ */
+
+package com.piclab.wikitest;
+import com.meterware.httpunit.*;
+
+public class WikiSearchThread extends Thread {
+
+private WebConversation m_conv;
+private int m_totalsearches;
+private long m_totaltime;
+private volatile boolean m_running;
+
+public WikiSearchThread() {
+       m_conv = new WebConversation();
+       m_totalsearches = 0;
+       m_totaltime = 0;
+}
+
+public int getSearches() { return m_totalsearches; }
+public long getTime() { return m_totaltime; }
+public void requestStop() { m_running = false; }
+
+/*
+ * First, a list of miscellaneous words that do appear in the
+ * titles and text of the testing articles.
+ */
+
+public static String[] searchterms = {
+       "agriculture", "husbandry", "corn", "vegetable", "farming", "nitrogen",
+       "anthropology", "human", "culture", "language", "networks", "society",
+       "archaeology", "archeology", "history", "marxism", "ownership", "land",
+       "architecture", "building", "landscape", "furniture", "carpentry", "roman",
+       "astronomy", "astrophysics", "astrology", "star", "cosmology", "galaxy",
+       "biology", "life", "monet", "evolution", "species", "animal", "plant",
+       "business", "industry", "capitalism", "commerce", "company", "corporation",
+       "chemistry", "atom", "organic", "element", "alchemy", "polymer",
+       "classics", "greece", "rome", "latin", "literature", "mythology", "art",
+       "communication", "media", "television", "radio", "film", "mail",
+       "computer", "engineering", "linguistics", "algorithm", "graphics", "logic",
+       "cooking", "food", "heat", "cuisine", "ethnic", "nutrition", "flavor",
+       "critical", "theory", "frankfurt", "postmodernism", "weber",
+       "dance", "rhythm", "music", "recreation", "performance", "ballet",
+       "earth", "science", "geology", "weather", "fossil", "ocean", "environment",
+       "economic", "scarcity", "communism", "socialism", "utility", "money",
+       "education", "teaching", "knowledge", "reading", "testing", "school",
+       "technology", "civil", "mechanical", "nuclear", "process", "control",
+       "entertainment", "animation", "sport", "humor", "illusion", "theater",
+       "family", "consumer", "parenting", "sewing", "homemaker", "decoration",
+       "movie", "cinema", "director", "actor", "genre", "studio", "festival",
+       "game", "card", "board", "competition", "probability", "drinking", "dice",
+       "geography", "map", "projection", "continent", "island", "river", "sea",
+       "handicraft", "bead", "marquetry", "paper", "wood", "garden", "metal",
+       "history", "etymology", "orthodox", "controversy", "pasteur", "method",
+       "hobby", "pastime", "professional", "amateur", "collecting", "genealogy",
+       "language", "othography", "writing", "alphabet", "phonetic", "speech",
+       "law", "taboo", "more", "jurisdiction", "legislature", "judge", "police",
+       "library", "information", "book", "journal", "pediodical", "database",
+       "philology", "syntax", "semantic", "lexicology", "comparative", "cipher",
+       "letter", "rhetoric", "bible", "poem", "novel", "epic", "essay", "drama",
+       "math", "mathematics","statistics", "number", "algebra", "calculus",
+       "music", "melody", "instrument", "ensemble", "orchestra", "harmony",
+       "opera", "costume", "dialogue", "acting", "voice", "libretto", "stage",
+       "painting", "glaze", "acrylic", "mural", "portrait", "canvas", "fresco",
+       "philosophy", "concept", "dialectic", "beauty", "ethic", "aristotle",
+       "physics", "matter", "space", "energy", "quantum", "particle", "momentum",
+       "poker", "stud", "wager", "gambling", "joker", "flush", "chip", "deal",
+       "political", "politics", "government", "violence", "democracy", "fascism",
+       "psychology", "freud", "ethology", "medicine", "therapy", "drug", "health",
+       "public", "policy", "activism", "defense", "tax", "administration",
+       "recreation", "weekend", "holiday", "vacation", "leisure", "sex",
+       "religion", "christianity", "judaism", "islam", "deity", "faith", "priest",
+       "sculpture", "clay", "marble", "mobile", "kinetic", "statue", "bust",
+       "sociology", "kinship", "criminology", "race", "revolution", "gender",
+       "sport", "equipment", "injury", "spectator", "football", "baseball",
+       "invention", "recording", "cryptography", "metallurgy", "hydraulic",
+       "theatre", "mime", "tennessee", "lighting", "scenery", "improvisation",
+       "tourism", "travel", "sightseeing", "hotel", "camping", "cruise",
+       "transport", "vehicle", "airline", "train", "ferry", "subway", "car",
+       "visual", "design", "photography", "fashion", "tattoo", "textile"
+};
+
+/*
+ * Then, a list of miscellaneous words that may or may not appear
+ * in the test articles.
+ */
+
+public static String[] randomterms = {
+       "abatement", "acacia", "aerate", "allergy", "anvil", "ashtray", "auger",
+       "badger", "bakery", "benign", "biceps", "bookie", "brazen", "bulldog",
+       "caliber", "castigate", "centipede", "chemise", "clamor", "cupboard",
+       "dawn", "debris", "derrick", "dig", "divorce", "doublet", "drummer",
+       "ebony", "eclipse", "elitist", "emulator", "escrow", "euphoria", "evade",
+       "famine", "feedback", "fiefdom", "flax", "fox", "freckle", "funnel",
+       "gallop", "ghetto", "gingham", "gnat", "gossip", "grudge", "guitar",
+       "halogen", "hedgehog", "heuristic", "hillbilly", "hologram", "hyacinth",
+       "idealism", "illustrator", "impeach", "income", "injunction", "irony",
+       "janitor", "jellyfish", "jitterbug", "journalism", "juggling", "jury",
+       "kamikaze", "kerosene", "kindergarten", "kitten", "klaxon", "knuckle", 
+       "lager", "leech", "lentil", "libido", "locust", "lox", "lullabye", "lyre",
+       "magenta", "marigold", "mediator", "mileage", "monarch", "municipal",
+       "navigation", "neurosis", "nicotine", "nostalgia", "nucleus", "nymph",
+       "oasis", "obscene", "oilcloth", "oratory", "osmosis", "ovary", "owl",
+       "parsley", "perplex", "phony", "pilgrim", "pliers", "pompadour", "prose",
+       "quahog", "quaver", "quench", "queue", "quilt", "quince", "quotient",
+       "railroad", "ravine", "recipe", "rescue", "rig", "roast", "ruthless",
+       "sarcasm", "sclerosis", "sellout", "shanty", "sigma", "skyhook", "synod",
+       "tantrum", "tenacious", "thorn", "tithe", "tonsil", "trauma", "tyranny",
+       "ulcer", "umpire", "unicorn", "unravel", "urinate", "upload", "utensil",
+       "valence", "veranda", "viewpoint", "volunteer", "vow", "vulnerable",
+       "wanton", "welcome", "wharf", "whiz", "wilderness", "woofer", "wretch",
+       "xanthate", "yeast", "yeoman", "yonder", "zealous", "zen", "zonal"
+};
+
+public void run() {
+       int tindex = 0, rindex = 0;
+       double r;
+       long start, end;
+       WebResponse wr;
+
+       String prefix = WikiSuite.getServer() + WikiSuite.getScript() + "?search=";
+       String term = null;
+
+       m_running = true;
+       while ( m_running ) {
+               r = Math.random();
+               if ( r < 0.1 ) {
+                       term = searchterms[tindex] + " AND " + randomterms[rindex];
+               } else if ( r < 0.3 ) {
+                       term = searchterms[tindex];
+                       if ( ++tindex >= searchterms.length ) { tindex = 0; }
+                       term += " AND " + searchterms[tindex];
+               } else if ( r < 0.4 ) {
+                       term = searchterms[tindex] + " OR " + randomterms[rindex];
+               } else if ( r < 0.5 ) {
+                       term = randomterms[rindex];
+                       if ( ++rindex >= randomterms.length ) { rindex = 0; }
+                       term += " OR " + randomterms[rindex];
+               } else if ( r < 0.7 ) {
+                       term = randomterms[rindex];
+               } else {
+                       term = searchterms[tindex];
+               }
+
+               start = System.currentTimeMillis();
+               try {
+                       term = java.net.URLEncoder.encode( term, "UTF-8" );
+                       wr = m_conv.getResponse( prefix + term );
+               } catch ( java.io.UnsupportedEncodingException e ) {
+                       break;
+               } catch (Exception e) {
+                       WikiSuite.warning( "Error (" + e + ") searching for \"" + term + "\"" );
+               }
+               end = System.currentTimeMillis();
+
+               WikiSuite.finer( "Searched for \"" + term + "\"" );
+               ++m_totalsearches;
+               m_totaltime += ( end - start );
+
+               if ( ++tindex >= searchterms.length ) { tindex = 0; }
+               if ( ++rindex >= randomterms.length ) { rindex = 0; }
+
+               try {
+                       Thread.sleep( 3000 );
+               } catch( InterruptedException e ) {
+                       break;
+               }
+       }
+       synchronized (this) { notify(); }
+}
+
+}
diff --git a/testsuite/src/com/piclab/wikitest/WikiSuite.java b/testsuite/src/com/piclab/wikitest/WikiSuite.java
new file mode 100644 (file)
index 0000000..0179c8b
--- /dev/null
@@ -0,0 +1,343 @@
+/*
+ * WikiSuite is the driver class for the wiki test suite.
+ * It represents the location of the wiki, and provides
+ * some common static routines for access.  When idividual
+ * tests are instantiated, they are passed this object,
+ * and they use its utility functions and result reporting.
+ */
+
+package com.piclab.wikitest;
+
+import com.meterware.httpunit.*;
+import java.util.prefs.*;
+import java.util.logging.*;
+import java.io.*;
+
+public class WikiSuite {
+
+private static Preferences ms_uprefs =
+  Preferences.userNodeForPackage( WikiSuite.class );
+
+/* Settings loaded from preferences:
+ */
+private static String ms_server = null;
+private static String ms_script = null;
+private static String ms_articlepath = null;
+private static String ms_uploadpath = null;
+private static String ms_mainpage = null;
+private static String ms_sysoppass = null;
+
+/* Primary conversation for test suite; individual
+ * tests may also create their own if needed.
+ */
+private WebConversation m_conv;
+
+private static Logger ms_logger = Logger.getLogger( "com.piclab.wikitest" );
+
+static {
+       /* Set logging level and properties:
+       */
+       ms_logger.setUseParentHandlers( false );
+       Handler h = new StreamHandler( System.out, new WikiLogFormatter() );
+       h.setLevel( Level.INFO );
+
+       ms_logger.addHandler( h );
+       ms_logger.setLevel( Level.INFO );
+       ms_logger.setFilter( null );
+}
+
+public static String preloadedPages[] = { "Agriculture", "Anthropology",
+       "Archaeology", "Architecture", "Astronomy_and_astrophysics",
+       "Biology", "Business_and_industry", "Card_game", "Chemistry",
+       "Classics", "Communication", "Computer_Science", "Cooking",
+       "Critical_theory", "Dance", "Earth_science", "Economics",
+       "Education", "Engineering", "Entertainment",
+       "Family_and_consumer_science", "Film", "Game", "Geography",
+       "Handicraft", "Health_science", "History_of_science_and_technology",
+       "History", "Hobby", "Language", "Law",
+       "Library_and_information_science", "Linguistics", "Literature",
+       "Main_Page", "Mathematics", "Music", "Opera", "Painting",
+       "Philosophy", "Physics", "Poker", "Political_science", "Psychology",
+       "Public_affairs", "Recreation", "Religion", "Sculpture",
+       "Sociology", "Sport", "Statistics", "Technology", "Theater",
+       "Tourism", "Transport", "Visual_arts_and_design",
+       "World_Series_of_Poker",
+       
+       "Bracketvars", "Quotes", "Headings", "Blocklevels",
+       "ExternalLinks", "InternalLinks", "Magics", "Equations" };
+
+/* Suite constructor: load the prefs to determine which
+ * wiki to test.
+ */
+
+public WikiSuite() {
+       try {
+               ms_uprefs.importPreferences(new java.io.FileInputStream(
+                 "wikitest.prefs" ));
+       } catch (java.io.IOException e) {
+               /* File probably doesn't exist: no problem, use defaults */
+       } catch (InvalidPreferencesFormatException e) {
+               System.err.println( "Bad preferences file format: " + e );
+       }
+
+       ms_server = ms_uprefs.get( "server", "http://localhost" );
+       ms_script = ms_uprefs.get( "script", "/wiki.phtml" );
+       ms_articlepath = ms_uprefs.get( "articlepath", "" );
+       ms_uploadpath = ms_uprefs.get( "uploadpath", "http://localhost/upload/" );
+       ms_mainpage = ms_uprefs.get( "mainpage", "Main Page" );
+       ms_sysoppass = ms_uprefs.get( "sysoppass", "adminpass" );
+
+       m_conv = new WebConversation();
+}
+
+public WebConversation getConv() { return m_conv; }
+public static String getServer() { return ms_server; }
+public static String getScript() { return ms_script; }
+public static String getArticlePath() { return ms_articlepath; }
+public static String getUploadPath() { return ms_uploadpath; }
+public static String getMainPage() { return ms_mainpage; }
+public static String getSysopPass() { return ms_sysoppass; }
+
+/*
+ * Logging/reporting routines:
+ */
+
+public static void fatal( String msg ) {
+       ms_logger.severe( msg );
+       ms_logger.getHandlers()[0].flush();
+}
+
+public static void error( String msg ) {
+       ms_logger.severe( msg );
+       ms_logger.getHandlers()[0].flush();
+}
+
+public static void warning( String msg ) {
+       ms_logger.warning( msg );
+       ms_logger.getHandlers()[0].flush();
+}
+
+public static void info( String msg ) {
+       ms_logger.info( msg );
+       ms_logger.getHandlers()[0].flush();
+}
+
+public static void fine( String msg ) {
+       ms_logger.fine( msg );
+       ms_logger.getHandlers()[0].flush();
+}
+
+public static void finer( String msg ) {
+       ms_logger.finer( msg );
+       ms_logger.getHandlers()[0].flush();
+}
+
+public static Level setLoggingLevel( Level newl ) {
+       Level oldl = ms_logger.getLevel();
+
+       ms_logger.getHandlers()[0].setLevel( newl );
+       ms_logger.setLevel( newl );
+       return oldl;
+}
+
+public static String threeDecimals( double val ) {
+       String result = "ERROR";
+       java.text.DecimalFormat df =
+         (java.text.DecimalFormat)(java.text.NumberFormat.getInstance());
+
+       df.applyPattern( "#######0.000" );
+       result = df.format( val );
+       return result;
+}
+
+/*
+ * Utility functions for loading and saving strings from/to a file.
+ */
+
+public static void saveText( String text, String filename ) {
+       try {
+               PrintWriter pw = new PrintWriter( new FileOutputStream( filename ) );
+               pw.write( text );
+               pw.close();
+       } catch( IOException e ) {
+               error( "Couldn't write to \"" + filename + "\"" );
+               return;
+       }
+       fine( "Saved \"" + filename + "\"" );
+}
+
+public static String loadText( String fname )
+{
+       FileInputStream fis = null;
+       BufferedInputStream bis;
+
+       try {
+               fis = new FileInputStream( fname );
+       } catch (FileNotFoundException e) {
+               error( "File \"" + fname + "\" not found." );
+               return null;
+       }
+       bis = new BufferedInputStream( fis );
+
+       int r;
+       StringBuffer result = new StringBuffer( 2048 );
+       byte[] buf = new byte[1024];
+
+       while (true) {
+               r = -1;
+               try {
+                       r = bis.read( buf );            
+               } catch (IOException e) {
+                       error( "I/O Error reading \"" + fname + "\"." );
+                       break;
+               }
+               if ( r <= 0 ) break;
+
+               try {
+                       result.append( new String( buf, 0, r, "ISO8859_1" ) );
+               } catch ( java.io.UnsupportedEncodingException e ) {
+                       result.append( new String( buf, 0, r ) );
+               }
+       }
+       try {
+               bis.close();
+               fis.close();
+       } catch (IOException e) {
+               warning( "I/O Error closing file \"" + fname + "\"." );
+       }
+       fine( "Loaded \"" + fname + "\"" );
+       return result.toString();
+}
+
+/*
+ * Start background threads that run while all the other
+ * tests are going on.
+ */
+
+private WikiFetchThread m_wft;
+private WikiSearchThread m_wst;
+
+private void startBackgroundThreads() {
+       info( "Starting background threads." );
+
+       m_wft = new WikiFetchThread();
+       m_wft.start();
+
+       m_wst = new WikiSearchThread();
+       m_wst.start();
+}
+
+private void stopBackgroundThreads() {
+       synchronized (m_wft) {
+               m_wft.requestStop();
+               try {
+                       m_wft.wait( 30000 );
+               } catch ( InterruptedException e ) {
+                       error( "Problem stopping background fetch thread." );
+               }
+       }
+       synchronized (m_wst) {
+               m_wst.requestStop();
+               try {
+                       m_wst.wait( 30000 );
+               } catch ( InterruptedException e ) {
+                       error( "Problem stopping background search thread." );
+               }
+       }
+       info( "Stopped background threads." );
+
+       int fetches = m_wft.getFetches();
+       double time = (double)(m_wft.getTime()) / 1000.0;
+       double avtime = time / (double)fetches;
+
+       StringBuffer sb = new StringBuffer(100);
+       sb.append( "Fetched " ).append( fetches ).append( " pages in " )
+         .append( threeDecimals( time ) ).append( " sec (" )
+         .append( threeDecimals( avtime ) ).append( " sec per fetch)." );
+       info( sb.toString() );
+
+       int searches = m_wst.getSearches();
+       time = (double)(m_wst.getTime()) / 1000.0;
+       avtime = time / (double)fetches;
+
+       sb.setLength(0);
+       sb.append( "Performed " ).append( searches ).append( " searches in " )
+         .append( threeDecimals( time ) ).append( " sec (" )
+         .append( threeDecimals( avtime ) ).append( " sec per search)." );
+       info( sb.toString() );
+}
+
+/*
+ * Main suite starts here.  Interpret command line, load the
+ * database, then run the individual tests.
+ */
+
+private static boolean f_skipload = false;
+private static boolean f_nobackground = false;
+private static boolean f_overwrite = false;
+private static boolean f_skipmath = false;
+
+public static void main( String[] params ) {
+       for ( int i = 0; i < params.length; ++i ) {
+               if ( "-p".equals( params[i].substring( 0, 2 ) ) ) {
+                       f_skipload = true;
+               } else if ( "-v".equals( params[i].substring( 0, 2 ) ) ) {
+                       setLoggingLevel( Level.ALL );
+               } else if ( "-m".equals( params[i].substring( 0, 2 ) ) ) {
+                       f_skipmath = true;
+               } else if ( "-b".equals( params[i].substring( 0, 2 ) ) ) {
+                       f_nobackground = true;
+               } else if ( "-o".equals( params[i].substring( 0, 2 ) ) ) {
+                       f_overwrite = true;
+               } else if ( "-h".equals( params[i].substring( 0, 2 ) )
+                               || "-?".equals( params[i].substring( 0, 2 ) ) ) {
+                       System.out.println( "Usage: java WikiSuite [-povb]\n" +
+                         "  -p : Skip preload of database\n" +
+                         "  -m : Skip math test\n" +
+                         "  -o : Overwrite database\n" +
+                         "  -v : Verbose logging\n" +
+                         "  -b : No background thread\n" );
+                       return;
+               }
+       }
+       WikiSuite ws = new WikiSuite();
+       if ( ! f_skipload ) {
+               (new DBLoader()).initializeDatabase( ws, f_overwrite );
+       }
+
+       info( "Started Wikipedia Test Suite" );
+       long start_time = System.currentTimeMillis();
+       if ( ! f_nobackground ) { ws.startBackgroundThreads(); }
+
+       /*
+        * All the actual tests go here.
+        */
+       (new LinkTest()).run(ws);
+       (new HTMLTest()).run(ws);
+       (new EditTest()).run(ws);
+       (new ParserTest()).run(ws);
+       (new SpecialTest()).run(ws);
+       (new UploadTest()).run(ws);
+       (new SearchTest()).run(ws);
+       if ( ! f_skipmath ) { (new MathTest()).run(ws); }
+
+       /*
+        * Tests are all done. Clean up and report.
+        */
+       if ( ! f_nobackground ) { ws.stopBackgroundThreads(); }
+       info( "Finished Wikipedia Test Suite" );
+
+       long elapsed_time = System.currentTimeMillis() - start_time;
+
+       long t_hr = elapsed_time / 3600000;
+       long t_min = (elapsed_time % 3600000) / 60000;
+       double t_sec = (double)(elapsed_time % 60000) / 1000.0;
+
+       StringBuffer sb = new StringBuffer(100);
+       sb.append( "Total elapsed time: " ).append( t_hr ).append( " hr, " )
+         .append( t_min ).append( " min, " )
+         .append( threeDecimals( t_sec ) ).append( " sec." );
+       info( sb.toString() );
+}
+
+}
diff --git a/testsuite/src/com/piclab/wikitest/WikiSuiteFailureException.java b/testsuite/src/com/piclab/wikitest/WikiSuiteFailureException.java
new file mode 100644 (file)
index 0000000..aaa2c25
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * This exception is thrown on any general test failure.
+ * It is usually fatal.
+ */
+
+package com.piclab.wikitest;
+
+public class WikiSuiteFailureException
+extends Exception {
+
+public WikiSuiteFailureException() {
+       super();
+}
+
+public WikiSuiteFailureException(Throwable t) {
+       super(t);
+}
+
+public WikiSuiteFailureException(String m) {
+       super(m);
+}
+
+public WikiSuiteFailureException(String m, Throwable t) {
+       super(m, t);
+}
+
+}
+
diff --git a/testsuite/src/com/piclab/wikitest/WikiTest.java b/testsuite/src/com/piclab/wikitest/WikiTest.java
new file mode 100644 (file)
index 0000000..78ac12e
--- /dev/null
@@ -0,0 +1,461 @@
+
+/*
+ * WikiTest is the base class for all the various
+ * individual tests of the installed wiki, which
+ * will be called by WikiSuite.
+ */
+
+package com.piclab.wikitest;
+import com.meterware.httpunit.*;
+import org.w3c.dom.*;
+import java.util.regex.*;
+
+public class WikiTest {
+
+protected WikiSuite m_suite = null;
+protected long m_start, m_stop;
+protected boolean m_verboseflag = false;
+
+/* All subclasses of WikiTest should override testName()
+ * to return a useful name and runTest() to perform the actual
+ * tests. runTest() should return true on success. You can
+ * also overrise initTest() if you like; it gets run before
+ * the individual test timer is started.
+ */
+
+public String testName() { return "Error"; }
+
+protected int initTest() throws Exception {
+       return 0;
+}
+
+protected int runTest() throws Exception {
+       return 0;
+}
+
+/*
+ * This is the primary entry point:
+ */
+
+public void run( WikiSuite ws ) {
+       m_suite = ws;
+       run();
+}
+
+private void run() {
+       int result = 0;
+
+       /* assert( m_suite != null ); */
+
+       java.util.logging.Level ll = null;
+       if ( m_verboseflag ) {
+               ll = WikiSuite.setLoggingLevel( java.util.logging.Level.FINE );
+       }
+
+       try {
+               result = initTest();
+       } catch ( Exception e ) {
+               WikiSuite.error( "Exception (" + e + ") initializing test \"" +
+                 testName() + "\"" );
+               e.printStackTrace();
+               result = 1;
+       }
+       if ( result != 0 ) {
+               WikiSuite.error( "Test \"" + testName() +
+                 "\" failed to initialize with code " + result );
+               return;
+       }
+       WikiSuite.info( "Started test \"" + testName() + "\"" );
+       m_start = System.currentTimeMillis();
+
+       try {
+               result = runTest();
+       } catch (Exception e) {
+               WikiSuite.error( "Exception (" + e + ") running test \"" +
+                 testName() + "\"" );
+               e.printStackTrace();
+               result = 2;
+       }
+       m_stop = System.currentTimeMillis();
+       double time = (double)(m_stop - m_start) / 1000.0;
+
+       StringBuffer sb = new StringBuffer(100);
+       sb.append( "Test \"" ).append( testName() ).append( "\" " )
+         .append( (result==0) ? "Succeeded" : "Failed   " ).append( "   (" )
+         .append( WikiSuite.threeDecimals( time ) ).append( " secs)" );
+       WikiSuite.info( sb.toString() );
+
+       if ( m_verboseflag ) {
+               WikiSuite.setLoggingLevel( ll );
+       }
+}
+
+/*
+ * General utility functions
+ */
+
+public int fail( int code ) {
+       WikiSuite.error( "Test \"" + testName() + "\" failed with code " + code );
+       return code;
+}
+
+public void clearCookies() { m_suite.getConv().clearContents(); }
+
+/*
+ * Encapsulate rules for converting a title to URL form; this
+ * should match the equivalent function in the Wiki code.
+ */
+
+public static String titleToUrl( String title ) {
+       StringBuffer sb = new StringBuffer( title.length() + 20 );
+
+       if ( "".equals( title ) ) {
+               title = WikiSuite.getMainPage();
+       }
+
+       for (int i=0; i<title.length(); ++i) {
+               char c = title.charAt(i);
+               if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) {
+                       sb.append(c);
+               } else if (c >= '0' && c <= '9') {
+                       sb.append(c);
+               } else if (c == '.' || c == '-' || c == '*' || c == ':' || c == '/'
+                 || c == '(' || c == ')' || c == '_') {
+                       sb.append(c);
+               } else if (c == ' ') {
+                       sb.append('_');
+               } else {
+                       sb.append('%');
+                       String hex = "00" + Integer.toHexString((int)c);
+                       sb.append(hex.substring(hex.length() - 2));
+               }
+       }
+       return sb.toString();
+}
+
+public static String viewUrl( String title, String query ) {
+       StringBuffer url = new StringBuffer(200);
+       String t = titleToUrl( title );
+
+       url.append( WikiSuite.getServer() )
+         .append( WikiSuite.getScript() ).append( "?title=" ).append( t )
+         .append( "&" ).append( query );
+       return url.toString();
+}
+
+public static String viewUrl( String title ) {
+       StringBuffer url = new StringBuffer(200);
+       String t = titleToUrl( title );
+       String ap = WikiSuite.getArticlePath();
+
+       int p = ap.indexOf( "$1" );
+       if ( p >= 0 ) {
+               url.append( ap );
+               url.replace( p, p+2, t );
+       } else {
+               url.append( WikiSuite.getServer() )
+                 .append( WikiSuite.getScript() ).append( "?title=" ).append( t );
+       }
+       return url.toString();
+}
+
+public WebResponse getResponse( String url )
+throws WikiSuiteFailureException {
+       WebResponse r = null;
+       String msg = null;
+
+       try {
+               r = m_suite.getConv().getResponse( url );
+       } catch (org.xml.sax.SAXException e) {
+               msg = "Error parsing received page \"" + url + "\"";
+               WikiSuite.warning( msg );
+       } catch (java.net.MalformedURLException e) {
+               msg = "Badly formed URL \"" + url + "\"";
+               WikiSuite.fatal( msg );
+               throw new WikiSuiteFailureException( msg );
+       } catch (java.io.IOException e) {
+               WikiSuite.warning( "I/O Error receiving page \"" + url + "\"" );
+       }
+       return r;
+}
+
+public WebResponse getResponse( WebRequest req ) {
+       WebResponse r = null;
+
+       try {
+               r = m_suite.getConv().getResponse( req );
+       } catch (org.xml.sax.SAXException e) {
+               WikiSuite.warning( "Error parsing received page." );
+       } catch (java.io.IOException e) {
+               WikiSuite.warning( "I/O Error receiving page." );
+       }
+       return r;
+}
+
+public void showResponseTitle( WebResponse wr )
+throws WikiSuiteFailureException {
+       String t = null;
+
+       try {
+               t = wr.getTitle();
+               if ( "Error".equals( t ) || "Database error".equals( t ) ) {
+                       throw new WikiSuiteFailureException( "Got wiki error page." );
+               }
+               WikiSuite.fine( "Viewing \"" + t + "\"" );
+       } catch (org.xml.sax.SAXException e) {
+               WikiSuite.error( "Exception (" + e + ")" );
+               throw new WikiSuiteFailureException( "Couldn't parse title." );
+       }
+}
+
+public WebResponse viewPage( String title )
+throws WikiSuiteFailureException {
+       WebResponse wr = getResponse( viewUrl( title ) );
+       showResponseTitle( wr );
+       return wr;
+}
+
+public WebResponse viewPage( String title, String query )
+throws WikiSuiteFailureException {
+       StringBuffer url = new StringBuffer( 200 );
+       String t = titleToUrl( title );
+
+       url.append( m_suite.getServer() )
+         .append( m_suite.getScript() ).append( "?title=" )
+         .append( t ).append( "&" ).append( query );
+
+       WebResponse wr = getResponse( url.toString() );
+       showResponseTitle( wr );
+       return wr;
+}
+
+public WebResponse searchFor( String target, String query )
+throws WikiSuiteFailureException {
+       StringBuffer url = new StringBuffer( 200 );
+       String t = null;
+       
+       try {
+               t = java.net.URLEncoder.encode( target, "UTF-8" );
+       } catch ( java.io.UnsupportedEncodingException e ) {
+               throw new WikiSuiteFailureException( e.toString() );
+       }
+       url.append( m_suite.getServer() )
+         .append( m_suite.getScript() ).append( "?search=" )
+         .append( t );
+       if ( ! "".equals( query ) ) {
+               url.append( "&" ).append( query );
+       }
+       return getResponse( url.toString() );
+}
+
+public WebResponse searchFor( String target )
+throws WikiSuiteFailureException {
+       return searchFor( target, null );
+}
+
+public WebResponse editPage( String title )
+throws WikiSuiteFailureException {
+       return viewPage( title, "action=edit" );
+}
+
+public static WebForm getFormByName( WebResponse resp, String name )
+throws WikiSuiteFailureException {
+       String msg = null;
+       WebForm[] forms = null;
+
+
+       try {
+               forms = resp.getForms();
+       } catch ( org.xml.sax.SAXException e ) {
+               msg = "Couldn't find form \"" + name + "\"";
+               WikiSuite.error( msg );
+               return null;
+       }
+       for (int i=0; i < forms.length; ++i) {
+               Node formNode = forms[i].getDOMSubtree();
+               NamedNodeMap nnm = formNode.getAttributes();
+               Node nameNode = nnm.getNamedItem( "id" );
+
+               if (nameNode == null) continue;
+               if (nameNode.getNodeValue().equalsIgnoreCase( name )) {
+                       return forms[i];
+               }
+       }
+       return null;
+}
+
+public WebResponse loginAs( String name, String password )
+throws WikiSuiteFailureException {
+       WebResponse wr = null;
+       WebRequest req = null;
+
+       wr = viewPage( "Special:Userlogin" );
+
+       WebForm loginform = getFormByName( wr, "userlogin" );
+       req = loginform.getRequest( "wpLoginattempt" );
+       req.setParameter( "wpName", name );
+       req.setParameter( "wpPassword", password );
+       wr = getResponse( req );
+
+       WikiSuite.fine( "Logged in as " + name );
+       return wr;
+}
+
+public WebResponse logout()
+throws WikiSuiteFailureException {
+       WebResponse wr = viewPage( "Special:Userlogout" );
+       clearCookies();
+       return wr;
+}
+
+public WebResponse deletePage( String title )
+throws WikiSuiteFailureException {
+       WebResponse wr = null;
+
+       wr = loginAs( "WikiSysop", m_suite.getSysopPass() );
+       wr = viewPage( title, "action=delete" );
+
+       String rt = null;
+       try {
+               rt = wr.getTitle();
+       } catch ( org.xml.sax.SAXException e ) {
+               WikiSuite.error( "Could not parse response to delete request." );
+               wr = logout();
+               return null;
+       }
+
+       if ( rt.equals( "Internal error" ) ) {
+               wr = logout();
+               return null;
+               /* Can't delete because it doesn't exist: no problem */
+       }
+
+       WebForm delform = getFormByName( wr, "deleteconfirm" );
+       WebRequest req = delform.getRequest( "wpConfirmB" );
+
+       req.setParameter( "wpReason", "Deletion for testing" );
+       req.setParameter( "wpConfirm", "1" );
+
+       WebResponse ret = getResponse( req );
+       WikiSuite.fine( "Deleted \"" + title + "\"" );
+
+       wr = logout();
+       return ret;
+}
+
+public WebResponse replacePage( String page, String text )
+throws WikiSuiteFailureException {
+       WebResponse wr = editPage( page );
+
+       WebForm editform = getFormByName( wr, "editform" );
+       WebRequest req = editform.getRequest( "wpSave" );
+       req.setParameter( "wpTextbox1", text );
+       return getResponse( req );
+}
+
+public WebResponse addText( String page, String text )
+throws WikiSuiteFailureException {
+       WebResponse wr = editPage( page );
+
+       WebForm editform = getFormByName( wr, "editform" );
+       WebRequest req = editform.getRequest( "wpSave" );
+       String old = req.getParameter( "wpTextbox1" );
+       
+       req.setParameter( "wpTextbox1", old + "\n" + text );
+       req.setParameter( "wpSummary", "Wikitest addition to " + page );
+
+       return getResponse( req );
+}
+
+public WebRequest openPrefs() throws WikiSuiteFailureException {
+       WebResponse wr = viewPage( "Special:Preferences" );
+    WebForm pform = getFormByName( wr, "preferences" );
+       return pform.getRequest( "wpSaveprefs" );
+}
+
+private static Pattern m_startdiv = null, m_enddiv = null;
+
+public String getArticle( WebResponse wr )
+throws WikiSuiteFailureException {
+       String msg = null;
+       String text = null;
+       Matcher m = null;
+
+       if ( m_startdiv == null ) {
+               m_startdiv = Pattern.compile( "<div\\s[^>]*id\\s*=\\s*.article[^>]*>",
+                 Pattern.CASE_INSENSITIVE | Pattern.DOTALL );
+               m_enddiv = Pattern.compile( "</div[^>]*>",
+                 Pattern.CASE_INSENSITIVE | Pattern.DOTALL );
+       }
+       try {
+               text = wr.getText();
+       } catch ( java.io.IOException e ) {
+               msg = "Error (" + e + ") parsing page.";
+               WikiSuite.error( msg );
+               throw new WikiSuiteFailureException( msg );
+       }
+       m = m_startdiv.matcher( text );
+       if (! m.find()) {
+               throw new WikiSuiteFailureException( "Can't find article div start." );
+       }
+
+       text = text.substring( m.end() );
+       m = m_enddiv.matcher( text );
+       if (! m.find()) {
+               throw new WikiSuiteFailureException( "Can't find article div end." );
+       }
+       text = text.substring( 0, m.start() );
+       return text;
+}
+
+public int checkGoodPatterns( String text, String[] pats ) {
+       Pattern p = null;
+       Matcher m = null;
+
+       for ( int i = 0; i < pats.length; ++i ) {
+               p = Pattern.compile( pats[i], Pattern.CASE_INSENSITIVE );
+               m = p.matcher( text );
+
+               if ( ! m.find() ) { return 1 + i; }
+       }
+       return 0;
+}
+
+public int checkBadPatterns( String text, String[] badpats ) {
+       Pattern p = null;
+       Matcher m = null;
+
+       for ( int i = 0; i < badpats.length; ++i ) {
+               p = Pattern.compile( badpats[i], Pattern.CASE_INSENSITIVE );
+               m = p.matcher( text );
+
+               if ( m.find() ) { return 1 + i; }
+       }
+       return 0;
+}
+
+/*
+ * The main method of a subclass should be able to just create 
+ * an instance of itself and call runSingle() to perform a
+ * standalone test, and we'll handle the commandline and
+ * setting up a suite object, etc. They are of course welcome
+ * to set up a more complex main if they want.
+ */
+
+public void runSingle( String[] params ) {
+       /*
+        * Do command line. For now, just verbose flag.
+        */
+       for ( int i = 0; i < params.length; ++i ) {
+               if ( "-v".equals( params[i].substring( 0, 2 ) ) ) {
+                       m_verboseflag = true;
+               }
+       }
+       run( new WikiSuite() );
+}
+
+public static void main( String params ) {
+       System.out.println( "WikiTest is not a runnable class." );
+}
+
+}
diff --git a/testsuite/wikitest.prefs.sample b/testsuite/wikitest.prefs.sample
new file mode 100644 (file)
index 0000000..188b065
--- /dev/null
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE preferences SYSTEM 'http://java.sun.com/dtd/preferences.dtd'>
+
+<!--
+  The preferences here should be set with the same values
+  found in the LocalSettings.php file in the installation
+  to be tested.
+-->
+
+<preferences EXTERNAL_XML_VERSION="1.0">
+  <root type="user">
+    <map />
+    <node name="com">
+      <map />
+      <node name="piclab">
+        <map />
+        <node name="wikitest">
+          <map>
+            <entry key="script" value="/wiki/wiki.phtml" />
+            <entry key="server" value="http://www.myhost.com" />
+            <entry key="articlepath" value="" />
+            <entry key="uploadpath" value="http://www.myhost.com/wiki/uploads" />
+            <entry key="mainpage" value="Main Page" />
+            <entry key="sysoppass" value="adminpass" />
+          </map>
+        </node>
+      </node>
+    </node>
+  </root>
+</preferences>
+
diff --git a/texvc.phtml b/texvc.phtml
new file mode 100644 (file)
index 0000000..7467f81
--- /dev/null
@@ -0,0 +1,155 @@
+<?
+gobal $IP;
+include( "./LocalSettings.php" );
+include( "$IP/Setup.php" );
+header( "Content-type: text/xml; charset={$wgInputEncoding}" );
+print "<";
+print "?xml version=\"1.0\" encoding=\"utf-8\"?";
+print ">";
+?>
+<!DOCTYPE html
+    PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+       "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><title>texvc</title></head><body>
+<?
+print "<form method=\"post\" action=\"{$wgServer}{$wgScriptPath}/texvc_cgi.phtml\">"
+?>
+<textarea name='math' rows='10' cols='80'><?
+    global $math;
+    $math = preg_replace ("/\\\\\\\\/", '\\', $math);
+    print $math;
+?></textarea><br /><input type="submit" value="Preview" name="preview" /></form>
+<?
+function xlinkToMathImage ( $tex, $outputhash )
+{
+    global $wgMathPath;
+    return "<img src=\"".$wgMathPath."/".$outputhash.".png\" alt=\"".wfEscapeHTML($tex)."\" />";
+}
+
+function texvc_cgi_renderMath( $tex )
+{
+    global $wgMathDirectory, $wgTmpDirectory, $wgInputEncoding;
+    $mf   = wfMsg( "math_failure" );
+    $munk = wfMsg( "math_unknown_error" );
+
+    $image = "";
+    $outhtml = "";
+    $outtex = "";
+
+    $fname = "texvc_cgi_renderMath";
+
+    $md5 = md5($tex);
+    $md5_sql = mysql_escape_string(pack("H32", $md5));
+    $sql = "SELECT math_outputhash,math_html_conservativeness,math_html,math_mathml FROM math WHERE math_inputhash = '".$md5_sql."'";
+
+    $res = wfQuery( $sql, $fname );
+    if ( wfNumRows( $res ) == 0 )
+    {
+       $cmd = "./math/texvc ".escapeshellarg($wgTmpDirectory)." ".
+                     escapeshellarg($wgMathDirectory)." ".escapeshellarg($tex)." ".escapeshellarg($wgInputEncoding);
+       $contents = `$cmd`;
+
+       if (strlen($contents) == 0)
+           return "<h3>".$mf." (".$munk."): ".wfEscapeHTML($tex)."</h3>";
+       $retval = substr ($contents, 0, 1);
+
+       if (($retval == "C") || ($retval == "M") || ($retval == "L")) {
+           if ($retval == "C")
+               $conservativeness = 2;
+           else if ($retval == "M")
+               $conservativeness = 1;
+           else
+               $conservativeness = 0;
+           $outdata = substr ($contents, 33);
+
+           $i = strpos($outdata, "\000");
+
+           $outhtml = substr($outdata, 0, $i);
+           $mathml = substr($outdata, $i+1);
+
+           $sql_html = "'".mysql_escape_string($outhtml)."'";
+           $sql_mathml = "'".mysql_escape_string($mathml)."'";
+       } else if (($retval == "c") || ($retval == "m") || ($retval == "l"))  {
+           $outhtml = substr ($contents, 33);
+           if ($retval == "c")
+               $conservativeness = 2;
+           else if ($retval == "m")
+               $conservativeness = 1;
+           else
+               $conservativeness = 0;
+           $sql_html = "'".mysql_escape_string($outhtml)."'";
+           $mathml = '';
+           $sql_mathml = 'NULL';
+       } else if ($retval == "X") {
+           $outhtml = '';
+           $mathml = substr ($contents, 33);
+           $sql_html = 'NULL';
+           $sql_mathml = "'".mysql_escape_string($mathml)."'";
+           $conservativeness = 0;
+       } else if ($retval == "+") {
+           $outhtml = '';
+           $mathml = '';
+           $sql_html = 'NULL';
+           $sql_mathml = 'NULL';
+           $conservativeness = 0;
+       } else {
+           if ($retval == "E")
+               $errmsg = wfMsg( "math_lexing_error" );
+           else if ($retval == "S")
+               $errmsg = wfMsg( "math_syntax_error" );
+           else if ($retval == "F")
+               $errmsg = wfMsg( "math_unknown_function" );
+           else
+               $errmsg = $munk;
+           return "<h3>".$mf." (".$errmsg.substr($contents, 1)."): ".wfEscapeHTML($tex)."</h3>";
+       }
+
+       $outmd5 = substr ($contents, 1, 32);
+       if (!preg_match("/^[a-f0-9]{32}$/", $outmd5))
+           return "<h3>".$mf." (".$munk."): ".wfEscapeHTML($tex)."</h3>";
+
+       $outmd5_sql = mysql_escape_string(pack("H32", $outmd5));
+
+       $sql = "INSERT INTO math VALUES ('".$md5_sql."', '".$outmd5_sql."', ".$conservativeness.", ".$sql_html.", ".$sql_mathml.")";
+
+       $res = wfQuery( $sql, $fname );
+// we don't really care if it fails
+    } else {
+       $rpage = wfFetchObject ( $res );
+       $outmd5 = unpack ("H32md5", $rpage->math_outputhash);
+       $outmd5 = $outmd5 ['md5'];
+       $outhtml = $rpage->math_html;
+       $conservativeness = $rpage->math_html_conservativeness;
+       $mathml = $rpage->math_mathml;
+    }
+    if ($mathml == '')
+       $mathml = "<h3>Failed to generate MathML</h3>";
+    else
+       $mathml = "<h3>MathML</h3><math xmlns=\"http://www.w3.org/1998/Math/MathML\">$mathml</math>";
+    $image = "<h3>Image</h3>" . xlinkToMathImage ( $tex, $outmd5 );
+    $cmd = "./math/texvc_tex ".escapeshellarg($tex)." ".escapeshellarg($wgInputEncoding);
+    $outtex = `$cmd`;
+
+    if ( $outhtml == '' )
+        $outhtml = "<h3>Failed to generate HTML</h3>";
+    else
+       if ( $conservativeness == 2)
+           $outhtml = "<h3>HTML (conservative)</h3>" . $outhtml;
+       else if ( $conservativeness == 1)
+           $outhtml = "<h3>HTML (moderate)</h3>" . $outhtml;
+       else
+           $outhtml = "<h3>HTML (liberal)</h3>" . $outhtml;
+
+    if ( $outtex == '' )
+       $outtex = "<h3>Failed to generate TeX</h3>";
+    else
+       $outtex = "<h3>TeX</h3>" . wfEscapeHTML($outtex);
+
+    return $outtex . $outhtml . $mathml . $image;
+}
+
+global $math;
+if ($math != '')
+    print texvc_cgi_renderMath($math);
+?>
+</body></html>
diff --git a/update.php b/update.php
new file mode 100644 (file)
index 0000000..3d81288
--- /dev/null
@@ -0,0 +1,85 @@
+<?
+
+# Update already-installed software
+#
+
+if ( ! ( is_readable( "./LocalSettings.php" )
+  && is_readable( "./AdminSettings.php" ) ) ) {
+       print "A copy of your installation's LocalSettings.php\n" .
+         "and AdminSettings.php must exist in this source directory.\n";
+       exit();
+}
+
+$DP = "./includes";
+include_once( "./LocalSettings.php" );
+include_once( "./AdminSettings.php" );
+
+if ( $wgUseTeX && ( ! is_executable( "./math/texvc" ) ) ) {
+       print "To use math functions, you must first compile texvc by\n" .
+         "running \"make\" in the math directory.\n";
+       exit();
+}
+
+umask( 000 );
+set_time_limit( 0 );
+
+#
+# Copy files into installation directories
+#
+print "Copying files...\n";
+
+copyfile( ".", "wiki.phtml", $IP );
+copyfile( ".", "redirect.phtml", $IP );
+copyfile( ".", "texvc.phtml", $IP );
+
+$handle = opendir( "./includes" );
+while ( false !== ( $f = readdir( $handle ) ) ) {
+       if ( "." == $f{0} ) continue;
+       copyfile( "./includes", $f, $IP );
+}
+
+$handle = opendir( "./stylesheets" );
+while ( false !== ( $f = readdir( $handle ) ) ) {
+       if ( "." == $f{0} ) continue;
+       copyfile( "./stylesheets", $f, $wgStyleSheetDirectory );
+}
+
+copyfile( "./images", "wiki.png", $wgUploadDirectory );
+copyfile( "./languages", "Language.php", $IP );
+copyfile( "./languages", "Language" . ucfirst( $wgLanguageCode ) . ".php", $IP );
+
+$fp = fopen( $wgDebugLogFile, "w" );
+if ( false === $fp ) {
+       print "Could not create log file \"{$wgDebugLogFile}\".\n";
+       exit();
+}
+$d = date( "Y-m-d H:i:s" );
+fwrite( $fp, "Wiki debug log file created {$d}\n\n" );
+fclose( $fp );
+
+if ( $wgUseTeX ) {
+       copyfile( "./math", "texvc", "{$IP}/math", 0775 );
+       copyfile( "./math", "texvc_test", "{$IP}/math", 0775 );
+       copyfile( "./math", "texvc_tex", "{$IP}/math", 0775 );
+}
+
+print "Done.\nIf any database changes are necessary, you may have to run\n" .
+  "one or more \"patch\" files from the maintenance directory.\n";
+exit();
+
+function copyfile( $sdir, $name, $ddir, $perms = 0644 ) {
+       global $installOwner, $installGroup;
+
+       $d = "{$ddir}/{$name}";
+       if ( copy( "{$sdir}/{$name}", $d ) ) {
+               if ( isset( $installOwner ) ) { chown( $d, $installOwner ); }
+               if ( isset( $installGroup ) ) { chgrp( $d, $installGroup ); }
+               chmod( $d, $perms );
+               # print "Copied \"{$name}\" to \"{$ddir}\".\n";
+       } else {
+               print "Failed to copy file \"{$name}\" to \"{$ddir}\".\n";
+               exit();
+       }
+}
+
+?>
diff --git a/wiki.phtml b/wiki.phtml
new file mode 100644 (file)
index 0000000..8b07102
--- /dev/null
@@ -0,0 +1,74 @@
+<?
+# Main wiki script; see design.doc
+#
+$wgRequestTime = microtime();
+
+session_cache_limiter( "public" );
+session_start();
+session_register( "wsUserID" );
+session_register( "wsUserName" );
+session_register( "wsUserPassword" );
+
+global $IP;
+include_once( "./LocalSettings.php" );
+include_once( "$IP/Setup.php" );
+
+wfProfileIn( "main-misc-setup" );
+OutputPage::setEncodings(); # Not really used yet
+
+# Query string fields
+#
+global $action, $title, $search, $go, $target, $printable;
+global $returnto, $diff, $oldid;
+
+$action = strtolower( trim( $action ) );
+if ( "" == $action ) { $action = "view"; }
+if ( "yes" == $printable ) { $wgOut->setPrintable(); }
+
+if ( "" == $title && "delete" != $action ) {
+       $wgTitle = Title::newFromText( wfMsg( "mainpage" ) );
+} else {
+       $wgTitle = Title::newFromURL( $title );
+#      if( $wgTitle->getInterwiki() != "" or $wgTitle->getDBkey() == "" or strncmp($wgTitle->getDBkey(),"_",1) == 0 ) {
+       if( $wgTitle->getInterwiki() != "" or $wgTitle->getDBkey() == "" ) {
+               $wgOut->errorpage( "badtitle", "badtitletext" );
+               $wgOut->output();
+               exit;
+       }
+}
+wfProfileOut();
+if ( -1 == $wgTitle->getNamespace() ) {
+       wfSpecialPage();
+} else if ( "" != $search ) {
+       if($go) {
+       
+               wfGo ($search);
+       
+       } else {
+       
+               wfSearch( $search );
+               
+       }
+               
+} else {
+       $wgArticle = new Article();
+
+       if ( "view" == $action ) { $wgArticle->view(); }
+       else if ( "edit" == $action ) { $wgArticle->edit(); }
+       else if ( "submit" == $action ) { $wgArticle->submit(); }
+       else if ( "print" == $action ) { $wgArticle->view(); }
+       else if ( "watch" == $action ) { $wgArticle->watch(); }
+       else if ( "unwatch" == $action ) { $wgArticle->unwatch(); }
+       else if ( "history" == $action ) { $wgArticle->history(); }
+       else if ( "delete" == $action ) { $wgArticle->delete(); }
+       else if ( "revert" == $action ) { $wgArticle->revert(); }
+       else if ( "rollback" == $action ) { $wgArticle->rollback(); }
+       else if ( "protect" == $action ) { $wgArticle->protect(); }
+       else if ( "unprotect" == $action ) { $wgArticle->unprotect(); }
+       else { $wgOut->errorpage( "nosuchaction", "nosuchactiontext" ); }
+}
+
+$wgOut->output();
+foreach ( $wgDeferredUpdateList as $up ) { $up->doUpdate(); }
+
+?>