مدیاویکی:Gadget-popups.js

از ویکی‌خبر، مرجع خبری آزاد

نکته: پس از انتشار ممکن است برای دیدن تغییرات نیاز باشد که حافظهٔ نهانی مرورگر خود را پاک کنید.

  • فایرفاکس / سافاری: کلید Shift را نگه دارید و روی دکمهٔ Reload کلیک کنید، یا کلید‌های Ctrl-F5 یا Ctrl-R را با هم فشار دهید (در رایانه‌های اپل مکینتاش کلید‌های ⌘-R)
  • گوگل کروم: کلیدهای Ctrl+Shift+R را با هم فشار دهید (در رایانه‌های اپل مکینتاش کلید‌های ⌘-Shift-R)
  • اینترنت اکسپلورر/ Edge: کلید Ctrl را نگه‌دارید و روی دکمهٔ Refresh کلیک کنید، یا کلید‌های Ctrl-F5 را با هم فشار دهید
  • اپرا: Ctrl-F5 را بفشارید.
/*<pre>*/
var popupVersion="Sat Feb 4 12:06:55 EST 2006";
//Credit goes to [[en:User:Lupin]] and others 
//Source: //en.wikipedia.org/w/index.php?title=User:Lupin/popups.js&oldid=38164589

// **********************************************************************
// **                             Warning                              **
// **********************************************************************
// ** if you edit this file, be sure that your editor recognizes it as **
// **   utf8, or the weird and wonderful characters in the namespaces  **
// **   below will be completely broken. You can check with the show   **
// **            changes button before submitting the edit.            **
// **                      test: مدیا מיוחד Мэдыя                      **
// **********************************************************************

// CONTENTS

// Stylesheets

// Utility functions

// Popup stuff
//   global variables 
//   html generation 
//   downloading 
//   link generation 
//   manipulation functions 
//   tests 
//   actions 
//   thingies 


////////////////////////////////////////////////////////////////////
// Import stylesheet(s)
////////////////////////////////////////////////////////////////////

document.write('<link rel="stylesheet" type="text/css" href="'  
             + 'http://fa.Wikinews.org/w/index.php?title=Mediawiki:Menus.css'
             + '&action=raw&ctype=text/css&dontcountme=s">');

////////////////////////////////////////////////////////////////////
// Utility functions
////////////////////////////////////////////////////////////////////

function time() {
  var d=new Date();
  return d.getHours() + ':' + d.getMinutes() + ':' + d.getSeconds() +
    '.' + (d.getTime() % 1000);
};

var gMsg='';
function log(x) { if(gMsg!='')gMsg += '\n'; gMsg+=time() + ' ' + x; };

function myalert(x) { return alert(time()+'\n'+ x); };

////////////////////////////////////////////////////////////////////
// Popup stuff
////////////////////////////////////////////////////////////////////

// livepreview uses a broken hex_md5 function, so we avoid it
function md5_hex(s) { return rstr2hex(rstr_md5(str2rstr_utf8(s))); };

/////////////////////
// GLOBAL VARIABLES //
//////////////////////

// Notes for translators
// If there's a string that I've not included below, please drop a note at [[:en:User_talk:Lupin]].
// These strings can be changed if they're impossible to translate to more flexible versions. 
// Just ask.

function popupString(str) {
  if (popupStrings[str]) return popupStrings[str];
  return str;
}
if (typeof window.popupStrings=='undefined') window.popupStrings={};
popupStrings['#']='#';
popupStrings['actions']='اعمال';
popupStrings['arin']='ARIN lookup';
popupStrings['article']='خبر';
popupStrings['block']='بستن';
popupStrings['BlockipHint']='بازداشتن %s از ویرایش';
popupStrings['block log']='سیاههٔ بسته‌شدن‌ها';
popupStrings['blockLogHint']='نمایش سیاههٔ بسته‌شدنهای %s';
popupStrings['block user']='بستن کاربر';
popupStrings['Bypass redirect']='دورزدن تغییر مسیر';
popupStrings['bytes']='بایت';
popupStrings['category']='رده';
popupStrings['categories']='رده';
popupStrings['Click to disambiguate this link to:']='کلیک کنید تا این پیوند را ابهام‌زدایی کنید به:';
popupStrings['contribs']='مشارکت‌کنندگان';
popupStrings['contribsTree']='درخت مشارکت‌کنندگان';
popupStrings['tree']='درخت';
popupStrings['contribsTreeHint']='Explore %s\'s contributions by namespace and by article';
popupStrings['contributions']='مشارکت';
popupStrings['ContributionsHint']='نمایش فهرست مشارکت‌های %s ';
popupStrings['cookies']='کوکی‌ها';
popupStrings['count']='شمارشگر';
popupStrings['cur']='کنونی';
popupStrings['day']='روز';
popupStrings['days']='روز';
popupStrings['defaultpopupFixDabsSummary']='ابهام‌زدایی [[%s]] به [[%s]] با استفاده از [[ویکی‌خبر:پاپآپس|پاپآپس]]';
popupStrings['defaultpopupFixRedirsSummary']='دور زدن تغییر مسیر [[%s]] به [[%s]] با استفاده از [[ویکی‌خبر:پاپآپس|پاپآپس]]';
popupStrings['defaultpopupRevertSummary']='واگردانی به نسخهٔ %s با استفاده از [[ویکی‌خبر:پاپآپس|پاپآپس]]'; 
popupStrings['defaultpopupRmDabLinkSummary']='Remove link to dab page [[%s]] using [[ویکی‌خبر:پاپآپس|پاپآپس]]'; 
popupStrings['del']='حذف';
popupStrings['delete']='حذف';
popupStrings['deleteHint']='%s حذف';
popupStrings['diffCur']='فرق جاری';
popupStrings['disambig']='ابهام‌زدایی';
popupStrings['disambigHint']='این پیوند را به [[%s]] ابهام زدایی کن';
popupStrings['Display navigation links at the top of the popup']='پیوندهای ناوبری را در اول منوی پاپ‌آپ نشان بده';
popupStrings['Download preview data']='اطلاعات پیش‌نمایش را از میزبان‌های ویکی‌خبر بارگیری کن';
popupStrings['edit article']='ویرایش خبر';
popupStrings['edit counter']='شمارشگر ویرایش';
popupStrings['edit']='ویرایش';
popupStrings['editHint']='ویرایش %s';
popupStrings['editOld']='editOld'; 
popupStrings['editorListHint']='نمایش فهرست نام ویرایشگران خبر %s'; 
popupStrings['editors']='ویرایشگران';
popupStrings['edit talk']='ویرایش بحث';
popupStrings['edit user talk']='ویرایش بحث کاربر';
popupStrings['eds']='eds';
popupStrings['email']='رایانامه';
popupStrings['email user']='رایانامه کاربر';
popupStrings['EmailuserHint']='ارسال رایانامه به %s'; 
popupStrings['Empty page']='خالی است!';
popupStrings['Fix this redirect']='اصلاح این تغییر مسیر';
popupStrings['global']='کلی';
popupStrings['globalSearchHint']='جستجوی %s در دیگر زبان‌های ویکی‌خبر'; 
popupStrings['hist']='تاریخچه';
popupStrings['historyHint']='نمایش فهرست تغییرات رخ‌داده در خبر %s';
popupStrings['history']='تاریخچه';
popupStrings['hour']='ساعت';
popupStrings['hours']='ساعت';
popupStrings['IpblocklistHint']='سیاههٔ بسته‌شدن‌ها %s';
popupStrings['image']='تصویر';
popupStrings['images']='تصویر';
popupStrings['katelinkHint']='مشارکت‌های %s را بشمار'; 
popupStrings['kB']='کیلوبایت';
popupStrings['lastEdit']='آخرین ویرایش';
popupStrings['last']='آخرین';
popupStrings['leave comment']='نوشتن یادداشت';
popupStrings['links here']='به اینجا پیوند دارد';
popupStrings['Load images']='بارگذاری تصاویر';
popupStrings['log']='سیاهه';
popupStrings['Look up %s in ARIN whois database']='Look up %s in ARIN whois database';
popupStrings['mainlink']='پیوند اصلی';
popupStrings['minute']='دقیقه';
popupStrings['minutes']='دقیقه';
popupStrings['move']='انتقال';
popupStrings['MovepageHint']='تغییر نام %s';
popupStrings['move page']='انتقال صفحه';
popupStrings['Never download extra stuff for images/previews']='Never download extra stuff for images/previews';
popupStrings['new']='جدید';
popupStrings['newSectionHint']='آغاز بخشی جدید در %s';
popupStrings['new topic']='عنوان جدید';
popupStrings['nullEditHint']='ویرایش در %sبدون تغییر چیزی ';
popupStrings['null edit']='ویرایش پوچ';
popupStrings['old']='پیش';
popupStrings['oldEdit']='ویرایش قدیمی';
popupStrings['Open full-size image']='نمایش تمام‌قد تصویر';
popupStrings['Only start downloading when told to do so']='فقط وقتی گفته می‌شود بارگیری کن';
popupStrings['PrefixindexHint']='Show pages in the userspace of %s';
popupStrings['Preview only on click']='پیش‌نمایش تنها پس از کلیک';
popupStrings['protectHint']='اختیارات ویرایشی را منحصر به  %s کن';
popupStrings['protect']='محافظت';
popupStrings['RecentchangeslinkedHint']='نمایش تغییرات مرتبط با %s';
popupStrings['Redirects']='Redirects'; // as in Redirect to ...
popupStrings['related changes']='تغییرات مرتبط';
popupStrings['related']='مرتبط';
popupStrings['remove all links to this disambig page from this article']='حذف تمام پیوندهای به این صفحهٔ ابهام‌زدایی در این مقاله';
popupStrings['remove this link']='حذف این پیوند';
popupStrings['revertHint']='واگردانی به %s';
popupStrings['revert']='واگردانی';
popupStrings['revision %s of %s']='نسخهٔ %s %s';
popupStrings['rv']='وگ';
popupStrings['SearchHint']='Find English Wikinews articles containing %s';
popupStrings['search']='جستجو';
popupStrings['second']='ثانیه';
popupStrings['seconds']='ثانیه';
popupStrings['Show changes since revision %s']='نمایش تغییرات از نسخهٔ %s';
popupStrings['Show/hide options']='نمایش/نهفتن گزینه‌ها';
popupStrings['Show image previews']='نمایش پیش‌نمایش‌های تصویر';
popupStrings['show last edit']='آخرین ویرایش‌ها';
popupStrings['last set of edits']='آخرین مجموعه ویرایش‌ها';
popupStrings['Show navigation links']='نمایش پیوندهای هدایت';
popupStrings['Show page summary data']='نمایش داده‌های خلاصهٔ صفحه';
popupStrings['Show previews']='نمایش پیش‌نمایش‌ها';
popupStrings['Show summary data']='نمایش داده‌های خلاصه';
popupStrings['Show text previews']='نمایش پیش‌نمایش‌های متن';
popupStrings['Show the edit made to get revision']='Show the edit made to get revision';
popupStrings['Show the last edit']='نمایش آخرین ویرایش';
popupStrings['Simple popups']='پاپ‌آپ‌های ساده';
popupStrings['spacebar']='فضا';
popupStrings['space']='فضا';
popupStrings['stub']='ناقص';
popupStrings['talk page']='صفحه بحث';
popupStrings['talk']='بحث';
popupStrings['this&nbsp;revision']='این&nbsp;نسخه';
popupStrings['Toggle image size']='تغییر اندازه تصویر';
popupStrings['Toggle this option']='Toggle this option';
popupStrings[' to ']=' به '; // as in Redirects to ...
popupStrings['unblockShort']='بازکردن';
popupStrings['UndeleteHint']='نشان‌دادن تاریخچهٔ حذف %s';
popupStrings['undeleteShort']='واگردانی حذف';
popupStrings['unprotectHint']='Allow %s to be edited by anyone again';
popupStrings['unprotectShort']='پایان محافظت';
popupStrings['unwatchHint']='حذف کردن %s از فهرست پی‌گیری‌های من';
popupStrings['unwatchShort']='توقف';
popupStrings['Use cookies to store popups options']='Use cookies to store popups options';
popupStrings['userLogHint']='Show %s\'s user log';
popupStrings['user log']='سیاهه کاربر';
popupStrings['user page']='صفحه کاربر';
popupStrings['user talk']='بحث کاربر';
popupStrings['user']='کاربر';
popupStrings['view article']='نمایش خبر';
popupStrings['viewHint']='برو به %s';
popupStrings['watchHint']='اضافه کردن %s به فهرست پی‌گیری‌های من';
popupStrings['watchThingy']='پی‌گیری';  // called watchThingy because {}.watch is a function
popupStrings['week']='هفته';
popupStrings['weeks']='هفته';
popupStrings['what links here']='آنچه به اینجا پیوند دارد';
popupStrings['whatLinksHere']='آنچه به اینجا پیوند دارد';
popupStrings['WhatlinkshereHint']='نمایش فهرست خبرهایی که به خبر %s پیوند دارند'; 
popupStrings['wikiLinks']='پیوند‌ ویکی';
popupStrings['sinceMeHint']='نمایش تغییرات پس از آخرین ویرایش من';
popupStrings['lastContribHint']='نمایش همهٔ تغییراتی که آخرین ویرایشگر انجام داده است';
popupStrings['changes since mine']='تفاوت با ویراستهٔ من';
popupStrings['Diff truncated for performance reasons']='Diff truncated for performance reasons';
popupStrings['googleSearchHint']='نتایج گوگل برای %s';
popupStrings['web']='وب';
popupStrings['google']='گوگل';
var splitLoc=window.location.href.split('/');
var thisWiki=splitLoc[2];
var wikiLang=thisWiki.split('.')[0];

// regexes and so on

// this stuff should be customized for different languages

var popNamespaces = ["Media", "Special", "Talk", "User", "User talk", "Wikinews", "Wikinews talk", "Image", "Image talk", "MediaWiki", "MediaWiki talk", "Template", "Template talk", "Help", "Help talk", "Category", "Category talk", "Portal", "Portal talk"];

switch (wikiLang) {
 case "ar": popNamespaces=["ملف", "خاص", "نقاش", "مستخدم", "نقاش المستخدم", "ويكي الأخبار", "نقاش ويكي الأخبار", "صورة", "نقاش الصورة", "ميدياويكي", "نقاش ميدياويكي", "Template", "نقاش Template", "مساعدة", "نقاش المساعدة", "تصنيف", "نقاش التصنيف"]; break;
 case "bg": popNamespaces=["Медия", "Специални", "Беседа", "Потребител", "Потребител беседа", "Уикиновини", "Уикиновини беседа", "Картинка", "Картинка беседа", "МедияУики", "МедияУики беседа", "Шаблон", "Шаблон беседа", "Помощ", "Помощ беседа", "Категория", "Категория беседа"]; break;
 case "ca": popNamespaces=["Media", "Especial", "Discussió", "Usuari", "Usuari Discussió", "Viquinotícies", "Viquinotícies Discussió", "Imatge", "Imatge Discussió", "MediaWiki", "MediaWiki Discussió", "Template", "Template Discussió", "Ajuda", "Ajuda Discussió", "Categoria", "Categoria Discussió"]; break;
 case "cs": popNamespaces=["Média", "Speciální", "Diskuse", "Wikizprávy", "Wikizprávy diskuse", "Wikizprávy", "Wikizprávy diskuse", "Soubor", "Soubor diskuse", "MediaWiki", "MediaWiki diskuse", "Šablona", "Šablona diskuse", "Nápověda", "Nápověda diskuse", "Kategorie", "Kategorie diskuse"]; break;
 case "de": popNamespaces=["Media", "Spezial", "Diskussion", "Benutzer", "Benutzer Diskussion", "Wikinews", "Wikinews Diskussion", "Bild", "Bild Diskussion", "MediaWiki", "MediaWiki Diskussion", "Vorlage", "Vorlage Diskussion", "Hilfe", "Hilfe Diskussion", "Kategorie", "Kategorie Diskussion", "Portal", "Portal Diskussion"]; break;
 case "eo": popNamespaces=["Media", "Speciala", "Diskuto", "Vikipediisto", "Vikipediista diskuto", "Vikinovaĵoj", "Vikinovaĵoj diskuto", "Dosiero", "Dosiera diskuto", "MediaWiki", "MediaWiki diskuto", "Ŝablono", "Ŝablona diskuto", "Helpo", "Helpa diskuto", "Kategorio", "Kategoria diskuto"]; break;
 case "es": popNamespaces=["Media", "Especial", "Discusión", "Usuario", "Usuario Discusión", "Wikinews", "Wikinews Discusión", "Imagen", "Imagen Discusión", "MediaWiki", "MediaWiki Discusión", "Plantilla", "Plantilla Discusión", "Ayuda", "Ayuda Discusión", "Categoría", "Categoría Discusión"]; break;
 case "fa": popNamespaces=["مدیا", "ویژه", "بحث", "کاربر", "بحث کاربر", "ویکی‌خبر", "بحث ویکی‌خبر", "تصویر", "بحث تصویر", "مدیاویکی", "بحث مدیاویکی", "الگو", "بحث الگو", "راهنما", "بحث راهنما", "رده", "بحث رده"]; break;
 case "fr": popNamespaces=["Media", "Special", "Discuter", "Utilisateur", "Discussion Utilisateur", "Wikinews", "Discussion Wikinews", "Image", "Discussion Image", "MediaWiki", "Discussion MediaWiki", "Modèle", "Discussion Modèle", "Aide", "Discussion Aide", "Catégorie", "Discussion Catégorie", "Portail", "Discussion Portail"]; break;
 case "he": popNamespaces=["Media", "מיוחד", "שיחה", "משתמש", "שיחת משתמש", "ויקיפדיה", "שיחת ויקיפדיה", "תמונה", "שיחת תמונה", "MediaWiki", "שיחת MediaWiki", "תבנית", "שיחת תבנית", "עזרה", "שיחת עזרה", "קטגוריה", "שיחת קטגוריה"]; break;
 case "hu": popNamespaces=["Média", "Speciális", "Vita", "User", "User vita", "Wikipédia", "Wikipédia vita", "Kép", "Kép vita", "MediaWiki", "MediaWiki vita", "Sablon", "Sablon vita", "Segítség", "Segítség vita", "Kategória", "Kategória vita"]; break;
 case "it": popNamespaces=["Media", "Speciale", "Discussione", "Utente", "Discussioni utente", "Wikinews", "Discussioni Wikinews", "Immagine", "Discussioni immagine", "MediaWiki", "Discussioni MediaWiki", "Template", "Discussioni template", "Aiuto", "Discussioni aiuto", "Categoria", "Discussioni categoria"]; break;
 case "ja": popNamespaces=["Media", "特別", "ノート", "利用者", "利用者‐会話", "Wikinews", "Wikinews‐ノート", "画像", "画像‐ノート", "MediaWiki", "MediaWiki‐ノート", "Template", "Template‐ノート", "Help", "Help‐ノート", "Category", "Category‐ノート"]; break;
 case "ko": popNamespaces=["Media", "특수기능", "토론", "사용자", "사용자토론", "위키백과", "위키백과토론", "그림", "그림토론", "분류", "분류토론", "MediaWiki", "MediaWiki talk", "Template", "Template talk", "Help", "Help talk"]; break;
 case "no": popNamespaces=["Medium", "Spesial", "Diskusjon", "Bruker", "Brukerdiskusjon", "Wikinews", "Wikinews-diskusjon", "Bilde", "Bildediskusjon", "MediaWiki", "MediaWiki-diskusjon", "Mal", "Maldiskusjon", "Hjelp", "Hjelpdiskusjon", "Kategori", "Kategoridiskusjon"]; break;
 case "pl": popNamespaces=["Media", "Specjalna", "Dyskusja", "Wikipedysta", "Dyskusja Wikipedysty", "Wikinews", "Dyskusja Wikipedii", "Grafika", "Dyskusja grafiki", "MediaWiki", "Dyskusja MediaWiki", "Szablon", "Dyskusja szablonu", "Pomoc", "Dyskusja pomocy", "Kategoria", "Dyskusja kategorii", "Portal", "Dyskusja portalu"]; break;
 case "pt": popNamespaces=["Media", "Especial", "Discussão", "Usuário", "Usuário Discussão", "Wikinews", "Wikinews Discussão", "Imagem", "Imagem Discussão", "MediaWiki", "MediaWiki Discussão", "Predefinição", "Predefinição Discussão", "Ajuda", "Ajuda Discussão", "Categoria", "Categoria Discussão"]; break;
 case "ro": popNamespaces=["Media", "Special", "Discuţie", "Utilizator", "Discuţie Utilizator", "Wikinews", "Discuţie Wikinews", "Imagine", "Discuţie Imagine", "MediaWiki", "Discuţie MediaWiki", "Format", "Discuţie Format", "Ajutor", "Discuţie Ajutor", "Categorie", "Discuţie Categorie"]; break;
 case "ru": popNamespaces=["Медиа", "Служебная", "Обсуждение", "Участник", "Обсуждение участника", "Википедия", "Обсуждение Википедии", "Изображение", "Обсуждение изображения", "MediaWiki", "Обсуждение MediaWiki", "Шаблон", "Обсуждение шаблона", "Справка", "Обсуждение справки", "Категория", "Обсуждение категории"]; break;
 case "sr": popNamespaces=["Media", "Посебно", "Разговор", "Корисник", "Разговор са корисником", "Википедија", "Разговор о Википедији", "Слика", "Разговор о слици", "МедијаВики", "Разговор о МедијаВикију", "Шаблон", "Разговор о шаблону", "Помоћ", "Разговор о помоћи", "Категорија", "Разговор о категорији", "Портал", "Разговор о порталу"]; break;
 case "th": popNamespaces=["Media", "พิเศษ", "พูดคุย", "ผู้ใช้", "คุยเกี่ยวกับผู้ใช้", "Wikinews", "Wikinews talk", "ภาพ", "คุยเกี่ยวกับภาพ", "MediaWiki", "คุยเกี่ยวกับ MediaWiki", "Template", "Template talk", "Help", "Help talk", "Category", "Category talk"]; break;
 case "tr": popNamespaces=["Media", "Özel", "Tartışma", "Kullanıcı", "Kullanıcı mesaj", "Vikipedi", "Vikipedi tartışma", "Resim", "Resim tartışma", "MedyaViki", "MedyaViki tartışma", "Şablon", "Şablon tartışma", "Yardım", "Yardım tartışma", "Kategori", "Kategori tartışma"]; break;
 case "uk": popNamespaces=["Медіа", "Спеціальні", "Обговорення", "Користувач", "Обговорення користувача", "Wikinews", "Обговорення Wikinews", "Зображення", "Обговорення зображення", "MediaWiki", "Обговорення MediaWiki", "Шаблон", "Обговорення шаблону", "Довідка", "Обговорення довідки", "Категорія", "Обговорення категорії"]; break;
 case "zh": popNamespaces=["Media", "Special", "Talk", "User", "User talk", "Wikinews", "Wikinews talk", "Image", "Image talk", "MediaWiki", "MediaWiki talk", "Template", "Template talk", "Help", "Help talk", "Category", "Category talk", "Portal", "Portal talk"]; break;
}

var popNamespacesWithTalk=[null]; // NB root (article) corresponds with this entry, null
var popTalkNamespaces=[popNamespaces[2]];

// if the number of namespaces changes then this will have to be changed
// maybe the easiest way is to specify the arrays by hand as in the comments following the loop

for (var i=3; i+1<popNamespaces.length; i=i+2) { 
  popNamespacesWithTalk.push(popNamespaces[i]);
  popTalkNamespaces.push(popNamespaces[i+1]);
}

var popSpecialNamespace=popNamespaces[1];
var popImageNamespace=popNamespaces[7];
var popUserNamespace=popNamespaces[3];
var popCategoryNamespace=popNamespaces[15];
var stubRegex= RegExp('stub[}][}]|This .*-related article is a .*stub', 'im') ;
var disambigRegex=RegExp('([{][{]\\s*disambig|disambig\\s*[}][}]|disamb\\s*[}][}]|dab\\s*[}][}])' +
                         '|[{][{]\\s*(geo|hn)dis\\s*[}][}]' + // explicit, whole template names on this line
                         '|is a .*disambiguation.*page', 'im') ;
var popNonArticleNamespaces=popNamespaces.slice(0,2).concat(popNamespaces.slice(2));

// end of language-specific things


var popContribsPage=popSpecialNamespace+':' + 'Contributions';
var popEmailPage=popSpecialNamespace+':' + 'Emailuser';

var exceptions=RegExp('((title=|/)'+popSpecialNamespace+':|section=[0-9])') ;
var contributions=RegExp('(title=|/)'+popContribsPage+'(&target=|/|/'+
                         popUserNamespace+':)(.*)') ;
var emailuser=    RegExp('(title=|/)'+popEmailPage   +'(&target=|/|/'+
                         popUserNamespace+':)(.*)') ;

//                      (^|\[\[)image: *([^|\]]*[^|\] ]) * 
//                      (^|\[\[)image: *([^|\]]*[^|\] ])([^0-9\]]*([0-9]+) *px)?
//                                                        $4 = 120 as in 120px
var imageRegex= RegExp('(^|\\[\\[)'+
                       popImageNamespace+
                       ': *([^|\\]]*[^|\\] ])([^0-9\\]]*([0-9]+) *px)?',
                       'img') ;
var imageRegexBracketCount = 4;

var categoryRegex= RegExp('\\[\\['+popCategoryNamespace+
                          ': *([^|\\]]*[^|\\] ]) *', 'i') ;
var categoryRegexBracketCount = 1;

var ipUserRegex=RegExp('('+popUserNamespace+':)?' + 
                       '((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){3}' + 
                       '(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])');

var oldidRegex=RegExp('[?&]oldid=([^&]*)');
var diffRegex=RegExp('[?&]diff=([^&]*)');

var wikimediaWiki=RegExp('wiki([pm]edia|source|books|news|quote)\\.org|wiktionary\\.org').test(thisWiki);
var localWiki=RegExp('^localhost').test(thisWiki);
var protocol=splitLoc[0].split(':')[0];

var titletail='/index.php?title=';
if (wikimediaWiki) titletail = '/w' + titletail;
else if (localWiki) titletail = '/wiki' + titletail;



// /REGEX

// we're not set up for interwiki stuff yet - only affect en, commons 
// and wiktionary links

var reStart='[^:]*://';
var preTitles='wiki/|w/index\\.php\\?title=';

if (!wikimediaWiki) {
  preTitles = 'wiki/index\\.php\\?title=|wiki/index\\.php/|'+preTitles
    + '|index\\.php\\?title=' ;
}
var reEnd='/(' + preTitles + ')([^&?]*)';
var re = RegExp(reStart + thisWiki.split('.').join('\\.') + reEnd);

var titlebase=protocol+'://'+thisWiki+titletail;     
var wikibase=protocol+'://'+thisWiki+'/wiki/';

var popupImageSize=60;

var imageSources=new Array ();

var commonsWiki='commons.wikimedia.org';

// frequently seen thumbs
imageSources.push(
   {wiki: thisWiki, thumb: true,  width: 180}, // default
   {wiki: thisWiki, thumb: true,  width: 120} // gallery
 );

// frequently seen thumbs on commons
if (wikimediaWiki && thisWiki!=commonsWiki) {
  imageSources.push(
    {wiki: commonsWiki, thumb: true,  width: 180},
    {wiki: commonsWiki, thumb: true,  width: 120}
  );
}

// unusual thumb sizes and full-size
imageSources.push(
   {wiki: thisWiki, thumb: true,  width: 200}, // common?
   {wiki: thisWiki, thumb: true,  width: 250}, // common?
   {wiki: thisWiki, thumb: true,  width: 300},
   {wiki: thisWiki, thumb: true,  width: 210},
   {wiki: thisWiki, thumb: true,  width: 230},
   {wiki: thisWiki, thumb: false, width: 0} // no comma
);

// full-size on commons
if (wikimediaWiki && thisWiki!=commonsWiki) {
  imageSources.push({wiki: commonsWiki, thumb: false, width: 0});
}

// downloading images are put here
var imageArray=new Array();

// page caching
var gCachedPages = new Array ();
var gImageCache = new Array();
  
// FIXME what is this for?
var gImage=null; // global for image

// check to see if images are done with this timer
var popupImageTimer=null;

// misc debug messages
var popupDebug=null;

// These are for checkImages()
var counter=0;
var checkImagesTimer=null;
var checkPoupPositionTimer=null;
var loopcounter=0;

// ids change with each popup: popupImage0, popupImage1 etc
var popupIdNumber=0;

// for myDecodeURI
var decodeExtras = new Array ();
decodeExtras.push ( 
  {from: '%2C', to: ',' }, 
  {from: '_',   to: ' ' },
  {from: '%24', to: '$'},  
  {from: '%26',   to: '&' } // no ,
);

// for setPopupHTML - needed for timers and stuff
var popupHTMLTimers=new Array();
var popupHTMLLoopFunctions = new Array();

// FIXME - eliminate this
var redirCount=0;

// Cookie handling
// pasted straight from http://www.quirksmode.org/js/cookies.html

function createCookie(name,value,days)
{
  var expires;
  if (days)
    {
      var date = new Date();
      date.setTime(date.getTime()+(days*24*60*60*1000));
      expires = "; expires="+date.toGMTString();
    }
  else expires = "";
  document.cookie = name+"="+value+expires+"; path=/";
};

function readCookie(name)
{
  var nameEQ = name + "=";
  var ca = document.cookie.split(';');
  for(var i=0;i < ca.length;i++)
    {
      var c = ca[i];
      while (c.charAt(0)==' ') c = c.substring(1,c.length);
      if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
    }
  return null;
};

function eraseCookie(name)
{
  createCookie(name,"",-1);
};


// options

// if there's no cookie, this should expand to something like
// if (window.foo===null) window.foo=window.dfoo;
function defaultize(x) {
  var val=null;
  var a='window.'+x;
  var b='window.d'+x;
  if (x!='popupCookies') {
    defaultize('popupCookies');
    if (popupCookies && (val=readCookie(x))) {
      window[x]=val;
      return;
    }
  }
  if (window[x]===null) window[x]=window['d'+x];
};

// this should expand to something like
// if (typeof window.foo=='undefined') { window.foo=null; }; window.dfoo = 0.5;
function newOption(x, def) {
  var a='window.'  + x;
  var b='window.d' + x;
  if (typeof window[x]=='undefined') { window[x]=null; }; window['d'+x]=def;
};

function getValueOf(varName) {defaultize(varName); return window[varName];};

// user-settable parameters and defaults
// names beginning with a d are probably a bad idea!
// NB strings must NO LONGER be "'double-quoted'"
newOption('popupDelay', 0.5);
newOption('removeTitles', true);
newOption('imagePopupsForImages', true);
newOption('popupSummaryData', true);
newOption('simplePopups',  false);
newOption('popupAdminLinks',  false);
newOption('popupImages', true);
newOption('popupPreviews', true);
newOption('popupMaxPreviewSentences', 4);
newOption('popupMaxPreviewCharacters', 600);
newOption('popupNavLinks', true);
newOption('popupNavLinkSeparator', ' &sdot; ');
newOption('popupOnlyArticleLinks', true);
newOption('popupNeverGetThumbs', false);
newOption('popupImagesFromThisWikiOnly', false);
newOption('popupAppendRedirNavLinks', true);
newOption('popupMaxWidth', 300);
newOption('popupSimplifyMainLink', true);
newOption('popupMinImageWidth', 50);
newOption('popupLastEditLink', true);
newOption('popupHistoricalLinks', true);
newOption('popupFixRedirs', false);
newOption('popupLiveOptions', false);
newOption('popupCookies', false);
newOption('popupUnsimplifyLink', false);
newOption('popupLoadImagesSequentially', false);
newOption('popupShortcutKeys', false);
newOption('popupLiveOptionsExpanded', false);
newOption('popupFixDabs', false);
newOption('popupImagesToggleSize',true);
newOption('popupNewWindows', false);
// see later - default for popupStructure is 'original' if simplePopups is true
newOption('popupStructure', 'menus'); 
newOption('popupInitialWidth', false); // integer or false
newOption('popupNavLinkStyle', 'default');
newOption('popupDragging', true); 
newOption('popupLastModified', true);
newOption('popupActionsMenu', true);
newOption('popupFixDabsSummary', popupString('defaultpopupFixDabsSummary') );
newOption('popupRevertSummary',  popupString('defaultpopupRevertSummary') );
newOption('popupFixRedirsSummary', popupString('defaultpopupFixRedirsSummary') );
newOption('popupRmDabLinkSummary', popupString('defaultpopupRmDabLinkSummary') );
newOption('popupPreviewKillTemplates', true);
newOption('popupPreviewRawTemplates', false);
newOption('popupRevertSummaryPrompt', false); // not yet implemented
newOption('popupExtraUserMenu', '');
newOption('popupRedirAutoClick', 'wpSave');
newOption('popupEditCounterTool', 'interiot');
newOption('popupPreviewFirstParOnly', true);
newOption('popupLinksNewWindow', {'lastContrib': true, 'sinceMe': true});
newOption('popupDiffMaxLines', 100);
newOption('popupDiffContextLines', 2);
newOption('popupDiffContextCharacters', 40);
newOption('popupRevertSummaryPrompt', false);

