<!--{{{-->
<link rel='alternate' type='application/rss+xml' title='RSS' href='index.xml' />
<!--}}}-->
Background: #fff
Foreground: #000
PrimaryPale: #8cf
PrimaryLight: #18f
PrimaryMid: #04b
PrimaryDark: #014
SecondaryPale: #ffc
SecondaryLight: #fe8
SecondaryMid: #db4
SecondaryDark: #841
TertiaryPale: #eee
TertiaryLight: #ccc
TertiaryMid: #999
TertiaryDark: #666
Error: #f88
/*{{{*/
body {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}

a {color:[[ColorPalette::PrimaryMid]];}
a:hover {background-color:[[ColorPalette::PrimaryMid]]; color:[[ColorPalette::Background]];}
a img {border:0;}

h1,h2,h3,h4,h5,h6 {color:[[ColorPalette::SecondaryDark]]; background:transparent;}
h1 {border-bottom:2px solid [[ColorPalette::TertiaryLight]];}
h2,h3 {border-bottom:1px solid [[ColorPalette::TertiaryLight]];}

.button {color:[[ColorPalette::PrimaryDark]]; border:1px solid [[ColorPalette::Background]];}
.button:hover {color:[[ColorPalette::PrimaryDark]]; background:[[ColorPalette::SecondaryLight]]; border-color:[[ColorPalette::SecondaryMid]];}
.button:active {color:[[ColorPalette::Background]]; background:[[ColorPalette::SecondaryMid]]; border:1px solid [[ColorPalette::SecondaryDark]];}

.header {background:[[ColorPalette::PrimaryMid]];}
.headerShadow {color:[[ColorPalette::Foreground]];}
.headerShadow a {font-weight:normal; color:[[ColorPalette::Foreground]];}
.headerForeground {color:[[ColorPalette::Background]];}
.headerForeground a {font-weight:normal; color:[[ColorPalette::PrimaryPale]];}

.tabSelected{color:[[ColorPalette::PrimaryDark]];
	background:[[ColorPalette::TertiaryPale]];
	border-left:1px solid [[ColorPalette::TertiaryLight]];
	border-top:1px solid [[ColorPalette::TertiaryLight]];
	border-right:1px solid [[ColorPalette::TertiaryLight]];
}
.tabUnselected {color:[[ColorPalette::Background]]; background:[[ColorPalette::TertiaryMid]];}
.tabContents {color:[[ColorPalette::PrimaryDark]]; background:[[ColorPalette::TertiaryPale]]; border:1px solid [[ColorPalette::TertiaryLight]];}
.tabContents .button {border:0;}

#sidebar {}
#sidebarOptions input {border:1px solid [[ColorPalette::PrimaryMid]];}
#sidebarOptions .sliderPanel {background:[[ColorPalette::PrimaryPale]];}
#sidebarOptions .sliderPanel a {border:none;color:[[ColorPalette::PrimaryMid]];}
#sidebarOptions .sliderPanel a:hover {color:[[ColorPalette::Background]]; background:[[ColorPalette::PrimaryMid]];}
#sidebarOptions .sliderPanel a:active {color:[[ColorPalette::PrimaryMid]]; background:[[ColorPalette::Background]];}

.wizard {background:[[ColorPalette::PrimaryPale]]; border:1px solid [[ColorPalette::PrimaryMid]];}
.wizard h1 {color:[[ColorPalette::PrimaryDark]]; border:none;}
.wizard h2 {color:[[ColorPalette::Foreground]]; border:none;}
.wizardStep {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];
	border:1px solid [[ColorPalette::PrimaryMid]];}
.wizardStep.wizardStepDone {background:[[ColorPalette::TertiaryLight]];}
.wizardFooter {background:[[ColorPalette::PrimaryPale]];}
.wizardFooter .status {background:[[ColorPalette::PrimaryDark]]; color:[[ColorPalette::Background]];}
.wizard .button {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::SecondaryLight]]; border: 1px solid;
	border-color:[[ColorPalette::SecondaryPale]] [[ColorPalette::SecondaryDark]] [[ColorPalette::SecondaryDark]] [[ColorPalette::SecondaryPale]];}
.wizard .button:hover {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::Background]];}
.wizard .button:active {color:[[ColorPalette::Background]]; background:[[ColorPalette::Foreground]]; border: 1px solid;
	border-color:[[ColorPalette::PrimaryDark]] [[ColorPalette::PrimaryPale]] [[ColorPalette::PrimaryPale]] [[ColorPalette::PrimaryDark]];}

.wizard .notChanged {background:transparent;}
.wizard .changedLocally {background:#80ff80;}
.wizard .changedServer {background:#8080ff;}
.wizard .changedBoth {background:#ff8080;}
.wizard .notFound {background:#ffff80;}
.wizard .putToServer {background:#ff80ff;}
.wizard .gotFromServer {background:#80ffff;}

#messageArea {border:1px solid [[ColorPalette::SecondaryMid]]; background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]];}
#messageArea .button {color:[[ColorPalette::PrimaryMid]]; background:[[ColorPalette::SecondaryPale]]; border:none;}

.popupTiddler {background:[[ColorPalette::TertiaryPale]]; border:2px solid [[ColorPalette::TertiaryMid]];}

.popup {background:[[ColorPalette::TertiaryPale]]; color:[[ColorPalette::TertiaryDark]]; border-left:1px solid [[ColorPalette::TertiaryMid]]; border-top:1px solid [[ColorPalette::TertiaryMid]]; border-right:2px solid [[ColorPalette::TertiaryDark]]; border-bottom:2px solid [[ColorPalette::TertiaryDark]];}
.popup hr {color:[[ColorPalette::PrimaryDark]]; background:[[ColorPalette::PrimaryDark]]; border-bottom:1px;}
.popup li.disabled {color:[[ColorPalette::TertiaryMid]];}
.popup li a, .popup li a:visited {color:[[ColorPalette::Foreground]]; border: none;}
.popup li a:hover {background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]]; border: none;}
.popup li a:active {background:[[ColorPalette::SecondaryPale]]; color:[[ColorPalette::Foreground]]; border: none;}
.popupHighlight {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}
.listBreak div {border-bottom:1px solid [[ColorPalette::TertiaryDark]];}

.tiddler .defaultCommand {font-weight:bold;}

.shadow .title {color:[[ColorPalette::TertiaryDark]];}

.title {color:[[ColorPalette::SecondaryDark]];}
.subtitle {color:[[ColorPalette::TertiaryDark]];}

.toolbar {color:[[ColorPalette::PrimaryMid]];}
.toolbar a {color:[[ColorPalette::TertiaryLight]];}
.selected .toolbar a {color:[[ColorPalette::TertiaryMid]];}
.selected .toolbar a:hover {color:[[ColorPalette::Foreground]];}

.tagging, .tagged {border:1px solid [[ColorPalette::TertiaryPale]]; background-color:[[ColorPalette::TertiaryPale]];}
.selected .tagging, .selected .tagged {background-color:[[ColorPalette::TertiaryLight]]; border:1px solid [[ColorPalette::TertiaryMid]];}
.tagging .listTitle, .tagged .listTitle {color:[[ColorPalette::PrimaryDark]];}
.tagging .button, .tagged .button {border:none;}

.footer {color:[[ColorPalette::TertiaryLight]];}
.selected .footer {color:[[ColorPalette::TertiaryMid]];}

.sparkline {background:[[ColorPalette::PrimaryPale]]; border:0;}
.sparktick {background:[[ColorPalette::PrimaryDark]];}

.error, .errorButton {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::Error]];}
.warning {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::SecondaryPale]];}
.lowlight {background:[[ColorPalette::TertiaryLight]];}

.zoomer {background:none; color:[[ColorPalette::TertiaryMid]]; border:3px solid [[ColorPalette::TertiaryMid]];}

.imageLink, #displayArea .imageLink {background:transparent;}

.annotation {background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]]; border:2px solid [[ColorPalette::SecondaryMid]];}

.viewer .listTitle {list-style-type:none; margin-left:-2em;}
.viewer .button {border:1px solid [[ColorPalette::SecondaryMid]];}
.viewer blockquote {border-left:3px solid [[ColorPalette::TertiaryDark]];}

.viewer table, table.twtable {border:2px solid [[ColorPalette::TertiaryDark]];}
.viewer th, .viewer thead td, .twtable th, .twtable thead td {background:[[ColorPalette::SecondaryMid]]; border:1px solid [[ColorPalette::TertiaryDark]]; color:[[ColorPalette::Background]];}
.viewer td, .viewer tr, .twtable td, .twtable tr {border:1px solid [[ColorPalette::TertiaryDark]];}

.viewer pre {border:1px solid [[ColorPalette::SecondaryLight]]; background:[[ColorPalette::SecondaryPale]];}
.viewer code {color:[[ColorPalette::SecondaryDark]];}
.viewer hr {border:0; border-top:dashed 1px [[ColorPalette::TertiaryDark]]; color:[[ColorPalette::TertiaryDark]];}

.highlight, .marked {background:[[ColorPalette::SecondaryLight]];}

.editor input {border:1px solid [[ColorPalette::PrimaryMid]];}
.editor textarea {border:1px solid [[ColorPalette::PrimaryMid]]; width:100%;}
.editorFooter {color:[[ColorPalette::TertiaryMid]];}

#backstageArea {background:[[ColorPalette::Foreground]]; color:[[ColorPalette::TertiaryMid]];}
#backstageArea a {background:[[ColorPalette::Foreground]]; color:[[ColorPalette::Background]]; border:none;}
#backstageArea a:hover {background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]]; }
#backstageArea a.backstageSelTab {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}
#backstageButton a {background:none; color:[[ColorPalette::Background]]; border:none;}
#backstageButton a:hover {background:[[ColorPalette::Foreground]]; color:[[ColorPalette::Background]]; border:none;}
#backstagePanel {background:[[ColorPalette::Background]]; border-color: [[ColorPalette::Background]] [[ColorPalette::TertiaryDark]] [[ColorPalette::TertiaryDark]] [[ColorPalette::TertiaryDark]];}
.backstagePanelFooter .button {border:none; color:[[ColorPalette::Background]];}
.backstagePanelFooter .button:hover {color:[[ColorPalette::Foreground]];}
#backstageCloak {background:[[ColorPalette::Foreground]]; opacity:0.6; filter:'alpha(opacity=60)';}
/*}}}*/
/*{{{*/
* html .tiddler {height:1%;}

body {font-size:.75em; font-family:arial,helvetica; margin:0; padding:0;}

h1,h2,h3,h4,h5,h6 {font-weight:bold; text-decoration:none;}
h1,h2,h3 {padding-bottom:1px; margin-top:1.2em;margin-bottom:0.3em;}
h4,h5,h6 {margin-top:1em;}
h1 {font-size:1.35em;}
h2 {font-size:1.25em;}
h3 {font-size:1.1em;}
h4 {font-size:1em;}
h5 {font-size:.9em;}

hr {height:1px;}

a {text-decoration:none;}

dt {font-weight:bold;}

ol {list-style-type:decimal;}
ol ol {list-style-type:lower-alpha;}
ol ol ol {list-style-type:lower-roman;}
ol ol ol ol {list-style-type:decimal;}
ol ol ol ol ol {list-style-type:lower-alpha;}
ol ol ol ol ol ol {list-style-type:lower-roman;}
ol ol ol ol ol ol ol {list-style-type:decimal;}

.txtOptionInput {width:11em;}

#contentWrapper .chkOptionInput {border:0;}

.externalLink {text-decoration:underline;}

.indent {margin-left:3em;}
.outdent {margin-left:3em; text-indent:-3em;}
code.escaped {white-space:nowrap;}

.tiddlyLinkExisting {font-weight:bold;}
.tiddlyLinkNonExisting {font-style:italic;}

/* the 'a' is required for IE, otherwise it renders the whole tiddler in bold */
a.tiddlyLinkNonExisting.shadow {font-weight:bold;}

#mainMenu .tiddlyLinkExisting,
	#mainMenu .tiddlyLinkNonExisting,
	#sidebarTabs .tiddlyLinkNonExisting {font-weight:normal; font-style:normal;}
#sidebarTabs .tiddlyLinkExisting {font-weight:bold; font-style:normal;}

.header {position:relative;}
.header a:hover {background:transparent;}
.headerShadow {position:relative; padding:4.5em 0 1em 1em; left:-1px; top:-1px;}
.headerForeground {position:absolute; padding:4.5em 0 1em 1em; left:0px; top:0px;}

.siteTitle {font-size:3em;}
.siteSubtitle {font-size:1.2em;}

#mainMenu {position:absolute; left:0; width:10em; text-align:right; line-height:1.6em; padding:1.5em 0.5em 0.5em 0.5em; font-size:1.1em;}

#sidebar {position:absolute; right:3px; width:16em; font-size:.9em;}
#sidebarOptions {padding-top:0.3em;}
#sidebarOptions a {margin:0 0.2em; padding:0.2em 0.3em; display:block;}
#sidebarOptions input {margin:0.4em 0.5em;}
#sidebarOptions .sliderPanel {margin-left:1em; padding:0.5em; font-size:.85em;}
#sidebarOptions .sliderPanel a {font-weight:bold; display:inline; padding:0;}
#sidebarOptions .sliderPanel input {margin:0 0 0.3em 0;}
#sidebarTabs .tabContents {width:15em; overflow:hidden;}

.wizard {padding:0.1em 1em 0 2em;}
.wizard h1 {font-size:2em; font-weight:bold; background:none; padding:0; margin:0.4em 0 0.2em;}
.wizard h2 {font-size:1.2em; font-weight:bold; background:none; padding:0; margin:0.4em 0 0.2em;}
.wizardStep {padding:1em 1em 1em 1em;}
.wizard .button {margin:0.5em 0 0; font-size:1.2em;}
.wizardFooter {padding:0.8em 0.4em 0.8em 0;}
.wizardFooter .status {padding:0 0.4em; margin-left:1em;}
.wizard .button {padding:0.1em 0.2em;}

#messageArea {position:fixed; top:2em; right:0; margin:0.5em; padding:0.5em; z-index:2000; _position:absolute;}
.messageToolbar {display:block; text-align:right; padding:0.2em;}
#messageArea a {text-decoration:underline;}

.tiddlerPopupButton {padding:0.2em;}
.popupTiddler {position: absolute; z-index:300; padding:1em; margin:0;}

.popup {position:absolute; z-index:300; font-size:.9em; padding:0; list-style:none; margin:0;}
.popup .popupMessage {padding:0.4em;}
.popup hr {display:block; height:1px; width:auto; padding:0; margin:0.2em 0;}
.popup li.disabled {padding:0.4em;}
.popup li a {display:block; padding:0.4em; font-weight:normal; cursor:pointer;}
.listBreak {font-size:1px; line-height:1px;}
.listBreak div {margin:2px 0;}

.tabset {padding:1em 0 0 0.5em;}
.tab {margin:0 0 0 0.25em; padding:2px;}
.tabContents {padding:0.5em;}
.tabContents ul, .tabContents ol {margin:0; padding:0;}
.txtMainTab .tabContents li {list-style:none;}
.tabContents li.listLink { margin-left:.75em;}

#contentWrapper {display:block;}
#splashScreen {display:none;}

#displayArea {margin:1em 17em 0 14em;}

.toolbar {text-align:right; font-size:.9em;}

.tiddler {padding:1em 1em 0;}

.missing .viewer,.missing .title {font-style:italic;}

.title {font-size:1.6em; font-weight:bold;}

.missing .subtitle {display:none;}
.subtitle {font-size:1.1em;}

.tiddler .button {padding:0.2em 0.4em;}

.tagging {margin:0.5em 0.5em 0.5em 0; float:left; display:none;}
.isTag .tagging {display:block;}
.tagged {margin:0.5em; float:right;}
.tagging, .tagged {font-size:0.9em; padding:0.25em;}
.tagging ul, .tagged ul {list-style:none; margin:0.25em; padding:0;}
.tagClear {clear:both;}

.footer {font-size:.9em;}
.footer li {display:inline;}

.annotation {padding:0.5em; margin:0.5em;}

* html .viewer pre {width:99%; padding:0 0 1em 0;}
.viewer {line-height:1.4em; padding-top:0.5em;}
.viewer .button {margin:0 0.25em; padding:0 0.25em;}
.viewer blockquote {line-height:1.5em; padding-left:0.8em;margin-left:2.5em;}
.viewer ul, .viewer ol {margin-left:0.5em; padding-left:1.5em;}