// browser-specific hacks

if (typeof window.opera != 'undefined') {
  dpopupStructure='original';
} else if ((self.navigator.appName)=='Konqueror') {
  dpopupNavLinkSeparator=' &bull; ';
} else if ((self.navigator.appName).indexOf("Microsoft")!=-1) {
  dpopupNavLinkSeparator=' &#183; ';
  dpopupStructure='original';
  window.popups_isIE=true;
}
// IE madness with encoding
// ========================
// 
// suppose throughout that the page is in utf8, like Wikinews
// 
// if a is an anchor DOM element and a.href should consist of
// 
// http://host.name.here/wiki/foo?bar=baz
// 
// then IE gives foo as "latin1-encoded" utf8; we have foo = decode_utf8(decodeURI(foo_ie))
// but IE gives bar=baz correctly as plain utf8
// 
// ---------------------------------
// 
// IE's xmlhttp doesn't understand utf8 urls. Have to use encodeURI here.
// 
// ---------------------------------
// 
// summat else


// String.prototype.parenSplit should do what ECMAscript says 
// String.prototype.split does, interspersing paren matches between
// the split elements

if (String('abc'.split(/(b)/))!='a,b,c') {
  // broken String.split, e.g. konq, IE
  String.prototype.parenSplit=function (re) {
    re=nonGlobalRegex(re);
    var s=this;
    var m=re.exec(s);
    var ret=[];
    while (m && s) {
      // without the following loop, we have 
      // 'ab'.parenSplit(/a|(b)/) != 'ab'.split(/a|(b)/)
      for(var i=0; i<m.length; ++i) {
        if (typeof m[i]=='undefined') m[i]='';
      }
      ret.push(s.substring(0,m.index));
      ret = ret.concat(m.slice(1));
      s=s.substring(m.index + m[0].length);
      m=re.exec(s);
    }
    ret.push(s);
    return ret;
  };
} else {
  String.prototype.parenSplit=function (re) {return this.split(re);};
}
function nonGlobalRegex(re) {
  var s=re.toString();
  flags='';
  for (var j=s.length; s.charAt(j) != '/'; --j) {
    if (s.charAt(j) != 'g') flags += s.charAt(j);
  }
  var t=s.substring(1,j);
  return RegExp(t,flags);
}

/////////////////////
// HTML GENERATION //
/////////////////////

// generate html for popup image
// <a id="popupImageLinkn"><img id="popupImagen">
// where n=popupIdNumber
function imageHTML(article) {
  var ret='';
  ret += '<a id="popupImageLink' + popupIdNumber + '">';
  ret += '<img align="right" valign="top" id="popupImg' + popupIdNumber + '" ' 
    + 'style="display: none;"></img>';
  ret += '</a>';
  return ret;
};

function isInToc(a) { return isSubElementOf(a,'toc'); };

function isInArticle(a) { 
  // content is for monobook.. damn. was hoping to avoid Wikinews skin references
  if (document.getElementById('article')) return isSubElementOf(a, 'article');
  else return isSubElementOf(a, 'content');
};

function isSubElementOf(a, tag) {
  var obj = a;
  var i=0;
  // this may well slow things down when this function is iterated
  // would perhaps be more efficient to cache this result before the 
  // function is called. or maybe the browser does that magically anyway
  var tagged=document.getElementById(tag);
  if (!tagged) return false;

  do {obj = obj.parentNode; ++i; }
  while (obj != tagged && obj.nodeName != 'HTML');

  if (obj.nodeName == 'HTML') return false;
  return true;
};

// Source: http://aktuell.de.selfhtml.org/artikel/javascript/utf8b64/utf8.htm
function encode_utf8(rohtext) {
  // dient der Normalisierung des Zeilenumbruchs
  rohtext = rohtext.replace(/\r\n/g,"\n");
  var utftext = "";
  for(var n=0; n<rohtext.length; n++)
    {
      // ermitteln des Unicodes des  aktuellen Zeichens
      var c=rohtext.charCodeAt(n);
      // alle Zeichen von 0-127 => 1byte
      if (c<128)
        utftext += String.fromCharCode(c);
      // alle Zeichen von 127 bis 2047 => 2byte
      else if((c>127) && (c<2048)) {
        utftext += String.fromCharCode((c>>6)|192);
        utftext += String.fromCharCode((c&63)|128);}
      // alle Zeichen von 2048 bis 66536 => 3byte
      else {
        utftext += String.fromCharCode((c>>12)|224);
        utftext += String.fromCharCode(((c>>6)&63)|128);
        utftext += String.fromCharCode((c&63)|128);}
    }
  return utftext;
}

function decode_utf8(utftext) {
  var plaintext = ""; var i=0; var c=c1=c2=0;
  // while-Schleife, weil einige Zeichen uebersprungen werden
  while(i<utftext.length)
    {
      c = utftext.charCodeAt(i);
      if (c<128) {
        plaintext += String.fromCharCode(c);
        i++;}
      else if((c>191) && (c<224)) {
        c2 = utftext.charCodeAt(i+1);
        plaintext += String.fromCharCode(((c&31)<<6) | (c2&63));
        i+=2;}
      else {
        c2 = utftext.charCodeAt(i+1); c3 = utftext.charCodeAt(i+2);
        plaintext += String.fromCharCode(((c&15)<<12) | ((c2&63)<<6) | (c3&63));
        i+=3;}
    }
  return plaintext;
}


function articleFromURL(h) {
  if (typeof h != 'string') h=String(h);
  if (window.popups_isIE) { 
    // IE is stupid, basically. it doesn't "get" this new-fangled utf-8 thing
	// no, wait. it's worse than that
	// IE seems to treat the query string differently to the rest of the url
	// the query is treated as bona-fide utf8, but the first bit of the url is pissed around with
    var splitted=h.split('?');
	h=decode_utf8(decodeURI(splitted[0]));
	if (splitted.length>1) { 
	  splitted[0]='';
	  var query=splitted.join('?');
	  h+=decodeURI(query);
	}
  } 
  else h=decodeURI(h);

  var article=null;

  var contribs=contributions.exec(h);
  if (contribs != null) { article=popUserNamespace+':'+contribs[3];  return article;  } 
  
  var email=emailuser.exec(h);
  if (email != null) { article=popUserNamespace+':'+email[3]; return article;  } 

  // no more special cases to check --
  // hopefully it's not a disguised user-related page

  var m=re.exec(h);
  if(m===null) return null;
  article=m[2];
  return article;
};

function articleFromAnchor(a) {return articleFromURL(a.href);}
function oldidFromAnchor(a) { var m=oldidRegex.exec(a.href); if (m) return m[1]; return null; }
function diffFromAnchor(a) { var m=diffRegex.exec(a.href); if (m) return m[1]; return null; }

function fillEmptySpans(args) { return fillEmptySpans2(args); }

function fillEmptySpans2(args) { // if redir is present and true then redirTarget is mandatory
  var redir=true;
  if (typeof args != 'object' || typeof args.redir == undef || !args.redir) redir=false;
  var a=window.currentLink;
  log('fillEmptySpans: a='+a+', window.currentLink='+window.currentLink);
  if (!a) { log('*****\nfillEmptySpans: a is no good\n*****'); return; }
  
  var article, hint, oldid;
  if (redir && typeof args.redirTarget == typeof '') {
    article=args.redirTarget; hint=null;
    // Gah.
    if (window.popups_isIE) article=decodeURI(article);
  } else {
    article=articleFromAnchor(a);
    hint=a.originalTitle;
    if (hint == '' || hint == null) hint = safeDecodeURI(article);
    oldid=(getValueOf('popupHistoricalLinks'))?oldidFromAnchor(a):null;
  }
  
  log('fillEmptySpans: redir='+redir+', article='+article);
  var x={article: article,
         hint: hint,
         oldid: oldid };
  
  defaultize('popupStructure');
  var structure=window.popupStructures[popupStructure];
  if (typeof structure != 'object') {
    setPopupHTML('popupError', 'Unknown structure (this should never happen): '+ popupStructure);
    return;
  }
  var spans=flatten(window.popupLayout);
  var redirs=window.popupRedirSpans;
  log('fillEmptySpans: spans.length='+spans.length);
  for (var i=0; i<spans.length; ++i) {
    var f=findThis(redirs, spans[i]); 
    log('redir='+redir+', f='+f+', spans[i]='+spans[i]);
    if ( (f!=null && !redir) || (f==null && redir) ) {
      log('skipping this set of the loop');
      continue;
    }
    var structurefn=structure[spans[i]];
    switch (typeof structurefn) {
    case 'function':
      log('running '+spans[i]+'({article:'+x.article+', hint:'+x.hint+', oldid: '+x.oldid+'})');
      setPopupHTML(structurefn(x), spans[i]);
      break;
    case 'string':
      setPopupHTML(structurefn, spans[i]);
      break;
    default:
      log('unknown thing with label '+spans[i]);
      break;
    }
  }
};

// flatten an array
function flatten(list, start) {
  var ret=[];
  if (typeof start == undef) start=0;
  for (var i=start; i<list.length; ++i) {
    if (typeof list[i] == typeof []) {
      return ret.concat(flatten(list[i])).concat(flatten(list, i+1));
    }
    else ret.push(list[i]);
  }
  return ret;
};


window.popupStructures = new Object;

window.popupStructures.original=new Object;

window.popupStructures.original.popupLayout=function () {
  return ['popupError', 'popupImage', 'popupTopLinks', 'popupTitle', 'popupData', 'popupOtherLinks', 
          'popupRedir', ['popupWarnRedir', 'popupRedirTopLinks', 'popupRedirTitle', 'popupRedirData', 'popupRedirOtherLinks'], 
          'popupMiscTools', ['popupLiveOptions', 'popupUnsimplify'],  
          'popupPreview', 'popupFixDab'];
};
window.popupStructures.original.popupRedirSpans=function () {
  return ['popupRedir', 'popupWarnRedir', 'popupRedirTopLinks', 'popupRedirTitle', 'popupRedirData', 'popupRedirOtherLinks'];
};
window.popupStructures.original.popupTitle=function (x) {
  log ('defaultstructure.popupTitle');
  if (!getValueOf('popupNavLinks')) return navlinkStringToHTML('<b><<mainlink>></b>',x.article,x.oldid);
  return '';
};
window.popupStructures.original.popupTopLinks=function (x) {
  log ('defaultstructure.popupTopLinks');
  if (getValueOf('popupNavLinks')) return navLinksHTML(x.article, x.hint, x.oldid);
  return '';
};
window.popupStructures.original.popupImage=function(x) {
  log ('original.popupImage, x.article='+x.article+', popupIdNumber='+popupIdNumber);
  return imageHTML(x.article);
};
window.popupStructures.original.popupUnsimplify=function(x) {
  if (getValueOf('popupUnsimplifyLink')) return '<br><span onClick="javascript:popupUnsimplify()" ' 
    + 'style="cursor:pointer; border: thin dotted black" ' 
    + 'title="' +popupString('Download preview data') + '">' 
    + 'Get preview data' 
    + '</span>';
  return '';
};
window.popupStructures.original.popupRedirTitle=window.popupStructures.original.popupTitle;
window.popupStructures.original.popupRedirTopLinks=window.popupStructures.original.popupTopLinks;


var prop;

function copyStructure(oldStructure, newStructure) {
  window.popupStructures[newStructure]=new Object();
  for (var prop in window.popupStructures[oldStructure]) 
    window.popupStructures[newStructure][prop]=window.popupStructures[oldStructure][prop];
}

/** -- fancy -- **/
copyStructure('original', 'fancy');
window.popupStructures.fancy.popupTitle=function (x) {
  return navlinkStringToHTML('<font size=+0><<mainlink>></font>',x.article,x.oldid);
}; 
window.popupStructures.fancy.popupTopLinks=function(x) {
  var hist='<<history|shortcut=h|hist>>|<<lastEdit|shortcut=/|last>>if(mainspace){|<<editors|shortcut=E|eds>>}';;
  var watch='<<unwatch|unwatchShort>>|<<watch|shortcut=w|watchThingy>>';
  var move='<<move|shortcut=m|move>>';
  return navlinkStringToHTML('if(talk){' 
                            +'<<edit|shortcut=e>>|<<new|shortcut=+|+>>*' + hist + '*'
                            +'<<article|shortcut=a>>|<<editArticle|edit>>' + '*' + watch + '*' + move
                            +'}else{<<edit|shortcut=e>>*' + hist 
                            +'*<<talk|shortcut=t|>>|<<editTalk|edit>>|<<newTalk|shortcut=+|new>>'
                            +'*' + watch + '*' + move+'}<br>', x.article, x.oldid);
};
window.popupStructures.fancy.popupOtherLinks=function(x) {
  var admin='<<unprotect|unprotectShort>>|<<protect|shortcut=p>>*<<undelete|undeleteShort>>|<<delete|shortcut=d|del>>';
  var user='<<contribs|shortcut=c>>';
  if (wikimediaWiki) user+='|<<count|shortcut=#|#>>'; 
  user+='if(ipuser){|<<arin>>}else{*<<email|shortcut=E|'+
    popupString('email')+'>>}if(admin){*<<block|shortcut=b>>}';

  var normal='<<whatLinksHere|shortcut=l|links here>>*<<relatedChanges|shortcut=r|related>>';
  return navlinkStringToHTML('<br>if(user){' + user + '*}if(admin){'+admin+'if(user){<br>}else{*}}'
            +normal, x.article, x.oldid);
};
window.popupStructures.fancy.popupRedirTitle=window.popupStructures.fancy.popupTitle;
window.popupStructures.fancy.popupRedirTopLinks=window.popupStructures.fancy.popupTopLinks;
window.popupStructures.fancy.popupRedirOtherLinks=window.popupStructures.fancy.popupOtherLinks;


/** -- fancy2 -- **/
// hack for [[User:MacGyverMagic]]
copyStructure('fancy', 'fancy2');
window.popupStructures.fancy2.popupTopLinks=function(x) { // hack out the <br> at the end and put one at the beginning
  return '<br>'+window.popupStructures.fancy.popupTopLinks(x).replace(RegExp('<br>$','i'),'');
};
window.popupStructures.fancy2.popupLayout=function () { // move toplinks to after the title
  return ['popupError', 'popupImage', 'popupTitle', 'popupData', 'popupTopLinks', 'popupOtherLinks', 
          'popupRedir', ['popupWarnRedir', 'popupRedirTopLinks', 'popupRedirTitle', 'popupRedirData', 'popupRedirOtherLinks'], 
          'popupMiscTools', ['popupLiveOptions', 'popupUnsimplify'],  
          'popupPreview', 'popupFixDab'];
};

/** -- menus -- **/
copyStructure('original', 'menus');
window.popupStructures.menus.popupLayout=function () {
  return ['popupError', 'popupImage', 'popupTopLinks', 'popupTitle', 'popupOtherLinks', 
          'popupRedir', ['popupWarnRedir', 'popupRedirTopLinks', 'popupRedirTitle', 'popupRedirData', 'popupRedirOtherLinks'], 
          'popupData', 'popupMiscTools', ['popupLiveOptions', 'popupUnsimplify'],  
          'popupPreview', 'popupFixDab'];
};

window.popupStructures.menus.popupTopLinks = function (x) {
  var s='';
  var dropdiv='<div class="popup_drop">';
  var menuspan='<span class="popup_menu">';
  var enddiv='</div>';
  var endspan='</span>';
  var hist='if(mainspace){<line>}<<history|shortcut=h>>if(mainspace){|<<editors|shortcut=E>></line>}';
  var lastedit='<<lastEdit|shortcut=/|show last edit>><<lastContrib|last set of edits>><<sinceMe|changes since mine>>';
  var linkshere='<<whatLinksHere|shortcut=l|what links here>>';
  var related='<<relatedChanges|shortcut=r|related changes>>';
  var search='<<search|shortcut=s>>';
  if (wikimediaWiki) search += '|<<globalsearch|shortcut=g|global>>';
  search += '|<<google|shortcut=G|web>>';
  var watch='<<unwatch|unwatchShort>>|<<watch|shortcut=w|watchThingy>>';
  var protect='<<unprotect|unprotectShort>>|<<protect|shortcut=p>>';
  var del='<<undelete|undeleteShort>>|<<delete|shortcut=d>>';
  var move='<<move|shortcut=m|move page>>';
  if (getValueOf('popupActionsMenu')) s += '<<mainlink>>*' + dropdiv + '<a href="#">'+popupString('actions') + '</a>';
  else s+= dropdiv + '<<mainlink>>';
  s+= menuspan 
        + 'if(oldid){<line><<edit|shortcut=e>>|<<editOld|shortcut=e|this&nbsp;revision>></line>'
        + '<<revert|shortcut=v>>'
        + '}else{<<edit|shortcut=e>>}'     
        + 'if(talk){<<new|shortcut=+|new topic>>}' 
        + hist + lastedit + move 
        + linkshere + related
        + '<<nullEdit|shortcut=n|null edit>>'
        + '<line>' + search + '</line>'
        + '<hr>'
        + '<line>' + watch + '</line>'
        + 'if(admin){<line>' + protect + '</line><line>' + del + '</line>}'
        + 'if(talk){'
        + '<hr>' 
        + '<<article|shortcut=a|view article>>'
        + '<<editArticle|edit article>>'  
        + '}else{'
        + '<hr>' 
        + '<<talk|shortcut=t|talk page>>'
        + '<<editTalk|edit talk>>' 
        + '<<newTalk|shortcut=+|new topic>>' 
        + '}'
        + endspan
  + enddiv;
  s+='if(user){*' + dropdiv + '<a href="#">'+popupString('user')+'</a>' + menuspan
        + '<line><<userPage|shortcut=u|user page>>|<<userSpace|space>></line>'
        + '<<userTalk|shortcut=t|user talk>>'
        + '<<editUserTalk|edit user talk>>'
        + '<<newUserTalk|shortcut=+|leave comment>>' 
        + 'if(ipuser){<<arin>>}else{<<email|shortcut=E|email user>>}'
        + '<hr>'
        + 'if(wikimedia){<line>}' 
        + '<<contribs|shortcut=c|contributions>>' 
        + 'if(wikimedia){|<<contribsTree|tree>></line>}' 
        + '<<userlog|shortcut=L|user log>>'
        + 'if(wikimedia){<<count|shortcut=#|edit counter>>}'
        + 'if(admin){<line><<unblock|unblockShort>>|<<block|shortcut=b|block user>></line>}'
        + '<<blocklog|shortcut=B|block log>>'
        + getValueOf('popupExtraUserMenu')
        + endspan 
        + enddiv
        + '}';
  return navlinkStringToHTML(s, x.article, x.oldid);
};

window.popupStructures.menus.popupRedirTitle=window.popupStructures.menus.popupTitle;
window.popupStructures.menus.popupRedirTopLinks=window.popupStructures.menus.popupTopLinks;

// Generate html for whole popup
function popupHTML (a) {
  defaultize('popupStructure');
  var structure=window.popupStructures[popupStructure];
  if (typeof structure != 'object') return 'Unknown structure: '+popupStructure +
                                      ( RegExp('^[\'"]').test(popupStructure) ? '<p>There has been a breaking change - please do not<br>' +
                                        ' quote strings in options like popupStructure twice any longer<br> in your user javascript file.' : '');
  if (typeof structure.popupLayout != 'function') return 'Bad layout';
  window.popupLayout=structure.popupLayout();
  if (typeof structure.popupRedirSpans == 'function') window.popupRedirSpans=structure.popupRedirSpans();
  else window.popupRedirSpans=[];
  return makeEmptySpans(window.popupLayout);
}; 

function makeEmptySpans (list) {
  var ret='';
  for (var i=0; i<list.length; ++i) {
    if (typeof list[i] == typeof '')
      ret += emptySpanHTML(list[i], popupIdNumber);
    else if (typeof list[i] == typeof [] ) {
      ret = ret.substring(0,ret.length-'</span>'.length) + makeEmptySpans(list[i]) + '</span>';
    }
  }
  return ret;
};

function popupUnsimplify() {};

function isIpUser(user) {return ipUserRegex.test(user);};

function popupToggleVar(varstring) {
  defaultize(varstring);
  window[varstring] = !window[varstring];
  defaultize('popupCookies');
  if (popupCookies) createCookie(varstring, String(window[varstring]));
};

function popupToggleShowOptions (dummy) {
  // just update state if dummy is true
  defaultize('popupLiveOptionsExpanded');
  if (!dummy) window.popupLiveOptionsExpanded=!window.popupLiveOptionsExpanded;
  setPopupHTML((window.popupLiveOptionsExpanded) ? '&lt;&lt;' : '&gt;&gt;',
               'optionPopped');
  var s=document.getElementById('popupOptionsDiv');
  // if (!s) return;
  if (window.popupLiveOptionsExpanded) s.style.display='inline';
  else s.style.display='none';
};

function popupOptionsCheckboxHTML(varstring, label, title) {
  var html='<br>';
  html += '<span title="'+title+'">';
  html += '<input type="checkbox" id="'+varstring+'Checkbox" ';
  html += (window[varstring]) ? 'checked="checked" ' : '';
  html += 'onClick="javascript:popupToggleVar(' + "'" + varstring + "'" + 
    ')">' + label + '</input></span>';
  return html;
};

function popupLiveOptionsHTML() {
  var html = '';
  html += '<br>';
  html += '<span title="' + popupString('Show/hide options') + '" ';
  html += 'style="border: thin dotted black; cursor: pointer" ';
  html += 'onClick="javascript:popupToggleShowOptions()">';
  html += 'Options <span id="optionPopped' + popupIdNumber + '"></span>';
  html += '</span>';
  html += '<div style="display: none" id="popupOptionsDiv">';
  html += popupOptionsCheckboxHTML('simplePopups', popupString('Simple popups'), 
               popupString('Never download extra stuff for images/previews'));
  html += popupOptionsCheckboxHTML('popupUnsimplifyLink', popupString('Preview only on click'), 
               popupString('Only start downloading when told to do so'));
  //html += popupOptionsCheckboxHTML('popupCookies', popupString('cookies'), 
  //             popupString('Use cookies to store popups options'));
  html += popupOptionsCheckboxHTML('popupNavLinks', popupString('Show navigation links'), 
               popupString('Display navigation links at the top of the popup'));
  html += popupOptionsCheckboxHTML('popupImages', popupString('Show image previews'), 
               popupString('Load images'));
  html += popupOptionsCheckboxHTML('popupSummaryData', popupString('Show summary data'), 
               popupString('Show page summary data'));
  html += popupOptionsCheckboxHTML('popupPreviews', popupString('Show text previews'), 
               popupString('Show previews'));
    
  var extraOptions=[
                    'imagePopupsForImages',
                    'popupAdminLinks',
                    'popupAppendRedirNavLinks',
                    'popupCookies',
                    'popupFixDabs',
                    'popupFixRedirs',
                    'popupHistoricalLinks',
                    'popupImagesFromThisWikiOnly',
                    'popupImagesToggleSize',
                    'popupLastEditLink',
                    'popupLiveOptions',
                    'popupLoadImagesSequentially',
                    'popupNeverGetThumbs',
                    'popupOnlyArticleLinks',
                    'popupPreviewKillTemplates',
                    'popupPreviewFirstParOnly',
                    'popupShortcutKeys',
                    'popupSimplifyMainLink',
                    'removeTitles' // no ,
  ];
  for (var i=0; i<extraOptions.length; ++i) {
    html += popupOptionsCheckboxHTML(extraOptions[i], extraOptions[i], popupString('Toggle this option'));
  }
  
  html += '</div>';
  return html;
};

function emptySpanHTML(name, id) {return '<span id="' + name + id + '"></span>';};

function addLinkProperty(html, property) {
  // take "<a href=...>...</a> and add a property
  // not sophisticated at all, easily broken
  var i=html.indexOf('>');
  if (i<0) return html;
  return html.substring(0,i) + ' ' + property + html.substring(i);
};

function addPopupShortcut(html, key) {
  if (!getValueOf('popupShortcutKeys')) return html;
  var ret= addLinkProperty(html, 'popupkey="'+key+'"');
  if (key==' ') key=popupString('spacebar');
  return ret.replace(RegExp('^(.*?)(title=")(.*?)(".*)$', 'i'),'$1$2$3 ['+key+']$4');
};

function defaultNavlinkSpec() {
  var str='';
  str += '<b><<mainlink|shortcut= >></b>';
  if (getValueOf('popupLastEditLink')) str += '*<<lastEdit|shortcut=/>>|<<lastContrib>>|<<sinceMe>>if(oldid){|<<oldEdit>>|<<diffCur>>}';
  str+='<<imagestatus>>';
  
  // user links
  // contribs - log - count - email - block
  // count only if applicable; block only if popupAdminLinks
  str += 'if(user){<br><<contribs|shortcut=c>>*<<userlog|shortcut=L|log>>';
  str+='if(ipuser){*<<arin>>}if(wikimedia){*<<count|shortcut=#>>}';
  str+='if(ipuser){}else{*<<email|shortcut=E>>}if(admin){*<<block|shortcut=b>>}}';
  
  // editing links
  // talkpage   -> edit|new - history - un|watch - article|edit 
  // other page -> edit - history - un|watch - talk|edit|new
  var editstr='<<edit|shortcut=e>>';
  var editOldidStr='if(oldid){<<editOld|shortcut=e>>|<<revert|shortcut=v|rv>>|<<edit|cur>>}else{' + editstr + '}'
  var historystr='<<history|shortcut=h>>if(mainspace){|<<editors|shortcut=E|>>}';
  var watchstr='<<unwatch|unwatchShort>>|<<watch|shortcut=w|watchThingy>>';

  str+='<br>if(talk){' + 
    editOldidStr+'|<<new|shortcut=+>>' + '*' + historystr+'*'+watchstr + '*' + '<b><<article|shortcut=a>></b>|<<editArticle|edit>>'
    + '}else{' // not a talk page
    + editOldidStr + '*' + historystr + '*' + watchstr + '*' + '<b><<talk|shortcut=t>></b>|<<editTalk|edit>>|<<newTalk|shortcut=+|new>>'
    + '}';
  
  // misc links
  str += '<br><<whatLinksHere|shortcut=l>>*<<relatedChanges|shortcut=r>>*<<move|shortcut=m>>';

  // admin links
  str += 'if(admin){<br><<unprotect|unprotectShort>>|<<protect|shortcut=p>>*' + '<<undelete|undeleteShort>>|<<delete|shortcut=d>>}';
  return str;
};

function navLinksHTML (article, hint, oldid) {
  //  defaultize('popupNavLinkSeparator');
  var str = '<span class="popupNavLinks">';
  var style=getValueOf('popupNavLinkStyle');
  switch (style) {
  case 'default':
    str += defaultNavlinkSpec();
    break;
  default:
    if (typeof style == 'function') str += style();
    else str+=String(style);
  }
  str += '</span>';

  // BAM
  return navlinkStringToHTML(str, article, oldid);
};

function reportErrorHTML(err) {
  return 'Error: '+err+ ' Please <a href="' + 
    '//en.wikipedia.org/wiki/User_talk:Lupin?action=edit&section=new' + 
    '">report this</a>!';
};

function expandConditionalNavlinkString(s,article,oldid,recursionCount) {
  // nested conditionals (up to 10 deep) are ok, hopefully! (work from the inside out)
  if (typeof recursionCount!=typeof 0) recursionCount=0;
  var conditionalSplitRegex=RegExp(
    '(;?\\s*if\\s*\\(\\s*([a-z]*)\\s*\\)\\s*\\{([^{}]*)\\}(\\s*else\\s*\\{([^{}]*?)\\}|))', 'i');
  var splitted=s.parenSplit(conditionalSplitRegex);
  // $1: whole conditional
  // $2: user|talk
  // $3: true expansion
  // $4: else clause (possibly empty)
  // $5: false expansion (possibly null)
  var numParens=5;
  ret = splitted[0];
  for (var i=1; i<splitted.length; i=i+numParens+1) {
    
    var testString=splitted[i+2-1];
    var trueString=splitted[i+3-1];
    var falseString=splitted[i+5-1];
    if (typeof falseString==undef || !falseString) falseString='';
    var testResult=null;

    switch (testString) {
    case 'user':
      testResult=(userName(article))?true:false;
      break;
    case 'talk':
      testResult=(talkPage(article))?false:true; // talkPage converts _articles_ to talkPages
      break;
    case 'admin':
      testResult=getValueOf('popupAdminLinks')?true:false;
      break;
    case 'oldid':
      testResult=(typeof oldid != undef && oldid)?true:false;
      break;
    case 'ipuser':
      testResult=(isIpUser(userName(article)))?true:false;
      break;
    case 'mainspace':
      testResult=isInMainNamespace(article);
      break;
    case 'wikimedia':
      testResult=(wikimediaWiki) ? true : false;
      break;
    }

    switch(testResult) {
    case null: ret+=splitted[i];  break;
    case true: ret+=trueString;   break;
    case false: ret+=falseString; break;
    }

    
    // append non-conditional string 
    ret += splitted[i+numParens];
  }
  if (conditionalSplitRegex.test(ret) && recursionCount < 10) 
    return expandConditionalNavlinkString(ret,article,oldid,recursionCount+1);
  else return ret;
};

function navlinkStringToArray(s, article, oldid) {
  s=expandConditionalNavlinkString(s,article,oldid);
  var splitted=s.parenSplit(RegExp('<<(.*?)>>'));
  var ret=[];
  for (var i=0; i<splitted.length; ++i) {
    if (i%2) { // i odd, so s is a tag
      var t=new navlinkTag();
      var ss=splitted[i].split('|');
      t.id=ss[0];
      for (var j=1; j<ss.length; ++j) {
        var sss=ss[j].split('=');
        if (sss.length>1)
          t[sss[0]]=sss[1];
        else // no assignment (no "="), so treat this as a title (overwriting the last one)
          t.text=popupString(sss[0]);
      }
      t.article=article;
      if (typeof oldid != undef && oldid != null) t.oldid=oldid;
      if (!t.text && t.id != 'mainlink') t.text=popupString(t.id);
      ret.push(t);
    }
    else { // plain HTML
      ret.push(splitted[i].split('*').join(getValueOf('popupNavLinkSeparator'))
               .split('<line>').join('<span class="popup_menu_row">').split('</line>').join('</span>'));
    }
  }
  return ret;
};

// navlinkString: * becomes the separator
//                <<foo|bar=baz|fubar>> becomes a foo-link with attribute bar='baz'
//                                      and visible text 'fubar'
//                if(test){...} and if(test){...}else{...} work too (nested ok)

function navlinkStringToHTML(s,article,oldid) {
  var p=navlinkStringToArray(s,article,oldid);
  var html='';
  for (var i=0; i<p.length; ++i) {
    if (typeof p[i] == typeof '') {
      html+=p[i];
    } else if (typeof p[i].type != undef && p[i].type=='navlinkTag') {
      html+=p[i].html();
    }
  }
  return html;
}

function navlinkTag() {this.type='navlinkTag';};

navlinkTag.prototype.html=function () {
  this.getNewWin();
  this.getPrintFunction();
  var html='';
  if (typeof this.print!='function') {
    log ('Oh dear - invalid print function for a navlinkTag, id='+this.id);
  } else {
    html=this.print(this);
    if (typeof html != typeof '') {html='';}
    else if (typeof this.shortcut!=undef) html=addPopupShortcut(html, this.shortcut);
  }
  return '<span class="popup_'+this.id+'">'+html+'</span>';
};

navlinkTag.prototype.getNewWin=function() {
  getValueOf('popupLinksNewWindow');
  if (typeof popupLinksNewWindow[this.id] === undef) this.newWin=null;
  this.newWin=popupLinksNewWindow[this.id];
}

navlinkTag.prototype.getPrintFunction=function() { //think about this some more
  // this.id and this.article should already be defined
  if (typeof this.id!=typeof '' || typeof this.article!=typeof'') return;
  var html='';
  var a,t;

  switch (this.id) {
  case 'email':     case 'contribs':  case 'block':     case 'unblock':
  case 'userlog':   case 'blocklog':  case 'userSpace':
    this.article=userName(this.article);
  }

  switch (this.id) {
    case 'blocklog': this.article=popUserNamespace+':'+this.article;
    break;
  }
  
  switch (this.id) {
  case 'userTalk': case 'newUserTalk': case 'editUserTalk':
  case 'userPage': case 'monobook': case 'editMonobook':
    delete this.oldid;
    this.article=popUserNamespace+':'+userName(this.article);
  }
  
  if (this.id=='editMonobook' || this.id=='monobook') { this.article+='/monobook.js'; }

  if (this.id != 'mainlink') {
    this.article=removeAnchor(this.article);
    // if (typeof this.text==undef) this.text=popupString(this.id);
  }

  switch (this.id) {
  case 'undelete':       this.print=specialLink; this.specialpage='Undelete'; this.sep='/'; break;
  case 'whatLinksHere':  this.print=specialLink; this.specialpage='Whatlinkshere'; break;
  case 'relatedChanges': this.print=specialLink; this.specialpage='Recentchangeslinked'; break;
  case 'move':           this.print=specialLink; this.specialpage='Movepage'; break;

  case 'contribs':       this.print=specialLink; this.specialpage='Contributions'; break;
  case 'email':          this.print=specialLink; this.specialpage='Emailuser'; break;
  case 'block':          this.print=specialLink; this.specialpage='Blockip'; this.sep='&ip='; break;
  case 'unblock':        this.print=specialLink; this.specialpage='Ipblocklist'; this.sep='&action=unblock&ip='; break;
  case 'userlog':        this.print=specialLink; this.specialpage='Log'; this.sep='&user='; break;
  case 'blocklog':       this.print=specialLink; this.specialpage='Log'; this.sep='&type=block&page='; break;
  case 'userSpace':      this.print=specialLink; this.specialpage='Prefixindex'; this.sep='&namespace=2&from='; break;
  case 'search':         this.print=specialLink; this.specialpage='Search'; this.sep='&fulltext=Search&search='; break;
  case 'history': case 'unwatch': case 'watch':
  case 'unprotect': case 'protect': 
    this.print=wikiLink; this.action=this.id; break;

  case 'delete':
    this.print=wikiLink; this.action='delete';
    if (isImagePage(this.article)) {
      var img=stripNamespace(this.article);
      this.action+='&image='+img;
    }
  break;

  case 'edit': case 'view':
    this.print=wikiLink;
    delete this.oldid;
    this.action=this.id; break;
  case 'new':
    this.print=wikiLink; this.action='edit&section=new'; break;
  case 'mainlink':
    if (typeof this.text==undef) this.text=safeDecodeURI(this.article);
    if (getValueOf('popupSimplifyMainLink') && isInStrippableNamespace(this.article)) { 
      var s=this.text.split('/'); this.text=s[s.length-1]; 
      if (this.text=='' && s.length > 1) this.text=s[s.length-2];
    }
    this.print=titledWikiLink;
    if (typeof this.title==undef && window.currentLink && typeof window.currentLink.href != undef) { 
      this.title=safeDecodeURI((window.currentLink.originalTitle)?window.currentLink.originalTitle:this.article);
      if (typeof this.oldid != undef && this.oldid) this.title='Revision ' + this.oldid + ' of ' + this.title;
    }
    this.action='view'; break;
  case 'userPage':
  case 'article': 
  case 'monobook':
    a=articleFromTalkPage(this.article); if (a) { this.article=a; delete this.oldid; }
    this.print=wikiLink;
    this.action='view'; break;
  case 'editMonobook':
  case 'editArticle': 
    a=articleFromTalkPage(this.article); if (a) { this.article=a; delete this.oldid; }
    this.print=wikiLink;
    this.action='edit'; break;
  case 'userTalk':
  case 'talk':
    t=talkPage(this.article); if(t) { this.article=t; delete this.oldid; }
    this.print=wikiLink; 
    this.action='view'; break;
  case 'arin':
    this.print=arinLink; break;
  case 'count':
    this.print=kateLink; break;
  case 'google':
    this.print=googleLink; break;
  case 'contribsTree':
    this.print=contribsTreeLink; break
  case 'editors':
    this.print=editorListLink; break;
  case 'globalsearch':
    this.print=globalSearchLink; break;
  case 'lastEdit':
    this.print=titledDiffLink;
    this.title=popupString('Show the last edit');
    this.from='prev'; this.to='cur'; break;
  case 'oldEdit':
    this.print=titledDiffLink;
    this.title=popupString('Show the edit made to get revision') + ' ' + this.oldid;
    this.from='prev'; this.to=this.oldid; break;
  case 'editOld':
    this.print=wikiLink; this.action='edit'; break;
  case 'revert':
    this.print=wikiLink; this.action='revert'; break;
  case 'nullEdit':
    this.print=wikiLink; this.action='nullEdit'; break;
  case 'diffCur':
    this.print=titledDiffLink;
    this.title=tprintf('Show changes since revision %s', [this.oldid]);
    this.from=this.oldid; this.to='cur'; break;
  case 'editUserTalk':
  case 'editTalk':
    t=talkPage(this.article); if (t) { this.article=t; delete this.oldid; }
    this.action='edit'; this.print=wikiLink; break;
  case 'newUserTalk':
  case 'newTalk':
    t=talkPage(this.article); if (t) { this.article=t; delete this.oldid; }
    this.action='edit&section=new'; this.print=wikiLink; break;
  case 'imagestatus':
    this.print=function () { return emptySpanHTML('popupImageStatus', popupIdNumber); }
    break;
  case 'lastContrib':
  case 'sinceMe':
    this.print=magicHistoryLink;
  break;
  default:
    this.print=function () {return 'Unknown navlink type: '+this.id+''};
  }
};


/////////////////
// DOWNLOADING //
/////////////////

//////////////
//
// downloader
//
//

var gDownloadsInProgress = { };

function downloader(url) {
  // Source: http://jibbering.com/2002/4/httprequest.html
  this.http = false;

  /*@cc_on @*/
  /*@if (@_jscript_version >= 5)
  // JScript gives us Conditional compilation, 
  // we can cope with old IE versions.
  // and security blocked creation of the objects.
  try {
  this.http = new ActiveXObject("Msxml2.XMLHTTP");
  } catch (e) {
  try {
  this.http = new ActiveXObject("Microsoft.XMLHTTP");
  } catch (E) {
  // this.http = false;
  }
  }
  @end @*/

  if (! this.http && typeof XMLHttpRequest!='undefined') this.http = new XMLHttpRequest();

  this.url = url; this.id=null;
  this.lastModified = null;
  this.callbackFunction = null;
};

new downloader();

downloader.prototype.send = function (x) {if (!this.http) return null; return this.http.send(x);}
downloader.prototype.abort = function () {if (!this.http) return null; return this.http.abort();}
downloader.prototype.runCallback = function () {this.callbackFunction(this);}
downloader.prototype.getData = function () {if(!this.http) return null; return this.http.responseText;}
downloader.prototype.setTarget = function () {if(!this.http) return null; this.http.open("GET", this.url, true);}
downloader.prototype.getReadyState=function () {if(!this.http) return null; return this.http.readyState;}

downloader.prototype.noCache=function () { // FIXME make date variable - "5 minutes ago" type stuff
  if(!this.http) return null; 
  try { this.http.setRequestHeader("If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT"); }
  catch (err) {};
}

downloader.prototype.start=function () {
  if(!this.http) return null;
  gDownloadsInProgress[this.id] = this;
  return this.http.send(null);
};

downloader.prototype.getLastModifiedDate=function () {
  if(!this.http) return null; 
  var lastmod=null;
  try {
    lastmod=this.http.getResponseHeader('Last-Modified'); 
  } catch (err) {}
  if (lastmod) return new Date(lastmod);
  return null;
}

downloader.prototype.setCallback = function (f) { 
  if(!this.http) return;
  this.http.onreadystatechange = f;
  this.callbackFunction = f;
};


function newDownload(url, id, callback) {
  var d=new downloader(url);
  if (!d.http) return 'ohdear';
  d.id=id;
  d.setTarget();
  var f = function () {
    if (d.getReadyState() == 4) { 
      delete gDownloadsInProgress[this.id];
      d.data=d.getData(); 
      d.lastModified=d.getLastModifiedDate();
      callback(d);
    }
  };
  d.setCallback(f);
  return d;//d.start();
};

function fakeDownload(url, id, callback, data, lastModified) {
  var d=newDownload(url,callback);
  d.id=id; d.data=data;
  d.lastModified=lastModified;
  return callback(d);
};

function startDownload(url, id, callback) {
  var d=newDownload(url, id, callback); 
  if (typeof d == typeof '' ) return d;
  return d.start();
};

function abortAllDownloads() {
  for ( var x in gDownloadsInProgress ) {
    try {
      gDownloadsInProgress[x].aborted=true;
      gDownloadsInProgress[x].abort();
      delete gDownloadsInProgress[x];
    } catch (e) { }
  }
};

//
//
// downloader
//
//////////////


window.getHistoryInfo=function(wikipage, whatNext) {
  getHistory(wikipage, whatNext ? function(d){whatNext(processHistory(d));} : processHistory);
}
window.getHistory=function(wikipage, onComplete) {
  var url = titlebase + removeAnchor(wikipage) + '&action=history';
  return startDownload(url, popupIdNumber+'history', onComplete);
}
window.processHistory=function(download) {
  // screen scrape alert
  var histInfo={};
  
  var d=download.data;
  window.d=d;

  var edits=[];
  var split=d.split('<li>');

  for (var i=0; i<split.length; ++i) {
    var match=RegExp('^[(].*?type="radio" value="([0-9]*)".*?class=\'history-user\'><a href="(/wiki/User:|/w/index.php[?]title=Special:Contributions&amp;target=)(.*?)"').exec(split[i]);
    if (match) { 
      edits.push({ oldid: match[1], editor: match[3] });
    }
  }
  histInfo.edits=edits;

  var userName=getValueOf('popupUserName') || readCookie('enwikiUserName').split('+').join('_');
  histInfo.userName=userName;

  for (var i=0; i<edits.length; ++i) {
    if (typeof histInfo.myLastEdit == 'undefined' && userName && edits[i].editor==userName) 
      histInfo.myLastEdit={index: i, oldid: edits[i].oldid, previd: (i==0 ? null : edits[i-1].oldid)} ; 
    if (typeof histInfo.firstNewEditor == 'undefined' && edits[i].editor != edits[0].editor) 
      histInfo.firstNewEditor={index:i, oldid:edits[i].oldid, previd: (i==0 ? null : edits[i-1].oldid)};
  }
  window.popupHistoryInfo=histInfo;
  return histInfo;
}

// Schematic for a getWiki call
//
//   getWiki->-getPageWithCaching
//                    |
//       false        |          true
// getPage<-[findPictureInCache]->-onComplete(a fake download)
//   \.
//     (async)->addPageToCache(download)->-onComplete(download)

function getWiki(wikipage, onComplete, oldid, randomness) {
  log('getWiki, wikipage='+wikipage);
  // set global variable (ugh) to holdwikipage
  window.currentArticle=wikipage;
  // IE needs a little help here
  // but even this is buggy :-( FIXME FIXME FIXME eg links on [[Pita Pit]]
  if (window.popups_isIE) wikipage=encodeURI(wikipage);
  // set ctype=text/css to get around opera bug
  var url = titlebase + removeAnchor(wikipage) + '&action=raw&ctype=text/css&maxage=0&smaxage=0';
  if (oldid!=null && oldid!='') url += '&oldid='+oldid;
  if (randomness) url += '&random='+Math.random();

  getPageWithCaching(url, onComplete);

};

// check cache to see if page exists

function getPageWithCaching(url, onComplete) {
  log('getPageWithCaching, url='+url);
  var i=findInPageCache(url);
  if (i > -1) return fakeDownload(url, popupIdNumber, onComplete, gCachedPages[i].data, gCachedPages[i].lastModified);
  return getPage(url, onComplete);
};

function getPage(url, onComplete) {
  log('getPage');
  var callback= function (d) { if (!d.aborted) {addPageToCache(d); onComplete(d)} };
  return startDownload(url, popupIdNumber, callback);
};

function findInPageCache(url) {
  for (var i=0; i<gCachedPages.length; ++i) if (url==gCachedPages[i].url) return i;
  return -1; 
};

function cachedPage (url, data, lastModified) {this.url=url; this.data=data; this.lastModified=lastModified};

function addPageToCache(download) {
  log('addPageToCache '+download.url);
  var page = new cachedPage(download.url, download.data, download.lastModified);
  return gCachedPages.push(page);
};


/////////////////////
// LINK GENERATION //
/////////////////////

// titledDiffLink --> titledWikiLink --> generalLink
// wikiLink       --> titledWikiLink --> generalLink
// kateLink --> generalLink

function titledDiffLink(l) { // article, text, title, from, to) {
  return titledWikiLink({article: l.article, action: l.to + '&oldid=' + l.from,
                                    newWin: l.newWin,
                                    text: l.text, title: l.title, 
                                    /* hack: no oldid here */ 
                                    actionName: 'diff'});
};


window.wikiLink=function(l) { 
  //{article:article, action:action, text:text, oldid}) {
  if (! (typeof l.article == typeof '' 
         && typeof l.action == typeof '' && typeof l.text==typeof '')) return null;
  if (typeof l.oldid == undef) l.oldid=null;
  if (l.action!='edit' && l.action!='view' && l.action != 'revert') l.oldid=null;
  var hint=popupStrings[l.action + 'Hint'];
  switch (l.action) {
  case 'edit&section=new': hint = popupString('newSectionHint');  break;
  case 'revert':
    l.action='edit&autoclick=wpSave&autosummary=' + simplePrintf(getValueOf('popupRevertSummary'), [ l.oldid ]);    
    if (getValueOf('popupRevertSummaryPrompt')) l.action += '&autosummaryprompt=true';
    break;
  case 'nullEdit':
    l.action='edit&autoclick=wpSave&autosummary=null';        
    break;
  }

  if (hint) {
    if (l.oldid) hint = simplePrintf(hint, [tprintf('revision %s of %s', [l.oldid, safeDecodeURI(l.article)])]);
    else hint = simplePrintf(hint, [safeDecodeURI(l.article)]);
  }
  else hint = safeDecodeURI(l.article + '&action=' + l.action) 
         + (l.oldid) ? '&oldid='+l.oldid : '';
  
  return titledWikiLink({article: l.article, action: l.action, text: l.text, newWin:l.newWin,
                                    title: hint, oldid: l.oldid});
};


window.undef='undefined';
window.defaultNavlinkClassname='popupNavLink';

function titledWikiLink(l) {
  // possible properties of argument:
  // article, action, text, title, oldid, actionName, className
  // oldid = null is fine here

  // article and action are mandatory args
  if (typeof l.article == undef || typeof l.action==undef) return null;
  if(window.popups_isIE) { 
    var v=encodeURI(l.article); 
    /*alert(l.article+'\n'+v);*/ 
    l.article=v;
  }
  l.article=l.article.split('&').join('%26');
  var base = titlebase +  l.article;
  var url=base;

  if (typeof l.actionName==undef || !l.actionName) l.actionName='action';
  
  // no need to add &action=view, and this confuses anchors
  if (l.action != 'view') url = base + '&' + l.actionName + '=' + l.action;

  if (typeof l.oldid!=undef && l.oldid) url+='&oldid='+l.oldid;
  
  var cssClass=defaultNavlinkClassname;
  if (typeof l.className!=undef && l.className) cssClass=l.className;
  
  return generalLink({url: url, newWin: l.newWin,
                             title: (typeof l.title != undef) ? l.title : null, 
                             className: cssClass,
                             text: (typeof l.text!=undef)?l.text:null});
};

function getLastContrib(wikipage, newWin) {
  getHistoryInfo(wikipage, function(x){processLastContribInfo(x,{page: wikipage, newWin: newWin})});
}
function processLastContribInfo(info, stuff) {
  if(!info.edits || !info.edits.length) { alert('Problem!'); return; }
  if(!info.firstNewEditor) {
    alert(tprintf('Only found one editor: %s made %s edits', [info.edits[0].editor,info.edits.length]));
    return;
  }
  var newUrl=titlebase + stuff.page + '&diff=cur&oldid='+info.firstNewEditor.oldid;
  displayUrl(newUrl, stuff.newWin);
}
function getDiffSinceMyEdit(wikipage, newWin) {
  getHistoryInfo(wikipage, function(x){processDiffSinceMyEdit(x,{page: wikipage, newWin: newWin})});
}
function processDiffSinceMyEdit(info, stuff) {
  if(!info.edits || !info.edits.length) { alert('Problem II!'); return; }
  if(!info.myLastEdit) {alert(tprintf('Couldn\'t find an edit made by %s', [info.userName])); return; }
  var newUrl=titlebase + stuff.page + '&diff=cur&oldid='+ info.myLastEdit.oldid;
  displayUrl(newUrl, stuff.newWin);
}
function displayUrl(url, newWin){
  if(newWin) window.open(url);
  else document.location=url;
}


function magicHistoryLink(l) {
  var jsUrl='', title='';
  switch(l.id) {
  case 'lastContrib':
    jsUrl=simplePrintf('javascript:getLastContrib(\'%s\', %s)', [l.article, l.newWin]);
    title=popupString('lastContribHint');
    break;
  case 'sinceMe':
    jsUrl=simplePrintf('javascript:getDiffSinceMyEdit(\'%s\', %s)', [l.article, l.newWin]);
    title=popupString('sinceMeHint');
    break;
  }

  return generalLink({url: jsUrl, newWin: false, // can't have new windows with JS links, I think
                             title: title,
                             className: defaultNavlinkClassname,
                             text: l.text});
}

function specialLink(l) {
  // properties: article, specialpage, text, sep
  if (typeof l.specialpage==undef||!l.specialpage) return null;
  var base = titlebase +  popSpecialNamespace+':'+l.specialpage;
  if (typeof l.sep == undef || l.sep===null) l.sep='&target=';
  var article=l.article;
  if(window.popups_isIE) { 
    var v=encodeURI(article); 
    article=v;
  }
  var hint=popupStrings[l.specialpage+'Hint'];
  switch (l.specialpage) {
  case 'Log': hint=(l.sep=='&user=') ? popupString('userLogHint') : popupString('blockLogHint'); break;
  case 'Search':  article=safeDecodeURI(article); break;
  }
  if (hint) hint = simplePrintf(hint, [safeDecodeURI(l.article)]);
  else hint = safeDecodeURI(l.specialpage+':'+l.article) ;

  var url = base + l.sep + article;
  return generalLink({url: url, title: hint, text: l.text, newWin:l.newWin,
                             className: 'popupNavLink'});
};

function generalLink(l) {
  // l.url, l.text, l.title, l.newWin, l.className
  
  if (typeof l.url==undef) return null;

  // only quotation marks in the url can screw us up now... I think
  var url=l.url.split('"').join('%22');

  var ret='<a href="' + url + '"';
  if (typeof l.title!=undef && l.title) ret += ' title="' + l.title + '"';
  var newWin;
  if (typeof l.newWin==undef || l.newWin===null) newWin=getValueOf('popupNewWindows'); 
  else newWin=l.newWin;
  if (newWin) ret += ' target="_blank"';
  if (typeof l.className!=undef&&l.className) ret+=' class="'+l.className+'"';
  ret += '>';
  if (typeof l.text==typeof '') ret+= l.text;
  ret +='</a>';
  return ret;
}

function literalizeRegex(str){
  return str.replace(RegExp('([-.()\\+?*^${}\\[\\]])', 'g'), '\\$1');
};

function appendParamsToLink(linkstr, params) {
  var sp=linkstr.parenSplit(RegExp('(href="[^"]+?)"', 'i'));
  if (sp.length<2) return null;
  var ret=sp.shift() + sp.shift();
  ret += '&' + params + '"';
  ret += sp.join('');
 return ret;
};

function changeLinkTargetLink(x) { // newTarget, text, hint, summary, clickButton, minor) {
  // optional: oldTarget (in wikitext)
  // if x.newTarget omitted or null, remove the link

  // escape '&' and other nasties
  if(x.newTarget) x.newTarget=encodeURI(x.newTarget);
  //x.text=encodeURI(x.text);  // this buggers things up on zh.wikipedia.org and doesn't seem necessary
  x.clickButton=encodeURI(x.clickButton);

  // this'll break if charAt(0) is nasty
  if (typeof x.oldTarget != typeof '') x.oldTarget=decodeURI(window.currentArticle);
  var cA=literalizeRegex(x.oldTarget);
  var chs=cA.charAt(0).toUpperCase();
  chs='['+chs + chs.toLowerCase()+']';
  var currentArticleRegexBit=chs+cA.substring(1);
  currentArticleRegexBit=currentArticleRegexBit
    .split(RegExp('[_ ]+', 'g')).join('[_ ]+')
    .split('\\(').join('(?:%2528|\\()')
    .split('\\)').join('(?:%2529|\\))');
  currentArticleRegexBit = '\\s*(' + currentArticleRegexBit + ')\\s*';
  // e.g. Computer (archaic) -> \s*([Cc]omputer[_ ](?:%2528|\()archaic(?:%2528|\)))\s*
      
  // autoedit=s~\[\[([Cc]ad)\]\]~[[Computer-aided%20design|$1]]~g;s~\[\[([Cc]AD)[|]~[[Computer-aided%20design|~g

  // get the page to edit from the title
  try { 
    //var title=document.getElementsByTagName('h1')[0].innerHTML.replace(RegExp(' ', 'g'), '_'); 
    var title=document.title.split(' - ');
    title[title.length-1]='';
    title=title.join(' - ').replace(/ - $/, '');
  } catch (err) { return; }

  var lk=titledWikiLink({article: title, newWin:x.newWin,
                                    action:  'edit', 
                                    text:    x.text, 
                                    title:   x.hint
                                    });
  var cmd='';
  if (x.newTarget) {
    cmd +='s~\\[\\['+currentArticleRegexBit+'\\]\\]~[['+x.newTarget+'|$1]]~g;';
    cmd +=  's~\\[\\['+currentArticleRegexBit+'[|]~[['+x.newTarget+'|~g';
  } else {
    cmd += 's~\\[\\['+currentArticleRegexBit+'\\]\\]~$1~g;';
    cmd += 's~\\[\\['+currentArticleRegexBit+'[|](.*?)\\]\\]~$2~g';
  }
  cmd += '&autoclick='+x.clickButton;
  cmd += '&autominor='+x.minor;
  cmd += '&autosummary='+x.summary;
  return appendParamsToLink(lk, 'autoedit='+cmd);
};


function redirLink(redirMatch) { 
  /* NB redirMatch is in wikiText */
  var ret='';

  if (getValueOf('popupAppendRedirNavLinks') && getValueOf('popupNavLinks')) {
    ret += '<hr>';
    if (getValueOf('popupFixRedirs') && typeof autoEdit != 'undefined' && autoEdit) {
      ret += addPopupShortcut(
                              changeLinkTargetLink({newTarget: redirMatch, text: popupString('Redirects'), hint: popupString('Fix this redirect'),
                                                   summary: simplePrintf(getValueOf('popupFixRedirsSummary'), 
                                                          [window.currentArticle.split('_').join(' '), redirMatch ]),
                                                   clickButton: getValueOf('popupRedirAutoClick'), minor: true})
                              , 'R');
      ret += popupString(' to ');
    }
    else ret += popupString('Redirects') + popupString(' to ');

    fillEmptySpans({redir: true, redirTarget: wikiMarkupToAddressFragment(redirMatch)});
    return ret;
  }
    
  else return '<br> ' + popupString('Redirects') + popupString(' to ') +
         titledWikiLink({article: myEncodeURI(redirMatch), action: 'view',  /* FIXME: newWin */
                        text: safeDecodeURI(redirMatch), title: popupString('Bypass redirect')});
};

function arinLink(l) {
  if (typeof l.article != typeof '' || typeof l.text != typeof '') return null;
  if (!isIpUser(userName(l.article)) || ! wikimediaWiki) return null;

  var uN=safeDecodeURI(userName(l.article));
  
  return generalLink({url:'http://ws.arin.net/cgi-bin/whois.pl?queryinput=' + uN, newWin:l.newWin,
                            title: tprintf('Look up %s in ARIN whois database', [uN]),
                            className: defaultNavlinkClassname,
                            text: l.text});
};

function toolDbName() {
  var ret=null;
  var theWiki=thisWiki.split('.')[1];
  switch(theWiki) {
  case 'Wikinews':
    ret = wikiLang + 'wiki';
    break;
  default:
    ret = theWiki;
    break;
  }
  ret+= '_p';
  return ret;
}

function saneLinkCheck(l) { 
  if (typeof l.article != typeof '' || typeof l.text != typeof '') return false; return true;
}
function kateLink(l) {
  if(!saneLinkCheck(l)) return null;
  if (! wikimediaWiki) return null;
  var uN=safeDecodeURI(userName(l.article));
  
  var url='http://tools.wikimedia.de/~' + getValueOf('popupEditCounterTool') + '/cgi-bin/count_edits?dbname=';
  url += toolDbName() + '&user=' + uN;

  return generalLink({url:url, title: tprintf('katelinkHint', [uN]), newWin:l.newWin, className: defaultNavlinkClassname, text: l.text});
};


function contribsTreeLink(l) {
  if(!saneLinkCheck(l)) return null;
  if (/* isIpUser(userName(l.article)) ||*/ ! wikimediaWiki) return null;
  var uN=safeDecodeURI(userName(l.article));
  
  var url='http://tools.wikimedia.de/~interiot/cgi-bin/contribution_tree?dbname=';
  url += toolDbName() + '&user='+ uN;

  return generalLink({url:url, title: tprintf('contribsTreeHint', [uN]), newWin:l.newWin, className: defaultNavlinkClassname, text: l.text});
}

function globalSearchLink(l) {
  if(!saneLinkCheck(l)) return null;

  var base='http://vs.aka-online.de/cgi-bin/globalwpsearch.pl?timeout=120&search=';
  var article=safeDecodeURI(l.article);

  return generalLink({url:base + article, newWin:l.newWin,
                            title: tprintf('globalSearchHint', [article]),
                            className: defaultNavlinkClassname,
                            text: l.text});
}

function googleLink(l) {
  if(!saneLinkCheck(l)) return null;

  var base='http://www.google.com/search?q=';
  var article=safeDecodeURI(l.article);

  return generalLink({url:base + '%22' + article + '%22', newWin:l.newWin,
                            title: tprintf('googleSearchHint', [article]),
                            className: defaultNavlinkClassname,
                            text: l.text});
}

function editorListLink(l) {
  if(!saneLinkCheck(l)) return null;
  var article= safeDecodeURI(articleFromTalkPage(l.article) || l.article);
  var base='http://tools.wikimedia.de/~tim/counter/?page=';
  return generalLink({url:base+article, title: tprintf('editorListHint', [article]), newWin:l.newWin,
                            className: defaultNavlinkClassname, text: l.text});
}

////////////////////////////
// MANIPULATION FUNCTIONS //
////////////////////////////

function upcaseFirst(str) {
  if (typeof str != typeof '' || str=='') return '';
  return str.charAt(0).toUpperCase() + str.substring(1);
};

function formatBytes(num) {return (num > 949) ? (Math.round(num/100)/10+popupString('kB')) : (num +'&nbsp;' + popupString('bytes')) ;};
function popupFilterStubDetect(data) {return (isStub(data)) ? popupString('stub') : '';};

function popupFilterDisambigDetect(data) {
  if (!isDisambig(data)) return '';
  // FIXME: this side-effect should live somewhere else
  return popupString('disambig');
};

function simplePrintf(str, subs) {
  if (!subs) return str;
  var ret=[];
  var s=str.split('%s');
  var i=0;
  do {
    if (i >= subs.length) { ret.push(s.join('%s')); break; }
    ret.push(s.shift());
    if (s.length == 0) break;
    ret.push(subs[i]);
    ++i;
  } while (s.length > 0);
  return ret.join('');
}
function tprintf(str,subs) { 
  if (typeof subs != typeof []) { subs = [subs]; }
  return simplePrintf(popupString(str), subs);
}

function listLinks(wikitext, oldTarget) {
  var reg=RegExp('\\[\\[([^|]*?)(\\||\\]\\])', 'gi');
  var ret=[];
  var splitted=wikitext.parenSplit(reg);
  // ^[a-z]+ should match interwiki links, hopefully (case-insensitive)
  // and ^[a-z]* should match those and [[:Category...]] style links too
  var omitRegex=RegExp('^[a-z]*:|^[Ss]pecial:|^[Ii]mage|^[Cc]ategory');
  var friendlyCurrentArticleName=window.currentArticle.split('_').join(' ');
  
  for (var i=1; i<splitted.length; i=i+3) {
    if (typeof splitted[i] == typeof 'string' && splitted[i].length>0 && !omitRegex.test(splitted[i])) {
      ret.push(changeLinkTargetLink({newTarget: splitted[i], 
                                    text: splitted[i].split(' ').join('&nbsp;'),
                                    hint: tprintf('disambigHint', [splitted[i]]),
                                    summary: simplePrintf(getValueOf('popupFixDabsSummary'), 
                                                          [friendlyCurrentArticleName, splitted[i] ]),
                                    clickButton: 'wpDiff', minor: true, oldTarget: oldTarget}));
    } /* if */
  } /* for loop */
  
  ret = rmDupesFromSortedList(ret.sort());
  
  ret.push(changeLinkTargetLink({ newTarget: null,
                                  text: popupString('remove this link').split(' ').join('&nbsp;'),
                                  hint: popupString("remove all links to this disambig page from this article"),
                                  clickButton: "wpDiff", oldTarget: oldTarget,
                                  summary: simplePrintf(getValueOf('popupRmDabLinkSummary'), [friendlyCurrentArticleName])}));
  return ret;

};

function rmDupesFromSortedList(list) {
  var ret=[];
  for (var i=0; i<list.length; ++i) {
    if (ret.length==0 || list[i]!=ret[ret.length-1]) ret.push(list[i]);
  }
  return ret;
};

function makeFixDab(data, oldTarget) {
  var list=listLinks(data, oldTarget);
  if (list.length==0) return null;
  var html='<hr>' + popupString('Click to disambiguate this link to:') + '<br>';
  html+=list[0];
  for (var i=1; i<list.length; ++i) html += ', '+list[i];
  return html;
};

function popupFilterPageSize(data) {return formatBytes(data.length);};
function popupFilterCountLinks(data) {
  var num=countLinks(data);return String(num) + '&nbsp;' + ((num!=1)?popupString('wikiLinks'):popupString('wikiLink'));
}

function popupFilterCountImages(data) {
  var num=countImages(data);return String(num) + '&nbsp;' + ((num!=1)?popupString('images'):popupString('image'));
}

function popupFilterCountCategories(data) {
  var num=countCategories(data); return String(num) + '&nbsp;' + ((num!=1)?popupString('categories'):popupString('category'));
}


function popupFilterLastModified(data,download) {
  var lastmod=download.lastModified;
  var now=new Date(); 
  var age=now-lastmod;
  if (lastmod && getValueOf('popupLastModified')) 
    return (formatAge(age) + ' ' + popupString('old')).replace(RegExp(' ','g'), '&nbsp;');
  //String(lastmod)
  //      .replace(RegExp('GMT[+-][0-9]+\\s*[(]([A-Z]{1,4})[)]\\s*'), '$1')
  //      .replace(RegExp('^(... ... )0'),'$1')
  //      .replace(' ','&nbsp;');
  return '';
}