.viewer table, table.twtable {border-collapse:collapse; margin:0.8em 1.0em;}
.viewer th, .viewer td, .viewer tr,.viewer caption,.twtable th, .twtable td, .twtable tr,.twtable caption {padding:3px;}
table.listView {font-size:0.85em; margin:0.8em 1.0em;}
table.listView th, table.listView td, table.listView tr {padding:0px 3px 0px 3px;}

.viewer pre {padding:0.5em; margin-left:0.5em; font-size:1.2em; line-height:1.4em; overflow:auto;}
.viewer code {font-size:1.2em; line-height:1.4em;}

.editor {font-size:1.1em;}
.editor input, .editor textarea {display:block; width:100%; font:inherit;}
.editorFooter {padding:0.25em 0; font-size:.9em;}
.editorFooter .button {padding-top:0px; padding-bottom:0px;}

.fieldsetFix {border:0; padding:0; margin:1px 0px;}

.sparkline {line-height:1em;}
.sparktick {outline:0;}

.zoomer {font-size:1.1em; position:absolute; overflow:hidden;}
.zoomer div {padding:1em;}

* html #backstage {width:99%;}
* html #backstageArea {width:99%;}
#backstageArea {display:none; position:relative; overflow: hidden; z-index:150; padding:0.3em 0.5em;}
#backstageToolbar {position:relative;}
#backstageArea a {font-weight:bold; margin-left:0.5em; padding:0.3em 0.5em;}
#backstageButton {display:none; position:absolute; z-index:175; top:0; right:0;}
#backstageButton a {padding:0.1em 0.4em; margin:0.1em;}
#backstage {position:relative; width:100%; z-index:50;}
#backstagePanel {display:none; z-index:100; position:absolute; width:90%; margin-left:3em; padding:1em;}
.backstagePanelFooter {padding-top:0.2em; float:right;}
.backstagePanelFooter a {padding:0.2em 0.4em;}
#backstageCloak {display:none; z-index:20; position:absolute; width:100%; height:100px;}

.whenBackstage {display:none;}
.backstageVisible .whenBackstage {display:block;}
/*}}}*/
/***
StyleSheet for use when a translation requires any css style changes.
This StyleSheet can be used directly by languages such as Chinese, Japanese and Korean which need larger font sizes.
***/
/*{{{*/
body {font-size:0.8em;}
#sidebarOptions {font-size:1.05em;}
#sidebarOptions a {font-style:normal;}
#sidebarOptions .sliderPanel {font-size:0.95em;}
.subtitle {font-size:0.8em;}
.viewer table.listView {font-size:0.95em;}
/*}}}*/
/*{{{*/
@media print {
#mainMenu, #sidebar, #messageArea, .toolbar, #backstageButton, #backstageArea {display: none !important;}
#displayArea {margin: 1em 1em 0em;}
noscript {display:none;} /* Fixes a feature in Firefox 1.5.0.2 where print preview displays the noscript content */
}
/*}}}*/
<!--{{{-->
<div class='header' macro='gradient vert [[ColorPalette::PrimaryLight]] [[ColorPalette::PrimaryMid]]'>
<div class='headerShadow'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
</div>
<div class='headerForeground'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
</div>
</div>
<div id='mainMenu' refresh='content' tiddler='MainMenu'></div>
<div id='sidebar'>
<div id='sidebarOptions' refresh='content' tiddler='SideBarOptions'></div>
<div id='sidebarTabs' refresh='content' force='true' tiddler='SideBarTabs'></div>
</div>
<div id='displayArea'>
<div id='messageArea'></div>
<div id='tiddlerDisplay'></div>
</div>
<!--}}}-->
<!--{{{-->
<div class='toolbar' macro='toolbar [[ToolbarCommands::ViewToolbar]]'></div>
<div class='title' macro='view title'></div>
<div class='subtitle'><span macro='view modifier link'></span>, <span macro='view modified date'></span> (<span macro='message views.wikified.createdPrompt'></span> <span macro='view created date'></span>)</div>
<div class='tagging' macro='tagging'></div>
<div class='tagged' macro='tags'></div>
<div class='viewer' macro='view text wikified'></div>
<div class='tagClear'></div>
<!--}}}-->
<!--{{{-->
<div class='toolbar' macro='toolbar [[ToolbarCommands::EditToolbar]]'></div>
<div class='title' macro='view title'></div>
<div class='editor' macro='edit title'></div>
<div macro='annotations'></div>
<div class='editor' macro='edit text'></div>
<div class='editor' macro='edit tags'></div><div class='editorFooter'><span macro='message views.editor.tagPrompt'></span><span macro='tagChooser excludeLists'></span></div>
<!--}}}-->
To get started with this blank [[TiddlyWiki]], you'll need to modify the following tiddlers:
* [[SiteTitle]] & [[SiteSubtitle]]: The title and subtitle of the site, as shown above (after saving, they will also appear in the browser title bar)
* [[MainMenu]]: The menu (usually on the left)
* [[DefaultTiddlers]]: Contains the names of the tiddlers that you want to appear when the TiddlyWiki is opened
You'll also need to enter your username for signing your edits: <<option txtUserName>>
These [[InterfaceOptions]] for customising [[TiddlyWiki]] are saved in your browser

Your username for signing your edits. Write it as a [[WikiWord]] (eg [[JoeBloggs]])

<<option txtUserName>>
<<option chkSaveBackups>> [[SaveBackups]]
<<option chkAutoSave>> [[AutoSave]]
<<option chkRegExpSearch>> [[RegExpSearch]]
<<option chkCaseSensitiveSearch>> [[CaseSensitiveSearch]]
<<option chkAnimate>> [[EnableAnimations]]

----
Also see [[AdvancedOptions]]
<<importTiddlers>>
#redirect [[Ajax (programming)]]
/***
|''Name:''|AdaptorCommandsPlugin|
|''Description:''|Commands to access hosted TiddlyWiki data|
|''Author:''|Martin Budden (mjbudden (at) gmail (dot) com)|
|''Source:''|http://www.martinswiki.com/#AdaptorCommandsPlugin |
|''CodeRepository:''|http://svn.tiddlywiki.org/Trunk/contributors/MartinBudden/adaptors/AdaptorCommandsPlugin.js |
|''Version:''|0.5.15|
|''Date:''|Aug 23, 2007|
|''Comments:''|Please make comments at http://groups.google.co.uk/group/TiddlyWikiDev |
|''License:''|[[Creative Commons Attribution-ShareAlike 3.0 License|http://creativecommons.org/licenses/by-sa/3.0/]] |
|''~CoreVersion:''|2.2.0|
***/

//{{{
// Ensure that the plugin is only installed once.
if(!version.extensions.AdaptorCommandsPlugin) {
version.extensions.AdaptorCommandsPlugin = {installed:true};
function getServerType(fields)
{
	if(!fields)
		return null;
	var serverType = fields['server.type'];
	if(!serverType)
		serverType = fields['wikiformat'];
	if(!serverType)
		serverType = config.defaultCustomFields['server.type'];
	if(!serverType && typeof RevisionAdaptor != 'undefined' && fields.uuid)
		serverType = RevisionAdaptor.serverType;
	return serverType;
}

function invokeAdaptor(fnName,param1,param2,context,userParams,callback,fields)
{
	var serverType = getServerType(fields);
	if(!serverType)
		return null;
	var adaptor = new config.adaptors[serverType];
	if(!adaptor)
		return false;
	if(!config.adaptors[serverType].prototype[fnName])
		return false;
	adaptor.openHost(fields['server.host']);
	adaptor.openWorkspace(fields['server.workspace']);
	var ret = false;
	if(param1)
		ret = param2 ? adaptor[fnName](param1,param2,context,userParams,callback) : adaptor[fnName](param1,context,userParams,callback);
	else
		ret = adaptor[fnName](context,userParams,callback);
	
	//adaptor.close();
	//delete adaptor;
	return ret;
}

function isAdaptorFunctionSupported(fnName,fields)
{
	var serverType = getServerType(fields);
	if(!serverType || !config.adaptors[serverType])
		return false;
	if(!config.adaptors[serverType].isLocal && !fields['server.host'])
		return false;
	var fn = config.adaptors[serverType].prototype[fnName];
	return fn ? true : false;
}

config.commands.getTiddler = {};
merge(config.commands.getTiddler,{
	text: "get",
	tooltip:"Download this tiddler",
	readOnlyText: "get",
	readOnlyTooltip: "Download this tiddler",
	done: "Tiddler downloaded"
	});

config.commands.getTiddler.isEnabled = function(tiddler)
{
	return isAdaptorFunctionSupported('getTiddler',tiddler.fields);
};

config.commands.getTiddler.handler = function(event,src,title)
{
	var tiddler = store.fetchTiddler(title);
	if(tiddler) {
		var fields = tiddler.fields;
	} else {
		fields = String(document.getElementById(story.idPrefix + title).getAttribute("tiddlyFields"));
		fields = fields ? fields.decodeHashMap() : null;
	}
	return invokeAdaptor('getTiddler',title,null,null,null,config.commands.getTiddler.callback,fields);
};

config.commands.getTiddler.callback = function(context,userParams)
{
	if(context.status) {
		var tiddler = context.tiddler;
		store.saveTiddler(tiddler.title,tiddler.title,tiddler.text,tiddler.modifier,tiddler.modified,tiddler.tags,tiddler.fields,true);
		story.refreshTiddler(tiddler.title,1,true);
		displayMessage(config.commands.getTiddler.done);
	} else {
		displayMessage(context.statusText);
	}
};

config.commands.putTiddler = {};
merge(config.commands.putTiddler,{
	text: "put",
	tooltip: "Upload this tiddler",
	hideReadOnly: true,
	done: "Tiddler uploaded"
	});

config.commands.putTiddler.isEnabled = function(tiddler)
{
	return tiddler && tiddler.isTouched() && isAdaptorFunctionSupported('putTiddler',tiddler.fields);
};

config.commands.putTiddler.handler = function(event,src,title)
{
	var tiddler = store.fetchTiddler(title);
	if(!tiddler)
		return false;
	return invokeAdaptor('putTiddler',tiddler,null,null,null,config.commands.putTiddler.callback,tiddler.fields);
};

config.commands.putTiddler.callback = function(context,userParams)
{
	if(context.status) {
		store.fetchTiddler(context.title).clearChangeCount();
		displayMessage(config.commands.putTiddler.done);
	} else {
		displayMessage(context.statusText);
	}
};

config.commands.revisions = {};
merge(config.commands.revisions,{
	text: "revisions",
	tooltip: "View another revision of this tiddler",
	loading: "loading...",
	done: "Revision downloaded",
	revisionTooltip: "View this revision",
	popupNone: "No revisions",
	revisionTemplate: "%0 r:%1"
	});

config.commands.revisions.isEnabled = function(tiddler)
{
	return isAdaptorFunctionSupported('getTiddlerRevisionList',tiddler.fields);
};

config.commands.revisions.handler = function(event,src,title)
{
	var tiddler = store.fetchTiddler(title);
	var userParams = {};
	userParams.tiddler = tiddler;
	userParams.src = src;
	userParams.dateFormat = 'YYYY mmm 0DD 0hh:0mm';
	var revisionLimit = 10;
	if(!invokeAdaptor('getTiddlerRevisionList',title,revisionLimit,null,userParams,config.commands.revisions.callback,tiddler.fields))
		return false;
	event.cancelBubble = true;
	if(event.stopPropagation)
		event.stopPropagation();
	return true;
};

config.commands.revisions.callback = function(context,userParams)
// The revisions are returned as tiddlers in the context.revisions array
{
	var revisions = context.revisions;
	popup = Popup.create(userParams.src);
	Popup.show(popup,false);
	if(revisions.length==0) {
		createTiddlyText(createTiddlyElement(popup,'li',null,'disabled'),config.commands.revisions.popupNone);
	} else {
		revisions.sort(function(a,b) {return a.modified < b.modified ? +1 : -1;});
		for(var i=0; i<revisions.length; i++) {
			var tiddler = revisions[i];
			var modified = tiddler.modified.formatString(context.dateFormat||userParams.dateFormat);
			var revision = tiddler.fields['server.page.revision'];
			var btn = createTiddlyButton(createTiddlyElement(popup,'li'),
					config.commands.revisions.revisionTemplate.format([modified,revision,tiddler.modifier]),
					tiddler.text||config.commands.revisions.revisionTooltip,
					function() {
						config.commands.revisions.getTiddlerRevision(this.getAttribute('tiddlerTitle'),this.getAttribute('tiddlerModified'),this.getAttribute('tiddlerRevision'));
						return false;
						},
					'tiddlyLinkExisting tiddlyLink');
			btn.setAttribute('tiddlerTitle',userParams.tiddler.title);
			btn.setAttribute('tiddlerRevision',revision);
			btn.setAttribute('tiddlerModified',tiddler.modified.convertToYYYYMMDDHHMM());
			if(userParams.tiddler.fields['server.page.revision'] == revision || (!userParams.tiddler.fields['server.page.revision'] && i==0))
				btn.className = 'revisionCurrent';
		}
	}
};

config.commands.revisions.getTiddlerRevision = function(title,modified,revision)
{
	var tiddler = store.fetchTiddler(title);
	var context = {modified:modified};
	return invokeAdaptor('getTiddlerRevision',title,revision,context,null,config.commands.revisions.getTiddlerRevisionCallback,tiddler.fields);
};

config.commands.revisions.getTiddlerRevisionCallback = function(context,userParams)
{
	if(context.status) {
		var tiddler = context.tiddler;
		//store.saveTiddler(tiddler.title,tiddler.title,tiddler.text,tiddler.modifier,tiddler.modified,tiddler.tags,tiddler.fields);
		store.addTiddler(tiddler);
		store.notify(tiddler.title,true);
		story.refreshTiddler(tiddler.title,1,true);
		displayMessage(config.commands.revisions.done);
	} else {
		displayMessage(context.statusText);
	}
};

config.commands.saveTiddlerAndPut = {};
merge(config.commands.saveTiddlerAndPut,{
	text: "done",
	tooltip: "Save this tiddler and upload",
	hideReadOnly: true,
	done: "Tiddler uploaded"
	});

config.commands.saveTiddlerAndPut.handler = function(event,src,title)
{
	config.commands.putTiddlerRevision.handler(event,src,title);// save the old tiddler as a revision
	var newTitle = story.saveTiddler(title,event.shiftKey);
	if(newTitle)
		story.displayTiddler(null,newTitle);
	return config.commands.putTiddler.handler(event,src,newTitle);
};

config.commands.saveTiddlerHosted = {};
merge(config.commands.saveTiddlerHosted,{
	text: "done",
	tooltip: "Save changes to this tiddler",
	hideReadOnly: true,
	done: "done"
	});
	
config.commands.saveTiddlerHosted.handler = function(event,src,title)
{
	var tiddler = store.fetchTiddler(title);
	if(!tiddler)
		return false;
	return invokeAdaptor('saveTiddlerHosted',tiddler,null,null,null,config.commands.saveTiddlerHosted.callback,tiddler.fields);
};

config.commands.saveTiddlerHosted.callback = function(context,userParams)
{
	if(context.status) {
		displayMessage(config.commands.saveTiddlerHosted.done);
	} else {
		displayMessage(context.statusText);
	}
};

config.commands.deleteTiddlerHosted = {};
merge(config.commands.deleteTiddlerHosted,{
	text: "delete",
	tooltip: "Delete this tiddler",
	warning: "Are you sure you want to delete '%0'?",
	hideReadOnly: true,
	done: "done"
	});
	
config.commands.deleteTiddlerHosted.handler = function(event,src,title)
{
	var tiddler = store.fetchTiddler(title);
	if(!tiddler)
		return false;
	return invokeAdaptor('deleteTiddler',title,null,null,null,config.commands.deleteTiddlerHosted.callback,tiddler.fields);
};

config.commands.deleteTiddlerHosted.callback = function(context,userParams)
{
	if(context.status) {
		displayMessage(config.commands.saveTiddlerHosted.done);
	} else {
		displayMessage(context.statusText);
	}
};

config.commands.diff = {};
merge(config.commands.diff,{
	text: "diff",
	tooltip: "View tiddler changes",
	done: "done",
	diffTooltip: "View this diff",
	popupNone: "No changes",
	diffTemplate: "%0 r:%1"
	});

config.commands.diff.isEnabled = function(tiddler)
{
	return isAdaptorFunctionSupported('getTiddlerDiff',tiddler.fields);
};

config.commands.diff.handler = function(event,src,title)
{
	var tiddler = store.fetchTiddler(title);
	var userParams = {tiddler:tiddler,src:src,dateFormat:'YYYY mmm 0DD 0hh:0mm'};
	var revisionLimit = 10;
	if(!invokeAdaptor('getTiddlerRevisionList',title,revisionLimit,null,userParams,config.commands.diff.callback,tiddler.fields))
		return false;
	event.cancelBubble = true;
	if(event.stopPropagation)
		event.stopPropagation();
	return true;
};

config.commands.diff.callback = function(context,userParams)
// The revisions are returned as tiddlers in the context.revisions array
{
	var revisions = context.revisions;
	popup = Popup.create(userParams.src);
	Popup.show(popup,false);
	if(revisions.length==0) {
		createTiddlyText(createTiddlyElement(popup,'li',null,'disabled'),config.commands.revisions.popupNone);
	} else {
		revisions.sort(function(a,b) {return a.modified < b.modified ? +1 : -1;});
		for(var i=0; i<revisions.length; i++) {
			var tiddler = revisions[i];
			var modified = tiddler.modified.formatString(context.dateFormat||userParams.dateFormat);
			var revision = tiddler.fields['server.page.revision'];
			var btn = createTiddlyButton(createTiddlyElement(popup,'li'),
					config.commands.diff.diffTemplate.format([modified,revision,tiddler.modifier]),
					tiddler.text||config.commands.diff.diffTooltip,
					function() {
						config.commands.diff.getTiddlerDiff(this.getAttribute('tiddlerTitle'),userParams.src,this.getAttribute('tiddlerRevision'),null);
						return false;
						},
					'tiddlyLinkExisting tiddlyLink');
			btn.setAttribute('tiddlerTitle',userParams.tiddler.title);
			btn.setAttribute('tiddlerRevision',revision);
			btn.setAttribute('tiddlerModified',tiddler.modified.convertToYYYYMMDDHHMM());
			if(userParams.tiddler.fields['server.page.revision'] == revision || (!userParams.tiddler.fields['server.page.revision'] && i==0))
				btn.className = 'revisionCurrent';
		}
	}
};

config.commands.diff.getTiddlerDiff = function(title,src,rev1,rev2)
{
	var tiddler = store.fetchTiddler(title);
	var userParams = {src:src};
	var context = {rev1:rev1,rev2:rev2};
//	var context = {};
	return invokeAdaptor('getTiddlerDiff',title,null,context,userParams,config.commands.diff.getTiddlerDiffCallback,tiddler.fields);
};

config.commands.diff.getTiddlerDiffCallback = function(context,userParams)
{
	console.log("config.commands.diff.getTiddlerDiffCallback:"+context.diff);
	var diff = context.diff;
	popup = Popup.create(userParams.src);
	Popup.show(popup,false);
	if(diff.length==0) {
		createTiddlyText(createTiddlyElement(popup,'li',null,'disabled'),config.commands.diff.popupNone);
	} else {
		for(var i=0; i<diff.length; i++) {
			createTiddlyText(createTiddlyElement(popup,'li'),diff[i]);
		}
	}
};

}//# end of 'install only once'
//}}}
/***
|''Name:''|AdaptorMacrosPlugin|
|''Description:''|Commands to access hosted TiddlyWiki data|
|''Author:''|Martin Budden (mjbudden (at) gmail (dot) com)|
|''Source:''|http://www.martinswiki.com/#AdaptorMacrosPlugin |
|''CodeRepository:''|http://svn.tiddlywiki.org/Trunk/contributors/MartinBudden/adaptors/AdaptorMacrosPlugin.js |
|''Version:''|0.3.8|
|''Date:''|Aug 23, 2007|
|''Comments:''|Please make comments at http://groups.google.co.uk/group/TiddlyWikiDev |
|''License:''|[[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]] |
|''~CoreVersion:''|2.2.0|
***/