function formatAge(age) {
  // coerce into a number
  var a=aa=0+age;

  var seclen=1000;
  var minlen=60*seclen;
  var hourlen=60*minlen;
  var daylen=24*hourlen;
  var weeklen=7*daylen;

  var numweeks=(a-a%weeklen)/weeklen; a=a-numweeks*weeklen; var sweeks=addunit(numweeks, 'week');
  var numdays=(a-a%daylen)/daylen;    a=a-numdays*daylen;   var sdays=addunit(numdays, 'day');
  var numhours=(a-a%hourlen)/hourlen; a=a-numhours*hourlen; var shours=addunit(numhours,'hour');
  var nummins=(a-a%minlen)/minlen;    a=a-nummins*minlen;   var smins=addunit(nummins, 'minute');
  var numsecs=(a-a%seclen)/seclen;    a=a-numsecs*seclen;   var ssecs=addunit(numsecs, 'second');

  //alert( [numdays,numhours,nummins,numsecs].join(':') );

  if (aa > 4*weeklen) return sweeks;
  if (aa > weeklen) return sweeks + ' ' + sdays;
  if (aa > daylen) return sdays + ' ' + shours;
  if (aa > 6*hourlen) return shours;
  if (aa > hourlen) return shours + ' ' + smins;
  if (aa > 10*minlen) return smins;
  if (aa > minlen) return smins + ' ' + ssecs;
  return ssecs;
}

function addunit(num,str) {
  return '' + num + ' ' + ((num!=1) ? popupString(str+'s') : popupString(str)) ;}


var popupFilters=[popupFilterStubDetect,popupFilterDisambigDetect,popupFilterPageSize,popupFilterCountLinks,
                  popupFilterCountImages,popupFilterCountCategories,popupFilterLastModified];

if (typeof extraPopupFilters=='undefined') { var extraPopupFilters=new Array(); }

function getPageInfo(data, download) {
  if (!data || data.length == 0) return popupString('Empty page');

  var pageInfoArray=new Array();
  var i,s;
  for (i=0; i<     popupFilters.length; ++i) {s=     popupFilters[i](data,download);if (s!='') pageInfoArray.push(s);}
  for (i=0; i<extraPopupFilters.length; ++i) {s=extraPopupFilters[i](data,download);if (s!='') pageInfoArray.push(s);}

  var pageInfo=pageInfoArray.join(', ');
  if (pageInfo != '' ) pageInfo = upcaseFirst(pageInfo);
  return pageInfo;
};     

function getValidImageFromWikiText(wikiText) {
  var imagePage=null;
  // nb in imageRegex we're interested in the second bracketed expression 
  // this may change if the regex changes :-(
  //var match=imageRegex.exec(wikiText);
  var matched=null;
  var match;
  defaultize('popupMinImageWidth');
  while ( match = imageRegex.exec(wikiText) ) {
    /* now find a sane image name - exclude templates by seeking { */
    var m = match[2];
    var pxWidth=match[4];
    if ( isValidImageName(m) && (!pxWidth || parseInt(pxWidth) >= popupMinImageWidth) ) { 
      matched=m; 
      break;
    }
  } 
  imageRegex.lastIndex=0;
  if (!matched) return null;
  return popImageNamespace+':'+upcaseFirst(matched);
};

// this could be improved!
function countLinks(wikiText) { return wikiText.split('[[').length - 1; };

// if N = # matches, n = # brackets, then
// String.parenSplit(regex) intersperses the N+1 split elements
// with Nn other elements. So total length is
// L= N+1 + Nn = N(n+1)+1. So N=(L-1)/(n+1).

function countImages(wikiText) {return (wikiText.parenSplit(imageRegex).length - 1) / (imageRegexBracketCount + 1);};

function countCategories(wikiText) {return (wikiText.parenSplit(categoryRegex).length - 1) / (categoryRegexBracketCount + 1); };

// returns /^(Talk|User[_ ]talk|Wikinews[_ ]talk|...):$/
function namespaceListToRegex(list) {return RegExp('^('+list.join('|').split(' ').join('[ _]')+'):');};

function talkPage(article) { // convert article to a talk page, or if we can't return null
  if (article===null) return null;
  var talkRegex=namespaceListToRegex(popTalkNamespaces);
  if (talkRegex.exec(article)) {return null;}

  var nsRegex=namespaceListToRegex(popNamespacesWithTalk);
  var splitted=article.parenSplit(nsRegex);
  if (splitted.length<2) return (popTalkNamespaces[0]+':'+article).split(' ').join('_');
  for (var i=0; i< popNamespacesWithTalk.length; ++i) {
    if (splitted[1]==popNamespacesWithTalk[i]) {
      splitted[1]=popTalkNamespaces[i];
      return splitted.join(':').substring(1).split(' ').join('_');
    }
  }
  return null;
};

function articleFromTalkPage(talkpage) {
  var talkRegex=namespaceListToRegex(popTalkNamespaces);
  var splitted=talkpage.parenSplit(talkRegex);
  if (splitted.length < 2 || splitted[0].length > 0) return null;
  if (splitted[1]==popTalkNamespaces[0]) {
    splitted[1]=''; return splitted.join(':').substring(2).split(' ').join('_');
  }
  for (var i=1; i< popTalkNamespaces.length; ++i) {
    if (splitted[1]==popTalkNamespaces[i] 
        || splitted[1]==popTalkNamespaces[i].split(' ').join('_')) {
      splitted[1]=popNamespacesWithTalk[i];
      return splitted.join(':').substring(1).split(' ').join('_');
    }
  }
  return null;
};

function userName(article) {
  if (!article) return null;
  var i=article.indexOf(popUserNamespace);
  var j=article.indexOf(':');
  if  (i != 0 || j == -1) return null;
  var k=article.indexOf('/');
  if (k==-1) return article.substring(j+1);
  else return article.substring(j+1,k);
};

function stripNamespace(article) {
  // this isn't very sophisticated 
  // it just removes everything up to the final :
  // BUG: probably does silly things for images with colons in the name - check it out
  var list = article.split(':');
  return list[list.length-1];
};

// those odd a/a5/ bits of image urls
function imagePathComponent(article) {
  var stripped=stripNamespace(article);
  var forhash=safeDecodeURI(stripped).split(' ').join('_');
  var hash=md5_hex(forhash);
  return hash.substring(0,1) + '/' + hash.substring(0,2) + '/';
};

function getImageUrlStart(wiki) { // this returns a trailing slash
  switch (wiki) {
    case 'fa.Wikinews.org':  return '//upload.wikimedia.org/Wikinews/fa/';
    case commonsWiki:         return '//upload.wikimedia.org/Wikinews/commons/';
    case 'en.wiktionary.org': return '//en.wiktionary.org/upload/en/';
    default: // unsupported - take a guess
      if (wikimediaWiki) {
        var lang=wiki.split('.')[0];
        return '//upload.wikimedia.org/Wikinews/' + lang +'/';
      }
      else /* this should work for wikicities */
        return 'http://' + wiki + '/images/';
  }
};

function imageURL(img, wiki) {
  if (getValueOf('popupImagesFromThisWikiOnly') && wiki != thisWiki) return null;
  var imgurl=null;
  if (isImage(img)) {
    var pathcpt = imagePathComponent(img);
    var stripped=stripNamespace(img);
    imgurl=getImageUrlStart(wiki) + pathcpt + stripped;
  }
  return imgurl;
};

function imageThumbURL(img, wiki, width) {
  // 
  // eg //upload.wikimedia.org/Wikinews/fa/thumb/6/61/ 
  //           Rubiks_cube_solved.jpg/120px-Rubiks_cube_solved.jpg
  //           ^^^^^^^^^^^^^^^^^^^^^^^ 
  //          wikicities omits this bit
  //  AND wikicities needs a new pathcpt for each filename including thumbs

  if (getValueOf('popupImagesFromThisWikiOnly') && wiki != thisWiki) return null;
  if (getValueOf('popupNeverGetThumbs')) return null;

  var imgurl=null;
  if (isImage(img)) {
    var stripped=stripNamespace(img);
    var pathcpt;
    if (wikimediaWiki) pathcpt = imagePathComponent(stripped);
    else pathcpt = imagePathComponent(width+'px-'+stripped);
    imgurl=getImageUrlStart(wiki) +  "thumb/" + pathcpt;
    if (wikimediaWiki) imgurl += stripped + '/';
    imgurl += width +"px-" + stripped;
  }
  return imgurl;
};


// (a) myDecodeURI (first standard decodeURI, then exceptions)
// (b) change spaces to underscores
// (c) encodeURI (just the straight one, no exceptions)

function wikiMarkupToAddressFragment (str) { // for images
  var ret = safeDecodeURI(str);
  ret = ret.split(' ').join('_');
  ret = encodeURI(ret);
  return ret;
};

function addressFragmentToWikiMarkup (str) { 
  // seemingly, not :( the inverse of wikiMarkupToAddressFragment
  return safeDecodeURI(str);
};

function myDecodeURI (str) {
  // log('myDecodeURI, str=' + str);
  var ret;
  try { ret=decodeURI(str); }
  catch (summat) { return null; }
  for (var i=0; i<decodeExtras.length; ++i) {
    var from=decodeExtras[i].from;
    var to=decodeExtras[i].to;
    ret=ret.split(from).join(to);
  }
  return ret;
};

function safeDecodeURI(str) {
  var ret=myDecodeURI(str); return ret || str;
};

function myEncodeURI (str) {
  log ('myEncodeURI: str='+str);
  var ret=str;
  ret=encodeURI(ret);
  for (var i=0; i<decodeExtras.length; ++i) {
    var from=decodeExtras[i].from;
    var to=decodeExtras[i].to;
    ret=ret.split(to).join(from);
  }
  return ret;
};

function removeAnchor(article) {
  if (!article) return null;
  // is there a #? if not, we're done
  var i=article.indexOf('#');
  if (i == -1) return article;
  return article.substring(0,i);
}
function getAnchor(article) {
  if(!article) return null;
  var i=article.indexOf('#');
  if (i == -1) return '';
  return article.substring(i+1);
}
function decodeAnchor(article) {
  var anch=getAnchor(article);
  if(!anch) return '';
  anch=anch.replace(RegExp('[.]([0-9A-F][0-9A-F])', 'g'), '%$1');
  return unescape(anch);
}

///////////
// TESTS //
///////////

function isStub(data) { return stubRegex.test(data); };
function isDisambig(data) { return talkPage(window.currentArticle) && disambigRegex.test(data); };

function isValidImageName(str){ // extend as needed...
  return ( str.indexOf('{') == -1 );
};

function isInNamespaceOrTalk(article, namespace) {
  if (!article) return false;
  if (isInNamespace(article, namespace)) return true;
  // FIXME: internationalize this
  if  (article.indexOf(namespace+'_talk:') == 0) return true;
  return false;
};

function isInNamespace(article, namespace) {
  if (!article) return false;
  var list=namespace;
  if (typeof list == typeof '') list=[list];
  for (var i=0; i<list.length; ++i) {
    if (article.indexOf(list[i]+':')==0) return true;
    // should also respect namespaces encoded with wikiMarkupToAddressFragment
    if (article.indexOf(wikiMarkupToAddressFragment(list[i]+':'))==0) return true;
  }
  return false;
};

function isInStrippableNamespace(article) {
  return isInNamespace(article, popNonArticleNamespaces);
};
function isInMainNamespace(article) {
  return !isInStrippableNamespace(article);
}

function isImage(thing)     {return isInNamespaceOrTalk(thing, popImageNamespace);};
function isImagePage(thing) {return isInNamespace      (thing, popImageNamespace);};

function isImageOk(img)
{ 
  // IE test
  if (!img.complete)
    return false;

  // gecko test
  if (typeof img.naturalWidth != "undefined" && img.naturalWidth == 0)
    return false;

  // test for konqueror and opera   

  // note that img.width must not be defined in the html with a width="..."
  // for this to work.

  // konq seems to give "broken images" width 16, presumably an icon width
  // this test would probably work in gecko too, *except for very small images*
  if (typeof img.width == 'undefined' || img.width <=  16) return false;

  // No other way of checking: assume it's ok.
  return true;
};

function anchorContainsImage(a) {
  // iterate over children of anchor a
  // see if any are images
  if (a===null) return false;
  kids=a.childNodes;
  for (var i=0; i<kids.length; ++i) if (kids[i].nodeName=='IMG') return true;
  return false;
};

/////////////
// ACTIONS //
/////////////

var imageCache = new Array ();

function loadThisImage(image) {
  if (getValueOf('popupLoadImagesSequentially')) return sequentialLoadThisImage(image);
  else return parallelLoadThisImage(image);
};

function getImageUrls(image) {
  var imageUrls=new Array();
  for (var i=0; i<imageSources.length; ++i) {
    var url;
    if (imageSources[i].thumb) 
      url=imageThumbURL(image, imageSources[i].wiki, imageSources[i].width);
    else 
      url=imageURL(image, imageSources[i].wiki);
    for (var j=0; j<gImageCache.length; ++j) {
      if (url == gImageCache[j]) {
        loadThisImageAtThisUrl(image, url);
        return null;
      }
    }
    if (url!=null) imageUrls.push(url);
  }
  return imageUrls;
};


// this is probably very wasteful indeed of bandwidth
// hey ho

function parallelLoadThisImage (image) {
  if (!popupImages) return;
  if (!isValidImageName(image)) return false;
  
  var imageUrls=getImageUrls(image);
  if (!imageUrls) return null;

  for (var i=0; i<imageUrls.length; ++i) {
    var url = imageUrls[i];
    imageArray[i]=new Image();
    imageArray[i].src=url;
  }
  if (popupImageTimer != null) {
    clearInterval(popupImageTimer);
    counter=0;
  }
  gImage=image;
  popupImageTimer=setInterval("checkImages()", 250);
  return true;
};

function nextOne (array, value) {
  // NB if the array has two consecutive entries equal 
  //    then this will loop on successive calls
  if (typeof array.length == 'undefined') return null;
  for (var i=0; i<array.length-1; ++i) {
    if (array[i]==value) return array[i+1];
  }
  return null;
};

function findThis(array, value) {
  if (typeof array.length == 'undefined') return null;
  for (var i=0; i<array.length; ++i) {
    if (array[i]==value) return i;
  }
  return null;
};

// global array for 404'ed image urls
var gBadImageUrls=[];

function sequentialLoadThisImage (image) {
  if (!popupImages) return false;
  if (!isValidImageName(image)) return false;

  var imageUrls=getImageUrls(image);
  if (!imageUrls) return null;

  var img=new Image();
  img.isNew=true;
  img.popupIdNumber=popupIdNumber;
  img.counter=1;

  img.onload = function () {
    // clear status thingy
    setImageStatus('');

    var i=findThis(imageUrls, this.src);
    var goodSrc=this.src;

    var setPopupImage=function () {
      var popupImage=document.getElementById("popupImage"+this.popupIdNumber);
      if (popupImage && typeof popupImage.src != 'undefined') {
        clearInterval(popupImageTimer);
        popupImage.src=goodSrc;
        popupImage.width=popupImageSize;
        popupImage.style.display='inline';
        setPopupImageLink(image, imageSources[i].wiki);
        return true;
      } else return false;
    };
    popupImageTimer=setInterval(setPopupImage, 250);
    gImageCache.push(goodSrc); 
  };
  
  img.onerror = function () {
    gBadImageUrls.push(this.src);
    // if the popup is visible, move on
    if (over && over.style.visibility=='visible' && this.popupIdNumber==popupIdNumber) this.setNext();
  };
  
  img.setNext = function () {
    var currentSrc=null;
    var newSrc;
    if (!this.isNew) currentSrc=this.src;
    this.isNew=false;
    
    newSrc= (currentSrc) ? nextOne(imageUrls, currentSrc) : imageUrls[0];

    while (findThis(gBadImageUrls, newSrc))  {
      newSrc=nextOne(imageUrls, newSrc);
      if (!newSrc) {
        setImageStatus (' :-(');
        return;
      }
    }
    setImageStatus(' '+findThis(imageUrls, newSrc));
    this.src=newSrc;
  }
  
  // start the ball rolling
  img.setNext();

};

function loadThisImageAtThisUrl(image, url) {
  log('loading "best" image:\n'+url);
  gImage=image;
  imageArray = new Array();
  imageArray[0] = new Image();
  imageArray[0].src=url;
  if (popupImageTimer != null) {
    clearInterval(popupImageTimer);
    counter=0;
  }
  popupImageTimer=setInterval("checkImages()", 250);
  return;
};

function loadImages(article) {if(! isImage(article) ) return null; return loadThisImage(article);};

// this has to use a timer loop as we don't know if the DOM element exists when we want to set the text
function setPopupHTML (str, elementId, popupId, onSuccess) {
  log('setPopupHTML, str='+str.substring(0,100)+'..., \n elementId='+elementId+', popupId='+popupId);
  if (typeof popupId === 'undefined') popupId = popupIdNumber;
  var popupElement=document.getElementById(elementId+popupId);
  var timer;

  if (typeof popupHTMLTimers[elementId] == 'undefined') timer=null;
  else timer=popupHTMLTimers[elementId];

  if (popupElement != null) {
    if(timer) clearInterval(timer);
    popupHTMLTimers[elementId]=null;
    popupElement.innerHTML=str;
    if (onSuccess) onSuccess();
    return true;
  } else {
    // call this function again in a little while...
    var loopFunction=function() { setPopupHTML(str,elementId,popupId,onSuccess);}
    popupHTMLLoopFunctions[elementId] = loopFunction;
    if (!timer) {
      var doThis = 'popupHTMLLoopFunctions["'+elementId+'"]()';
      popupHTMLTimers[elementId] = setInterval(doThis, 600);
    }
  }
  return null;
};

function setImageStatus(str, id) {return setPopupHTML(str, 'popupImageStatus', id);};
function setPopupTrailer(str,id) {return setPopupHTML(str, 'popupData', id);};

// methinks this is unbelievably silly
// it dovetails with the parallel image loader function
function checkImages() {
  log('checkImages: loopcounter='+loopcounter+'; counter='+counter);
  if (checkImagesTimer!=null) {
    clearInterval(checkImagesTimer);
    checkImagesTimer=null;
    if (loopcounter > 10); {loopcounter=0; log('too many iterations of checkImages'); return;}
    loopcounter++;
  } else counter++;

  var status =  ( counter % 2 ) ? ':' : '.' ;
  setImageStatus(status);

  if (counter > 100) {counter = 0; log ('counter too big in checkImages; returning'); clearInterval(popupImageTimer);}

  var popupImage=null;
  popupImage=document.getElementById("popupImg"+popupIdNumber);
  if (popupImage == null) {
    // this doesn't seem to happen any more in practise for some reason
    // still, I'll leave it in
    log('checkImages: document.getElementById("popupImg'+popupIdNumber+'") is null! retrying in 333ms...');
    checkImagesTimer=setInterval("checkImages()",333);
    return;
  }
  
  log('checkImages: found element popupImg'+popupIdNumber+', and src='+popupImage.src);
 
  // get the first image to successfully load
  // and put it in the popupImage
  for(var i = 0; i < imageArray.length; ++i) {
    if(isImageOk(imageArray[i])) {
      // stop all the gubbins, assign the image and return
     
      log('checkImages: got at pos '+i+', src='+imageArray[i].src);
      clearInterval(popupImageTimer);

      if(isImage(gImage)) {
        popupImage.src=imageArray[i].src;
        popupImage.width=popupImageSize;
        popupImage.style.display='inline';
        // should we check to see if it's already there? maybe...
        gImageCache.push(imageArray[i].src); 

        setPopupImageLink(gImage, imageSources[i].wiki);
        stopImagesDownloading();
      }

      setImageStatus('');

      // reset evil nonconstant globals
      delete imageArray; imageArray=new Array();
      popupImageTimer=null;

      counter=0;
      loopcounter=0;

      return popupImage.src; 
    }
  }
  log('checkImages: no good image found. retrying in a tic...');
  checkImagesTimer=setInterval("checkImages()",333);
};

function stopImagesDownloading() {
  gImage=null;
  if (imageArray == null) return null;
  var i;
  for (i=0; i<imageArray.length; ++i) {
    //imageArray[i].src=''; // this is a REALLY BAD IDEA
    delete imageArray[i];
    //imageArray[i] = new Image();
  }
  imageArray = new Array ();
  return i;
};

function toggleSize() {
  var imgContainer=this;
  if (!imgContainer) { alert('imgContainer is null :/'); return;}
  img=imgContainer.firstChild;
  if (!img) { alert('img is null :/'); return;}
  if (!img.style.width || img.style.width=='') img.style.width='100%'; 
  else img.style.width=''; // popupImageSize+'px';
};

function setPopupImageLink (img, wiki) {
  if( wiki === null || img === null ) return null;
 
  var a=document.getElementById("popupImageLink"+popupIdNumber);
  if (a === null) return null; 

  var linkURL = imageURL(img, wiki); 
  if (linkURL != null) {
    if (getValueOf('popupImagesToggleSize')) { a.onclick=toggleSize; a.title=popupString('Toggle image size'); } 
    else { a.href=linkURL; a.title=popupString('Open full-size image'); }
  }
  return linkURL;
};

var ranSetupTooltipsAlready=false;

function setupTooltips() {
  if (ranSetupTooltipsAlready) return;
  ranSetupTooltipsAlready=true;
  
  try {
    document.editform.wpTextbox1.onmouseup=function() {
      doSelectionPopup();
    }
  } catch (neverMind) {}
  
  var anchors;
  
  // article/content is a structure-dependent thing
  if (getValueOf('popupOnlyArticleLinks'))
    anchors=( document.getElementById('article') || 
              document.getElementById('content')   ).getElementsByTagName('A');
  else
    anchors=document.getElementsByTagName('A');

  setupTooltipsLoop(anchors, 0, 250, 100);
  
};


function setupTooltipsLoop(anchors,begin,howmany,sleep) {
  var finish=begin+howmany;
  for (var i=begin; i < finish && i < anchors.length; ++i) {
    var a=anchors[i];
    if (a.onclick) continue;
    var h=a.href;
    if (
        ( (re.test(h)  && !exceptions.test(h)) 
          || 
          (contributions.test(h) && h.indexOf('&limit=') == -1 ) 
        )
        && (! isInToc(a)) 
       ) {
      a.onmouseover=mouseOverWikiLink;
      a.onmouseout= mouseOutWikiLink;
      a.onclick= killPopup;
      if (getValueOf('removeTitles') && typeof a.originalTitle=='undefined') {
        a.originalTitle=a.title;
        a.title='';
      }
    }
  }
  if (finish < anchors.length) {
    popups_runOnce(function() {setupTooltipsLoop(anchors,finish,howmany,sleep);}, sleep);
  }
  else window.popupsFinishedLoading=true;
}

//////////////
// THINGIES //
//////////////

// How the URLs for images in the popup come about

//   loadPreview 
//          |                                  
//       getWiki                                
//          |<----------------see other schematic for details 
//    insertPreview      (insertPreview = onComplete)
//          |
//          |            insertPreview gets a wikiText fragment from 
//          |                       the wikiText downloaded by getWiki
//          |                                   
//  [wikiMarkupToAddressFragment]         
//       |                                      
//       |                     mouseOverWikiLink  (gets an "address fragment",       
//       |                            |            no processing needed)
//       \->-loadThisImage---<----loadImages    
//                 |                            
//           [image(Thumb)URL]-->--hopefully valid image urls


window.currentLink=null;

function popupHandleKeypress(evt) {
  var keyCode = window.event ? window.event.keyCode : ( evt.keyCode ? evt.keyCode : evt.which);
  if (!keyCode || !over) return;
  if (keyCode==27) { // escape
    killPopup();
    return false; // swallow keypress
  }

  var letter=String.fromCharCode(keyCode);
  var links=over.getElementsByTagName('A');
  var startLink=0;
  var i,j;
  
  if (window.lastPopupLinkSelected) {
    for (i=0; i<links.length; ++i) {
      if (links[i]==window.lastPopupLinkSelected) startLink=i;
    }
  }
  for (j=0; j<links.length; ++j) {
    i=(startLink + j + 1) % links.length;
    if (links[i].getAttribute('popupkey')==letter) {
      if (evt && evt.preventDefault) evt.preventDefault();
      links[i].focus();
      window.lastPopupLinkSelected=links[i];
      return false; // swallow keypress
    }
  }
  
  // pass keypress on
  if (document.oldPopupOnkeypress) return document.oldPopupOnkeypress(evt);
  else return true;  
};

function addPopupShortcuts() {
  if (document.onkeypress && document.onkeypress.toString()==popupHandleKeypress.toString()) return;
  document.oldPopupOnkeypress=document.onkeypress;
  document.onkeypress=popupHandleKeypress;
};

function rmPopupShortcuts() {
  try {
    if (document.oldPopupOnkeypress && document.oldPopupOnkeypress.toString()==popupHandleKeypress.toString()) {
      // panic
      document.onkeypress=function () {};
      return;
    }
    document.onkeypress=document.oldPopupOnkeypress;
  } catch (nasties) { /* IE goes here */ }
};

// add CSS class to table

function addPopupStylesheetClasses () {
  var tables=over.getElementsByTagName('table');
  tables[0].className='popupBorderTable';
  tables[1].className='popupTable';
  var fonts=over.getElementsByTagName('font');
  fonts[0].className='popupFont';
  fonts[0].id='overFontWrapper';
};

var alreadyRegisteredHooks=false;

function registerHooks() {
  if (window.alreadyRegisteredHooks) return;
  window.alreadyRegisteredHooks=true;
  
  defaultize('popupMaxWidth');

  if (typeof popupMaxWidth == 'number') {
    window.setmaxwidth = function () {
      over.style.maxWidth = popupMaxWidth+'px'; 
      
      // hack for IE
      // see http://www.svendtofte.com/code/max_width_in_ie/
      // who knows if this will work? not me.
      // use setExpression as documented here on msdn: http://tinyurl dot com/dqljn 
      
      // this seems to be the source of that error.... grr.....
      if (over.style.setExpression) {
        over.style.setExpression('width', 
                                 'document.body.clientWidth > '
                                 + popupMaxWidth + ' ? "' 
                                 + popupMaxWidth + 'px": "auto"');
      }
    };
    registerHook("createPopup", window.setmaxwidth, FAFTER);
  }
  
  registerHook('createPopup', window.fillEmptySpans, FAFTER);
  
  if (getValueOf('popupShortcutKeys')) {
    registerHook("createPopup", window.addPopupShortcuts, FAFTER);
    registerHook("hideObject", window.rmPopupShortcuts, FAFTER);
  }

  if (getValueOf('popupDragging')) 
    registerHook("createPopup", window.makeOverDraggable, FAFTER);

  registerHook("createPopup", window.addPopupStylesheetClasses, FAFTER);
};


function makeOverDraggable() {
  if (typeof over == undef || !over) return null;
  if (typeof over.draggable != undef && over.draggable) return null;
  Drag.originalEnd=Drag.end;
  Drag.end=function(e) { Drag.originalEnd(); olMouseMove(e); return false; }
  Drag.originalStart=Drag.start;
  Drag.start=function (e) { try { if (!e.shiftKey) return; }
                            catch (err) { return; }
                            Drag.originalStart.apply(this, [e]); 
                            return false; }
  Drag.init(over);
};

window.mouseOverWikiLink=function() {
  if (!window.popupsFinishedLoading) return;
  return mouseOverWikiLink2(this);
};

window.mouseOverWikiLink2=function(a) {
  // FIXME: should not generate the HTML until the delay has elapsed,
  //        and then popup immediately. Can be a CPU hog otherwise.
 
  log('mouseOverWikiLink: a='+a+', window.currentLink='+window.currentLink);

  // try not to duplicate effort
  if (a==window.currentLink) return;
  window.currentLink=a;

  if (typeof over != undef && over != null
      && typeof over.dragging != undef && over.dragging) return;

  // increment global counter now
  popupIdNumber++;


  if (getValueOf('simplePopups') && window.popupStructure===null) {
    // reset *default value* of popupStructure
    log ('simplePopups is true and no popupStructure selected. Defaulting to "original"');
    newOption('popupStructure', 'original');
  }

  var html = popupHTML(a);
  var article=articleFromAnchor(a); 
  var oldid=oldidFromAnchor(a);
  var diff=diffFromAnchor(a);
  if (! /^[0-9]+$/.test(diff)) {
	switch (diff) {
	case 'cur': diff=0; break;
	default: diff=null;
	}
  }

  if (popupImageTimer != null) {
    clearInterval(popupImageTimer);
    counter=0;
  }
  
  // keep this (or fix other refs)
  defaultize('popupImages');

  log('running overlib now');
  
  registerHooks();
  
  defaultize('popupInitialWidth');
  if (typeof popupInitialWidth == typeof 0) {
    overlib(html, STICKY, WIDTH, popupInitialWidth,
            CELLPAD, 5, OFFSETX, 2, OFFSETY, 2, 
            DELAY, getValueOf('popupDelay')*1000);
  } else {
    overlib(html, STICKY, WRAP, 
            CELLPAD, 5, OFFSETX, 2, OFFSETY, 2, 
            DELAY, getValueOf('popupDelay')*1000);
  }    
  
  if (typeof window.checkPopupPosition==typeof 1) clearInterval(window.checkPopupPosition);
  checkPopupPositionTimer=setInterval(checkPopupPosition, 600);

  if (getValueOf('popupLiveOptions')) {
    setPopupHTML(popupLiveOptionsHTML(), 'popupLiveOptions', popupIdNumber,
                 function () { popupToggleShowOptions(true); } );
  }

  if(getValueOf('simplePopups')) return;

  
  // dunno what this is doing here
  // FIXME: what is going on?
  // We're creating a closure with all our data in it because... we're lazy
  // this is a bad idea
  window.popupUnsimplify = function () {
    var previewImage=true;
    
    gImage=null;
    
    if (diff==null) {
      if (isImage(article) && ( getValueOf('imagePopupsForImages') || ! anchorContainsImage(a) )) {
        loadImages(article);
      }
      else if (!isImage(article) && previewImage && !diff) {
        redirCount=0;
        loadPreview(article, oldid, diff);
      }
    }
    else loadDiff(article, oldid, diff);

    var s=document.getElementById('popupUnsimplify' + popupIdNumber);
    if (s && s.style) {
      s.style.display='none';
    }
    
  };

  if (getValueOf('popupUnsimplifyLink')) return;

  window.popupUnsimplify();
}

window.getEditboxSelection=function() {
  // see http://www.webgurusforum.com/8/12/0
  try { 
    var editbox=document.editform.wpTextbox1;
  } catch (dang) { return; }
  // IE, Opera
  if (document.selection) { return document.selection.createRange().text; }
  // Mozilla
  var selStart = editbox.selectionStart;
  var selEnd = editbox.selectionEnd;
  return (editbox.value).substring(selStart, selEnd);
} 
window.doSelectionPopup=function() {
  // popup if the selection looks like [[foo|anything afterwards at all
  // or [[foo|bar]]text without ']]'
  // or [[foo|bar]]
  var sel=getEditboxSelection();
  var open=sel.indexOf('[[');  var pipe=sel.indexOf('|');  var close=sel.indexOf(']]');
  if (open == -1 || ( pipe == -1 && close == -1) ) return;
  if (pipe != -1 && open > pipe || close != -1 && open > close) return;
  var article=sel.substring(open+2, (pipe < 0) ? close : pipe);
  if (close > 0 && sel.substring(close+2).indexOf('[[') >= 0) return;
  var a=document.createElement('a');
  a.href=titlebase + article;
  mouseOverWikiLink2(a);
  runStopPopupTimer();
}

function loadPreview(article, oldid, diff) {
  getWiki(article, insertPreview, oldid);
}

function loadDiff(article, oldid, diff) {
  window.popupDiffData={};
  getWiki(article, doneDiffNew, diff);
  getWiki(article, doneDiffOld, oldid);
}

function doneDiffNew(download) {
  if (download.id != popupIdNumber) return;
  window.popupDiffData.New=download;
  if (window.popupDiffData.Old && window.popupDiffData.Old.id == popupIdNumber) insertDiff();
}

function doneDiffOld(download) {
  if (download.id != popupIdNumber) return;
  window.popupDiffData.Old=download;
  if (window.popupDiffData.New && window.popupDiffData.New.id == popupIdNumber) insertDiff();
}


window.rmBoringLines=function(a,b,context) {

  if (context == null) context=2;
  // this is fairly slow... i think it's quicker than doing a word-based diff from the off, though
  var aa=[], aaa=[];
  var bb=[], bbb=[];

  // first, gather all disconnected nodes in a and all crossing nodes in a and b
  for (var i=0; i<a.length; ++i ) {
    if(a[i].row==null) aa[i]=1;
    else if (countCrossings(b,a,i, true)) {
      aa[i]=1; 
      bb[ a[i].row ] = 1;
    }
  }

  // pick up remaining disconnected nodes in b
  for (var i=0; i<b.length; ++i ) {
    if (bb[i]==1) continue;
    if(b[i].row==null) bb[i]=1;
  }

  // another pass to gather context: we want the neighbours of included nodes which are not yet included
  // we have to add in partners of these nodes, but we don't want to add context for *those* nodes in the next pass
  for (var i=0; i<b.length; ++i) {
    if ( bb[i] == 1 ) {
      for (var j=max(0,i-context); j < min(b.length, i+context); ++j) 
        if ( bb[j] == null ) { bb[j] = 1; aa[ b[j].row ] = 0.5; }
    }
  }
  
  for (var i=0; i<a.length; ++i) {
    if ( aa[i] == 1 ) {
      for (var j=max(0,i-context); j < min(a.length, i+context); ++j) 
        if ( aa[j] == null ) { aa[j] = 1; bb[ a[j].row ] = 0.5; }
    }
  }

  for (var i=0; i<bb.length; ++i) {
    if (bb[i] > 0) { // it's a row we need
      if (b[i].row!=null) bbb.push(b[i].text); // joined; partner should be in aa
      else { 
        bbb.push(b[i]); 
      }
    }
  }
  for (var i=0; i<aa.length; ++i) {
    if (aa[i] > 0) { // it's a row we need
      if (a[i].row!=null) aaa.push(a[i].text); // joined; partner should ae in aa
      else { 
        aaa.push(a[i]); 
      }
    }
  }
  
  return { a: aaa, b: bbb};
}

window.stripOuterCommonLines=function(a,b,context) {
  var i=0;
  while (i<a.length && i < b.length && a[i]==b[i]) { ++i };
  var j=a.length-1; var k=b.length-1;
  while ( j>=0 && k>=0 && a[j]==b[k] ) { --j; --k; }
  
  return { a: a.slice(max(0,i - 1 - context), min(a.length+1, j + context+1)), 
           b: b.slice(max(0,i - 1 - context), min(b.length+1, k + context+1)) };
}

window.insertDiff=function() {
  // for speed reasons, we first do a line-based diff, discard stuff that seems boring, then do a word-based diff
  // FIXME: sometimes this gives misleading diffs as distant chunks are squashed together
  var oldlines=popupDiffData.Old.data.split('\n');
  var newlines=popupDiffData.New.data.split('\n');
  getValueOf('popupDiffContextLines');
  var inner=stripOuterCommonLines(oldlines,newlines,popupDiffContextLines);
  oldlines=inner.a; newlines=inner.b;
  var truncated=false;
  getValueOf('popupDiffMaxLines');
  if (oldlines.length > popupDiffMaxLines ||  newlines.length > popupDiffMaxLines) {
    // truncate
    truncated=true;
    var inner=stripOuterCommonLines(oldlines.slice(0,popupDiffMaxLines), newlines.slice(0,popupDiffMaxLines), popupDiffContextLines);
    oldlines=inner.a; newlines=inner.b;
  }
  
  var lineDiff=diff(oldlines, newlines);
  var lines2=rmBoringLines(lineDiff.o, lineDiff.n);
  var oldlines2=lines2.a; var newlines2=lines2.b;
    
  var html='<hr>'+shortenDiffString(diffString(oldlines2.join('\n'), newlines2.join('\n')), 
                                    getValueOf('popupDiffContextCharacters')).join('<hr>');
  setPopupHTML(html.split('\n').join('<br>') + 
               (truncated ? '<hr><b>'+popupString('Diff truncated for performance reasons')+'</b>' : '')
               , 'popupPreview');
}


function loadPreviewFromRedir(redirPage, redirMatch) {
  /* redirMatch is a regex match */
  log('loadPreviewFromRedir, redirCount='+redirCount);
  var target = redirMatch[1];
  var trailingRubbish=redirMatch[3];
  window.redirCount=window.redirCount+1;
  var warnRedir = redirLink(target);

  setPopupHTML(warnRedir, 'popupWarnRedir');

  if (!window.popups_isIE) target=myEncodeURI(target);
  return loadPreview(target);
};

// header...!___ -> ...
function extractChunk(str, header, breakChar) {
  if (str.indexOf(header) != 0) return null;
  if (!breakChar) return str.substring(header.length);
  var findChar=str.indexOf(breakChar);
  if (findChar==-1) return str.substring(header.length);
  return str.substring(header.length, findChar);
};

function urlToWikiPage (url) {
  log ('urlToWikiPage\nurl='+url);
  var urlFragment=null;
  if (!urlFragment) urlFragment=extractChunk(url, titlebase, '&');
  if (!urlFragment) urlFragment=extractChunk(url, wikibase, '?');
  if (!urlFragment) return null;
  return addressFragmentToWikiMarkup(urlFragment);
};

function makeFixDabs(wikiText, oldTarget)
{
  if (getValueOf('popupFixDabs') && isDisambig(wikiText) && 
      location.href.indexOf(popSpecialNamespace+':') == -1 &&
      talkPage(window.currentArticle)
      ) 
    setPopupHTML(makeFixDab(wikiText, oldTarget), 'popupFixDab', popupIdNumber);
}

window.insertPreview=function(download) {
  log('insertPreview, redirCount='+redirCount);
  if (download.id != popupIdNumber) {
    log ('insertPreview: download.id='+download.id+' but popupIdNumber='+popupIdNumber+'. Bailing...');
    return;
  }
  var wikiText=download.data;
  var redirectRegex=RegExp('^[ \\n]*[#]redirect[:\\s]*\\[{2}([^\\|\\]]*)(|[^\\]]*)?\\]{2}\\s*(.*)', 'i');
  var redirMatch = redirectRegex.exec(wikiText);

  var art=window.currentArticle;

  if (redirCount==0 && redirMatch) {
    window.currentRedirectionSource=window.currentArticle;
    loadPreviewFromRedir(urlToWikiPage(download.url), redirMatch);
    return;
  }

  var redirSource=window.currentRedirectionSource||'';

  if (redirCount==0) makeFixDabs(wikiText); // not a redir, so we don't have to specify an oldTarget
  else makeFixDabs(wikiText, redirSource);

  window.currentRedirectionSource=null;
  redirCount=0;

  if (getValueOf('popupSummaryData')) {
    var pgInfo=getPageInfo(wikiText, download);
    setPopupTrailer('<br>' + pgInfo);
  }


  var imagePage=getValidImageFromWikiText(wikiText);
  if(imagePage) {
    // loadThisImage expects an "address fragment"
    imagePage = wikiMarkupToAddressFragment(imagePage); 
    defaultize('popupLoadImagesSequentially');
    loadThisImage(imagePage);
  }
   
  if (getValueOf('popupPreviews')) {
    if (download && typeof download.data == typeof ''){
      if (isInNamespace(window.currentArticle, 'Template') && getValueOf('popupPreviewRawTemplates')) {
        var h='<hr><tt>'
          +download.data
          .split("&").join("&amp;")
          .split("<").join("&lt;")
          .split(">").join("&gt;")
          .split('\\n').join('<br>\\n')
          +'</tt>';
        setPopupHTML(h, 'popupPreview');
      }
      else {
        var anch=decodeAnchor(window.currentArticle);
        var d=download.data;
        if (anch) {
          var anchRe=RegExp('=+\\s*' + literalizeRegex(anch).replace(/[_ ]/g, '[_ ]') + '\\s*=+');
          var match=d.match(anchRe); 
          if(match && match.length > 0 && match[0]) d=d.substring(d.indexOf(match[0]));
          else { // try to deal with == foo [[bar|baz]] boom == -> #foo_baz_boom
            var lines=d.split('\n');
            for (var i=0; i<lines.length; ++i) {
              lines[i]=lines[i].replace(RegExp('[[]{2}([^|\\]]*?[|])?(.*?)[\\]]{2}', 'g'), '$2');
              if (lines[i].match(anchRe)) {
                d=d.split('\n').slice(i).join('\n').replace(RegExp('^[^=]*'), '');
                break;
              }
            }
          }
        }
        var p=new previewMaker(d.substring(0,10000));
        p.showPreview();
      }
    }
  }
}

var localTest=false;

function previewMaker(wikiText) {this.data=wikiText;}
previewMaker.prototype.killComments = function () {
  // this also kills trailing spaces and one trailing newline, eg [[diamyo]]
  this.data=this.data.replace(RegExp('<!--(\\n|.)*?--> *\\n?', 'g'), '');
};
previewMaker.prototype.killDivs=function () {
  // say goodbye, divs (can be nested, so use * not *?)
  this.data=this.data.replace(RegExp('< *div[^>]* *>[\\s\\S]*< */ *div *>',
                           'gi'), '');
};
previewMaker.prototype.killGalleries=function () {
  this.data=this.data.replace(RegExp('< *gallery[^>]* *>[\\s\\S]*?< */ *gallery *>',
                           'gi'), '');
};
previewMaker.prototype.killBoxTemplates=function () {
  // taxobox hack... in fact, there's a saudiprincebox_begin, so let's be more general
  this.data=this.data.replace(RegExp('[{][{][^}\\s|]*box[ _](begin|start)' +
                           '[\\s\\S]*?[^{\\s|]*box[ _](end|finish) *[}][}]', 'gi'), '');

  // infoboxes etc
  this.data=this.data.replace(RegExp('[{][{][^}\\s|]*(info|element)box[ _][\\s\\S]*?[}][}]', 
                                     'gi'), '');

  // also, have float_begin, ... float_end
  this.data=this.data.replace(RegExp('[{][{][^}\\s|]*float[ _]begin' + 
                           '[\\s\\S]*?[^{\\s|]*float[ _]end.*?[}][}]',
                           'gi'), '');

  // from [[User:Zyxw/popups.js]]: kill frames too
  this.data=this.data.replace(RegExp('[{][{][^}\\s|]*[_ ]frame' +
                                     '[\\s\\S]*?[^{\\s|]*[_ ]?end[_ ]+frame[}][}]', 'gi'), '');
};
previewMaker.prototype.killTemplates = function () {
  this.data=this.data.replace(RegExp('[{][{]([{][{][^}]*[}][}]|[^{}])*[}][}]', 'g'), ' ');
};
previewMaker.prototype.killTables=function () {
  // tables are bad, too
  this.data=this.data.replace
  (RegExp('[{]\\|([{][|]([^\\|]|\\|[^}])*[|][}]|[^\\|]|\\|[^}])*\\|[}]', 'g')
   , '');
  // remove lines starting with a pipe
  this.data=this.data.replace(RegExp('^[|].*$', 'mg'), '');
};
previewMaker.prototype.killImages=function () {
  // images are a nono
  // who says regexes aren't fun?
  // i think we should match:
  // [[image: ...... ]] where ....... consists of repetitions of any of:
  // 1. not [ or ]
  // 2. [[ (not ])* ]] 
  // 3. [ (not ])* ]
  var imagedetector =
  '[[][[]\\s*('+
    popImageNamespace + '|' + popCategoryNamespace+
  ')\\s*:([^\\[\\]]|\\[\\[[^\\]]*\\]\\]|\\[[^\\]]*\\])*\\]\\]\\s*';
  var crudeImageRegex = RegExp(imagedetector, 'gi');
  this.data=this.data.replace(crudeImageRegex, '');
};
previewMaker.prototype.killHTML=function () {
  // kill <ref>...</ref>
  this.data=this.data.replace(RegExp('<ref>[\\s\\S]*?</ref>', 'gi'), '');
  
  // kill html tables // this doesn't cope with embedded tables
  // may this is good enough?
  this.data=this.data.replace(RegExp('<table.*?>[\\s\\S]*?</\\s*table\\s*>\\n+', 'gi'), '');
  
  // let's also delete entire lines starting with <. it's worth a try.
  this.data=this.data.replace(RegExp('(^|\\n) *<.*', 'g'), '\n');

  // and those pesky html tags
  this.data=this.data.replace(RegExp('<.*?>','g'),'');
};
previewMaker.prototype.killChunks=function() { // heuristics alert
  // chunks of italic text? you crazy, man?
  var italicChunkRegex=new RegExp
    ("((^|\\n)\\s*:*\\s*''[^']([^']|'''|'[^']){20}(.|\\n[^\\n])*''[.!?\\s]*\\n)*", 'g');
  this.data=this.data.replace(italicChunkRegex, '');
};
previewMaker.prototype.mopup=function () {
  // we simply *can't* be doing with horizontal rules right now
  this.data=this.data.replace(RegExp('^-{4,}','mg'),'');

  // no indented lines 
  this.data=this.data.replace(RegExp('(^|\\n) *:[^\\n]*','g'), '\n');

  // replace __TOC__, __NOTOC__ and whatever else there is
  // this'll probably do
  this.data=this.data.replace(RegExp('^__[A-Z_]*__ *$', 'gmi'),'');
};
previewMaker.prototype.firstBit=function () {
  // dont't be givin' me no subsequent paragraphs, you hear me?
  /// first we "normalize" section headings, removing whitespace after, adding before
  
  this.data=this.data.replace(RegExp('\\s*(==+[^=]*==+)\\s*', 'g'), '\n\n$1 ');

  /// then we want to get rid of paragraph breaks whose text ends badly
  this.data=this.data.replace(RegExp('([:;]) *\\n{2,}', 'g'), '$1\n');

  this.data=this.data.replace(RegExp('^[\\s\\n]*'), '');
  stuff=(RegExp('^([^\\n]|\\n[^\\n\\s])*')).exec(this.data);
  var d;
  if (stuff) d = stuff[0];  
  if (!getValueOf('popupPreviewFirstParOnly')) d = this.data;
  
  /// now put \n\n after sections so that bullets and numbered lists work
  d=d.replace(RegExp('(==+[^=]*==+)\\s*', 'g'), '$1\n\n');

  // superfluous sentences are RIGHT OUT.
  // note: exactly 1 set of parens here needed to make the slice work
  d = d.parenSplit(RegExp('([!?.]+["'+"'"+']*\\s)','g'));
  // leading space is bad, mmkay?
  d[0]=d[0].replace(RegExp('^\\s*'), '');

  var notSentenceEnds=RegExp('([^.][a-z][.][a-z]|etc|sic|Dr|Mr|Mrs|Ms|\\[[^\\]]*|\\s[A-Zvclm])$', 'i');
  
  d = this.fixSentenceEnds(d, notSentenceEnds);

  defaultize('popupMaxPreviewSentences');
  defaultize('popupMaxPreviewCharacters');
  
  var n=getValueOf('popupMaxPreviewSentences'); 
  var dd;
  
  do {dd=this.firstSentences(d,n); --n; } 
  while ( dd.length > popupMaxPreviewCharacters && n > 0 );
  
  this.data = dd;
};
previewMaker.prototype.fixSentenceEnds=function(strs, reg) { 
  // take an array of strings, strs
  // join strs[i] to strs[i+1] & strs[i+2] if strs[i] matches regex reg
  
  for (var i=0; i<strs.length-2; ++i) {
    if (reg.test(strs[i])) {
      a=[];
      for (var j=0; j<strs.length; ++j) {
        if (j<i)   a[j]=strs[j];
        if (j==i)  a[i]=strs[i]+strs[i+1]+strs[i+2];
        if (j>i+2) a[j-2]=strs[j];
      }
      return this.fixSentenceEnds(a,reg);
    }
  }
  return strs;
};
previewMaker.prototype.firstSentences=function(strs, howmany) {
  var t=strs.slice(0, 2*howmany); 
  return t.join(''); 
};

previewMaker.prototype.makePreview=function() {
  if (!isInNamespace(window.currentArticle, 'Template')) {
    this.killComments();
    this.killDivs();
    this.killGalleries();
    this.killBoxTemplates();
    if (getValueOf('popupPreviewKillTemplates')) this.killTemplates();
    else this.killMultilineTemplates();
    this.killTables();
    this.killImages();
    this.killHTML();
    this.killChunks();
    this.mopup();
    
    this.firstBit();
  }

  this.html=wiki2html(this.data); // needs livepreview
  this.fixHTML();
  this.stripLongTemplates();
};

previewMaker.prototype.fixHTML=function() {
  // work around quoting bug: 
  // wiki2html('[[Foo\'s "bar"]]') gives <a href='Foo's "bar"'> which doesn't do very well
  // we change this into <a href="Foo's %22bar%22">
  if(!this.html) return;
  var splitted=this.html.parenSplit(/href='([^>]*)'/g);
  var ret='';
  for (var i=0; i<splitted.length; ++i) {
    if(i%2==0) { ret += splitted[i]; continue; }
    if(i%2==1) { ret += 'href="' + splitted[i].split('"').join('%22') + '"'; }
  }
  this.html=ret;
}
previewMaker.prototype.showPreview=function () {
  this.makePreview();
  if (typeof this.html != typeof '') return;
  if (RegExp('^\\s*$').test(this.html)) return;
  //if (getValueOf('popupNavLinks') || getValueOf('popupSummaryData')) 
  setPopupHTML('<hr>'+this.html, 'popupPreview');
};
previewMaker.prototype.stripLongTemplates=function() {
  // operates on the HTML!
  this.html=this.html.replace(RegExp('^.{0,1000}[{][{][^}]*?(<(p|br)( /)?>\\s*){2,}([^{}]*?[}][}])?', 'gi'), '');
  this.html=this.html.split('\n').join(' '); // workaround for <pre> templates
  this.html=this.html.replace(RegExp('[{][{][^}]*<pre>[^}]*[}][}]','gi'), '');
  //this.html=this.html.replace(RegExp('[{][{]([^}]*|\\s){0,50}?<pre>[^{}]*?[}][}]', 'gi'), '');
  //window.h=this.html;
  //alert(this.html);
}
previewMaker.prototype.killMultilineTemplates=function() {
  this.data=this.data.replace(RegExp('\\s*[{][{][^{}]*\\n[^{}]*[}][}]', 'g'), ' ');  
  //this.data=this.data.replace(RegExp('[{][{]([{][{][^}]*[}][}]|[^{}])*\\n([{][{][^}]*[}][}]|[^{}])*[}][}]', 'g'), ' ');  
}

function fuzzyCursorOffMenus(fuzz) {
  if(!over) return null;
  var spans=over.getElementsByTagName('span');
  for (var i=0; i<spans.length; ++i) {
    if (typeof spans[i].className != undef && spans[i].className=='popup_menu') {
      if (!fuzzyCursorOffDiv(fuzz, spans[i])) return false;
    } // else {document.title+='.';}
  }
  return true;
};

function fuzzyCursorOffDiv(fuzz, div) {
  log('fuzzyCursorOffDiv: mouse (x,y)=('+o3_x+',' + o3_y+')');
  var left=findPosX(div)-fuzz; 
  var top=findPosY(div) - fuzz;
  var right=left + div.offsetWidth + 2*fuzz;
  var height=0;
  for (var i=0; i<div.childNodes.length;++i) {
    log('adding child '+div.childNodes[i]+'.offsetHeight: '+div.childNodes[i].offsetHeight);
    if (typeof div.childNodes[i].offsetHeight==typeof 1)
      height+=div.childNodes[i].offsetHeight;
  }
  var bottom = top + height + 2*fuzz;
  log(left+'->'+right+' , '+top+'->'+bottom);
  //document.title+=' offsetHeight:'+div.offsetHeight;
  if (typeof left != 'number' || typeof right != 'number' || typeof top != 'number') return true;
  if (o3_x < left || o3_x > right || o3_y < top) // || o3_y > bottom) // FIXME: should check the bottom too
    return true;
  return false;
};

function checkPopupPosition () { // stop the popup running off the right of the screen
  if (typeof over == undef || !over) return null;
  var x=findPosX(over);
  var w=parseInt(over.offsetWidth);
  if ( (x+w) >= document.body.clientWidth ) {
    // for what I am about to do, may the Lord forgive me
    over.style.left=0;
    var ww=parseInt(over.offsetWidth);
    over.style.left=(document.body.clientWidth-ww-1)+'px';
  }
  /*
  var y=findPosY(over);
  var h=parseInt(over.offsetHeight);
  var winH=window.innerHeight + window.pageYOffset;
  document.title=[y,h,winH].join(',');
  if ( h < winH && (y+h) >= winH ) {
    over.style.top=0;
    var hh=parseInt(over.offsetHeight);
    document.title+=','+hh;
    over.style.top=(winH-hh-24)+'px';
  }
  */
  return true;
};


function findPosX(obj)
{
	var curleft = 0;
	if (obj.offsetParent)
	{
		while (obj.offsetParent)
		{
			curleft += obj.offsetLeft
			obj = obj.offsetParent;
		}
	}
	else if (obj.x)
		curleft += obj.x;
	return curleft;
}

function findPosY(obj)
{
	var curtop = 0;
	if (obj.offsetParent)
	{
		while (obj.offsetParent)
		{
			curtop += obj.offsetTop
			obj = obj.offsetParent;
		}
	}
	else if (obj.y)
		curtop += obj.y;
	return curtop;
}


function fuzzyCursorOffOver(fuzz) {
  if (!over) return null;
  var left = parseInt(over.style.left);
  var top = parseInt(over.style.top);
  var right = left + 
    (over.offsetWidth >= parseInt(o3_width) ? over.offsetWidth : parseInt(o3_width));
  var bottom = top + 
    (over.offsetHeight >= o3_aboveheight ? over.offsetHeight : o3_aboveheight);

  if (o3_x < left-fuzz || o3_x > right+fuzz || o3_y < top-fuzz || o3_y > bottom + fuzz)
   return true;
  return false;
};

window.fuzzyCursorOff=function(fuzz) {
  return fuzzyCursorOffOver(fuzz) && fuzzyCursorOffMenus(fuzz);
}

// seems that fuzzyCursorOff should precede mouseOutWikiLink in the source
// or sometimes during page loads, errors are generated

var stopPopupTimer=null;

function mouseOutWikiLink () {
  if (typeof over != undef &&  over && over.dragging) return null;
  if (fuzzyCursorOff(5)) { 
    if (window.stopPopupTimer) {
      clearInterval(window.stopPopupTimer); 
      window.stopPopupTimer=null; 
    }
    killPopup(); 
    return;
  }
  runStopPopupTimer();
}

function runStopPopupTimer() {
  // at this point, we should have left the link but remain within the popup
  // so we call this function again until we leave the popup.
  if (!window.stopPopupTimer) 
    window.stopPopupTimer=setInterval(mouseOutWikiLink, 500);
}

function killPopup() {
  // o3_showingsticky should be defined in overlib.js
  //if ( typeof o3_showingsticky != "undefined" && o3_showingsticky == 0 ) {
  if (getValueOf('popupShortcutKeys')) rmPopupShortcuts();
  cClick();
  window.currentLink=null;
  abortAllDownloads();
  stopImagesDownloading();
  if (checkPopupPositionTimer != null) { clearInterval(checkPopupPositionTimer); checkPopupPositionTimer=null; }
  if (checkImagesTimer != null) { clearInterval(checkImagesTimer); checkImagesTimer=null; }
  if (popupImageTimer != null) { clearInterval(popupImageTimer); popupImageTimer=null; }
  return true; // preserve default action (eg from onclick)
};

function popups_runOnce(f, time) {
  var i=popups_runOnce.timers.length;
  var ff = function () { clearInterval(popups_runOnce.timers[i]); f() };
  var timer=setInterval(ff, time);
  popups_runOnce.timers.push(timer);
}
popups_runOnce.timers=[];


////////////////////////////////////////////////////////////////////
// Run things
////////////////////////////////////////////////////////////////////

if (window.addEventListener) {
  window.addEventListener("DOMContentLoaded",setupTooltips,false) || window.addEventListener("load", setupTooltips, false);
}
else if (window.attachEvent) {
  window.attachEvent("onload",setupTooltips);
}
else {
  window._old_popup_onload = window.onload;
  window.onload = function() {
    window._old_popup_onload();
    setupTooltips();
  }
}

/// Local Variables: ///
/// mode:c ///
/// End: ///
// --FILE BOUNDARY-- // --FILE BOUNDARY-- // --FILE BOUNDARY--
function getParamValue(paramName) {
  var cmdRe=RegExp('[&?]'+paramName+'=([^&]*)');
  var h=document.location;
  var m;
  if (m=cmdRe.exec(h)) {
    try { 
      return decodeURI(m[1]);
    } catch (someError) {}
  }
  return null;
};

function substitute(data,cmdBody) {
  // alert('sub\nfrom: '+cmdBody.from+'\nto: '+cmdBody.to+'\nflags: '+cmdBody.flags);
  var fromRe=RegExp(cmdBody.from, cmdBody.flags);
  return data.replace(fromRe, cmdBody.to);
};

function execCmds(data, cmdList) {
  for (var i=0; i<cmdList.length; ++i) {
    data=cmdList[i].action(data, cmdList[i]);
  }
  return data;
}

function parseCmd(str) {
  // returns a list of commands
  if (!str.length) return [];
  var p=false;
  switch (str.charAt(0)) {
  case 's':
    p=parseSubstitute(str);
    break;
  case 'j':
    p=parseJavascript(str);
    break;
  default:
    return false;
  }
  if (p) return [p].concat(parseCmd(p.remainder));
  return false;
};

function unEscape(str, sep) {
  return str.split('\\\\').join('\\')
        .split('\\'+sep).join(sep)
        .split('\\n').join('\n');
};


function runJavascript(data, argWrapper) {
  // flags aren't used (yet)

  // from the user's viewpoint,
  // data is a special variable may appear inside code
  // and gets assigned the text in the edit box

  // alert('eval-ing '+argWrapper.code);

  return eval(argWrapper.code);
};

function parseJavascript(str) {
  // takes a string like j/code/;othercmds and parses it

  var tmp,code,flags;

  if (str.length<3) return false;
  var sep=str.charAt(1);
  str=str.substring(2);
  
  tmp=skipOver(str,sep);
  if (tmp) { code=tmp.segment.split('\n').join('\\n'); str=tmp.remainder; }
  else return false;

  flags='';
  if (str.length) {
    tmp=skipOver(str,';') || skipToEnd(str, ';');
    if (tmp) {flags=tmp.segment; str=tmp.remainder; }
  }

  return { action: runJavascript, code: code, flags: flags, remainder: str };
};

function parseSubstitute(str) {
  // takes a string like s/a/b/flags;othercmds and parses it

  var from,to,flags,tmp;

  if (str.length<4) return false;
  var sep=str.charAt(1);
  str=str.substring(2);

  tmp=skipOver(str,sep);
  if (tmp) { from=tmp.segment; str=tmp.remainder; } 
  else return false;

  tmp=skipOver(str,sep);
  if (tmp) { to=tmp.segment; str=tmp.remainder; } 
  else return false;

  flags='';
  if (str.length) {
    tmp=skipOver(str,';') || skipToEnd(str, ';');
    if (tmp) {flags=tmp.segment; str=tmp.remainder; }
  }
  
  return {action: substitute, from: from, to: to, flags: flags, remainder: str};

};

function skipOver(str,sep) {
  var endSegment=findNext(str,sep);
  if (endSegment<0) return false;
  var segment=unEscape(str.substring(0,endSegment), sep);
  return {segment: segment, remainder: str.substring(endSegment+1)};
}

function skipToEnd(str,sep) {
  return {segment: str, remainder: ''};
}

function findNext(str, ch) {
  for (var i=0; i<str.length; ++i) {
    if (str.charAt(i)=='\\') i+=2;
    if (str.charAt(i)==ch) return i;
  }
  return -1;
};

function runOnLoad(f) {
  if (window.addEventListener) {
    window.addEventListener("load",f,false);
  }
  else if (window.attachEvent) {
    window.attachEvent("onload",f);
  }
  else {
    window._old_popup_autoedit_onload = window.onload;
    window.onload = function() {
      window._old_popup_autoedit_onload();
      f();
    }
  }
};

window.autoEdit=function() {
  if (window.autoEdit.alreadyRan) return false;
  window.autoEdit.alreadyRan=true;
  var cmdString=getParamValue('autoedit');
  if (cmdString) {
    try { 
      var editbox=document.editform.wpTextbox1;
    } catch (dang) { return; }
    var cmdList=parseCmd(cmdString);
    var input=editbox.value;
    var output=execCmds(input, cmdList);
    editbox.value=output;
  }

  var summary=getParamValue('autosummary');
  var summaryprompt=getParamValue('autosummaryprompt');
  if (summaryprompt) {
    var txt='Enter a non-empty edit summary or press cancel to abort';
    if (popupString) txt=popupString(txt);
    var response=prompt(txt, summary);
    if (response) summary=response;
    else return;
  }
  if (summary) document.editform.wpSummary.value=summary;

  var minor=getParamValue('autominor');
  if (minor) {
    switch (minor) {
    case '1':
    case 'yes':
    case 'true':
      document.editform.wpMinoredit.checked=true;
      break;
    case '0':
    case 'no':
    case 'false':
      document.editform.wpMinoredit.checked=false;
    }
  }

  var btn=getParamValue('autoclick');
  if (btn) {
    if (document.editform && document.editform[btn]) {
      var headings=document.getElementsByTagName('h1');
      if (headings) {
        var div=document.createElement('div');
        var button=document.editform[btn];
        div.innerHTML='<font size=+1><b>The "' + button.value + 
          '" button has been automatically clicked.' + 
          ' Please wait for the next page to load.</b></font>';
        document.title='('+document.title+')';
        headings[0].parentNode.insertBefore(div, headings[0]);
        button.click();
      }
    } else {
      alert('autoedit.js\n\nautoclick: could not find button "'+ btn +'".');
    }  
  }
};

runOnLoad(autoEdit);
// --FILE BOUNDARY-- // --FILE BOUNDARY-- // --FILE BOUNDARY--
// Last update: 21:51, 15 Feb 2005 (UTC)

// Script to embed Live Preview in MediaWiki's edit page
function LivePreviewInstall()
{
 copywarn = document.getElementById('editpage-copywarn');
 if (copywarn != null) {
  var cleaner = "<br style=\\'clear:both;\\' />";
  LivePreviewHTML = '<input type="button" value="Live Preview" onclick="document.getElementById(\'PreviewBox\').innerHTML = wiki2html(editform.wpTextbox1.value) + \'' + cleaner + '\';" />';
  //LivePreviewHTML = '<input type="button" value="Live Preview" onclick="document.getElementById(\'PreviewBox\').innerHTML = wiki2html(editform.wpTextbox1.value);" />';
  LivePreviewHTML += '<div style="margin-top: 5px; margin-bottom: 5px; padding: 5px; border: 3px double orange;" id="PreviewBox"></div>';
  copywarn.innerHTML = LivePreviewHTML + copywarn.innerHTML;
 }
}

// User options
var wpUserName=wpUserName||'Wikinewsn';
var wpUserSignature=wpUserSignature||wpUserName;
var wpShowImages=wpShowImages||true;