//{{{
// Ensure that the plugin is only installed once.
if(!version.extensions.AdaptorMacrosPlugin) {
version.extensions.AdaptorMacrosPlugin = {installed:true};

// Return an array of tiddler titles that are in the given workspace on the host
TiddlyWiki.prototype.getHostedTiddlers = function(host,workspace)
{
	var results = [];
	if(!this.hostedTiddlers || !this.hostedTiddlers[host])
		return results;
	var tiddlers = this.hostedTiddlers[host][workspace];
	if(tiddlers) {
		for(var i=0; i<tiddlers.length; i++) {
			results.push(tiddlers[i].title);
		}
	}
	return results;
};

config.macros.viewTiddlerFields = {};
config.macros.viewTiddlerFields.handler = function(place,macroName,params,wikifier,paramString,tiddler)
{
	if(tiddler instanceof Tiddler) {
		var value = '';
		var comma = '';
		for(i in tiddler.fields) {
			if (!i.match(/^temp[\._]/)) {
				value += comma + i + '=' + tiddler.fields[i];
				comma = ', ';
			}
		}
		if(tiddler.created)
			value += comma + 'created=' + tiddler.created.convertToYYYYMMDDHHMM();
		if(tiddler.modified)
			value += ', modified=' + tiddler.modified.convertToYYYYMMDDHHMM();
		if(tiddler.modifier)
			value += ', modifier=' + tiddler.modifier;
		value += ', touched=' + (tiddler.isTouched() ? 'true' : 'false');
		highlightify(value,place,highlightHack,tiddler);
	}
};

config.macros.list.updatedOffline = {};
config.macros.list.updatedOffline.handler = function(params)
{
	var results = [];
	store.forEachTiddler(function(title,tiddler) {
		if(tiddler.fields['server.host'] && tiddler.isTouched())
			results.push(tiddler);
		});
	results.sort();
	return results;
};

config.macros.list.workspaceTiddlers = {};
config.macros.list.workspaceTiddlers.prompt = "List Tiddlers in the workspace";
config.macros.list.workspaceTiddlers.handler = function(params,wikifier,paramString,tiddler)
{
	var customFields = getParam(params,'fields',false);
	if(!customFields)
		customFields = config.defaultCustomFields;
	return store.getHostedTiddlers(customFields['server.host'],customFields['server.workspace']);
};

config.macros.updateWorkspaceTiddlerList = {};
merge(config.macros.updateWorkspaceTiddlerList,{
	label: "update tiddler list",
	prompt: "Update list of tiddlers in workspace",
	done: "List updated"});

config.macros.updateWorkspaceTiddlerList.handler = function(place,macroName,params,wikifier,paramString,tiddler)
{
	params = paramString.parseParams('anon',null,true,false,false);
	var customFields = getParam(params,'fields',false);
	if(!customFields)
		customFields = String.encodeHashMap(config.defaultCustomFields);
	var btn = createTiddlyButton(place,this.label,this.prompt,this.onClick);
	btn.setAttribute('customFields',customFields);
	btn.setAttribute('title',tiddler.title);
};

config.macros.updateWorkspaceTiddlerList.onClick = function(e)
{
	clearMessage();
	var customFields = this.getAttribute("customFields");
	var fields = customFields.decodeHashMap();
	var userParams = {host:fields['server.host'],workspace:fields['server.workspace'],title:this.getAttribute("title")};
	return invokeAdaptor('getTiddlerList',null,null,null,userParams,config.macros.updateWorkspaceTiddlerList.callback,fields);
};

config.macros.updateWorkspaceTiddlerList.callback = function(context,userParams)
{
	if(context.status) {
		if(!store.hostedTiddlers)
			store.hostedTiddlers = {};
		if(!store.hostedTiddlers[userParams.host])
			store.hostedTiddlers[userParams.host] = {};
		store.hostedTiddlers[userParams.host][userParams.workspace] = context.tiddlers;
		displayMessage(config.macros.updateWorkspaceTiddlerList.done);
		story.displayTiddler(null,userParams.title);
		story.refreshTiddler(userParams.title,1,true);
	} else {
		displayMessage(context.statusText);
	}
};


config.macros.updateWorkspaceList = {};
merge(config.macros.updateWorkspaceList,{
	label: "update workspace list",
	prompt: "Update list of workspaces",
	done: "List updated"});

config.macros.updateWorkspaceList.handler = function(place,macroName,params,wikifier,paramString,tiddler)
{
	params = paramString.parseParams('anon',null,true,false,false);
	var customFields = getParam(params,'fields',false);
	if(!customFields)
		customFields = String.encodeHashMap(config.defaultCustomFields);
	var btn = createTiddlyButton(place,this.label,this.prompt,this.onClick);
	btn.setAttribute('customFields',customFields);
	btn.setAttribute('title',tiddler.title);
};

config.macros.updateWorkspaceList.onClick = function(e)
{
	clearMessage();
	var customFields = this.getAttribute("customFields");
	var fields = customFields.decodeHashMap();
	var userParams = {host:fields['server.host'],callback:config.macros.updateWorkspaceList.callback};
	return invokeAdaptor('getWorkspaceList',context,fields);
};

config.macros.updateWorkspaceList.callback = function(context,userParams)
{
	if(context.status) {
		displayMessage(config.macros.updateWorkspaceList.done);
		for(var i=0; i<context.workspaces.length; i++) {
			displayMessage("workspace:"+context.workspaces[i]);
		}
	} else {
		displayMessage(context.statusText);
	}
};

} // end of 'install only once'
//}}}
[[AJAX]]
/***
|''Name:''|MediaWikiAdaptorPlugin|
|''Description:''|Adaptor for moving and converting data from MediaWikis|
|''Author:''|Martin Budden (mjbudden (at) gmail (dot) com)|
|''Source:''|http://www.martinswiki.com/#MediaWikiAdaptorPlugin |
|''CodeRepository:''|http://svn.tiddlywiki.org/Trunk/contributors/MartinBudden/adaptors/MediaWikiAdaptorPlugin.js |
|''Version:''|0.8.14|
|''Date:''|Jul 27, 2007|
|''Comments:''|Please make comments at http://groups.google.co.uk/group/TiddlyWikiDev |
|''License:''|[[Creative Commons Attribution-ShareAlike 3.0 License|http://creativecommons.org/licenses/by-sa/3.0/]] |
|''~CoreVersion:''|2.4.1|

|''Max number of tiddlers to download''|<<option txtMediaWikiAdaptorLimit>>|


MediaWiki REST documentation is at:
http://meta.wikimedia.org/w/api.php
http://meta.wikimedia.org/w/query.php

''For debug:''
|''Default MediaWiki username''|<<option txtMediaWikiUsername>>|
|''Default MediaWiki password''|<<option txtMediaWikiPassword>>|

***/
//{{{
if(!config.options.txtMediaWikiUsername)
	{config.options.txtMediaWikiUsername = '';}
if(!config.options.txtMediaWikiPassword)
	{config.options.txtMediaWikiPassword = '';}
//}}}