// System options
var wpLanguageCode=wpLanguageCode||'en';
var wpInterwikiCodes=wpInterwikiCodes||'aa|ab|af|ak|als|am|an|ang|ar|arc|as|ast|av|ay|az|ba|be|ber|bg|bh|bi|bm|bn|bdf|bo|br|bs|ca|ce|ceb|ch|cho|chr|chy|co|cr|cs|csb|cu|cv|cy|da|de|dv|dz|el|en|eo|es|et|eu|fa|ff|fi|fiu-vro|fj|fo|fr|fur|fy|ga|gd|gil|gl|gn|got|gu|gv|ha|haw|he|hi|ho|hr|ht|hu|hy|hz|ia|id|ie|ig|ii|ik|io|is|it|iu|ja|jbo|jv|ka|kg|ki|kj|kk|kl|km|kn|ko|kr|ks|ku|kv|kw|ky|la|lad|lan|lb|lg|li|ln|lo|lt|lu|lv|mg|mh|mi|mk|ml|mn|mo|mr|ms|mt|mus|my|na|nah|nap|nb|nd|nds|ne|ng|nl|nn|no|nr|nv|ny|oc|oj|om|or|os|pa|pam|pi|pl|ps|pt|qu|rm|rn|ro|roa-rup|ru|rw|sa|sc|scn|sco|sd|se|sg|sh|si|sk|sl|sm|smg|sn|so|sq|sr|ss|st|su|sv|sw|ta|te|tg|th|ti|tk|tl|tlh|tn|to|tpi|tr|ts|tt|tum|tw|ty|ug|uk|ur|uz|ve|vi|vk|vo|wa|war|wen|wo|xh|yi|yo|za|zh|zh-min-nan|zu';
var wpBaseArticlePath=wpBaseArticlePath||'/wiki/';
var wpMathBasePath=wpMathBasePath||'/math/';
var wpImageBasePath=wpImageBasePath||'//upload.wikimedia.org/Wikinews/'+wpLanguageCode+'/';
var wpImageFallbackPath=wpImageFallbackPath||'//upload.wikimedia.org/Wikinews/commons/';
var wpDefaultThumbWidth=wpDefaultThumbWidth||180;
var wpSkinMagnifyClip=wpSkinMagnifyClip||'/skins/common/images/magnify-clip.png';
var wpUserNamespace=wpUserNamespace||'User';
var wpImageNamespace=wpImageNamespace||'Image';
var wpCategoryNamespace=wpCategoryNamespace||'Category';

// Packed code (DO NOT MODIFY)
function wiki2html(str)
{str=strip_cr(str);var w=new WikiCode();w.lines=str.split(/\n/);w.parse();return w.html;};var wpSignature='[['+wpUserNamespace+':'+wpUserName+'|'+wpUserSignature+']]';var wpBlockImage=new RegExp('^\\[\\['+wpImageNamespace+':.*?\\|.*?(?:frame|thumbnail|thumb|none|right|left|center)','i');function WikiCode()
{this.lines=new Array;this.html=new String;this._endline=function(str)
{this.html+=str;this.lines.shift();};this.parse=function()
{var p=false;do{if(h_match=this.lines[0].match(/^(={1,6})(.*)\1(.*)$/)){p=false;this._endline('<h'+h_match[1].length+'>'+_parse_inline_nowiki(h_match[2])+'</h'+h_match[1].length+'>'+h_match[3]);}else if(this.lines[0].match(/^[*#:;]/)){p=false;this._parse_list();}else if(this.lines[0].charAt(0)==' '){p=false;this._parse_pre();}else if(this.lines[0].substr(0,2)=='{|'){p=false;this._parse_table();}else if(this.lines[0].match(/^----+$/)){p=false;this._endline('<hr/>');}else if(this.lines[0].match(wpBlockImage)){p=false;this._parse_block_image();}else{if(this.lines[0]==''){if(p=(this.lines.length>1&&this.lines[1]=='')){this._endline('<p><br />');}}else{if(!p){this.html+='<p>';p=true;}
this.html+=_parse_inline_nowiki(this.lines[0])+' ';}
this.lines.shift();}}while(this.lines.length);};this._parse_list=function(){var prev=new String;var l_match,imatch,dt_match;while(this.lines.length&&(l_match=this.lines[0].match(/^([*#:;]+)(.*)$/))){this.lines.shift();imatch=str_imatch(prev,l_match[1]);for(var i=prev.length-1;i>=imatch;i--){if(prev.charAt(i)=='*'){this.html+='</ul>';}else if(prev.charAt(i)=='#'){this.html+='</ol>'}else{this.html+='</d'+((prev.charAt(i)==';')?'t':'d')+'>';switch(l_match[1].charAt(i)){case'':case'*':case'#':this.html+='</dl>';}}}
for(var i=imatch;i<l_match[1].length;i++){if(l_match[1].charAt(i)=='*'){this.html+='<ul>';}else if(l_match[1].charAt(i)=='#'){this.html+='<ol>';}else{switch(prev.charAt(i)){case'':case'*':case'#':this.html+='<dl>';}
this.html+='<d'+((l_match[1].charAt(i)==';')?'t':'d')+'>';}}
switch(l_match[1].charAt(l_match[1].length-1)){case'*':case'#':this.html+='<li>'+_parse_inline_nowiki(l_match[2]);break;case';':if(dt_match=l_match[2].match(/(.*?) (:.*?)$/)){this.html+=_parse_inline_nowiki(dt_match[1]);this.lines.unshift(dt_match[2]);break;}
case':':this.html+=_parse_inline_nowiki(l_match[2]);}
prev=l_match[1];}
for(i=prev.length-1;i>=0;i--){if(prev.charAt(i)=='*'){this.html+='</ul>';}else if(prev.charAt(i)=='#'){this.html+='</ol>';}else{this.html+='</d'+((prev.charAt(i)==';')?'t':'d')+'></dl>';}}};this._parse_table=function()
{var table_match;if(table_match=this.lines[0].match(/^\{\|( .*)$/)){this._endline('<table'+table_match[1]+'>');}else this._endline('<table>');do{if(this.lines[0].charAt(0)=='|'){switch(this.lines[0].charAt(1)){case'}':this._endline('</table>');return;case'-':this._endline('<tr '+this.lines[0].match(/\|-*(.*)/)[1]+'>');break;default:this._parse_table_data();}}else if(this.lines[0].charAt(0)=='!'){this._parse_table_data();}else{this.lines.shift();}}while(this.lines.length)};this._parse_table_data=function()
{var td_match,td_line;td_match=this.lines.shift().match(/^(\|\+|\||!)((?:([^[|]*?)\|(?!\|))?(.*))$/);if(td_match[1]=='|+'){this.html+='<caption';}else{this.html+='<t'+((td_match[1]=='|')?'d':'h');}
if(typeof td_match[3]!='undefined'){this.html+=' '+td_match[3];td_line=td_match[4].split('||');}else{td_line=td_match[2].split('||');}
this.html+='>';while(td_line.length>1){this.lines.unshift(td_match[1]+td_line.pop());}
this.html+=_parse_inline_nowiki(td_line[0]);var td=new WikiCode;var table_count=0;while(this.lines.length){if(this.lines[0].charAt(0)=='|'){if(table_count==0)break;else if(this.lines[0].charAt(1)=='}')table_count--;}else if(this.lines[0].charAt(0)=='!'&&table_count==0){break;}else if(this.lines[0].substr(0,2)=='{|')table_count++;td.lines.push(this.lines.shift());}
if(td.lines.length){td.parse();}
this.html+=td.html;};this._parse_pre=function()
{this.html+='<pre>';do{this._endline(_parse_inline_nowiki(this.lines[0].substring(1,this.lines[0].length))+"\n");}while(this.lines.length&&this.lines[0].charAt(0)==' ');this.html+='</pre>';};this._parse_block_image=function()
{this.html+=_parse_image(this.lines.shift());};};function _parse_image(str)
{var attr=str.substring(wpImageNamespace.length+3,str.length-2).split(/\s*\|\s*/);var filename=attr[0];var caption=attr[attr.length-1];var width,w_match;var thumb=false;var frame=false;var center=false;var align='';var html='';do{if(w_match=attr[0].match(/^(\d*)px$/)){width=w_match[1];}else switch(attr[0]){case'thumb':case'thumbnail':thumb=true;case'frame':frame=true;break;case'none':case'right':case'left':center=false;align=attr[0];break;case'center':center=true;align='none';}
attr.shift();}while(attr.length);if(frame){if(align=='')align='right';html+="<div class='thumb t"+align+"'>";if(thumb){if(!width)width=wpDefaultThumbWidth;html+="<div style='width:"+(2+parseInt(width))+"px;'>";html+=_make_image(filename,caption,width);html+="<div class='thumbcaption'><div class='magnify' style='float:right'><a href='"+wpBaseArticlePath+wpImageNamespace+':'+filename+"' class='internal' title='Enlarge'><img src='"+wpSkinMagnifyClip+"' /></a></div>"+_parse_inline_nowiki(caption)+"</div>";}else{html+='<div>';html+=_make_image(filename,caption);html+="<div class='thumbcaption'>"+_parse_inline_nowiki(caption)+"</div>";}
html+='</div></div>';}else if(align!=''){html+="<div class='float"+align+"'><span>"+_make_image(filename,caption,width)+"</span></div>";}else{return _make_image(filename,caption,width);}
if(center){return"<div class='center'>"+html+'</div>';}else{return html;}};this._parse_inline_nowiki=function(str)
{var start,lastend=0
var substart=0,nestlev=0,open,close,subloop;var html='';while(-1!=(start=str.indexOf('<'+'nowiki>',substart))){html+=_parse_inline_wiki(str.substring(lastend,start));start+=8;substart=start;subloop=true;do{open=str.indexOf('<'+'nowiki>',substart);close=str.indexOf('</nowiki>',substart);if(close<=open||open==-1){if(close==-1){return html+html_entities(str.substr(start));}
substart=close+9;if(nestlev){nestlev--;}else{lastend=substart;html+=html_entities(str.substring(start,lastend-9));subloop=false;}}else{substart=open+8;nestlev++;}}while(subloop);}
return html+_parse_inline_wiki(str.substr(lastend));};function _make_image(filename,caption,width)
{filename=filename.charAt(0).toUpperCase()+filename.substr(1);filename=filename.replace(/ /g,'_');var md5=hex_md5(filename);var source=md5.charAt(0)+'/'+md5.substr(0,2)+'/'+filename;var img;if(wpShowImages){if(width){width="width='"+width+"px'";}
img="<img onerror='this.onerror=null;this.src=\""+wpImageFallbackPath+source+"\";' src='"+wpImageBasePath+source+"' alt='"+caption+"' "+width+"/>";}else{img=wpImageNamespace+':'+filename+" <em style='color:red;'>(images disabled)</em>";}
caption=_strip_inline_wiki(caption);return"<a class='image' title='"+caption+"' href='"+wpBaseArticlePath+wpImageNamespace+':'+filename+"'>"+img+"</a>";};function _parse_inline_images(str)
{var start,substart=0,nestlev=0;var loop,close,open,wiki,html;while(-1!=(start=str.indexOf('[[',substart))){if(str.substr(start+2).match(RegExp('^'+wpImageNamespace+':','i'))){loop=true;substart=start;do{substart+=2;close=str.indexOf(']]',substart);open=str.indexOf('[[',substart);if(close<=open||open==-1){if(close==-1)return str;substart=close;if(nestlev){nestlev--;}else{wiki=str.substring(start,close+2);html=_parse_image(wiki);str=str.replace(wiki,html);substart=start+html.length;loop=false;}}else{substart=open;nestlev++;}}while(loop);}else{break;}}
return str;};function _parse_inline_wiki(str)
{var aux_match,math_md5;str=_parse_inline_images(str);while(aux_match=str.match(/<(?:)math>(.*?)<\/math>/i)){math_md5=hex_md5(aux_match[1]);str=str.replace(aux_match[0],"<img src='"+wpMathBasePath+math_md5+'.png'+"' />");}
return str.replace(/'''''(.*?)''(.*?)'''/g,'<strong><em>$1</em>$2</strong>').replace(/'''''(.*?)'''(.*?)''/g,'<em><strong>$1</strong>$2</em>').replace(/'''(.*?)''(.*?)'''''/g,'<strong>$1<em>$2</em></strong>').replace(/'''(.*?)'''/g,'<strong>$1</strong>').replace(/''(.*?)''/g,'<em>$1</em>').replace(/~{5}(?!~)/g,Date()).replace(/~{4}(?!~)/g,wpSignature+' '+Date()).replace(/~{3}(?!~)/g,wpSignature).replace(RegExp('\\[\\[:((?:'+wpCategoryNamespace+'|'+wpInterwikiCodes+'):.*?)\\]\\]','gi'),"<a href='"+wpBaseArticlePath+"$1'>$1</a>").replace(RegExp('\\[\\[(?:'+wpCategoryNamespace+'|'+wpInterwikiCodes+'):.*?\\]\\]','gi'),'').replace(/\[\[([^|]*?)\]\](\w*)/g,"<a href='"+wpBaseArticlePath+"$1'>$1$2</a>").replace(/\[\[(.*?)\|([^\]]+?)\]\](\w*)/g,"<a href='"+wpBaseArticlePath+"$1'>$2$3</a>").replace(/\[\[([^\]]*?:)?(.*?)( *\(.*?\))?\|\]\]/g,"<a href='"+wpBaseArticlePath+"$1$2$3'>$2</a>").replace(/\[(http|news|ftp|mailto|gopher|irc):(\/*)([^\]]*?) (.*?)\]/g,"<a href='$1:$2$3'>$4</a>").replace(/\[http:\/\/(.*?)\]/g,"<a href='http://$1'>[#]</a>").replace(/\[(news|ftp|mailto|gopher|irc):(\/*)(.*?)\]/g,"<a href='$1:$2$3'>$1:$2$3</a>").replace(/(^| )(http|news|ftp|mailto|gopher|irc):(\/*)([^ $]*)/g,"$1<a href='$2:$3$4'>$2:$3$4</a>").replace('__NOTOC__','').replace('__NOEDITSECTION__','');};function _strip_inline_wiki(str)
{return str.replace(/\[\[[^\]]*\|(.*?)\]\]/g,'$1').replace(/\[\[(.*?)\]\]/g,'$1').replace(/''(.*?)''/g,'$1');};function max(a,b)
{if(a>b)return a;else return b;};function min(a,b)
{if(a<b)return a;else return b;};function str_imatch(str_a,str_b)
{var lim=min(str_a.length,str_b.length);for(var i=0;i<lim;i++){if(str_a.charAt(i)!=str_b.charAt(i))return i;}
return i;};function strip_cr(str)
{return str.replace(/\n\r/g,"\n").replace(/\r/g,'');};function html_entities(str)
{return str.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;");};var chrsz=8;var hex_tab="0123456789abcdef";function hex_md5(s){return binl2hex(core_md5(str2binl(s),s.length*chrsz));};function core_md5(x,len)
{x[len>>5]|=0x80<<((len)%32);x[(((len+64)>>>9)<<4)+14]=len;var a=1732584193;var b=-271733879;var c=-1732584194;var d=271733878;for(var i=0;i<x.length;i+=16)
{var olda=a;var oldb=b;var oldc=c;var oldd=d;a=md5_ff(a,b,c,d,x[i+0],7,-680876936);d=md5_ff(d,a,b,c,x[i+1],12,-389564586);c=md5_ff(c,d,a,b,x[i+2],17,606105819);b=md5_ff(b,c,d,a,x[i+3],22,-1044525330);a=md5_ff(a,b,c,d,x[i+4],7,-176418897);d=md5_ff(d,a,b,c,x[i+5],12,1200080426);c=md5_ff(c,d,a,b,x[i+6],17,-1473231341);b=md5_ff(b,c,d,a,x[i+7],22,-45705983);a=md5_ff(a,b,c,d,x[i+8],7,1770035416);d=md5_ff(d,a,b,c,x[i+9],12,-1958414417);c=md5_ff(c,d,a,b,x[i+10],17,-42063);b=md5_ff(b,c,d,a,x[i+11],22,-1990404162);a=md5_ff(a,b,c,d,x[i+12],7,1804603682);d=md5_ff(d,a,b,c,x[i+13],12,-40341101);c=md5_ff(c,d,a,b,x[i+14],17,-1502002290);b=md5_ff(b,c,d,a,x[i+15],22,1236535329);a=md5_gg(a,b,c,d,x[i+1],5,-165796510);d=md5_gg(d,a,b,c,x[i+6],9,-1069501632);c=md5_gg(c,d,a,b,x[i+11],14,643717713);b=md5_gg(b,c,d,a,x[i+0],20,-373897302);a=md5_gg(a,b,c,d,x[i+5],5,-701558691);d=md5_gg(d,a,b,c,x[i+10],9,38016083);c=md5_gg(c,d,a,b,x[i+15],14,-660478335);b=md5_gg(b,c,d,a,x[i+4],20,-405537848);a=md5_gg(a,b,c,d,x[i+9],5,568446438);d=md5_gg(d,a,b,c,x[i+14],9,-1019803690);c=md5_gg(c,d,a,b,x[i+3],14,-187363961);b=md5_gg(b,c,d,a,x[i+8],20,1163531501);a=md5_gg(a,b,c,d,x[i+13],5,-1444681467);d=md5_gg(d,a,b,c,x[i+2],9,-51403784);c=md5_gg(c,d,a,b,x[i+7],14,1735328473);b=md5_gg(b,c,d,a,x[i+12],20,-1926607734);a=md5_hh(a,b,c,d,x[i+5],4,-378558);d=md5_hh(d,a,b,c,x[i+8],11,-2022574463);c=md5_hh(c,d,a,b,x[i+11],16,1839030562);b=md5_hh(b,c,d,a,x[i+14],23,-35309556);a=md5_hh(a,b,c,d,x[i+1],4,-1530992060);d=md5_hh(d,a,b,c,x[i+4],11,1272893353);c=md5_hh(c,d,a,b,x[i+7],16,-155497632);b=md5_hh(b,c,d,a,x[i+10],23,-1094730640);a=md5_hh(a,b,c,d,x[i+13],4,681279174);d=md5_hh(d,a,b,c,x[i+0],11,-358537222);c=md5_hh(c,d,a,b,x[i+3],16,-722521979);b=md5_hh(b,c,d,a,x[i+6],23,76029189);a=md5_hh(a,b,c,d,x[i+9],4,-640364487);d=md5_hh(d,a,b,c,x[i+12],11,-421815835);c=md5_hh(c,d,a,b,x[i+15],16,530742520);b=md5_hh(b,c,d,a,x[i+2],23,-995338651);a=md5_ii(a,b,c,d,x[i+0],6,-198630844);d=md5_ii(d,a,b,c,x[i+7],10,1126891415);c=md5_ii(c,d,a,b,x[i+14],15,-1416354905);b=md5_ii(b,c,d,a,x[i+5],21,-57434055);a=md5_ii(a,b,c,d,x[i+12],6,1700485571);d=md5_ii(d,a,b,c,x[i+3],10,-1894986606);c=md5_ii(c,d,a,b,x[i+10],15,-1051523);b=md5_ii(b,c,d,a,x[i+1],21,-2054922799);a=md5_ii(a,b,c,d,x[i+8],6,1873313359);d=md5_ii(d,a,b,c,x[i+15],10,-30611744);c=md5_ii(c,d,a,b,x[i+6],15,-1560198380);b=md5_ii(b,c,d,a,x[i+13],21,1309151649);a=md5_ii(a,b,c,d,x[i+4],6,-145523070);d=md5_ii(d,a,b,c,x[i+11],10,-1120210379);c=md5_ii(c,d,a,b,x[i+2],15,718787259);b=md5_ii(b,c,d,a,x[i+9],21,-343485551);a=safe_add(a,olda);b=safe_add(b,oldb);c=safe_add(c,oldc);d=safe_add(d,oldd);}
return Array(a,b,c,d);};function md5_cmn(q,a,b,x,s,t)
{return safe_add(bit_rol(safe_add(safe_add(a,q),safe_add(x,t)),s),b);};function md5_ff(a,b,c,d,x,s,t)
{return md5_cmn((b&c)|((~b)&d),a,b,x,s,t);};function md5_gg(a,b,c,d,x,s,t)
{return md5_cmn((b&d)|(c&(~d)),a,b,x,s,t);};function md5_hh(a,b,c,d,x,s,t)
{return md5_cmn(b^c^d,a,b,x,s,t);};function md5_ii(a,b,c,d,x,s,t)
{return md5_cmn(c^(b|(~d)),a,b,x,s,t);};function safe_add(x,y)
{var lsw=(x&0xFFFF)+(y&0xFFFF);var msw=(x>>16)+(y>>16)+(lsw>>16);return(msw<<16)|(lsw&0xFFFF);};function bit_rol(num,cnt)
{return(num<<cnt)|(num>>>(32-cnt));};function str2binl(str)
{var bin=Array();var mask=(1<<chrsz)-1;for(var i=0;i<str.length*chrsz;i+=chrsz)
bin[i>>5]|=(str.charCodeAt(i/chrsz)&mask)<<(i%32);return bin;};function binl2hex(binarray)
{var str='';for(var i=0;i<binarray.length*4;i++)
{str+=hex_tab.charAt((binarray[i>>2]>>((i%4)*8+4))&0xF)+
hex_tab.charAt((binarray[i>>2]>>((i%4)*8))&0xF);}
return str;}; // </math>// --FILE BOUNDARY-- // --FILE BOUNDARY-- // --FILE BOUNDARY--
/*
 * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
 * Digest Algorithm, as defined in RFC 1321.
 * Version 2.2-alpha Copyright (C) Paul Johnston 1999 - 2005
 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
 * Distributed under the BSD License
 * See http://pajhome.org.uk/crypt/md5 for more info.
 */

/*
 * Configurable variables. You may need to tweak these to be compatible with
 * the server-side, but the defaults work in most cases.
 */
var hexcase = 0;   /* hex output format. 0 - lowercase; 1 - uppercase        */
var b64pad  = ""; /* base-64 pad character. "=" for strict RFC compliance   */

/*
 * These are the functions you'll usually want to call
 * They take string arguments and return either hex or base-64 encoded strings
 */
function hex_md5(s)    { return rstr2hex(rstr_md5(str2rstr_utf8(s))); }
function b64_md5(s)    { return rstr2b64(rstr_md5(str2rstr_utf8(s))); }
function any_md5(s, e) { return rstr2any(rstr_md5(str2rstr_utf8(s)), e); }
function hex_hmac_md5(k, d)
  { return rstr2hex(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d))); }
function b64_hmac_md5(k, d)
  { return rstr2b64(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d))); }
function any_hmac_md5(k, d, e)
  { return rstr2any(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d)), e); }

/*
 * Perform a simple self-test to see if the VM is working
 */
function md5_vm_test()
{
  return hex_md5("abc") == "900150983cd24fb0d6963f7d28e17f72";
}

/*
 * Calculate the MD5 of a raw string
 */
function rstr_md5(s)
{
  return binl2rstr(binl_md5(rstr2binl(s), s.length * 8));
}

/*
 * Calculate the HMAC-MD5, of a key and some data (raw strings)
 */
function rstr_hmac_md5(key, data)
{
  var bkey = rstr2binl(key);
  if(bkey.length > 16) bkey = binl_md5(bkey, key.length * 8);

  var ipad = Array(16), opad = Array(16);
  for(var i = 0; i < 16; i++)
  {
    ipad[i] = bkey[i] ^ 0x36363636;
    opad[i] = bkey[i] ^ 0x5C5C5C5C;
  }

  var hash = binl_md5(ipad.concat(rstr2binl(data)), 512 + data.length * 8);
  return binl2rstr(binl_md5(opad.concat(hash), 512 + 128));
}

/*
 * Convert a raw string to a hex string
 */
function rstr2hex(input)
{
  var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
  var output = "";
  var x;
  for(var i = 0; i < input.length; i++)
  {
    x = input.charCodeAt(i);
    output += hex_tab.charAt((x >>> 4) & 0x0F)
           +  hex_tab.charAt( x        & 0x0F);
  }
  return output;
}

/*
 * Convert a raw string to a base-64 string
 */
function rstr2b64(input)
{
  var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  var output = "";
  var len = input.length;
  for(var i = 0; i < len; i += 3)
  {
    var triplet = (input.charCodeAt(i) << 16)
                | (i + 1 < len ? input.charCodeAt(i+1) << 8 : 0)
                | (i + 2 < len ? input.charCodeAt(i+2)      : 0);
    for(var j = 0; j < 4; j++)
    {
      if(i * 8 + j * 6 > input.length * 8) output += b64pad;
      else output += tab.charAt((triplet >>> 6*(3-j)) & 0x3F);
    }
  }
  return output;
}

/*
 * Convert a raw string to an arbitrary string encoding
 */
function rstr2any(input, encoding)
{
  var divisor = encoding.length;
  var remainders = Array();
  var i, q, x, quotient;

  /* Convert to an array of 16-bit big-endian values, forming the dividend */
  var dividend = Array(input.length / 2);
  for(i = 0; i < dividend.length; i++)
  {
    dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1);
  }

  /*
   * Repeatedly perform a long division. The binary array forms the dividend,
   * the length of the encoding is the divisor. Once computed, the quotient
   * forms the dividend for the next step. We stop when the dividend is zero.
   * All remainders are stored for later use.
   */
  while(dividend.length > 0)
  {
    quotient = Array();
    x = 0;
    for(i = 0; i < dividend.length; i++)
    {
      x = (x << 16) + dividend[i];
      q = Math.floor(x / divisor);
      x -= q * divisor;
      if(quotient.length > 0 || q > 0)
        quotient[quotient.length] = q;
    }
    remainders[remainders.length] = x;
    dividend = quotient;
  }

  /* Convert the remainders to the output string */
  var output = "";
  for(i = remainders.length - 1; i >= 0; i--)
    output += encoding.charAt(remainders[i]);

  return output;
}

/*
 * Encode a string as utf-8.
 * For efficiency, this assumes the input is valid utf-16.
 */
function str2rstr_utf8(input)
{
  var output = "";
  var i = -1;
  var x, y;

  while(++i < input.length)
  {
    /* Decode utf-16 surrogate pairs */
    x = input.charCodeAt(i);
    y = i + 1 < input.length ? input.charCodeAt(i + 1) : 0;
    if(0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF)
    {
      x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF);
      i++;
    }

    /* Encode output as utf-8 */
    if(x <= 0x7F)
      output += String.fromCharCode(x);
    else if(x <= 0x7FF)
      output += String.fromCharCode(0xC0 | ((x >>> 6 ) & 0x1F),
                                    0x80 | ( x         & 0x3F));
    else if(x <= 0xFFFF)
      output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F),
                                    0x80 | ((x >>> 6 ) & 0x3F),
                                    0x80 | ( x         & 0x3F));
    else if(x <= 0x1FFFFF)
      output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07),
                                    0x80 | ((x >>> 12) & 0x3F),
                                    0x80 | ((x >>> 6 ) & 0x3F),
                                    0x80 | ( x         & 0x3F));
  }
  return output;
}

/*
 * Encode a string as utf-16
 */
function str2rstr_utf16le(input)
{
  var output = "";
  for(var i = 0; i < input.length; i++)
    output += String.fromCharCode( input.charCodeAt(i)        & 0xFF,
                                  (input.charCodeAt(i) >>> 8) & 0xFF);
  return output;
}

function str2rstr_utf16be(input)
{
  var output = "";
  for(var i = 0; i < input.length; i++)
    output += String.fromCharCode((input.charCodeAt(i) >>> 8) & 0xFF,
                                   input.charCodeAt(i)        & 0xFF);
  return output;
}

/*
 * Convert a raw string to an array of little-endian words
 * Characters >255 have their high-byte silently ignored.
 */
function rstr2binl(input)
{
  var output = Array(input.length >> 2);
  for(var i = 0; i < output.length; i++)
    output[i] = 0;
  for(var i = 0; i < input.length * 8; i += 8)
    output[i>>5] |= (input.charCodeAt(i / 8) & 0xFF) << (i%32);
  return output;
}

/*
 * Convert an array of little-endian words to a string
 */
function binl2rstr(input)
{
  var output = "";
  for(var i = 0; i < input.length * 32; i += 8)
    output += String.fromCharCode((input[i>>5] >>> (i % 32)) & 0xFF);
  return output;
}

/*
 * Calculate the MD5 of an array of little-endian words, and a bit length.
 */
function binl_md5(x, len)
{
  /* append padding */
  x[len >> 5] |= 0x80 << ((len) % 32);
  x[(((len + 64) >>> 9) << 4) + 14] = len;

  var a =  1732584193;
  var b = -271733879;
  var c = -1732584194;
  var d =  271733878;

  for(var i = 0; i < x.length; i += 16)
  {
    var olda = a;
    var oldb = b;
    var oldc = c;
    var oldd = d;

    a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);
    d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);
    c = md5_ff(c, d, a, b, x[i+ 2], 17,  606105819);
    b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);
    a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);
    d = md5_ff(d, a, b, c, x[i+ 5], 12,  1200080426);
    c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);
    b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);
    a = md5_ff(a, b, c, d, x[i+ 8], 7 ,  1770035416);
    d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);
    c = md5_ff(c, d, a, b, x[i+10], 17, -42063);
    b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162);
    a = md5_ff(a, b, c, d, x[i+12], 7 ,  1804603682);
    d = md5_ff(d, a, b, c, x[i+13], 12, -40341101);
    c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290);
    b = md5_ff(b, c, d, a, x[i+15], 22,  1236535329);

    a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);
    d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);
    c = md5_gg(c, d, a, b, x[i+11], 14,  643717713);
    b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);
    a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);
    d = md5_gg(d, a, b, c, x[i+10], 9 ,  38016083);
    c = md5_gg(c, d, a, b, x[i+15], 14, -660478335);
    b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);
    a = md5_gg(a, b, c, d, x[i+ 9], 5 ,  568446438);
    d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);
    c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);
    b = md5_gg(b, c, d, a, x[i+ 8], 20,  1163531501);
    a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);
    d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);
    c = md5_gg(c, d, a, b, x[i+ 7], 14,  1735328473);
    b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734);

    a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);
    d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);
    c = md5_hh(c, d, a, b, x[i+11], 16,  1839030562);
    b = md5_hh(b, c, d, a, x[i+14], 23, -35309556);
    a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);
    d = md5_hh(d, a, b, c, x[i+ 4], 11,  1272893353);
    c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);
    b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640);
    a = md5_hh(a, b, c, d, x[i+13], 4 ,  681279174);
    d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);
    c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);
    b = md5_hh(b, c, d, a, x[i+ 6], 23,  76029189);
    a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);
    d = md5_hh(d, a, b, c, x[i+12], 11, -421815835);
    c = md5_hh(c, d, a, b, x[i+15], 16,  530742520);
    b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);

    a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);
    d = md5_ii(d, a, b, c, x[i+ 7], 10,  1126891415);
    c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905);
    b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);
    a = md5_ii(a, b, c, d, x[i+12], 6 ,  1700485571);
    d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);
    c = md5_ii(c, d, a, b, x[i+10], 15, -1051523);
    b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);
    a = md5_ii(a, b, c, d, x[i+ 8], 6 ,  1873313359);
    d = md5_ii(d, a, b, c, x[i+15], 10, -30611744);
    c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);
    b = md5_ii(b, c, d, a, x[i+13], 21,  1309151649);
    a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);
    d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379);
    c = md5_ii(c, d, a, b, x[i+ 2], 15,  718787259);
    b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);

    a = safe_add(a, olda);
    b = safe_add(b, oldb);
    c = safe_add(c, oldc);
    d = safe_add(d, oldd);
  }
  return Array(a, b, c, d);
}

/*
 * These functions implement the four basic operations the algorithm uses.
 */
function md5_cmn(q, a, b, x, s, t)
{
  return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b);
}
function md5_ff(a, b, c, d, x, s, t)
{
  return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
}
function md5_gg(a, b, c, d, x, s, t)
{
  return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
}
function md5_hh(a, b, c, d, x, s, t)
{
  return md5_cmn(b ^ c ^ d, a, b, x, s, t);
}
function md5_ii(a, b, c, d, x, s, t)
{
  return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
}

/*
 * Add integers, wrapping at 2^32. This uses 16-bit operations internally
 * to work around bugs in some JS interpreters.
 */
function safe_add(x, y)
{
  var lsw = (x & 0xFFFF) + (y & 0xFFFF);
  var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
  return (msw << 16) | (lsw & 0xFFFF);
}

/*
 * Bitwise rotate a 32-bit number to the left.
 */
function bit_rol(num, cnt)
{
  return (num << cnt) | (num >>> (32 - cnt));
}// --FILE BOUNDARY-- // --FILE BOUNDARY-- // --FILE BOUNDARY--
//\/////
//\  overLIB 4.21 - You may not remove or change this notice.
//\  Copyright Erik Bosrup 1998-2004. All rights reserved.
//\
//\  Contributors are listed on the homepage.
//\  This file might be old, always check for the latest version at:
//\  http://www.bosrup.com/web/overlib/
//\
//\  Please read the license agreement (available through the link above)
//\  before using overLIB. Direct any licensing questions to erik@bosrup.com.
//\
//\  Do not sell this as your own work or remove this copyright notice. 
//\  For full details on copying or changing this script please read the
//\  license agreement at the link above. Please give credit on sites that
//\  use overLIB and submit changes of the script so other people can use
//\  them as well.
//\/////
//\  THIS IS A VERY MODIFIED VERSION. DO NOT EDIT OR PUBLISH. GET THE ORIGINAL!
var olLoaded=0,pmStart=10000000,pmUpper=10001000,pmCount=pmStart+1,pmt='',pms=new Array(),olInfo=new Info('4.21',1),FREPLACE=0,FBEFORE=1,FAFTER=2,FALTERNATE=3,FCHAIN=4,olHideForm=0,olHautoFlag=0,olVautoFlag=0,hookPts=new Array(),postParse=new Array(),cmdLine=new Array(),runTime=new Array();
registerCommands('donothing,inarray,caparray,sticky,background,noclose,caption,left,right,center,offsetx,offsety,fgcolor,bgcolor,textcolor,capcolor,closecolor,width,border,cellpad,status,autostatus,autostatuscap,height,closetext,snapx,snapy,fixx,fixy,relx,rely,fgbackground,bgbackground,padx,pady,fullhtml,above,below,capicon,textfont,captionfont,closefont,textsize,captionsize,closesize,timeout,function,delay,hauto,vauto,closeclick,wrap,followmouse,mouseoff,closetitle,cssoff,compatmode,cssclass,fgclass,bgclass,textfontclass,captionfontclass,closefontclass');
if(typeof ol_fgcolor=='undefined')var ol_fgcolor="#CCCCFF";if(typeof ol_bgcolor=='undefined')var ol_bgcolor="#333399";if(typeof ol_textcolor=='undefined')var ol_textcolor="#000000";if(typeof ol_capcolor=='undefined')var ol_capcolor="#FFFFFF";if(typeof ol_closecolor=='undefined')var ol_closecolor="#9999FF";if(typeof ol_textfont=='undefined')var ol_textfont="Verdana,Arial,Helvetica";if(typeof ol_captionfont=='undefined')var ol_captionfont="Verdana,Arial,Helvetica";if(typeof ol_closefont=='undefined')var ol_closefont="Verdana,Arial,Helvetica";if(typeof ol_textsize=='undefined')var ol_textsize="1";if(typeof ol_captionsize=='undefined')var ol_captionsize="1";if(typeof ol_closesize=='undefined')var ol_closesize="1";if(typeof ol_width=='undefined')var ol_width="200";if(typeof ol_border=='undefined')var ol_border="1";if(typeof ol_cellpad=='undefined')var ol_cellpad=2;if(typeof ol_offsetx=='undefined')var ol_offsetx=10;if(typeof ol_offsety=='undefined')var ol_offsety=10;if(typeof ol_text=='undefined')var ol_text="Default Text";if(typeof ol_cap=='undefined')var ol_cap="";if(typeof ol_sticky=='undefined')var ol_sticky=0;if(typeof ol_background=='undefined')var ol_background="";if(typeof ol_close=='undefined')var ol_close="Close";if(typeof ol_hpos=='undefined')var ol_hpos=RIGHT;if(typeof ol_status=='undefined')var ol_status="";if(typeof ol_autostatus=='undefined')var ol_autostatus=0;if(typeof ol_height=='undefined')var ol_height=-1;if(typeof ol_snapx=='undefined')var ol_snapx=0;if(typeof ol_snapy=='undefined')var ol_snapy=0;if(typeof ol_fixx=='undefined')var ol_fixx=-1;if(typeof ol_fixy=='undefined')var ol_fixy=-1;if(typeof ol_relx=='undefined')var ol_relx=null;if(typeof ol_rely=='undefined')var ol_rely=null;if(typeof ol_fgbackground=='undefined')var ol_fgbackground="";if(typeof ol_bgbackground=='undefined')var ol_bgbackground="";if(typeof ol_padxl=='undefined')var ol_padxl=1;if(typeof ol_padxr=='undefined')var ol_padxr=1;if(typeof ol_padyt=='undefined')var ol_padyt=1;if(typeof ol_padyb=='undefined')var ol_padyb=1;if(typeof ol_fullhtml=='undefined')var ol_fullhtml=0;if(typeof ol_vpos=='undefined')var ol_vpos=BELOW;if(typeof ol_aboveheight=='undefined')var ol_aboveheight=0;if(typeof ol_capicon=='undefined')var ol_capicon="";if(typeof ol_frame=='undefined')var ol_frame=self;if(typeof ol_timeout=='undefined')var ol_timeout=0;if(typeof ol_function=='undefined')var ol_function=null;if(typeof ol_delay=='undefined')var ol_delay=0;if(typeof ol_hauto=='undefined')var ol_hauto=0;if(typeof ol_vauto=='undefined')var ol_vauto=0;if(typeof ol_closeclick=='undefined')var ol_closeclick=0;if(typeof ol_wrap=='undefined')var ol_wrap=0;if(typeof ol_followmouse=='undefined')var ol_followmouse=1;if(typeof ol_mouseoff=='undefined')var ol_mouseoff=0;if(typeof ol_closetitle=='undefined')var ol_closetitle='Close';if(typeof ol_compatmode=='undefined')var ol_compatmode=0;if(typeof ol_css=='undefined')var ol_css=CSSOFF;if(typeof ol_fgclass=='undefined')var ol_fgclass="";if(typeof ol_bgclass=='undefined')var ol_bgclass="";if(typeof ol_textfontclass=='undefined')var ol_textfontclass="";if(typeof ol_captionfontclass=='undefined')var ol_captionfontclass="";if(typeof ol_closefontclass=='undefined')var ol_closefontclass="";
if(typeof ol_texts=='undefined')var ol_texts=new Array("Text 0","Text 1");if(typeof ol_caps=='undefined')var ol_caps=new Array("Caption 0","Caption 1");
var o3_text="",o3_cap="",o3_sticky=0,o3_background="",o3_close="Close",o3_hpos=RIGHT,o3_offsetx=2,o3_offsety=2,o3_fgcolor="",o3_bgcolor="",o3_textcolor="",o3_capcolor="",o3_closecolor="",o3_width=100,o3_border=1,o3_cellpad=2,o3_status="",o3_autostatus=0,o3_height=-1,o3_snapx=0,o3_snapy=0,o3_fixx=-1,o3_fixy=-1,o3_relx=null,o3_rely=null,o3_fgbackground="",o3_bgbackground="",o3_padxl=0,o3_padxr=0,o3_padyt=0,o3_padyb=0,o3_fullhtml=0,o3_vpos=BELOW,o3_aboveheight=0,o3_capicon="",o3_textfont="Verdana,Arial,Helvetica",o3_captionfont="Verdana,Arial,Helvetica",o3_closefont="Verdana,Arial,Helvetica",o3_textsize="1",o3_captionsize="1",o3_closesize="1",o3_frame=self,o3_timeout=0,o3_timerid=0,o3_allowmove=0,o3_function=null,o3_delay=0,o3_delayid=0,o3_hauto=0,o3_vauto=0,o3_closeclick=0,o3_wrap=0,o3_followmouse=1,o3_mouseoff=0,o3_closetitle='',o3_compatmode=0,o3_css=CSSOFF,o3_fgclass="",o3_bgclass="",o3_textfontclass="",o3_captionfontclass="",o3_closefontclass="";
var o3_x=0,o3_y=0,o3_showingsticky=0,o3_removecounter=0;
var over=null,fnRef,hoveringSwitch=false,olHideDelay;
var isMac=(navigator.userAgent.indexOf("Mac")!=-1),olOp=(navigator.userAgent.toLowerCase().indexOf('opera')>-1&&document.createTextNode),olNs4=(navigator.appName=='Netscape'&&parseInt(navigator.appVersion)==4),olNs6=(document.getElementById)?true:false,olKq=(olNs6&&/konqueror/i.test(navigator.userAgent)),olIe4=(document.all)?true:false,olIe5=false,olIe55=false,docRoot='document.body';
if(olNs4){var oW=window.innerWidth;var oH=window.innerHeight;window.onresize=function(){if(oW!=window.innerWidth||oH!=window.innerHeight)location.reload();}}
if(olIe4){var agent=navigator.userAgent;if(/MSIE/.test(agent)){var versNum=parseFloat(agent.match(/MSIE[ ](\d\.\d+)\.*/i)[1]);if(versNum>=5){olIe5=true;olIe55=(versNum>=5.5&&!olOp)?true:false;if(olNs6)olNs6=false;}}
if(olNs6)olIe4=false;}
if(document.compatMode&&document.compatMode=='CSS1Compat'){docRoot=((olIe4&&!olOp)?'document.documentElement':docRoot);}
if(window.addEventListener)window.addEventListener("load",OLonLoad_handler,false);else if(window.attachEvent)window.attachEvent("onload",OLonLoad_handler);
var capExtent;
function overlib(){if(!olLoaded||isExclusive(overlib.arguments))return true;if(olCheckMouseCapture)olMouseCapture();if(over){over=(typeof over.id!='string')?o3_frame.document.all['overDiv']:over;cClick();}
olHideDelay=0;o3_text=ol_text;o3_cap=ol_cap;o3_sticky=ol_sticky;o3_background=ol_background;o3_close=ol_close;o3_hpos=ol_hpos;o3_offsetx=ol_offsetx;o3_offsety=ol_offsety;o3_fgcolor=ol_fgcolor;o3_bgcolor=ol_bgcolor;o3_textcolor=ol_textcolor;o3_capcolor=ol_capcolor;o3_closecolor=ol_closecolor;o3_width=ol_width;o3_border=ol_border;o3_cellpad=ol_cellpad;o3_status=ol_status;o3_autostatus=ol_autostatus;o3_height=ol_height;o3_snapx=ol_snapx;o3_snapy=ol_snapy;o3_fixx=ol_fixx;o3_fixy=ol_fixy;o3_relx=ol_relx;o3_rely=ol_rely;o3_fgbackground=ol_fgbackground;o3_bgbackground=ol_bgbackground;o3_padxl=ol_padxl;o3_padxr=ol_padxr;o3_padyt=ol_padyt;o3_padyb=ol_padyb;o3_fullhtml=ol_fullhtml;o3_vpos=ol_vpos;o3_aboveheight=ol_aboveheight;o3_capicon=ol_capicon;o3_textfont=ol_textfont;o3_captionfont=ol_captionfont;o3_closefont=ol_closefont;o3_textsize=ol_textsize;o3_captionsize=ol_captionsize;o3_closesize=ol_closesize;o3_timeout=ol_timeout;o3_function=ol_function;o3_delay=ol_delay;o3_hauto=ol_hauto;o3_vauto=ol_vauto;o3_closeclick=ol_closeclick;o3_wrap=ol_wrap;o3_followmouse=ol_followmouse;o3_mouseoff=ol_mouseoff;o3_closetitle=ol_closetitle;o3_css=ol_css;o3_compatmode=ol_compatmode;o3_fgclass=ol_fgclass;o3_bgclass=ol_bgclass;o3_textfontclass=ol_textfontclass;o3_captionfontclass=ol_captionfontclass;o3_closefontclass=ol_closefontclass;
setRunTimeVariables();
fnRef='';
o3_frame=ol_frame;
if(!(over=createDivContainer()))return false;
parseTokens('o3_',overlib.arguments);if(!postParseChecks())return false;
if(o3_delay==0){return runHook("olMain",FREPLACE);}else{o3_delayid=setTimeout("runHook('olMain',FREPLACE)",o3_delay);return false;}}
function nd(time){if(olLoaded&&!isExclusive()){hideDelay(time);
if(o3_removecounter>=1){o3_showingsticky=0 };
if(o3_showingsticky==0){o3_allowmove=0;if(over!=null&&o3_timerid==0)runHook("hideObject",FREPLACE,over);}else{o3_removecounter++;}}
return true;}
function cClick(){if(olLoaded){runHook("hideObject",FREPLACE,over);o3_showingsticky=0;}
return false;}
function overlib_pagedefaults(){parseTokens('ol_',overlib_pagedefaults.arguments);}
function olMain(){var layerhtml,styleType;runHook("olMain",FBEFORE);
if(o3_background!=""||o3_fullhtml){
layerhtml=runHook('ol_content_background',FALTERNATE,o3_css,o3_text,o3_background,o3_fullhtml);}else{
styleType=(pms[o3_css-1-pmStart]=="cssoff"||pms[o3_css-1-pmStart]=="cssclass");
if(o3_fgbackground!="")o3_fgbackground="background=\""+o3_fgbackground+"\"";if(o3_bgbackground!="")o3_bgbackground=(styleType?"background=\""+o3_bgbackground+"\"":o3_bgbackground);
if(o3_fgcolor!="")o3_fgcolor=(styleType?"bgcolor=\""+o3_fgcolor+"\"":o3_fgcolor);if(o3_bgcolor!="")o3_bgcolor=(styleType?"bgcolor=\""+o3_bgcolor+"\"":o3_bgcolor);
if(o3_height>0)o3_height=(styleType?"height=\""+o3_height+"\"":o3_height);else o3_height="";
if(o3_cap==""){
layerhtml=runHook('ol_content_simple',FALTERNATE,o3_css,o3_text);}else{
if(o3_sticky){
layerhtml=runHook('ol_content_caption',FALTERNATE,o3_css,o3_text,o3_cap,o3_close);}else{
layerhtml=runHook('ol_content_caption',FALTERNATE,o3_css,o3_text,o3_cap,"");}}}
if(o3_sticky){if(o3_timerid>0){clearTimeout(o3_timerid);o3_timerid=0;}
o3_showingsticky=1;o3_removecounter=0;}
if(!runHook("createPopup",FREPLACE,layerhtml))return false;
if(o3_autostatus>0){o3_status=o3_text;if(o3_autostatus>1)o3_status=o3_cap;}
o3_allowmove=0;
if(o3_timeout>0){if(o3_timerid>0)clearTimeout(o3_timerid);o3_timerid=setTimeout("cClick()",o3_timeout);}
runHook("disp",FREPLACE,o3_status);runHook("olMain",FAFTER);
return(olOp&&event&&event.type=='mouseover'&&!o3_status)?'':(o3_status!='');}
function ol_content_simple(text){var cpIsMultiple=/,/.test(o3_cellpad);var txt='<table width="'+o3_width+'" border="0" cellpadding="'+o3_border+'" cellspacing="0" '+(o3_bgclass?'class="'+o3_bgclass+'"':o3_bgcolor+' '+o3_height)+'><tr><td><table width="100%" border="0" '+((olNs4||!cpIsMultiple)?'cellpadding="'+o3_cellpad+'" ':'')+'cellspacing="0" '+(o3_fgclass?'class="'+o3_fgclass+'"':o3_fgcolor+' '+o3_fgbackground+' '+o3_height)+'><tr><td valign="TOP"'+(o3_textfontclass?' class="'+o3_textfontclass+'">':((!olNs4&&cpIsMultiple)?' style="'+setCellPadStr(o3_cellpad)+'">':'>'))+(o3_textfontclass?'':wrapStr(0,o3_textsize,'text'))+text+(o3_textfontclass?'':wrapStr(1,o3_textsize))+'</td></tr></table></td></tr></table>';
set_background("");return txt;}
function ol_content_caption(text,title,close){var nameId,txt,cpIsMultiple=/,/.test(o3_cellpad);var closing,closeevent;
closing="";closeevent="onmouseover";if(o3_closeclick==1)closeevent=(o3_closetitle?"title='"+o3_closetitle+"'":"")+" onclick";if(o3_capicon!=""){nameId=' hspace=\"5\"'+' align=\"middle\" alt=\"\"';if(typeof o3_dragimg!='undefined'&&o3_dragimg)nameId=' hspace=\"5\"'+' name=\"'+o3_dragimg+'\" id=\"'+o3_dragimg+'\" align=\"middle\" alt=\"Drag Enabled\" title=\"Drag Enabled\"';o3_capicon='<img src=\"'+o3_capicon+'\"'+nameId+' />';}
if(close!="")
closing='<td '+(!o3_compatmode&&o3_closefontclass?'class="'+o3_closefontclass:'align="RIGHT')+'"><a href="javascript:return '+fnRef+'cClick();"'+((o3_compatmode&&o3_closefontclass)?' class="'+o3_closefontclass+'" ':' ')+closeevent+'="return '+fnRef+'cClick();">'+(o3_closefontclass?'':wrapStr(0,o3_closesize,'close'))+close+(o3_closefontclass?'':wrapStr(1,o3_closesize,'close'))+'</a></td>';txt='<table width="'+o3_width+'" border="0" cellpadding="'+o3_border+'" cellspacing="0" '+(o3_bgclass?'class="'+o3_bgclass+'"':o3_bgcolor+' '+o3_bgbackground+' '+o3_height)+'><tr><td><table width="100%" border="0" cellpadding="2" cellspacing="0"><tr><td'+(o3_captionfontclass?' class="'+o3_captionfontclass+'">':'>')+(o3_captionfontclass?'':'<b>'+wrapStr(0,o3_captionsize,'caption'))+o3_capicon+title+(o3_captionfontclass?'':wrapStr(1,o3_captionsize)+'</b>')+'</td>'+closing+'</tr></table><table width="100%" border="0" '+((olNs4||!cpIsMultiple)?'cellpadding="'+o3_cellpad+'" ':'')+'cellspacing="0" '+(o3_fgclass?'class="'+o3_fgclass+'"':o3_fgcolor+' '+o3_fgbackground+' '+o3_height)+'><tr><td valign="TOP"'+(o3_textfontclass?' class="'+o3_textfontclass+'">' :((!olNs4&&cpIsMultiple)?' style="'+setCellPadStr(o3_cellpad)+'">':'>'))+(o3_textfontclass?'':wrapStr(0,o3_textsize,'text'))+text+(o3_textfontclass?'':wrapStr(1,o3_textsize))+'</td></tr></table></td></tr></table>';
set_background("");return txt;}
function ol_content_background(text,picture,hasfullhtml){if(hasfullhtml){txt=text;}else{txt='<table width="'+o3_width+'" border="0" cellpadding="0" cellspacing="0" height="'+o3_height+'"><tr><td colspan="3" height="'+o3_padyt+'"></td></tr><tr><td width="'+o3_padxl+'"></td><td valign="TOP" width="'+(o3_width-o3_padxl-o3_padxr)+(o3_textfontclass?'" class="'+o3_textfontclass:'')+'">'+(o3_textfontclass?'':wrapStr(0,o3_textsize,'text'))+text+(o3_textfontclass?'':wrapStr(1,o3_textsize))+'</td><td width="'+o3_padxr+'"></td></tr><tr><td colspan="3" height="'+o3_padyb+'"></td></tr></table>';}
set_background(picture);return txt;}
function set_background(pic){if(pic==""){if(olNs4){over.background.src=null;}else if(over.style){over.style.backgroundImage="none";}
}else{if(olNs4){over.background.src=pic;}else if(over.style){over.style.width=o3_width+'px';over.style.backgroundImage="url("+pic+")";}}}
var olShowId=-1;
function disp(statustext){runHook("disp",FBEFORE);
if(o3_allowmove==0){runHook("placeLayer",FREPLACE);(olNs6&&olShowId<0)?olShowId=setTimeout("runHook('showObject',FREPLACE,over)",1):runHook("showObject",FREPLACE,over);o3_allowmove=(o3_sticky||o3_followmouse==0)?0:1;}
runHook("disp",FAFTER);
if(statustext!="")self.status=statustext;}
function createPopup(lyrContent){runHook("createPopup",FBEFORE);
if(o3_wrap){var wd,ww,theObj=(olNs4?over:over.style);theObj.top=theObj.left=((olIe4&&!olOp)?0:-10000)+(!olNs4?'px':0);layerWrite(lyrContent);wd=(olNs4?over.clip.width:over.offsetWidth);if(wd>(ww=windowWidth())){lyrContent=lyrContent.replace(/\&nbsp;/g,' ');o3_width=ww;o3_wrap=0;}}
layerWrite(lyrContent);
if(o3_wrap)o3_width=(olNs4?over.clip.width:over.offsetWidth);
runHook("createPopup",FAFTER,lyrContent);
return true;}
function placeLayer(){var placeX,placeY,widthFix=0;
if(o3_frame.innerWidth)widthFix=18;iwidth=windowWidth();
winoffset=(olIe4)?eval('o3_frame.'+docRoot+'.scrollLeft'):o3_frame.pageXOffset;
placeX=runHook('horizontalPlacement',FCHAIN,iwidth,winoffset,widthFix);
if(o3_frame.innerHeight){iheight=o3_frame.innerHeight;}else if(eval('o3_frame.'+docRoot)&&eval("typeof o3_frame."+docRoot+".clientHeight=='number'")&&eval('o3_frame.'+docRoot+'.clientHeight')){iheight=eval('o3_frame.'+docRoot+'.clientHeight');}
scrolloffset=(olIe4)?eval('o3_frame.'+docRoot+'.scrollTop'):o3_frame.pageYOffset;placeY=runHook('verticalPlacement',FCHAIN,iheight,scrolloffset);
repositionTo(over,placeX,placeY);}
function olMouseMove(e){var e=(e)?e:event;
if(e.pageX){o3_x=e.pageX;o3_y=e.pageY;}else if(e.clientX){o3_x=eval('e.clientX+o3_frame.'+docRoot+'.scrollLeft');o3_y=eval('e.clientY+o3_frame.'+docRoot+'.scrollTop');}
if(o3_allowmove==1)runHook("placeLayer",FREPLACE);
if(hoveringSwitch&&!olNs4&&runHook("cursorOff",FREPLACE)){(olHideDelay?hideDelay(olHideDelay):cClick());hoveringSwitch=!hoveringSwitch;}}
function no_overlib(){return ver3fix;}
function olMouseCapture(){capExtent=document;var fN,str='',l,k,f,wMv,sS,mseHandler=olMouseMove;var re=/function[ ]*(\w*)\(/;
wMv=(!olIe4&&window.onmousemove);if(document.onmousemove||wMv){if(wMv)capExtent=window;f=capExtent.onmousemove.toString();fN=f.match(re);if(fN==null){str=f+'(e);';}else if(fN[1]=='anonymous'||fN[1]=='olMouseMove'||(wMv&&fN[1]=='onmousemove')){if(!olOp&&wMv){l=f.indexOf('{')+1;k=f.lastIndexOf('}');sS=f.substring(l,k);if((l=sS.indexOf('('))!=-1){sS=sS.substring(0,l).replace(/^\s+/,'').replace(/\s+$/,'');if(eval("typeof "+sS+"=='undefined'"))window.onmousemove=null;else str=sS+'(e);';}}
if(!str){olCheckMouseCapture=false;return;}
}else{if(fN[1])str=fN[1]+'(e);';else{l=f.indexOf('{')+1;k=f.lastIndexOf('}');str=f.substring(l,k)+'\n';}}
str+='olMouseMove(e);';mseHandler=new Function('e',str);}
capExtent.onmousemove=mseHandler;if(olNs4)capExtent.captureEvents(Event.MOUSEMOVE);}
function parseTokens(pf,ar){
var v,i,mode=-1,par=(pf!='ol_'),fnMark=(par&&!ar.length?1:0);
for(i=0;i<ar.length;i++){if(mode<0){
if(typeof ar[i]=='number'&&ar[i]>pmStart&&ar[i]<pmUpper){fnMark=(par?1:0);i--;}else{switch(pf){case 'ol_':
ol_text=ar[i].toString();break;default:
o3_text=ar[i].toString();}}
mode=0;}else{
if(ar[i]>=pmCount||ar[i]==DONOTHING){continue;}
if(ar[i]==INARRAY){fnMark=0;eval(pf+'text=ol_texts['+ar[++i]+'].toString()');continue;}
if(ar[i]==CAPARRAY){eval(pf+'cap=ol_caps['+ar[++i]+'].toString()');continue;}
if(ar[i]==STICKY){if(pf!='ol_')eval(pf+'sticky=1');continue;}
if(ar[i]==BACKGROUND){eval(pf+'background="'+ar[++i]+'"');continue;}
if(ar[i]==NOCLOSE){if(pf!='ol_')opt_NOCLOSE();continue;}
if(ar[i]==CAPTION){eval(pf+"cap='"+escSglQuote(ar[++i])+"'");continue;}
if(ar[i]==CENTER||ar[i]==LEFT||ar[i]==RIGHT){eval(pf+'hpos='+ar[i]);if(pf!='ol_')olHautoFlag=1;continue;}
if(ar[i]==OFFSETX){eval(pf+'offsetx='+ar[++i]);continue;}
if(ar[i]==OFFSETY){eval(pf+'offsety='+ar[++i]);continue;}
if(ar[i]==FGCOLOR){eval(pf+'fgcolor="'+ar[++i]+'"');continue;}
if(ar[i]==BGCOLOR){eval(pf+'bgcolor="'+ar[++i]+'"');continue;}
if(ar[i]==TEXTCOLOR){eval(pf+'textcolor="'+ar[++i]+'"');continue;}
if(ar[i]==CAPCOLOR){eval(pf+'capcolor="'+ar[++i]+'"');continue;}
if(ar[i]==CLOSECOLOR){eval(pf+'closecolor="'+ar[++i]+'"');continue;}
if(ar[i]==WIDTH){eval(pf+'width='+ar[++i]);continue;}
if(ar[i]==BORDER){eval(pf+'border='+ar[++i]);continue;}
if(ar[i]==CELLPAD){i=opt_MULTIPLEARGS(++i,ar,(pf+'cellpad'));continue;}
if(ar[i]==STATUS){eval(pf+"status='"+escSglQuote(ar[++i])+"'");continue;}
if(ar[i]==AUTOSTATUS){eval(pf+'autostatus=('+pf+'autostatus==1)?0:1');continue;}
if(ar[i]==AUTOSTATUSCAP){eval(pf+'autostatus=('+pf+'autostatus==2)?0:2');continue;}
if(ar[i]==HEIGHT){eval(pf+'height='+pf+'aboveheight='+ar[++i]);continue;}
if(ar[i]==CLOSETEXT){eval(pf+"close='"+escSglQuote(ar[++i])+"'");continue;}
if(ar[i]==SNAPX){eval(pf+'snapx='+ar[++i]);continue;}
if(ar[i]==SNAPY){eval(pf+'snapy='+ar[++i]);continue;}
if(ar[i]==FIXX){eval(pf+'fixx='+ar[++i]);continue;}
if(ar[i]==FIXY){eval(pf+'fixy='+ar[++i]);continue;}
if(ar[i]==RELX){eval(pf+'relx='+ar[++i]);continue;}
if(ar[i]==RELY){eval(pf+'rely='+ar[++i]);continue;}
if(ar[i]==FGBACKGROUND){eval(pf+'fgbackground="'+ar[++i]+'"');continue;}
if(ar[i]==BGBACKGROUND){eval(pf+'bgbackground="'+ar[++i]+'"');continue;}
if(ar[i]==PADX){eval(pf+'padxl='+ar[++i]);eval(pf+'padxr='+ar[++i]);continue;}
if(ar[i]==PADY){eval(pf+'padyt='+ar[++i]);eval(pf+'padyb='+ar[++i]);continue;}
if(ar[i]==FULLHTML){if(pf!='ol_')eval(pf+'fullhtml=1');continue;}
if(ar[i]==BELOW||ar[i]==ABOVE){eval(pf+'vpos='+ar[i]);if(pf!='ol_')olVautoFlag=1;continue;}
if(ar[i]==CAPICON){eval(pf+'capicon="'+ar[++i]+'"');continue;}
if(ar[i]==TEXTFONT){eval(pf+"textfont='"+escSglQuote(ar[++i])+"'");continue;}
if(ar[i]==CAPTIONFONT){eval(pf+"captionfont='"+escSglQuote(ar[++i])+"'");continue;}
if(ar[i]==CLOSEFONT){eval(pf+"closefont='"+escSglQuote(ar[++i])+"'");continue;}
if(ar[i]==TEXTSIZE){eval(pf+'textsize="'+ar[++i]+'"');continue;}
if(ar[i]==CAPTIONSIZE){eval(pf+'captionsize="'+ar[++i]+'"');continue;}
if(ar[i]==CLOSESIZE){eval(pf+'closesize="'+ar[++i]+'"');continue;}
if(ar[i]==TIMEOUT){eval(pf+'timeout='+ar[++i]);continue;}
if(ar[i]==FUNCTION){if(pf=='ol_'){if(typeof ar[i+1]!='number'){v=ar[++i];ol_function=(typeof v=='function'?v:null);}}else{fnMark=0;v=null;if(typeof ar[i+1]!='number')v=ar[++i]; opt_FUNCTION(v);} continue;}
if(ar[i]==DELAY){eval(pf+'delay='+ar[++i]);continue;}
if(ar[i]==HAUTO){eval(pf+'hauto=('+pf+'hauto==0)?1:0');continue;}
if(ar[i]==VAUTO){eval(pf+'vauto=('+pf+'vauto==0)?1:0');continue;}
if(ar[i]==CLOSECLICK){eval(pf+'closeclick=('+pf+'closeclick==0)?1:0');continue;}
if(ar[i]==WRAP){eval(pf+'wrap=('+pf+'wrap==0)?1:0');continue;}
if(ar[i]==FOLLOWMOUSE){eval(pf+'followmouse=('+pf+'followmouse==1)?0:1');continue;}
if(ar[i]==MOUSEOFF){eval(pf+'mouseoff=('+pf+'mouseoff==0)?1:0');v=ar[i+1];if(pf!='ol_'&&eval(pf+'mouseoff')&&typeof v=='number'&&(v<pmStart||v>pmUpper))olHideDelay=ar[++i];continue;}
if(ar[i]==CLOSETITLE){eval(pf+"closetitle='"+escSglQuote(ar[++i])+"'");continue;}
if(ar[i]==CSSOFF||ar[i]==CSSCLASS){eval(pf+'css='+ar[i]);continue;}
if(ar[i]==COMPATMODE){eval(pf+'compatmode=('+pf+'compatmode==0)?1:0');continue;}
if(ar[i]==FGCLASS){eval(pf+'fgclass="'+ar[++i]+'"');continue;}
if(ar[i]==BGCLASS){eval(pf+'bgclass="'+ar[++i]+'"');continue;}
if(ar[i]==TEXTFONTCLASS){eval(pf+'textfontclass="'+ar[++i]+'"');continue;}
if(ar[i]==CAPTIONFONTCLASS){eval(pf+'captionfontclass="'+ar[++i]+'"');continue;}
if(ar[i]==CLOSEFONTCLASS){eval(pf+'closefontclass="'+ar[++i]+'"');continue;}
i=parseCmdLine(pf,i,ar);}}
if(fnMark&&o3_function)o3_text=o3_function();
if((pf=='o3_')&&o3_wrap){o3_width=0;
var tReg=/<.*\n*>/ig;if(!tReg.test(o3_text))o3_text=o3_text.replace(/[ ]+/g,'&nbsp;');if(!tReg.test(o3_cap))o3_cap=o3_cap.replace(/[ ]+/g,'&nbsp;');}
if((pf=='o3_')&&o3_sticky){if(!o3_close&&(o3_frame!=ol_frame))o3_close=ol_close;if(o3_mouseoff&&(o3_frame==ol_frame))opt_NOCLOSE(' ');}}
function layerWrite(txt){txt+="\n";if(olNs4){var lyr=o3_frame.document.layers['overDiv'].document
lyr.write(txt)
lyr.close()
}else if(typeof over.innerHTML!='undefined'){if(olIe5&&isMac)over.innerHTML='';over.innerHTML=txt;}else{range=o3_frame.document.createRange();range.setStartAfter(over);domfrag=range.createContextualFragment(txt);
while(over.hasChildNodes()){over.removeChild(over.lastChild);}
over.appendChild(domfrag);}}
function showObject(obj){runHook("showObject",FBEFORE);
var theObj=(olNs4?obj:obj.style);theObj.visibility='visible';
runHook("showObject",FAFTER);}
function hideObject(obj){runHook("hideObject",FBEFORE);
var theObj=(olNs4?obj:obj.style);if(olNs6&&olShowId>0){clearTimeout(olShowId);olShowId=0;}
theObj.visibility='hidden';theObj.top=theObj.left=((olIe4&&!olOp)?0:-10000)+(!olNs4?'px':0);
if(o3_timerid>0)clearTimeout(o3_timerid);if(o3_delayid>0)clearTimeout(o3_delayid);
o3_timerid=0;o3_delayid=0;self.status="";
if(obj.onmouseout||obj.onmouseover){if(olNs4)obj.releaseEvents(Event.MOUSEOUT||Event.MOUSEOVER);obj.onmouseout=obj.onmouseover=null;}
runHook("hideObject",FAFTER);}
function repositionTo(obj,xL,yL){var theObj=(olNs4?obj:obj.style);theObj.left=xL+(!olNs4?'px':0);theObj.top=yL+(!olNs4?'px':0);}
function cursorOff(){var left=parseInt(over.style.left);var top=parseInt(over.style.top);var right=left+(over.offsetWidth>=parseInt(o3_width)?over.offsetWidth:parseInt(o3_width));var bottom=top+(over.offsetHeight>=o3_aboveheight?over.offsetHeight:o3_aboveheight);
if(o3_x<left||o3_x>right||o3_y<top||o3_y>bottom)return true;
return false;}
function opt_FUNCTION(callme){o3_text=(callme?(typeof callme=='string'?(/.+\(.*\)/.test(callme)?eval(callme):callme):callme()):(o3_function?o3_function():'No Function'));
return 0;}
function opt_NOCLOSE(unused){if(!unused)o3_close="";
if(olNs4){over.captureEvents(Event.MOUSEOUT||Event.MOUSEOVER);over.onmouseover=function(){if(o3_timerid>0){clearTimeout(o3_timerid);o3_timerid=0;} }
over.onmouseout=function(e){if(olHideDelay)hideDelay(olHideDelay);else cClick(e);}
}else{over.onmouseover=function(){hoveringSwitch=true;if(o3_timerid>0){clearTimeout(o3_timerid);o3_timerid=0;} }}
return 0;}
function opt_MULTIPLEARGS(i,args,parameter){var k=i,re,pV,str='';
for(k=i;k<args.length;k++){if(typeof args[k]=='number'&&args[k]>pmStart)break;str+=args[k]+',';}
if(str)str=str.substring(0,--str.length);
k--;pV=(olNs4&&/cellpad/i.test(parameter))?str.split(',')[0]:str;eval(parameter+'="'+pV+'"');
return k;}
function nbspCleanup(){if(o3_wrap){o3_text=o3_text.replace(/\&nbsp;/g,' ');o3_cap=o3_cap.replace(/\&nbsp;/g,' ');}}
function escSglQuote(str){return str.toString().replace(/'/g,"\\'");}
function OLonLoad_handler(e){var re=/\w+\(.*\)[;\s]+/g,olre=/overlib\(|nd\(|cClick\(/,fn,l,i;
if(!olLoaded)olLoaded=1;
if(window.removeEventListener&&e.eventPhase==3)window.removeEventListener("load",OLonLoad_handler,false);else if(window.detachEvent){window.detachEvent("onload",OLonLoad_handler);var fN=document.body.getAttribute('onload');if(fN){fN=fN.toString().match(re);if(fN&&fN.length){for(i=0;i<fN.length;i++){if(/anonymous/.test(fN[i]))continue;while((l=fN[i].search(/\)[;\s]+/))!=-1){fn=fN[i].substring(0,l+1);fN[i]=fN[i].substring(l+2);if(olre.test(fn))eval(fn);}}}}}}
function wrapStr(endWrap,fontSizeStr,whichString){var fontStr,fontColor,isClose=((whichString=='close')?1:0),hasDims=/[%\-a-z]+$/.test(fontSizeStr);fontSizeStr=(olNs4)?(!hasDims?fontSizeStr:'1'):fontSizeStr;if(endWrap)return(hasDims&&!olNs4)?(isClose?'</span>':'</div>'):'</font>';else{fontStr='o3_'+whichString+'font';fontColor='o3_'+((whichString=='caption')? 'cap':whichString)+'color';return(hasDims&&!olNs4)?(isClose?'<span style="font-family: '+quoteMultiNameFonts(eval(fontStr))+';color: '+eval(fontColor)+';font-size: '+fontSizeStr+';">':'<div style="font-family: '+quoteMultiNameFonts(eval(fontStr))+';color: '+eval(fontColor)+';font-size: '+fontSizeStr+';">'):'<font face="'+eval(fontStr)+'" color="'+eval(fontColor)+'" size="'+(parseInt(fontSizeStr)>7?'7':fontSizeStr)+'">';}}
function quoteMultiNameFonts(theFont){var v,pM=theFont.split(',');for(var i=0;i<pM.length;i++){v=pM[i];v=v.replace(/^\s+/,'').replace(/\s+$/,'');if(/\s/.test(v)&&!/['"]/.test(v)){v="\'"+v+"\'";pM[i]=v;}}
return pM.join();}
function isExclusive(args){return false;}
function setCellPadStr(parameter){var Str='',j=0,ary=new Array(),top,bottom,left,right;
Str+='padding: ';ary=parameter.replace(/\s+/g,'').split(',');
switch(ary.length){case 2:
top=bottom=ary[j];left=right=ary[++j];break;case 3:
top=ary[j];left=right=ary[++j];bottom=ary[++j];break;case 4:
top=ary[j];right=ary[++j];bottom=ary[++j];left=ary[++j];break;}
Str+=((ary.length==1)?ary[0]+'px;':top+'px '+right+'px '+bottom+'px '+left+'px;');
return Str;}
function hideDelay(time){if(time&&!o3_delay){if(o3_timerid>0)clearTimeout(o3_timerid);
o3_timerid=setTimeout("cClick()",(o3_timeout=time));}}
function horizontalPlacement(browserWidth,horizontalScrollAmount,widthFix){var placeX,iwidth=browserWidth,winoffset=horizontalScrollAmount;var parsedWidth=parseInt(o3_width);
if(o3_fixx>-1||o3_relx!=null){
placeX=(o3_relx!=null?( o3_relx<0?winoffset+o3_relx+iwidth-parsedWidth-widthFix:winoffset+o3_relx):o3_fixx);}else{
if(o3_hauto==1){if((o3_x-winoffset)>(iwidth/2)){o3_hpos=LEFT;}else{o3_hpos=RIGHT;}}
if(o3_hpos==CENTER){placeX=o3_x+o3_offsetx-(parsedWidth/2);
if(placeX<winoffset)placeX=winoffset;}
if(o3_hpos==RIGHT){placeX=o3_x+o3_offsetx;
if((placeX+parsedWidth)>(winoffset+iwidth-widthFix)){placeX=iwidth+winoffset-parsedWidth-widthFix;if(placeX<0)placeX=0;}}
if(o3_hpos==LEFT){placeX=o3_x-o3_offsetx-parsedWidth;if(placeX<winoffset)placeX=winoffset;}
if(o3_snapx>1){var snapping=placeX % o3_snapx;
if(o3_hpos==LEFT){placeX=placeX-(o3_snapx+snapping);}else{
placeX=placeX+(o3_snapx-snapping);}
if(placeX<winoffset)placeX=winoffset;}}
return placeX;}
function verticalPlacement(browserHeight,verticalScrollAmount){var placeY,iheight=browserHeight,scrolloffset=verticalScrollAmount;var parsedHeight=(o3_aboveheight?parseInt(o3_aboveheight):(olNs4?over.clip.height:over.offsetHeight));
if(o3_fixy>-1||o3_rely!=null){
placeY=(o3_rely!=null?(o3_rely<0?scrolloffset+o3_rely+iheight-parsedHeight:scrolloffset+o3_rely):o3_fixy);}else{
if(o3_vauto==1){if((o3_y-scrolloffset)>(iheight/2)&&o3_vpos==BELOW&&(o3_y+parsedHeight+o3_offsety-(scrolloffset+iheight)>0)){o3_vpos=ABOVE;}else if(o3_vpos==ABOVE&&(o3_y-(parsedHeight+o3_offsety)-scrolloffset<0)){o3_vpos=BELOW;}}
if(o3_vpos==ABOVE){if(o3_aboveheight==0)o3_aboveheight=parsedHeight;
placeY=o3_y-(o3_aboveheight+o3_offsety);if(placeY<scrolloffset)placeY=scrolloffset;}else{
placeY=o3_y+o3_offsety;}
if(o3_snapy>1){var snapping=placeY % o3_snapy;
if(o3_aboveheight>0&&o3_vpos==ABOVE){placeY=placeY-(o3_snapy+snapping);}else{placeY=placeY+(o3_snapy-snapping);}
if(placeY<scrolloffset)placeY=scrolloffset;}}
return placeY;}
function checkPositionFlags(){if(olHautoFlag)olHautoFlag=o3_hauto=0;if(olVautoFlag)olVautoFlag=o3_vauto=0;return true;}
function windowWidth(){var w;if(o3_frame.innerWidth)w=o3_frame.innerWidth;else if(eval('o3_frame.'+docRoot)&&eval("typeof o3_frame."+docRoot+".clientWidth=='number'")&&eval('o3_frame.'+docRoot+'.clientWidth'))
w=eval('o3_frame.'+docRoot+'.clientWidth');return w;}
function createDivContainer(id,frm,zValue){id=(id||'overDiv'),frm=(frm||o3_frame),zValue=(zValue||1000);var objRef,divContainer=layerReference(id);
if(divContainer==null){if(olNs4){divContainer=frm.document.layers[id]=new Layer(window.innerWidth,frm);objRef=divContainer;}else{var body=(olIe4?frm.document.all.tags('BODY')[0]:frm.document.getElementsByTagName("BODY")[0]);if(olIe4&&!document.getElementById){body.insertAdjacentHTML("beforeEnd",'<div id="'+id+'"></div>');divContainer=layerReference(id);}else{divContainer=frm.document.createElement("DIV");divContainer.id=id;body.appendChild(divContainer);}
objRef=divContainer.style;}
objRef.position='absolute';objRef.visibility='hidden';objRef.zIndex=zValue;if(olIe4&&!olOp)objRef.left=objRef.top='0px';else objRef.left=objRef.top=-10000+(!olNs4?'px':0);}
return divContainer;}
function layerReference(id){return(olNs4?o3_frame.document.layers[id]:(document.all?o3_frame.document.all[id]:o3_frame.document.getElementById(id)));}
function isFunction(fnRef){var rtn=true;
if(typeof fnRef=='object'){for(var i=0;i<fnRef.length;i++){if(typeof fnRef[i]=='function')continue;rtn=false;break;}
}else if(typeof fnRef!='function'){rtn=false;}
return rtn;}
function argToString(array,strtInd,argName){var jS=strtInd,aS='',ar=array;argName=(argName?argName:'ar');
if(ar.length>jS){for(var k=jS;k<ar.length;k++)aS+=argName+'['+k+'], ';aS=aS.substring(0,aS.length-2);}
return aS;}
function reOrder(hookPt,fnRef,order){var newPt=new Array(),match,i,j;
if(!order||typeof order=='undefined'||typeof order=='number')return hookPt;
if(typeof order=='function'){if(typeof fnRef=='object'){newPt=newPt.concat(fnRef);}else{newPt[newPt.length++]=fnRef;}
for(i=0;i<hookPt.length;i++){match=false;if(typeof fnRef=='function'&&hookPt[i]==fnRef){continue;}else{for(j=0;j<fnRef.length;j++)if(hookPt[i]==fnRef[j]){match=true;break;}}
if(!match)newPt[newPt.length++]=hookPt[i];}
newPt[newPt.length++]=order;
}else if(typeof order=='object'){if(typeof fnRef=='object'){newPt=newPt.concat(fnRef);}else{newPt[newPt.length++]=fnRef;}
for(j=0;j<hookPt.length;j++){match=false;if(typeof fnRef=='function'&&hookPt[j]==fnRef){continue;}else{for(i=0;i<fnRef.length;i++)if(hookPt[j]==fnRef[i]){match=true;break;}}
if(!match)newPt[newPt.length++]=hookPt[j];}
for(i=0;i<newPt.length;i++)hookPt[i]=newPt[i];newPt.length=0;
for(j=0;j<hookPt.length;j++){match=false;for(i=0;i<order.length;i++){if(hookPt[j]==order[i]){match=true;break;}}
if(!match)newPt[newPt.length++]=hookPt[j];}
newPt=newPt.concat(order);}
hookPt=newPt;
return hookPt;}
function setRunTimeVariables(){if(typeof runTime!='undefined'&&runTime.length){for(var k=0;k<runTime.length;k++){runTime[k]();}}}
function parseCmdLine(pf,i,args){if(typeof cmdLine!='undefined'&&cmdLine.length){for(var k=0;k<cmdLine.length;k++){var j=cmdLine[k](pf,i,args);if(j >-1){i=j;break;}}}
return i;}
function postParseChecks(pf,args){if(typeof postParse!='undefined'&&postParse.length){for(var k=0;k<postParse.length;k++){if(postParse[k](pf,args))continue;return false;}}
return true;}
function registerCommands(cmdStr){if(typeof cmdStr!='string')return;
var pM=cmdStr.split(',');pms=pms.concat(pM);
for(var i=0;i< pM.length;i++){eval(pM[i].toUpperCase()+'='+pmCount++);}}
function registerNoParameterCommands(cmdStr){if(!cmdStr&&typeof cmdStr!='string')return;pmt=(!pmt)?cmdStr:pmt+','+cmdStr;}
function registerHook(fnHookTo,fnRef,hookType,optPm){var hookPt,last=typeof optPm;
if(fnHookTo=='plgIn'||fnHookTo=='postParse')return;if(typeof hookPts[fnHookTo]=='undefined')hookPts[fnHookTo]=new FunctionReference();
hookPt=hookPts[fnHookTo];
if(hookType!=null){if(hookType==FREPLACE){hookPt.ovload=fnRef;if(fnHookTo.indexOf('ol_content_')>-1)hookPt.alt[pms[CSSOFF-1-pmStart]]=fnRef;
}else if(hookType==FBEFORE||hookType==FAFTER){var hookPt=(hookType==1?hookPt.before:hookPt.after);
if(typeof fnRef=='object'){hookPt=hookPt.concat(fnRef);}else{hookPt[hookPt.length++]=fnRef;}
if(optPm)hookPt=reOrder(hookPt,fnRef,optPm);
}else if(hookType==FALTERNATE){if(last=='number')hookPt.alt[pms[optPm-1-pmStart]]=fnRef;}else if(hookType==FCHAIN){hookPt=hookPt.chain;if(typeof fnRef=='object')hookPt=hookPt.concat(fnRef);else hookPt[hookPt.length++]=fnRef;}
return;}}
function registerRunTimeFunction(fn){if(isFunction(fn)){if(typeof fn=='object'){runTime=runTime.concat(fn);}else{runTime[runTime.length++]=fn;}}}
function registerCmdLineFunction(fn){if(isFunction(fn)){if(typeof fn=='object'){cmdLine=cmdLine.concat(fn);}else{cmdLine[cmdLine.length++]=fn;}}}
function registerPostParseFunction(fn){if(isFunction(fn)){if(typeof fn=='object'){postParse=postParse.concat(fn);}else{postParse[postParse.length++]=fn;}}}
function runHook(fnHookTo,hookType){var l=hookPts[fnHookTo],k,rtnVal=null,optPm,arS,ar=runHook.arguments;
if(hookType==FREPLACE){arS=argToString(ar,2);
if(typeof l=='undefined'||!(l=l.ovload))rtnVal=eval(fnHookTo+'('+arS+')');else rtnVal=eval('l('+arS+')');
}else if(hookType==FBEFORE||hookType==FAFTER){if(typeof l!='undefined'){l=(hookType==1?l.before:l.after);
if(l.length){arS=argToString(ar,2);for(var k=0;k<l.length;k++)eval('l[k]('+arS+')');}}
}else if(hookType==FALTERNATE){optPm=ar[2];arS=argToString(ar,3);
if(typeof l=='undefined'||(l=l.alt[pms[optPm-1-pmStart]])=='undefined'){rtnVal=eval(fnHookTo+'('+arS+')');}else{rtnVal=eval('l('+arS+')');}
}else if(hookType==FCHAIN){arS=argToString(ar,2);l=l.chain;
for(k=l.length;k>0;k--)if((rtnVal=eval('l[k-1]('+arS+')'))!=void(0))break;}
return rtnVal;}
function FunctionReference(){this.ovload=null;this.before=new Array();this.after=new Array();this.alt=new Array();this.chain=new Array();}
function Info(version,prerelease){this.version=version;this.prerelease=prerelease;
this.simpleversion=Math.round(this.version*100);this.major=parseInt(this.simpleversion/100);this.minor=parseInt(this.simpleversion/10)-this.major * 10;this.revision=parseInt(this.simpleversion)-this.major * 100-this.minor * 10;this.meets=meets;}
function meets(reqdVersion){return(!reqdVersion)?false:this.simpleversion>=Math.round(100*parseFloat(reqdVersion));}
registerHook("ol_content_simple",ol_content_simple,FALTERNATE,CSSOFF);registerHook("ol_content_caption",ol_content_caption,FALTERNATE,CSSOFF);registerHook("ol_content_background",ol_content_background,FALTERNATE,CSSOFF);registerHook("ol_content_simple",ol_content_simple,FALTERNATE,CSSCLASS);registerHook("ol_content_caption",ol_content_caption,FALTERNATE,CSSCLASS);registerHook("ol_content_background",ol_content_background,FALTERNATE,CSSCLASS);registerPostParseFunction(checkPositionFlags);registerHook("hideObject",nbspCleanup,FAFTER);registerHook("horizontalPlacement",horizontalPlacement,FCHAIN);registerHook("verticalPlacement",verticalPlacement,FCHAIN);if(olNs4||(olIe5&&isMac)||olKq)olLoaded=1;registerNoParameterCommands('sticky,autostatus,autostatuscap,fullhtml,hauto,vauto,closeclick,wrap,followmouse,mouseoff,compatmode');
var olCheckMouseCapture=true;if((olNs4||olNs6||olIe4)){olMouseCapture();}else{overlib=no_overlib;nd=no_overlib;ver3fix=true;}// --FILE BOUNDARY-- // --FILE BOUNDARY-- // --FILE BOUNDARY--
/**************************************************
 * dom-drag.js
 * 09.25.2001
 * www.youngpup.net
 **************************************************
 * 10.28.2001 - fixed minor bug where events
 * sometimes fired off the handle, not the root.
 **************************************************/

// Minor modifications by [[User:Lupin]]

var Drag = {

    obj : null,

    init : function(o, oRoot, minX, maxX, minY, maxY, bSwapHorzRef, bSwapVertRef, fXMapper, fYMapper)
    {
        o.onmousedown    = Drag.start;
        o.dragging       = false;
        o.draggable      = true;
        o.hmode          = bSwapHorzRef ? false : true ;
        o.vmode          = bSwapVertRef ? false : true ;

        o.root = oRoot && oRoot != null ? oRoot : o ;

        if (o.hmode  && isNaN(parseInt(o.root.style.left  ))) o.root.style.left   = "0px";
        if (o.vmode  && isNaN(parseInt(o.root.style.top   ))) o.root.style.top    = "0px";
        if (!o.hmode && isNaN(parseInt(o.root.style.right ))) o.root.style.right  = "0px";
        if (!o.vmode && isNaN(parseInt(o.root.style.bottom))) o.root.style.bottom = "0px";

        o.minX    = typeof minX != 'undefined' ? minX : null;
        o.minY    = typeof minY != 'undefined' ? minY : null;
        o.maxX    = typeof maxX != 'undefined' ? maxX : null;
        o.maxY    = typeof maxY != 'undefined' ? maxY : null;

        o.xMapper = fXMapper ? fXMapper : null;
        o.yMapper = fYMapper ? fYMapper : null;

        o.root.onDragStart    = new Function();
        o.root.onDragEnd    = new Function();
        o.root.onDrag        = new Function();
    },

    start : function(e)
    {
        var o = Drag.obj = this;
        e = Drag.fixE(e);
        var y = parseInt(o.vmode ? o.root.style.top  : o.root.style.bottom);
        var x = parseInt(o.hmode ? o.root.style.left : o.root.style.right );
        o.root.onDragStart(x, y);

        o.lastMouseX    = e.clientX;
        o.lastMouseY    = e.clientY;

        if (o.hmode) {
            if (o.minX != null)    o.minMouseX    = e.clientX - x + o.minX;
            if (o.maxX != null)    o.maxMouseX    = o.minMouseX + o.maxX - o.minX;
        } else {
            if (o.minX != null) o.maxMouseX = -o.minX + e.clientX + x;
            if (o.maxX != null) o.minMouseX = -o.maxX + e.clientX + x;
        }

        if (o.vmode) {
            if (o.minY != null)    o.minMouseY    = e.clientY - y + o.minY;
            if (o.maxY != null)    o.maxMouseY    = o.minMouseY + o.maxY - o.minY;
        } else {
            if (o.minY != null) o.maxMouseY = -o.minY + e.clientY + y;
            if (o.maxY != null) o.minMouseY = -o.maxY + e.clientY + y;
        }

        o.onmousemoveDefault    = document.onmousemove;
        o.dragging              = true;
        document.onmousemove    = Drag.drag;
        document.onmouseup      = Drag.end;

        return false;
    },

    drag : function(e)
    {
        e = Drag.fixE(e);
        var o = Drag.obj;

        var ey    = e.clientY;
        var ex    = e.clientX;
        var y = parseInt(o.vmode ? o.root.style.top  : o.root.style.bottom);
        var x = parseInt(o.hmode ? o.root.style.left : o.root.style.right );
        var nx, ny;

        if (o.minX != null) ex = o.hmode ? Math.max(ex, o.minMouseX) : Math.min(ex, o.maxMouseX);
        if (o.maxX != null) ex = o.hmode ? Math.min(ex, o.maxMouseX) : Math.max(ex, o.minMouseX);
        if (o.minY != null) ey = o.vmode ? Math.max(ey, o.minMouseY) : Math.min(ey, o.maxMouseY);
        if (o.maxY != null) ey = o.vmode ? Math.min(ey, o.maxMouseY) : Math.max(ey, o.minMouseY);

        nx = x + ((ex - o.lastMouseX) * (o.hmode ? 1 : -1));
        ny = y + ((ey - o.lastMouseY) * (o.vmode ? 1 : -1));

        if (o.xMapper)        nx = o.xMapper(y)
        else if (o.yMapper)    ny = o.yMapper(x)

        Drag.obj.root.style[o.hmode ? "left" : "right"] = nx + "px";
        Drag.obj.root.style[o.vmode ? "top" : "bottom"] = ny + "px";
        Drag.obj.lastMouseX    = ex;
        Drag.obj.lastMouseY    = ey;

        Drag.obj.root.onDrag(nx, ny);
        return false;
    },

    end : function()
    {
        //Document.onmousemove = null;
        document.onmousemove=Drag.obj.onmousemoveDefault;
        document.onmouseup   = null;
        Drag.obj.dragging    = false;
        Drag.obj.root.onDragEnd(    parseInt(Drag.obj.root.style[Drag.obj.hmode ? "left" : "right"]), 
                                    parseInt(Drag.obj.root.style[Drag.obj.vmode ? "top" : "bottom"]));
        Drag.obj = null;
    },

    fixE : function(e)
    {
        if (typeof e == 'undefined') e = window.event;
        if (typeof e.layerX == 'undefined') e.layerX = e.offsetX;
        if (typeof e.layerY == 'undefined') e.layerY = e.offsetY;
        return e;
    }
};

// Copyright Aaron Boodman. Saying stupid things daily since March 2001.
// --FILE BOUNDARY-- // --FILE BOUNDARY-- // --FILE BOUNDARY--
/*
 * Javascript Diff Algorithm
 *  By John Resig (http://ejohn.org/) and [[:en:User:Lupin]]
 *
 * More Info:
 *  http://ejohn.org/projects/javascript-diff-algorithm/
 */

function diffEscape(n) {
    return n.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;")
      .replace(RegExp('"','g'), "&quot;");
}
function delFmt(x) { 
  if (!x.length) return ''; 
  return "<del style='background:#FFE6E6;'>" + diffEscape(x.join('')).split('\n').join('&para;\n') +"</del>"; 
}
function insFmt(x) { 
  if (!x.length) return '';
  return "<ins style='background:#AAFFEE;'>" + diffEscape(x.join('')).split('\n').join('&para;\n') +"</ins>"; 
}

function copyDiffObj(x){
  var ret=[];
  for (var i=0; i<x.length; ++i) {
    if (typeof x[i] == 'string') ret[i]=x[i];
    else {
      ret[i]={};
      for (var prop in x[i]) ret[i][prop]=x[i][prop];
    }
  }
  return ret;
}

window.countCrossings=function(a, b, i, eject) {
  // count the crossings on the edge starting at b[i]
  if (b[i].row==null) return -1;
  var count=0;
  for (var j=0; j<a.length; ++j) {
    if (a[j].row==null) continue;
    if ( (j-b[i].row)*(i-a[j].row) > 0) { if(eject) return true; count++; }
  }
  return count;
}

//de=document.createElement('div');
//de.id='debug'
//ti=document.getElementsByTagName('h1')[0];
//ti.parentNode.appendChild(de);

//function debug(s){
//  try {document.getElementById('debug').innerHTML+=s+'<br>'; } catch(foo) {};
//}

function untangle( a, b) {
  // try to remove crossing edges from an ordered bipartite graph,
  // removing the least number possible
  var aa=copyDiffObj(a);
  var bb=copyDiffObj(b);

  // remove the edge with the largest number of crossings until no
  // crossings remain
  do {
    var maxCrossings=0;
    var worstEdge=null;
    for (var i=0; i<bb.length; ++i) {
      var c=countCrossings(aa,bb,i);
      if (c > maxCrossings) { maxCrossings=c; worstEdge=i; }
    }
    if (worstEdge!=null) {
      aa[ bb[worstEdge].row ] = aa[ bb[worstEdge].row ].text;
      bb[worstEdge] = bb[worstEdge].text;
    }
  } while (maxCrossings > 0);
  return { a: aa, b: bb };
}

window.max=function(a,b){return a<b ? b : a;}
window.min=function(a,b){return a>b ? b : a;}

window.shortenDiffString=function(str, context) {
  var re=RegExp('(<del[\\s\\S]*?</del>|<ins[\\s\\S]*?</ins>)');
  var splitted=str.parenSplit(re);
  var ret=[''];
  for (var i=0; i<splitted.length; i+=2) {
    if (splitted[i].length < 2*context) {
      ret[ret.length-1] += splitted[i];
      if (i+1<splitted.length) ret[ret.length-1] += splitted[i+1];
      continue;
    }
    else {
      if (i > 0) ret[ret.length-1] += splitted[i].substring(0,context);
      if (i+1 < splitted.length) ret.push(splitted[i].substring(splitted[i].length-context) + splitted[i+1]);
    }
  }
  return ret;
}
  

window.diffString=function( o, n, slow ) {
  var splitRe=RegExp('([[]{2}|[\]]{2}|[{]{2,3}|[}]{2,3}|[|]|=|[*:]+|\\b)');
  var out;
  if (window.popups_isIE) out = diff( o.split(/\b/), n.split(/\b/) );
  else out = diff( o.parenSplit(splitRe), n.parenSplit(splitRe) );
  var str = "";
  var acc=[]; // accumulator for prettier output

  // crossing pairings -- 'A B' vs 'B A' -- cause problems, so let's iron them out 
  if (slow) {
    var untangled=untangle(out.o, out.n); // <-- too slow!
    out.o=untangled.a; out.n=untangled.b;
  } else {
    var maxOutputPair=0;
    for (var i=0; i<out.n.length; ++i) {
      if ( out.n[i].row != null) { 
        if( maxOutputPair > out.n[i].row ) {
          // tangle - delete pairing
          out.o[ out.n[i].row ]=out.o[ out.n[i].row ].text;
          out.n[i]=out.n[i].text;
        }
        if (maxOutputPair < out.n[i].row) maxOutputPair = out.n[i].row;
      }
    }
  }

  // output the stuff preceding the first paired old line 
  for (var i=0; i<out.o.length && out.o[i].text == null; ++i) acc.push( out.o[i] );
  str += delFmt(acc); acc=[];
  
  // main loop 
  for ( var i = 0; i < out.n.length; ++i ) {
    // output unpaired new "lines" 
    while ( i < out.n.length && out.n[i].text == null ) acc.push( out.n[i++] ); 
    str += insFmt(acc); acc=[]; 
    if ( i < out.n.length ) { // this new "line" is paired with the (out.n[i].row)th old "line" 
      str += out.n[i].text;
      // output unpaired old rows starting after this new line's partner 
      var m = out.n[i].row + 1; 
      while ( m < out.o.length && out.o[m].text == null ) acc.push ( out.o[m++] );
      str += delFmt(acc); acc=[];
    }
  }
  return str;
}

window.jsReservedProperties=RegExp('^((un)?watch|toString|eval)$');
window.diffBugAlerts='';


function diffBugAlert(word) {
  if (diffBugAlerts.indexOf(word+'\n')==-1) {
    diffBugAlerts+=word+'\n';
    alert('Bad word: '+word+'\n\nPlease report this bug.'); 
  }
}

function diff( o, n ) {
  var ns = new Object();
  var os = new Object();
  
  // pass 1: make hashtable ns with new rows as keys
  for ( var i = 0; i < n.length; i++ ) {
    if ( jsReservedProperties.test(n[i]) ) n[i] += '<!-- -->';
    if ( ns[ n[i] ] == null )
      ns[ n[i] ] = { rows: new Array(), o: null };
    try { ns[ n[i] ].rows.push( i ); } catch (err) { diffBugAlert(n[i]); }
  }
  
  // pass 2: make hashtable os with old rows as keys
  for ( var i = 0; i < o.length; i++ ) {
    if ( jsReservedProperties.test(o[i]) ) o[i] += '<!-- -->';
    if ( os[ o[i] ] == null )
      os[ o[i] ] = { rows: new Array(), n: null };
    try {os[ o[i] ].rows.push( i ); } catch (err) { diffBugAlert(n[i]); }
  }
  
  // pass 3: pair unique new rows and matching unique old rows
  for ( var i in ns ) {
    if ( ns[i].rows.length == 1 && typeof(os[i]) != "undefined" && os[i].rows.length == 1 ) {
      n[ ns[i].rows[0] ] = { text: n[ ns[i].rows[0] ], row: os[i].rows[0] };
      o[ os[i].rows[0] ] = { text: o[ os[i].rows[0] ], row: ns[i].rows[0] };
    }
  }
  
  // pass 4: pair matching rows immediately following paired rows (not necessarily unique)
  for ( var i = 0; i < n.length - 1; i++ ) {
    if ( n[i].text != null && n[i+1].text == null && 
         n[i].row < o.length - 1 && o[ n[i].row + 1 ].text == null && 
         n[i+1] == o[ n[i].row + 1 ] ) {
      n[i+1] = { text: n[i+1], row: n[i].row + 1 };
      o[n[i].row+1] = { text: o[n[i].row+1], row: i + 1 };
    }
  }
  
  // pass 5: pair matching rows immediately preceding paired rows (not necessarily unique)
  for ( var i = n.length - 1; i > 0; i-- ) {
    if ( n[i].text != null && n[i-1].text == null && 
         n[i].row > 0 && o[ n[i].row - 1 ].text == null && 
         n[i-1] == o[ n[i].row - 1 ] ) {
      n[i-1] = { text: n[i-1], row: n[i].row - 1 };
      o[n[i].row-1] = { text: o[n[i].row-1], row: i - 1 };
    }
  }
  
  return { o: o, n: n };
}
/*</pre>*/