//{{{
if(!config.adaptors.mediawiki) {

if(config.options.txtMediaWikiAdaptorLimit == undefined)
	{config.options.txtMediaWikiAdaptorLimit = '500';}


config.adaptors.mediawiki = function() {};

(function(adaptor) {

adaptor.prototype = new AdaptorBase();

adaptor.serverType = 'mediawiki';
adaptor.serverParsingErrorMessage = "Error parsing result from server";
adaptor.errorInFunctionMessage = "Error in function MediaWikiAdaptor.%0";

adaptor.doHttpGET = function(uri,callback,params,headers,data,contentType,username,password)
{
	return httpReq('GET',uri,callback,params,headers,data,contentType,username,password);
};

adaptor.doHttpPOST = function(uri,callback,params,headers,data,contentType,username,password)
{
	return httpReq('POST',uri,callback,params,headers,data,contentType,username,password);
};

adaptor.minHostName = function(host)
{
	return host ? host.replace(/^http:\/\//,'').replace(/\/$/,'') : '';
};

adaptor.normalizedTitle = function(title)
{
	var n = title.charAt(0).toUpperCase() + title.substr(1);
	return n.replace(/\s/g,'_');
};

adaptor.dateFromTimestamp = function(timestamp)
// Convert a MediaWiki timestamp in ISO 8601 (YYYY-MM-DDThh:mm:ssZ)  format into a JavaScript Date object
{
	var dt = timestamp;
	return new Date(Date.UTC(dt.substr(0,4),dt.substr(5,2)-1,dt.substr(8,2),dt.substr(11,2),dt.substr(14,2)));
};

adaptor.anyChild = function(obj)
{
	for(var key in obj) {
		if(typeof obj[key]!='function')
			return obj[key];
	}
	return null;
};


adaptor.prototype.complete = function(context,fn)
{
	context.complete = fn;
	var ret;
	if(context.sessionToken) {
		ret = context.complete(context,context.userParams);
	} else {
		ret = this.login(context);
	}
	return ret;
};

adaptor.prototype.login = function(context)
{
	var host = this.fullHostName(context.host);
	var uriTemplate = '%0/api.php?action=login&format=json&lgname=%1&lgpassword=%2';
	var uri = uriTemplate.format([host,escape(config.options.txtMediaWikiUsername),escape(config.options.txtMediaWikiPassword)]);

	var req = adaptor.doHttpPOST(uri,adaptor.loginCallback,context,{"Content-Length":"1"}," ");
	return typeof req == 'string' ? req : true;
};


adaptor.loginCallback = function(status,context,responseText,uri,xhr)
{
	if(status) {
		try {
			eval('var info=' + responseText);
		} catch (ex) {
			context.statusText = exceptionText(ex,adaptor.serverParsingErrorMessage);
			if(context.complete)
				context.complete(context,context.userParams);
			return;
		}
		context.status = true;
		context.sessionToken = info.login.lgtoken;
		if(context.complete)
			context.complete(context,context.userParams);
	} else {
		context.status = false;
		context.statusText = xhr.statusText;
		if(context.callback)
			context.callback(context,context.userParams);
	}
};

adaptor.getWorkspaceId = function(workspace)
{
	var workspaces = {
		"media": -2, "special":-1,
		"":0, "talk":1,"user":2,"user talk":3,"meta":4,"meta talk":5,"image":6,"image talk":7,
		"mediawiki":8,"mediawiki talk":9,"template":10,"template talk":11,"help":12,"help talk":13,
		"category":14,"category talk":15};
	workspace = workspace.toLowerCase();
	var id = workspaces[workspace];
	if(!id) {
		if(workspace=="" || workspace=="main")
			id = 0;
		else if(workspace.lastIndexOf("talk") != -1)
			id = 5;
		else
			id = 4;
	}
	return id;
};

adaptor.prototype.openWorkspace = function(workspace,context,userParams,callback)
{
	if(!workspace)
		workspace = "";
	this.workspace = workspace;
	this.workspaceId = null;
	context = this.setContext(context,userParams,callback);
	if(workspace) {
		if(context.workspaces) {
			for(var i=0;i<context.workspaces.length;i++) {
				if(context.workspaces[i].name == workspace) {
					this.workspaceId = context.workspaces[i].id;
					break;
				}
			}
		} else {
			workspace = workspace.toLowerCase();
			this.workspaceId = adaptor.getWorkspaceId(workspace);
		}
	}
	if(!this.workspaceId) {
		if(workspace=="" || workspace.toLowerCase()=="main")
			this.workspaceId = 0;
		else if(workspace.lastIndexOf("talk") != -1)
			this.workspaceId = 5;
		else
			this.workspaceId = 4;
	}
	if(context.callback) {
		context.status = true;
		window.setTimeout(function() {callback(context,userParams);},0);
	}
	return true;
};

adaptor.prototype.getWorkspaceList = function(context,userParams,callback)
{
	context = this.setContext(context,userParams,callback);
	if(context.workspace) {
		context.status = true;
		context.workspaces = [{name:context.workspace,title:context.workspace}];
		if(context.callback)
			window.setTimeout(function() {callback(context,userParams);},0);
		return true;
	}
	var uriTemplate = '%0/api.php?format=json&action=query&meta=siteinfo&siprop=namespaces';
	var uri = uriTemplate.format([context.host]);
	var req = adaptor.doHttpGET(uri,adaptor.getWorkspaceListCallback,context);
	return typeof req == 'string' ? req : true;
};


adaptor.getWorkspaceListCallback = function(status,context,responseText,uri,xhr)
{
	context.status = false;
	if(status) {
		try {
			eval('var info=' + responseText);
		} catch (ex) {
			context.statusText = exceptionText(ex,adaptor.serverParsingErrorMessage);
			if(context.callback)
				context.callback(context,context.userParams);
			return;
		}
		var namespaces = info.query.namespaces;
		var list = [];
		for(var i in namespaces) {
			var item = {};
			item.id = namespaces[i]['id'];
			item.title = namespaces[i]['*'];
			item.name = item.title;
			list.push(item);
		}
		context.workspaces = list;
		context.status = true;
	} else {
		context.statusText = xhr.statusText;
		context.statusCode = xhr.status;
	}
	if(context.callback)
		context.callback(context,context.userParams);
};

adaptor.prototype.getTiddlerList = function(context,userParams,callback,filter)
// get a list of the tiddlers in the current workspace
{
	context = this.setContext(context,userParams,callback);
	if(!context.filter)
		context.filter = filter;

	context.tiddlers = [];
	context.uri = null;
	var host = this.fullHostName(context.host);
	if(!context.tiddlerLimit)
		context.tiddlerLimit = !config.options.txtMediaWikiAdaptorLimit ? config.maxTiddlerImportCount : config.options.txtMediaWikiAdaptorLimit;
	context.tiddlerLimit = parseInt(context.tiddlerLimit,10);
	var limit = context.tiddlerLimit;
	if(limit>500)
		limit = 500;
	filter = context.filter;
	if(host.indexOf('wikipedia.org')!=-1) {
		if(!filter) {
			filter = '[template[Featured_article]]';
		}
	}
	if(filter) {
		var re = /\[(\w+)\[([ \w\.\:]+)\]\]/;
		var match = re.exec(filter);
		if(match) {
			var filterParams = adaptor.normalizedTitle(match[2]);
			switch(match[1]) {
			case 'tag':
				context.responseType = 'query.categorymembers';
				var uriTemplate = '%0/api.php?format=json&action=query&list=categorymembers&cmnamespace=%1&cmlimit=%2&cmtitle=Category:%3';
				break;
			case 'template':
				context.responseType = 'query.embeddedin';
				uriTemplate = '%0/api.php?format=json&action=query&list=embeddedin&einamespace=%1&eititle=Template:%3';
				if(limit)
					uriTemplate += '&eilimit=%2';
				break;
			case 'wikipedia':
				context.responseType = 'query.embeddedin';
				uriTemplate = '%0/api.php?format=json&action=query&list=embeddedin&einamespace=1&eititle=Wikipedia:%3';
				if(limit)
					uriTemplate += '&eilimit=%2';
				break;
			default:
				break;
			}
		} else {
			var params = filter.parseParams('anon',null,false);
			for(var i=1; i<params.length; i++) {
				var tiddler = new Tiddler(params[i].value);
				tiddler.fields.workspaceId = this.workspaceId;
				context.tiddlers.push(tiddler);
			}
			context.status = true;
			if(context.callback)
				window.setTimeout(function() {callback(context,userParams);},0);
			return true;
		}
	} else {
		context.responseType = 'query.pages';
		uriTemplate = '%0/api.php?format=json&action=query&generator=allpages&gapfilterredir=nonredirects&gapfrom=%4&prop=info';
		if(this.workspaceId != 0)
			uriTemplate += '&gapnamespace=%1';
		if(limit) {
			uriTemplate += '&gaplimit=%2';
			context.gaplimit = limit;
		}
		context.count = 0;
		context.uri = uriTemplate.format([host,this.workspaceId,limit,filterParams,'%0']);
		context.urifrom = 'gapfrom';
	}
	var from = '0';
	var uri = uriTemplate.format([host,this.workspaceId,limit,filterParams,from]);
	var req = adaptor.doHttpGET(uri,adaptor.getTiddlerListCallback,context);
	return typeof req == 'string' ? req : true;
};

adaptor.getTiddlerListCallback = function(status,context,responseText,uri,xhr)
{
	context.status = false;
	context.statusText = adaptor.errorInFunctionMessage.format(['getTiddlerListCallback']);
	if(status) {
		try {
			eval('var info=' + responseText);
			var pages;
			if(context.responseType == 'query.embeddedin')
				pages = info.query.embeddedin;
			else if(context.responseType == 'query.categorymembers')
				pages = info.query.categorymembers;
			else if(context.responseType == 'query.allpages')
				pages = info.query.allpages;
			else if(context.responseType == 'query.pages')
				pages = info.query.pages;
			else
				pages = info.pages;
			var c = null;
			if(info['query-continue']) {
				if(info['query-continue'].allpages) {
					c = adaptor.normalizedTitle(info['query-continue'].allpages[context.urifrom]);
					context.count += context.gaplimit;
					if(context.count>=context.tiddlerLimit)
						c = null;
				}
			}
			var useMain = false;
			if(context.workspace=="Talk" && context.filter)
				useMain = true;
			for(i in pages) {
				var title = pages[i].title;
				if(useMain&&title)
					title = title.replace(/^Talk:/g,"");
				if(title && !store.isShadowTiddler(title)) {
					tiddler = new Tiddler(title);
					tiddler.fields.workspaceId = useMain ? 0 : pages[i].ns;
					if(!useMain)
						tiddler.fields['temp.size'] = pages[i].length;
					context.tiddlers.push(tiddler);
				}
			}
		} catch (ex) {
			context.statusText = exceptionText(ex,adaptor.serverParsingErrorMessage);
			if(context.callback)
				context.callback(context,context.userParams);
			return;
		}
		context.status = true;
	} else {
		context.statusText = xhr.statusText;
	}
	if(context.uri && c) {
		var u = context.uri.format([c]);
		var req = adaptor.doHttpGET(u,adaptor.getTiddlerListCallback,context);
	} else {
		if(context.callback)
			context.callback(context,context.userParams);
	}
};

adaptor.prototype.generateTiddlerInfo = function(tiddler)
{
	var info = {};
	var host = this && this.host ? this.host : tiddler.fields['server.host'];
	host = this.fullHostName(host);
	if(host.match(/w\/$/)) {
		host = host.replace(/w\/$/,'');
		var uriTemplate = '%0wiki/%2';
	} else {
		uriTemplate = '%0/index.php?title=%2';
	}
	info.uri = uriTemplate.format([host,this.workspace,tiddler.title]);
	return info;
};

adaptor.prototype.getTiddlerRevision = function(title,revision,context,userParams,callback)
{
	context = this.setContext(context,userParams,callback);
	context.revision = revision;
	return this.getTiddler(title,context,userParams,callback);
};

adaptor.prototype.getTiddler = function(title,context,userParams,callback)
{
	context = this.setContext(context,userParams,callback);
	context.title = title;
	var host = this.fullHostName(context.host);
	var uriTemplate = '%0/api.php?format=json&action=query&prop=revisions&titles=%1&rvprop=content|timestamp|user|ids';
	if(context.revision)
		uriTemplate += '&rvstartid=%2&rvlimit=1';
	var uri = uriTemplate.format([host,adaptor.normalizedTitle(context.title),context.revision]);
	context.tiddler = new Tiddler(context.title);
	context.tiddler.fields.wikiformat = 'mediawiki';
	context.tiddler.fields['server'] = null;
	context.tiddler.fields['server.host'] = adaptor.minHostName(host);
	var req = adaptor.doHttpGET(uri,adaptor.getTiddlerCallback,context);
	return typeof req == 'string' ? req : true;
};



adaptor.prototype.getTiddlerPostProcess = function(context)
{
	return context.tiddler;
};

adaptor.getTiddlerCallback = function(status,context,responseText,uri,xhr)
{
	context.status = false;
	if(status) {
		var content = null;
		try {
			eval('var info=' + responseText);
			var page = adaptor.anyChild(info.query.pages);
			var revision = adaptor.anyChild(page.revisions);
			var text = revision['*'];
			context.tiddler.fields['server.page.revision'] = String(revision['revid']);
			context.tiddler.fields['server.page.timestamp'] = String(revision['timestamp']);
			var host = context.tiddler.fields['server.host'];
			if(host.indexOf('wikipedia')==-1) {
				context.tiddler.modified = adaptor.dateFromTimestamp(revision['timestamp']);
				context.tiddler.modifier = revision.user;
			} else {
				// content is from wikipedia
				context.tiddler.created = version.date;
				context.tiddler.modified= version.date;
				// remove links to other language articles
				text = text.replace(/\[\[[a-z\-]{2,12}:(?:.*?)\]\](?:\r?)(?:\n?)/g,'');
			}
			context.tiddler.text = text;
			var catRegExp = /\[\[(Category:[^|\]]*?)\]\]/mg;
			var tags = '';
			var delim = '';
			catRegExp.lastIndex = 0;
			var match = catRegExp.exec(text);
			while(match) {
				tags += delim;
				if(match[1].indexOf(' ')==-1)
					tags += match[1];
				else
					tags += '[[' + match[1] + ']]';
				delim = ' ';
				match = catRegExp.exec(text);
			}
			context.tiddler.tags = tags.readBracketedList();
			context.tiddler = context.adaptor.getTiddlerPostProcess.call(context.adaptor,context);
		} catch (ex) {
			context.statusText = exceptionText(ex,adaptor.serverParsingErrorMessage);
			if(context.callback)
				context.callback(context,context.userParams);
			return;
		}
		context.status = true;
	} else {
		context.statusText = xhr.statusText;
	}
	if(context.callback)
		context.callback(context,context.userParams);
};


adaptor.prototype.getTiddlerRevisionList = function(title,limit,context,userParams,callback)
// get a list of the revisions for a tiddler
{
	context = this.setContext(context,userParams,callback);

	var uriTemplate = '%0/api.php?format=json&action=query&prop=revisions&titles=%1&rvlimit=%2&rvprop=ids|flags|timestamp|user|comment';
	if(!limit)
		limit = 5;
	var host = this.fullHostName(context.host);
	var uri = uriTemplate.format([host,adaptor.normalizedTitle(title),limit]);
	var req = adaptor.doHttpGET(uri,adaptor.getTiddlerRevisionListCallback,context);
	return typeof req == 'string' ? req : true;
};

adaptor.getTiddlerRevisionListCallback = function(status,context,responseText,uri,xhr)
{
	context.status = false;
	if(status) {
		var content = null;
		try {
			eval('var info=' + responseText);
			var page = adaptor.anyChild(info.query.pages);
			var title = page.title;
			var revisions = page.revisions;
			var list = [];
			for(var i=0;i<revisions.length;i++) {
				var tiddler = new Tiddler(title);
				tiddler.modified = adaptor.dateFromTimestamp(revisions[i].timestamp);
				tiddler.modifier = revisions[i].user;
				tiddler.fields.comment = revisions[i].comment;
				tiddler.fields['server.page.id'] = adaptor.normalizedTitle(title);
				tiddler.fields['server.page.name'] = title;
				tiddler.fields['server.page.revision'] = String(revisions[i].revid);
				list.push(tiddler);
			}
			context.revisions = list;
		} catch (ex) {
			context.statusText = exceptionText(ex,adaptor.serverParsingErrorMessage);
			if(context.callback)
				context.callback(context,context.userParams);
			return;
		}
		context.status = true;
	} else {
		context.statusText = xhr.statusText;
	}
	if(context.callback)
		context.callback(context,context.userParams);
};



adaptor.prototype.putTiddler = function(tiddler,context,userParams,callback)
{
	context = this.setContext(context,userParams,callback);
	context.tiddler = tiddler;
	context.title = tiddler.title;
	return this.complete(context,adaptor.putTiddlerComplete);
};


adaptor.putTiddlerComplete = function(context,userParams)
{
	var uriTemplate = '%0/api.php?format=json&action=query&prop=info|revisions&intoken=edit&titles=%1';
	var uri = uriTemplate.format([context.host,escape(adaptor.normalizedTitle(context.tiddler.title))]);

	var req = adaptor.doHttpGET(uri,adaptor.putTiddlerCallback,context);
	return typeof req == 'string' ? req : true;
};

adaptor.putTiddlerCallback = function(status,context,responseText,uri,xhr)
{
	if(status) {
		try {
			eval('var info=' + responseText);
			var page = adaptor.anyChild(info.query.pages);
			var token = page.edittoken;
			token = token.substr(0,token.length-2) + '%2B%5C';
		} catch (ex) {
			context.statusText = exceptionText(ex,adaptor.serverParsingErrorMessage);
			if(context.callback)
				context.callback(context,context.userParams);
			return;
		}
		context.status = true;
		var uriTemplate = '%0/api.php?format=json&action=edit&title=%1&text=%2&basetimestamp=%3&token=%4';
		var tiddler = context.tiddler;
		var timestamp = tiddler.fields['server.page.timestamp'];
		uri = uriTemplate.format([context.host,escape(adaptor.normalizedTitle(tiddler.title)),escape(tiddler.text),timestamp,token]);
		var req = adaptor.doHttpPOST(uri,adaptor.putTiddlerCallback2,context,{"Content-Length":"1"}," ","application/x-www-form-urlencoded");
	} else {
		context.status = false;
		context.statusText = xhr.statusText;
		if(context.callback)
			context.callback(context,context.userParams);
	}
};

adaptor.putTiddlerCallback2 = function(status,context,responseText,uri,xhr)
{
	var info;
	context.statusText = xhr.statusText;
	try {
		eval('info=' + responseText + ';');
	} catch(ex) {
		status = false;
		context.status = false;
		context.statusText = 'putTiddler exception';
	}
	if(status) {
		context.status = true;
	} else {
		context.status = false;
	}
	if(info && info.error) {
		context.status = false;
		context.statusText = info.error.info;
	}
	if(context.callback)
		context.callback(context,context.userParams);
};

/*adaptor.prototype.deleteTiddler = function(tiddler,context,userParams,callback)
{
	context = this.setContext(context,userParams,callback);
	context.title = tiddler.title;
	return this.complete(context,adaptor.deleteTiddlerComplete);
};*/

adaptor.deleteTiddlerComplete = function(context,userParams)
{
	var uriTemplate = '%0/api.php?format=json&action=query&prop=intoken=edit&titles=%1';
	var uri = uriTemplate.format([context.host,escape(adaptor.normalizedTitle(context.tiddler.title))]);

	var req = adaptor.doHttpGET(uri,adaptor.deleteTiddlerCallback,context);
	return typeof req == 'string' ? req : true;
};

adaptor.deleteTiddlerCallback = function(context,userParams)
{
	if(status) {
		try {
			eval('var info=' + responseText);
			var page = adaptor.anyChild(info.query.pages);
			var token = page.edittoken;
			token = token.substr(0,token.length-2) + '%2B%5C';
		} catch (ex) {
			context.statusText = exceptionText(ex,adaptor.serverParsingErrorMessage);
			if(context.callback)
				context.callback(context,context.userParams);
			return;
		}
		context.status = true;
		var uriTemplate = '%0/api.php?action=delete&title=%1&token=%2';
		var uri = uriTemplate.format([context.host,context.workspace,escape(adaptor.normalizedTitle(context.title)),token]);
		var req = adaptor.doHttpPOST(uri,adaptor.deleteTiddlerCallback,context,{"Content-Length":"1"}," ");
	} else {
		context.status = false;
		context.statusText = xhr.statusText;
		if(context.callback)
			context.callback(context,context.userParams);
	}
};

adaptor.deleteTiddlerCallback2 = function(status,context,responseText,uri,xhr)
{
	if(status) {
		context.status = true;
	} else {
		context.status = false;
		context.statusText = xhr.statusText;
	}
	if(context.callback)
		context.callback(context,context.userParams);
};

})(config.adaptors.mediawiki);

} // end of 'install only once'
//}}}
/***
|''Name:''|MediaWikiFormatterPlugin|
|''Description:''|Allows Tiddlers to use [[MediaWiki|http://meta.wikimedia.org/wiki/Help:Wikitext]] ([[WikiPedia|http://meta.wikipedia.org/]]) text formatting|
|''Author:''|Martin Budden (mjbudden (at) gmail (dot) com)|
|''Source:''|http://www.martinswiki.com/#MediaWikiFormatterPlugin |
|''CodeRepository:''|http://svn.tiddlywiki.org/Trunk/contributors/MartinBudden/formatters/MediaWikiFormatterPlugin.js |
|''Version:''|0.5.14|
|''Date:''|Jul 27, 2007|
|''Comments:''|Please make comments at http://groups.google.co.uk/group/TiddlyWikiDev |
|''License:''|[[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/3.0/]] |
|''~CoreVersion:''|2.1.0|

|''Display instrumentation''|<<option chkDisplayInstrumentation>>|
|''Allow zooming of thumbnail images''|<<option chkMediaWikiDisplayEnableThumbZoom>>|
|''List references''|<<option chkMediaWikiListReferences>>|
|''Display unsupported magic words''|<<option chkDisplayMediaWikiMagicWords>>|
|''Use host images''|<<option chkUseHostImages>>|

This is the MediaWikiFormatterPlugin, which allows you to insert MediaWiki formated text into a TiddlyWiki.

The aim is not to fully emulate MediaWiki, but to allow you to work with MediaWiki content off-line and then resync the content with your MediaWiki later on, with the expectation that only minor edits will be required.

To use MediaWiki format in a Tiddler, tag the Tiddler with MediaWikiFormat or set the tiddler's {{{wikiformat}}} extended field to {{{mediawiki}}}.

!!!Issues
There are (at least) the following known issues:
# Not all styles from http://meta.wikimedia.org/wiki/MediaWiki:Common.css incorporated
## Styles for tables don't yet match Wikipedia styles.
## Styles for image galleries don't yet match Wikipedia styles.
# Anchors not yet supported.

!!!Not supported
# Template parser functions (also called colon functions) http://meta.wikimedia.org/wiki/ParserFunctions eg &#123;&#123; #functionname: argument 1 | argument 2 | argument 3... &#125;&#125;
# Magic words and variables http://meta.wikimedia.org/wiki/Help:Magic_words eg {{{__TOC__}}}, &#123;&#123;CURRENTDAY&#125;&#125;, &#123;&#123;PAGENAME&#125;&#125;
# {{{^''}}} (italic at start of line) indents, makes italic and quotes with guilmot quote

!!!No plans to support
# Template substitution on save http://meta.wikimedia.org/wiki/Help:Substitution eg &#123;&#123; subst: templatename &#125;&#125;

***/

//{{{
// Ensure that the MediaWikiFormatter Plugin is only installed once.
if(!version.extensions.MediaWikiFormatterPlugin) {
version.extensions.MediaWikiFormatterPlugin = {installed:true};

if(version.major < 2 || (version.major == 2 && version.minor < 1))
	{alertAndThrow('MediaWikiFormatterPlugin requires TiddlyWiki 2.1 or later.');}

if(config.options.chkDisplayInstrumentation == undefined)
	{config.options.chkDisplayInstrumentation = false;}

if(config.options.chkMediaWikiDisplayEnableThumbZoom == undefined)
	{config.options.chkMediaWikiDisplayEnableThumbZoom = false;}
if(config.options.chkMediaWikiListReferences == undefined)
	{config.options.chkMediaWikiListReferences = false;}
if(config.options.chkDisplayMediaWikiMagicWords == undefined)
	{config.options.chkDisplayMediaWikiMagicWords = false;}
if(config.options.chkUseHostImages == undefined)
	{config.options.chkUseHostImages = false;}


//<div class='viewer' macro='view text wikified'></div>;

config.macros.include = {};
config.macros.include.handler = function(place,macroName,params,wikifier,paramString,tiddler)
{
	if((tiddler instanceof Tiddler) && params[0]) {
		var host = store.getValue(tiddler,'server.host');
		if(host && host.indexOf('wikipedia')!=-1) {
			var t = store.fetchTiddler(params[0]);
			var text = store.getValue(t,'text');
			wikify(text,place,highlightHack,tiddler);
		}
	}
};


MediaWikiFormatter = {}; // 'namespace' for local functions

mwDebug = function(out,str)
{
	createTiddlyText(out,str.replace(/\n/mg,'\\n').replace(/\r/mg,'RR'));
	createTiddlyElement2(out,'br');
};

MediaWikiFormatter.Tiddler_changed = Tiddler.prototype.changed;
Tiddler.prototype.changed = function()
{
	if((this.fields.wikiformat==config.parsers.mediawikiFormatter.format) || this.isTagged(config.parsers.mediawikiFormatter.formatTag)) {
		this.links = [];
		var tiddlerLinkRegExp = /\[\[(?::?([A-Za-z]{2,}:)?)(#?)([^\|\]]*?)(?:(\]\])|(\|(.*?)\]\]))/mg;
		tiddlerLinkRegExp.lastIndex = 0;
		var match = tiddlerLinkRegExp.exec(this.text);
		while(match) {
			if(!match[1] && !match[2])
				this.links.pushUnique(match[3]);
			match = tiddlerLinkRegExp.exec(this.text);
		}
	} else if(!this.isTagged('systemConfig')) {
		MediaWikiFormatter.Tiddler_changed.apply(this,arguments);
		return;
	}
	this.linksUpdated = true;
};

TiddlyWiki.prototype.getMediaWikiPagesInNamespace = function(namespace)
{
	var results = [];
	this.forEachTiddler(function(title,tiddler) {
		if(tiddler.title.indexOf(namespace)==0)
			results.push(tiddler);
		});
	results.sort(function(a,b) {return a.title < b.title ? -1 : +1;});
	return results;
};

TiddlyWiki.prototype.getMediaWikiPages = function()
{
	var results = [];
	this.forEachTiddler(function(title,tiddler) {
		if(!tiddler.isTagged('excludeLists') && tiddler.title.indexOf(':')==-1)
			results.push(tiddler);
		});
	results.sort(function(a,b) {return a.title < b.title ? -1 : +1;});
	return results;
};

TiddlyWiki.prototype.getMediaWikiOtherPages = function()
{
	var results = [];
	this.forEachTiddler(function(title,tiddler) {
		if(!tiddler.isTagged('excludeLists') && tiddler.title.indexOf(':')!=-1)
			results.push(tiddler);
		});
	results.sort(function(a,b) {return a.title < b.title ? -1 : +1;});
	return results;
};

config.macros.list.otherpages = {};
config.macros.list.otherpages.handler = function(params)
{
	return store.getMediaWikiOtherPages();
};

config.macros.list.templates = {};
config.macros.list.templates.handler = function(params)
{
	return store.getMediaWikiPagesInNamespace('Template:');
};

config.macros.list.categories = {};
config.macros.list.categories.handler = function(params)
{
	return store.getMediaWikiPagesInNamespace('Category:');
};

function createTiddlyElement2(parent,element)
{
	return parent.appendChild(document.createElement(element));
}

config.formatterHelpers.createElementAndWikify = function(w)
{
	w.subWikifyTerm(createTiddlyElement2(w.output,this.element),this.termRegExp);
};

MediaWikiFormatter.hijackListAll = function ()
{
	MediaWikiFormatter.oldListAll = config.macros.list.all.handler;
	config.macros.list.all.handler = function(params) {
		return store.getMediaWikiPages();
	};
};
MediaWikiFormatter.hijackListAll();

MediaWikiFormatter.fullHostName = function(host)
{
	if(!host)
		return '';
	host = host.trim();
	if(!host.match(/:\/\//))
		host = 'http://' + host;
	if(host.substr(host.length-1) != '/')
		host = host + '/';
	return host;
};

MediaWikiFormatter.normalizedTitle = function(title)
{
	title = title.trim();
	var n = title.charAt(0).toUpperCase() + title.substr(1);
	return n.replace(/\s/g,'_');
};

MediaWikiFormatter.readToDelim = function(w)
//!!! this is a bit rubish, needs doing properly.
{
	var dRegExp = /\|/mg;
	var sRegExp = /\[\[/mg;
	var tRegExp = /\]\]/mg;

	dRegExp.lastIndex = w.startMatch;
	var dMatch = dRegExp.exec(w.source);
	sRegExp.lastIndex = w.startMatch;
	var sMatch = sRegExp.exec(w.source);
	tRegExp.lastIndex = w.startMatch;
	var tMatch = tRegExp.exec(w.source);
	if(!tMatch) {
		return false;
	}

	while(sMatch && sMatch.index<tMatch.index) {
		if(dMatch && dMatch.index<sMatch.index) {
			w.nextMatch = dRegExp.lastIndex;
			w.matchLength = dMatch.index - w.startMatch;
			return true;
		}
		tRegExp.lastIndex = sRegExp.lastIndex;
		tMatch = tRegExp.exec(w.source);
		
		w.nextMatch = tRegExp.lastIndex;
		dRegExp.lastIndex = w.nextMatch;
		dMatch = dRegExp.exec(w.source);
		sRegExp.lastIndex = w.nextMatch;
		sMatch = sRegExp.exec(w.source);
		tRegExp.lastIndex = w.nextMatch;
		tMatch = tRegExp.exec(w.source);
	}
		
	if(dMatch && dMatch.index<tMatch.index) {
		w.nextMatch = dRegExp.lastIndex;
		w.matchLength = dMatch.index - w.startMatch;
		return true;
	}
	if(tMatch) {
		w.nextMatch = tRegExp.lastIndex;
		w.matchLength = tMatch.index - w.startMatch;
		return false;
	}
	w.nextMatch = tRegExp.lastIndex;
	w.matchLength = -1;
	return false;
};

MediaWikiFormatter.getParams = function(w)
{
	var params = [];
	var i = 1;
	w.startMatch = w.nextMatch;
	var read = MediaWikiFormatter.readToDelim(w);
	if(w.matchLength!=-1) {
		params[i] = w.source.substr(w.startMatch,w.matchLength);
	}
	while(read) {
		i++;
		w.startMatch = w.nextMatch;
		read = MediaWikiFormatter.readToDelim(w);
		if(w.matchLength!=-1) {
			params[i] = w.source.substr(w.startMatch,w.matchLength);
		}
	}
	return params;
};

MediaWikiFormatter.setFromParams = function(w,p)
{
	var r = {};
	var re = /\s*(.*?)=(?:(?:"(.*?)")|(?:'(.*?)')|((?:\w|%|#)*))/mg;
	var match = re.exec(p);
	while(match)
		{
		var s = match[1].unDash();
		if(match[2]) {
			r[s] = match[2];
		} else if(match[3]) {
			r[s] = match[3];
		} else {
			r[s] = match[4];
		}
		match = re.exec(p);
	}
	return r;
};

MediaWikiFormatter.setAttributesFromParams = function(e,p)
{
	var re = /\s*(.*?)=(?:(?:"(.*?)")|(?:'(.*?)')|((?:\w|%|#)*))/mg;
	var match = re.exec(p);
	while(match) {
		var s = match[1].unDash();
		if(s == 'bgcolor') {
			s = 'backgroundColor';
		}
		try {
			if(match[2]) {
				e.setAttribute(s,match[2]);
			} else if(match[3]) {
				e.setAttribute(s,match[3]);
			} else {
				e.setAttribute(s,match[4]);
			}
		}
		catch(ex) {}
		match = re.exec(p);
	}
};

config.mediawiki = {};
config.mediawiki.formatters = [
{
	name: 'mediaWikiHeading',
	match: '^={1,6}(?!=) *\\n?',
	termRegExp: /(={1,6} *\n)/mg,
	handler: function(w)
	{
		var output = w.output;
		var e = createTiddlyElement2(output,'h' + w.matchLength);
		var a = createTiddlyElement2(e,'a');
		var t = w.tiddler ? MediaWikiFormatter.normalizedTitle(w.tiddler.title) + ':' : '';
		var len = w.source.substr(w.nextMatch).indexOf('=\n');
		while(w.source.substr(w.nextMatch+len-1,1)=='=') {
			len--;
		}
		a.setAttribute('name',t+MediaWikiFormatter.normalizedTitle(w.source.substr(w.nextMatch,len)));
		w.subWikifyTerm(e,this.termRegExp);
	}
},

{
	name: 'mediaWikiTable',
	match: '^\\{\\|', // ^{|
	handler: function(w)
	{
		var pair = MediaWikiTemplate.findTableBracePair(w.source,w.matchStart);
		if(pair.start==w.matchStart) {
			w.nextMatch = w.matchStart;
			var table = createTiddlyElement2(w.output,'table');
			var tbody = createTiddlyElement2(table,'tbody');// needed for IE
			var mwt = new MediaWikiTemplate();
			mwt.wikifyTable(tbody,w,pair);
		}
	}
},

{
	name: 'mediaWikiList',
	match: '^[\\*#;:]+',
	lookaheadRegExp: /(?:(?:(\*)|(#)|(;)|(:))+)(?: ?)/mg,
	termRegExp: /(\n)/mg,
	handler: function(w)
	{
		var stack = [w.output];
		var currLevel = 0, currType = null;
		var listType, itemType;
		w.nextMatch = w.matchStart;
		this.lookaheadRegExp.lastIndex = w.nextMatch;
		var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
		while(lookaheadMatch && lookaheadMatch.index == w.nextMatch) {
			if(lookaheadMatch[1]) {
				listType = 'ul';
				itemType = 'li';
			} else if(lookaheadMatch[2]) {
				listType = 'ol';
				itemType = 'li';
			} else if(lookaheadMatch[3]) {
				listType = 'dl';
				itemType = 'dt';
			} else if(lookaheadMatch[4]) {
				listType = 'dl';
				itemType = 'dd';
			}
			var listLevel = lookaheadMatch[0].length;
			w.nextMatch += listLevel;
			if(listLevel > currLevel) {
				for(var i=currLevel; i<listLevel; i++) {
					stack.push(createTiddlyElement2(stack[stack.length-1],listType));
				}
			} else if(listLevel < currLevel) {
				for(i=currLevel; i>listLevel; i--) {
					stack.pop();
				}
			} else if(listLevel == currLevel && listType != currType) {
				stack.pop();
				stack.push(createTiddlyElement2(stack[stack.length-1],listType));
			}
			currLevel = listLevel;
			currType = listType;
			var e = createTiddlyElement2(stack[stack.length-1],itemType);
			var ci = w.source.indexOf(':',w.nextMatch);
			var ni = w.source.indexOf('\n',w.nextMatch);
			if(itemType=='dt' && (ni==-1 || (ci!=-1 && ci<ni))) {
				w.subWikifyTerm(e,/(:)/mg);
				w.nextMatch--;
			} else {
				w.subWikifyTerm(e,this.termRegExp);
			}
			this.lookaheadRegExp.lastIndex = w.nextMatch;
			lookaheadMatch = this.lookaheadRegExp.exec(w.source);
		}
	}
},

{
	name: 'mediaWikiRule',
	match: '^----+$\\n?',
	handler: function(w)
	{
		createTiddlyElement2(w.output,'hr');
	}
},

/*{
	name: 'mediaWikiLeadingSpaces',
	match: '^ ',
	lookaheadRegExp: /^ /mg,
	termRegExp: /(\n)/mg,
	handler: function(w)
	{
		var e = createTiddlyElement2(w.output,'pre');
		while(true) {
			w.subWikifyTerm(e,this.termRegExp);
			createTiddlyElement2(e,'br');
			this.lookaheadRegExp.lastIndex = w.nextMatch;
			var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
			if(lookaheadMatch && lookaheadMatch.index == w.nextMatch) {
				w.nextMatch += lookaheadMatch[0].length;
			} else {
				break;
			}
		}
	}
},*/


{
	name: 'mediaWikiImage',
	match: '\\[\\[(?:[Ii]mage|Bild):',
	lookaheadRegExp: /\[\[(?:[Ii]mage|Bild):/mg,
	defaultPx: 180,
	handler: function(w)
	{
		this.lookaheadRegExp.lastIndex = w.matchStart;
		var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
		if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
			var params = MediaWikiFormatter.getParams(w);
			var src = params[1];
			src = src.trim().replace(/ /mg,'_');
			src = src.substr(0,1).toUpperCase() + src.substring(1);
			var palign = null;
			var ptitle = '';
			var psrc = false;
			var px = null;
			var pthumb = false;
			var pframed = false;
			for(var i=2;i<params.length;i++) {
				var p = params[i];
				if(p=='right'||p=='left'||p=='center'||p=='none') {
					palign = p;
				} else if(p=='thumbnail'||p=='thumb') {
					pthumb = true;
				} else if(p=='framed') {
					pframed = true;
				} else if(/\d{1,4} ?px/.exec(p)) {
					px = p.substr(0,p.length-2).trim();
				} else {
					ptitle = p;
				}
			}//#end for
			if(pthumb) {
				var output = w.output;
				if(!palign) {
					palign = 'right';
				}
				if(!px) {
					px = 180;
				}
				psrc = px + 'px-' + src;
				var t = createTiddlyElement(output,'div',null,'thumb'+(palign?' t'+palign:''));
				var s = createTiddlyElement2(t,'div');
				s.style['width'] = Number(px) + 2 + 'px';
				var a = createTiddlyElement(s,'a',null,'internal');
				if(config.options.chkMediaWikiDisplayEnableThumbZoom) {
					a.href = src;
				}
				a.title = ptitle;
				var img = createTiddlyElement2(a,'img');
				img.src = 'images/' + psrc;
				if(config.options.chkUseHostImages && Crypto.hexMd5Str) {
					var md5 = Crypto.hexMd5Str(src);
					var md5dir = '/' + (md5.substr(0,1) + '/' + md5.substr(0,2)).toLowerCase();
					img.src = MediaWikiFormatter.fullHostName(w.tiddler.fields['server.host']||config.defaultCustomFields['server.host']);
					var imgDir = 'images';
					//if(img.src=='http://en.wikipedia.org/w/') {
					if(img.src.indexOf('wikipedia.org/')!=-1) {
						//imgDir = 'wikipedia/en';
						imgDir = 'wikipedia/commons';
						img.src = 'http://upload.wikimedia.org/';
					}	
					img.src += imgDir;
					img.src += '/thumb' + md5dir + '/' + src + '/' + psrc;
				}

				img.width = px;
				img.longdesc = 'Image:' + src;
				img.alt = ptitle;

				var tc = createTiddlyElement(s,'div',null,'thumbcaption');
				var oldSource = w.source; var oldMatch = w.nextMatch;
				w.source = ptitle; w.nextMatch = 0;
				w.subWikifyUnterm(tc);
				w.source = oldSource; w.nextMatch = oldMatch;

				if(config.options.chkMediaWikiDisplayEnableThumbZoom) {
					var tm = createTiddlyElement(tc,'div',null,'magnify');
					tm.style['float'] = 'right';
					var ta = createTiddlyElement(tm,'a',null,'internal');
					ta.title = 'Enlarge';
					timg = createTiddlyElement2(ta,'img'); timg.src = 'magnify-clip.png'; timg.alt = 'Enlarge'; timg.width = '15'; timg.height = '11';
					ta.href = src;
				}
			} else {
				a = createTiddlyElement(w.output,'a',null,'image');
				a.title = ptitle;
				img = createTiddlyElement2(a,'img');
				if(palign) {img.align = palign;}
				if(px) {img.width = px;}
				img.longdesc = 'Image:' + src;
				img.alt = ptitle;
				if(config.options.chkUseHostImages) {
					md5dir = '';
					if(Crypto.hexMd5Str) {
						md5 = Crypto.hexMd5Str(src);
						md5dir = '/'+ (md5.substr(0,1) + '/' + md5.substr(0,2)).toLowerCase();
					}
					img.src = MediaWikiFormatter.fullHostName(w.tiddler.fields['server.host']||config.defaultCustomFields['server.host']);
					imgDir = 'images';
					if(img.src.indexOf('wikipedia.org/')!=-1) {
						imgDir = 'wikipedia/commons';
						img.src = 'http://upload.wikimedia.org/';
					}	
					img.src += imgDir + md5dir + '/' + src;
				} else {
					img.src = px ? 'images/' + px + 'px-' + src : 'images/' + src;
				}
			}
		}
	}//#end image handler
},

{
	name: 'mediaWikiExplicitLink',
	match: '\\[\\[',
	lookaheadRegExp: /\[\[(?:([a-z]{2,3}:)?)(#?)([^\|\]]*?)(?:(\]\](\w*))|(\|(.*?)\]\]))/mg,
	handler: function(w)
	{
		this.lookaheadRegExp.lastIndex = w.matchStart;
		var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
		if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
			if(!lookaheadMatch[1]) {
				var e;
				var link = lookaheadMatch[3];
				var text = link;
				link = link.substr(0,1).toUpperCase() + link.substring(1);
				if(link.substr(0,1)=='/') {
					link = w.tiddler.title + link;
				} else if(link=='../') {
					link = w.tiddler.title.substr(0,w.tiddler.title.lastIndexOf('/'));
				} else if(link.substr(0,3)=='../') {
					var pos = w.tiddler.title.lastIndexOf('/');
					link = w.tiddler.title.substr(0,pos) + link.substr(2);
				}
				if(lookaheadMatch[4]) {
					if(lookaheadMatch[2]) {
						var a = createTiddlyElement(w.output,'a');
						var t = w.tiddler ? MediaWikiFormatter.normalizedTitle(w.tiddler.title) + ':' : '';
						t = '#' + t + MediaWikiFormatter.normalizedTitle(link);
						a.setAttribute('href',t);
						a.title = '#' + MediaWikiFormatter.normalizedTitle(link);
						createTiddlyText(a,'#'+link);
					} else {
						e = createTiddlyLink(w.output,link,false,null,w.isStatic,w.tiddler);
						if(lookaheadMatch[5]) {
							text += lookaheadMatch[5];
						}
						createTiddlyText(e,text);
					}
				} else if(lookaheadMatch[6]) {
					while(link.charAt(0)==':')
						link = link.substring(1);
					link = MediaWikiFormatter.normalizedTitle(link);
					var i = link.indexOf('#');
					if(i==-1) {
						e = createTiddlyLink(w.output,link,false,null,w.isStatic,w.tiddler);
					} else {
						e = createTiddlyLink(w.output,link.substr(0,i),false,null,w.isStatic,w.tiddler);
					}
					var oldSource = w.source; var oldMatch = w.nextMatch;
					w.source = lookaheadMatch[7].trim(); w.nextMatch = 0;
					w.subWikifyUnterm(e);
					w.source = oldSource; w.nextMatch = oldMatch;
				}
			}
			w.nextMatch = this.lookaheadRegExp.lastIndex;
		}
	}
},

{
	name: 'mediaWikiParagraph',
	match: '\\n{2,}',
	handler: function(w)
	{
		w.output = createTiddlyElement2(w.output,'p');
	}
},

{
	name: 'mediaWikiExplicitLineBreak',
	match: '<br ?/?>',
	handler: function(w)
	{
		createTiddlyElement2(w.output,'br');
	}
},

{
	name: 'mediaWikiExplicitLineBreakWithParams',
	match: "<br(?:\\s*(?:(?:.*?)=[\"']?(?:.*?)[\"']?))*?\\s*/?>",
	lookaheadRegExp: /<br((?:\s+(?:.*?)=["']?(?:.*?)["']?)*?)?\s*\/?>/mg, //'
	handler: function(w)
	{
		this.lookaheadRegExp.lastIndex = w.matchStart;
		var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
		if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
			var e =createTiddlyElement2(w.output,'br');
			if(lookaheadMatch[1]) {
				MediaWikiFormatter.setAttributesFromParams(e,lookaheadMatch[1]);
			}
			w.nextMatch = this.lookaheadRegExp.lastIndex;// empty tag
		}
	}
},

{
	name: 'mediaWikiTitledUrlLink',
	match: '\\[' + config.textPrimitives.urlPattern + '(?:\\s+[^\\]]+)?' + '\\]', //'
	handler: function(w)
	{
		var lookaheadRegExp = new RegExp('\\[(' + config.textPrimitives.urlPattern + ')(?:\\s+([^\[]+))?' + '\\]','mg');
		lookaheadRegExp.lastIndex = w.matchStart;
		var lookaheadMatch = lookaheadRegExp.exec(w.source);
		if(lookaheadMatch && lookaheadMatch.index==w.matchStart) {
			var link = lookaheadMatch[1];
			if(lookaheadMatch[2]) {
				var e = createExternalLink(w.output,link);
				var oldSource = w.source; var oldMatch = w.nextMatch;
				w.source = lookaheadMatch[2].trim(); w.nextMatch = 0;
				w.subWikifyUnterm(e);
				w.source = oldSource; w.nextMatch = oldMatch;
			} else {
				e = createExternalLink(createTiddlyElement2(w.output,'sup'),link);
				if(w.linkCount===undefined)
					w.linkCount = 0;
				w.linkCount++;
				createTiddlyText(e,'['+w.linkCount+']');
			}
			w.nextMatch = lookaheadRegExp.lastIndex;
		}
	}
},

{
	name: 'mediaWikiUrlLink',
	match: config.textPrimitives.urlPattern,
	handler: function(w)
	{
		w.outputText(createExternalLink(w.output,w.matchText),w.matchStart,w.nextMatch);
	}
},

{
	name: "mediaWikiCharacterFormat",
	match: "'{2,5}|(?:<[usbi]>)",
	handler: function(w)
	{
		switch(w.matchText) {
		case "'''''":
			var e = createTiddlyElement(w.output,'strong');
			w.subWikifyTerm(createTiddlyElement(e,'em'),/('''''|(?=\n))/mg);
			break;
		case "'''":
			w.subWikifyTerm(createTiddlyElement(w.output,'strong'),/('''|(?=\n))/mg);
			break;
		case "''":
			w.subWikifyTerm(createTiddlyElement(w.output,'em'),/((?:''(?!'))|(?=\n))/mg);
			break;
		case '<u>':
			w.subWikifyTerm(createTiddlyElement(w.output,'u'),/(<\/u>|(?=\n))/mg);
			break;
		case '<s>':
			w.subWikifyTerm(createTiddlyElement(w.output,'del'),/(<\/s>|(?=\n))/mg);
			break;
		case '<b>':
			w.subWikifyTerm(createTiddlyElement(w.output,'b'),/(<\/b>|(?=\n))/mg);
			break;
		case '<i>':
			w.subWikifyTerm(createTiddlyElement(w.output,'i'),/(<\/i>|(?=\n))/mg);
			break;
		}
	}
},

/*{
	name: 'mediaWikiTemplateParam',
	match: '\\{\\{\\{',
	lookaheadRegExp: /(\{\{\{(?:.|\n)*?\}\}\})/mg,
	element: 'span',
	handler: config.formatterHelpers.enclosedTextHelper
},
*/

{
	name: 'mediaWikiInsertReference',
	match: '<ref[^/]*>',
	lookaheadRegExp: /<ref(\s+(?:.*?)=["']?(?:.*?)["']?)?>([^<]*?)<\/ref>/mg,
	handler: function(w)
	{
		if(config.browser.isIE) {
			refRegExp = /<ref[^\/]*>((?:.|\n)*?)<\/ref>/mg;
			refRegExp.lastIndex = w.matchStart;
			var refMatch = refRegExp.exec(w.source);
			if(refMatch && refMatch.index == w.matchStart) {
				w.nextMatch = refRegExp.lastIndex;
				return;
			}
		}
		this.lookaheadRegExp.lastIndex = w.matchStart;
		var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
		if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
			var x = {id:'',value:''};
			w.nextMatch = this.lookaheadRegExp.lastIndex;
			if(!w.referenceCount) {
				w.referenceCount = 0;
				w.references = {};
			}
			var s = createTiddlyElement(w.output,'sup',null,'reference');
			var a = createTiddlyElement2(s,'a');
			var prefix = w.tiddler ? w.tiddler.title + ':' : '';
			var name;
			if(lookaheadMatch[1]) {
				var r = MediaWikiFormatter.setFromParams(w,lookaheadMatch[1]);
				name = r.name ? r.name.trim() : '';
				name = name.replace(/ /g,'_');
				s.id = prefix + '_ref-' + name;// + '_' + nameCount;(w.referenceCount+1);
				if(!w.references[name]) {
					w.references[name] = x;
					w.references[name].id = w.referenceCount;
					w.references[name].value = lookaheadMatch[2].trim();
				}
			} else {
				w.references[w.referenceCount] = x;
				w.references[w.referenceCount].id = w.referenceCount;
				w.references[w.referenceCount].value = lookaheadMatch[2].trim();
				name = w.referenceCount;
				s.id = prefix + '_ref-' + w.referenceCount;
			}
			w.referenceCount++;
			a.title = lookaheadMatch[2].trim();//mb, extra to wikipedia
			a.href = '#' + prefix + '_note-' + name;
			a.innerHTML = '['+w.referenceCount+']';
		}
	}
},

{
	name: 'mediaWikiListReferences',
	match: '<references ?/>',
	lookaheadRegExp: /<references ?\/>/mg,
	handler: function(w)
	{
		this.lookaheadRegExp.lastIndex = w.matchStart;
		var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
		if(config.options.chkMediaWikiListReferences && w.referenceCount) {
			var ol = createTiddlyElement(w.output,'ol',null,'references');
			var oldSource = w.source;
			if(w.referenceCount>0) {
				for(var i in w.references) {
					var li = createTiddlyElement2(ol,'li');
					var prefix = w.tiddler ? w.tiddler.title + ':' : '';
					var b = createTiddlyElement2(li,'b');
					var a = createTiddlyElement2(b,'a');
					li.id = prefix + '_note-' + i;
					a.href = '#' + prefix + '_ref-' + i;
					a.innerHTML = '^';
					w.source = w.references[i].value;
					w.nextMatch = 0;
					w.subWikifyUnterm(li);
				}
			}
			w.source = oldSource;
		}
		w.nextMatch = this.lookaheadRegExp.lastIndex;
	}
},

{
	name: 'mediaWikiRepeatReference',
	match: '<ref[^/]*/>',
	lookaheadRegExp: /<ref(\s+(?:.*?)=["'](?:.*?)["'])?\s*\/>/mg, //'
	handler: function(w)
	{
		if(config.browser.isIE) {
			refRegExp = /<ref.*?\/>/mg;
			refRegExp.lastIndex = w.matchStart;
			var refMatch = refRegExp.exec(w.source);
			if(refMatch && refMatch.index == w.matchStart) {
				w.nextMatch = refRegExp.lastIndex;
				return;
			}
		}
		this.lookaheadRegExp.lastIndex = w.matchStart;
		var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
		if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
			var x = {id:'',value:''};
			w.nextMatch = this.lookaheadRegExp.lastIndex;
			var s = createTiddlyElement(w.output,"sup",null,"reference");
			var a = createTiddlyElement2(s,"a");
			var prefix = w.tiddler ? w.tiddler.title : '';
			if(lookaheadMatch[1]) {
				var r = {};
				r = MediaWikiFormatter.setFromParams(w,lookaheadMatch[1]);
				var name = r.name ? r.name.trim() : '';
				name = name.replace(/ /g,'_');
				s.id = prefix + '_ref-' + name +'_' + (w.referenceCount+1);
				var count = w.references && w.references[name] ? (w.references[name].id+1) : '?';
			}
			a.href = '#' + prefix + '_note-' + name;
			a.innerHTML = '['+count+']';
			a.title = name;
		}
	}//# end handler
},

{
	name: 'mediaWikiHtmlEntitiesEncoding',
	match: '&#?[a-zA-Z0-9]{2,8};',
	handler: function(w)
	{
		if(!config.browser.isIE)
			createTiddlyElement(w.output,"span").innerHTML = w.matchText;
	}
},

{
	name: 'mediaWikiComment',
	match: '<!\\-\\-',
	lookaheadRegExp: /<!\-\-((?:.|\n)*?)\-\->/mg,
	handler: function(w)
	{
		this.lookaheadRegExp.lastIndex = w.matchStart;
		var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
		if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
			w.nextMatch = this.lookaheadRegExp.lastIndex;
		}
	}
},

{
	name: 'mediaWikiIncludeOnly',
	match: '<includeonly>',
	lookaheadRegExp: /<includeonly>((?:.|\n)*?)<\/includeonly>/mg,
	handler: function(w)
	{
		this.lookaheadRegExp.lastIndex = w.matchStart;
		var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
		if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
			w.nextMatch = this.lookaheadRegExp.lastIndex;
		}
	}
},

{
	name: 'mediaWikiNoWiki',
	match: '<nowiki>',
	lookaheadRegExp: /<nowiki>((?:.|\n)*?)<\/nowiki>/mg,
	element: 'span',
	handler: config.formatterHelpers.enclosedTextHelper
},

{
	name: 'mediaWikiPreNoWiki',
	match: '<pre>\s*<nowiki>',
	lookaheadRegExp: /<pre>\s*<nowiki>((?:.|\n)*?)<\/nowiki>\s*<\/pre>/mg,
	element: 'pre',
	handler: config.formatterHelpers.enclosedTextHelper
},

{
	name: 'mediaWikiPre',
	match: '<pre>',
	lookaheadRegExp: /<pre>((?:.|\n)*?)<\/pre>/mg,
	element: 'pre',
	handler: config.formatterHelpers.enclosedTextHelper
},

{
	name: 'mediaWikiMagicWords',
	match: '__',
	lookaheadRegExp: /__([A-Z]*?)__/mg,
	handler: function(w)
	{
		this.lookaheadRegExp.lastIndex = w.matchStart;
		var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
		if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
			switch(lookaheadMatch[1]) {
			case 'NOTOC':
				break;
			default:
				if(config.options.chkDisplayMediaWikiMagicWords) {
					w.outputText(w.output,w.matchStart,w.nextMatch);
				}
				break;
			}
			w.nextMatch = this.lookaheadRegExp.lastIndex;
		}
	}
},

{
	name: 'mediaWikiGallery',
	match: '<gallery>',
	lookaheadRegExp: /[Ii]mage:(.*?)\n/mg,
	handler: function(w)
	{
		var table = createTiddlyElement(w.output,'table',null,'gallery');
		table.cellspacing = '0';
		table.cellpadding = '0';
		var rowElem = createTiddlyElement2(table,'tr');
		var col = 0;
		this.lookaheadRegExp.lastIndex = w.matchStart;
		var nM = w.nextMatch;
		var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
		var oldSource = w.source;
		while(lookaheadMatch) {
			nM += lookaheadMatch[1].length;
			w.source = lookaheadMatch[1] +']]';//!! ]] is hack until getParams is working
			w.nextMatch = 0;
			var params = MediaWikiFormatter.getParams(w);
			var src = params[1]||'';
			src = src.trim().replace(/ /mg,'_');
			src = src.substr(0,1).toUpperCase() + src.substring(1);
			var palign = 'right'; 
			var psrc = '120px-'+src;
			var px = 120;
			var pframed = false;
			ptitle = null;
			for(var i=2;i<params.length;i++) {
				var p = params[i];
				if(p=='right'||p=='left'||p=='center'||p=='none') {
					palign = p;
				} else if(p=='framed') {
					pframed = true;
				} else if(/\d{1,4}px/.exec(p)) {
					px = p.substr(0,p.length-2).trim();
					psrc = px + 'px-' + src;
				} else {
					ptitle = p;
				}
			}//#end for
			var td = createTiddlyElement2(rowElem,'td');
			var gb = createTiddlyElement(td,'div',null,'gallerybox');
			var t = createTiddlyElement(gb,'div',null,'thumb');
			t.style['padding'] = '26px 0';

			var a = createTiddlyElement2(t,'a');
			if(config.options.chkMediaWikiDisplayEnableThumbZoom) {
				a.href = src;
			}
			a.title = ptitle;
			var img = createTiddlyElement2(a,'img');
			img.src = psrc;
			img.width = px;
			img.alt = '';

			var gt = createTiddlyElement(gb,'div',null,'gallerytext');
			p = createTiddlyElement2(gt,'p');
			var oldSource2 = w.source; var oldMatch = w.nextMatch;
			w.source = ptitle; w.nextMatch = 0;
			w.subWikifyUnterm(p);
			w.source = oldSource2; w.nextMatch = oldMatch;

			col++;
			if(col>3) {
				rowElem = createTiddlyElement2(table,'tr');
				col = 0;
			}
			w.source = oldSource;
			lookaheadMatch = this.lookaheadRegExp.exec(w.source);
		}
		w.nextMatch = nM + '<gallery>'.length*2+1+'Image:'.length;//!! hack
	}
},

{
	name: 'mediaWikiHtmlTag',
	match: "<[a-zA-Z0-9]{2,}(?:.*?)>",
	//match: "<[a-zA-Z]{2,}(?:\\s*(?:(?:.*?)=[\"']?(?:.*?)[\"']?))*?>",
	lookaheadRegExp: /<([a-zA-Z0-9]{2,})((?:\s+(?:.*?)=(["']?)(?:.*?)\3?)*?)?\s*(\/)?>/mg, //'
	handler: function(w)
	{
		this.lookaheadRegExp.lastIndex = w.matchStart;
		var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
		if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
			var e =createTiddlyElement2(w.output,lookaheadMatch[1]);
			if(lookaheadMatch[2]) {
				MediaWikiFormatter.setAttributesFromParams(e,lookaheadMatch[2]);
			}
			if(lookaheadMatch[4]) {
				w.nextMatch = this.lookaheadRegExp.lastIndex;
			} else {
				w.subWikify(e,'</'+lookaheadMatch[1]+'>');
			}
		}
	}
}
];

config.parsers.mediawikiFormatter = new Formatter(config.mediawiki.formatters);
config.parsers.mediawikiFormatter.format = 'mediawiki';
config.parsers.mediawikiFormatter.formatTag = 'MediaWikiFormat';

MediaWikiTemplate = function()
{
	this.stack = [];
	this.error = false;
	this.tiddler = null;
};

MediaWikiTemplate.findRawDelimiter = function(delimiter,text,start)
{
	var d = text.indexOf(delimiter,start);
	if(d==-1)
		return -1;
	var b = {start:-1,end:-1};
	var bs = text.indexOf('[[',start);
	var bi = text.indexOf('{{',start);
	if((bi==-1 || bi > d) && (bs==-1 || bs >d))
		return d;
	var s1 = -1;
	if(bs!=-1 && bs <d) {
		var be = text.indexOf(']]',bs);
		if(be!=-1) {
			b.start = bs;
			b.end = be;
		}
	}
	if(b.start!=-1 && d>b.start)
		s1 = b.end+2;
	var db = MediaWikiTemplate.findDBP(text,start);
	if(db.end!=-1 && d>db.start) {
		if(db.end+2>s1)
			s1 = db.end+2;
	}
	var tb = MediaWikiTemplate.findTBP(text,start);
	if(tb.end!=-1 && d>tb.start) {
		if(tb.end+3>s1)
			s1 = tb.end+3;
	}
	return s1==-1 ? d : MediaWikiTemplate.findRawDelimiter(delimiter,text,s1);
};

/*
* Matched sets of four consecutive braces are interpreted as a parameter surrounded by single braces:
	{{{{foo}}}} is equivalent to { {{{foo}}} }.
* Unmatched sets of four braces are interpreted as nested template calls:
	{{{{TEx1}} }} is parsed as a call to a template, the name of which is dependent on the output of TEx1.
In this example, {{{{TEx1}} }} results in Template:Hello world!, as the Hello world! template does not exist.
* Matched sets of five consecutive braces are interpreted as a template call surrounding a parameter:
	{{{{{foo}}}}} is equivalent to {{ {{{foo}}} }}.
* Unmatched sets of five braces are interpreted using the standard rules:
	{{{{{TEx1}} }}} is interpreted as a named parameter with the name dependent on the result of Template:TEx1,
	which in this case is equivalent to {{{Hello world!}}}.
*/
//	dbrTest('{{ {{{a}}} b }} {{c}}',0,0,13);
MediaWikiTemplate.findDBP = function(text,start,end)
// findDoubleBracePair
{
	var ret = {start:-1,end:-1};
	var s = text.indexOf('{{',start);
	if(s==-1) {
		return ret;
	}
	if(end && s>end)
		return ret;
	if(text.substr(s+2,1)!='{') {
		var e = text.indexOf('}}',s+2);
		if(e==-1)
			return ret;
		var s2 = text.indexOf('{{',s+2);
		if(s2==-1 || s2 > e)
			return {start:s,end:e};
		var si = s+2;
		var db = MediaWikiTemplate.findDBP(text,si,e);
		var tb = MediaWikiTemplate.findTBP(text,si,e);
		while((db.end!=-1 && e>db.start && e<=db.end) || (tb.end!=-1 && e>tb.start && e<=tb.end)) {
			if(db.end!=-1 && e>db.start && e<=db.end) {
				si = db.end+2;
				if(tb.end!=-1 && e>tb.start && e<=tb.end) {
					if(tb.end>db.end)
						si = tb.end+3;
				}
			} else {
				si = tb.end+3;
			}			
			e = text.indexOf('}}',si);
			db = MediaWikiTemplate.findDBP(text,si,e);
			tb = MediaWikiTemplate.findTBP(text,si,e);
			if(e==-1) {
				return ret;
			}
		}
		return {start:s,end:e};
	}
	var c = 2;
	while(text.substr(s+c,1)=='{') {
		c++;
	}
	if(c==3) {
		//tb = MediaWikiTemplate.findTBP(text,s);
		//return tb.end==-1 ? ret : MediaWikiTemplate.findDBP(text,tb.end+3);
		return MediaWikiTemplate.findDBP(text,s+3);
	} else if(c==4) {
		db = MediaWikiTemplate.findDBP(text,s+2);
		if(db.end==-1)
			return ret;
		if(text.substr(db.end+2,2)=='}}') {
			return MediaWikiTemplate.findDBP(text,db.end+4);
		} else {
			e = text.indexOf('}}',db.end+2);
			return e==-1 ? ret : {start:s,end:e};
		}
	} else if(c==5) {
		db = MediaWikiTemplate.findDBP(text,s+3);
		if(db.end==-1)
			return ret;
		if(text.substr(db.end+2,3)=='}}}') {
			// it's matched
			return {start:s,end:db.end+3};
		} else if(text.substr(db.end+2,1)!='}') {
			// it's not matched
			// {{{{{x}} }}}
			return {start:s+3,end:db.end};
		} else {
			// }}} }}
			e = text.indexOf('}}',db.end+3);
			return e==-1 ? ret : {start:s,end:e};
		}
	} else {
		return MediaWikiTemplate.findDBP(text,s+6);
	}
};

MediaWikiTemplate.findTBP = function(text,start,end)
// findTripleBracePair
{
	var ret = {start:-1,end:-1};
	var s = text.indexOf('{{{',start);
	if(s==-1)
		return ret;
	if(end && s>end)
		return ret;
	if(text.substr(s+3,1)!='{' || text.substr(s+3,3)=='{{{') {
		var si = s+3;
		var e = text.indexOf('}}}',si);
		if(e==-1)
			return ret;
		var s2 = text.indexOf('{{',si);
		if(s2==-1 || s2 > e)
			return {start:s,end:e};
		var db = MediaWikiTemplate.findDBP(text,si,e);
		var tb = MediaWikiTemplate.findTBP(text,si,e);
//	console.log('t:'+text.substr(s,100));
		while((db.end!=-1 && e>=db.end) || (tb.end!=-1 && e>=tb.end)) {
			if(db.end!=-1 && e>=db.end) {
				si = db.end+2;
				if(tb.end!=-1 && e>=tb.end) {
					if(tb.end>=db.end)
						si = tb.end+3;
				}
			} else {
				si = tb.end+3;
			}
			db = MediaWikiTemplate.findDBP(text,si,e);
			tb = MediaWikiTemplate.findTBP(text,si,e);
			e = text.indexOf('}}}',si);
			if(e==-1)
				return ret;
		}
		return {start:s,end:e};
	}
	var c = 3;
	while(text.substr(s+c,1)=='{') {
		c++;
	}
	if(c==4) {
		tb = MediaWikiTemplate.findTBP(text,s+1);
		if(tb.end==-1)
			return ret;
		if(text.substr(tb.end+1,1)=='}') {
			return {start:s+1,end:tb.end};
		} else {
			return MediaWikiTemplate.findTBP(text,tb.end+4);
		}
	} else if(c==5) {
		db = MediaWikiTemplate.findDBP(text,s+3);
		if(db.end==-1)
			return ret;
		if(text.substr(db.end+2,3)=='}}}') {
			return {start:s+2,end:db.end};
		} else if(text.substr(db.end+2,1)!='}') {
			e = text.indexOf('}}}',db.end+2);
			return e==-1 ? ret : {start:s,end:e};
		} else {
			return {start:s+2,end:db.end};
		}
	}
};

MediaWikiTemplate.findTableBracePair = function(text,start)
{
	var ret = {start:-1,end:-1};
	var s = text.indexOf('{|',start);
	if(s==-1)
		return ret;
	var e = text.indexOf('\n|}',s+2);
	if(e==-1)
		return ret;
	e++;
	var s2 = text.indexOf('{|',s+2);
	if(s2==-1 || s2 > e)
		return {start:s,end:e};
	var tp = MediaWikiTemplate.findTableBracePair(text,s+2);
	while(tp.end!=-1 && e>tp.start && e<=tp.end) {
		e = tp.end+2;
		tp = MediaWikiTemplate.findTableBracePair(text,e);
		e = text.indexOf('\n|}',e);
		if(e==-1)
			return ret;
		e++;
	}
	return {start:s,end:e};
};

MediaWikiTemplate.prototype.wikifyTable = function(table,w,pair)
{
	function lineEnd(w) {
		var r = w.source.indexOf('\n',w.nextMatch);
		while(r!=-1) {
			var n = w.source.substr(r+1,1);
			if(n=='|' || n=='!' || (n=='{' && w.source.substr(r+2,1)=='|'))
				break;
			r = w.source.indexOf('\n',r+1);
		}
		return r;
	}
	function subWikifyText(e,w,text) {
			var oldSource = w.source; var oldMatch = w.nextMatch;
			w.source = text; w.nextMatch = 0;
			w.subWikifyUnterm(e);
			w.source = oldSource; w.nextMatch = oldMatch;
	}		
	w.nextMatch += 2;
	var i = lineEnd(w);
	if(i>w.nextMatch) {
		MediaWikiFormatter.setAttributesFromParams(table.parentNode,w.source.substring(w.nextMatch,i));
		w.nextMatch = i;
	}
	w.nextMatch++;
	if(w.source.substr(w.nextMatch,2)=='|+') {
		var caption = createTiddlyElement2(table,'caption');
		w.nextMatch += 2;
		i = lineEnd(w);
		var d = MediaWikiTemplate.findRawDelimiter('|',w.source,w.nextMatch);
		if(d!=-1 && d<i) {
			MediaWikiFormatter.setAttributesFromParams(caption,w.source.substring(w.nextMatch,d));
			w.nextMatch = d+1;
		}
		w.subWikifyTerm(caption,/(\n)/mg);
	}
	var tr = createTiddlyElement2(table,'tr');
	if(w.source.substr(w.nextMatch,2)=='|-') {
		w.nextMatch += 2;
		i = lineEnd(w);
		//if(i==-1)
		//	break;
		if(i>w.nextMatch) {
			MediaWikiFormatter.setAttributesFromParams(tr,w.source.substring(w.nextMatch,i));
			w.nextMatch = i;
		}
		w.nextMatch++;
	}
	var x = w.source.substr(w.nextMatch,2);
	while(x!='|}') {
		if(x=='{|') {
			var pair2 = MediaWikiTemplate.findTableBracePair(w.source,w.nextMatch);
			if(pair2.start==w.nextMatch) {
				var table2 = createTiddlyElement2(cell,'table');
				this.wikifyTable(table2,w,pair2);
				var y = w.source.substr(w.nextMatch).escapeLineBreaks();
				while(w.source.substr(w.nextMatch,1)=='\n') {
					w.nextMatch++;
				}
			}
		} else if(x=='|-') {
			tr = createTiddlyElement2(table,'tr');
			w.nextMatch += 2;
			i = lineEnd(w);
			if(i==-1)
				break;
			if(i>w.nextMatch) {
				MediaWikiFormatter.setAttributesFromParams(tr,w.source.substring(w.nextMatch,i));
				w.nextMatch = i;
			}
			w.nextMatch++;
		} else if(x.substr(0,1)=='!') {
			w.nextMatch++;
			i = lineEnd(w);
			if(i==-1)
				break;
			var cell = createTiddlyElement2(tr,'th');
			var c = w.source.indexOf('!!',w.nextMatch);
			while(c!=-1 && c<i) {
				d = MediaWikiTemplate.findRawDelimiter('|',w.source,w.nextMatch);
				if(d!=-1 && d<c) {
					MediaWikiFormatter.setAttributesFromParams(cell,w.source.substring(w.nextMatch,d));
					w.nextMatch = d+1;
				}
				while(w.source.substr(w.nextMatch,1)==' ') {
					w.nextMatch++;
				}
				w.subWikifyTerm(cell,/(\!\!)/mg);
				cell = createTiddlyElement2(tr,'th');
				c = w.source.indexOf('!!',w.nextMatch);
			}
			d = MediaWikiTemplate.findRawDelimiter('|',w.source,w.nextMatch);
			if(d!=-1 && d<i) {
				MediaWikiFormatter.setAttributesFromParams(cell,w.source.substring(w.nextMatch,d));
				w.nextMatch = d+1;
			}
			while(w.source.substr(w.nextMatch,1)==' ') {
				w.nextMatch++;
			}
			subWikifyText(cell,w,w.source.substring(w.nextMatch,i));
			w.nextMatch = i+1;
			//w.subWikifyTerm(cell,/(\n)/mg);
		} else if(x.substr(0,1)=='|') {
			w.nextMatch++;
			i = lineEnd(w);
			if(i==-1)
				break;
			cell = createTiddlyElement2(tr,'td');
			c = w.source.indexOf('||',w.nextMatch);
			while(c!=-1 && c<i) {
				d = MediaWikiTemplate.findRawDelimiter('|',w.source,w.nextMatch);
				if(d!=-1 && d<c) {
					MediaWikiFormatter.setAttributesFromParams(cell,w.source.substring(w.nextMatch,d));
					w.nextMatch = d+1;
				}
				while(w.source.substr(w.nextMatch,1)==' ') {
					w.nextMatch++;
				}
				w.subWikifyTerm(cell,/(\|\|)/mg);
				cell = createTiddlyElement2(tr,'td');
				c = w.source.indexOf('||',w.nextMatch);
			}
			d = MediaWikiTemplate.findRawDelimiter('|',w.source,w.nextMatch);
			if(d!=-1 && d<i) {
				MediaWikiFormatter.setAttributesFromParams(cell,w.source.substring(w.nextMatch,d));
				w.nextMatch = d+1;
			}
			while(w.source.substr(w.nextMatch,1)==' ') {
				w.nextMatch++;
			}
			subWikifyText(cell,w,w.source.substring(w.nextMatch,i));
			w.nextMatch = i+1;
			//w.subWikifyTerm(cell,/(\n)/mg);
		} else {
		}
	x = w.source.substr(w.nextMatch,2);
	}
	w.nextMatch = pair.end + 3;
	return;
	
};

} //# end of 'install only once'
//}}}
/***
|''Name:''|MediaWikiTemplatePlugin|
|''Description:''|Development plugin for MediaWiki Template expansion|
|''Author:''|Martin Budden (mjbudden (at) gmail (dot) com)|
|''Version:''|0.1.10|
|''Date:''|Feb 27, 2008|
|''Comments:''|Please make comments at http://groups.google.co.uk/group/TiddlyWikiDev |
|''License:''|[[Creative Commons Attribution-ShareAlike 3.0 License|http://creativecommons.org/licenses/by-sa/3.0/]] |
|''~CoreVersion:''|2.4.1|

|''Display empty template links:''|<<option chkMediaWikiDisplayEmptyTemplateLinks>>|


http://meta.wikimedia.org/wiki/Help:Template
http://meta.wikimedia.org/wiki/User:Happy-melon/Templates

http://meta.wikimedia.org/wiki/Help:Parser_function
http://meta.wikimedia.org/wiki/Help:ParserFunctions (extensions)
http://www.mediawiki.org/wiki/Help:Magic_words
http://meta.wikimedia.org/wiki/Help:Variable

==Parsing templates==

When the MediaWiki [[mw:Manual:Parser.php|parser]] encounters a template (defined as a matched pair of braces not inside <nowiki><nowiki></nowiki> tags), the template is expanded using the following algorithm:

#The template call is divided into the template name and parameter expressions, by looking for pipe characters.  Pipes contained within matched double braces or square brackets are ignored.  
#*This division is performed purely based on pipe characters ''currently'' present in the template call, ignoring those potentially contained within templates.  This is what permits the use of [[Template:!]].
#*A potentially interesting feature is that characters including and following a hash <code>#</code> are stripped from the template name after this division.  So <code><nowiki>{{TEx4#def|ABC}}</nowiki></code> will be parsed in exactly the same way as <code><nowiki>{{TEx4|ABC}}</nowiki></code>.
#The wikicode for the template name is evaluated, calling the template parser [[w:Recursion (computer science)|recursively]] if necessary.  
#The wikicode for each parameter expression is evaluated, again using recursion if the wikicode contains another template. 
#Any parameter expression now containing a raw equals sign is split around that equals sign into a parameter ''name'' and parameter ''value''.  If a parameter expression contains more than one equals sign, the division is done around the ''first'' (working left to right).  
#Any remaining parameter expressions which do not contain equals signs are assigned as values to the implicit parameters, working left to right.  So the first parameter expression which does not contain an equals sign is assigned as the value of parameter <code>1</code>, the next parameter expression is assigned as the value of parameter <code>2</code>, etc.  
#The wikicode of the template page is analysed and stripped around <code><nowiki><noinclude></nowiki></code>, <code><nowiki><includeonly></nowiki></code> or <code><nowiki><onlyinclude></nowiki></code> tags, if present.
#The template call is replaced by the analysed wikicode, replacing parameters by their values if possible.
#*Any parameters that do not appear in the analysed wikicode are discarded, and any parameters appearing in the wikicode which have not been assigned a value are replaced by their defaults (if defined) or left as they are.

***/

//{{{
// Ensure that the MediaWikiTemplate Plugin is only installed once.
if(!version.extensions.MediaWikiTemplatePlugin) {
version.extensions.MediaWikiTemplatePlugin = {installed:true};

if(version.major < 2 || (version.major == 2 && version.minor < 1))
	{alertAndThrow('MediaWikiTemplatePlugin requires TiddlyWiki 2.1 or later.');}

if(config.options.chkMediaWikiDisplayEmptyTemplateLinks == undefined)
	{config.options.chkMediaWikiDisplayEmptyTemplateLinks = false;}

fnLog = function(text)
{
//	if(window.console) console.log(text); else displayMessage(text.substr(0,100));
};

MediaWikiTemplate.subWikify = Wikifier.prototype.subWikify;
Wikifier.prototype.subWikify = function(output,terminator)
{
	if(this.formatter.format=='mediawiki') {
		var mwt = new MediaWikiTemplate();
		this.source = mwt.transcludeTemplates(this.source,this.tiddler);
	}
	MediaWikiTemplate.subWikify.apply(this,arguments);
};

MediaWikiTemplate.normalizeTitle = function(title)
{
	title = title.replace(/_/mg,' ');
	title = title.substr(0,1).toUpperCase() + title.substring(1);
	return title;
};

MediaWikiTemplate.getTemplateContent = function(name)
{
	var i = name.indexOf(':');
	var namespace = 'Template:';
	if(i==0) {
		name = name.substr(1);
		namespace = '';
	} else if(i!=-1) {
		namespace = '';
	}
	i = name.indexOf('#');
	if(i!=-1) {
		name = name.substr(0,i);
	}
	
	name = MediaWikiTemplate.normalizeTitle(name);
	var tiddler = store.fetchTiddler(namespace+name);
	var text = '';
	if(tiddler) {
		text = tiddler.text;
		if(text.indexOf('<')==-1)
			return text; // optimization to avoid regular expression matching
		text = text.replace(/<noinclude>((?:.|\n)*?)<\/noinclude>/mg,'');// remove text between noinclude tags
		text = text.replace(/<includeonly>/mg,'');
		text = text.replace(/<\/includeonly>/mg,'');
		var onlyIncludeRegExp = /<onlyinclude>((?:.|\n)*?)<\/onlyinclude>/mg;
		var t = '';
		onlyIncludeRegExp.lastIndex = 0;
		var match = onlyIncludeRegExp.exec(text);
		while(match) {
			t += match[1];
			match = onlyIncludeRegExp.exec(text);
		}
		text = t == '' ? text : t;
	} else {
		text = namespace + name;
		if(config.options.chkMediaWikiDisplayEmptyTemplateLinks) {
			text = '[['+text+']]';
		}
	}
	return text;
};

MediaWikiTemplate.prototype.substituteParameters = function(text,params)
{
	var t = '';
	var pi = 0;
	var bp = MediaWikiTemplate.findTBP(text,pi);
	var paramIndex = 1;
	while(bp.start!=-1) {
		var name = text.substring(bp.start+3,bp.end);
		var d = MediaWikiTemplate.findRawDelimiter('|',name,0);
		if(d!=-1) {
			var def = name.substr(d+1);
			name = name.substr(0,d);
			var np = MediaWikiTemplate.findDBP(name,0);
			while(np.start!=-1) {
				var nx = this._expandTemplateNTag(this.substituteParameters(name.substring(np.start+2,np.end),params));
				name = name.substr(0,np.start) + nx + name.substr(np.end+2);
				np = MediaWikiTemplate.findDBP(name,0);
			}
		}
		//params is [undefined,"param1=aaa"]
		var val = params[name];
		if(val===undefined) {
			val = params[paramIndex];
		}
		if(val===undefined) {
			val = def;
		}
		if(val===undefined) {
			val = '{{{'+name+'}}}';
		} else {
			// remove numbered parameters before substitute nested parameters
			var p2 = {};
			for(var i in params) {
				if(isNaN(parseInt(i,10)))
					p2[i] = params[i];
			}
			val = this.substituteParameters(val,p2);
		}
		t += text.substring(pi,bp.start) + this._transcludeTemplates(val);
		pi = bp.end+3;
		bp = MediaWikiTemplate.findTBP(text,pi);
		paramIndex++;
	}
	t += text.substring(pi);
	return t;
};

MediaWikiTemplate.prototype.expandTemplateContent = function(templateName,params)
{
	if(this.stack.indexOf(templateName)!=-1) {
		this.error = true;
		//return 'ERROR: template recursion detected';
		return 'Template loop detected: '+templateName;
	}
	this.stack.push(templateName);

	var text = MediaWikiTemplate.getTemplateContent(templateName);
	text = this.substituteParameters(text,params);
//fnLog('ret expandTemplateContent'+text);
	return text;
};

MediaWikiTemplate.prototype._expandVariable = function(text)
{
	if(text.length>16)// optimization to avoid switch statement
		return false;
	var ret = false;
	switch(text) {
	case 'BASEPAGENAME':
		ret = this.tiddler.title;
		var i = ret.indexOf(':');
		if(i!=-1)
			ret = ret.substr(i+1);
		break;
	case 'NAMESPACE':
		ret = this.tiddler.title;
		i = ret.indexOf(':');
		ret = i==-1 ? '' : ret.substr(0,i);
		break;
	case 'PAGENAME':
		ret = this.tiddler.title;
		break;
	case 'PAGENAMEE':
		ret = MediaWikiTemplate.normalizedTitle(this.tiddler.title);
		break;
	case 'NUMBEROFARTICLES':
		var n = 0;
		store.forEachTiddler(function(title,tiddler) {
			if((tiddler.fields.wikiformat && tiddler.fields.wikiformat==config.parsers.mediawikiFormatter.format) || tiddler.isTagged(config.parsers.mediawikiFormatter.formatTag)) {
					++n;
			};
		});
		return String(n);
		break;
	case 'REVISIONID':
		ret  = this.tiddler.fields['server.revision'];
		break;
	case 'SITENAME':
		ret  = store.getTiddlerText('SiteTitle');
		if(ret.indexOf('~')==0) {
			ret = ret.substr(1);
		}
		break;
	default:
		break;
	}
	return ret;
};

MediaWikiTemplate.prototype._expandParserFunction = function(text)
{
	var fnRegExp = /\s*(#?[a-z]+):/mg;
	fnRegExp.lastIndex = 0;
	var match = fnRegExp.exec(text);
	if(!match) {
		return false;
	}
	var ret = false;
	var len = match[0].length;
	var fn = match[1];
	switch(fn.toLowerCase()) {
	case '#if':
		var e = MediaWikiTemplate.findRawDelimiter('|',text,0);
		var p = text.substring(len,e).trim();
		var lhs = text.substr(e+1);
		e = MediaWikiTemplate.findRawDelimiter('|',lhs,0);
		if(e==-1) {
			ret = p=='' ? '' : lhs;
		} else {
			var rhs = lhs.substr(e+1);
			lhs = lhs.substr(0,e);
			ret = p=='' ? rhs : lhs;
		}
		break;
	default:
		break;
	}
	return ret;
};

MediaWikiTemplate.prototype._splitTemplateNTag = function(ntag)
// split naked template tag (ie without {{ and }}) at raw pipes into name and parameter definitions
{
	var pd = []; // parameters definitions array, p[0] contains template name
	var i = 0;
	var s = 0;
	var e = MediaWikiTemplate.findRawDelimiter('|',ntag,s);
	while(e!=-1) {
		pd[i] = ntag.substring(s,e);//.trim();
		i++;
		s = e+1;
		e = MediaWikiTemplate.findRawDelimiter('|',ntag,s);
	}
	pd[i] = ntag.substring(s);//.trim();
	return pd;
};

MediaWikiTemplate.prototype._expandTemplateNTag = function(ntag)
{
	var ret = this._expandVariable(ntag);
	if(ret!==false) {
		return ret;
	}
	var c = MediaWikiTemplate.findDBP(ntag,0);
	if(c.start==-1) {
		// only expand parser functions if all parameters have been subsituted
		ret = this._expandParserFunction(ntag);
		if(ret!==false) {
			return ret;
		}
	}
	var pd = this._splitTemplateNTag(ntag);
	var templateName = pd[0];
	var s = 1;

	var params = {};
	var n = 1;
	for(var i = s;i<pd.length;i++) {
		var t = pd[i];
		var p = MediaWikiTemplate.findRawDelimiter('=',t,0);
		if(p!=-1) {
			var pnRegExp = /\s*([A-Za-z0-9\-]*)\s*=(.*)/mg;
			pnRegExp.lastIndex = 0;
			match = pnRegExp.exec(t);
			if(match) {
				var name = match[1];
				var x = parseInt(name,10);
				if(!isNaN(x)) {
					n = x;
					//t = t.substr(p+1);
					t = match[2];
					p = -2;// do not increment parameter number
				}
			} else {
				p = -1;
			}
		}
		if(p==-2) {
			params[String(n)] = t;
		} else if(p==-1) {
			params[String(n)] = t;
			n++;
		} else if(name!='0') {//0 sets null parameter
			name = this._transcludeTemplates(name);
			var val = t.substr(p+1).trim();// trim named parameter values
			if(val) {
				params[name] = val;
			}
		}
	}
	/*for(i in params) {
		console.log('p0['+i+']='+params[i]);
		params[i] = this.substituteParameters(params[i],params);
		console.log('p1['+i+']='+params[i]);
		params[i] = this._transcludeTemplates(params[i]);
		console.log('p2['+i+']='+params[i]);
	}*/
	
	ret = this.expandTemplateContent(templateName.trim(),params);
	return ret;
};

MediaWikiTemplate.prototype._transcludeTemplates = function(text)
{
	if(!text)
		return text;
	var c = MediaWikiTemplate.findDBP(text,0);
	var ns = text.indexOf('<nowiki>');
	var ne = text.indexOf('</nowiki>',ns);
	if(ns!=-1 && c.start!=-1 && (c.start>ns && c.start<ne)) {
		c = MediaWikiTemplate.findDBP(text,ne);
	}
	while(c.start!=-1) {
		var t = this._expandTemplateNTag(text.substring(c.start+2,c.end));
		if(this.error) {
			text = text.substring(0,c.start) + t + text.substring(c.end+2);
			return text;
		}
		t = this._transcludeTemplates(t);
		text = text.substring(0,c.start) + t + text.substring(c.end+2);
		if(this.error)
			return text;
		c = MediaWikiTemplate.findDBP(text,c.start+t.length);
		this.stack = [];
		this.error = false;
	}
	return text;
};

MediaWikiTemplate.prototype.transcludeTemplates = function(text,tiddler)
{
	this.stack = [];
	this.error = false;
	this.tiddler = tiddler;
	if(tiddler.title.indexOf('Template:')==0)
		return text;
	return this._transcludeTemplates(text);
};

} //# end of 'install only once'