<!--{{{-->
<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]];}

.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]];}
.readOnly {background:[[ColorPalette::TertiaryPale]];}

#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:0; top:0;}

.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:0 3px 0 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:0; padding-bottom:0;}

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

.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>>
/***
|Name|CopyTiddlerPlugin|
|Source|http://www.TiddlyTools.com/#CopyTiddlerPlugin|
|Version|3.2.6|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.3|
|Type|plugin|
|Description|Quickly create a copy of any existing tiddler|
!!!Usage
<<<
The plugin automatically updates the default (shadow) ToolbarCommands definitions to insert the ''copyTiddler'' command, which will appear as ''copy'' when a tiddler is rendered.  If you are already using customized toolbar definitions, you will need to manually add the ''copyTiddler'' toolbar command to your existing ToolbarCommands tiddler, e.g.:
{{{
|EditToolbar|... copyTiddler ... |
}}}
When the ''copy'' command is selected, a new tiddler is created containing an exact copy of the current text/tags/fields, using a title of "{{{TiddlerName (n)}}}", where ''(n)'' is the next available number (starting with 1, of course).  If you copy while //editing// a tiddler, the current values displayed in the editor are used (including any changes you may have already made to those values), and the new tiddler is immediately opened for editing.

The plugin also provides a macro that allows you to embed a ''copy'' command directly in specific tiddler content:
{{{
<<copyTiddler TidderName label:"..." prompt:"...">>
}}}
where
* ''TiddlerName'' (optional)<br>specifies the //source// tiddler to be copied.  If omitted, the current containing tiddler (if any) will be copied.
* ''label:"..."'' (optional)<br>specifies text to use for the embedded link (default="copy TiddlerName")
* ''prompt:"..."'' (optional)<br>specifies mouseover 'tooltip' help text for link
//Note: to use non-default label/prompt values with the current containing tiddler, use "" for the TiddlerName//
<<<
!!!Configuration
<<<
<<option chkCopyTiddlerDate>> use date/time from existing tiddler (otherwise, use current date/time)
{{{<<option chkCopyTiddlerDate>>}}}
<<<
!!!Revisions
<<<
2010.11.30 3.2.6 use story.getTiddler()
2009.06.08 3.2.5 added option to use timestamp from source tiddler
2009.03.09 3.2.4 fixed IE-specific syntax error
2009.03.02 3.2.3 refactored code (again) to restore use of config.commands.copyTiddler.* custom settings
2009.02.13 3.2.2 in click(), fix calls to displayTiddler() to use current tiddlerElem and use getTiddlerText() to permit copying of shadow tiddler content
2009.01.30 3.2.1 fixed handling for copying field values when in edit mode
2009.01.23 3.2.0 refactored code and added {{{<<copyTiddler TiddlerName>>}}} macro
2008.12.18 3.1.4 corrected code for finding next (n) value when 'sparse' handling is in effect
2008.11.14 3.1.3 added optional 'sparse' setting (avoids 'filling in' missing numbers that may have been previously deleted)
2008.11.14 3.1.2 added optional 'zeroPad' setting
2008.11.14 3.1.1 moved hard-coded '(n)' regex into 'suffixPattern' object property so it can be customized
2008.09.26 3.1.0 changed new title generation to use '(n)' suffix instead of 'Copy of' prefix
2008.05.20 3.0.3 in handler, when copying from VIEW mode, create duplicate array from existing tags array before saving new tiddler.
2007.12.19 3.0.2 in handler, when copying from VIEW mode, duplicate custom fields before saving new tiddler.
2007.09.26 3.0.1 in handler, use findContainingTiddler(src) to get tiddlerElem (and title).  Allows 'copy' command to find correct tiddler when transcluded using {{{<<tiddler>>}}} macro or enhanced toolbar inclusion (see [[CoreTweaks]])
2007.06.28 3.0.0 complete re-write to handle custom fields and alternative view/edit templates
2007.05.17 2.1.2 use store.getTiddlerText() to retrieve tiddler content, so that SHADOW tiddlers can be copied correctly when in VIEW mode
2007.04.01 2.1.1 in copyTiddler.handler(), fix check for editor fields by ensuring that found field actually has edit=='text' attribute
2007.02.05 2.1.0 in copyTiddler.handler(), if editor fields (textfield and/or tagsfield) can't be found (i.e., tiddler is in VIEW mode, not EDIT mode), then get text/tags values from stored tiddler instead of active editor fields.  Allows use of COPY toolbar directly from VIEW mode
2006.12.12 2.0.0 completely rewritten so plugin just creates a new tiddler EDITOR with a copy of the current tiddler EDITOR contents, instead of creating the new tiddler in the STORE by copying the current tiddler values from the STORE.
2005.xx.xx 1.0.0 original version by Tim Morgan
<<<
!!!Code
***/
//{{{
version.extensions.CopyTiddlerPlugin= {major: 3, minor: 2, revision: 6, date: new Date(2010,11,30)};

// automatically tweak shadow EditTemplate to add 'copyTiddler' toolbar command (following 'cancelTiddler')
config.shadowTiddlers.ToolbarCommands=config.shadowTiddlers.ToolbarCommands.replace(/cancelTiddler/,'cancelTiddler copyTiddler');

if (config.options.chkCopyTiddlerDate===undefined) config.options.chkCopyTiddlerDate=false;

config.commands.copyTiddler = {
	text: 'copy',
	hideReadOnly: true,
	tooltip: 'Make a copy of this tiddler',
	notitle: 'this tiddler',
	prefix: '',
	suffixText: ' (%0)',
	suffixPattern: / \(([0-9]+)\)$/,
	zeroPad: 0,
	sparse: false,
	handler: function(event,src,title)
		{ return config.commands.copyTiddler.click(src,event); },
	click: function(here,ev) {
		var tiddlerElem=story.findContainingTiddler(here);
		var template=tiddlerElem?tiddlerElem.getAttribute('template'):null;
		var title=here.getAttribute('from');
		if (!title || !title.length) {
			if (!tiddlerElem) return false;
			else title=tiddlerElem.getAttribute('tiddler');
		}
		var root=title.replace(this.suffixPattern,''); // title without suffix
		// find last matching title
		var last=title;
		if (this.sparse) { // don't fill-in holes... really find LAST matching title
			var tids=store.getTiddlers('title','excludeLists');
			for (var t=0; t<tids.length; t++) if (tids[t].title.startsWith(root)) last=tids[t].title;
		}
		// get next number (increment from last matching title)
		var n=1; var match=this.suffixPattern.exec(last); if (match) n=parseInt(match[1])+1;
		var newTitle=this.prefix+root+this.suffixText.format([String.zeroPad(n,this.zeroPad)]);
		// if not sparse mode, find the next hole to fill in...
		while (store.tiddlerExists(newTitle)||story.getTiddler(newTitle))
			{ n++; newTitle=this.prefix+root+this.suffixText.format([String.zeroPad(n,this.zeroPad)]); }
		if (!story.isDirty(title)) { // if tiddler is not being EDITED
			// duplicate stored tiddler (if any)
			var text=store.getTiddlerText(title,'');
			var who=config.options.txtUserName;
			var when=new Date();
			var newtags=[]; var newfields={};
			var tid=store.getTiddler(title); if (tid) {
				if (config.options.chkCopyTiddlerDate) var when=tid.modified;
				for (var t=0; t<tid.tags.length; t++) newtags.push(tid.tags[t]);
				store.forEachField(tid,function(t,f,v){newfields[f]=v;},true);
			}
	                store.saveTiddler(newTitle,newTitle,text,who,when,newtags,newfields,true);
			story.displayTiddler(tiddlerElem,newTitle,template);
		} else {
			story.displayTiddler(tiddlerElem,newTitle,template);
			var fields=config.commands.copyTiddler.gatherFields(tiddlerElem); // get current editor fields
			var newTiddlerElem=story.getTiddler(newTitle);
			for (var f=0; f<fields.length; f++) {  // set fields in new editor
				if (fields[f].name=='title') fields[f].value=newTitle; // rename title in new tiddler
				var fieldElem=config.commands.copyTiddler.findField(newTiddlerElem,fields[f].name);
				if (fieldElem) {
					if (fieldElem.getAttribute('type')=='checkbox')
						fieldElem.checked=fields[f].value;
					else 
						fieldElem.value=fields[f].value;
				}
			}
		}
		story.focusTiddler(newTitle,'title');
		return false;
	},
	findField: function(tiddlerElem,field) {
		var inputs=tiddlerElem.getElementsByTagName('input');
		for (var i=0; i<inputs.length; i++) {
			if (inputs[i].getAttribute('type')=='checkbox' && inputs[i].field == field) return inputs[i];
			if (inputs[i].getAttribute('type')=='text' && inputs[i].getAttribute('edit') == field) return inputs[i];
		}
		var tas=tiddlerElem.getElementsByTagName('textarea');
		for (var i=0; i<tas.length; i++) if (tas[i].getAttribute('edit') == field) return tas[i];
		var sels=tiddlerElem.getElementsByTagName('select');
		for (var i=0; i<sels.length; i++) if (sels[i].getAttribute('edit') == field) return sels[i];
		return null;
	},
	gatherFields: function(tiddlerElem) { // get field names and values from current tiddler editor
		var fields=[];
		// get checkboxes and edit fields
		var inputs=tiddlerElem.getElementsByTagName('input');
		for (var i=0; i<inputs.length; i++) {
			if (inputs[i].getAttribute('type')=='checkbox')
				if (inputs[i].field) fields.push({name:inputs[i].field,value:inputs[i].checked});
			if (inputs[i].getAttribute('type')=='text')
				if (inputs[i].getAttribute('edit')) fields.push({name:inputs[i].getAttribute('edit'),value:inputs[i].value});
		}
		// get textareas (multi-line edit fields)
		var tas=tiddlerElem.getElementsByTagName('textarea');
		for (var i=0; i<tas.length; i++)
			if (tas[i].getAttribute('edit')) fields.push({name:tas[i].getAttribute('edit'),value:tas[i].value});
		// get selection lists (droplist or listbox)
		var sels=tiddlerElem.getElementsByTagName('select');
		for (var i=0; i<sels.length; i++)
			if (sels[i].getAttribute('edit')) fields.push({name:sels[i].getAttribute('edit'),value:sels[i].value});
		return fields;
	}
};
//}}}
// // MACRO DEFINITION
//{{{
config.macros.copyTiddler = {
	label: 'copy',
	prompt: 'Make a copy of %0',
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		var title=params.shift();
		params=paramString.parseParams('anon',null,true,false,false);
		var label	=getParam(params,'label',this.label+(title?' '+title:''));
		var prompt	=getParam(params,'prompt',this.prompt).format([title||this.notitle]);
		var b=createTiddlyButton(place,label,prompt,
			function(ev){return config.commands.copyTiddler.click(this,ev)});
		b.setAttribute('from',title||'');
	}
};
//}}}
[[GettingStarted]]
<<infobox
Type:"Example Person"
Image-Person:"http://www.google.com/logos/2012/childrensday-2012-hp.jpg"
Homeworld:"test1"
Born:"test1"
Died:"test1"
Hair color:"test1"
Eye color:"test1"
Skin color:"test1"
Eras:"test1"
Affiliation:"test1"
Known_masters:"test1"
Known_apprentices:"test1"
>>
<<infobox
Type:"Wrong Type"
Image-Person:"http://www.google.com/logos/2012/childrensday-2012-hp.jpg"
Homeworld:"test1"
Born:"test1"
Died:"test1"
Species:"test1"
Gender:"test1"
Height:"test1"
Hair_color:"test1"
Eye_color:"test1"
Skin_color:"test1"
Eras:"test1"
Affiliation:"test1"
Known_masters:"test1"
Known_apprentices:"test1"
>>
<<infobox
Image-Person:"http://www.google.com/logos/2012/childrensday-2012-hp.jpg"
Homeworld:"test1"
Born:"test1"
Died:"test1"
Species:"test1"
Gender:"test1"
Height:"test1"
Hair_color:"test1"
Eye_color:"test1"
Skin_color:"test1"
Eras:"test1"
Affiliation:"test1"
Known_masters:"test1"
Known_apprentices:"test1"
>>
<<infobox
Type:"Example Person"
>>
<<infobox
Type:"Example Battle"
img:"http://www.google.com/logos/2012/childrensday-2012-hp.jpg"
Date:"test1"
loc:"shorthandtest1"
Outcome:"test1"
Previous:"test1"
Next:"test1"
gcommanders:"shorthandtest1left"
bcommanders:"shorthandtest1right"
gstrength:"shorthandtest1left"
bstrength:"shorthandtest1right"
Side1-Good_casualties:"test1left"
Side2-Bad_casualties:"test1right"
>>
<<infobox
Type:"Example Person"
InstanceID:"test1"
Species:"test1"
Gender:"test1"
Height:"test1"
Skin_color:"test1"
Eras:"test1"
Affiliation:"test1"
Known_masters:"test1"
>>
<<infobox
Type:"Example Person"
InstanceID:"test2"
Image-Person:"http://www.google.com/logos/2012/childrensday-2012-hp.jpg"
Homeworld:"test2"
Born:"test2"
Died:"test2"
Eras:"test2"
Affiliation:"test2"
Known_masters:"test2"
Known_apprentices:"test2"
>>
<<infobox
Type:"Example Person"
InstanceID:"test3"
Image-Person:"http://www.google.com/logos/2012/childrensday-2012-hp.jpg"
Homeworld:"test3"
Born:"test3"
Died:"test3"
Species:"test3"
Gender:"test3"
>>
<<infobox
Type:"Example Person"
InstanceID:"test4"
Homeworld:"test4"
Died:"test4"
Species:"test4"
Height:"test4"
Hair_color:"test4"
Skin_color:"test4"
Eras:"test4"
Known_masters:"test4"
>>
<<infobox
Type:"Example Battle"
InstanceID:"test5"
img:"http://www.google.com/logos/2012/childrensday-2012-hp.jpg"
Date:"test1"
loc:"test1"
Outcome:"test1"
Previous:"test1"
Concurrent:"test1"
Next:"test1"
gfighters:"shorthandtest1left"
bfighters:"shorthandtest1right"
gcommanders:"shorthandtest1left"
bcommanders:"shorthandtest1right"
gstrength:"shorthandtest1left"
bstrength:"shorthandtest1right"
Side1-Good_casualties:"test1left"
Side2-Bad_casualties:"test1right"
>>
<<infobox
Type:"Example Battle"
InstanceID:"test6"
img:"http://www.google.com/logos/2012/childrensday-2012-hp.jpg"
Date:"test2"
loc:"test2"
Outcome:"test2"
Previous:"test2"
Next:"test2"
bfighters:"shorthandtest1right"
gstrength:"shorthandtest1left"
Side1-Good_casualties:"test1left"
Side2-Bad_casualties:"test1right"
>>
<<infobox
Type:"Example Person"
InstanceID:"test1"
Image-Person:"http://www.google.com/logos/2012/childrensday-2012-hp.jpg"
Homeworld:"test1"
Born:"test1"
Died:"test1"
Species:"test1"
Gender:"test1"
Height:"test1"
Hair_color:"test1"
Eye_color:"test1"
Skin_color:"test1"
Eras:"test1"
Affiliation:"test1"
Known_masters:"test1"
Known_apprentices:"test1"
>>
<<infobox
Type:"Example Person"
InstanceID:"test2"
Image-Person:"http://www.google.com/logos/2012/childrensday-2012-hp.jpg"
Homeworld:"test2"
Born:"test2"
Died:"test2"
Species:"test2"
Gender:"test2"
Height:"test2"
Hair_color:"test2"
Eye_color:"test2"
Skin_color:"test2"
Eras:"test2"
Affiliation:"test2"
Known_masters:"test2"
Known_apprentices:"test2"
>>
<<infobox
Type:"Example Person"
Image-Person:"http://www.google.com/logos/2012/childrensday-2012-hp.jpg"
Homeworld:"test23
Born:"test3"
Died:"test3"
Species:"test3"
Gender:"test3"
Height:"test3"
Hair_color:"test3"
Eye_color:"test3"
Skin_color:"test3"
Eras:"test3"
Affiliation:"test3"
Known_masters:"test3"
Known_apprentices:"test3"
>>
<<tiddler [[Example with two infoboxes with and without a custom title]]>>
<<infobox
Type:"Example Person"
Image-Person:"http://www.google.com/logos/2012/childrensday-2012-hp.jpg"
Homeworld:"test1"
Born:"test1"
Died:"test1"
Species:"test1"
Hair_color:"test1"
Eye_color:"test1"
Skin_color:"test1"
Eras:"test1"
Affiliation:"test1"
Known_masters:"test1"
Known_apprentices:"test1"
>>
<<infobox
Type:"Example Battle"
img:"http://www.google.com/logos/2012/childrensday-2012-hp.jpg"
Date:"test1"
loc:"test1"
Previous:"test1"
Next:"test1"
gfighters:"shorthandtest1left"
bfighters:"shorthandtest1right"
gstrength:"shorthandtest1left"
bstrength:"shorthandtest1right"
Side1-Good_casualties:"test1left"
Side2-Bad_casualties:"test1right"
>>
<<infobox
Type:"Example Person"
InstanceID:"test1"
Image-Person:"http://www.google.com/logos/2012/childrensday-2012-hp.jpg"
Homeworld:"test1"
Born:"test1"
Died:"test1"
Species:"test1"
Gender:"test1"
Hair_color:"test1"
Eye_color:"test1"
Skin_color:"test1"
Eras:"test1"
Affiliation:"test1"
Known_masters:"test1"
Known_apprentices:"test1"
>>
<<infobox
Type:"Example Person"
InstanceID:"test2"
Image-Person:"http://www.google.com/logos/2012/childrensday-2012-hp.jpg"
Homeworld:"test2"
Born:"test2"
Died:"test2"
Species:"test2"
Gender:"test2"
Height:"test2"
Skin_color:"test2"
Eras:"test2"
Affiliation:"test2"
Known_masters:"test2"
Known_apprentices:"test2"
>>
<<infobox
Type:"Example Person"
InstanceID:"test1"
Image-Person:"http://www.google.com/logos/2012/childrensday-2012-hp.jpg"
Homeworld:"test1"
Born:"test1"
Species:"test1"
Gender:"test1"
Hair_color:"test1"
Eye_color:"test1"
Skin color:"test1"
Eras:"test1"
Affiliation:"test1"
>>
<<infobox
Type:"Example Person"
InstanceID:"test1"
Image-Person:"http://www.google.com/logos/2012/childrensday-2012-hp.jpg"
Homeworld:"test2"
Born:"test2"
Died:"test2"
Species:"test2"
Gender:"test2"
Eye_color:"test2"
Skin_color:"test2"
Eras:"test2"
Affiliation:"test2"
Known_masters:"test2"
Known_apprentices:"test2"
>>
<<infobox
Type:"Example Person"
InstanceID:"test1"
Image-Person:"http://www.google.com/logos/2012/childrensday-2012-hp.jpg"
Homeworld:"test1"
Born:"test1"
Died:"test1"
Species:"test1"
Gender:"test1"
Height:"test1"
Hair_color:"test1"
Eye_color:"test1"
Skin_color:"test1"
Eras:"test1"
Affiliation:"test1"
Known_masters:"test1"
Known_apprentices:"test1"
>>
<<infobox
Type:"Example Person"
InstanceID:"test2"
Title:"This is a custom title"
Image-Person:"http://www.google.com/logos/2012/childrensday-2012-hp.jpg"
Homeworld:"test2"
Born:"test2"
Died:"test2"
Species:"test2"
Gender:"test2"
Height:"test2"
Hair_color:"test2"
Eye_color:"test2"
Skin_color:"test2"
Eras:"test2"
Affiliation:"test2"
Known_masters:"test2"
Known_apprentices:"test2"
>>
<<infobox
Type:"Example Person"
Image-Person:"http://www.google.com/logos/2012/childrensday-2012-hp.jpg"
Homeworld:"test1"
Born:"test1"
Died:"test1"
Species:"test1"
Gender:"test1"
Height:"test1"
Hair_color:"test1"
Eye_color:"test1"
Skin_color:"test1"
Eras:"test1"
Affiliation:"test1"
Known_masters:"test1"
Known_apprentices:"test1"
>>
<<infobox
Type:"Example Person"
Image-Person:"http://www.google.com/logos/2012/childrensday-2012-hp.jpg"
Homeworld:"test2"
Born:"test2"
Died:"test2"
Species:"test2"
Gender:"test2"
Height:"test2"
Hair_color:"test2"
Eye_color:"test2"
Skin_color:"test2"
Eras:"test2"
Affiliation:"test2"
Known_masters:"test2"
Known_apprentices:"test2"
>>
/***
|Name|ExportTiddlersPlugin|
|Source|http://www.TiddlyTools.com/#ExportTiddlersPlugin|
|Documentation|http://www.TiddlyTools.com/#ExportTiddlersPluginInfo|
|Version|2.9.6|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|interactively select/export tiddlers to a separate file|
!!!!!Documentation
>see [[ExportTiddlersPluginInfo]]
!!!!!Inline control panel (live):
><<exportTiddlers inline>>
!!!!!Revisions
<<<
2011.02.14 2.9.6 fix OSX error: use picker.file.path
2010.02.25 2.9.5 added merge checkbox option and improved 'merge' status message
|please see [[ExportTiddlersPluginInfo]] for additional revision details|
2005.10.09 0.0.0 development started
<<<
!!!!!Code
***/
//{{{
// version
version.extensions.ExportTiddlersPlugin= {major: 2, minor: 9, revision: 6, date: new Date(2011,2,14)};

// default shadow definition
config.shadowTiddlers.ExportTiddlers='<<exportTiddlers inline>>';

// add 'export' backstage task (following built-in import task)
if (config.tasks) { // TW2.2 or above
	config.tasks.exportTask = {
		text:'export',
		tooltip:'Export selected tiddlers to another file',
		content:'<<exportTiddlers inline>>'
	}
	config.backstageTasks.splice(config.backstageTasks.indexOf('importTask')+1,0,'exportTask');
}

config.macros.exportTiddlers = {
	$: function(id) { return document.getElementById(id); }, // abbreviation
	label: 'export tiddlers',
	prompt: 'Copy selected tiddlers to an export document',
	okmsg: '%0 tiddler%1 written to %2',
	failmsg: 'An error occurred while creating %1',
	overwriteprompt: '%0\ncontains %1 tiddler%2 that will be discarded or replaced',
	mergestatus: '%0 tiddler%1 added, %2 tiddler%3 updated, %4 tiddler%5 unchanged',
	statusmsg: '%0 tiddler%1 - %2 selected for export',
	newdefault: 'export.html',
	datetimefmt: '0MM/0DD/YYYY 0hh:0mm:0ss',  // for 'filter date/time' edit fields
	type_TW: "tw", type_PS: "ps", type_TX: "tx", type_CS: "cs", type_NF: "nf", // file type tokens
	type_map: { // maps type param to token values
		tiddlywiki:"tw", tw:"tw", wiki: "tw",
		purestore: "ps", ps:"ps", store:"ps",
		plaintext: "tx", tx:"tx", text: "tx",
		comma:     "cs", cs:"cs", csv:  "cs",
		newsfeed:  "nf", nf:"nf", xml:  "nf", rss:"nf"
	},
	handler: function(place,macroName,params) {
		if (params[0]!='inline')
			{ createTiddlyButton(place,this.label,this.prompt,this.togglePanel); return; }
		var panel=this.createPanel(place);
		panel.style.position='static';
		panel.style.display='block';
	},
	createPanel: function(place) {
		var panel=this.$('exportPanel');
		if (panel) { panel.parentNode.removeChild(panel); }
		setStylesheet(store.getTiddlerText('ExportTiddlersPlugin##css',''),'exportTiddlers');
		panel=createTiddlyElement(place,'span','exportPanel',null,null)
		panel.innerHTML=store.getTiddlerText('ExportTiddlersPlugin##html','');
		this.initFilter();
		this.refreshList(0);
		var fn=this.$('exportFilename');
		if (window.location.protocol=='file:' && !fn.value.length) {
			// get new target path/filename
			var newPath=getLocalPath(window.location.href);
			var slashpos=newPath.lastIndexOf('/'); if (slashpos==-1) slashpos=newPath.lastIndexOf('\\'); 
			if (slashpos!=-1) newPath=newPath.substr(0,slashpos+1); // trim filename
			fn.value=newPath+this.newdefault;
		}
		return panel;
	},
	togglePanel: function(e) { var e=e||window.event;
		var cme=config.macros.exportTiddlers; // abbrev
		var parent=resolveTarget(e).parentNode;
		var panel=cme.$('exportPanel');
		if (panel==undefined || panel.parentNode!=parent)
			panel=cme.createPanel(parent);
		var isOpen=panel.style.display=='block';
		if(config.options.chkAnimate)
			anim.startAnimating(new Slider(panel,!isOpen,e.shiftKey || e.altKey,'none'));
		else
			panel.style.display=isOpen?'none':'block' ;
		if (panel.style.display!='none') {
			cme.refreshList(0);
			cme.$('exportFilename').focus(); 
			cme.$('exportFilename').select();
		}
		e.cancelBubble = true; if (e.stopPropagation) e.stopPropagation(); return(false);
	},
	process: function(which) { // process panel control interactions
		var theList=this.$('exportList'); if (!theList) return false;
		var count = 0;
		var total = store.getTiddlers('title').length;
		switch (which.id) {
			case 'exportFilter':
				count=this.filterExportList();
				var panel=this.$('exportFilterPanel');
				if (count==-1) { panel.style.display='block'; break; }
				this.$('exportStart').disabled=(count==0);
				this.$('exportDelete').disabled=(count==0);
				this.displayStatus(count,total);
				if (count==0) { alert('No tiddlers were selected'); panel.style.display='block'; }
				break;
			case 'exportStart':
				this.go();
				break;
			case 'exportDelete':
				this.deleteTiddlers();
				break;
			case 'exportHideFilter':
			case 'exportToggleFilter':
				var panel=this.$('exportFilterPanel')
				panel.style.display=(panel.style.display=='block')?'none':'block';
				break;
			case 'exportSelectChanges':
				var lastmod=new Date(document.lastModified);
				for (var t = 0; t < theList.options.length; t++) {
					if (theList.options[t].value=='') continue;
					var tiddler=store.getTiddler(theList.options[t].value); if (!tiddler) continue;
					theList.options[t].selected=(tiddler.modified>lastmod);
					count += (tiddler.modified>lastmod)?1:0;
				}
				this.$('exportStart').disabled=(count==0);
				this.$('exportDelete').disabled=(count==0);
				this.displayStatus(count,total);
				if (count==0) alert('There are no unsaved changes');
				break;
			case 'exportSelectAll':
				for (var t = 0; t < theList.options.length; t++) {
					if (theList.options[t].value=='') continue;
					theList.options[t].selected=true;
					count += 1;
				}
				this.$('exportStart').disabled=(count==0);
				this.$('exportDelete').disabled=(count==0);
				this.displayStatus(count,count);
				break;
			case 'exportSelectOpened':
				for (var t=0; t<theList.options.length; t++) theList.options[t].selected=false;
				var tiddlerDisplay=this.$('tiddlerDisplay');
				for (var t=0; t<tiddlerDisplay.childNodes.length;t++) {
					var tiddler=tiddlerDisplay.childNodes[t].id.substr(7);
					for (var i=0; i<theList.options.length; i++) {
						if (theList.options[i].value!=tiddler) continue;
						theList.options[i].selected=true; count++; break;
					}
				}
				this.$('exportStart').disabled=(count==0);
				this.$('exportDelete').disabled=(count==0);
				this.displayStatus(count,total);
				if (count==0) alert('There are no tiddlers currently opened');
				break;
			case 'exportSelectRelated':
				// recursively build list of related tiddlers
				function getRelatedTiddlers(tid,tids) {
					var t=store.getTiddler(tid); if (!t || tids.contains(tid)) return tids;
					tids.push(t.title);
					if (!t.linksUpdated) t.changed();
					for (var i=0; i<t.links.length; i++)
						if (t.links[i]!=tid) tids=getRelatedTiddlers(t.links[i],tids);
					return tids;
				}
				// for all currently selected tiddlers, gather up the related tiddlers (including self) and select them as well
				var tids=[];
				for (var i=0; i<theList.options.length; i++)
					if (theList.options[i].selected) tids=getRelatedTiddlers(theList.options[i].value,tids);
				// select related tiddlers (includes original selected tiddlers)
				for (var i=0; i<theList.options.length; i++)
					theList.options[i].selected=tids.contains(theList.options[i].value);
				this.displayStatus(tids.length,total);
				break;
			case 'exportListSmaller':	// decrease current listbox size
				var min=5;
				theList.size-=(theList.size>min)?1:0;
				break;
			case 'exportListLarger':	// increase current listbox size
				var max=(theList.options.length>25)?theList.options.length:25;
				theList.size+=(theList.size<max)?1:0;
				break;
			case 'exportClose':
				this.$('exportPanel').style.display='none';
				break;
		}
		return false;
	},
	displayStatus: function(count,total) {
		var txt=this.statusmsg.format([total,total!=1?'s':'',!count?'none':count==total?'all':count]);
		clearMessage();	displayMessage(txt);
		return txt;
	},
	refreshList: function(selectedIndex) {
		var theList = this.$('exportList'); if (!theList) return;
		// get the sort order
		var sort;
		if (!selectedIndex)   selectedIndex=0;
		if (selectedIndex==0) sort='modified';
		if (selectedIndex==1) sort='title';
		if (selectedIndex==2) sort='modified';
		if (selectedIndex==3) sort='modifier';
		if (selectedIndex==4) sort='tags';

		// unselect headings and count number of tiddlers actually selected
		var count=0;
		for (var t=5; t < theList.options.length; t++) {
			if (!theList.options[t].selected) continue;
			if (theList.options[t].value!='')
				count++;
			else { // if heading is selected, deselect it, and then select and count all in section
				theList.options[t].selected=false;
				for ( t++; t<theList.options.length && theList.options[t].value!=''; t++) {
					theList.options[t].selected=true;
					count++;
				}
			}
		}

		// disable 'export' and 'delete' buttons if no tiddlers selected
		this.$('exportStart').disabled=(count==0);
		this.$('exportDelete').disabled=(count==0);

		// show selection count
		var tiddlers = store.getTiddlers('title');
		if (theList.options.length) this.displayStatus(count,tiddlers.length);

		// if a [command] item, reload list... otherwise, no further refresh needed
		if (selectedIndex>4) return;

		// clear current list contents
		while (theList.length > 0) { theList.options[0] = null; }
		// add heading and control items to list
		var i=0;
		var indent=String.fromCharCode(160)+String.fromCharCode(160);
		theList.options[i++]=
			new Option(tiddlers.length+' tiddlers in document', '',false,false);
		theList.options[i++]=
			new Option(((sort=='title'   )?'>':indent)+' [by title]', '',false,false);
		theList.options[i++]=
			new Option(((sort=='modified')?'>':indent)+' [by date]', '',false,false);
		theList.options[i++]=
			new Option(((sort=='modifier')?'>':indent)+' [by author]', '',false,false);
		theList.options[i++]=
			new Option(((sort=='tags'    )?'>':indent)+' [by tags]', '',false,false);

		// output the tiddler list
		switch(sort) {
			case 'title':
				for(var t = 0; t < tiddlers.length; t++)
					theList.options[i++] = new Option(tiddlers[t].title,tiddlers[t].title,false,false);
				break;
			case 'modifier':
			case 'modified':
				var tiddlers = store.getTiddlers(sort);
				// sort descending for newest date first
				tiddlers.sort(function (a,b) {if(a[sort] == b[sort]) return(0); else return (a[sort] > b[sort]) ? -1 : +1; });
				var lastSection = '';
				for(var t = 0; t < tiddlers.length; t++) {
					var tiddler = tiddlers[t];
					var theSection = '';
					if (sort=='modified') theSection=tiddler.modified.toLocaleDateString();
					if (sort=='modifier') theSection=tiddler.modifier;
					if (theSection != lastSection) {
						theList.options[i++] = new Option(theSection,'',false,false);
						lastSection = theSection;
					}
					theList.options[i++] = new Option(indent+indent+tiddler.title,tiddler.title,false,false);
				}
				break;
			case 'tags':
				var theTitles = {}; // all tiddler titles, hash indexed by tag value
				var theTags = new Array();
				for(var t=0; t<tiddlers.length; t++) {
					var title=tiddlers[t].title;
					var tags=tiddlers[t].tags;
					if (!tags || !tags.length) {
						if (theTitles['untagged']==undefined) { theTags.push('untagged'); theTitles['untagged']=new Array(); }
						theTitles['untagged'].push(title);
					}
					else for(var s=0; s<tags.length; s++) {
						if (theTitles[tags[s]]==undefined) { theTags.push(tags[s]); theTitles[tags[s]]=new Array(); }
						theTitles[tags[s]].push(title);
					}
				}
				theTags.sort();
				for(var tagindex=0; tagindex<theTags.length; tagindex++) {
					var theTag=theTags[tagindex];
					theList.options[i++]=new Option(theTag,'',false,false);
					for(var t=0; t<theTitles[theTag].length; t++)
						theList.options[i++]=new Option(indent+indent+theTitles[theTag][t],theTitles[theTag][t],false,false);
				}
				break;
			}
		theList.selectedIndex=selectedIndex; // select current control item
		this.$('exportStart').disabled=true;
		this.$('exportDelete').disabled=true;
		this.displayStatus(0,tiddlers.length);
	},
	askForFilename: function(here) {
		var msg=here.title; // use tooltip as dialog box message
		var path=getLocalPath(document.location.href);
		var slashpos=path.lastIndexOf('/'); if (slashpos==-1) slashpos=path.lastIndexOf('\\'); 
		if (slashpos!=-1) path = path.substr(0,slashpos+1); // remove filename from path, leave the trailing slash
		var filetype=this.$('exportFormat').value.toLowerCase();
		var defext='html';
		if (filetype==this.type_TX) defext='txt';
		if (filetype==this.type_CS) defext='csv';
		if (filetype==this.type_NF) defext='xml';
		var file=this.newdefault.replace(/html$/,defext);
		var result='';
		if(window.Components) { // moz
			try {
				netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
				var nsIFilePicker = window.Components.interfaces.nsIFilePicker;
				var picker = Components.classes['@mozilla.org/filepicker;1'].createInstance(nsIFilePicker);
				picker.init(window, msg, nsIFilePicker.modeSave);
				var thispath = Components.classes['@mozilla.org/file/local;1'].createInstance(Components.interfaces.nsILocalFile);
				thispath.initWithPath(path);
				picker.displayDirectory=thispath;
				picker.defaultExtension=defext;
				picker.defaultString=file;
				picker.appendFilters(nsIFilePicker.filterAll|nsIFilePicker.filterText|nsIFilePicker.filterHTML);
				if (picker.show()!=nsIFilePicker.returnCancel) var result=picker.file.path;
			}
			catch(e) { alert('error during local file access: '+e.toString()) }
		}
		else { // IE
			try { // XPSP2 IE only
				var s = new ActiveXObject('UserAccounts.CommonDialog');
				s.Filter='All files|*.*|Text files|*.txt|HTML files|*.htm;*.html|XML files|*.xml|';
				s.FilterIndex=defext=='txt'?2:'html'?3:'xml'?4:1;
				s.InitialDir=path;
				s.FileName=file;
				if (s.showOpen()) var result=s.FileName;
			}
			catch(e) {  // fallback
				var result=prompt(msg,path+file);
			}
		}
		return result;
	},
	initFilter: function() {
		this.$('exportFilterStart').checked=false; this.$('exportStartDate').value='';
		this.$('exportFilterEnd').checked=false;  this.$('exportEndDate').value='';
		this.$('exportFilterTags').checked=false; this.$('exportTags').value='';
		this.$('exportFilterText').checked=false; this.$('exportText').value='';
		this.showFilterFields();
	},
	showFilterFields: function(which) {
		var show=this.$('exportFilterStart').checked;
		this.$('exportFilterStartBy').style.display=show?'block':'none';
		this.$('exportStartDate').style.display=show?'block':'none';
		var val=this.$('exportFilterStartBy').value;
		this.$('exportStartDate').value
			=this.getFilterDate(val,'exportStartDate').formatString(this.datetimefmt);
		if (which && (which.id=='exportFilterStartBy') && (val=='other'))
			this.$('exportStartDate').focus();

		var show=this.$('exportFilterEnd').checked;
		this.$('exportFilterEndBy').style.display=show?'block':'none';
		this.$('exportEndDate').style.display=show?'block':'none';
		var val=this.$('exportFilterEndBy').value;
		this.$('exportEndDate').value
			=this.getFilterDate(val,'exportEndDate').formatString(this.datetimefmt);
		 if (which && (which.id=='exportFilterEndBy') && (val=='other'))
			this.$('exportEndDate').focus();

		var show=this.$('exportFilterTags').checked;
		this.$('exportTags').style.display=show?'block':'none';

		var show=this.$('exportFilterText').checked;
		this.$('exportText').style.display=show?'block':'none';
	},
	getFilterDate: function(val,id) {
		var result=0;
		switch (val) {
			case 'file':
				result=new Date(document.lastModified);
				break;
			case 'other':
				result=new Date(this.$(id).value);
				break;
			default: // today=0, yesterday=1, one week=7, two weeks=14, a month=31
				var now=new Date(); var tz=now.getTimezoneOffset()*60000; now-=tz;
				var oneday=86400000;
				if (id=='exportStartDate')
					result=new Date((Math.floor(now/oneday)-val)*oneday+tz);
				else
					result=new Date((Math.floor(now/oneday)-val+1)*oneday+tz-1);
				break;
		}
		return result;
	},
	filterExportList: function() {
		var theList  = this.$('exportList'); if (!theList) return -1;
		var filterStart=this.$('exportFilterStart').checked;
		var val=this.$('exportFilterStartBy').value;
		var startDate=config.macros.exportTiddlers.getFilterDate(val,'exportStartDate');
		var filterEnd=this.$('exportFilterEnd').checked;
		var val=this.$('exportFilterEndBy').value;
		var endDate=config.macros.exportTiddlers.getFilterDate(val,'exportEndDate');
		var filterTags=this.$('exportFilterTags').checked;
		var tags=this.$('exportTags').value;
		var filterText=this.$('exportFilterText').checked;
		var text=this.$('exportText').value;
		if (!(filterStart||filterEnd||filterTags||filterText)) {
			alert('Please set the selection filter');
			this.$('exportFilterPanel').style.display='block';
			return -1;
		}
		if (filterStart&&filterEnd&&(startDate>endDate)) {
			var msg='starting date/time:\n'
			msg+=startDate.toLocaleString()+'\n';
			msg+='is later than ending date/time:\n'
			msg+=endDate.toLocaleString()
			alert(msg);
			return -1;
		}
		// if filter by tags, get list of matching tiddlers
		// use getMatchingTiddlers() (if MatchTagsPlugin is installed) for full boolean expressions
		// otherwise use getTaggedTiddlers() for simple tag matching
		if (filterTags) {
			var fn=store.getMatchingTiddlers||store.getTaggedTiddlers;
			var t=fn.apply(store,[tags]);
			var tagged=[];
			for (var i=0; i<t.length; i++) tagged.push(t[i].title);
		}
		// scan list and select tiddlers that match all applicable criteria
		var total=0;
		var count=0;
		for (var i=0; i<theList.options.length; i++) {
			// get item, skip non-tiddler list items (section headings)
			var opt=theList.options[i]; if (opt.value=='') continue;
			// get tiddler, skip missing tiddlers (this should NOT happen)
			var tiddler=store.getTiddler(opt.value); if (!tiddler) continue; 
			var sel=true;
			if ( (filterStart && tiddler.modified<startDate)
			|| (filterEnd && tiddler.modified>endDate)
			|| (filterTags && !tagged.contains(tiddler.title))
			|| (filterText && (tiddler.text.indexOf(text)==-1) && (tiddler.title.indexOf(text)==-1)))
				sel=false;
			opt.selected=sel;
			count+=sel?1:0;
			total++;
		}
		return count;
	},
	deleteTiddlers: function() {
		var list=this.$('exportList'); if (!list) return;
		var tids=[];
		for (i=0;i<list.length;i++)
			if (list.options[i].selected && list.options[i].value.length)
				tids.push(list.options[i].value);
		if (!confirm('Are you sure you want to delete these tiddlers:\n\n'+tids.join(', '))) return;
		store.suspendNotifications();
		for (t=0;t<tids.length;t++) {
			var tid=store.getTiddler(tids[t]); if (!tid) continue;
			var msg="'"+tid.title+"' is tagged with 'systemConfig'.\n\n";
			msg+='Removing this tiddler may cause unexpected results.  Are you sure?'
			if (tid.tags.contains('systemConfig') && !confirm(msg)) continue;
			store.removeTiddler(tid.title);
			story.closeTiddler(tid.title);
		}
		store.resumeNotifications();
		alert(tids.length+' tiddlers deleted');
		this.refreshList(0); // reload listbox
		store.notifyAll(); // update page display
	},
	go: function() {
		if (window.location.protocol!='file:') // make sure we are local
			{ displayMessage(config.messages.notFileUrlError); return; }
		// get selected tidders, target filename, target type, and notes
		var list=this.$('exportList'); if (!list) return;
		var tids=[]; for (var i=0; i<list.options.length; i++) {
			var opt=list.options[i]; if (!opt.selected||!opt.value.length) continue;
			var tid=store.getTiddler(opt.value); if (!tid) continue;
			tids.push(tid);
		}
		if (!tids.length) return; // no tiddlers selected
		var target=this.$('exportFilename').value.trim();
		if (!target.length) {
			displayMessage('A local target path/filename is required',target);
			return;
		}
		var merge=this.$('exportMerge').checked;
		var filetype=this.$('exportFormat').value.toLowerCase();
		var notes=this.$('exportNotes').value.replace(/\n/g,'<br>');
		var total={val:0};
		var out=this.assembleFile(target,filetype,tids,notes,total,merge);
		if (!total.val) return; // cancelled file overwrite
		var link='file:///'+target.replace(/\\/g,'/');
		var samefile=link==decodeURIComponent(window.location.href);
		var p=getLocalPath(document.location.href);
		if (samefile) {
			if (config.options.chkSaveBackups) { var t=loadOriginal(p);if(t)saveBackup(p,t); }
			if (config.options.chkGenerateAnRssFeed && saveRss instanceof Function) saveRss(p);
		}
		var ok=saveFile(target,out);
		displayMessage((ok?this.okmsg:this.failmsg).format([total.val,total.val!=1?'s':'',target]),link);
	},
	plainTextHeader:
		 'Source:\n\t%0\n'
		+'Title:\n\t%1\n'
		+'Subtitle:\n\t%2\n'
		+'Created:\n\t%3 by %4\n'
		+'Application:\n\tTiddlyWiki %5 / %6 %7\n\n',
	plainTextTiddler:
		'- - - - - - - - - - - - - - -\n'
		+'|     title: %0\n'
		+'|   created: %1\n'
		+'|  modified: %2\n'
		+'| edited by: %3\n'
		+'|      tags: %4\n'
		+'- - - - - - - - - - - - - - -\n'
		+'%5\n',
	plainTextFooter:
		'',
	newsFeedHeader:
		 '<'+'?xml version="1.0"?'+'>\n'
		+'<rss version="2.0">\n'
		+'<channel>\n'
		+'<title>%1</title>\n'
		+'<link>%0</link>\n'
		+'<description>%2</description>\n'
		+'<language>en-us</language>\n'
		+'<copyright>Copyright '+(new Date().getFullYear())+' %4</copyright>\n'
		+'<pubDate>%3</pubDate>\n'
		+'<lastBuildDate>%3</lastBuildDate>\n'
		+'<docs>http://blogs.law.harvard.edu/tech/rss</docs>\n'
		+'<generator>TiddlyWiki %5 / %6 %7</generator>\n',
	newsFeedTiddler:
		'\n%0\n',
	newsFeedFooter:
		'</channel></rss>',
	pureStoreHeader:
		 '<html><body>'
		+'<style type="text/css">'
		+'	#storeArea {display:block;margin:1em;}'
		+'	#storeArea div {padding:0.5em;margin:1em;border:2px solid black;height:10em;overflow:auto;}'
		+'	#pureStoreHeading {width:100%;text-align:left;background-color:#eeeeee;padding:1em;}'
		+'</style>'
		+'<div id="pureStoreHeading">'
		+'	TiddlyWiki "PureStore" export file<br>'
		+'	Source'+': <b>%0</b><br>'
		+'	Title: <b>%1</b><br>'
		+'	Subtitle: <b>%2</b><br>'
		+'	Created: <b>%3</b> by <b>%4</b><br>'
		+'	TiddlyWiki %5 / %6 %7<br>'
		+'	Notes:<hr><pre>%8</pre>'
		+'</div>'
		+'<div id="storeArea">',
	pureStoreTiddler:
		'%0\n%1',
	pureStoreFooter:
		'</div><!--POST-BODY-START-->\n<!--POST-BODY-END--></body></html>',
	assembleFile: function(target,filetype,tids,notes,total,merge) {
		var revised='';
		var now = new Date().toLocaleString();
		var src=convertUnicodeToUTF8(document.location.href);
		var title = convertUnicodeToUTF8(wikifyPlain('SiteTitle').htmlEncode());
		var subtitle = convertUnicodeToUTF8(wikifyPlain('SiteSubtitle').htmlEncode());
		var user = convertUnicodeToUTF8(config.options.txtUserName.htmlEncode());
		var twver = version.major+'.'+version.minor+'.'+version.revision;
		var v=version.extensions.ExportTiddlersPlugin; var pver = v.major+'.'+v.minor+'.'+v.revision;
		var headerargs=[src,title,subtitle,now,user,twver,'ExportTiddlersPlugin',pver,notes];
		switch (filetype) {
			case this.type_TX: // plain text
				var header=this.plainTextHeader.format(headerargs);
				var footer=this.plainTextFooter;
				break;
			case this.type_CS: // comma-separated
				var fields={};
				for (var i=0; i<tids.length; i++) for (var f in tids[i].fields) fields[f]=f;
				var names=['title','created','modified','modifier','tags','text'];
				for (var f in fields) names.push(f);
				var header=names.join(',')+'\n';
				var footer='';
				break;
			case this.type_NF: // news feed (XML)
				headerargs[0]=store.getTiddlerText('SiteUrl','');
				var header=this.newsFeedHeader.format(headerargs);
				var footer=this.newsFeedFooter;
				break;
			case this.type_PS: // PureStore (no code)
				var header=this.pureStoreHeader.format(headerargs);
				var footer=this.pureStoreFooter;
				break;
			case this.type_TW: // full TiddlyWiki
			default:
				var currPath=getLocalPath(window.location.href);
				var original=loadFile(currPath);
				if (!original) { displayMessage(config.messages.cantSaveError); return; }
				var posDiv = locateStoreArea(original);
				if (!posDiv) { displayMessage(config.messages.invalidFileError.format([currPath])); return; }
				var header = original.substr(0,posDiv[0]+startSaveArea.length)+'\n';
				var footer = '\n'+original.substr(posDiv[1]);
				break;
		}
		var out=this.getData(target,filetype,tids,fields,merge);
		var revised = header+convertUnicodeToUTF8(out.join('\n'))+footer;
		// if full TW, insert page title and language attr, and reset all MARKUP blocks...
		if (filetype==this.type_TW) {
			var newSiteTitle=convertUnicodeToUTF8(getPageTitle()).htmlEncode();
			revised=revised.replaceChunk('<title'+'>','</title'+'>',' ' + newSiteTitle + ' ');
			revised=updateLanguageAttribute(revised);
			var titles=[]; for (var i=0; i<tids.length; i++) titles.push(tids[i].title);
			revised=updateMarkupBlock(revised,'PRE-HEAD',
				titles.contains('MarkupPreHead')? 'MarkupPreHead' :null);
			revised=updateMarkupBlock(revised,'POST-HEAD',
				titles.contains('MarkupPostHead')?'MarkupPostHead':null);
			revised=updateMarkupBlock(revised,'PRE-BODY',
				titles.contains('MarkupPreBody')? 'MarkupPreBody' :null);
			revised=updateMarkupBlock(revised,'POST-SCRIPT',
				titles.contains('MarkupPostBody')?'MarkupPostBody':null);
		}
		total.val=out.length;
		return revised;
	},
	getData: function(target,filetype,tids,fields,merge) {
		// output selected tiddlers and gather list of titles (for use with merge)
		var out=[]; var titles=[];
		var url=store.getTiddlerText('SiteUrl','');
		for (var i=0; i<tids.length; i++) {
			out.push(this.formatItem(store,filetype,tids[i],url,fields));
			titles.push(tids[i].title);
		}
		// if TW or PureStore format, ask to merge with existing tiddlers (if any)
		if (filetype==this.type_TW || filetype==this.type_PS) {
			var txt=loadFile(target);
			if (txt && txt.length) {
				var remoteStore=new TiddlyWiki();
				if (version.major+version.minor*.1+version.revision*.01<2.52) txt=convertUTF8ToUnicode(txt);
				if (remoteStore.importTiddlyWiki(txt)) {
					var existing=remoteStore.getTiddlers('title');
					var msg=this.overwriteprompt.format([target,existing.length,existing.length!=1?'s':'']);
					if (merge) {
						var added=titles.length; var updated=0; var kept=0;
						for (var i=0; i<existing.length; i++)
							if (titles.contains(existing[i].title)) {
								added--; updated++;
							} else {
								out.push(this.formatItem(remoteStore,filetype,existing[i],url));
								kept++;
							}
						displayMessage(this.mergestatus.format(
							[added,added!=1?'s':'',updated,updated!=1?'s':'',kept,kept!=1?'s':'',]));
					}
					else if (!confirm(msg)) out=[]; // empty the list = don't write file
				}
			}
		}
		return out;
	},
	formatItem: function(s,f,t,u,fields) {
		if (f==this.type_TW)
			var r=s.getSaver().externalizeTiddler(s,t);
		if (f==this.type_PS)
			var r=this.pureStoreTiddler.format([t.title,s.getSaver().externalizeTiddler(s,t)]);
		if (f==this.type_NF)
			var r=this.newsFeedTiddler.format([t.saveToRss(u)]);
		if (f==this.type_TX)
			var r=this.plainTextTiddler.format([t.title, t.created.toLocaleString(), t.modified.toLocaleString(),
				t.modifier, String.encodeTiddlyLinkList(t.tags), t.text]);
		if (f==this.type_CS) {
			function toCSV(t) { return '"'+t.replace(/"/g,'""')+'"'; } // always encode CSV
			var out=[ toCSV(t.title), toCSV(t.created.toLocaleString()), toCSV(t.modified.toLocaleString()),
				toCSV(t.modifier), toCSV(String.encodeTiddlyLinkList(t.tags)), toCSV(t.text) ];
			for (var f in fields) out.push(toCSV(t.fields[f]||''));
			var r=out.join(',');
		}
		return r||"";
	}
}
//}}}
/***
!!!Control panel CSS
//{{{
!css
#exportPanel {
	display: none; position:absolute; z-index:12; width:35em; right:105%; top:6em;
	background-color: #eee; color:#000; font-size: 8pt; line-height:110%;
	border:1px solid black; border-bottom-width: 3px; border-right-width: 3px;
	padding: 0.5em; margin:0em; -moz-border-radius:1em;-webkit-border-radius:1em;
}
#exportPanel a, #exportPanel td a { color:#009; display:inline; margin:0px; padding:1px; }
#exportPanel table {
	width:100%; border:0px; padding:0px; margin:0px;
	font-size:8pt; line-height:110%; background:transparent;
}
#exportPanel tr { border:0px;padding:0px;margin:0px; background:transparent; }
#exportPanel td { color:#000; border:0px;padding:0px;margin:0px; background:transparent; }
#exportPanel select { width:98%;margin:0px;font-size:8pt;line-height:110%;}
#exportPanel input  { width:98%;padding:0px;margin:0px;font-size:8pt;line-height:110%; }
#exportPanel textarea  { width:98%;padding:0px;margin:0px;overflow:auto;font-size:8pt; }
#exportPanel .box {
	border:1px solid black; padding:3px; margin-bottom:5px;
	background:#f8f8f8; -moz-border-radius:5px;-webkit-border-radius:5px; }
#exportPanel .topline { border-top:2px solid black; padding-top:3px; margin-bottom:5px; }
#exportPanel .rad { width:auto;border:0 }
#exportPanel .chk { width:auto;border:0 }
#exportPanel .btn { width:auto; }
#exportPanel .btn1 { width:98%; }
#exportPanel .btn2 { width:48%; }
#exportPanel .btn3 { width:32%; }
#exportPanel .btn4 { width:24%; }
#exportPanel .btn5 { width:19%; }
!end
//}}}
!!!Control panel HTML
//{{{
!html
<!-- target path/file  -->
<div>
<div style="float:right;padding-right:.5em">
<input type="checkbox" style="width:auto" id="exportMerge" CHECKED
	title="combine selected tiddlers with existing tiddlers (if any) in export file"> merge
</div>
export to:<br>
<input type="text" id="exportFilename" size=40 style="width:93%"><input 
	type="button" id="exportBrowse" value="..." title="select or enter a local folder/file..." style="width:5%" 
	onclick="var fn=config.macros.exportTiddlers.askForFilename(this); if (fn.length) this.previousSibling.value=fn; ">
</div>

<!-- output format -->
<div>
format:
<select id="exportFormat" size=1>
	<option value="TW">TiddlyWiki HTML document (includes core code)</option>
	<option value="PS">TiddlyWiki "PureStore" HTML file (tiddler data only)</option>
	<option value="TX">TiddlyWiki plain text TXT file (tiddler source listing)</option>
	<option value="CS">Comma-Separated Value (CSV) data file</option>
	<option value="NF">RSS NewsFeed XML file</option>
</select>
</div>

<!-- notes -->
<div>
notes:<br>
<textarea id="exportNotes" rows=3 cols=40 style="height:4em;margin-bottom:5px;" onfocus="this.select()"></textarea> 
</div>

<!-- list of tiddlers -->
<table><tr align="left"><td>
	select:
	<a href="JavaScript:;" id="exportSelectAll"
		onclick="return config.macros.exportTiddlers.process(this)" title="select all tiddlers">
		&nbsp;all&nbsp;</a>
	<a href="JavaScript:;" id="exportSelectChanges"
		onclick="return config.macros.exportTiddlers.process(this)" title="select tiddlers changed since last save">
		&nbsp;changes&nbsp;</a>
	<a href="JavaScript:;" id="exportSelectOpened"
		onclick="return config.macros.exportTiddlers.process(this)" title="select tiddlers currently being displayed">
		&nbsp;opened&nbsp;</a>
	<a href="JavaScript:;" id="exportSelectRelated"
		onclick="return config.macros.exportTiddlers.process(this)" title="select tiddlers related to the currently selected tiddlers">
		&nbsp;related&nbsp;</a>
	<a href="JavaScript:;" id="exportToggleFilter"
		onclick="return config.macros.exportTiddlers.process(this)" title="show/hide selection filter">
		&nbsp;filter&nbsp;</a>
</td><td align="right">
	<a href="JavaScript:;" id="exportListSmaller"
		onclick="return config.macros.exportTiddlers.process(this)" title="reduce list size">
		&nbsp;&#150;&nbsp;</a>
	<a href="JavaScript:;" id="exportListLarger"
		onclick="return config.macros.exportTiddlers.process(this)" title="increase list size">
		&nbsp;+&nbsp;</a>
</td></tr></table>
<select id="exportList" multiple size="10" style="margin-bottom:5px;"
	onchange="config.macros.exportTiddlers.refreshList(this.selectedIndex)">
</select><br>

<!-- selection filter -->
<div id="exportFilterPanel" style="display:none">
<table><tr align="left"><td>
	selection filter
</td><td align="right">
	<a href="JavaScript:;" id="exportHideFilter"
		onclick="return config.macros.exportTiddlers.process(this)" title="hide selection filter">hide</a>
</td></tr></table>
<div class="box">

<input type="checkbox" class="chk" id="exportFilterStart" value="1"
	onclick="config.macros.exportTiddlers.showFilterFields(this)"> starting date/time<br>
<table cellpadding="0" cellspacing="0"><tr valign="center"><td width="50%">
	<select size=1 id="exportFilterStartBy"
		onchange="config.macros.exportTiddlers.showFilterFields(this);">
		<option value="0">today</option>
		<option value="1">yesterday</option>
		<option value="7">a week ago</option>
		<option value="30">a month ago</option>
		<option value="file">file date</option>
		<option value="other">other (mm/dd/yyyy hh:mm)</option>
	</select>
</td><td width="50%">
	<input type="text" id="exportStartDate" onfocus="this.select()"
		onchange="config.macros.exportTiddlers.$('exportFilterStartBy').value='other';">
</td></tr></table>

<input type="checkbox" class="chk" id="exportFilterEnd" value="1"
	onclick="config.macros.exportTiddlers.showFilterFields(this)"> ending date/time<br>
<table cellpadding="0" cellspacing="0"><tr valign="center"><td width="50%">
	<select size=1 id="exportFilterEndBy"
		onchange="config.macros.exportTiddlers.showFilterFields(this);">
		<option value="0">today</option>
		<option value="1">yesterday</option>
		<option value="7">a week ago</option>
		<option value="30">a month ago</option>
		<option value="file">file date</option>
		<option value="other">other (mm/dd/yyyy hh:mm)</option>
	</select>
</td><td width="50%">
	<input type="text" id="exportEndDate" onfocus="this.select()"
		onchange="config.macros.exportTiddlers.$('exportFilterEndBy').value='other';">
</td></tr></table>

<input type="checkbox" class="chk" id=exportFilterTags value="1"
	onclick="config.macros.exportTiddlers.showFilterFields(this)"> match tags<br>
<input type="text" id="exportTags" onfocus="this.select()">

<input type="checkbox" class="chk" id=exportFilterText value="1"
	onclick="config.macros.exportTiddlers.showFilterFields(this)"> match titles/tiddler text<br>
<input type="text" id="exportText" onfocus="this.select()">

</div> <!--box-->
</div> <!--panel-->

<!-- action buttons -->
<div style="text-align:center">
<input type=button class="btn4" onclick="config.macros.exportTiddlers.process(this)"
	id="exportFilter" value="apply filter">
<input type=button class="btn4" onclick="config.macros.exportTiddlers.process(this)"
	id="exportStart" value="export tiddlers">
<input type=button class="btn4" onclick="config.macros.exportTiddlers.process(this)"
	id="exportDelete" value="delete tiddlers">
<input type=button class="btn4" onclick="config.macros.exportTiddlers.process(this)"
	id="exportClose" value="close">
</div><!--center-->
!end
//}}}
***/
/***
|Name|ExportTiddlersPluginInfo|
|Source|http://www.TiddlyTools.com/#ExportTiddlersPlugin|
|Documentation|http://www.TiddlyTools.com/#ExportTiddlersPluginInfo|
|Version|2.9.5|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|documentation|
|Description|Documentation for ExportTiddlersPlugin|
interactively select and extract tiddlers from your ~TiddlyWiki document, and write them into another file, using one of several different file formats:
* ~TiddlyWiki - a complete, stand-alone, standard TiddlyWiki HTML document
* ~PureStore - a small HTML archive file containing tiddler data only (no core code)
* ~PlainText - a simple TXT text file with tiddler source listings
* Comma - a "Comma Separated Value" data/spreadsheet file
* ~NewsFeed  - an XML-format file that can be published for RSS syndication.
!!!!!Usage
<<<
{{{
<<exportTiddlers>> (sidebar menu item)
<<exportTiddlers inline>> (embedded control panel)
}}}

Inline control panel (live):
<<exportTiddlers inline>>

Optional "special tiddlers" used by this plugin:
* SiteUrl<br>URL for official server-published version of document being viewed (used in XML export). Default: //none//
<<<
!!!!!Revisions
<<<
2010.02.25 2.9.5 added merge checkbox option and improved 'merge' status message
2009.09.12 2.9.4 fixed 'return false' to prevent IE page transitions
2009.07.06 2.9.3 moved HTML to section for size reduction
2009.07.03 2.9.2 TW252 fixup: don't call convertUTF8ToUnicode() for local loadFile() I/O
2009.04.30 2.9.1 custom fields in CSV output
2009.04.19 2.9.0 added CSV format
2009.02.26 2.8.5 use macro-specific definition of $() function abbreviation (avoids conflict with JQuery)
2008.09.29 2.8.4 in getData(), convert existing TW file from UTF8 to Unicode before merging to correct handling of international characters and symbols.
2008.09.26 2.8.3 in go(), if rewriting *current* file and chkSaveBackups and/or chkGenerateAnRssFeed is enabled, then write a backup file or RSS feed, respectively.
2008.09.24 2.8.2 in assembleFile(), make sure that markup block is updated if corresponding Markup* tiddler is exported.
2008.09.19 2.8.1 in formatItem(), removed unnecessary convertUnicodeToUTF8() (was causing double-conversion!)
2008.09.11 2.8.0 extensive code cleanup: moved all global functions inside macro object. Re-wrote file generator and I/O to support TiddlyWiki, PlainText, PureStore, and NewsFeed file formats.  Replaced inline 'match tags' code with use of getMatchingTiddlers() from [[MatchTagsPlugin]] (if installed), with fallback to core getTaggedTiddlers() otherwise.
2008.05.27 2.7.0 added ability to 'merge' with existing export file.  Also, revised 'matchTags' functionality to be more robust and more efficient
2008.05.12 2.6.1 automatically add 'export' task to backstage (moved from BackstageTweaks)
2008.03.10 2.6.0 added "delete tiddlers" button
2007.12.04 *.*.* update for TW2.3.0: replaced deprecated core functions, regexps, and macros
2007.11.10 2.5.1 removed debugging alert messages from promptForExportFilename()
2007.10.31 2.5.0 code reduction: removed incomplete/unused interface and supporting functions for exporting directly to http, https or ftp servers.  Plugin now supports exporting to local file only.  Also, updated TW document output to generate TW2.2 compatible file format.
2007.10.30 2.4.2 added automatic shadow tiddler definition for [[ExportTiddlers]]
2007.07.16 2.4.1 in exportTWHeader(), reset HTML source 'markup' so installed markup is NOT copied to new file.
2007.06.30 2.4.0 added "select related tiddlers" feature.  Recursively scans the tiddler links[] info to find all tiddlers referenced by any of the currently selected tiddler, and then selects them all (including the original tiddlers).
2007.04.19 2.3.0 in exportData(), pass SiteURL value as param to saveToRss().  Fixes 'undefined' appearing in tiddler link in XML output.  Also, in refreshExportList(), added 'sort by tags'.  Also, added 'group select'... selecting a heading (date,author,tag) auto-selects all tiddlers in that group.
2007.03.02 2.2.6 in onClickExportButton(), when selecting open tiddlers for TW2.2, look for "storyDisplay" with fallback to "tiddlerDisplay" for TW2.1 or earlier
2007.03.01 2.2.5 removed hijack of store.saveChanges()
2006.11.08 2.2.4 added promptForExportFilename() and replaced type="file" control with edit field + browse button ("...").
2006.10.12 2.2.3 in exportDIVFooter(), write POST-BODY-START/END markers for compatibility with TW2.1 core file format.
2006.05.11 2.2.2 in createExportPanel, removed call to addNotification() to reduce unneeded feedback messages and increase overall document performance.
2006.05.02 2.2.1 Use displayMessage() to show number of selected tiddlers instead of updating listbox 'header' item after each selection.  Prevents awkward 'scroll-to-top' behavior that made multi-select via ctrl-click nearly impossible.
2006.04.29 2.2.0 New features: free-form "Notes" text inserted in the header of PureStore files.
2006.03.29 2.1.3 added calls to convertUnicodeToUTF8() for generated output, so it better handles international characters.
2006.02.12 2.1.2 more FF1501 bug fixes.
2006.02.04 2.1.1 added var to unintended globals to avoids FireFox1501 crash bug
2006.02.02 2.1.0 Added support for output of complete TiddlyWiki documents
2006.01.21 2.0.1 Defer initial panel creation and only register a notification function when panel first is created
in saveChanges 'hijack', create panel as needed.  Note: if window.event is not available to identify the click location, the export panel is positioned relative to the 'tiddlerDisplay' element of the TW document.
2005.12.27 2.0.0 Update for TW2.0.
2005.12.24 0.9.5 Minor adjustments to CSS to force correct link colors regardless of TW stylesheet selection
2005.12.16 0.9.4 Dynamically create/remove exportPanel so only one instance exists at a time
2005.11.15 0.9.2 added non-Ajax post to bypass cross-domain security restrictions.
2005.11.08 0.9.1 moved HTML, CSS and control initialization into exportInit() function and call from macro handler instead of at load time.
2005.10.28 0.9.0 added 'select opened tiddlers' feature. Based on a suggestion by Geoff Slocock
2005.10.24 0.8.3 Corrected hijack of 'save changes' when using http:
2005.10.18 0.8.2 added AJAX functions
2005.10.18 0.8.1 Corrected timezone handling and error checking/reporting when filtering tiddlers. More style tweaks, minor text changes and some assorted layout cleanup.
2005.10.17 0.8.0 First pre-release.
2005.10.16 0.7.0 filter by tags
2005.10.15 0.6.0 filter by title/text
2005.10.14 0.5.0 export to local file (DIV or XML)
2005.10.14 0.4.0 filter by start/end date
2005.10.13 0.3.0 panel interaction
2005.10.11 0.2.0 panel layout
2005.10.10 0.1.0 code framework
2005.10.09 0.0.0 development started
<<<
!Mandatory tiddlers
[[InfoboxTablesPlugin]]
[[InfoboxTablesPluginInfo]]

!Optional tiddlers
[[InfoboxTablesPluginCommand]]
[[InfoboxTablesPluginCommandInfo]]

!Examples
<<list filter [tag[infoboxexample]]>>

!Templates
<<list filter [tag[infobox]]>>
/***
|Name|ImportTiddlersPlugin|
|Source|http://www.TiddlyTools.com/#ImportTiddlersPlugin|
|Documentation|http://www.TiddlyTools.com/#ImportTiddlersPluginInfo|
|Version|4.6.2|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|interactive controls for import/export with filtering.|
Combine tiddlers from any two TiddlyWiki documents.  Interactively select and copy tiddlers from another TiddlyWiki source document.  Includes prompting for skip, rename, merge or replace actions when importing tiddlers that match existing titles.  When done, a list of all imported tiddlers is written into [[ImportedTiddlers]].
!!!!!Documentation
<<<
see [[ImportTiddlersPluginInfo]] for details
<<<
!!!!!interactive control panel
<<<
<<importTiddlers inline>>
{{clear{
^^(see also: [[ImportTiddlers]] shadow tiddler)^^}}}
<<<
!!!!!Revisions
<<<
2011.02.14 4.6.2 fix OSX error: use picker.file.path
2009.10.10 4.6.1 in createImportPanel, Use {{{window.Components}}} instead of {{{config.browser.isGecko}}} to avoid applying FF3 'file browse' fixup in Chrome.
2009.10.06 4.6.0 added createTiddlerFromFile (import text files)
|please see [[ImportTiddlersPluginInfo]] for additional revision details|
2005.07.20 1.0.0 Initial Release
<<<
!!!!!Code
***/
//{{{
version.extensions.ImportTiddlersPlugin= {major: 4, minor: 6, revision: 2, date: new Date(2011,2,14)};

// IE needs explicit global scoping for functions/vars called from browser events
window.onClickImportButton=onClickImportButton;
window.refreshImportList=refreshImportList;

// default cookie/option values
if (!config.options.chkImportReport) config.options.chkImportReport=true;

// default shadow definition
config.shadowTiddlers.ImportTiddlers='<<importTiddlers inline>>';

// use shadow tiddler content in backstage panel
if (config.tasks) config.tasks.importTask.content='<<tiddler ImportTiddlers>>' // TW2.2 or above
//}}}
//{{{
// backward-compatiblity for TW2.0.x and TW1.2.x
if (config.macros.importTiddlers==undefined) config.macros.importTiddlers={};
if (typeof merge=='undefined') {
	function merge(dst,src,preserveExisting) {
		for(var i in src) { if(!preserveExisting || dst[i] === undefined) dst[i] = src[i]; }
		return dst;
	}
}
if (config.browser.isGecko===undefined)
	config.browser.isGecko=(config.userAgent.indexOf('gecko')!=-1);
//}}}
//{{{
merge(config.macros.importTiddlers,{
	$: function(id) { return document.getElementById(id); }, // abbreviation
	label: 'import tiddlers',
	prompt: 'Copy tiddlers from another document',
	openMsg: 'Opening %0',
	openErrMsg: 'Could not open %0 - error=%1',
	readMsg: 'Read %0 bytes from %1',
	foundMsg: 'Found %0 tiddlers in %1',
	filterMsg: "Filtered %0 tiddlers matching '%1'",
	summaryMsg: '%0 tiddler%1 in the list',
	summaryFilteredMsg: '%0 of %1 tiddler%2 in the list',
	plural: 's are',
	single: ' is',
	countMsg: '%0 tiddlers selected for import',
	processedMsg: 'Processed %0 tiddlers',
	importedMsg: 'Imported %0 of %1 tiddlers from %2',
	loadText: 'please load a document...',
	closeText: 'close',
	doneText: 'done',
	startText: 'import',
	stopText: 'stop',
	local: true,		// default to import from local file
	src: '',		// path/filename or URL of document to import (retrieved from SiteUrl)
	proxy: '',		// URL for remote proxy script (retrieved from SiteProxy)
	useProxy: false,	// use specific proxy script in front of remote URL
	inbound: null,		// hash-indexed array of tiddlers from other document
	newTags: '',		// text of tags added to imported tiddlers
	addTags: true,		// add new tags to imported tiddlers
	listsize: 10,		// # of lines to show in imported tiddler list
	importTags: true,	// include tags from remote source document when importing a tiddler
	keepTags: true,		// retain existing tags when replacing a tiddler
	sync: false,		// add 'server' fields to imported tiddlers (for sync function)
	lastFilter: '',		// most recent filter (URL hash) applied
	lastAction: null,	// most recent collision button performed
	index: 0,		// current processing index in import list
	sort: ''		// sort order for imported tiddler listbox
});
//}}}
//{{{
// hijack core macro handler
if (config.macros.importTiddlers.coreHandler==undefined)
	config.macros.importTiddlers.coreHandler=config.macros.importTiddlers.handler;

config.macros.importTiddlers.handler = function(place,macroName,params,wikifier,paramString,tiddler) {
	if (!params[0] || params[0].toLowerCase()=='core') { // default to built in
		if (config.macros.importTiddlers.coreHandler)
			config.macros.importTiddlers.coreHandler.apply(this,arguments);
		else 
			createTiddlyButton(place,this.label,this.prompt,onClickImportMenu);
	} else if (params[0]=='link') { // show link to floating panel
		createTiddlyButton(place,params[1]||this.label,params[2]||this.prompt,onClickImportMenu);
	} else if (params[0]=='inline') {// show panel as INLINE tiddler content
		createImportPanel(place);
		this.$('importPanel').style.position='static';
		this.$('importPanel').style.display='block';
	} else if (config.macros.loadTiddlers)
		config.macros.loadTiddlers.handler(place,macroName,params); // any other params: loadtiddlers
}
//}}}
//{{{
// Handle link click to create/show/hide control panel
function onClickImportMenu(e) { var e=e||window.event;
	var parent=resolveTarget(e).parentNode;
	var panel=document.getElementById('importPanel');
	if (panel==undefined || panel.parentNode!=parent) panel=createImportPanel(parent);
	var isOpen=panel.style.display=='block';
	if(config.options.chkAnimate)
		anim.startAnimating(new Slider(panel,!isOpen,false,'none'));
	else
		panel.style.display=isOpen?'none':'block';
	e.cancelBubble = true; if (e.stopPropagation) e.stopPropagation(); return(false);
}
//}}}
//{{{
// Create control panel: HTML, CSS
function createImportPanel(place) {
	var cmi=config.macros.importTiddlers; // abbrev
	var panel=cmi.$('importPanel');
	if (panel) { panel.parentNode.removeChild(panel); }
	setStylesheet(store.getTiddlerText('ImportTiddlersPlugin##css'),'importTiddlers');
	panel=createTiddlyElement(place,'span','importPanel',null,null)
	panel.innerHTML=store.getTiddlerText('ImportTiddlersPlugin##html');
	refreshImportList();
	if (!cmi.src.length) cmi.src=store.getTiddlerText('SiteUrl')||'';
	cmi.$('importSourceURL').value=cmi.src;
	if (!cmi.proxy.length) cmi.proxy=store.getTiddlerText('SiteProxy')||'SiteProxy';
	cmi.$('importSiteProxy').value=cmi.proxy;
	if (window.Components) { // FF3 FIXUP
		cmi.$('fileImportSource').style.display='none';
		cmi.$('importLocalPanelFix').style.display='block';
	}
	cmi.$('chkSync').checked=cmi.sync;
	cmi.$('chkImportTags').checked=cmi.importTags;
	cmi.$('chkKeepTags').checked=cmi.keepTags;
	cmi.$('chkAddTags').checked=cmi.addTags;
	cmi.$('txtNewTags').value=cmi.newTags;
	cmi.$('txtNewTags').style.display=cmi.addTags?'block':'none';
	cmi.$('chkSync').checked=cmi.sync;
	cmi.$('chkImportReport').checked=config.options.chkImportReport;
	return panel;
}
//}}}
//{{{
// process control interactions
function onClickImportButton(which,event) {
	var cmi=config.macros.importTiddlers; // abbreviation
	var list=cmi.$('importList'); if (!list) return false;
	var thePanel=cmi.$('importPanel');
	var theCollisionPanel=cmi.$('importCollisionPanel');
	var theNewTitle=cmi.$('importNewTitle');
	var count=0;
	switch (which.id)
		{
		case 'importFromFile':	// show local panel
		case 'importFromWeb':	// show HTTP panel
			cmi.local=(which.id=='importFromFile');
			cmi.showPanel('importLocalPanel',cmi.local);
			cmi.showPanel('importHTTPPanel',!cmi.local);
			break;
		case 'importOptions':	// show/hide options panel
			cmi.showPanel('importOptionsPanel',cmi.$('importOptionsPanel').style.display=='none');
			break;
		case 'fileImportSource':
		case 'importLoad':		// load import source into hidden frame
			importReport();		// if an import was in progress, generate a report
			cmi.inbound=null;	// clear the imported tiddler buffer
			refreshImportList();	// reset/resize the listbox
			if (cmi.src=='') break;
			// Load document, read it's DOM and fill the list
			cmi.loadRemoteFile(cmi.src,cmi.filterTiddlerList);
			break;
		case 'importSelectFeed':	// select a pre-defined systemServer feed URL
			var p=Popup.create(which); if (!p) return false;
			var tids=store.getTaggedTiddlers('systemServer');
			if (!tids.length)
				createTiddlyText(createTiddlyElement(p,'li'),'no pre-defined server feeds');
			for (var t=0; t<tids.length; t++) {
				var u=store.getTiddlerSlice(tids[t].title,'URL');
				var d=store.getTiddlerSlice(tids[t].title,'Description');
				if (!d||!d.length) d=store.getTiddlerSlice(tids[t].title,'description');
				if (!d||!d.length) d=u;
				createTiddlyButton(createTiddlyElement(p,'li'),tids[t].title,d,
					function(){
						var u=this.getAttribute('url');
						document.getElementById('importSourceURL').value=u;
						config.macros.importTiddlers.src=u;
						document.getElementById('importLoad').onclick();
					},
					null,null,null,{url:u});
			}
			Popup.show();
			event.cancelBubble = true;
			if (event.stopPropagation) event.stopPropagation();
			return false;
			// create popup with feed list
			// onselect, insert feed URL into input field.
			break;
		case 'importSelectAll':		// select all tiddler list items (i.e., not headings)
			importReport();		// if an import was in progress, generate a report
			for (var t=0,count=0; t < list.options.length; t++) {
				if (list.options[t].value=='') continue;
				list.options[t].selected=true;
				count++;
			}
			clearMessage(); displayMessage(cmi.countMsg.format([count]));
			cmi.$('importStart').disabled=!count;
			break;
		case 'importSelectNew':		// select tiddlers not in current document
			importReport();		// if an import was in progress, generate a report
			for (var t=0,count=0; t < list.options.length; t++) {
				list.options[t].selected=false;
				if (list.options[t].value=='') continue;
				list.options[t].selected=!store.tiddlerExists(list.options[t].value);
				count+=list.options[t].selected?1:0;
			}
			clearMessage(); displayMessage(cmi.countMsg.format([count]));
			cmi.$('importStart').disabled=!count;
			break;
		case 'importSelectChanges':		// select tiddlers that are updated from existing tiddlers
			importReport();		// if an import was in progress, generate a report
			for (var t=0,count=0; t < list.options.length; t++) {
				list.options[t].selected=false;
				if (list.options[t].value==''||!store.tiddlerExists(list.options[t].value)) continue;
				for (var i=0; i<cmi.inbound.length; i++) // find matching inbound tiddler
					{ var inbound=cmi.inbound[i]; if (inbound.title==list.options[t].value) break; }
				list.options[t].selected=(inbound.modified-store.getTiddler(list.options[t].value).modified>0); // updated tiddler
				count+=list.options[t].selected?1:0;
			}
			clearMessage(); displayMessage(cmi.countMsg.format([count]));
			cmi.$('importStart').disabled=!count;
			break;
		case 'importSelectDifferences':		// select tiddlers that are new or different from existing tiddlers
			importReport();		// if an import was in progress, generate a report
			for (var t=0,count=0; t < list.options.length; t++) {
				list.options[t].selected=false;
				if (list.options[t].value=='') continue;
				if (!store.tiddlerExists(list.options[t].value)) { list.options[t].selected=true; count++; continue; }
				for (var i=0; i<cmi.inbound.length; i++) // find matching inbound tiddler
					{ var inbound=cmi.inbound[i]; if (inbound.title==list.options[t].value) break; }
				list.options[t].selected=(inbound.modified-store.getTiddler(list.options[t].value).modified!=0); // changed tiddler
				count+=list.options[t].selected?1:0;
			}
			clearMessage(); displayMessage(cmi.countMsg.format([count]));
			cmi.$('importStart').disabled=!count;
			break;
		case 'importApplyFilter':	// filter list to include only matching tiddlers
			importReport();		// if an import was in progress, generate a report
			clearMessage();
			if (!cmi.all) // no tiddlers loaded = '0 selected'
				{ displayMessage(cmi.countMsg.format([0])); return false; }
			var hash=cmi.$('importLastFilter').value;
			cmi.inbound=cmi.filterByHash('#'+hash,cmi.all);
			refreshImportList();	// reset/resize the listbox
			break;
		case 'importStart':		// initiate the import processing
			importReport();		// if an import was in progress, generate a report
			cmi.$('importApplyToAll').checked=false;
			cmi.$('importStart').value=cmi.stopText;
			if (cmi.index>0) cmi.index=-1; // stop processing
			else cmi.index=importTiddlers(0); // or begin processing
			importStopped();
			break;
		case 'importClose':		// unload imported tiddlers or hide the import control panel
			// if imported tiddlers not loaded, close the import control panel
			if (!cmi.inbound) { thePanel.style.display='none'; break; }
			importReport();		// if an import was in progress, generate a report
			cmi.inbound=null;	// clear the imported tiddler buffer
			refreshImportList();	// reset/resize the listbox
			break;
		case 'importSkip':	// don't import the tiddler
			cmi.lastAction=which;
			var theItem	= list.options[cmi.index];
			for (var j=0;j<cmi.inbound.length;j++)
			if (cmi.inbound[j].title==theItem.value) break;
			var theImported = cmi.inbound[j];
			theImported.status='skipped after asking';			// mark item as skipped
			theCollisionPanel.style.display='none';
			cmi.index=importTiddlers(cmi.index+1);	// resume with NEXT item
			importStopped();
			break;
		case 'importRename':		// change name of imported tiddler
			cmi.lastAction=which;
			var theItem		= list.options[cmi.index];
			for (var j=0;j<cmi.inbound.length;j++)
			if (cmi.inbound[j].title==theItem.value) break;
			var theImported		= cmi.inbound[j];
			theImported.status	= 'renamed from '+theImported.title;	// mark item as renamed
			theImported.set(theNewTitle.value,null,null,null,null);		// change the tiddler title
			theItem.value		= theNewTitle.value;			// change the listbox item text
			theItem.text		= theNewTitle.value;			// change the listbox item text
			theCollisionPanel.style.display='none';
			cmi.index=importTiddlers(cmi.index);	// resume with THIS item
			importStopped();
			break;
		case 'importMerge':	// join existing and imported tiddler content
			cmi.lastAction=which;
			var theItem	= list.options[cmi.index];
			for (var j=0;j<cmi.inbound.length;j++)
			if (cmi.inbound[j].title==theItem.value) break;
			var theImported	= cmi.inbound[j];
			var theExisting	= store.getTiddler(theItem.value);
			var theText	= theExisting.text+'\n----\n^^merged from: ';
			theText		+='[['+cmi.src+'#'+theItem.value+'|'+cmi.src+'#'+theItem.value+']]^^\n';
			theText		+='^^'+theImported.modified.toLocaleString()+' by '+theImported.modifier+'^^\n'+theImported.text;
			var theDate	= new Date();
			var theTags	= theExisting.getTags()+' '+theImported.getTags();
			theImported.set(null,theText,null,theDate,theTags);
			theImported.status   = 'merged with '+theExisting.title;	// mark item as merged
			theImported.status  += ' - '+theExisting.modified.formatString('MM/DD/YYYY 0hh:0mm:0ss');
			theImported.status  += ' by '+theExisting.modifier;
			theCollisionPanel.style.display='none';
			cmi.index=importTiddlers(cmi.index);	// resume with this item
			importStopped();
			break;
		case 'importReplace':		// substitute imported tiddler for existing tiddler
			cmi.lastAction=which;
			var theItem		  = list.options[cmi.index];
			for (var j=0;j<cmi.inbound.length;j++)
			if (cmi.inbound[j].title==theItem.value) break;
			var theImported     = cmi.inbound[j];
			var theExisting	  = store.getTiddler(theItem.value);
			theImported.status  = 'replaces '+theExisting.title;		// mark item for replace
			theImported.status += ' - '+theExisting.modified.formatString('MM/DD/YYYY 0hh:0mm:0ss');
			theImported.status += ' by '+theExisting.modifier;
			theCollisionPanel.style.display='none';
			cmi.index=importTiddlers(cmi.index);	// resume with THIS item
			importStopped();
			break;
		case 'importListSmaller':		// decrease current listbox size, minimum=5
			if (list.options.length==1) break;
			list.size-=(list.size>5)?1:0;
			cmi.listsize=list.size;
			break;
		case 'importListLarger':		// increase current listbox size, maximum=number of items in list
			if (list.options.length==1) break;
			list.size+=(list.size<list.options.length)?1:0;
			cmi.listsize=list.size;
			break;
		case 'importListMaximize':	// toggle listbox size between current and maximum
			if (list.options.length==1) break;
			list.size=(list.size==list.options.length)?cmi.listsize:list.options.length;
			break;
		}
}
//}}}
//{{{
config.macros.importTiddlers.showPanel=function(place,show,skipAnim) {
	if (typeof place=='string') var place=document.getElementById(place);
	if (!place||!place.style) return;
	if(!skipAnim && anim && config.options.chkAnimate) anim.startAnimating(new Slider(place,show,false,'none'));
	else place.style.display=show?'block':'none';
}
//}}}
//{{{
function refreshImportList(selectedIndex) {
	var cmi=config.macros.importTiddlers; // abbrev
	var list=cmi.$('importList'); if (!list) return;
	// if nothing to show, reset list content and size
	if (!cmi.inbound) {
		while (list.length > 0) { list.options[0] = null; }
		list.options[0]=new Option(cmi.loadText,'',false,false);
		list.size=cmi.listsize;
		cmi.$('importLoad').disabled=false;
		cmi.$('importLoad').style.display='inline';
		cmi.$('importStart').disabled=true;
		cmi.$('importOptions').disabled=true;
		cmi.$('importOptions').style.display='none';
		cmi.$('fileImportSource').disabled=false;
		cmi.$('importFromFile').disabled=false;
		cmi.$('importFromWeb').disabled=false;
		cmi.$('importStart').value=cmi.startText;
		cmi.$('importClose').value=cmi.doneText;
		cmi.$('importSelectPanel').style.display='none';
		cmi.$('importOptionsPanel').style.display='none';
		return;
	}
	// there are inbound tiddlers loaded...
	cmi.$('importLoad').disabled=true;
	cmi.$('importLoad').style.display='none';
	cmi.$('importOptions').style.display='inline';
	cmi.$('importOptions').disabled=false;
	cmi.$('fileImportSource').disabled=true;
	cmi.$('importFromFile').disabled=true;
	cmi.$('importFromWeb').disabled=true;
	cmi.$('importClose').value=cmi.closeText;
	if (cmi.$('importSelectPanel').style.display=='none')
		cmi.showPanel('importSelectPanel',true);

	// get the sort order
	if (!selectedIndex)   selectedIndex=0;
	if (selectedIndex==0) cmi.sort='title';		// heading
	if (selectedIndex==1) cmi.sort='title';
	if (selectedIndex==2) cmi.sort='modified';
	if (selectedIndex==3) cmi.sort='tags';
	if (selectedIndex>3) {
		// display selected tiddler count
		for (var t=0,count=0; t < list.options.length; t++) {
			if (!list.options[t].selected) continue;
			if (list.options[t].value!='')
				count+=1;
			else { // if heading is selected, deselect it, and then select and count all in section
				list.options[t].selected=false;
				for ( t++; t<list.options.length && list.options[t].value!=''; t++) {
					list.options[t].selected=true;
					count++;
				}
			}
		}
		clearMessage(); displayMessage(cmi.countMsg.format([count]));
	}
	cmi.$('importStart').disabled=!count;
	if (selectedIndex>3) return; // no refresh needed

	// get the alphasorted list of tiddlers
	var tiddlers=cmi.inbound;
	tiddlers.sort(function (a,b) {if(a['title'] == b['title']) return(0); else return (a['title'] < b['title']) ? -1 : +1; });
	// clear current list contents
	while (list.length > 0) { list.options[0] = null; }
	// add heading and control items to list
	var i=0;
	var indent=String.fromCharCode(160)+String.fromCharCode(160);
	if (cmi.all.length==tiddlers.length)
		var summary=cmi.summaryMsg.format([tiddlers.length,(tiddlers.length!=1)?cmi.plural:cmi.single]);
	else
		var summary=cmi.summaryFilteredMsg.format([tiddlers.length,cmi.all.length,(cmi.all.length!=1)?cmi.plural:cmi.single]);
	list.options[i++]=new Option(summary,'',false,false);
	list.options[i++]=new Option(((cmi.sort=='title'   )?'>':indent)+' [by title]','',false,false);
	list.options[i++]=new Option(((cmi.sort=='modified')?'>':indent)+' [by date]','',false,false);
	list.options[i++]=new Option(((cmi.sort=='tags')?'>':indent)+' [by tags]','',false,false);
	// output the tiddler list
	switch(cmi.sort) {
		case 'title':
			for(var t = 0; t < tiddlers.length; t++)
				list.options[i++] = new Option(tiddlers[t].title,tiddlers[t].title,false,false);
			break;
		case 'modified':
			// sort descending for newest date first
			tiddlers.sort(function (a,b) {if(a['modified'] == b['modified']) return(0); else return (a['modified'] > b['modified']) ? -1 : +1; });
			var lastSection = '';
			for(var t = 0; t < tiddlers.length; t++) {
				var tiddler = tiddlers[t];
				var theSection = tiddler.modified.toLocaleDateString();
				if (theSection != lastSection) {
					list.options[i++] = new Option(theSection,'',false,false);
					lastSection = theSection;
				}
				list.options[i++] = new Option(indent+indent+tiddler.title,tiddler.title,false,false);
			}
			break;
		case 'tags':
			var theTitles = {}; // all tiddler titles, hash indexed by tag value
			var theTags = new Array();
			for(var t=0; t<tiddlers.length; t++) {
				var title=tiddlers[t].title;
				var tags=tiddlers[t].tags;
				if (!tags || !tags.length) {
					if (theTitles['untagged']==undefined) { theTags.push('untagged'); theTitles['untagged']=new Array(); }
					theTitles['untagged'].push(title);
				}
				else for(var s=0; s<tags.length; s++) {
					if (theTitles[tags[s]]==undefined) { theTags.push(tags[s]); theTitles[tags[s]]=new Array(); }
					theTitles[tags[s]].push(title);
				}
			}
			theTags.sort();
			for(var tagindex=0; tagindex<theTags.length; tagindex++) {
				var theTag=theTags[tagindex];
				list.options[i++]=new Option(theTag,'',false,false);
				for(var t=0; t<theTitles[theTag].length; t++)
					list.options[i++]=new Option(indent+indent+theTitles[theTag][t],theTitles[theTag][t],false,false);
			}
			break;
		}
	list.selectedIndex=selectedIndex;		  // select current control item
	if (list.size<cmi.listsize) list.size=cmi.listsize;
	if (list.size>list.options.length) list.size=list.options.length;
}
//}}}
//{{{
// re-entrant processing for handling import with interactive collision prompting
function importTiddlers(startIndex) {
	var cmi=config.macros.importTiddlers; // abbrev
	if (!cmi.inbound) return -1;
	var list=cmi.$('importList'); if (!list) return;
	var t;
	// if starting new import, reset import status flags
	if (startIndex==0)
		for (var t=0;t<cmi.inbound.length;t++)
			cmi.inbound[t].status='';
	for (var i=startIndex; i<list.options.length; i++) {
		// if list item is not selected or is a heading (i.e., has no value), skip it
		if ((!list.options[i].selected) || ((t=list.options[i].value)==''))
			continue;
		for (var j=0;j<cmi.inbound.length;j++)
			if (cmi.inbound[j].title==t) break;
		var inbound = cmi.inbound[j];
		var theExisting = store.getTiddler(inbound.title);
		// avoid redundant import for tiddlers that are listed multiple times (when 'by tags')
		if (inbound.status=='added')
			continue;
		// don't import the 'ImportedTiddlers' history from the other document...
		if (inbound.title=='ImportedTiddlers')
			continue;
		// if tiddler exists and import not marked for replace or merge, stop importing
		if (theExisting && (inbound.status.substr(0,7)!='replace') && (inbound.status.substr(0,5)!='merge'))
			return i;
		// assemble tags (remote + existing + added)
		var newTags = '';
		if (cmi.importTags)
			newTags+=inbound.getTags()	// import remote tags
		if (cmi.keepTags && theExisting)
			newTags+=' '+theExisting.getTags(); // keep existing tags
		if (cmi.addTags && cmi.newTags.trim().length)
			newTags+=' '+cmi.newTags; // add new tags
		inbound.set(null,null,null,null,newTags.trim());
		// set the status to 'added' (if not already set by the 'ask the user' UI)
		inbound.status=(inbound.status=='')?'added':inbound.status;
		// set sync fields
		if (cmi.sync) {
			if (!inbound.fields) inbound.fields={}; // for TW2.1.x backward-compatibility
			inbound.fields['server.page.revision']=inbound.modified.convertToYYYYMMDDHHMM();
			inbound.fields['server.type']='file';
			inbound.fields['server.host']=(cmi.local&&!cmi.src.startsWith('file:')?'file:///':'')+cmi.src;
		}
		// do the import!
		store.suspendNotifications();
		store.saveTiddler(inbound.title, inbound.title, inbound.text, inbound.modifier, inbound.modified, inbound.tags, inbound.fields, true, inbound.created);
                store.fetchTiddler(inbound.title).created = inbound.created; // force creation date to imported value (needed for TW2.1.x and earlier)
		store.resumeNotifications();
		}
	return(-1);	// signals that we really finished the entire list
}
function importStopped() {
	var cmi=config.macros.importTiddlers; // abbrev
	var list=cmi.$('importList'); if (!list) return;
	var theNewTitle=cmi.$('importNewTitle');
	if (cmi.index==-1){ 
		cmi.$('importStart').value=cmi.startText;
		importReport();	// import finished... generate the report
	} else {
		// import collision...
		// show the collision panel and set the title edit field
		cmi.$('importStart').value=cmi.stopText;
		cmi.showPanel('importCollisionPanel',true);
		theNewTitle.value=list.options[cmi.index].value;
		if (cmi.$('importApplyToAll').checked && cmi.lastAction && cmi.lastAction.id!='importRename')
			onClickImportButton(cmi.lastAction);
	}
}
//}}}
//{{{
function importReport() {
	var cmi=config.macros.importTiddlers; // abbrev
	if (!cmi.inbound) return;
	// if import was not completed, the collision panel will still be open... close it now.
	var panel=cmi.$('importCollisionPanel'); if (panel) panel.style.display='none';
	// get the alphasorted list of tiddlers
	var tiddlers = cmi.inbound;
	// gather the statistics
	var count=0; var total=0;
	for (var t=0; t<tiddlers.length; t++) {
		if (!tiddlers[t].status || !tiddlers[t].status.trim().length) continue;
		if (tiddlers[t].status.substr(0,7)!='skipped') count++;
		total++;
	}
	// generate a report
	if (total) displayMessage(cmi.processedMsg.format([total]));
	if (count && config.options.chkImportReport) {
		// get/create the report tiddler
		var theReport = store.getTiddler('ImportedTiddlers');
		if (!theReport) { theReport=new Tiddler(); theReport.title='ImportedTiddlers'; theReport.text=''; }
		// format the report content
		var now = new Date();
		var newText = 'On '+now.toLocaleString()+', '+config.options.txtUserName
		newText +=' imported '+count+' tiddler'+(count==1?'':'s')+' from\n[['+cmi.src+'|'+cmi.src+']]:\n';
		if (cmi.addTags && cmi.newTags.trim().length)
			newText += 'imported tiddlers were tagged with: "'+cmi.newTags+'"\n';
		newText += '<<<\n';
		for (var t=0; t<tiddlers.length; t++) if (tiddlers[t].status)
			newText += '#[['+tiddlers[t].title+']] - '+tiddlers[t].status+'\n';
		newText += '<<<\n';
		// update the ImportedTiddlers content and show the tiddler
		theReport.text	 = newText+((theReport.text!='')?'\n----\n':'')+theReport.text;
		theReport.modifier = config.options.txtUserName;
		theReport.modified = new Date();
                store.saveTiddler(theReport.title, theReport.title, theReport.text, theReport.modifier, theReport.modified, theReport.tags, theReport.fields);
		story.displayTiddler(null,theReport.title,1,null,null,false);
		story.refreshTiddler(theReport.title,1,true);
	}
	// reset status flags
	for (var t=0; t<cmi.inbound.length; t++) cmi.inbound[t].status='';
	// mark document as dirty and let display update as needed
	if (count) { store.setDirty(true); store.notifyAll(); }
	// always show final message when tiddlers were actually loaded
	if (count) displayMessage(cmi.importedMsg.format([count,tiddlers.length,cmi.src.replace(/%20/g,' ')]));
}
//}}}
//{{{
// // File and XMLHttpRequest I/O
config.macros.importTiddlers.askForFilename=function(here) {
	var msg=here.title; // use tooltip as dialog box message
	var path=getLocalPath(document.location.href);
	var slashpos=path.lastIndexOf('/'); if (slashpos==-1) slashpos=path.lastIndexOf('\\'); 
	if (slashpos!=-1) path = path.substr(0,slashpos+1); // remove filename from path, leave the trailing slash
	var file='';
	var result='';
	if(window.Components) { // moz
		try {
			netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');

			var nsIFilePicker = window.Components.interfaces.nsIFilePicker;
			var picker = Components.classes['@mozilla.org/filepicker;1'].createInstance(nsIFilePicker);
			picker.init(window, msg, nsIFilePicker.modeOpen);
			var thispath = Components.classes['@mozilla.org/file/local;1'].createInstance(Components.interfaces.nsILocalFile);
			thispath.initWithPath(path);
			picker.displayDirectory=thispath;
			picker.defaultExtension='html';
			picker.defaultString=file;
			picker.appendFilters(nsIFilePicker.filterAll|nsIFilePicker.filterText|nsIFilePicker.filterHTML);
			if (picker.show()!=nsIFilePicker.returnCancel) var result=picker.file.path;
		}
		catch(e) { alert('error during local file access: '+e.toString()) }
	}
	else { // IE
		try { // XPSP2 IE only
			var s = new ActiveXObject('UserAccounts.CommonDialog');
			s.Filter='All files|*.*|Text files|*.txt|HTML files|*.htm;*.html|';
			s.FilterIndex=3; // default to HTML files;
			s.InitialDir=path;
			s.FileName=file;
			if (s.showOpen()) var result=s.FileName;
		}
		catch(e) {  // fallback
			var result=prompt(msg,path+file);
		}
	}
	return result;
}

config.macros.importTiddlers.loadRemoteFile = function(src,callback) {
	if (src==undefined || !src.length) return null; // filename is required
	var original=src; // URL as specified
	var hashpos=src.indexOf('#'); if (hashpos!=-1) src=src.substr(0,hashpos); // URL with #... suffix removed (needed for IE)
	clearMessage();
	displayMessage(this.openMsg.format([src.replace(/%20/g,' ')]));
	if (src.substr(0,5)!='http:' && src.substr(0,5)!='file:') { // if not a URL, read from local filesystem
		var txt=loadFile(src);
		if (!txt) { // file didn't load, might be relative path.. try fixup
			var pathPrefix=document.location.href;  // get current document path and trim off filename
			var slashpos=pathPrefix.lastIndexOf('/'); if (slashpos==-1) slashpos=pathPrefix.lastIndexOf('\\'); 
			if (slashpos!=-1 && slashpos!=pathPrefix.length-1) pathPrefix=pathPrefix.substr(0,slashpos+1);
			src=pathPrefix+src;
			if (pathPrefix.substr(0,5)!='http:') src=getLocalPath(src);
			var txt=loadFile(src);
		}
		if (!txt) { // file still didn't load, report error
			displayMessage(config.macros.importTiddlers.openErrMsg.format([src.replace(/%20/g,' '),'(filesystem error)']));
		} else {
			displayMessage(config.macros.importTiddlers.readMsg.format([txt.length,src.replace(/%20/g,' ')]));
			if (version.major+version.minor*.1+version.revision*.01!=2.52) txt=convertUTF8ToUnicode(txt);
			if (callback) callback(true,original,txt,src,null);
		}
	} else {
		doHttp('GET',src,null,null,config.options.txtRemoteUsername,config.options.txtRemotePassword,callback,original,null);
	}
}

config.macros.importTiddlers.readTiddlersFromHTML=function(html){
	var remoteStore=new TiddlyWiki();
	remoteStore.importTiddlyWiki(html);
	return remoteStore.getTiddlers('title');	
}

config.macros.importTiddlers.readTiddlersFromCSV=function(CSV){
	var remoteStore=new TiddlyWiki();
	// GET NAMES
	var lines=CSV.replace(/\r/g,'').split('\n');
	var names=lines.shift().replace(/"/g,'').split(',');
	CSV=lines.join('\n');
	// ENCODE commas and newlines within quoted values
	var comma='!~comma~!'; var commaRE=new RegExp(comma,'g');
	var newline='!~newline~!'; var newlineRE=new RegExp(newline,'g');
	CSV=CSV.replace(/"([^"]*?)"/g,
		function(x){ return x.replace(/\,/g,comma).replace(/\n/g,newline); });
	// PARSE lines
	var lines=CSV.split('\n');
	for (var i=0; i<lines.length; i++) { if (!lines[i].length) continue;
		var values=lines[i].split(',');
		// DECODE commas, newlines, and doubled-quotes, and remove enclosing quotes (if any)
		for (var v=0; v<values.length; v++)
			values[v]=values[v].replace(commaRE,',').replace(newlineRE,'\n')
				.replace(/^"|"$/g,'').replace(/""/g,'"');
		// EXTRACT tiddler values
		var title=''; var text=''; var tags=[]; var fields={};
		var created=null; var when=new Date(); var who=config.options.txtUserName;
		for (var v=0; v<values.length; v++) { var val=values[v];
			if (names[v]) switch(names[v].toLowerCase()) {
				case 'title':	title=val.replace(/\[\]\|/g,'_'); break;
				case 'created': created=new Date(val); break;
				case 'modified':when=new Date(val); break;
				case 'modifier':who=val; break;
				case 'text':	text=val; break;
				case 'tags':	tags=val.readBracketedList(); break;
				default:	fields[names[v].toLowerCase()]=val; break;
			}
		}
		// CREATE tiddler in temporary store
		if (title.length)
			remoteStore.saveTiddler(title,title,text,who,when,tags,fields,true,created||when);
	}
	return remoteStore.getTiddlers('title');
}

config.macros.importTiddlers.createTiddlerFromFile=function(src,txt) {
	var t=new Tiddler();
	var pos=src.lastIndexOf("/"); if (pos==-1) pos=src.lastIndexOf("\\");
	t.title=pos==-1?src:src.substr(pos+1);
	t.text=txt; 
	t.created=t.modified=new Date();
	t.modifier=config.options.txtUserName;
	if (src.substr(src.length-3,3)=='.js') t.tags=['systemConfig'];
	return [t];
}

config.macros.importTiddlers.filterTiddlerList=function(success,params,txt,src,xhr){
	var cmi=config.macros.importTiddlers; // abbreviation
	var src=src.replace(/%20/g,' ');
	if (!success) { displayMessage(cmi.openErrMsg.format([src,xhr.status])); return; }
	cmi.all=cmi.readTiddlersFromHTML(txt);
	if (!cmi.all||!cmi.all.length) cmi.all=cmi.readTiddlersFromCSV(txt)
	if (!cmi.all||!cmi.all.length) cmi.all=cmi.createTiddlerFromFile(src,txt)
	var count=cmi.all?cmi.all.length:0;
	var querypos=src.lastIndexOf('?'); if (querypos!=-1) src=src.substr(0,querypos);
	displayMessage(cmi.foundMsg.format([count,src]));
	cmi.inbound=cmi.filterByHash(params,cmi.all); // use full URL including hash (if any)
	cmi.$('importLastFilter').value=cmi.lastFilter;
	window.refreshImportList(0);
}

config.macros.importTiddlers.filterByHash=function(src,tiddlers){
	var hashpos=src.lastIndexOf('#'); if (hashpos==-1) return tiddlers;
	var hash=src.substr(hashpos+1); if (!hash.length) return tiddlers;
	var tids=[];
	var params=hash.parseParams('anon',null,true,false,false);
	for (var p=1; p<params.length; p++) {
		switch (params[p].name) {
			case 'anon':
			case 'open':
				tids.pushUnique(params[p].value);
				break;
			case 'tag':
				if (store.getMatchingTiddlers) { // for boolean expressions - see MatchTagsPlugin
					var r=store.getMatchingTiddlers(params[p].value,null,tiddlers);
					for (var t=0; t<r.length; t++) tids.pushUnique(r[t].title);
				} else for (var t=0; t<tiddlers.length; t++)
					if (tiddlers[t].isTagged(params[p].value))
						tids.pushUnique(tiddlers[t].title);
				break;
			case 'story':
				for (var t=0; t<tiddlers.length; t++)
					if (tiddlers[t].title==params[p].value) {
						tiddlers[t].changed();
						for (var s=0; s<tiddlers[t].links.length; s++)
							tids.pushUnique(tiddlers[t].links[s]);
						break;
					}
				break;
			case 'search':
				for (var t=0; t<tiddlers.length; t++)
					if (tiddlers[t].text.indexOf(params[p].value)!=-1)
						tids.pushUnique(tiddlers[t].title);
				break;
		}
	}
	var matches=[];
	for (var t=0; t<tiddlers.length; t++)
		if (tids.contains(tiddlers[t].title))
			matches.push(tiddlers[t]);
	displayMessage(config.macros.importTiddlers.filterMsg.format([matches.length,hash]));
	config.macros.importTiddlers.lastFilter=hash;
	return matches;
}
//}}}
/***
!!!Control panel CSS
//{{{
!css
#importPanel {
	display: none; position:absolute; z-index:11; width:35em; right:105%; top:3em;
	background-color: #eee; color:#000; font-size: 8pt; line-height:110%;
	border:1px solid black; border-bottom-width: 3px; border-right-width: 3px;
	padding: 0.5em; margin:0em; -moz-border-radius:1em;-webkit-border-radius:1em;
}
#importPanel a, #importPanel td a { color:#009; display:inline; margin:0px; padding:1px; }
#importPanel table { width:100%; border:0px; padding:0px; margin:0px; font-size:8pt; line-height:110%; background:transparent; }
#importPanel tr { border:0px;padding:0px;margin:0px; background:transparent; }
#importPanel td { color:#000; border:0px;padding:0px;margin:0px; background:transparent; }
#importPanel select { width:100%;margin:0px;font-size:8pt;line-height:110%;}
#importPanel input  { width:98%;padding:0px;margin:0px;font-size:8pt;line-height:110%}
#importPanel .box { border:1px solid #000; background-color:#eee; padding:3px 5px; margin-bottom:5px; -moz-border-radius:5px;-webkit-border-radius:5px;}
#importPanel .topline { border-top:1px solid #999; padding-top:2px; margin-top:2px; }
#importPanel .rad { width:auto; }
#importPanel .chk { width:auto; margin:1px;border:0; }
#importPanel .btn { width:auto; }
#importPanel .btn1 { width:98%; }
#importPanel .btn2 { width:48%; }
#importPanel .btn3 { width:32%; }
#importPanel .btn4 { width:23%; }
#importPanel .btn5 { width:19%; }
#importPanel .importButton { padding: 0em; margin: 0px; font-size:8pt; }
#importPanel .importListButton { padding:0em 0.25em 0em 0.25em; color: #000000; display:inline }
#backstagePanel #importPanel { left:10%; right:auto; }
!end
//}}}
!!!Control panel HTML
//{{{
!html
<!-- source and report -->
<table><tr><td align=left>
	import from
	<input type="radio" class="rad" name="importFrom" id="importFromFile" value="file" CHECKED
		onclick="onClickImportButton(this,event)" title="show file controls"> local file
	<input type="radio" class="rad" name="importFrom" id="importFromWeb"  value="http"
		onclick="onClickImportButton(this,event)" title="show web controls"> web server
</td><td align=right>
	<input type=checkbox class="chk" id="chkImportReport"
		onClick="config.options['chkImportReport']=this.checked;"> create report
</td></tr></table>

<div class="box" id="importSourcePanel" style="margin:.5em">
<div id="importLocalPanel" style="display:block;margin-bottom:2px;"><!-- import from local file  -->
enter or browse for source path/filename<br>
<input type="file" id="fileImportSource" size=57 style="width:100%"
	onKeyUp="config.macros.importTiddlers.src=this.value"
	onChange="config.macros.importTiddlers.src=this.value;document.getElementById('importLoad').onclick()">
<div id="importLocalPanelFix" style="display:none"><!-- FF3 FIXUP -->
	<input type="text" id="fileImportSourceFix" style="width:90%"
		title="Enter a path/file to import"
		onKeyUp="config.macros.importTiddlers.src=this.value"
		onChange="config.macros.importTiddlers.src=this.value;document.getElementById('importLoad').onclick()">
	<input type="button" id="fileImportSourceFixButton" style="width:7%" value="..."
		title="Select a path/file to import"
		onClick="var r=config.macros.importTiddlers.askForFilename(this); if (!r||!r.length) return;
			document.getElementById('fileImportSourceFix').value=r;
			config.macros.importTiddlers.src=r;
			document.getElementById('importLoad').onclick()">
</div><!--end FF3 FIXUP-->
</div><!--end local-->
<div id="importHTTPPanel" style="display:none;margin-bottom:2px;"><!-- import from http server -->
<table><tr><td align=left>
	enter a URL or <a href="javascript:;" id="importSelectFeed"
		onclick="return onClickImportButton(this,event)" title="select a pre-defined 'systemServer' URL">
		select a server</a><br>
</td><td align=right>
	<input type="checkbox" class="chk" id="importUsePassword"
		onClick="config.macros.importTiddlers.usePassword=this.checked;
			config.macros.importTiddlers.showPanel('importIDPWPanel',this.checked,true);">password
	<input type="checkbox" class="chk" id="importUseProxy"
		onClick="config.macros.importTiddlers.useProxy=this.checked;
			config.macros.importTiddlers.showPanel('importSiteProxy',this.checked,true);">proxy
</td></tr></table>
<input type="text" id="importSiteProxy" style="display:none;margin-bottom:1px" onfocus="this.select()" value="SiteProxy"
	onKeyUp="config.macros.importTiddlers.proxy=this.value"
	onChange="config.macros.importTiddlers.proxy=this.value;">
<input type="text" id="importSourceURL" onfocus="this.select()" value="SiteUrl"
	onKeyUp="config.macros.importTiddlers.src=this.value"
	onChange="config.macros.importTiddlers.src=this.value;">
<div id="importIDPWPanel" style="text-align:center;margin-top:2px;display:none";>
username: <input type=text id="txtImportID" style="width:25%" 
	onChange="config.options.txtRemoteUsername=this.value;">
 password: <input type=password id="txtImportPW" style="width:25%" 
	onChange="config.options.txtRemotePassword=this.value;">
</div><!--end idpw-->
</div><!--end http-->
</div><!--end source-->

<div class="box" id="importSelectPanel" style="display:none;margin:.5em;">
<table><tr><td align=left>
select:
<a href="javascript:;" id="importSelectAll"
	onclick="return onClickImportButton(this)" title="SELECT all tiddlers">
	all</a>
&nbsp;<a href="javascript:;" id="importSelectNew"
	onclick="return onClickImportButton(this)" title="SELECT tiddlers not already in destination document">
	added</a>
&nbsp;<a href="javascript:;" id="importSelectChanges"
	onclick="return onClickImportButton(this)" title="SELECT tiddlers that have been updated in source document">
	changes</a>
&nbsp;<a href="javascript:;" id="importSelectDifferences"
	onclick="return onClickImportButton(this)" title="SELECT tiddlers that have been added or are different from existing tiddlers">
	differences</a>
</td><td align=right>
<a href="javascript:;" id="importListSmaller"
	onclick="return onClickImportButton(this)" title="SHRINK list size">
	&nbsp;&#150;&nbsp;</a>
<a href="javascript:;" id="importListLarger"
	onclick="return onClickImportButton(this)" title="GROW list size">
	&nbsp;+&nbsp;</a>
<a href="javascript:;" id="importListMaximize"
	onclick="return onClickImportButton(this)" title="MAXIMIZE/RESTORE list size">
	&nbsp;=&nbsp;</a>
</td></tr></table>
<select id="importList" size=8 multiple
	onchange="setTimeout('refreshImportList('+this.selectedIndex+')',1)">
	<!-- NOTE: delay refresh so list is updated AFTER onchange event is handled -->
</select>
<div style="text-align:center">
	<a href="javascript:;"
		title="click for help using filters..."
		onclick="alert('A filter consists of one or more space-separated combinations of: tiddlertitle, tag:[[tagvalue]], tag:[[tag expression]] (requires MatchTagsPlugin), story:[[TiddlerName]], and/or search:[[searchtext]]. Use a blank filter to restore the list of all tiddlers.'); return false;"
	>filter</a>
	<input type="text" id="importLastFilter" style="margin-bottom:1px; width:65%"
		title="Enter a combination of one or more filters. Use a blank filter for all tiddlers."
		onfocus="this.select()" value=""
		onKeyUp="config.macros.importTiddlers.lastFilter=this.value"
		onChange="config.macros.importTiddlers.lastFilter=this.value;">
	<input type="button" id="importApplyFilter" style="width:20%" value="apply"
		title="filter list of tiddlers to include only those that match certain criteria"
		onclick="return onClickImportButton(this)">
	</div>
</div><!--end select-->

<div class="box" id="importOptionsPanel" style="text-align:center;margin:.5em;display:none;">
	apply tags: <input type=checkbox class="chk" id="chkImportTags" checked
		onClick="config.macros.importTiddlers.importTags=this.checked;">from source&nbsp;
	<input type=checkbox class="chk" id="chkKeepTags" checked
		onClick="config.macros.importTiddlers.keepTags=this.checked;">keep existing&nbsp;
	<input type=checkbox class="chk" id="chkAddTags" 
		onClick="config.macros.importTiddlers.addTags=this.checked;
			config.macros.importTiddlers.showPanel('txtNewTags',this.checked,false);
			if (this.checked) document.getElementById('txtNewTags').focus();">add tags<br>
	<input type=text id="txtNewTags" style="margin-top:4px;display:none;" size=15 onfocus="this.select()" 
		title="enter tags to be added to imported tiddlers" 
		onKeyUp="config.macros.importTiddlers.newTags=this.value;
		document.getElementById('chkAddTags').checked=this.value.length>0;" autocomplete=off>
	<nobr><input type=checkbox class="chk" id="chkSync" 
		onClick="config.macros.importTiddlers.sync=this.checked;">
		link tiddlers to source document (for sync later)</nobr>
</div><!--end options-->

<div id="importButtonPanel" style="text-align:center">
	<input type=button id="importLoad"	class="importButton btn3" value="open"
		title="load listbox with tiddlers from source document"
		onclick="onClickImportButton(this)">
	<input type=button id="importOptions"	class="importButton btn3" value="options..."
		title="set options for tags, sync, etc."
		onclick="onClickImportButton(this)">
	<input type=button id="importStart"	class="importButton btn3" value="import"
		title="start/stop import of selected source tiddlers into current document"
		onclick="onClickImportButton(this)">
	<input type=button id="importClose"	class="importButton btn3" value="done"
		title="clear listbox or hide control panel"
		onclick="onClickImportButton(this)">
</div>

<div class="none" id="importCollisionPanel" style="display:none;margin:.5em 0 .5em .5em;">
	<table><tr><td style="width:65%" align="left">
		<table><tr><td align=left>
			tiddler already exists:
		</td><td align=right>
			<input type=checkbox class="chk" id="importApplyToAll" 
			onclick="document.getElementById('importRename').disabled=this.checked;"
			checked>apply to all
		</td></tr></table>
		<input type=text id="importNewTitle" size=15 autocomplete=off">
	</td><td style="width:34%" align="center">
		<input type=button id="importMerge"
			class="importButton" style="width:47%" value="merge"
			title="append the incoming tiddler to the existing tiddler"
			onclick="onClickImportButton(this)"><!--
		--><input type=button id="importSkip"
			class="importButton" style="width:47%" value="skip"
			title="do not import this tiddler"
			onclick="onClickImportButton(this)"><!--
		--><br><input type=button id="importRename"
			class="importButton" style="width:47%" value="rename"
			title="rename the incoming tiddler"
			onclick="onClickImportButton(this)"><!--
		--><input type=button id="importReplace"
			class="importButton" style="width:47%" value="replace"
			title="discard the existing tiddler"
			onclick="onClickImportButton(this)">
	</td></tr></table>
</div><!--end collision-->
!end
//}}}
***/
/***
|Name|ImportTiddlersPluginInfo|
|Source|http://www.TiddlyTools.com/#ImportTiddlersPlugin|
|Documentation|http://www.TiddlyTools.com/#ImportTiddlersPluginInfo|
|Version|4.6.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|documentation|
|Description|documentation for ImportTiddlersPlugin|
Combine tiddlers from any two TiddlyWiki documents.  An interactive control panel lets you pick a source document and import selected tiddlers, with prompting for skip, rename, merge or replace actions when importing tiddlers that match existing titles.  Generates a detailed report of import 'history' in ImportedTiddlers.
!!!!!Usage
<<<
{{{<<importTiddlers>>}}} or {{{<<importTiddlers core>>}}}
invokes the built-in importTiddlers macro (TW2.1.x+).  If installed in documents using TW2.0.x or earlier, fallback is to use 'link' display (see below)

{{{<<importTiddlers link label tooltip>>}}}
The ''link'' keyword creates an "import tiddlers" link that when clicked to show/hide import control panel.  ''label'' and ''tooltip'' are optional text parameters (enclosed in quotes or {{{[[...]]}}}, and allow you to override the default display text for the link and the mouseover help text, respectively.

{{{<<importTiddlers inline>>}}}
creates import control panel directly in tiddler content

<<importTiddlers inline>>

Enter a document URL or press "..." to select a TiddlyWiki file to import, and then press ''[open]''.  //Note: There may be a delay before the list of tiddlers appears.//  Use the ''[-]'', ''[+]'', or ''[=]'' links to adjust the listbox size so you can view more (or less) tiddler titles at one time.

Select one or more titles from the listbox.  Use CTRL-click or SHIFT-click to select/deselect individual titles.  Click on ''all'', ''new'', ''changes'', or ''differences'' to automatically select a subset of tiddlers from the list, based on a comparison of the two documents:
*''all'' selects ALL tiddlers from the import source document, even if they have not been changed.
*''new'' selects only tiddlers that are found in the import source document, but do not yet exist in the destination document
*''changes'' selects only tiddlers that exist in both documents but that are newer in the source document
*''differences'' selects all new and existing tiddlers that are different from the destination document (even if destination tiddler is newer)

Press ''[import]'' to begin copying tiddlers to the current document.  If an 'inbound' tiddler matches one that already exists in the document, the import process pauses and the tiddler title is displayed in an input field, along with four push buttons: ''skip'', ''rename'', ''merge'' and ''replace''.
* to bypass importing the tiddler, press ''skip''
* to give the inbound tiddler a different name, so that both the old and new tiddlers will exist when the import is done, enter a new title in the input field and press ''rename'' 
* to combine the content from both tiddlers into a single tiddler so you can then edit it later to eliminate unwanted content, press ''merge''
* to overwrite the existing tiddler with the imported one (discarding the previous content), press ''[replace]''

''Import Report History''

Whenever tiddlers are imported, a report is generated into a tiddler named [[ImportedTiddlers]], recording when the latest import was performed, the number of tiddlers successfully imported, from what location, and by whom, as well as a list of the tiddlers that were processed.  When more tiddlers are imported at a later time, a new report is //added// to the existing [[ImportedTiddlers]], above the previous report (i.e., at the top of the tiddler), so that a history of imports is maintained.  If this record is not desired, you can delete [[ImportedTiddlers]] at any time.

Note: You can prevent a report from being generated for any given import activity by clearing the "create a report" checkbox before pressing the ''import'' button
<<<
!!!!!Installation Notes
<<<
* As of 6/27/2007, support for TW2.1.x and earlier have been moved to [[ImportTiddlersPluginPatch]].  ''//Only install the patch plugin when using TW2.1.x or earlier.//''
<<<
!!!!!Revisions
<<<
2009.10.06 4.6.0 added createTiddlerFromFile (import text files)
2009.09.27 4.5.5 in readTiddlersFromCSV(), strip \r from input and fixed handling for quoted values
2009.09.12 4.5.4 fixed 'return false' to prevent IE page transition. Also, moved html/css definitions to separate sections
2009.08.23 4.5.3 in importTiddlers(), add 'file:///' to local server.host sync field only if not already present in URL
2009.08.20 4.5.2 only use SiteURL/SiteProxy values if control panel value has not yet been set
2009.07.03 4.5.1 fixups for TW252: doHttp() doesn't return XHR and convertUTF8ToUnicode() not needed for local I/O
2009.05.04 4.5.0 import from CSV-formatted files
2009.03.04 4.4.2 in createImportPanel(), init option checkboxes so display matches internal state variables
2009.02.26 4.4.1 use macro-specific definition of $() function abbreviation (avoids conflict with JQuery)
2008.09.30 4.4.0 added fallback definition of merge() for use with TW2.0.x and TW1.2.x
2008.08.12 4.3.3 rewrite backstage and shadow tiddler definitions for easier customization
2008.08.05 4.3.2 rewrote loadRemoteFile() to eliminate use of platform-specific fileExists() function
2008.06.29 4.3.1 More layout/animation work for simpler sequential interaction.  Code reduction/cleanup
2008.06.28 4.3.0 HTML and CSS cleanup and tweaks to layout.  Added animation to panels
2008.06.22 4.2.0 For FireFox, use HTML with separate text+button control instead of type='file' control
2008.06.05 4.1.0 in filterByHash(), added support for boolean tag expressions using getMatchingTiddlers() (defined by MatchTagsPlugin)
2008.05.12 4.0.2 automatically tweak the backstage "import" task to add the ImportTiddlers control panel
2008.04.30 4.0.1 trim #... suffix for loading files/URLs in IE
2008.04.30 4.0.0 added source filtering (using URL paramifiers).  Also, abbreviations for code-size reduction.
2008.04.13 3.9.0 added 'apply to all' checkbox for collision processing
2008.03.26 3.8.0 added support for selecting pre-defined systemServer URLs
2008.03.25 3.7.0 added support for setting 'server' fields on imported tiddlers (for later synchronizing of changes)
2008.01.03 3.6.0 in loadRemoteFile(), use lower-level doHttp() instead of loadRemoteFile() in order to support username/password access to remote server
2007.10.30 3.5.6 update [[ImportTiddlers]] shadow tiddler definition to include "inline" link
2007.06.27 3.5.5 added missing 'fields' params to saveTiddler() calls.  Fixes problem where importing tiddlers would lose the custom fields.  Also, moved functions for TW2.1.x to [[ImportTiddlersPluginPatch2.1.x]].
2007.06.25 3.5.4 added calls to store.suspendNotifications() and store.resumeNotifications().  Eliminates redisplay processing overhead DURING import activities
2007.04.29 3.5.3 in refreshImportList() when inbound tiddlers are loaded, change "close" button to "done", and disable certain controls to creates a modal condition, so that actions that reload tiddlers cannot be performed unless "done" is first pressed to end the mode..
2007.04.28 3.5.2 in handler(), added param support for custom link label/prompt
2007.04.19 3.5.1 in readTiddlersFromHTML(), for TW2.2 and above, use importTiddlyWiki() (new core functionality) to get tiddlers from remote file content.  Also, copied updated TW21Loader.prototype.internalizeTiddler() definition from TW2.2b5 so plugin can read tiddlers from TW2.2+ even when running under TW2.1.x
2007.03.22 3.5.0 in refreshImportList(), add handling for 'select section' when a heading is selected.  Makes it really easy to import by tag or date!
2007.03.21 3.4.0 split loadTiddlers functionality into separate plugin (see [[LoadTiddlersPlugin]])
2007.03.20 3.3.1 tweak to previous change to allow relative file references via http: (bypasses getLocalPath() so remote URL will be used)
2007.03.20 3.3.0 added support for local, relative file references: in loadRemoteFile(), check for fileExists().  If not found, prepend relative path and retry.
2007.02.24 3.2.1 re-labeled control panel "open" button to "load"
2007.02.09 3.2.0 loadTiddlers: added support for "noReload" tag (prevents overwriting existing tiddler, even if inbound tiddler is newer)
2007.02.08 3.1.3 loadTiddlers: added missing code and documentation for "newTags" handling (a feature change from long, long ago that somehow got lost!)
2006.11.14 3.1.2 fix macro handler parameter declaration (double-pasted param list corrupts IE)
2006.11.13 3.1.1 use apply() method to invoke hijacked core handler
2006.11.13 3.1.0 hijack built-in importTiddlers.handler() to co-exist with plugin interface.  If no params or 'core' keyword, display core interface.  "link" param embeds "import tiddlers" link that shows floating panel when clicked.
2006.10.12 3.0.8 in readTiddlersFromHTML(), fallback to find end of store area by matching "/body" when POST-BODY-START is not present (backward compatibility for older documents)
2006.09.10 3.0.7 in readTiddlersFromHTML(), find end of store area by matching "POST-BODY-START" instead of "/body" 
2006.08.16 3.0.6 Use higher-level store.saveTiddler() instead of store.addTiddler() to avoid conflicts with adaptations that hijack low-level tiddler handling.  in CreateImportPanel(), removed "refresh listbox after every tiddler change".
2006.07.29 3.0.5 added noChangeMsg to loadTiddlers processing.  if not 'quiet' mode, reports skipped tiddlers.
2006.04.18 3.0.4 in loadTiddlers.handler, fixed parsing of "prompt:" param. Also, corrected parameters mismatch in loadTiddlers() callback function definition (order of params was wrong, resulting in filters NOT being applied)
2006.04.12 3.0.3 moved many display messages to macro properties for easier L10N translations via 'lingo' definitions.
2006.04.12 3.0.2 more work on 'core candidate' code.  Proposed API now defines "loadRemoteFile()" for XMLHttpRequest processing with built in fallback for handling local filesystem access, and readTiddlersFromHTML() to process the resulting source HTML content.
2006.04.04 3.0.1 in refreshImportList(), when using [by tags], tiddlers without tags are now included in a new "untagged" psuedo-tag list section
2006.04.04 3.0.0 Separate non-interactive {{{<<importTiddlers...>>}}} macro functionality for incorporation into TW2.1 core and renamed as {{{<<loadTiddlers>>}}} macro.  New parameters for loadTiddlers: ''label:text'' and ''prompt:text'' for link creation,  ''ask'' for filename/URL, ''tag:text'' for filtering, "confirm" for accept/reject of individual inbound tiddlers.  Removed support for "importReplace/importPublic" tags and "force" param (unused feature). 
2006.03.30 2.9.1 when extracting store area from remote URL, look for "</body>" instead of "</body>\n</html>" so it will match even if the "\n" is absent from the source.
2006.03.30 2.9.0 added optional 'force' macro param.  When present, autoImportTiddlers() bypasses the checks for importPublic and importReplace.  Based on a request from Tom Otvos.
2006.03.28 2.8.1 in loadImportFile(), added checks to see if 'netscape' and 'x.overrideMimeType()' are defined (not in IE). Also, when extracting store area, look for "</body>\n</html>" and omit extra content that may have been added to the end of the file.
2006.02.21 2.8.0 added support for "tiddler:TiddlerName" filtering parameter in auto-import processing
2006.02.21 2.7.1 Clean up layout problems with IE.  (Use tables for alignment instead of SPANs styled with float:left and float:right)
2006.02.21 2.7.0 Added "local file" and "web server" radio buttons.  Default remote URL uses value from [[SiteURL]].  Also, added 'proxy' option, using value from [[SiteProxy]] as prefix to permit cross-domain document access via server-side scripting.
2006.02.17 2.6.0 Removed "differences only" listbox display mode, replaced with selection filter 'presets': all/new/changes/differences.  fixed init of "add new tags" checkbox
2006.02.16 2.5.4 added checkbox options to control "import remote tags" and "keep existing tags" behavior, in addition to existing "add new tags" functionality.
2006.02.14 2.5.3 FF1501 corrected unintended global 't' (loop index) in importReport() and autoImportTiddlers()
2006.02.10 2.5.2 corrected unintended global variable in importReport().
2006.02.05 2.5.1 moved globals from window.* to config.macros.importTiddlers.* to avoid FireFox 1.5.0.1 crash bug when referencing globals
2006.01.18 2.5.0 added checkbox for "create a report".  Default is to create/update the ImportedTiddlers report.
2006.01.15 2.4.1 added "importPublic" tag and inverted default so that auto sharing is NOT done unless tagged with importPublic
2006.01.15 2.4.0 Added support for tagging tiddlers with importSkip, importReplace, and/or importPrivate to enable/disable overwriting or sharing with others when using auto-import macro syntax.  Defaults: don't overwrite existing tiddlers, and allow your tiddlers to be auto-imported by others.
2006.01.15 2.3.2 Added "ask" parameter to confirm each tiddler before importing (for use with auto-importing)
2006.01.15 2.3.1 Strip TW core scripts from import source content and load just the storeArea into the hidden IFRAME to prevent imported document's core code from being invoked.  Also, when importing local documents, use convertUTF8ToUnicode() to support international characters sets.
2006.01.12 2.3.0 Reorganized code to use callback function for loading import files to support event-driven I/O via an ASYNCHRONOUS XMLHttpRequest instead of waiting for remote hosts to respond to URL requests.  Added non-interactive 'batch' mode, using macro parameters to specify source path/file or URL, and select tiddlers to import.  Improved messages and added optional 'quiet' switch for batch mode to eliminate //most// feedback.
2006.01.11 2.2.0 Added "[by tags]" to list of tiddlers, based on code submitted by BradleyMeck
2006.01.08 2.1.0 IMPORT FROM ANYWHERE!!! re-write getImportedTiddlers() logic to either read a local file (using local I/O), OR... read a remote file, using a combination of XML and an iframe to permit cross-domain reading of DOM elements.  Adapted from example code and techniques courtesy of Jonny LeRoy.
2006.01.06 2.0.2 When refreshing list contents, fixed check for tiddlerExists() when "show differences only" is selected, so that imported tiddlers that don't exist in the current file will be recognized as differences and included in the list.
2006.01.04 2.0.1 When "show differences only" is NOT checked, import all tiddlers that have been selected even when they have a matching title and date.
2005.12.27 2.0.0 Update for TW2.0
Defer initial panel creation and only register a notification function when panel first is created
2005.12.22 1.3.1 tweak formatting in importReport() and add 'discard report' link to output
2005.12.03 1.3.0 Dynamically create/remove importPanel as needed to ensure only one instance of interface elements exists, even if there are multiple instances of macro embedding.  Also, dynamically create/recreate importFrame each time an external TW document is loaded for importation (reduces DOM overhead and ensures a 'fresh' frame for each document)
2005.11.29 1.2.1 fixed formatting of 'detail info' in importReport()
2005.11.11 1.2.0 added 'inline' param to embed controls in a tiddler
2005.11.09 1.1.0 only load HTML and CSS the first time the macro handler is called.  Allows for redundant placement of the macro without creating multiple instances of controls with the same ID's.
2005.10.25 1.0.5 fixed typo in importReport() that prevented reports from being generated
2005.10.09 1.0.4 combined documentation with plugin code instead of using separate tiddlers
2005.08.05 1.0.3 moved CSS and HTML definitions into plugin code instead of using separate tiddlers
2005.07.27 1.0.2 core update 1.2.29: custom overlayStyleSheet() replaced with new core setStylesheet()
2005.07.23 1.0.1 added parameter checks and corrected addNotification() usage
2005.07.20 1.0.0 Initial Release
<<<
/***
|Name|[[InfoboxTablesPlugin]]|
|Source|http://infoboxes.tiddlyspot.com|
|Documentation|[[InfoboxTablesPluginInfo]]|
|Version|2.2.2|
|Author|Kristjan Brezovnik|
|License|[[Creative Commons Attribution-Share Alike 3.0 License|http://creativecommons.org/licenses/by-sa/3.0/]]|
|~CoreVersion|2.6.3|
|Requires||
|Type|plugin|
|Description|Provides customizable infoboxes for different types of articles.|

!Configuration
<<option chkHideInfoboxes>> Hide the infoboxes when opening a tiddler
<<option chkSaveMode>> When editing the table, save the macro so each parameter is in its own line (default) or so that the entire macro is a single line
<<option chkSavePrompt>> Prompt if you really want to save

!Code
***/
//{{{
//Ensure that the plugin is only installed once
if (!version.extensions.InfoboxTablesPlugin) {
version.extensions.InfoboxTablesPlugin = {installed: true};
version.extensions.InfoboxTablesPlugin = {major: 2, minor: 2, revision: 1, date: new Date(2013,4,22)};
//}}}

/***
!!Generic Color Palette
***/
//{{{
var palette = store.getTiddler("InfoboxTablesColorPalette");
if (palette === null) {
config.shadowTiddlers.InfoboxTablesColorPalette = 
"/***\nGeneric Color Palette\n***/\n/*{{{*/\n" + 
"InfoboxTableBackground: whitesmoke\n" + 
"InfoboxTableTopColor: whitesmoke\n" + 
"InfoboxTypeError: red\n" + 
"/*}}}*/\n/***\nTemplate-Specific Color Palette\n***/\n/*{{{*/\n";
}
//}}}

/***
!!Generic Stylesheet
***/
//{{{
var stylesheet = store.getTiddler("InfoboxTablesStylesheet");
if (stylesheet === null) {
config.shadowTiddlers.InfoboxTablesStylesheet = 
"/***\nGeneric Stylesheet\n***/\n/*{{{*/\n" + 
".InfoboxTable {width: 300px !important; margin: 0px 1px !important; border-collapse: separate !important; border: none 0px !important; border-spacing: 0px !important;}\n" + 
".InfoboxTableHeader, .InfoboxTableFooter {width: 300px !important; font-size: 10px; font-weight: bold; background: [[InfoboxTablesColorPalette::InfoboxTableBackground]];}\n" + 
".InfoboxTableHeader {border-radius: 10px 10px 0px 0px; -moz-border-radius: 10px 10px 0px 0px; -webkit-border-radius: 10px 10px 0px 0px;} /* Header table */\n" + 
".InfoboxTableFooter {border-radius: 0px 0px 10px 10px; -moz-border-radius: 0px 0px 10px 10px; -webkit-border-radius: 0px 0px 10px 10px;} /* Footer table */\n" + 
".InfoboxTableTop, .InfoboxTableBottom {width: 300px !important; border: none 0px; text-align: center; font-size: 16px; line-height: 120%;}\n" + 
".InfoboxTableTop {font-size: 14px; line-height: 120%; border-radius: 10px 10px 0px 0px; -moz-border-radius: 10px 10px 0px 0px; -webkit-border-radius: 10px 10px 0px 0px;} /* Header row */\n" + 
".InfoboxTableBottom {line-height: 80%; border-radius: 0px 0px 10px 10px; -moz-border-radius: 0px 0px 10px 10px; -webkit-border-radius: 0px 0px 10px 10px;} /* Footer row */\n" + 
".InfoboxSection {width: 300px !important; border: none 0px; font-weight: bold;} /* Section header row */\n" + 
".InfoboxRow {display: table-row;} /* Content row */\n" + 
".InfoboxCellLeft, .InfoboxCellRight, .InfoboxCellEqual, .InfoboxCellImage {border: 1px solid; vertical-align: top !important; background: [[InfoboxTablesColorPalette::InfoboxTableBackground]]; word-wrap: break-word !important; word-break: hyphenate !important;}\n" + 
".InfoboxCellLeft {width: 100px !important; max-width: 90px !important;}\n" + 
".InfoboxCellRight {width: 200px !important; max-width: 190px !important;}\n" + 
".InfoboxCellEqual {width: 150px !important; max-width: 140px !important;}\n" + 
".InfoboxCellImage, .InfoboxCellSingle {width: 300px !important;}\n" + 
".InfoboxCellImage {text-align: center;}\n" + 
".InfoboxCellSingle {text-align: left;}\n" + 
"img.InfoboxImage {max-width: 290px !important;} /* Image max width must be less than cell width */\n" + 
".InfoboxOuterDiv, .InfoboxInnerDiv {display: block; position: relative; float: right; clear: both;}\n" + 
".SmallButton {display: inline; position: relative; float: right;}\n" + 
".InfoboxOuterDiv {z-index: 10; padding: 0.5em; margin: 0px;}\n" + 
".InfoboxOuterDivCommand, .InfoboxInnerDivCommand {display: inline-block; position: relative; clear: both;}\n" + 
".SmallButton {border: 1px solid black!important; background: [[InfoboxTablesColorPalette::InfoboxTableBackground]]!important; padding: 1px; margin: 1px;}\n" + 
".SmallButton, .SmallText,.InfoboxCellLeft, .InfoboxCellRight, .InfoboxCellEqual, .InfoboxCellImage, .InfoboxSection {font-size: 10px; line-height: 120%;}\n" + 
".InfoboxNoInfo {display: none; width: 300px !important; font-weight: bold; border: solid 2px; border-radius: 5px; -moz-border-radius: 5px; -webkit-border-radius: 5px; padding: 5px 5px;} /* No Info */\n" + 
".InfoboxError {width: 300px !important; font-weight: bold; border-radius: 5px; -moz-border-radius: 5px; -webkit-border-radius: 5px; padding: 5px 5px; float: right;} /* Error */\n" + 
".InfoboxTypeError {width: 300px; background: [[InfoboxTablesColorPalette::InfoboxTypeError]]; font-weight: bold; border: solid 5px; border-radius: 5px; -moz-border-radius: 5px; -webkit-border-radius: 5px; padding: 5px 5px; float: right;} /* Type Error */\n" + 
".TypeErrorEditMode {background: [[InfoboxTablesColorPalette::InfoboxTypeError]];}\n" + 
".InfoboxEditTextarea {height: 20px; width: 99% !important; border: 1px solid black !important; padding: 0px !important; margin: 0px !important; overflow: auto; overflow-y: scroll !important; resize: vertical !important;} /* Textarea on the edit panel*/\n" + 
".InfoboxEditTextareaOnfocus {height: 200px; width: 97% !important;}\n" + 
".InfoboxEditTextareaOnblur {height: 16px; width: 97% !important;}\n" + 
".EqualEditParamName {display: none;}\n" + 
".EditComment {display: none;}\n" + 
"/*}}}*/\n/***\nTemplate-Specific Stylesheet\n***/\n/*{{{*/\n";
store.addNotification("InfoboxTablesStylesheet", refreshStyles);
}
//}}}

/***
!!Template-Specific Color Palette, Stylesheet
***/
//{{{
var list = store.getTaggedTiddlers("infobox");
var listTitle, listColors, listColorsText, listColorsTitle, listColorsSubtitle, paramListInfo, paramListInfoParsed;
var i, j;
var validTypes = "";
for (i = 0; i < list.length; i++) {
listTitle = list[i].title.replace(/Infobox|_| /g, "");
validTypes += list[i].title.replace(/Infobox_/, "").replace(/_/g, " ") + ", ";
listColorsText = store.getTiddlerText(list[i].title + "::Text");
listColorsTitle = store.getTiddlerText(list[i].title + "::Title");
listColorsSubtitle = store.getTiddlerText(list[i].title + "::Subtitle");
if (listColorsText === null) {
listColorsText = "black";
}
if (listColorsTitle === null) {
listColorsTitle = "white";
}
if (listColorsSubtitle === null) {
listColorsSubtitle = "white";
}
//Color Palette
if (palette === null) {
config.shadowTiddlers.InfoboxTablesColorPalette += 
"Infobox" + listTitle + "Text: " + listColorsText + "\n" + 
"Infobox" + listTitle + "Title: " + listColorsTitle + "\n" + 
"Infobox" + listTitle + "Subtitle: " + listColorsSubtitle + "\n";
}
//Stylesheet
if (stylesheet === null) {
config.shadowTiddlers.InfoboxTablesStylesheet += 
".Infobox" + listTitle + "Title {background: [[InfoboxTablesColorPalette::Infobox" + listTitle + "Title]]; color: [[InfoboxTablesColorPalette::Infobox" + listTitle + "Text]];}\n" + 
".Infobox" + listTitle + "Subtitle {background: [[InfoboxTablesColorPalette::Infobox" + listTitle + "Subtitle]]; color: [[InfoboxTablesColorPalette::Infobox" + listTitle + "Text]];}\n" + 
".NoInfo" + listTitle + " {background: [[InfoboxTablesColorPalette::Infobox" + listTitle + "Title]]; color: [[InfoboxTablesColorPalette::Infobox" + listTitle + "Text]];}\n" + 
".Infobox" + listTitle + "Error {background: [[InfoboxTablesColorPalette::InfoboxTypeError]]; color: [[InfoboxTablesColorPalette::Infobox" + listTitle + "Text]]; border: solid 5px [[InfoboxTablesColorPalette::Infobox" + listTitle + "Title]];}\n";
store.addNotification("InfoboxTablesStylesheet", refreshStyles);
}
}
if (palette === null) {
config.shadowTiddlers.InfoboxTablesColorPalette += "/*}}}*/\n";
}
if (stylesheet === null) {
config.shadowTiddlers.InfoboxTablesStylesheet += "/*}}}*/\n";
}
//}}}

/***
!!Infobox Macro
***/
//{{{
config.macros.infobox = {};
config.macros.infobox.handler = function (place,macroName,params,wikifier,paramString,tiddler) {

params = paramString.parseParams(null, null, true);

var Type = getParam(params, 'Type', 'unknown');
var Title = getParam(params, 'Title', tiddler.title);
var InstanceID = getParam(params, 'InstanceID', 'DefaultID');
var TypeX = Type.replace(/[\s]/g, "");
var TitleX = Title.replace(/[\W\s]/g, "");
var InstanceIDX = InstanceID.replace(/[\W\s]/g, "");
var TTIX = TypeX + TitleX + InstanceIDX;

//Decide if the infoboxes should be displayed by default or not
if (config.options.chkHideInfoboxes === undefined) {
config.options.chkHideInfoboxes = false;
}
if (config.options.chkSaveMode === undefined) {
config.options.chkSaveMode = true;
}
if (config.options.chkSavePrompt === undefined) {
config.options.chkSavePrompt = true;
}

var noEdit = "false";

//Create the outer container
var infoboxDiv = createTiddlyElement(place, "div", "InfoboxOuterDiv"+TTIX, "InfoboxOuterDiv");

var saveButton, editButton, deleteButton, toggleButton, infoboxTableDiv, infoboxTableEditDiv;

//Set initial values for the toggle button
var closedtext = "show";
var closedtip = "show";
var openedtext = "hide";
var openedtip = "hide";
var toggleButtonTitle, toggleButtonTooltip;
var hideInfoboxes = config.options.chkHideInfoboxes;
if (hideInfoboxes === true) {
toggleButtonTitle = (hideInfoboxes === true ? closedtext : openedtext);
toggleButtonTooltip = (hideInfoboxes === true ? closedtip : openedtip);
}
else {
toggleButtonTitle = (hideInfoboxes === false ? openedtext : closedtext);
toggleButtonTooltip = (hideInfoboxes === false ? openedtip : closedtip);
}

//Create the toggle button
toggleButton = createTiddlyButton(infoboxDiv, toggleButtonTitle, toggleButtonTooltip, function() {config.macros.infobox.toggleInfobox(editButton,toggleButton,infoboxTableDiv);}, "SmallButton", "SmallButton"+TTIX);
toggleButton.style.display = "block";
toggleButton.setAttribute("closedtext",closedtext);
toggleButton.setAttribute("closedtip",closedtip);
toggleButton.setAttribute("openedtext",openedtext);
toggleButton.setAttribute("openedtip",openedtip);

//Create the delete button
deleteButton = createTiddlyButton(infoboxDiv, "delete", "delete infobox", function() {config.macros.infobox.deleteInfobox(Type,Title,InstanceID);}, "SmallButton", "SmallButtonSave"+TTIX);
deleteButton.style.display = "none";

//Set initial values for the edit/cancel button
var edittext = "edit";
var edittip = "edit infobox";
var canceltext = "cancel";
var canceltip = "cancel edit";

//Create the edit/cancel button
editButton = createTiddlyButton(infoboxDiv, "edit", "edit infobox", function() {config.macros.infobox.editInfobox(saveButton,editButton,deleteButton,toggleButton,infoboxTableDiv,infoboxTableEditDiv,Title,noEdit);}, "SmallButton", "SmallButtonEdit"+TTIX);
if (hideInfoboxes === true) {
editButton.style.display = "none";
}
else {
editButton.style.display = "block";
}
editButton.setAttribute("edittext",edittext);
editButton.setAttribute("edittip",edittip);
editButton.setAttribute("canceltext",canceltext);
editButton.setAttribute("canceltip",canceltip);

//Create the save button
saveButton = createTiddlyButton(infoboxDiv, "save", "save infobox", function() {config.macros.infobox.saveInfobox(saveButton,editButton,deleteButton,toggleButton,infoboxTableDiv,infoboxTableEditDiv,Type,Title,InstanceID);}, "SmallButton", "SmallButtonSave"+TTIX);
saveButton.style.display = "none";

//Create the container for the table
infoboxTableDiv = createTiddlyElement(infoboxDiv, "div", "InfoboxInnerDiv"+TTIX, "InfoboxInnerDiv");
if (hideInfoboxes === true) {
infoboxTableDiv.style.display = "none";
}
else {
infoboxTableDiv.style.display = "block";
}

//Create container for the edit table
infoboxTableEditDiv = createTiddlyElement(infoboxDiv, "div", "InfoboxEditInnerDiv"+TTIX, "InfoboxInnerDiv");
infoboxTableEditDiv.style.display = "none";

//Cancel edit by pressing escape
infoboxDiv.onkeyup = function(e) {
if (e.keyCode === 27) {
config.macros.infobox.editInfobox(saveButton,editButton,deleteButton,toggleButton,infoboxTableDiv,infoboxTableEditDiv,Title,noEdit);
}
};

//Output for beginning of table
var start = "<html><div id=\"DivContainer" + TTIX + "\"><table id=\"Header" + TTIX + "\" class=\"InfoboxTable InfoboxTableHeader\"><tr id=\"Title" + TTIX + "\"><td class=\"InfoboxTableTop Infobox" + TypeX + "Title\" colspan=\"2\">" + Title + "</td></tr>";
//Output for content of table
var out = "";
//Output for end of table
var end = "</table><table id=\"Footer" + TTIX + "\" class=\"InfoboxTable InfoboxTableFooter\"><tr id=\"Info" + TTIX + "\"><td class=\"InfoboxTableBottom Infobox" + TypeX + "Title\" colspan=\"2\">&nbsp;</td></tr></table></div><div id=\"NoInfo" + TTIX + "\" class=\"InfoboxNoInfo NoInfo" + TypeX + "\">No information available.</div></html>{{SmallButton{[[View template|Infobox_" + Type.replace(/ /g, "_") + "]]}}}";

//Output for beginning of edit table
var startEdit = "<html><div id=\"EditDivContainer" + TTIX + "\"><table id=\"EditHeader" + TTIX + "\" class=\"InfoboxTable\"><tr><td class=\"InfoboxSection Infobox" + TypeX + "Subtitle\" colspan=\"2\">Infobox Head</td></tr><tr id=\"EditType" + TTIX + "\"><td class=\"InfoboxCellLeft\">Type</td><td class=\"InfoboxCellRight\">" + Type + "</td></tr><tr id=\"EditTitle" + TTIX + "\"><td class=\"InfoboxCellLeft\">Title</td><td class=\"InfoboxCellRight\"><textarea id=\"EditTextareaTitle" + TTIX + "\" class=\"InfoboxEditTextarea\" onfocus=\"this.className = 'InfoboxEditTextareaOnfocus';\" onblur=\"this.className = 'InfoboxEditTextareaOnblur'; this.defaultValue = this.value;\">" + Title + "</textarea></td></tr><tr id=\"EditInstanceID" + TTIX + "\"><td class=\"InfoboxCellLeft\">Instance ID</td><td class=\"InfoboxCellRight\"><textarea id=\"EditTextareaInstanceID" + TTIX + "\" class=\"InfoboxEditTextarea\" onfocus=\"this.className = 'InfoboxEditTextareaOnfocus';\" onblur=\"this.className = 'InfoboxEditTextareaOnblur'; this.defaultValue = this.value;\">" + InstanceID + "</textarea></td></tr><tr><td class=\"InfoboxSection Infobox" + TypeX + "Subtitle\" colspan=\"2\">Infobox Content</td></tr>";
//Output for content of edit table
var outEdit = "";
//Output for end of edit table
var endEdit = "</table></div></html>";

//If Type is missing
if (Type === "unknown" || Type === null || Type.length === 0) {
wikify("{{InfoboxTypeError{\nType is mandatory! Allowed types are: " + validTypes.replace(/, $/, "") + "\nEdit mode is not available.}}}", infoboxTableDiv);
noEdit = "true";
return;
}
//If Type is wrong
else if (validTypes.indexOf(Type) === -1) {
wikify("{{InfoboxTypeError{\nYou entered a non-existent type! Allowed types are: " + validTypes.replace(/, $/, "") + "\nEdit mode is not available.}}}", infoboxTableDiv);
noEdit = "true";
return;
}
//If Type is okay
else if (validTypes.indexOf(Type) !== -1) {

//Check how many instances of the same type there are in a tiddler
var instanceCheck = store.getTiddlerText(tiddler.title);
var instanceInfobox = instanceCheck.match(/<<infobox/g); //Find all instances of the macro in the tiddler
if (instanceInfobox.length > 1) { //If there is more than one instance
var instanceInfoboxType = instanceCheck.match(/<<infobox[\w\W\s]*?Type:"[\w\s]*?"[\w\W\s]*?>>/g); //Get all infoboxes
var instanceInfoboxTypeResultEmpty = [];
var instanceInfoboxTypeResult = [];
var l;
for (l = 0; l < instanceInfoboxType.length; l++) {
if ((instanceInfoboxType[l].match("Type:\"" + Type + "\"") !== -1) && (InstanceID === "DefaultID" || InstanceID === null || InstanceID.length === 0) && (instanceInfoboxType[l].indexOf("\""+Type+"\"") !== -1)) { //If the infobox matches the type and does not have an InstanceID parameter, put it into array
instanceInfoboxTypeResultEmpty.push(instanceInfoboxType[l]);
}
if ((instanceInfoboxType[l].match("Type:\"" + Type + "\"") !== -1) && !(InstanceID === "DefaultID" || InstanceID === null || InstanceID.length === 0) && (instanceInfoboxType[l].indexOf("\""+Type+"\"") !== -1)) { //If the infobox matches the type and has an InstanceID parameter, put it into array
instanceInfoboxTypeResult.push(instanceInfoboxType[l]);
}
}

if (instanceInfoboxTypeResultEmpty.length > 1) { //If there is more than one infobox without the InstanceID parameter
var instanceIDCount = 0;
var m;
for (m = 0; m < instanceInfoboxTypeResultEmpty.length; m++) { //Count the number or missing InstanceID parameters
if (instanceInfoboxTypeResultEmpty[m].match(/InstanceID:"[\w\s]*?"/g) !== null) {
instanceIDCount = instanceIDCount + 1;
}
}

if (instanceInfoboxType.length > instanceIDCount) { //If there are more infoboxes than InstanceID parameters per type
if (InstanceID === "DefaultID" || InstanceID === null || InstanceID.length === 0) { //Display error message for all infoboxes without an InstanceID parameter
wikify("{{InfoboxError Infobox" + TypeX + "Error{\nThere are ''" + instanceInfoboxTypeResultEmpty.length + "'' infoboxes of ''\"" + Type + "\"'' type, but ''" + instanceIDCount + "'' ~IDs. This infobox does not have an ''~InstanceID'' parameter.<br/>When using more than one infobox of the same type, you need to add ''~InstanceID'' parameter to all of them. This parameter can be a random ''alphanumeric'' string and must be different for each infobox of the same type.\nEdit mode is not available.}}}", infoboxTableDiv);
noEdit = "true";
return;
}
}
} //End missing instanceID check

//Check for duplicate InstanceID parameters for a type
var instanceIDs = [];
var instanceIDMatch;
var n;
if (instanceInfoboxTypeResult.length > 1) { //If there is more than one infobox with the InstanceID parameter
for (n = 0; n < instanceInfoboxTypeResult.length; n++) { //Count the number or InstanceID parameters
if ((instanceInfoboxTypeResult[n].match(/InstanceID:"[\w\s]*?"/g) !== null) && !(InstanceID === "DefaultID" || InstanceID === null || InstanceID.length === 0)) {
instanceIDMatch = instanceInfoboxTypeResult[n].match(/InstanceID:"[\w\s]*?"/g);
instanceIDs.push(instanceIDMatch);
}
}
var instanceIDsSorted = instanceIDs.sort();
var duplicateIDs = [];
var o;
for (o = 0; o < instanceIDsSorted.length - 1; o++) { //Find the duplicates
if (instanceIDsSorted[o].toString() === instanceIDsSorted[o+1].toString()) {
duplicateIDs.push(instanceIDsSorted[o]);
}
}
if (duplicateIDs.length > 0) {
wikify("{{InfoboxError Infobox" + TypeX + "Error{\nThis infobox has the same ''~InstanceID'' parameter (''\"" + InstanceID + "\"'') as another infobox of the same type (''\"" + Type + "\"'').<br/>Infoboxes of the same type must have ''unique ~IDs''.\nEdit mode is not available.}}}", infoboxTableDiv);
noEdit = "true";
return;
}
} //End duplicate check
} //End of checks when there's more than one instance

//Begin parsing parameters for output
noEdit = "false";
var paramList = store.getTiddlerText("Infobox_"+ Type.replace(/[\s]/g, "_") + "##Content");
var paramListParsed = paramList.replace(/----\n/g, "").replace(/ /g, "_").split("\n"); //Get parameters
var paramCount = 0;
var param;
var k;
for (k = 0; k < paramListParsed.length; k++) {
if (paramListParsed[k].indexOf("((") !== -1) { //Params when there is a shorthand definition
param = getParam(params, paramListParsed[k].replace(/^[\W\w\s]*?\(\(|\)\)[\W\w\s]*?$/g, ""), 'unknown');
}
else { //Params when there is no shorthand definition
param = getParam(params, paramListParsed[k].replace(/_\*\*[\W\w\s]*?$/g, ""), 'unknown');
}

//Output for section titles
if (paramListParsed[k].indexOf("Section-") !== -1) {
out += "</table><table id=\"SectionTable" + TTIX + paramListParsed[k].replace(/Section-|_\(\([\w\s]*?\)\)|_\*\*[\w\W\s]*?$/g, "") + "\" class=\"InfoboxTable\"><tr id=\"SectionHeader" + TTIX + paramListParsed[k].replace(/Section-|_\(\([\w\s]*?\)\)|_\*\*[\w\W\s]*?$/g, "") + "\"><td class=\"InfoboxSection Infobox" + TypeX + "Subtitle\" colspan=\"2\">" + paramListParsed[k].replace(/Section-|_\(\([\w\s]*?\)\)|_\*\*[\w\W\s]*?$/g, "").replace(/_/g, " ") + "</td></tr>";
outEdit += "</table><table id=\"EditSectionTable" + TTIX + paramListParsed[k].replace(/Section-|_\(\([\w\s]*?\)\)|_\*\*[\w\W\s]*?$/g, "") + "\" class=\"InfoboxTable\"><tr id=\"EditSectionHeader" + TTIX + paramListParsed[k].replace(/Section-|_\(\([\w\s]*?\)\)|_\*\*[\w\W\s]*?$/g, "") + "\"><td class=\"InfoboxSection Infobox" + TypeX + "Subtitle\" colspan=\"2\">" + paramListParsed[k].replace(/Section-|_\(\([\w\s]*?\)\)|_\*\*[\w\W\s]*?$/g, "").replace(/_/g, " ") + "</td></tr>";
}
//Output for images
else if (paramListParsed[k].indexOf("Image-") !== -1) {
out += "<tr id=\"" + TTIX + paramListParsed[k].replace(/Image-|_\(\([\w\s]*?\)\)|_\*\*[\w\W\s]*?$/g, "") + "\" class=\"InfoboxRow\"><td class=\"InfoboxCellImage\" colspan=\"2\"><a href=\"" + param + "\"><img src=\"" + param + "\" alt=\"" + param + "\" title=\"" + param + "\" class=\"InfoboxImage\"/></a></td></tr>";
outEdit += "<tr id=\"Edit" + TTIX + paramListParsed[k].replace(/Image-|_\(\([\w\s]*?\)\)|_\*\*[\w\W\s]*?$/g, "") + "\" class=\"InfoboxRow\"><td class=\"InfoboxCellLeft\">Image: " + paramListParsed[k].replace(/_/g, " ").replace(/Image-| \(\([\w\s]*?\)\)| \*\*[\w\W\s]*?$/g, "") + "</td><td class=\"InfoboxCellRight\"><span id=\"EditComment" + TTIX + paramListParsed[k].replace(/Image-|_\(\([\w\s]*?\)\)|_\*\*[\w\W\s]*?$/g, "") + "\" class=\"EditComment\">" + paramListParsed[k].replace(/Image-[\w\W\s]*?\*\*/g, "").replace(/_/g, " ").replace(/Image-[\w\W\s]*?$/g, "No comment available.") + "</span><textarea id=\"EditTextarea" + TTIX + paramListParsed[k].replace(/Image-|_\(\([\w\s]*?\)\)|_\*\*[\w\W\s]*?$/g, "") + "\" class=\"InfoboxEditTextarea\" onfocus=\"this.className = 'InfoboxEditTextareaOnfocus'; this.previousSibling.style.display = 'block';\" onblur=\"this.className = 'InfoboxEditTextareaOnblur'; this.defaultValue = this.value; this.previousSibling.style.display = 'none';\">" + param + "</textarea></td></tr>";
}
//Output for single cells
else if (paramListParsed[k].indexOf("Single-") !== -1) {
out += "<tr id=\"" + TTIX + paramListParsed[k].replace(/Single-|_\(\([\w\s]*?\)\)|_\*\*[\w\W\s]*?$/g, "") + "\" class=\"InfoboxRow\"><td class=\"InfoboxCellSingle\" colspan=\"2\">" + param + "</td></tr>";
outEdit += "<tr id=\"Edit" + TTIX + paramListParsed[k].replace(/Single-|_\(\([\w\s]*?\)\)|_\*\*[\w\W\s]*?$/g, "") + "\" class=\"InfoboxRow\"><td class=\"InfoboxCellLeft\">Single: " + paramListParsed[k].replace(/_/g, " ").replace(/Single-| \(\([\w\s]*?\)\)| \*\*[\w\W\s]*?$/g, "") + "</td><td class=\"InfoboxCellRight\"><span id=\"EditComment" + TTIX + paramListParsed[k].replace(/Single-|_\(\([\w\s]*?\)\)|_\*\*[\w\W\s]*?$/g, "") + "\" class=\"EditComment\">" + paramListParsed[k].replace(/Single-[\w\W\s]*?\*\*/g, "").replace(/_/g, " ").replace(/Single-[\w\W\s]*?$/g, "No comment available.") + "</span><textarea id=\"EditTextarea" + TTIX + paramListParsed[k].replace(/Single-|_\(\([\w\s]*?\)\)|_\*\*[\w\W\s]*?$/g, "") + "\" class=\"InfoboxEditTextarea\" onfocus=\"this.className = 'InfoboxEditTextareaOnfocus'; this.previousSibling.style.display = 'block';\" onblur=\"this.className = 'InfoboxEditTextareaOnblur'; this.defaultValue = this.value; this.previousSibling.style.display = 'none';\">" + param + "</textarea></td></tr>";
}
//Start output if using sides (left cell)
else if (paramListParsed[k].indexOf("Side1-") !== -1) {
out += "<tr id=\"Content" + TTIX + paramListParsed[k-1].replace(/Section-|_\*\*[\w\W\s]*?$/g, "") + "\" class=\"InfoboxRow\"><td class=\"InfoboxCellEqual\">" + param + "</td>";
outEdit += "<tr id=\"EditContent" + TTIX + paramListParsed[k-1].replace(/Section-|_\*\*[\w\W\s]*?$/g, "") + "\" class=\"InfoboxRow\"><td class=\"InfoboxCellEqual\"><span id=\"EqualEditParam" + TTIX + paramListParsed[k].replace(/_\(\([\w\s]*?\)\)|_\*\*[\w\W\s]*?$/g, "") + "\" class=\"EqualEditParamName\">" + paramListParsed[k].replace(/_/g, " ").replace(/ \(\([\w\s]*?\)\)| \*\*[\w\W\s]*?$/g, "") + "</span><span id=\"EditComment" + TTIX + paramListParsed[k].replace(/Side1-|_\(\([\w\s]*?\)\)|_\*\*[\w\W\s]*?$/g, "") + "\" class=\"EditComment\">" + paramListParsed[k].replace(/Side1-[\w\W\s]*?\*\*/g, "").replace(/_/g, " ").replace(/Side1-[\w\W\s]*?$/g, "No comment available.") + "</span><textarea id=\"EditTextarea" + TTIX + paramListParsed[k].replace(/_\(\([\w\s]*?\)\)|_\*\*[\w\W\s]*?$/g, "") + "\" class=\"InfoboxEditTextarea\" onfocus=\"this.className = 'InfoboxEditTextareaOnfocus'; this.previousSibling.style.display = 'block';\" onblur=\"this.className = 'InfoboxEditTextareaOnblur'; this.defaultValue = this.value; this.previousSibling.style.display = 'none';\">" + param + "</textarea></td>";
}
//End output if using sides (right cell)
else if (paramListParsed[k].indexOf("Side2-") !== -1) {
out += "<td class=\"InfoboxCellEqual\">" + param + "</td></tr>";
outEdit += "<td class=\"InfoboxCellEqual\"><span id=\"EqualEditParam" + TTIX + paramListParsed[k].replace(/_\(\([\w\s]*?\)\)|_\*\*[\w\W\s]*?$/g, "") + "\" class=\"EqualEditParamName\">" + paramListParsed[k].replace(/_/g, " ").replace(/ \(\([\w\s]*?\)\)| \*\*[\w\W\s]*?$/g, "") + "</span><span id=\"EditComment" + TTIX + paramListParsed[k].replace(/Side2-|_\(\([\w\s]*?\)\)|_\*\*[\w\W\s]*?$/g, "") + "\" class=\"EditComment\">" + paramListParsed[k].replace(/Side2-[\w\W\s]*?\*\*/g, "").replace(/_/g, " ").replace(/Side2-[\w\W\s]*?$/g, "No comment available.") + "</span><textarea id=\"EditTextarea" + TTIX + paramListParsed[k].replace(/_\(\([\w\s]*?\)\)|_\*\*[\w\W\s]*?$/g, "") + "\" class=\"InfoboxEditTextarea\" onfocus=\"this.className = 'InfoboxEditTextareaOnfocus'; this.previousSibling.style.display = 'block';\" onblur=\"this.className = 'InfoboxEditTextareaOnblur'; this.defaultValue = this.value; this.previousSibling.style.display = 'none';\">" + param + "</textarea></td></tr>";
}
//Normal output
else {
out += "<tr id=\"" + TTIX + paramListParsed[k].replace(/_\(\([\w\s]*?\)\)|_\*\*[\w\W\s]*?$/g, "") + "\" class=\"InfoboxRow\"><td class=\"InfoboxCellLeft\">" + paramListParsed[k].replace(/_/g, " ").replace(/ \(\([\w\s]*?\)\)| \*\*[\w\W\s]*?$/g, "") + "</td><td class=\"InfoboxCellRight\">" + param + "</td></tr>";
outEdit += "<tr id=\"Edit" + TTIX + paramListParsed[k].replace(/_\(\([\w\s]*?\)\)|_\*\*[\w\W\s]*?$/g, "") + "\" class=\"InfoboxRow\"><td class=\"InfoboxCellLeft\">" + paramListParsed[k].replace(/_/g, " ").replace(/ \(\([\w\s]*?\)\)| \*\*[\w\W\s]*?$/g, "") + "</td><td class=\"InfoboxCellRight\"><span id=\"EditComment" + TTIX + paramListParsed[k].replace(/_\(\([\w\s]*?\)\)|_\*\*[\w\W\s]*?$/g, "") + "\" class=\"EditComment\">" + paramListParsed[k].replace(/^/, "dummy").replace(/dummy[\w\W\s]*?\*\*/g, "").replace(/_/g, " ").replace(/dummy[\w\W\s]*?$/g, "No comment available.") + "</span><textarea id=\"EditTextarea" + TTIX + paramListParsed[k].replace(/_\(\([\w\s]*?\)\)|_\*\*[\w\W\s]*?$/g, "") + "\" class=\"InfoboxEditTextarea\" onfocus=\"this.className = 'InfoboxEditTextareaOnfocus'; this.previousSibling.style.display = 'block';\" onblur=\"this.className = 'InfoboxEditTextareaOnblur'; this.defaultValue = this.value; this.previousSibling.style.display = 'none';\">" + param + "</textarea></td></tr>";
}

//Hide lines with no information
if ((param === "unknown") && (paramListParsed[k].indexOf("Section-") === -1)) {
setStylesheet("#" + TTIX + paramListParsed[k].replace(/Image-|Single-|_\(\([\w\s]*?\)\)|_\*\*[\w\W\s]*?$/g, "") + " {display: none !important;}", "InfoboxContentRows" + TTIX + paramListParsed[k].replace(/Image-|Single-|\(\([\w\s]*?\)\)|\*\*[\w\W\s]*?$| /g, ""));
} else {
setStylesheet("#" + TTIX + paramListParsed[k].replace(/Image-|Single-|_\(\([\w\s]*?\)\)|_\*\*[\w\W\s]*?$/g, "") + " {display: table-row;}", "InfoboxContentRows" + TTIX + paramListParsed[k].replace(/Image-|Single-|\(\([\w\s]*?\)\)|\*\*[\w\W\s]*?| /g, ""));
}

//Hide the whole table if all parameters are unknown
if (param === "unknown") { //First count how many params are unknown
paramCount = paramCount + 1;
}
if (paramCount === paramListParsed.length) { //If all params are unknown
setStylesheet("#DivContainer" + TTIX + " {display: none;}", "InfoboxTable" + TTIX);
setStylesheet("#NoInfo" + TTIX + " {display: block;}", "NoInfo" + TTIX);
} else {
setStylesheet("#DivContainer" + TTIX + " {display: block;}", "InfoboxTable" + TTIX);
setStylesheet("#NoInfo" + TTIX + " {display: none;}", "NoInfo" + TTIX);
}
} //End parsing of parameters for output

//Hide section title if all params in the section are unknown (requires extra parsing of parameters by sections)
var section = paramList.replace(/Section-[\w\W\s]*?/g, "").replace(/ /g, "_").split("\n----\n"); //Get sections
var sectionParsed, sectionParams;
var sectionParamCount = 0;
var p, q;
if (section.length > 1) {
for (p = 0; p < section.length; p++) {
sectionParsed = section[p].split("\n"); //Split sections into parameters
for (q = 0; q < sectionParsed.length; q++) { //Parse the parameters
if (sectionParsed[q].indexOf("((") !== -1) { //Params when there is a shorthand definition
sectionParams = getParam(params, sectionParsed[q].replace(/^[\W\w\s]*?\(\(|\)\)[\W\w\s]*?$/g, ""), 'unknown');
}
else { //Params when there is no shorthand definition
sectionParams = getParam(params, sectionParsed[q].replace(/_\*\*[\W\w\s]*?$/g, ""), 'unknown');
}
if (sectionParams === "unknown") { //Count how many parameters in the section are unknown
sectionParamCount = sectionParamCount + 1;
}
}

if (sectionParamCount === sectionParsed.length) {
setStylesheet("#SectionTable" + TTIX + sectionParsed[0].replace(/Section-|_\*\*[\w\W\s]*?$/g, "") + " {display: none;}", "InfoboxSection" + TTIX + sectionParsed[0].replace(/Section-|_\*\*[\w\W\s]*?$/g, ""));
} else {
setStylesheet("#SectionTable" + TTIX + sectionParsed[0].replace(/Section-|_\*\*[\w\W\s]*?$/g, "") + " {display: block;}", "InfoboxSection" + TTIX + sectionParsed[0].replace(/Section-|_\*\*[\w\W\s]*?$/g, ""));
}
sectionParamCount = 0; //Reset the count for the next section
}
}

//Final output
wikify(start + out + end, infoboxTableDiv);
wikify(startEdit + outEdit + endEdit, infoboxTableEditDiv);
} //End if Type is okay

}; //End of Infobox macro

//Toggle display of infoboxes
config.macros.infobox.toggleInfobox = function(editButton,toggleButton,place) {
var hideInfoboxes = config.options.chkHideInfoboxes;
if (hideInfoboxes === true) {
if (place.style.display === "block"){
place.style.display = "none";
editButton.style.display = "none";
toggleButton.innerHTML = toggleButton.getAttribute("closedtext");
toggleButton.setAttribute("title",toggleButton.getAttribute("closedtip"));
} else {
place.style.display = "block";
editButton.style.display = "block";
toggleButton.innerHTML = toggleButton.getAttribute("openedtext");
toggleButton.setAttribute("title",toggleButton.getAttribute("openedtip"));
}
} else {
if (place.style.display === "none") {
place.style.display = "block";
editButton.style.display = "block";
toggleButton.innerHTML = toggleButton.getAttribute("openedtext");
toggleButton.setAttribute("title",toggleButton.getAttribute("openedtip"));
} else {
place.style.display = "none";
editButton.style.display = "none";
toggleButton.innerHTML = toggleButton.getAttribute("closedtext");
toggleButton.setAttribute("title",toggleButton.getAttribute("closedtip"));
}
}
};
//End toggle display of infoboxes

//Edit infoboxes
config.macros.infobox.editInfobox = function(saveButton,editButton,deleteButton,toggleButton,place,placeEdit,tiddler,noEdit) {
if (noEdit === "false") {
if (place.style.display === "block"){
deleteButton.style.display = "block";
saveButton.style.display = "block";
toggleButton.style.display = "none";
place.style.display = "none";
placeEdit.style.display = "block";
editButton.innerHTML = editButton.getAttribute("canceltext");
editButton.setAttribute("title",editButton.getAttribute("canceltip"));
}
else {
deleteButton.style.display = "none";
saveButton.style.display = "none";
toggleButton.style.display = "block";
place.style.display = "block";
placeEdit.style.display = "none";
editButton.innerHTML = editButton.getAttribute("edittext");
editButton.setAttribute("title",editButton.getAttribute("edittip"));
story.refreshTiddler(tiddler, null, true);
}
}
};
//End edit infoboxes

//Delete infoboxes
config.macros.infobox.deleteInfobox = function(type,title,instance) {
var confirmDelete = confirm("Do you really want to delete this infobox?\nTitle: \""+title+"\"\nType: \""+type+"\"\nInstance ID: \""+instance+"\"");
if (confirmDelete === true) {
//Get macro
var articleText = store.getTiddlerText(title); //Get article text
var macros = articleText.match(/<<infobox[\w\W\s]*?Type:"[\w\s]*?"[\w\W\s]*?>>/g); //Get all macros
var i;
var targetMacro;
for (i = 0; i < macros.length; i++) { //Get the correct macro
var macroType = "Type:\""+type+"\"";
if (macros[i].match(macroType)) {
if (macros[i].match(instance)) {
var macroInstancID = "InstanceID:\""+instance+"\"";
if (macros[i].match(macroInstancID)) {
targetMacro = macros[i];
}
}
else {
targetMacro = macros[i];
}
}
}

//Delete
var tid = store.getTiddler(title);
var tags = tid.tags;
var oldText;
var oldTextCheck = articleText.match(targetMacro+"\n");
if (oldTextCheck === null) {
oldText = targetMacro;
}
else {
oldText = targetMacro+"\n";
}
var newText = articleText.replace(oldText, "");
store.saveTiddler(title,title,newText,config.options.txtUserName,new Date(),tags); 
autoSaveChanges(null,[tiddler]);
story.displayTiddler(null,title); 
}
else {
return;
}
};
//End delete infoboxes

//Save infoboxes
config.macros.infobox.saveInfobox = function(saveButton,editButton,deleteButton,toggleButton,place,placeEdit,type,title,instance) {
var savePrompt = config.options.chkSavePrompt;
var doSave;
if (savePrompt === true) {
var confirmSave = confirm("Do you really want to save changes to this infobox?\nTitle: \""+title+"\"\nType: \""+type+"\"\nInstance ID: \""+instance+"\"");
if (confirmSave === true) {
doSave = true;
}
else {
doSave = false;
}
}
else {
doSave = true;
}

if (doSave === true) {
//Get the rendered content
var macroContent = placeEdit.innerHTML.replace(/<td[^>]*?colspan[^>]*?>[\w\W\s]*?<\/td>|<span[^>]*?EditComment[^>]*?>[\w\W\s]*?<\/span>|<span>|<\/span>/g, "").replace(/<\/textarea>/g, "\"\n").replace(/<textarea [\w\W\s]*?>/g, ":\"").replace(/<td[^>]*?>Type<\/td>/g, "Type:\"").replace(/<td[^>]*?>Title<\/td>/g, "\"\nTitle").replace(/<[\w\W\s]*?>|<\/[\w\W\s]*?>/g, "").replace(/Image: /g, "Image-").replace(/Single: /g, "Single-").replace(/Instance ID/g, "InstanceID"); //The "span" tags need to be removed, because they are added by HTMLFormattingPlugin, which is why comments and double cell columns are removed first

//Get the correct macro
var articleText = store.getTiddlerText(title); //Get article text
var macros = articleText.match(/<<infobox[\w\W\s]*?Type:"[\w\s]*?"[\w\W\s]*?>>/g);
var i;
var targetMacro;
for (i = 0; i < macros.length; i++) {
var macroType = "Type:\""+type+"\"";
if (macros[i].match(macroType)) {
if (macros[i].match(instance)) {
var macroInstancID = "InstanceID:\""+instance+"\"";
if (macros[i].match(macroInstancID)) {
targetMacro = macros[i];
}
}
else {
targetMacro = macros[i];
}
}
}

//Remove sections from the rendered content
var template = "Infobox_" + type.replace(/ /g, "_"); //Get template name
var templateText = store.getTiddlerText(template + "##Content"); //Get template definition
var templateSection = templateText.match(/Section-[\w\W\s]*?\n/g); //Get sections
var templateSectionCleaned = [];
var sectionCleaned, targetMacroSectionsReplace;
var j;
for (j = 0; j < templateSection.length; j++) {
sectionCleaned = templateSection[j].replace(/Section-| \*\*[\w\W\s]*?\n/g, ""); //Clean up sections
targetMacroSectionsReplace = sectionCleaned+"\"\\n";
if (macroContent.match(sectionCleaned)) {
templateSectionCleaned.push(targetMacroSectionsReplace); //Add all containd sections to array
}
}
var templateSectionCleanedString = new RegExp(templateSectionCleaned.toString().replace(/,/g, "|"), "g"); //Convert the array to string to be used in regexp
var macroContentSectionsCleaned = macroContent.replace(templateSectionCleanedString, ""); //Remove the sections from the macro

//Remove unknown parameters from the rendered content
var templateParams = templateText.replace(/----\n|Section-[\w\W\s]*?\n/g, "").replace(/ \*\*[\w\W\s]*?\n/g, "\n").split("\n"); //Get parameters
var templateParamsCleaned = [];
var shorthands = [];
var paramsCleaned, targetMacroParamsReplaceUnknown, targetMacroParamsReplaceEmpty, longhand, shorthand;
var k;
for (k = 0; k < templateParams.length; k++) { //Clean up parameters
if (templateParams[k].indexOf("((") !== -1) { //Get shorthand definitions for later
longhand = templateParams[k].replace(/Image-|Single-|Side1-|Side2-| \(\([\W\w\s]*?$/g, "");
shorthand = templateParams[k].replace(/^[\W\w\s]*?\(\(|\)\)[\W\w\s]*?$/g, "");
shorthands.push(longhand);
shorthands.push(shorthand);
}
paramsCleaned = templateParams[k].replace(/ \(\([\W\w\s]*?$|\n/g, ""); //Remove shorthand definitions and comments

targetMacroParamsReplaceUnknown = paramsCleaned+":\"unknown\"\\n";
if (macroContent.match(targetMacroParamsReplaceUnknown)) {
templateParamsCleaned.push(targetMacroParamsReplaceUnknown); //Add all contained unknown params to array
}
targetMacroParamsReplaceEmpty = paramsCleaned+":\"\"\\n";
if (macroContent.match(targetMacroParamsReplaceEmpty)) {
templateParamsCleaned.push(targetMacroParamsReplaceEmpty); //Add all contained empty params to array
}
}
var templateParamsCleanedString = new RegExp(templateParamsCleaned.toString().replace(/,/g, "|"), "g"); //Convert the array to string to be used in regexp
var macroContentParamsCleaned = macroContentSectionsCleaned.replace(templateParamsCleanedString, ""); //Remove the unknown params from the macro

//Replace longhand parameters with shorthands
var macroContentParamsCleanedSplit = macroContentParamsCleaned.split("\n"); //Convert macro string to array
var macroContentShorthandsArray = [];
var m, n;
var macroContentParamsClean, shorthandReplacement;
for (m = 0; m < macroContentParamsCleanedSplit.length; m++) { //Find out which parameters have shorthand definition
macroContentParamsClean = macroContentParamsCleanedSplit[m].replace(/Image-|Single-|Side1-|Side2-|:"[\w\W\s]*?"/g, "");
shorthandReplacement = "none";
for (n = 0; n < shorthands.length; n = n + 2) {
if (macroContentParamsClean === shorthands[n]) {
shorthandReplacement = macroContentParamsCleanedSplit[m].replace(/Image-|Single-|Side1-|Side2-/g, "").replace(shorthands[n], shorthands[n+1]); //Replace longhand parameters with shorthands
}
}
if (shorthandReplacement === "none") {
shorthandReplacement = macroContentParamsCleanedSplit[m];
}
macroContentShorthandsArray.push(shorthandReplacement); //Add all parameters to array
}

var macroContentShorthands = macroContentShorthandsArray.toString().replace(/",/g, "\"\n"); //Convert the array back to string

//Remove instance ID
var removeInstanceID = macroContentShorthands.replace(/InstanceID:"DefaultID"\n/, "");

//Remove title from the rendered content if it's the tiddler title and it isn't already in the macro
var defaultTitle = "Title:\""+title+"\"";
var removeTitleRE = defaultTitle+"\n";
var removeTitle;
if (!targetMacro.match(defaultTitle)) {
removeTitle = removeInstanceID.replace(removeTitleRE, "");
}
else {
removeTitle = removeInstanceID;
}

//Replace spaces in params with underscores
var matchSpaces = removeTitle.match(/^[\w\W\s]*?:|\n[\w\W\s]*?:/g); //Get the parameter names
var matchContent = removeTitle.match(/"[\w\W\s]*?"/g); //Get the parameter values
var replaceSpaces = [];
var l;
for (l = 0; l < matchSpaces.length; l++) {
replaceSpaces.push(matchSpaces[l].replace(/ /g, "_") + matchContent[l]); //Rejoin the parameter names and values
}
var noSpaces = replaceSpaces.toString().replace(/,/g, "");

//Add start and end macro code
var fullCode = "<<infobox\n" + noSpaces + "\n>>";
var addCode;
var saveMode = config.options.chkSaveMode;
if (saveMode === true) {
addCode = fullCode;
}
else {
addCode = fullCode.replace(/[\s]*?\n|\n[\s]*?|\n/g, " ").replace(/ >>/, ">>");
}

//Save
var tid = store.getTiddler(title);
var tags = tid.tags;
var newText = articleText.replace(targetMacro, addCode);
store.saveTiddler(title,title,newText,config.options.txtUserName,new Date(),tags); 
autoSaveChanges(null,[tiddler]);
story.displayTiddler(null,title); 

//Toggle display
editButton.style.display = "block";
deleteButton.style.display = "none";
saveButton.style.display = "none";
toggleButton.style.display = "block";
place.style.display = "block";
placeEdit.style.display = "none";
}
else {
return;
}
};
//End save of infoboxes
//}}}

//{{{
} //End of install only once
//}}}
/***
|Name|[[InfoboxTablesPlugin]]|
|Source|[[InfoboxTablesPlugin]]|
|Documentation|[[InfoboxTablesPluginInfo]]|
|Version|(2.0.0) ALPHA/INCOMPLETE|
|Author|Kristjan Brezovnik|
|License||
|~CoreVersion|2.1|
|Requires||
|Makes use of|[[NestedSlidersPlugin|http://www.TiddlyTools.com/#NestedSlidersPlugin]]<br>[[HTMLFormattingPlugin|http://www.TiddlyTools.com/#HTMLFormattingPlugin]]|
|Type|plugin|
|Description|Provides infoboxes for different types of articles.|
***/

/***
!To Do
*Check why InfoboxTable class is not applied correctly (style attribute is required for some parameters instead of using class attribute)
*Display warning when InstanceIDs are duplicated
*InfoCellLeft and InfoCellRight get squeezed to InfoCellEqual width in Waterfox, Chrome and Safari, in IE and Opera, all columns are the same width - try using <col span="2"/>
*Add InfoboxInfo mechanism
**Add xxxInfoboxParams to InfoboxInfo, to enable copying of params when entering info
**config.shadowTiddlers.ToolbarCommands.replace(/ViewToolbar\|/,"ViewToolbar\|InfoboxInfo"); - for adding to EditToolbar
*Maybe change checking for sections and pasing of parameters, so that parameters are only parsed once
***/

/***
!Configuration
<<option chkUseNestedSlidersPlugin>> Use [[NestedSlidersPlugin|http://www.TiddlyTools.com/#NestedSlidersPlugin]], if it's installed
<<option chkUseHTMLFormattingPlugin>> Use [[HTMLFormattingPlugin|http://www.TiddlyTools.com/#HTMLFormattingPlugin]], if it's installed ([[NestedSlidersPlugin|http://www.TiddlyTools.com/#NestedSlidersPlugin]] must be installed and enabled as well)
***/

/***
!Code
***/
//{{{
//Ensure that the plugin is only installed once
if (!version.extensions.InfoboxTablesPlugin) {
version.extensions.InfoboxTablesPlugin = {installed: true};
version.extensions.InfoboxTablesPlugin = {major: 2, minor: 0, revision: 0, date: new Date(2012,3,13)};

//Use NestedSlidersPlugin and HTMLFormattingPlugin, if they're installed
if (config.options.chkUseNestedSlidersPlugin === undefined) {config.options.chkUseNestedSlidersPlugin = true;}
if (config.options.chkUseHTMLFormattingPlugin === undefined) {config.options.chkUseHTMLFormattingPlugin = true;}
//}}}

/***
!!Generic Color Palette
***/
//{{{
config.shadowTiddlers.InfoboxTablesColorPalette = 
"InfoboxTableBackground: whitesmoke\n" + 
"InfoboxTableTopColor: whitesmoke\n" + 
"InfoboxTypeError: red\n";
//}}}

/***
!!Generic Stylesheet
***/
//{{{
config.shadowTiddlers.InfoboxTablesStylesheet = 
".InfoboxTable {border-collapse: separate; border: none 0px; border-spacing: 0px; border-radius: 10px; -moz-border-radius: 10px; -webkit-border-radius: 10px; width: 300px; font-size: 10px; font-weight: bold; background: [[InfoboxTablesColorPalette::InfoboxTableBackground]];}\n"+
".InfoboxTableTop, .InfoboxTableBottom {text-align: center; font-size: 16px; line-height:120%}\n" + 
".InfoboxTableTop {border: none 0px; border-radius: 10px 10px 0px 0px; -moz-border-radius: 10px 10px 0px 0px; -webkit-border-radius: 10px 10px 0px 0px;}\n" + 
".InfoboxTableBottom {border: none 0px; border-radius: 0px 0px 10px 10px; -moz-border-radius: 0px 0px 10px 10px; -webkit-border-radius: 0px 0px 10px 10px;}\n" + 
".InfoboxCellLeft, .InfoboxCellRight, .InfoboxCellEqual, .InfoboxCellImage {font-weight: normal; border: 1px solid; background: [[InfoboxTablesColorPalette::InfoboxTableBackground]]}\n"+
".InfoboxCellLeft {width: 100px;}\n" + 
".InfoboxCellRight {width: 200px;}\n" + 
".InfoboxCellEqual {width: 150px;}\n" + 
".InfoboxCellImage {width: 300px; text-align: center;}\n" + 
"img.InfoboxImage {max-width: 290px;}\n" + 
"#displayArea .viewer a.NestedSliderButton {border: 1px solid black; background: [[InfoboxTablesColorPalette::InfoboxTableBackground]]; padding: 1px; margin: 1px;} /* This makes the label/tooltip from the NestedSlidersPlugin look like a button */\n" + 
".FloatRight {float: right;}\n" + 
".SmallButton {font-size: 10px; line-height: 120%;}\n" + 
".InfoboxTypeError {width: 300px; background: [[InfoboxTablesColorPalette::InfoboxTypeError]]; font-weight: bold; border: solid 5px; border-radius: 5px; -moz-border-radius: 5px; -webkit-border-radius: 5px; padding: 5px 5px;}\n";
store.addNotification("InfoboxTablesStylesheet", refreshStyles);
//}}}

/***
!!Specific Color Palette, Stylesheet, Info
***/
//{{{
var list = store.getTaggedTiddlers("infobox");
var listTitle, listContent, listColors, listColorsTitle, listColorsSubtitle, paramListInfo, paramListInfoParsed;
var i, j;
var validTypes = "";
config.shadowTiddlers.InfoboxTablesInfo = "";
for (i = 0; i < list.length; i++) {
listTitle = list[i].title.replace(/Infobox|_| /g, "");
validTypes += list[i].title.replace(/Infobox_/, "").replace(/_/g, " ") + ", ";
listContent = store.getTiddlerText(list[i].title + "##Content");
listColorsTitle = store.getTiddlerText(list[i].title + "::Title");
listColorsSubtitle = store.getTiddlerText(list[i].title + "::Subtitle");
//Color Palette
config.shadowTiddlers.InfoboxTablesColorPalette += 
"Infobox" + listTitle + "Title: " + listColorsTitle + "\n" + 
"Infobox" + listTitle + "Subtitle: " + listColorsSubtitle + "\n";
//Stylesheet
config.shadowTiddlers.InfoboxTablesStylesheet += 
".Infobox" + listTitle + "Title {background: [[InfoboxTablesColorPalette::Infobox" + listTitle + "Title]];}\n" + 
".Infobox" + listTitle + "Subtitle {background: [[InfoboxTablesColorPalette::Infobox" + listTitle + "Subtitle]];}\n" + 
".NoInfo" + listTitle + " {width: 300px; background: [[InfoboxTablesColorPalette::Infobox" + listTitle + "Title]]; font-weight: bold; border: solid 2px; border-radius: 5px; -moz-border-radius: 5px; -webkit-border-radius: 5px; padding: 5px 5px;}\n" + 
".Infobox" + listTitle + "Error {width: 300px; background: [[InfoboxTablesColorPalette::InfoboxTypeError]]; font-weight: bold; border: solid 5px [[InfoboxTablesColorPalette::Infobox" + listTitle + "Title]]; border-radius: 5px; -moz-border-radius: 5px; -webkit-border-radius: 5px; padding: 5px 5px;}\n";
store.addNotification("InfoboxTablesStylesheet", refreshStyles);
//Info
paramListInfo = listContent.split("\n");
paramListInfoParsed = "";
for (j = 0; j < paramListInfo.length; j++) {
if (paramListInfo[j].indexOf("Section-") === -1) {
paramListInfoParsed += paramListInfo[j].replace(/Image-|Side1-|Side2-/g, "") + "\n";
}
}
config.shadowTiddlers.InfoboxTablesInfo += 
"!" + listTitle.toLowerCase() + "InfoboxInfo\n" + paramListInfoParsed;
}
//}}}

/***
!!Infobox Macro
***/
//{{{
config.macros.infobox = {};
config.macros.infobox.handler = function (place,macroName,params,wikifier,paramString,tiddler) {

params = paramString.parseParams(null, null, true);

var Type = getParam(params, 'Type', 'unknown');
var Title = getParam(params, 'Title', tiddler.title);
var InstanceID = getParam(params, 'InstanceID', '_DefaultID');
var TypeX = Type.replace(/[\s]/g, "");
var TitleX = Title.replace(/[\W\s]/g, "");
var InstanceIDX = InstanceID.replace(/[\s\W]/g, "");

//Output for beginning of table
var startNSP = "{{FloatRight{++++{{NestedSliderButton{[Show infobox|Show infobox][Hide infobox|Hide infobox]}}}<html><table id=\"Table" + TypeX + TitleX + InstanceIDX + "\" class=\"InfoboxTable\" style=\"border-collapse: separate; border: none 0px;\"><tr id=\"Title" + TitleX + InstanceIDX + "\"><td class=\"InfoboxTableTop Infobox" + TypeX + "Title\" colspan=\"2\">" + Title + "</td></tr>";
var start = "{{FloatRight{<html><table id=\"Table" + TypeX + TitleX + InstanceIDX + "\" class=\"InfoboxTable\" style=\"border-collapse: separate; border: none 0px;\"><tr id=\"Title" + TitleX + InstanceIDX + "\"><td class=\"InfoboxTableTop Infobox" + TypeX + "Title\" colspan=\"2\">" + Title + "</td></tr>";
//Output for content of table
var out = "";
//Output for end of table
var endNSPHFP = "<tr id=\"Info" + TypeX + TitleX + InstanceIDX + "\"><td class=\"InfoboxTableBottom Infobox" + TypeX + "Title\" colspan=\"2\">{{SmallButton{+++^*{{NestedSliderButton{[Show info|Show info][Hide info|Hide info]}}}...<<tiddler [[InfoboxTablesInfo##" + Type.toLowerCase().replace(/ /g, "") + "InfoboxInfo]]>>===}}}</td></tr></table><br/><div id=\"NoInfo" + TypeX + TitleX + InstanceIDX + "\" class=\"NoInfo" + TypeX + "\">No information available.</div></html>===}}}";
var endNSP = "<tr id=\"Info" + TypeX + TitleX + InstanceIDX + "\"><td class=\"InfoboxTableBottom Infobox" + TypeX + "Title\" colspan=\"2\">&nbsp;</td></tr></table><br/><div id=\"NoInfo" + TypeX + TitleX + InstanceIDX + "\" class=\"NoInfo" + TypeX + "\">No information available.</div></html>===}}}";
var end = "<tr id=\"Info" + TitleX + InstanceIDX + "\"><td class=\"InfoboxTableBottom Infobox" + TypeX + "Title\" colspan=\"2\">&nbsp;</td></tr></table><br/><div id=\"NoInfo" + TypeX + TitleX + InstanceIDX + "\" class=\"NoInfo" + TypeX + "\">No information available.</div></html>}}}";

//If Type is missing
if (Type === "unknown" || Type === null || Type.length === 0) {
wikify("{{InfoboxTypeError{\nType is mandatory! Allowed types are: " + validTypes.replace(/, $/, "") + "}}}", place);
return;
}
//If Type is wrong
else if (validTypes.indexOf(Type) === -1) {
wikify("{{InfoboxTypeError{\nYou entered a non-existent type! Allowed types are: " + validTypes.replace(/, $/, "") + "}}}", place);
return;
}
//If Type is okay
else if (validTypes.indexOf(Type) !== -1) {

//Check how many instances of the same type there are in a tiddler
var instanceCheck = store.getTiddlerText(tiddler.title);
var instanceInfobox = instanceCheck.match(/<<infobox/g); //Find all instances of the macro in the tiddler
if (instanceInfobox.length > 1) { //If there is more than one instance
var instanceInfoboxType = instanceCheck.match(/<<infobox[\w\W\n]*?Type:"[\w\s]*?"[\w\W\n]*?>>/g); //Get all infoboxes
var instanceInfoboxTypeResultEmpty = [];
var instanceInfoboxTypeResult = [];
var l;
for (l = 0; l < instanceInfoboxType.length; l++) {
if ((instanceInfoboxType[l].match("Type:\"" + Type + "\"") !== -1) && (InstanceID === "_DefaultID" || InstanceID === null || InstanceID.length === 0) && (instanceInfoboxType[l].indexOf(Type) !== -1)) { //If the infobox matches the type and does not have an InstanceID parameter, put it into array
instanceInfoboxTypeResultEmpty.push(instanceInfoboxType[l]);
}
if ((instanceInfoboxType[l].match("Type:\"" + Type + "\"") !== -1) && !(InstanceID === "_DefaultID" || InstanceID === null || InstanceID.length === 0) && (instanceInfoboxType[l].indexOf(Type) !== -1))  { //If the infobox matches the type and has an InstanceID parameter, put it into array
instanceInfoboxTypeResult.push(instanceInfoboxType[l]);
}
}

if (instanceInfoboxTypeResultEmpty.length > 1) { //If there is more than one infobox without athe InstanceID parameter
var instanceIDCount = 0;
var m;
for (m = 0; m < instanceInfoboxTypeResultEmpty.length; m++) { //Count the number or missing InstanceID parameters
if (instanceInfoboxTypeResultEmpty[m].match(/InstanceID:"[\w\s]*?"/g) !== null) {
instanceIDCount = instanceIDCount + 1;
}
}

if (instanceInfoboxType.length > instanceIDCount) { //If there are more infoboxes than InstanceID parameters per type
if (InstanceID === "_DefaultID" || InstanceID === null || InstanceID.length === 0) { //Display error message for all infoboxes without an InstanceID parameter
wikify("{{Infobox" + TypeX + "Error{\nThere are " + instanceInfoboxTypeResultEmpty.length + " infoboxes of \"" + Type + "\" type, but " + instanceIDCount + " ~IDs. This infobox does not have an ''~InstanceID'' parameter.<br/>When using more than one infobox of the same type, you need to add ''~InstanceID'' parameter to all of them. This parameter can be a random ''alphanumeric'' string and must be different for each infobox of the same type.}}}", place);
return;
}
}
} //End missing check

//Check for duplicate InstanceID parameters for a type
var instanceIDs = [];
var instanceIDMatch;
var n;
if (instanceInfoboxTypeResult.length > 1) { //If there is more than one infobox with the InstanceID parameter
for (n = 0; n < instanceInfoboxTypeResult.length; n++) { //Count the number or InstanceID parameters
if ((instanceInfoboxTypeResult[n].match(/InstanceID:"[\w\s]*?"/g) !== null) && !(InstanceID === "_DefaultID" || InstanceID === null || InstanceID.length === 0)) {
instanceIDMatch = instanceInfoboxTypeResult[n].match(/InstanceID:"[\w\s]*?"/g);
instanceIDs.push(instanceIDMatch);
}
}
var instanceIDsSorted = instanceIDs.sort();
var duplicateIDs = [];
var o;
for (o = 0; o < instanceIDsSorted.length - 1; o++) { //Find the duplicates
if (instanceIDsSorted[o+1] === instanceIDsSorted[o]) {
duplicateIDs.push(instanceIDsSorted[o]);
}
}
if (duplicateIDs.length > 1) {
wikify("{{Infobox" + TypeX + "Error{\nThis infobox has the same ''~InstanceID'' parameter (\"" + InstanceID + "\") as another infobox of the same type (\"" + Type + "\").<br/>Infoboxes of the same type must have ''unique ~IDs''.}}}", place);
return;
}
} //End duplicate check
} //End of checks when there's more than one instance

//Begin parsing parameters for output
var paramList = store.getTiddlerText("Infobox_"+ Type.replace(/[\s]/g, "_") + "##Content");
var paramListParsed = paramList.replace(/----\n/g, "").replace(/ /g, "_").split("\n"); //Get parameters
var paramCount = 0;
var param;
var k;
for (k = 0; k < paramListParsed.length; k++) {
param = getParam(params, paramListParsed[k], 'unknown');

//Output for section titles
if (paramListParsed[k].indexOf("Section-") !== -1) {
out += "<tr id=\"Section" + TitleX + paramListParsed[k].replace(/Section-/g, "") + InstanceIDX + "\"><td class=\"Infobox" + TypeX + "Subtitle\" colspan=\"2\">" + paramListParsed[k].replace(/Section-|\*\*[\w\W]*?$/g, "").replace(/_/g, " ") + "</td></tr>";
}
//Output for images
else if (paramListParsed[k].indexOf("Image-") !== -1) {
out += "<tr id=\"" + TitleX + paramListParsed[k].replace(/Image-/g, "") + InstanceIDX + "\"><td class=\"InfoboxCellImage\" colspan=\"2\"><img src=\"" + param + "\" alt=\"" + param + "\" title=\"" + param + "\" class=\"InfoboxImage\"/></td></tr>";
}
//Start output if using sides (left cell)
else if (paramListParsed[k].indexOf("Side1-") !== -1) {
out += "<tr id=\"" + TitleX + paramListParsed[k-1].replace(/Section-/g, "") + "Content" + InstanceIDX + "\"><td id=\"" + TitleX + paramListParsed[k].replace(/Side1-/g, "") + InstanceIDX + "\" class=\"InfoboxCellEqual\">" + param + "</td>";
}
//End output if using sides (right cell)
else if (paramListParsed[k].indexOf("Side2-") !== -1) {
out += "<td id=\"" + TitleX + paramListParsed[k].replace(/Side2-/g, "") + InstanceIDX + "\" class=\"InfoboxCellEqual\">" + param + "</td></tr>";
}
//Normal output
else {
out += "<tr id=\"" + TitleX + paramListParsed[k].replace(/ /g, "") + InstanceIDX + "\"><td class=\"InfoboxCellLeft\">" + paramListParsed[k].replace(/_/g, " ") + "</td><td class=\"InfoboxCellRight\">" + param + "</td></tr>";
}
//Hide lines with no information
if ((param === "unknown") && (paramListParsed[k].indexOf("Section-") === -1)) {
setStylesheet("#" + TitleX + paramListParsed[k].replace(/ /g, "") + InstanceIDX + " {display: none;}", "Infobox" + TypeX + paramListParsed[k] + TitleX + InstanceIDX);
} else {
setStylesheet("#" + TitleX + paramListParsed[k].replace(/ /g, "") + InstanceIDX + " {display: inherit;}", "Infobox" + TypeX + paramListParsed[k] + TitleX + InstanceIDX);
}
//Hide the whole table if all parameters are unknown
if (param === "unknown") { //First count how many params are unknown
paramCount = paramCount + 1;
}
if (paramCount === paramListParsed.length) { //If all params are unknown
setStylesheet("#Table" + TypeX + TitleX + InstanceIDX +  " {display: none;}\n", "Infobox" + TypeX + "Table" + TitleX  + InstanceIDX);
setStylesheet("#NoInfo" + TypeX + TitleX + InstanceIDX + " {display: inherit;}", "NoInfo" + TypeX + TitleX + InstanceIDX);
} else {
setStylesheet("#Table" + TypeX + TitleX + InstanceIDX + " {display: inherit;}\n", "Infobox" + TypeX + "Table" + TitleX  + InstanceIDX);
setStylesheet("#NoInfo" + TypeX + TitleX + InstanceIDX + " {display: none;}", "NoInfo" + TypeX + TitleX + InstanceIDX);
}
} //End parsing of parameters for output

//Hide section title if all params in the section are unknown (requires extra parsing of parameters by sections)
var section = paramList.replace(/Section-[\w\W\n]*?/g, "").replace(/ /g, "_").split("\n----\n"); //Get sections
var sectionParsed, sectionParams;
var sectionParamCount = 0;
var p, q;
if (section.length > 1) {
for (p = 0; p < section.length; p++) {
sectionParsed = section[p].split("\n"); //Split sections into parameters
for (q = 0; q < sectionParsed.length; q++) { //Parse the parameters
sectionParams = getParam(params, sectionParsed[q], 'unknown');
if (sectionParams === "unknown") { //Count how many parameters in the section are unknown
sectionParamCount = sectionParamCount + 1;
}
}
if (sectionParamCount === sectionParsed.length) {
setStylesheet("#Section" + TitleX + sectionParsed[0].replace(/Section-/g, "") + InstanceIDX + " {display: none;}", "Infobox" + TypeX + "Section" + sectionParsed[0] + Title.replace(/Section-/g, "") + InstanceIDX);
} else {
setStylesheet("#Section" + TitleX + sectionParsed[0].replace(/Section-/g, "") + InstanceIDX + " {display: inherit;}", "Infobox" + TypeX + "Section" + sectionParsed[0] + Title.replace(/Section-/g, "") + InstanceIDX);
}
sectionParamCount = 0; //Reset the count for the next section
}
}

//Final output
//If NestedSlidersPlugin and HTMLFormattingPlugin are installed and both options are true
if ((version.extensions.NestedSlidersPlugin && config.options.chkUseNestedSlidersPlugin === true) && (version.extensions.HTMLFormattingPlugin && config.options.chkUseHTMLFormattingPlugin === true)) {
wikify(startNSP + out + endNSPHFP, place);
}
//If NestedSlidersPlugin is installed and option is true, HTMLFormattingPlugin is not installed or option is false
else if ((version.extensions.NestedSlidersPlugin && config.options.chkUseNestedSlidersPlugin === true) && (!version.extensions.HTMLFormattingPlugin || config.options.chkUseHTMLFormattingPlugin === false)) {
wikify(startNSP + out + endNSP, place);
}
//If NestedSlidersPlugin and HTMLFormattingPlugin are not installed
else {
wikify(start + out + end, place);
}
}
}; //End of macro
} //End of install only once
//}}}
/***
|Name|[[InfoboxTablesPlugin]]|
|Source|[[InfoboxTablesPlugin]]|
|Documentation|[[InfoboxTablesPluginInfo]]|
|Version|(2.0.0) ALPHA/INCOMPLETE|
|Author|Kristjan Brezovnik|
|License||
|~CoreVersion|2.1|
|Requires||
|Makes use of|[[NestedSlidersPlugin|http://www.TiddlyTools.com/#NestedSlidersPlugin]]<br>[[HTMLFormattingPlugin|http://www.TiddlyTools.com/#HTMLFormattingPlugin]]|
|Type|plugin|
|Description|Provides infoboxes for different types of articles.|
***/

/***
!To Do
*Check why InfoboxTable class is not applied correctly (style attribute is required for some parameters instead of using class attribute)
*Display warning when InstanceIDs are duplicated
*InfoCellLeft and InfoCellRight get squeezed to InfoCellEqual width in Waterfox, Chrome and Safari, in IE and Opera, all columns are the same width - try using <col span="2"/>
*Add InfoboxInfo mechanism
**Add xxxInfoboxParams to InfoboxInfo, to enable copying of params when entering info
**config.shadowTiddlers.ToolbarCommands.replace(/ViewToolbar\|/,"ViewToolbar\|InfoboxInfo"); - for adding to EditToolbar
*Maybe change checking for sections and pasing of parameters, so that parameters are only parsed once
* Unify the way the IDs are written and join TypeX + TitleX + InstanceIDX into a single variable
***/

/***
!Configuration
<<option chkUseNestedSlidersPlugin>> Use [[NestedSlidersPlugin|http://www.TiddlyTools.com/#NestedSlidersPlugin]], if it's installed
<<option chkUseHTMLFormattingPlugin>> Use [[HTMLFormattingPlugin|http://www.TiddlyTools.com/#HTMLFormattingPlugin]], if it's installed ([[NestedSlidersPlugin|http://www.TiddlyTools.com/#NestedSlidersPlugin]] must be installed and enabled as well)
***/

/***
!Code
***/
//{{{
//Ensure that the plugin is only installed once
if (!version.extensions.InfoboxTablesPlugin) {
version.extensions.InfoboxTablesPlugin = {installed: true};
version.extensions.InfoboxTablesPlugin = {major: 2, minor: 0, revision: 0, date: new Date(2012,3,13)};

//Use NestedSlidersPlugin and HTMLFormattingPlugin, if they're installed
if (config.options.chkUseNestedSlidersPlugin === undefined) {config.options.chkUseNestedSlidersPlugin = true;}
if (config.options.chkUseHTMLFormattingPlugin === undefined) {config.options.chkUseHTMLFormattingPlugin = true;}
//}}}

/***
!!Generic Color Palette
***/
//{{{
config.shadowTiddlers.InfoboxTablesColorPalette = 
"InfoboxTableBackground: whitesmoke\n" + 
"InfoboxTableTopColor: whitesmoke\n" + 
"InfoboxTypeError: red\n";
//}}}

/***
!!Generic Stylesheet
***/
//{{{
config.shadowTiddlers.InfoboxTablesStylesheet = 
".InfoboxTable {border-collapse: separate; border: none 0px; border-spacing: 0px; border-radius: 10px; -moz-border-radius: 10px; -webkit-border-radius: 10px; width: 300px; font-size: 10px; font-weight: bold; background: [[InfoboxTablesColorPalette::InfoboxTableBackground]];}\n"+
".InfoboxTableTop, .InfoboxTableBottom {text-align: center; font-size: 16px; line-height: 120%;}\n" + 
".InfoboxTableTop {border: none 0px; border-radius: 10px 10px 0px 0px; -moz-border-radius: 10px 10px 0px 0px; -webkit-border-radius: 10px 10px 0px 0px;}\n" + 
".InfoboxTableBottom {border: none 0px; border-radius: 0px 0px 10px 10px; -moz-border-radius: 0px 0px 10px 10px; -webkit-border-radius: 0px 0px 10px 10px;}\n" + 
".InfoboxCellLeft, .InfoboxCellRight, .InfoboxCellEqual, .InfoboxCellImage {font-weight: normal; border: 1px solid; background: [[InfoboxTablesColorPalette::InfoboxTableBackground]];}\n"+
".InfoboxCellLeft {width: 100px;}\n" + 
".InfoboxCellRight {width: 200px;}\n" + 
".InfoboxCellEqual {width: 150px;}\n" + 
".InfoboxCellImage {width: 300px; text-align: center;}\n" + 
"img.InfoboxImage {max-width: 290px;}\n" + 
"#displayArea .viewer a.NestedSliderButton {border: 1px solid black; background: [[InfoboxTablesColorPalette::InfoboxTableBackground]]; padding: 1px; margin: 1px;} /* This makes the label/tooltip from the NestedSlidersPlugin look like a button */\n" + 
".FloatRight {float: right;}\n" + 
".SmallButton {font-size: 10px; line-height: 120%;}\n" + 
".InfoboxTypeError {width: 300px; background: [[InfoboxTablesColorPalette::InfoboxTypeError]]; font-weight: bold; border: solid 5px; border-radius: 5px; -moz-border-radius: 5px; -webkit-border-radius: 5px; padding: 5px 5px;}\n";
store.addNotification("InfoboxTablesStylesheet", refreshStyles);
//}}}

/***
!!Specific Color Palette, Stylesheet, Info
***/
//{{{
var list = store.getTaggedTiddlers("infobox");
var listTitle, listContent, listColors, listColorsTitle, listColorsSubtitle, paramListInfo, paramListInfoParsed;
var i, j;
var validTypes = "";
config.shadowTiddlers.InfoboxTablesInfo = "";
for (i = 0; i < list.length; i++) {
listTitle = list[i].title.replace(/Infobox|_| /g, "");
validTypes += list[i].title.replace(/Infobox_/, "").replace(/_/g, " ") + ", ";
listContent = store.getTiddlerText(list[i].title + "##Content");
listColorsTitle = store.getTiddlerText(list[i].title + "::Title");
listColorsSubtitle = store.getTiddlerText(list[i].title + "::Subtitle");
//Color Palette
config.shadowTiddlers.InfoboxTablesColorPalette += 
"Infobox" + listTitle + "Title: " + listColorsTitle + "\n" + 
"Infobox" + listTitle + "Subtitle: " + listColorsSubtitle + "\n";
//Stylesheet
config.shadowTiddlers.InfoboxTablesStylesheet += 
".Infobox" + listTitle + "Title {background: [[InfoboxTablesColorPalette::Infobox" + listTitle + "Title]];}\n" + 
".Infobox" + listTitle + "Subtitle {background: [[InfoboxTablesColorPalette::Infobox" + listTitle + "Subtitle]];}\n" + 
".NoInfo" + listTitle + " {width: 300px; background: [[InfoboxTablesColorPalette::Infobox" + listTitle + "Title]]; font-weight: bold; border: solid 2px; border-radius: 5px; -moz-border-radius: 5px; -webkit-border-radius: 5px; padding: 5px 5px;}\n" + 
".Infobox" + listTitle + "Error {width: 300px; background: [[InfoboxTablesColorPalette::InfoboxTypeError]]; font-weight: bold; border: solid 5px [[InfoboxTablesColorPalette::Infobox" + listTitle + "Title]]; border-radius: 5px; -moz-border-radius: 5px; -webkit-border-radius: 5px; padding: 5px 5px;}\n";
store.addNotification("InfoboxTablesStylesheet", refreshStyles);
//Info
paramListInfo = listContent.split("\n");
paramListInfoParsed = "";
for (j = 0; j < paramListInfo.length; j++) {
if (paramListInfo[j].indexOf("Section-") === -1) {
paramListInfoParsed += paramListInfo[j].replace(/Image-|Side1-|Side2-/g, "") + "\n";
}
}
config.shadowTiddlers.InfoboxTablesInfo += 
"!" + listTitle.toLowerCase() + "InfoboxInfo\n" + paramListInfoParsed;
}
//}}}

/***
!!Infobox Macro
***/
//{{{
config.macros.infobox = {};
config.macros.infobox.handler = function (place,macroName,params,wikifier,paramString,tiddler) {

params = paramString.parseParams(null, null, true);

var Type = getParam(params, 'Type', 'unknown');
var Title = getParam(params, 'Title', tiddler.title);
var InstanceID = getParam(params, 'InstanceID', '_DefaultID');
var TypeX = Type.replace(/[\s]/g, "");
var TitleX = Title.replace(/[\W\s]/g, "");
var InstanceIDX = InstanceID.replace(/[\s\W]/g, "");

//Output for beginning of table
var startNSP = "{{FloatRight{++++{{NestedSliderButton{[Show infobox|Show infobox][Hide infobox|Hide infobox]}}}<html><table id=\"Table" + TypeX + TitleX + InstanceIDX + "\" class=\"InfoboxTable\" style=\"border-collapse: separate; border: none 0px;\"><tr id=\"Title" + TitleX + InstanceIDX + "\"><td class=\"InfoboxTableTop Infobox" + TypeX + "Title\" colspan=\"2\">" + Title + "</td></tr>";
var start = "{{FloatRight{<html><table id=\"Table" + TypeX + TitleX + InstanceIDX + "\" class=\"InfoboxTable\" style=\"border-collapse: separate; border: none 0px;\"><tr id=\"Title" + TitleX + InstanceIDX + "\"><td class=\"InfoboxTableTop Infobox" + TypeX + "Title\" colspan=\"2\">" + Title + "</td></tr>";
//Output for content of table
var out = "";
var outE = "";
//Output for end of table
var endNSPHFP = "<tr id=\"Info" + TypeX + TitleX + InstanceIDX + "\"><td class=\"InfoboxTableBottom Infobox" + TypeX + "Title\" colspan=\"2\">{{SmallButton{+++^*{{NestedSliderButton{[Show info|Show info][Hide info|Hide info]}}}...<<tiddler [[InfoboxTablesInfo##" + TypeX.toLowerCase() + "InfoboxInfo]]>>===}}}</td></tr></table><br/><div id=\"NoInfo" + TypeX + TitleX + InstanceIDX + "\" class=\"NoInfo" + TypeX + "\">No information available.</div></html>===}}}";
var endNSP = "<tr id=\"Info" + TypeX + TitleX + InstanceIDX + "\"><td class=\"InfoboxTableBottom Infobox" + TypeX + "Title\" colspan=\"2\">&nbsp;</td></tr></table><br/><div id=\"NoInfo" + TypeX + TitleX + InstanceIDX + "\" class=\"NoInfo" + TypeX + "\">No information available.</div></html>===}}}";
var end = "<tr id=\"Info" + TitleX + InstanceIDX + "\"><td class=\"InfoboxTableBottom Infobox" + TypeX + "Title\" colspan=\"2\">&nbsp;</td></tr></table><br/><div id=\"NoInfo" + TypeX + TitleX + InstanceIDX + "\" class=\"NoInfo" + TypeX + "\">No information available.</div></html>}}}";

//If Type is missing
if (Type === "unknown" || Type === null || Type.length === 0) {
wikify("{{InfoboxTypeError{\nType is mandatory! Allowed types are: " + validTypes.replace(/, $/, "") + "}}}", place);
return;
}
//If Type is wrong
else if (validTypes.indexOf(Type) === -1) {
wikify("{{InfoboxTypeError{\nYou entered a non-existent type! Allowed types are: " + validTypes.replace(/, $/, "") + "}}}", place);
return;
}
//If Type is okay
else if (validTypes.indexOf(Type) !== -1) {

//Check how many instances of the same type there are in a tiddler
var instanceCheck = store.getTiddlerText(tiddler.title);
var instanceInfobox = instanceCheck.match(/<<infobox/g); //Find all instances of the macro in the tiddler
if (instanceInfobox.length > 1) { //If there is more than one instance
var instanceInfoboxType = instanceCheck.match(/<<infobox[\w\W\n]*?Type:"[\w\s]*?"[\w\W\n]*?>>/g); //Get all infoboxes
var instanceInfoboxTypeResultEmpty = [];
var instanceInfoboxTypeResult = [];
var l;
for (l = 0; l < instanceInfoboxType.length; l++) {
if ((instanceInfoboxType[l].match("Type:\"" + Type + "\"") !== -1) && (InstanceID === "_DefaultID" || InstanceID === null || InstanceID.length === 0) && (instanceInfoboxType[l].indexOf(Type) !== -1)) { //If the infobox matches the type and does not have an InstanceID parameter, put it into array
instanceInfoboxTypeResultEmpty.push(instanceInfoboxType[l]);
}
if ((instanceInfoboxType[l].match("Type:\"" + Type + "\"") !== -1) && !(InstanceID === "_DefaultID" || InstanceID === null || InstanceID.length === 0) && (instanceInfoboxType[l].indexOf(Type) !== -1))  { //If the infobox matches the type and has an InstanceID parameter, put it into array
instanceInfoboxTypeResult.push(instanceInfoboxType[l]);
}
}

if (instanceInfoboxTypeResultEmpty.length > 1) { //If there is more than one infobox without athe InstanceID parameter
var instanceIDCount = 0;
var m;
for (m = 0; m < instanceInfoboxTypeResultEmpty.length; m++) { //Count the number or missing InstanceID parameters
if (instanceInfoboxTypeResultEmpty[m].match(/InstanceID:"[\w\s]*?"/g) !== null) {
instanceIDCount = instanceIDCount + 1;
}
}

if (instanceInfoboxType.length > instanceIDCount) { //If there are more infoboxes than InstanceID parameters per type
if (InstanceID === "_DefaultID" || InstanceID === null || InstanceID.length === 0) { //Display error message for all infoboxes without an InstanceID parameter
wikify("{{Infobox" + TypeX + "Error{\nThere are " + instanceInfoboxTypeResultEmpty.length + " infoboxes of \"" + Type + "\" type, but " + instanceIDCount + " ~IDs. This infobox does not have an ''~InstanceID'' parameter.<br/>When using more than one infobox of the same type, you need to add ''~InstanceID'' parameter to all of them. This parameter can be a random ''alphanumeric'' string and must be different for each infobox of the same type.}}}", place);
return;
}
}
} //End missing check

//Check for duplicate InstanceID parameters for a type
var instanceIDs = [];
var instanceIDMatch;
var n;
if (instanceInfoboxTypeResult.length > 1) { //If there is more than one infobox with the InstanceID parameter
for (n = 0; n < instanceInfoboxTypeResult.length; n++) { //Count the number or InstanceID parameters
if ((instanceInfoboxTypeResult[n].match(/InstanceID:"[\w\s]*?"/g) !== null) && !(InstanceID === "_DefaultID" || InstanceID === null || InstanceID.length === 0)) {
instanceIDMatch = instanceInfoboxTypeResult[n].match(/InstanceID:"[\w\s]*?"/g);
instanceIDs.push(instanceIDMatch);
}
}
var instanceIDsSorted = instanceIDs.sort();
var duplicateIDs = [];
var o;
for (o = 0; o < instanceIDsSorted.length - 1; o++) { //Find the duplicates
if (instanceIDsSorted[o+1] === instanceIDsSorted[o]) {
duplicateIDs.push(instanceIDsSorted[o]);
}
}
if (duplicateIDs.length > 1) {
wikify("{{Infobox" + TypeX + "Error{\nThis infobox has the same ''~InstanceID'' parameter (\"" + InstanceID + "\") as another infobox of the same type (\"" + Type + "\").<br/>Infoboxes of the same type must have ''unique ~IDs''.}}}", place);
return;
}
} //End duplicate check
} //End of checks when there's more than one instance

//Begin parsing parameters for output
var paramList = store.getTiddlerText("Infobox_"+ Type.replace(/[\s]/g, "_") + "##Content");
var paramListParsed = paramList.replace(/----\n/g, "").replace(/ /g, "_").split("\n"); //Get parameters
var paramCount = 0;
var param;
var k;
for (k = 0; k < paramListParsed.length; k++) {
param = getParam(params, paramListParsed[k], 'unknown');

//Output for section titles
if (paramListParsed[k].indexOf("Section-") !== -1) {
out += "<tr id=\"Section" + TitleX + paramListParsed[k].replace(/Section-/g, "") + InstanceIDX + "\"><td class=\"Infobox" + TypeX + "Subtitle\" colspan=\"2\">" + paramListParsed[k].replace(/Section-|\*\*[\w\W]*?$/g, "").replace(/_/g, " ") + "</td></tr>";
}
//Output for images
else if (paramListParsed[k].indexOf("Image-") !== -1) {
out += "<tr id=\"" + TitleX + paramListParsed[k].replace(/Image-/g, "") + InstanceIDX + "\"><td class=\"InfoboxCellImage\" colspan=\"2\"><img src=\"" + param + "\" alt=\"" + param + "\" title=\"" + param + "\" class=\"InfoboxImage\"/></td></tr>";
}
//Start output if using sides (left cell)
else if ((paramListParsed[k].indexOf("Side1-") !== -1) || (paramListParsed[k].indexOf("Side2-") !== -1)) {
if (paramListParsed[k].indexOf("Side1-") !== -1) {
out += "<tr id=\"" + TitleX + paramListParsed[k-1].replace(/Section-/g, "") + "Content" + InstanceIDX + "\"><td id=\"" + TitleX + paramListParsed[k].replace(/Side1-/g, "") + InstanceIDX + "\" class=\"InfoboxCellEqual\">" + param + "</td>";
}
//End output if using sides (right cell)
else if (paramListParsed[k].indexOf("Side2-") !== -1) {
out += "<td id=\"" + TitleX + paramListParsed[k].replace(/Side2-/g, "") + InstanceIDX + "\" class=\"InfoboxCellEqual\">" + param + "</td></tr>";
}
if (outE.indexOf("</tr>") !== -1) {
//out += outE;
}
}
//Normal output
else {
if ((paramList.indexOf("Side1-") !== -1) || (paramList.indexOf("Side2-") !== -1)) { //If parameters contain Side1- or Side2-
out += "<tr id=\"" + TitleX + paramListParsed[k].replace(/ /g, "") + InstanceIDX + "\"><td class=\"InfoboxCellEqual\">" + paramListParsed[k].replace(/_/g, " ") + "</td><td class=\"InfoboxCellEqual\">" + param + "</td></tr>";
}
else {
out += "<tr id=\"" + TitleX + paramListParsed[k].replace(/ /g, "") + InstanceIDX + "\"><td class=\"InfoboxCellLeft\">" + paramListParsed[k].replace(/_/g, " ") + "</td><td class=\"InfoboxCellRight\">" + param + "</td></tr>";
}
}
//Hide lines with no information
if ((param === "unknown") && (paramListParsed[k].indexOf("Section-") === -1)) {
setStylesheet("#" + TitleX + paramListParsed[k].replace(/Image-| /g, "") + InstanceIDX + " {display: none;}", "Infobox" + TypeX + paramListParsed[k] + TitleX + InstanceIDX);
} else {
setStylesheet("#" + TitleX + paramListParsed[k].replace(/Image-| /g, "") + InstanceIDX + " {display: inherit;}", "Infobox" + TypeX + paramListParsed[k] + TitleX + InstanceIDX);
}
//Hide the whole table if all parameters are unknown
if (param === "unknown") { //First count how many params are unknown
paramCount = paramCount + 1;
}
if (paramCount === paramListParsed.length) { //If all params are unknown
setStylesheet("#Table" + TypeX + TitleX + InstanceIDX +  " {display: none;}\n", "Infobox" + TypeX + "Table" + TitleX  + InstanceIDX);
setStylesheet("#NoInfo" + TypeX + TitleX + InstanceIDX + " {display: inherit;}", "NoInfo" + TypeX + TitleX + InstanceIDX);
} else {
setStylesheet("#Table" + TypeX + TitleX + InstanceIDX + " {display: inherit;}\n", "Infobox" + TypeX + "Table" + TitleX  + InstanceIDX);
setStylesheet("#NoInfo" + TypeX + TitleX + InstanceIDX + " {display: none;}", "NoInfo" + TypeX + TitleX + InstanceIDX);
}
} //End parsing of parameters for output

//Hide section title if all params in the section are unknown (requires extra parsing of parameters by sections)
var section = paramList.replace(/Section-[\w\W\n]*?/g, "").replace(/ /g, "_").split("\n----\n"); //Get sections
var sectionParsed, sectionParams;
var sectionParamCount = 0;
var p, q;
if (section.length > 1) {
for (p = 0; p < section.length; p++) {
sectionParsed = section[p].split("\n"); //Split sections into parameters
for (q = 0; q < sectionParsed.length; q++) { //Parse the parameters
sectionParams = getParam(params, sectionParsed[q], 'unknown');
if (sectionParams === "unknown") { //Count how many parameters in the section are unknown
sectionParamCount = sectionParamCount + 1;
}
}
if (sectionParamCount === sectionParsed.length) {
setStylesheet("#Section" + TitleX + sectionParsed[0].replace(/Section-/g, "") + InstanceIDX + " {display: none;}", "Infobox" + TypeX + "Section" + sectionParsed[0] + Title.replace(/Section-/g, "") + InstanceIDX);
setStylesheet(TitleX + sectionParsed[0].replace(/Section-/g, "") + "Content" + InstanceIDX + " {display: none;}", "Infobox" + TypeX + "Section" + sectionParsed[0] + Title.replace(/Section-/g, "") + "Content" + InstanceIDX);
} else {
setStylesheet("#Section" + TitleX + sectionParsed[0].replace(/Section-/g, "") + InstanceIDX + " {display: inherit;}", "Infobox" + TypeX + "Section" + sectionParsed[0] + Title.replace(/Section-/g, "") + InstanceIDX);
setStylesheet(TitleX + sectionParsed[0].replace(/Section-/g, "") + "Content" + InstanceIDX + " {display: inherit;}", "Infobox" + TypeX + "Section" + sectionParsed[0] + Title.replace(/Section-/g, "") + "Content" + InstanceIDX);
}
sectionParamCount = 0; //Reset the count for the next section
}
}

//Final output
//If NestedSlidersPlugin and HTMLFormattingPlugin are installed and both options are true
if ((version.extensions.NestedSlidersPlugin && config.options.chkUseNestedSlidersPlugin === true) && (version.extensions.HTMLFormattingPlugin && config.options.chkUseHTMLFormattingPlugin === true)) {
wikify(startNSP + out + endNSPHFP, place);
}
//If NestedSlidersPlugin is installed and option is true, HTMLFormattingPlugin is not installed or option is false
else if ((version.extensions.NestedSlidersPlugin && config.options.chkUseNestedSlidersPlugin === true) && (!version.extensions.HTMLFormattingPlugin || config.options.chkUseHTMLFormattingPlugin === false)) {
wikify(startNSP + out + endNSP, place);
}
//If NestedSlidersPlugin and HTMLFormattingPlugin are not installed
else {
wikify(start + out + end, place);
}
}
}; //End of macro
} //End of install only once
//}}}
/***
|Name|[[InfoboxTablesPlugin]]|
|Source|[[InfoboxTablesPlugin]]|
|Documentation|[[InfoboxTablesPluginInfo]]|
|Version|(2.0.0) ALPHA/INCOMPLETE|
|Author|Kristjan Brezovnik|
|License||
|~CoreVersion|2.1|
|Requires||
|Makes use of|[[NestedSlidersPlugin|http://www.TiddlyTools.com/#NestedSlidersPlugin]]<br>[[HTMLFormattingPlugin|http://www.TiddlyTools.com/#HTMLFormattingPlugin]]|
|Type|plugin|
|Description|Provides customizable infoboxes for different types of articles.|
***/

/***
!To Do
*Display warning when InstanceIDs are duplicated
*InfoCellLeft and InfoCellRight get squeezed to InfoCellEqual width in Waterfox, Chrome and Safari, in IE and Opera, all columns are the same width
**Lines with Side1/2 parameters don't correctly hide section title in IE, but the table is displayed correctly
*Maybe change checking for sections and passing of parameters, so that parameters are only parsed once
*Check why InfoboxTable class is not applied correctly (style attribute is required for some parameters instead of using class attribute)
*Add InfoboxInfo mechanism
**Add xxxInfoboxParams to InfoboxInfo, to enable copying of params when entering info
**config.shadowTiddlers.ToolbarCommands.replace(/ViewToolbar\|/,"ViewToolbar\|InfoboxInfo"); - for adding to EditToolbar
*Add the option of shorthand for parameters: Participation at important events ((paie)) - ignore stuff in double brackets in Info dropdown; remove )), split by ((, use paramsListParsed(k-1)

***/

/***
!Configuration
<<option chkUseNestedSlidersPlugin>> Use [[NestedSlidersPlugin|http://www.TiddlyTools.com/#NestedSlidersPlugin]], if it's installed
<<option chkUseHTMLFormattingPlugin>> Use [[HTMLFormattingPlugin|http://www.TiddlyTools.com/#HTMLFormattingPlugin]], if it's installed ([[NestedSlidersPlugin|http://www.TiddlyTools.com/#NestedSlidersPlugin]] must be installed and enabled as well)
***/

/***
!Code
***/
//{{{
//Ensure that the plugin is only installed once
if (!version.extensions.InfoboxTablesPlugin) {
version.extensions.InfoboxTablesPlugin = {installed: true};
version.extensions.InfoboxTablesPlugin = {major: 2, minor: 0, revision: 0, date: new Date(2012,3,13)};

//Use NestedSlidersPlugin and HTMLFormattingPlugin, if they're installed
if (config.options.chkUseNestedSlidersPlugin === undefined) {config.options.chkUseNestedSlidersPlugin = true;}
if (config.options.chkUseHTMLFormattingPlugin === undefined) {config.options.chkUseHTMLFormattingPlugin = true;}
//}}}

/***
!!Generic Color Palette
***/
//{{{
config.shadowTiddlers.InfoboxTablesColorPalette = 
"InfoboxTableBackground: whitesmoke\n" + 
"InfoboxTableTopColor: whitesmoke\n" + 
"InfoboxTypeError: red\n";
//}}}

/***
!!Generic Stylesheet
***/
//{{{
config.shadowTiddlers.InfoboxTablesStylesheet = 
".InfoboxTable {border-collapse: separate; border: none 0px; border-spacing: 0px; border-radius: 10px; -moz-border-radius: 10px; -webkit-border-radius: 10px; width: 300px; font-size: 10px; font-weight: bold; background: [[InfoboxTablesColorPalette::InfoboxTableBackground]];}\n"+
".InfoboxTableTop, .InfoboxTableBottom {text-align: center; font-size: 16px; line-height: 120%;}\n" + 
".InfoboxTableTop {border: none 0px; border-radius: 10px 10px 0px 0px; -moz-border-radius: 10px 10px 0px 0px; -webkit-border-radius: 10px 10px 0px 0px;}\n" + 
".InfoboxTableBottom {border: none 0px; border-radius: 0px 0px 10px 10px; -moz-border-radius: 0px 0px 10px 10px; -webkit-border-radius: 0px 0px 10px 10px;}\n" + 
".InfoboxCellLeft, .InfoboxCellRight, .InfoboxCellEqual, .InfoboxCellImage {font-weight: normal; border: 1px solid; background: [[InfoboxTablesColorPalette::InfoboxTableBackground]];}\n"+
".InfoboxCellLeft {width: 100px;}\n" + 
".InfoboxCellRight {width: 200px;}\n" + 
".InfoboxCellEqual {width: 150px;}\n" + 
".InfoboxCellImage {width: 300px; text-align: center;}\n" + 
"img.InfoboxImage {max-width: 290px;}\n" + 
"#displayArea .viewer a.NestedSliderButton {border: 1px solid black; background: [[InfoboxTablesColorPalette::InfoboxTableBackground]]; padding: 1px; margin: 1px;} /* This makes the label/tooltip from the NestedSlidersPlugin look like a button */\n" + 
".FloatRight {float: right;}\n" + 
".SmallButton {font-size: 10px; line-height: 120%;}\n" + 
".InfoboxTypeError {width: 300px; background: [[InfoboxTablesColorPalette::InfoboxTypeError]]; font-weight: bold; border: solid 5px; border-radius: 5px; -moz-border-radius: 5px; -webkit-border-radius: 5px; padding: 5px 5px; float: right;}\n";
store.addNotification("InfoboxTablesStylesheet", refreshStyles);
//}}}

/***
!!Specific Color Palette, Stylesheet, Info
***/
//{{{
var list = store.getTaggedTiddlers("infobox");
var listTitle, listContent, listColors, listColorsTitle, listColorsSubtitle, paramListInfo, paramListInfoParsed;
var i, j;
var validTypes = "";
config.shadowTiddlers.InfoboxTablesInfo = "";
for (i = 0; i < list.length; i++) {
listTitle = list[i].title.replace(/Infobox|_| /g, "");
validTypes += list[i].title.replace(/Infobox_/, "").replace(/_/g, " ") + ", ";
listContent = store.getTiddlerText(list[i].title + "##Content");
listColorsTitle = store.getTiddlerText(list[i].title + "::Title");
listColorsSubtitle = store.getTiddlerText(list[i].title + "::Subtitle");
//Color Palette
config.shadowTiddlers.InfoboxTablesColorPalette += 
"Infobox" + listTitle + "Title: " + listColorsTitle + "\n" + 
"Infobox" + listTitle + "Subtitle: " + listColorsSubtitle + "\n";
//Stylesheet
config.shadowTiddlers.InfoboxTablesStylesheet += 
".Infobox" + listTitle + "Title {background: [[InfoboxTablesColorPalette::Infobox" + listTitle + "Title]];}\n" + 
".Infobox" + listTitle + "Subtitle {background: [[InfoboxTablesColorPalette::Infobox" + listTitle + "Subtitle]];}\n" + 
".NoInfo" + listTitle + " {width: 300px; background: [[InfoboxTablesColorPalette::Infobox" + listTitle + "Title]]; font-weight: bold; border: solid 2px; border-radius: 5px; -moz-border-radius: 5px; -webkit-border-radius: 5px; padding: 5px 5px;}\n" + 
".Infobox" + listTitle + "Error {width: 300px; background: [[InfoboxTablesColorPalette::InfoboxTypeError]]; font-weight: bold; border: solid 5px [[InfoboxTablesColorPalette::Infobox" + listTitle + "Title]]; border-radius: 5px; -moz-border-radius: 5px; -webkit-border-radius: 5px; padding: 5px 5px; float: right;}\n";
store.addNotification("InfoboxTablesStylesheet", refreshStyles);
//Info
paramListInfo = listContent.split("\n");
paramListInfoParsed = "";
for (j = 0; j < paramListInfo.length; j++) {
if (paramListInfo[j].indexOf("Section-") === -1) {
paramListInfoParsed += paramListInfo[j].replace(/Image-|Side1-|Side2-/g, "") + "\n";
}
}
config.shadowTiddlers.InfoboxTablesInfo += 
"!" + listTitle.toLowerCase() + "InfoboxInfo\n" + paramListInfoParsed;
}
//}}}

/***
!!Infobox Macro
***/
//{{{
config.macros.infobox = {};
config.macros.infobox.handler = function (place,macroName,params,wikifier,paramString,tiddler) {

params = paramString.parseParams(null, null, true);

var Type = getParam(params, 'Type', 'unknown');
var Title = getParam(params, 'Title', tiddler.title);
var InstanceID = getParam(params, 'InstanceID', 'DefaultID');
var TypeX = Type.replace(/[\s]/g, "");
var TitleX = Title.replace(/[\W\s]/g, "");
var InstanceIDX = InstanceID.replace(/[\s\W]/g, "");
var TTIX = TypeX + TitleX + InstanceIDX;

//Output for beginning of table
var startNSP = "{{FloatRight{++++{{NestedSliderButton{[Show infobox|Show infobox][Hide infobox|Hide infobox]}}}<html><table id=\"Table" + TTIX + "\" class=\"InfoboxTable\" style=\"border-collapse: separate; border: none 0px;\"><tr id=\"Title" + TTIX + "\"><td class=\"InfoboxTableTop Infobox" + TypeX + "Title\" colspan=\"4\">" + Title + "</td></tr><tr width=\"300\"><td width=\"100\"></td><td width=\"50\"></td><td width=\"50\"></td><td width=\"100\"></td></tr>";
var start = "{{FloatRight{<html><table id=\"Table" + TTIX + "\" class=\"InfoboxTable\" style=\"border-collapse: separate; border: none 0px;\"><tr id=\"Title" + TitleX + InstanceIDX + "\"><td class=\"InfoboxTableTop Infobox" + TypeX + "Title\" colspan=\"4\">" + Title + "</td></tr><tr width=\"300\"><td width=\"100\"></td><td width=\"50\"></td><td width=\"50\"></td><td width=\"100\"></td></tr>";
//Output for content of table
var out = "";
//Output for end of table
var endNSPHFP = "<tr id=\"Info" + TTIX + "\"><td class=\"InfoboxTableBottom Infobox" + TypeX + "Title\" colspan=\"4\">{{SmallButton{+++^*{{NestedSliderButton{[Show info|Show info][Hide info|Hide info]}}}...<<tiddler [[InfoboxTablesInfo##" + TypeX.toLowerCase() + "InfoboxInfo]]>>===}}}</td></tr></table><br/><div id=\"NoInfo" + TTIX + "\" class=\"NoInfo" + TypeX + "\">No information available.</div></html>===}}}";
var endNSP = "<tr id=\"Info" + TTIX + "\"><td class=\"InfoboxTableBottom Infobox" + TypeX + "Title\" colspan=\"4\">&nbsp;</td></tr></table><br/><div id=\"NoInfo" + TTIX + "\" class=\"NoInfo" + TypeX + "\">No information available.</div></html>===}}}";
var end = "<tr id=\"Info" + TTIX + "\"><td class=\"InfoboxTableBottom Infobox" + TypeX + "Title\" colspan=\"4\">&nbsp;</td></tr></table><br/><div id=\"NoInfo" + TTIX + "\" class=\"NoInfo" + TypeX + "\">No information available.</div></html>}}}";

//If Type is missing
if (Type === "unknown" || Type === null || Type.length === 0) {
wikify("{{InfoboxTypeError{\nType is mandatory! Allowed types are: " + validTypes.replace(/, $/, "") + "}}}", place);
return;
}
//If Type is wrong
else if (validTypes.indexOf(Type) === -1) {
wikify("{{InfoboxTypeError{\nYou entered a non-existent type! Allowed types are: " + validTypes.replace(/, $/, "") + "}}}", place);
return;
}
//If Type is okay
else if (validTypes.indexOf(Type) !== -1) {

//Check how many instances of the same type there are in a tiddler
var instanceCheck = store.getTiddlerText(tiddler.title);
var instanceInfobox = instanceCheck.match(/<<infobox/g); //Find all instances of the macro in the tiddler
if (instanceInfobox.length > 1) { //If there is more than one instance
var instanceInfoboxType = instanceCheck.match(/<<infobox[\w\W\n]*?Type:"[\w\s]*?"[\w\W\n]*?>>/g); //Get all infoboxes
var instanceInfoboxTypeResultEmpty = [];
var instanceInfoboxTypeResult = [];
var l;
for (l = 0; l < instanceInfoboxType.length; l++) {
if ((instanceInfoboxType[l].match("Type:\"" + Type + "\"") !== -1) && (InstanceID === "DefaultID" || InstanceID === null || InstanceID.length === 0) && (instanceInfoboxType[l].indexOf(Type) !== -1)) { //If the infobox matches the type and does not have an InstanceID parameter, put it into array
instanceInfoboxTypeResultEmpty.push(instanceInfoboxType[l]);
}
if ((instanceInfoboxType[l].match("Type:\"" + Type + "\"") !== -1) && !(InstanceID === "DefaultID" || InstanceID === null || InstanceID.length === 0) && (instanceInfoboxType[l].indexOf(Type) !== -1))  { //If the infobox matches the type and has an InstanceID parameter, put it into array
instanceInfoboxTypeResult.push(instanceInfoboxType[l]);
}
}

if (instanceInfoboxTypeResultEmpty.length > 1) { //If there is more than one infobox without the InstanceID parameter
var instanceIDCount = 0;
var m;
for (m = 0; m < instanceInfoboxTypeResultEmpty.length; m++) { //Count the number or missing InstanceID parameters
if (instanceInfoboxTypeResultEmpty[m].match(/InstanceID:"[\w\s]*?"/g) !== null) {
instanceIDCount = instanceIDCount + 1;
}
}

if (instanceInfoboxType.length > instanceIDCount) { //If there are more infoboxes than InstanceID parameters per type
if (InstanceID === "DefaultID" || InstanceID === null || InstanceID.length === 0) { //Display error message for all infoboxes without an InstanceID parameter
wikify("{{Infobox" + TypeX + "Error{\nThere are " + instanceInfoboxTypeResultEmpty.length + " infoboxes of \"" + Type + "\" type, but " + instanceIDCount + " ~IDs. This infobox does not have an ''~InstanceID'' parameter.<br/>When using more than one infobox of the same type, you need to add ''~InstanceID'' parameter to all of them. This parameter can be a random ''alphanumeric'' string and must be different for each infobox of the same type.}}}", place);
return;
}
}
} //End missing check

//Check for duplicate InstanceID parameters for a type
var instanceIDs = [];
var instanceIDMatch;
var n;
if (instanceInfoboxTypeResult.length > 1) { //If there is more than one infobox with the InstanceID parameter
for (n = 0; n < instanceInfoboxTypeResult.length; n++) { //Count the number or InstanceID parameters
if ((instanceInfoboxTypeResult[n].match(/InstanceID:"[\w\s]*?"/g) !== null) && !(InstanceID === "DefaultID" || InstanceID === null || InstanceID.length === 0)) {
instanceIDMatch = instanceInfoboxTypeResult[n].match(/InstanceID:"[\w\s]*?"/g);
instanceIDs.push(instanceIDMatch);
}
}
var instanceIDsSorted = instanceIDs.sort();
//var instanceIDsCropped = instanceIDs.replace(/InstanceID:"|"/g, "");
//var instanceIDsSorted = instanceIDsCropped.sort();
//var duplicateIDs = [];
var duplicateIDs = 0;
var o;
for (o = 0; o < instanceIDsSorted.length - 1; o++) { //Find the duplicates
if (instanceIDsSorted[o] === instanceIDsSorted[o+1]) { //DOESN'T PUSH - Perhaps the problem lies in the fact that the array contains InstanceID:"..."" values, which is different type of array, SEE http://www.w3schools.com/js/js_loop_for_in.asp
//duplicateIDs.push(instanceIDsSorted[o]);
duplicateIDs = duplicateIDs +1;
}
}
//alert(duplicateIDs);
/*
var x, y; //Alternative version
for (x = 0; x < instanceIDsSorted.length; x++) { //Find the duplicates
for (y = x + 1; y < instanceIDsSorted.length; y++) {
//alert(instanceIDsSorted[x]+" - "+instanceIDsSorted[y]);
if (instanceIDsSorted[x] === instanceIDsSorted[y]) {
duplicateIDs.push(ps);
}
}
}
*/
if (duplicateIDs > 0) {
wikify("{{Infobox" + TypeX + "Error{\nThis infobox has the same ''~InstanceID'' parameter (\"" + InstanceID + "\") as another infobox of the same type (\"" + Type + "\").<br/>Infoboxes of the same type must have ''unique ~IDs''.}}}", place);
return;
}
} //End duplicate check
} //End of checks when there's more than one instance

//Begin parsing parameters for output
var paramList = store.getTiddlerText("Infobox_"+ Type.replace(/[\s]/g, "_") + "##Content");
var paramListParsed = paramList.replace(/----\n/g, "").replace(/ /g, "_").split("\n"); //Get parameters
var paramCount = 0;
var param;
var k;
for (k = 0; k < paramListParsed.length; k++) {
param = getParam(params, paramListParsed[k], 'unknown');

//Output for section titles
if (paramListParsed[k].indexOf("Section-") !== -1) {
out += "<tr id=\"Section" + TTIX + paramListParsed[k].replace(/Section-|\*\*[\w\W]*?$/g, "") + "\"><td class=\"Infobox" + TypeX + "Subtitle\" colspan=\"4\">" + paramListParsed[k].replace(/Section-|\*\*[\w\W]*?$/g, "").replace(/_/g, " ") + "</td></tr>";
}
//Output for images
else if (paramListParsed[k].indexOf("Image-") !== -1) {
out += "<tr id=\"" + TTIX + paramListParsed[k].replace(/Image-/g, "") + "\"><td class=\"InfoboxCellImage\" colspan=\"4\"><img src=\"" + param + "\" alt=\"" + param + "\" title=\"" + param + "\" class=\"InfoboxImage\"/></td></tr>";
}
//Start output if using sides (left cell)
else if (paramListParsed[k].indexOf("Side1-") !== -1) {
out += "<tr id=\"Content" + TTIX + paramListParsed[k-1].replace(/Section-|\*\*[\w\W]*?$/g, "") + "\"><td class=\"InfoboxCellEqual\" colspan=\"2\">" + param + "</td>";
}
//End output if using sides (right cell)
else if (paramListParsed[k].indexOf("Side2-") !== -1) {
out += "<td class=\"InfoboxCellEqual\" colspan=\"2\">" + param + "</td></tr>";
}
//Normal output
else {
//if ((paramList.indexOf("xSide1-") !== -1) || (paramList.indexOf("xSide2-") !== -1)) { //If parameters contain Side1- or Side2-
//out += "<tr id=\"" + TTIX + paramListParsed[k].replace(/ /g, "") + "\"><td class=\"InfoboxCellEqual\">" + paramListParsed[k].replace(/_/g, " ") + "</td><td class=\"InfoboxCellEqual\">" + param + "</td></tr>";
//}
//else {
out += "<tr id=\"" + TTIX + paramListParsed[k].replace(/ /g, "") + "\"><td class=\"InfoboxCellLeft\">" + paramListParsed[k].replace(/_/g, " ") + "</td><td class=\"InfoboxCellRight\" colspan=\"3\">" + param + "</td></tr>";
//}
}
//Hide lines with no information
if ((param === "unknown") && (paramListParsed[k].indexOf("Section-") === -1)) {
setStylesheet("#" + TTIX + paramListParsed[k].replace(/Image-| /g, "") + " {display: none;}", "Infobox" + TTIX + paramListParsed[k]);
} else {
setStylesheet("#" + TTIX + paramListParsed[k].replace(/Image-| /g, "") + " {display: inherit;}", "Infobox" + TTIX + paramListParsed[k]);
}
//Hide the whole table if all parameters are unknown
if (param === "unknown") { //First count how many params are unknown
paramCount = paramCount + 1;
}
if (paramCount === paramListParsed.length) { //If all params are unknown
setStylesheet("#Table" + TTIX +  " {display: none;}\n", "InfoboxTable" + TTIX);
setStylesheet("#NoInfo" + TTIX + " {display: inherit;}", "NoInfo" + TTIX);
} else {
setStylesheet("#Table" + TTIX + " {display: inherit;}\n", "InfoboxTable" + TTIX);
setStylesheet("#NoInfo" + TTIX + " {display: none;}", "NoInfo" + TTIX);
}
} //End parsing of parameters for output

//Hide section title if all params in the section are unknown (requires extra parsing of parameters by sections)
var section = paramList.replace(/Section-[\w\W\n]*?/g, "").replace(/ /g, "_").split("\n----\n"); //Get sections
var sectionParsed, sectionParams;
var sectionParamCount = 0;
var p, q;
if (section.length > 1) {
for (p = 0; p < section.length; p++) {
sectionParsed = section[p].split("\n"); //Split sections into parameters
for (q = 0; q < sectionParsed.length; q++) { //Parse the parameters
sectionParams = getParam(params, sectionParsed[q], 'unknown');
if (sectionParams === "unknown") { //Count how many parameters in the section are unknown
sectionParamCount = sectionParamCount + 1;
}
}
if (sectionParamCount === sectionParsed.length) {
setStylesheet("#Section" + TTIX + sectionParsed[0].replace(/Section-|\*\*[\w\W]*?$/g, "") + " {display: none;}", "InfoboxSection" + TTIX + sectionParsed[0].replace(/Section-|\*\*[\w\W]*?$/g, ""));
setStylesheet("#Content" + TTIX + sectionParsed[0].replace(/Section-|\*\*[\w\W]*?$/g, "") + " {display: none;}", "InfoboxContent" + TTIX + sectionParsed[0].replace(/Section-|\*\*[\w\W]*?$/g, ""));
} else {
setStylesheet("#Section" + TTIX + sectionParsed[0].replace(/Section-|\*\*[\w\W]*?$/g, "") + " {display: inherit;}", "InfoboxSection" + TTIX + sectionParsed[0].replace(/Section-|\*\*[\w\W]*?$/g, ""));
setStylesheet("#Content" + TTIX + sectionParsed[0].replace(/Section-|\*\*[\w\W]*?$/g, "") + " {display: inherit;}", "InfoboxContent" + TTIX + sectionParsed[0].replace(/Section-|\*\*[\w\W]*?$/g, ""));
}
sectionParamCount = 0; //Reset the count for the next section
}
}

//Final output
//If NestedSlidersPlugin and HTMLFormattingPlugin are installed and both options are true
if ((version.extensions.NestedSlidersPlugin && config.options.chkUseNestedSlidersPlugin === true) && (version.extensions.HTMLFormattingPlugin && config.options.chkUseHTMLFormattingPlugin === true)) {
wikify(startNSP + out + endNSPHFP, place);
}
//If NestedSlidersPlugin is installed and option is true, HTMLFormattingPlugin is not installed or option is false
else if ((version.extensions.NestedSlidersPlugin && config.options.chkUseNestedSlidersPlugin === true) && (!version.extensions.HTMLFormattingPlugin || config.options.chkUseHTMLFormattingPlugin === false)) {
wikify(startNSP + out + endNSP, place);
}
//If NestedSlidersPlugin and HTMLFormattingPlugin are not installed
else {
wikify(start + out + end, place);
}
}
}; //End of macro
} //End of install only once
//}}}
/***
|Name|[[InfoboxTablesPluginCommand]]|
|Source|http://infoboxes.tiddlyspot.com|
|Documentation|[[InfoboxTablesPluginCommandInfo]]|
|Version|1.0.1|
|Author|Kristjan Brezovnik|
|License|[[Creative Commons Attribution-Share Alike 3.0 License|http://creativecommons.org/licenses/by-sa/3.0/]]<br/>[[ELS Design Studios Legal Statements|http://www.TiddlyTools.com/#LegalStatements]]|
|~CoreVersion|2.6.1|
|Requires|[[InfoboxTablesPlugin]]|
|Type|plugin|
|Description|Provides "infobox info" command for [[InfoboxTablesPlugin]].|

!Configuration
<<option chkInfoboxInfoEditToolbar>> Add/remove ~InfoboxInfo to/from default ~EditToolbar in the default [[ToolbarCommands]] shadow tiddler; requires refresh
<<option chkInfoboxInfoViewToolbar>> Add/remove ~InfoboxInfo to/from default~ViewToolbar in the default [[ToolbarCommands]] shadow tiddler; requires refresh

/***
!Code
***/
//{{{
if(!version.extensions.InfoboxTablesPlugin) { //Check if InfoboxTablesPlugin is installed
throw "InfoboxTablesPlugin is not installed!";
}
else {
//Ensure that the plugin is only installed once
if (!version.extensions.infoboxInfo) {
version.extensions.infoboxInfo = {installed: true};
version.extensions.infoboxInfo = {major: 1, minor: 0, revision: 1, date: new Date(2013,3,27)};

//Stylesheet
var infoStylesheet = store.getTiddler("InfoboxTablesInfoboxInfoStylesheet");
if (infoStylesheet === null) {
config.shadowTiddlers.InfoboxTablesInfoboxInfoStylesheet = 
"/***\nStylesheet\n***/\n/*{{{*/\n" + 
".InfoboxInfoButton {display: inline-block; position: relative; float: left; clear: both; padding: 1px; margin: 1px; font-size: 10px; line-height: 120%; border: 1px solid black; background: [[InfoboxTablesColorPalette::InfoboxTableBackground]];}\n" + 
".InfoboxNoInfo {display: none; width: 300px !important; font-weight: bold; border: solid 2px; border-radius: 5px; -moz-border-radius: 5px; -webkit-border-radius: 5px; padding: 5px 5px;} /* No Info */\n" + 
".InfoboxInfo2, .InfoboxInfo3 {vertical-align: top; font-size: 10px; white-space: nowrap; line-height: 80%; border: 1px solid black !important; border-collapse: collapse;} /* InfoboxInfo tables */\n" + 
".InfoboxInfo2 td, .InfoboxInfo3 td, .InfoboxInfo2 th, .InfoboxInfo3 th {border: 1px solid black !important; border-collapse: collapse !important;}\n" + 
".InfoboxInfo2 th, .InfoboxInfo3 th {background: darkgrey;}\n" + 
".InfoboxInfo2 caption, .InfoboxInfo3 caption {white-space: normal; text-align: left;  line-height: 120%;} /* InfoboxInfo captions */\n" + 
".InfoboxInfo2 td:last-child {display: none;}\n" + 
"/*}}}*/\n";
store.addNotification("InfoboxTablesInfoboxInfoStylesheet", refreshStyles);
}

//Add InfoboxInfo to EditToolbar and ViewToolbar
if (config.options.chkInfoboxInfoEditToolbar === undefined) {
config.options.chkInfoboxInfoEditToolbar = false;
}
if (config.options.chkInfoboxInfoViewToolbar === undefined) {
config.options.chkInfoboxInfoViewToolbar = false;
}

if ((config.options.chkInfoboxInfoEditToolbar === true) && !config.shadowTiddlers.ToolbarCommands.match("EditToolbar\\|infoboxInfo")) {
config.shadowTiddlers.ToolbarCommands = config.shadowTiddlers.ToolbarCommands.replace(/EditToolbar\|/, "EditToolbar\|infoboxInfo ");
}
if ((config.options.chkInfoboxInfoEditToolbar === false) && config.shadowTiddlers.ToolbarCommands.match("EditToolbar\\|infoboxInfo")) {
config.shadowTiddlers.ToolbarCommands = config.shadowTiddlers.ToolbarCommands.replace(/EditToolbar\|infoboxInfo /, "EditToolbar|");
}
if ((config.options.chkInfoboxInfoViewToolbar === true) && !config.shadowTiddlers.ToolbarCommands.match("ViewToolbar\\|infoboxInfo")) {
config.shadowTiddlers.ToolbarCommands = config.shadowTiddlers.ToolbarCommands.replace(/ViewToolbar\|/, "ViewToolbar\|infoboxInfo ");
}
if ((config.options.chkInfoboxInfoViewToolbar === false) && config.shadowTiddlers.ToolbarCommands.match("ViewToolbar\\|infoboxInfo")) {
config.shadowTiddlers.ToolbarCommands = config.shadowTiddlers.ToolbarCommands.replace(/ViewToolbar\|infoboxInfo /, "ViewToolbar|");
}

//InfoboxInfo command
config.commands.infoboxInfo = {
text: "infobox info",
tooltip: "Show details for infoboxes in the current tiddler"
};

config.commands.infoboxInfo.handler = function(event,src,title) {
config.commands.infoboxInfo.showPopup(src);
};

config.commands.infoboxInfo.showPopup = function(place) { //Show the popup

var tid;
var here = story.findContainingTiddler(place);
if (here) {
tid = store.getTiddler(here.getAttribute("tiddler"));
}

var title = tid.title;

var popupCommand = Popup.create(place);
if (!popupCommand) {
return;
}
addClass(popupCommand,"sticky");

var infoboxInfoDiv = createTiddlyElement(popupCommand, "div", "InfoboxInfoDiv"+title.replace(/[\W\s]/g, ""), "InfoboxOuterDivCommand");
infoboxInfoDiv.style.padding = "5px";

if (tid !== null) { //If the tiddler is not a shadow tiddler
if (tid.isTagged("article") && tid.text.match("infobox")) { //If the tiddler is an article and contains an infobox

var getinfoboxes = store.getTaggedTiddlers("infobox"); //Get all infoboxes
var infoboxarray = "";
var i;
for (i = 0; i < getinfoboxes.length; i++) { //Put the infoboxes into array
infoboxarray += getinfoboxes[i].title.replace(/Infobox_/g, "").replace(/_/g, " ") + ",";
}
var infoboxes = infoboxarray.split(",");
var table = "";
var infoboxcount = 0;
var j;
for (j = 0; j < infoboxes.length; j++) { //Go through all infoboxes
var comms = 0;
if (tid.text.match("Type:\""+infoboxes[j]+"\"")) { //If a tiddler contains an infobox
infoboxcount = infoboxcount + 1;
var info = store.getTiddlerText("Infobox_" + infoboxes[j].replace(/ /g, "_") + "##Content");
var note = store.getTiddlerText("Infobox_" + infoboxes[j].replace(/ /g, "_") + "##Notes");
if (note === undefined) {
note = "";
}
var infosplit = info.replace(/----\n/g, "").split("\n");
var desc, param, comm;
var out = "";
var k;
for (k = 0; k < infosplit.length; k++) { //Parse the infobox
if (infosplit[k].indexOf("Section-") !== -1) {
desc = "|{{Infobox"+infoboxes[j].replace(/ /g, "")+"Title{" + infosplit[k].replace(/Section-/g, "Section: ").replace(/ \(\([\w\s]*?\)\)| \*\*[\w\W\s]*?$/g, "") + "}}}|";
param = "|";
}
else {
desc = "|" + infosplit[k].replace(/Image-/g, "Image: ").replace(/Single-/g, "Single cell: ").replace(/Side1-/g, "Left Side: ").replace(/Side2-/g, "Right Side: ").replace(/ \(\([\w\s]*?\)\)| \*\*[\w\W\s]*?$/g, "") + "|";
if (infosplit[k].indexOf("\(\(") !== -1) {
param = "<nowiki>" + infosplit[k].replace(/^[\w\W\s]*?\(\(|\)\)[\w\W\s]*?$/g, "") + "</nowiki>|";
}
else {
param = "<nowiki>" + infosplit[k].replace(/ \*\*[\w\W\s]*?$/g, "").replace(/ /g, "_") + "</nowiki>|";
}
}
if (infosplit[k].indexOf("\*\*") !== -1) {
comm = infosplit[k].replace(/[\w\W\s]*?\*\*/g, "") + "|\n";
comms = comms + 1;
}
else {
comm = "|\n";
}
out += desc + param + comm;
} //End parse the infobox

if (comms === 0) { //If there are no comments
table += "!" + infoboxes[j] + " \n|!Description|!Parameter|\n"+ out + "|" + note + "|c\n|InfoboxInfo2|k\nsplitter" + infoboxes[j] + "splitter";
}
else { //If there are comments

table += "!" + infoboxes[j] + "\n|!Description|!Parameter|!Comment|\n"+ out + "|" + note + "|c\n|InfoboxInfo3|k\nsplitter" + infoboxes[j] + "splitter";
}

} //End if a tiddler contains the infobox
} //End go through all infoboxes
var tableSplit = table.split("splitter");
tableSplit.pop();

if (infoboxcount === 1) { //If there is only one infobox type, display the content
wikify("{{SmallText{This article contains the following infobox:}}}\n" + table.replace(/splitter[\w\W\s]+?splitter/g, ""), infoboxInfoDiv);
}
else { //If there are more infobox types, show a list
wikify("{{SmallText{This article contains the following infoboxes:}}}\n",infoboxInfoDiv);
var ButtonTitleSub;
var ButtonTooltipSub;
var x;
for (x = 0; x < tableSplit.length; x = x + 2) {
ButtonTitleSub = tableSplit[x+1];
ButtonTooltipSub = tableSplit[x+1];
var infoboxInfoButtonSub = createTiddlyButton(infoboxInfoDiv, ButtonTitleSub, ButtonTooltipSub, function() {config.commands.infoboxInfo.toggleInfoboxInfo(this.nextSibling,this);}, "InfoboxInfoButton", "InfoboxInfoButton"+tableSplit[x+1].replace(/ /g, ""));
infoboxInfoButtonSub.setAttribute("closedtext",ButtonTitleSub);
infoboxInfoButtonSub.setAttribute("closedtip",ButtonTooltipSub);
infoboxInfoButtonSub.setAttribute("openedtext",ButtonTitleSub);
infoboxInfoButtonSub.setAttribute("openedtip",ButtonTooltipSub);
var infoboxInfoDivSub = createTiddlyElement(infoboxInfoDiv, "div", "InfoboxInfoDivSub"+title.replace(/[\W\s]/g, "")+tableSplit[x+1].replace(/[\W\s]/g, ""), "InfoboxInnerDivCommand");
infoboxInfoDivSub.style.display = "none";
wikify(tableSplit[x], infoboxInfoDivSub);
}
}
} //End if the tiddler is an article and contains an infobox
else {
wikify("The tiddler is not an article.", infoboxInfoDiv);
}
} //End if the tiddler is not a shadow tiddler

Popup.show();
event.cancelBubble = true;
if (event.stopPropagation) {
event.stopPropagation();
return false;
}

}; //End show the popup

//Get content panel index
config.commands.infoboxInfo.panelIndex = function(panel) {
var panelIndex = 0;
while((panel = panel.previousSibling) !== null) {
panelIndex++;
}
return panelIndex;
};
//End get content panel index

//Toggle display of infoboxInfo popup
config.commands.infoboxInfo.toggleInfoboxInfo = function(panel,button) {
var panelIndex = config.commands.infoboxInfo.panelIndex(panel);
var i;
var siblings = panel.parentNode.childNodes.length;
for(i = 0; i < siblings; i++) {
if(i !== panelIndex) {
panel.parentNode.childNodes.item(i).style.display = "none";
}
}
if (panel.style.display === "none") {
panel.style.display = "block";
button.innerHTML = button.getAttribute("openedtext");
button.setAttribute("title",button.getAttribute("openedtip"));
if (window.adjustPopupPosition && panel.parentNode.parentNode.id === "popup") {
window.adjustPopupPosition(panel.parentNode.parentNode,button,panel);
}
} else {
panel.style.display = "none";
button.innerHTML = button.getAttribute("closedtext");
button.setAttribute("title",button.getAttribute("closedtip"));
//if (window.adjustPopupPosition && panel.parentNode.parentNode.id === "popup") {
//window.adjustPopupPosition(panel.parentNode.parentNode,button,panel);
//}
}
};
//End toggle display of infoboxInfo popup

//Modified from StickyPopupPlugin (http://www.TiddlyTools.com/#StickyPopupPlugin)
//ELS Design Studios Legal Statements (http://www.TiddlyTools.com/#LegalStatements) apply
//This was added to avoid having to install the StickyPopupPlugin
Popup.stickyPopupCommand = function(event) {
var e = event ? event : window.event;
var target = resolveTarget(e);
var pop = target;
while (pop) { //If in a sticky popup
if (hasClass(pop,"popup") && hasClass(pop,"sticky")) {
break;
}
else {
pop = pop.parentNode;
}
}
if (!pop) { //If not in sticky popup
Popup.onDocumentClick(event);
return true;
}
};
try {
removeEvent(document,"click",Popup.onDocumentClick);
}
catch(e) {}
try {
addEvent(document,"click",Popup.stickyPopupCommand);
}
catch(e) {}
//End modified from StickyPopupPlugin (http://www.TiddlyTools.com/#StickyPopupPlugin)

//Adjust the popup position for when there is more than one infobox type
if (window.adjustPopupPosition === undefined) {
window.adjustPopupPosition = function (place,button,panel) {
if (hasClass(panel, "InfoboxInnerDivCommand")) {
var rightEdge = document.body.offsetWidth - 1;
var panelWidth = place.offsetWidth;
//var left = 1442;
var left = 0;
if (findPosX(place) + panelWidth > rightEdge) {
left = rightEdge - panelWidth;
}
place.style.left = left + "px";
}
};
}
//End adjust the popup position for when there is more than one infobox type

} //End of install only once
}
//}}}
/***
|Name|[[InfoboxTablesPluginCommand]]|
|Source|http://infoboxes.tiddlyspot.com|
|Documentation|[[InfoboxTablesPluginCommandInfo]]|
|Version|1.0.1|
|Author|Kristjan Brezovnik|
|License|[[Creative Commons Attribution-Share Alike 3.0 License|http://creativecommons.org/licenses/by-sa/3.0/]]<br/>[[ELS Design Studios Legal Statements|http://www.TiddlyTools.com/#LegalStatements]]|
|~CoreVersion|2.6.1|
|Requires|[[InfoboxTablesPlugin]]|
|Type|plugin|
|Description|Provides "infobox info" command for [[InfoboxTablesPlugin]].|

!Notes
This used to be a part of [[InfoboxTablesPlugin]] to help when figuring out which parameters to use. But since [[InfoboxTablesPlugin]] has an in-place edit mode as of version 2.2.0, this command is no longer necessary. It can, however still be used for informational purposes.

!Use
!Configuration
<<option chkInfoboxInfoEditToolbar>> Add/remove ~InfoboxInfo to/from default ~EditToolbar in the default [[ToolbarCommands]] shadow tiddler; requires refresh
<<option chkInfoboxInfoViewToolbar>> Add/remove ~InfoboxInfo to/from default~ViewToolbar in the default [[ToolbarCommands]] shadow tiddler; requires refresh

!!~InfoboxInfo Command (infoboxInfo)
The plugin also defines the ''infoboxInfo'' command. This command is not mandatory for displaying the actual infoboxes, however, it does enable you to view the infobox template in a dropdown menu, so you can quickly see which parameters are supported (and copy them), whether there are shorthand parameters, as well as any comments and notes. Under Configuration, you can quickly add it to the default ~EditToolbar or ~ViewToolbar slice in [[ToolbarCommands]]. However, note that this solution uses cookies, so if you enable it in one browser, it won't work in any other browser, unless you also enable it in the other browser. And if you clear the cookies on browser close, you need to re-enable the option manually, unless you use a plugin for saving ~TiddlyWiki cookies.
You can also permanently enable the options by putting the following in a tiddler tagged ''systemConfig'':
{{{
config.options.chkInfoboxInfoEditToolbar=true;
config.options.chkInfoboxInfoViewToolbar=true;
}}}

If you use the SystemSettings tiddler, you need to add:
{{{
chkInfoboxInfoEditToolbar: true
chkInfoboxInfoViewToolbar: true
}}}

If you use your own toolbars or if you modified the existing ~EditToolbar or ~ViewToolbar slice in the [[ToolbarCommands]], you need to add the command manually.
Example for [[ToolbarCommands]]:
{{{
|ViewToolbar|infoboxInfo ...|
|EditToolbar|infoboxInfo ...|
}}}

Example for modified EditTemplate and ViewTemplate:
{{{
<div class='toolbar' macro='toolbar infoboxInfo ...'></div>
}}}

Adding it to the ~ViewToolbar is useful if you use [[EditSectionPlugin|http://www.TiddlyTools.com/#EditSectionPlugin]].

After you add the infoboxInfo command to a template or toolbar, in order for the dropdown menu to actually show up, the ''tiddler must be tagged'' with the tag ''article'' and a ''valid Type in lower case'', as well as actually contain an infobox with a valid type. Also, you must save/create the tiddler before you can use this command.

!!Shadow tiddlers
In the [[InfoboxTablesColorPalette]] shadow tiddler you can modify the color scheme without modifying the templates.
In the [[InfoboxTablesStylesheet]] shadow tiddler you can modify the layout a bit.

!Version History
1.0.1 - Added check to see if InfoboxTablesPlugin is installed
1.0.0 - Initial standalone release (from InfoboxTablesInfobox 2.1.1)
>Added separate [[InfoboxTablesPluginCommand|info]] tiddler
|Name|[[InfoboxTablesPlugin]]|
|Source|http://infoboxes.tiddlyspot.com|
|Documentation|[[InfoboxTablesPluginInfo]]|
|Version|2.2.2|
|Author|Kristjan Brezovnik|
|License|[[Creative Commons Attribution-Share Alike 3.0 License|http://creativecommons.org/licenses/by-sa/3.0/]]|
|~CoreVersion|2.6.3|
|Requires||
|Type|plugin|
|Description|Provides customizable infoboxes for different types of articles.|

!Notes
This plugin is intended to simulate the Wookiepedia/Wikipedia style infoboxes. If you're a writer, you need to keep a list of characters and events, and with ~TiddlyWiki you can make a simple wiki to help you do that. These infoboxes help you list basic information in an easy and clear way. It is designed to be generic, so you can define your own types of infoboxes or modify the ones I've made.
In ~TiddlyWiki 2.6.2 and probably earlier, Internet Explorer didn't hide the whole table correctly, if there were no information, and there might have been some other related minor issues. ~TiddlyWiki 2.6.3 seems to have corrected that.

!Use
!!Configuration
<<option chkHideInfoboxes>> Hide the infoboxes when opening a tiddler
<<option chkSaveMode>> When editing the table, save the macro so each parameter is in its own line (default) or so that the entire macro is a single line
<<option chkSavePrompt>> Prompt if you really want to save

!!~InfoboxInfo Command (infoboxInfo)
No longer necessary as of InfoboxTablesPlugin version 2.2.0. It is still available as a dependent plugin ([[InfoboxTablesInfoboxInfoCommand]]) with accompanying information ([[InfoboxTablesInfoboxInfoCommandInfo]]).

!!Infobox Macro (infobox)
Use:
{{{
<<infobox Type:"value" Title:"value" InstanceID:"value" parameter_name:"value" parameter_name:"value" parameter_name:"value" ... parameter_name:"value">>
}}}

There are three predefined parameters, of which one is mandatory (Type) and two are optional (Title and ~InstanceID).

The only mandatory parameter is ''Type'', because it determines which template will be used.

For parameter values, you need to use HTML code to add styling, not wiki markup. You can use line breaks, but they get eaten, if you don't use the &lt;br/&gt; tag. If you use HTML tags that already add a line break, like &lt;li&gt;&lt;/li&gt;, you don't need to add &lt;br/&gt; afterwards.

Normally, you use one infobox of a type in a tiddler. If, however, that is not enough, you can use the ''~InstanceID'' parameter and assign ''each'' instance a ''unique ID''. Note that if using more than one instance of the same type, you ''must'' use the ''~InstanceID'' parameter for all of them, otherwise the settings from the last one used override the settings from the ones before. If you use instances of different types or if you only use one instance, the ''~InstanceID'' parameter is not required. The plugin also checks for missing or duplicate ''~InstanceID'' parameters.

By default, the tiddler title is displayed in the table header, since the subject of the tiddler is usually also the subject of the table. You can, however, define a custom title using the ''Title'' parameter, which is useful when you have multiple infoboxes in the same tiddler.

The order in which the parameters will be displayed in a table is defined in the template. Because this plugin uses named parameters, you can list them in any order in the macro and they will be displayed correctly. However, due to an easier overview, I suggest you stick to the order in the template.

Because there are often many parameters, you can write each parameter on its own line, so you have a better overview. This is how the edit mode saves them by default. You can, however, also use the option above to specify that you want the edit mode to write the entire macro as a single line.

!!Edit Mode
Edit mode enables you to edit the infobox without having to open the tiddler and manually enter parameters. The only parameter that you need to enter is Type. If you use multiple infoboxes of the same type in the same tiddler, you also need to enter ~InstanceID. After that, you can use edit mode to add the rest of the parameters.

All parameters specified in the template are available in edit mode. Any comments are visible above the respective text area where you enter the values. If the value is empty or unknown, the macro ignores those parameters when saving.

Note that if you change the template, ie add, remove or rename a parameter, the newly added or the renamed parameters will show up in edit mode, but the old ones won't. So if you need the information from the old or renamed parameter, you need to backup the data, because once you save the infobox from edit mode, the old macro will be overwritten.

Edit mode is ''not'' supported for error messages. In this case you need to edit the macro manually. You only need to correct/add the Type and/or ~InstanceID parameter. Once they're correct, you can use the edit mode normally.

You can cancel editing an infobox by pressing escape, but only as long as you're somewhere on the infobox. If you click in the tiddler or somewhere else off the infobox, escape won't work. This is to prevent the escape key from affecting other potential infoboxes in the same tiddler.

Cancelling edit resets the edit mode and you will lose any changes.

You can also delete the infobox from the tiddler.

!!Error messages
An error message is displayed in the following cases:
*if you enter a wrong type
*if you don't enter the type
*if you use multiple infoboxes of the same type and you forget to add the ~InstanceID parameters to all of them
*if you use multiple infoboxes of the same type and you use a duplicate ~InstanceID parameter

!!Shadow tiddlers
In the [[InfoboxTablesColorPalette]] shadow tiddler you can modify the color scheme without modifying the templates.
In the [[InfoboxTablesStylesheet]] shadow tiddler you can modify the layout a bit.

!!Templates
You can define your own templates, which should be named ''Infobox_<Type>'' and tagged ''infobox''. Replace <Type> to match whatever information the infobox will display. Note that you should ''use underscores instead of spaces''.
Templates consists of two mandatory sections (Content and Colors) and one optional (Notes).
Under ''Content'', you can specify how the table will be set up and what parameters are supported.
Under ''Colors'', you can specify the color of the table header/footer (Title) and section titles (Subtitle). The basic table colors can be changed in the [[InfoboxTablesColorPalette]] shadow tiddler.
Under ''Notes'', you can write any information you might think is relevant to the template.

Each table section consists of a table title and the group of relevant parameters. Note that images can also be a part of a section or they can be in a section of their own.
Table sections are separated with the four dashes separator.

There are several key words that help with table formatting:
*''Section-'' - denotes a section title
*''Image-'' - denotes an image
*''Side1-'' - denotes the left side of a comparison
*''Side2-'' - denotes the right side of a comparison
*''((...))'' - denotes a shorthand parameter; must follow a normal parameter (it is irrelevant for section titles)
*''**'' - denotes a comment; must follow the shorthand parameter, if any, or the parameter

Order:
Descriptive parameter ((shorthand)) **Comment

Section-, Image-, Side1- and Side2- all contain a mandatory dash, which cannot be followed by a space.
Side1- and Side2- should be in a section by themselves.
The shorthand parameters must be separated with a space from the descriptive parameter.
Comments must be separated with a space from the parameter/shorthand parameter. They are not visible in the table.

Parameters may contain spaces in the template, but these ''spaces must be replaced with underscores when used in the macro''. There is no limitation on the number of parameters or sections, but, the more parameters there are, the longer the table takes to render.
If a parameter does not have a value, the line is hidden. If all parameters in a section are unknown, the whole section is hidden. If all parameters in the table is unknown, the whole table is hidden.

Usually, you write out parameters descriptively, since they are displayed in the left table column. Shorthand parameters can be used to help you shorten the amount of text you need to write. Note that if you define a shorthand parameter, you need to use it instead of the descriptive parameter. In the table, only the descriptive parameters are displayed. If you assign a shorthand parameter to a parameter that uses a key word, you don't need to include the keyword in the shorthand parameter. Sections don't take shorthand parameters and if you add one, it will be removed.

Sections don't take shorthand parameters, so if you mistakenly add one, it will automatically be removed.

Comments are usuful for adding specifics regarding a parameter or a section.

After adding a new template or modifying an existing one, you might need to refresh.

!!!Template structure
&excl;Content
~Image-Your image 1
----
~Section-Section 1 title **Optional comment for section
Section 1 param 1 
Section 1 param 2
Section 1 param n
----
~Image-Your image 2
----
~Section-Section 2 title **Optional comment for section
Section 2 param 1
~Image-Your image 3 **Optional comment for a param without a shorthand param
Section 2 param 2 ((random)) **Optional comment for a param with a shorthand param
Section 2 param n
----
~Section-Section 3 title **Optional comment for section
~Side1-Section 3 param 1 ((left)) **Notice how the keyword is not included in the shorthand parameter
~Side2-Section 3 param 2 ((right))
----
~Section-Section n title
Section n param 1
Section n param 2
Section n param n
&excl;Colors
Text:black
Title:green
Subtitle:yellow
&excl;Notes
Here you can add a detailed description or some other note.

!!!Bare minimum template
&excl;Content
&excl;Colors
Text:
Title:
Subtitle:

!!!Sample templates used in examples
* [[Infobox_Example_Battle]]
* [[Infobox_Example_Person]]

!Downlodable templates
Note that you can modify these templates and adapt them to your own needs. You don't need to download them, if you don't need them. You can, of course, also create new ones.
<<list filter "[tag[infobox]]">>

!Examples
<<list filter [tag[infoboxexample]]>>

!Version History
2.2.2 - Fixed a conflict with [[HTMLFormattingPlugin|http://www.TiddlyTools.com/#HTMLFormattingPlugin]], which added extra span tags, which is why the HTML code wasn't correctly cleaned up in inline edit mode
2.2.1 - Minor code cleanup and CSS fix to enforce button style
2.2.0 - Added in-place edit for infoboxes (including for error messages), which also includes the ability to delete the infobox
>moved InfoboxInfo command to a separate dependent plugin ([[InfoboxTablesInfoboxInfoCommand]]) (not required anymore, but can still be used)
>added check, if InfoboxTablesColorPalette and InfoboxTablesStylesheet exist, skip creating shadow tiddlers
>fixed a bug where an error was reported, if there were two templates and one template contained the other's name (ie Template_Officer and Template_Navy_Officer or Template_Vessel and Template_Vessel_Class; the "Template_" part is removed during processing; the template names are used as the Type parameter) and they both had the same ~InstanceID parameter
>fixed a bug where comments sometimes caused problems with displaying parameters
>added check for illegal shorthand parameters in section titles
>added more information
>optimized the code a little
2.1.1 - Fixed the issue where the error messages were incorrectly placed; removed the requirement that the tiddlers be tagged with infobox type
2.1.0 - Turned infoboxInfo a proper command (checkboxes now add to the ToolbarCommands slices instead of ViewTemplate and EditTemplate)
>removed dependency on NestedSlidersPlugin for both the Infobox and ~InfoboxInfo macros
>cleaned up the stylesheet some more
>fixed the table lines in the popup infoboxInfo tables
>added formatting to the color palette and stylesheet; made the button for the infobox table panel in the body dynamic
2.0.7 - Fixed a bug in InfoboxInfo, where the wrong matching function broke the macro; tweaked the stylesheet to make the tables more compact; changed the code that still depended on the [[HTMLFormattingPlugin|http://www.TiddlyTools.com/#HTMLFormattingPlugin]]
2.0.6 - Minor code cleanup and documentation update
2.0.5 - Added the option to show the infobox tables hidden
>removed the need for the [[HTMLFormattingPlugin|http://www.TiddlyTools.com/#HTMLFormattingPlugin]]
>remove the need for [[CoreTweaks|http://www.TiddlyTools.com/#CoreTweaks]] if core version is less than 2.6.3
>replaced the "Show info" button with a link to the infobox template
>added the ~InfoboxInfo function
>removed the InfoboxTablesInfo shadow tiddler, since it was replaced with a link to the template and the ~InfoboxInfo function
>tweaked the stylesheet some more
>made the title non-wikified, so came case words don't become wiki links
2.0.1 - Fixed the table styling bug by changing the output so that each section is a separate table and all the tables are contained in a div container; fixed a bug where the sections didn't hide correctly if all params were unknown; cleaned up the stylesheet; added support for comments anywhere in the Content section
2.0.0 - Completely rewrote the plugin to make it generic, reduce the number of lines and macros and to enable easier adding of infobox templates
>removed the dependency on [[NestedSlidersPlugin|http://www.TiddlyTools.com/#NestedSlidersPlugin]] and [[HTMLFormattingPlugin|http://www.TiddlyTools.com/#HTMLFormattingPlugin]] (although it can still make use of them, if they're present; added option to disable using these two plugins even if they're installed)
>rewrote the documentation and put it in a separate tiddler
>added templates, which were previously part of the macro
>added examples of use
>added support for images, comments for sections and template comments
>removed the scripts checking if third party plugins exist (the macro checks that and modifies the output accordingly)
>enabled multiple instances of the same type in the same tiddler using ~InstanceID parameter (including check of missing or duplicate ~InstanceID parameters)
>added the option to use Title parameter to give the infobox a custom name (for example when using multiple instances or in case you don't want the title to be the tiddler title)
>added the ability to define "shorthand" parameters, which can be used instead of the long descriptive parameters
>removed ~InfoboxInfo
1.2.7 - Added ~IDs to table rows and the CSS class names, so that they are differentiated by tiddler names and don't mess things up between tiddlers
1.2.6 - Moved macro-specific styles to their respective macros, thereby enabling modularity (moving individual infoboxes to their own tiddlers); renamed Vehicle to Vehicle Class and Fighter to Fighter Class
1.2.5 - Changed from unnamed parameters to named parameters
1.2.2 - Replaced the button for checking if [[NestedSlidersPlugin|http://www.TiddlyTools.com/#NestedSlidersPlugin]] exists with a script; added ~InfoboxInfo (requires [[ForEachTiddlerPlugin|http://tiddlywiki.abego-software.de/#ForEachTiddlerPlugin]])
1.2.1 - Moved [info] button content display to a nested slider instead of an annotation; moved the info content itself to a shadow tiddler; added a button to check if [[NestedSlidersPlugin|http://www.TiddlyTools.com/#NestedSlidersPlugin]] is installed
1.2.0 - Added shadow tiddlers for color palette and stylesheet to enable easier modifying of the infobox color scheme; moved everything style-related to stylesheet
1.1.2 - Renamed from ~InfoboxMacrosPlugin to ~InfoboxTablesPlugin; added the [info] button with information on what information can be entered; modified some parameters
1.1.1 - Included the stylesheet into the plugin itself; added documentation
1.1.0 - Added rounded corners and styles instead of direct code; added formatting to the code for easier understanding and to give it a plugin look
1.0.1 - Changed code so it automatically includes the tiddler title
1.0.0 - Initial version
!Content
Image-Battle
----
Section-Conflict
Date
Place
Outcome
Previous
Concurrent
Next
----
Section-Combatants
Side1-Good combatants
Side2-Bad combatants
----
Section-Commanders
Side1-Good commanders
Side2-Bad commanders
----
Section-Strength
Side1-Good strength
Side2-Bad strength
----
Section-Casualties
Side1-Good casualties
Side2-Bad casualties
!Colors
Text:
Title:crimson
Subtitle:red
!Notes
This is template is based on the Battle template from the [[Wookipedia|http://starwars.wikia.com/wiki/Main_Page]].
!Content
Image-City
----
Section-General information
Constructed
Location information
Planet
Location
----
Section-Societal
Eras
Affiliation
!Colors
Text:
Title:palegoldenrod
Subtitle:lemonchiffon
!Notes
This is template is based on the City template from the [[Wookipedia|http://starwars.wikia.com/wiki/Main_Page]].
!Content
Image-Company
----
Section-Organizational information
Primary roles
Chronological and political information
Eras
!Colors
Text:
Title:slategray
Subtitle:lightslategray
!Notes
This is template is based on the Company template from the [[Wookipedia|http://starwars.wikia.com/wiki/Main_Page]].
!Content
Image-Country
----
Section-Physical
Planet
Location
Climate
Primary terrain
Points of interest
----
Section-Societal
Native species
Immigrated species
Official language
Population
Major cities
Major imports
Major exports
Affiliation
!Colors
Text:
Title:orange
Subtitle:sandybrown
!Notes
This is template is based on the Country template from the [[Wookipedia|http://starwars.wikia.com/wiki/Main_Page]].
!Content
Image-Creature
Designation
Planet of origin
Height of average adult
Skin color
Distinctions
!Colors
Text:
Title:darkturquoise
Subtitle:whitesmoke
!Notes
This is template is based on the Creature template from the [[Wookipedia|http://starwars.wikia.com/wiki/Main_Page]].
!Content
Image-Droid
----
Section-Production information
Homeworld
Date created
Creator
Manufacturer
Model
Class
----
Section-Technical specifications
Height
Gender
Sensor color
Armament
Equipment
----
Section-Chronological and political information
Eras
Affiliation
!Colors
Text:
Title:silver
Subtitle:lightgray
!Notes
This is template is based on the Droid template from the [[Wookipedia|http://starwars.wikia.com/wiki/Main_Page]].
!Content
Image-Event
Date
Place
Affiliations involved
Participants
!Colors
Text:
Title:deeppink
Subtitle:whitesmoke
!Notes
This is template is based on the Event template from the [[Wookipedia|http://starwars.wikia.com/wiki/Main_Page]].
!Content
Image-Battle ((img)) **You can add a comment anywhere
----
Section-Conflict **To section titles
Date **Or to data
Place ((loc))
Outcome
Previous
Concurrent
Next
----
Section-Combatants **Notice, how this and the following three sections only contain two parameters each
Side1-Good combatants ((gfighters))
Side2-Bad combatants ((bfighters))
----
Section-Commanders **Notice the "shorthand" parameters
Side1-Good commanders ((gcommanders))
Side2-Bad commanders ((bcommanders))
----
Section-Strength **While shorthand parameters may contain spaces, their purpose is to be short
Side1-Good strength ((gstrength))
Side2-Bad strength ((bstrength))
----
Section-Casualties **All parameters may contain spaces
Side1-Good casualties
Side2-Bad casualties
!Colors
Text:
Title:crimson
Subtitle:red
!Notes
This is a modified Battle template, which is used for demonstration purposes. For actual use, use the [[Battle|Infobox_Battle]] template instead.
!Content
Image-Person **Notice how the image is all alone and not in a section
----
Section-Biographical information
Homeworld
Born
Died
----
Section-Physical description **Notice how there is no space between the keyword's dash and the parameter name
Species
Gender
Height
Hair color
Eye color
Skin color
----
Section-Chronological and political information **Notice the space between the parameter name and the comment separator
Eras
Affiliation
Known masters
Known apprentices
!Colors
Text:white
Title:mediumblue
Subtitle:blue
!Notes
This is a modified Person template, which is used for demonstration purposes. For actual use, use the [[Person|Infobox_Person]] template instead.
!Content
Image-Fighter Class
----
Section-Production information
Manufacturer
Model
Class
Cost
----
Section-Technical specifications
Length
Maximum acceleration
MGLT
Maximum speed (atmosphere)
Engine units
Alternate configuration
Hyperdrive rating
Hyperdrive system
Power plant
Shielding
Hull
Sensor systems
Targeting systems
Navigation system
Avionics
Countermeasures
Armament
Crew
Passengers
Cargo capacity
Consumables
Other systems
----
Section-Usage
Roles
Eras
Affiliation
!Colors
Text:
Title:bisque
Subtitle:papayawhip
!Notes
This is template is based on the Fighter Class template from the [[Wookipedia|http://starwars.wikia.com/wiki/Main_Page]].
!Content
Image-Location
----
Section-General information
Location
Builder
----
Section-Usage
Eras
Affiliation
!Colors
Text:
Title:peru
Subtitle:burlywood
!Notes
This is template is based on the Location template from the [[Wookipedia|http://starwars.wikia.com/wiki/Main_Page]].
!Content
Image-Organization
----
Section-General information
Leaders
Notable members
Headquarters
Locations 
----
Section-Historical information
Fragmentation
Reorganization
Dissolution
Restoration
----
Section-Other information
Eras
Affiliation
!Colors
Text:
Title:darkslategray
Subtitle:dimgray
!Notes
This is template is based on the Organization template from the [[Wookipedia|http://starwars.wikia.com/wiki/Main_Page]].
!Content
Image-Person
----
Section-Biographical information
Homeworld
Born
Died
----
Section-Physical description
Species
Gender
Height
Hair color
Eye color
Skin color
----
Section-Chronological and political information
Eras
Affiliation
Known masters
Known apprentices
!Colors
Text:
Title:mediumblue
Subtitle:blue
!Notes
This is template is based on the Person template from the [[Wookipedia|http://starwars.wikia.com/wiki/Main_Page]].
!Content
Image-Planet
----
Section-Astrographical
Region
System
Suns
Moons
Rotation period
Orbital period
----
Section-Physical
Class
Diameter
Atmosphere
Climate
Gravity
Primary terrain
Points of interest
----
Section-Societal
Native species
Immigrated species
Official language
Population
Major cities
Major imports
Major exports
Affiliation
!Colors
Text:
Title:darkgoldenrod
Subtitle:goldenrod
!Notes
This is template is based on the Planet template from the [[Wookipedia|http://starwars.wikia.com/wiki/Main_Page]].
!Content
Image-Plant
Planet of origin
Distinctions
!Colors
Text:
Title:dodgerblue
Subtitle:whitesmoke
!Notes
This is template is based on the Plant template from the [[Wookipedia|http://starwars.wikia.com/wiki/Main_Page]].
!Content
Image-Species
Homeworld
Language
Average height
Hair color
Skin color
Distinctions
Races
Average lifespan
Famous members
!Colors
Text:
Title:midnightblue
Subtitle:
!Notes
This is template is based on the Species template from the [[Wookipedia|http://starwars.wikia.com/wiki/Main_Page]].
!Content
Image-System
----
Section-Astrographical
Region
System
Suns
Planets
Moons
Asteroids
Affiliation
!Colors
Text:
Title:gold
Subtitle:yellow
!Notes
This is template is based on the System template from the [[Wookipedia|http://starwars.wikia.com/wiki/Main_Page]].
!Content
Image-Tool
!Colors
Text:
Title:silver
Subtitle:gainsboro
!Notes
This is template is based on the Tool template from the [[Wookipedia|http://starwars.wikia.com/wiki/Main_Page]].
!Content
Image-Vehicle
----
Section-Production information
Manufacturer
Product line
Model
Class
Cost
----
Section-Technical specifications
Length
Height/depth
Maximum speed
Maximum altitude
Engine units
Armament
Crew
Passengers
Cargo capacity
----
Section-Usage
Roles
Eras
Affiliation
!Colors
Text:
Title:tan
Subtitle:wheat
!Notes
This is template is based on the Vehicle Class template from the [[Wookipedia|http://starwars.wikia.com/wiki/Main_Page]].
!Content
Image-Vessel
Class
Year launched
Notable crew
Special characteristics
Participation at important events
Eras
Affiliation
!Colors
Text:
Title:navajowhite
Subtitle:peachpuff
!Notes
This is template is based on the Vessel template from the [[Wookipedia|http://starwars.wikia.com/wiki/Main_Page]].
!Content
Image-Vessel Class
----
Section-Production information
Manufacturer
Product line
Model
Class
Cost
----
Section-Technical specifications
Length
Maximum acceleration
MGLT
Engine units
Hyperdrive rating
Hyperdrive system
Power output
Power plant
Shielding
Sensor systems
Targeting systems
Armament
Complement
Crew
Minimum crew
Passengers
Cargo capacity
Consumables
Other systems
----
Section-Usage
Roles
Year introduced
Eras
Affiliation
!Colors
Text:
Title:navajowhite
Subtitle:peachpuff
!Notes
This is template is based on the Vessel_Class template from the [[Wookipedia|http://starwars.wikia.com/wiki/Main_Page]].
!Content
Image-War
----
Section-General
Beginning
End
Place
Outcome
Major battles
----
Section-Combatants
Side1-Good combatants
Side2-Bad combatants
----
Section-Commanders
Side1-Good commanders
Side2-Bad commanders
!Colors
Text:
Title:darkred
Subtitle:firebrick
!Notes
This is template is based on the War template from the [[Wookipedia|http://starwars.wikia.com/wiki/Main_Page]].
!Content
Image-Weapon
!Colors
Text:
Title:grey
Subtitle:darkgrey
!Notes
This is template is based on the Weapon template from the [[Wookipedia|http://starwars.wikia.com/wiki/Main_Page]].
/***
|''Name:''|LoadRemoteFileThroughProxy (previous LoadRemoteFileHijack)|
|''Description:''|When the TiddlyWiki file is located on the web (view over http) the content of [[SiteProxy]] tiddler is added in front of the file url. If [[SiteProxy]] does not exist "/proxy/" is added. |
|''Version:''|1.1.0|
|''Date:''|mar 17, 2007|
|''Source:''|http://tiddlywiki.bidix.info/#LoadRemoteFileHijack|
|''Author:''|BidiX (BidiX (at) bidix (dot) info)|
|''License:''|[[BSD open source license|http://tiddlywiki.bidix.info/#%5B%5BBSD%20open%20source%20license%5D%5D ]]|
|''~CoreVersion:''|2.2.0|
***/
//{{{
version.extensions.LoadRemoteFileThroughProxy = {
 major: 1, minor: 1, revision: 0, 
 date: new Date("mar 17, 2007"), 
 source: "http://tiddlywiki.bidix.info/#LoadRemoteFileThroughProxy"};

if (!window.bidix) window.bidix = {}; // bidix namespace
if (!bidix.core) bidix.core = {};

bidix.core.loadRemoteFile = loadRemoteFile;
loadRemoteFile = function(url,callback,params)
{
 if ((document.location.toString().substr(0,4) == "http") && (url.substr(0,4) == "http")){ 
 url = store.getTiddlerText("SiteProxy", "/proxy/") + url;
 }
 return bidix.core.loadRemoteFile(url,callback,params);
}
//}}}
[[GettingStarted]]

[[InfoboxTablesPlugin]]
[[InfoboxTablesPluginInfo]]

[[InfoboxTablesPluginCommand]]
[[InfoboxTablesPluginCommandInfo]]
/***
|''Name:''|PasswordOptionPlugin|
|''Description:''|Extends TiddlyWiki options with non encrypted password option.|
|''Version:''|1.0.2|
|''Date:''|Apr 19, 2007|
|''Source:''|http://tiddlywiki.bidix.info/#PasswordOptionPlugin|
|''Author:''|BidiX (BidiX (at) bidix (dot) info)|
|''License:''|[[BSD open source license|http://tiddlywiki.bidix.info/#%5B%5BBSD%20open%20source%20license%5D%5D ]]|
|''~CoreVersion:''|2.2.0 (Beta 5)|
***/
//{{{
version.extensions.PasswordOptionPlugin = {
	major: 1, minor: 0, revision: 2, 
	date: new Date("Apr 19, 2007"),
	source: 'http://tiddlywiki.bidix.info/#PasswordOptionPlugin',
	author: 'BidiX (BidiX (at) bidix (dot) info',
	license: '[[BSD open source license|http://tiddlywiki.bidix.info/#%5B%5BBSD%20open%20source%20license%5D%5D]]',
	coreVersion: '2.2.0 (Beta 5)'
};

config.macros.option.passwordCheckboxLabel = "Save this password on this computer";
config.macros.option.passwordInputType = "password"; // password | text
setStylesheet(".pasOptionInput {width: 11em;}\n","passwordInputTypeStyle");

merge(config.macros.option.types, {
	'pas': {
		elementType: "input",
		valueField: "value",
		eventName: "onkeyup",
		className: "pasOptionInput",
		typeValue: config.macros.option.passwordInputType,
		create: function(place,type,opt,className,desc) {
			// password field
			config.macros.option.genericCreate(place,'pas',opt,className,desc);
			// checkbox linked with this password "save this password on this computer"
			config.macros.option.genericCreate(place,'chk','chk'+opt,className,desc);			
			// text savePasswordCheckboxLabel
			place.appendChild(document.createTextNode(config.macros.option.passwordCheckboxLabel));
		},
		onChange: config.macros.option.genericOnChange
	}
});

merge(config.optionHandlers['chk'], {
	get: function(name) {
		// is there an option linked with this chk ?
		var opt = name.substr(3);
		if (config.options[opt]) 
			saveOptionCookie(opt);
		return config.options[name] ? "true" : "false";
	}
});

merge(config.optionHandlers, {
	'pas': {
 		get: function(name) {
			if (config.options["chk"+name]) {
				return encodeCookie(config.options[name].toString());
			} else {
				return "";
			}
		},
		set: function(name,value) {config.options[name] = decodeCookie(value);}
	}
});

// need to reload options to load passwordOptions
loadOptionsCookie();

/*
if (!config.options['pasPassword'])
	config.options['pasPassword'] = '';

merge(config.optionsDesc,{
		pasPassword: "Test password"
	});
*/
//}}}
/***
|Requires|ShCore.js|
***/
//{{{
/**
 * SyntaxHighlighter
 * http://alexgorbatchev.com/SyntaxHighlighter
 *
 * SyntaxHighlighter is donationware. If you are using it, please donate.
 * http://alexgorbatchev.com/SyntaxHighlighter/donate.html
 *
 * @version
 * 3.0.83 (July 02 2010)
 * 
 * @copyright
 * Copyright (C) 2004-2010 Alex Gorbatchev.
 *
 * @license
 * Dual licensed under the MIT and GPL licenses.
 */
;(function()
{
	// CommonJS
	typeof(require) != 'undefined' ? SyntaxHighlighter = require('shCore').SyntaxHighlighter : null;

	function Brush()
	{
		function getKeywordsCSS(str)
		{
			return '\\b([a-z_]|)' + str.replace(/ /g, '(?=:)\\b|\\b([a-z_\\*]|\\*|)') + '(?=:)\\b';
		};
	
		function getValuesCSS(str)
		{
			return '\\b' + str.replace(/ /g, '(?!-)(?!:)\\b|\\b()') + '\:\\b';
		};

		var keywords =	'ascent azimuth background-attachment background-color background-image background-position ' +
						'background-repeat background baseline bbox border-collapse border-color border-spacing border-style border-top ' +
						'border-right border-bottom border-left border-top-color border-right-color border-bottom-color border-left-color ' +
						'border-top-style border-right-style border-bottom-style border-left-style border-top-width border-right-width ' +
						'border-bottom-width border-left-width border-width border bottom cap-height caption-side centerline clear clip color ' +
						'content counter-increment counter-reset cue-after cue-before cue cursor definition-src descent direction display ' +
						'elevation empty-cells float font-size-adjust font-family font-size font-stretch font-style font-variant font-weight font ' +
						'height left letter-spacing line-height list-style-image list-style-position list-style-type list-style margin-top ' +
						'margin-right margin-bottom margin-left margin marker-offset marks mathline max-height max-width min-height min-width orphans ' +
						'outline-color outline-style outline-width outline overflow padding-top padding-right padding-bottom padding-left padding page ' +
						'page-break-after page-break-before page-break-inside pause pause-after pause-before pitch pitch-range play-during position ' +
						'quotes right richness size slope src speak-header speak-numeral speak-punctuation speak speech-rate stemh stemv stress ' +
						'table-layout text-align top text-decoration text-indent text-shadow text-transform unicode-bidi unicode-range units-per-em ' +
						'vertical-align visibility voice-family volume white-space widows width widths word-spacing x-height z-index';

		var values =	'above absolute all always aqua armenian attr aural auto avoid baseline behind below bidi-override black blink block blue bold bolder '+
						'both bottom braille capitalize caption center center-left center-right circle close-quote code collapse compact condensed '+
						'continuous counter counters crop cross crosshair cursive dashed decimal decimal-leading-zero default digits disc dotted double '+
						'embed embossed e-resize expanded extra-condensed extra-expanded fantasy far-left far-right fast faster fixed format fuchsia '+
						'gray green groove handheld hebrew help hidden hide high higher icon inline-table inline inset inside invert italic '+
						'justify landscape large larger left-side left leftwards level lighter lime line-through list-item local loud lower-alpha '+
						'lowercase lower-greek lower-latin lower-roman lower low ltr marker maroon medium message-box middle mix move narrower '+
						'navy ne-resize no-close-quote none no-open-quote no-repeat normal nowrap n-resize nw-resize oblique olive once open-quote outset '+
						'outside overline pointer portrait pre print projection purple red relative repeat repeat-x repeat-y rgb ridge right right-side '+
						'rightwards rtl run-in screen scroll semi-condensed semi-expanded separate se-resize show silent silver slower slow '+
						'small small-caps small-caption smaller soft solid speech spell-out square s-resize static status-bar sub super sw-resize '+
						'table-caption table-cell table-column table-column-group table-footer-group table-header-group table-row table-row-group teal '+
						'text-bottom text-top thick thin top transparent tty tv ultra-condensed ultra-expanded underline upper-alpha uppercase upper-latin '+
						'upper-roman url visible wait white wider w-resize x-fast x-high x-large x-loud x-low x-slow x-small x-soft xx-large xx-small yellow';

		var fonts =		'[mM]onospace [tT]ahoma [vV]erdana [aA]rial [hH]elvetica [sS]ans-serif [sS]erif [cC]ourier mono sans serif';
	
		this.regexList = [
			{ regex: SyntaxHighlighter.regexLib.multiLineCComments,		css: 'comments' },	// multiline comments
			{ regex: SyntaxHighlighter.regexLib.doubleQuotedString,		css: 'string' },	// double quoted strings
			{ regex: SyntaxHighlighter.regexLib.singleQuotedString,		css: 'string' },	// single quoted strings
			{ regex: /\#[a-fA-F0-9]{3,6}/g,								css: 'value' },		// html colors
			{ regex: /(-?\d+)(\.\d+)?(px|em|pt|\:|\%|)/g,				css: 'value' },		// sizes
			{ regex: /!important/g,										css: 'color3' },	// !important
			{ regex: new RegExp(getKeywordsCSS(keywords), 'gm'),		css: 'keyword' },	// keywords
			{ regex: new RegExp(getValuesCSS(values), 'g'),				css: 'value' },		// values
			{ regex: new RegExp(this.getKeywords(fonts), 'g'),			css: 'color1' }		// fonts
			];

		this.forHtmlScript({ 
			left: /(&lt;|<)\s*style.*?(&gt;|>)/gi, 
			right: /(&lt;|<)\/\s*style\s*(&gt;|>)/gi 
			});
	};

	Brush.prototype	= new SyntaxHighlighter.Highlighter();
	Brush.aliases	= ['css'];

	SyntaxHighlighter.brushes.CSS = Brush;

	// CommonJS
	typeof(exports) != 'undefined' ? exports.Brush = Brush : null;
})();
//}}}
/***
***/
/*{{{*/
/**
 * SyntaxHighlighter
 * http://alexgorbatchev.com/SyntaxHighlighter
 *
 * SyntaxHighlighter is donationware. If you are using it, please donate.
 * http://alexgorbatchev.com/SyntaxHighlighter/donate.html
 *
 * @version
 * 3.0.83 (July 02 2010)
 * 
 * @copyright
 * Copyright (C) 2004-2010 Alex Gorbatchev.
 *
 * @license
 * Dual licensed under the MIT and GPL licenses.
 */
;(function()
{
	// CommonJS
	typeof(require) != 'undefined' ? SyntaxHighlighter = require('shCore').SyntaxHighlighter : null;

	function Brush()
	{
		var keywords =	'break case catch continue ' +
						'default delete do else false  ' +
						'for function if in instanceof ' +
						'new null return super switch ' +
						'this throw true try typeof var while with'
						;

		var r = SyntaxHighlighter.regexLib;
		
		this.regexList = [
			{ regex: r.multiLineDoubleQuotedString,					css: 'string' },			// double quoted strings
			{ regex: r.multiLineSingleQuotedString,					css: 'string' },			// single quoted strings
			{ regex: r.singleLineCComments,							css: 'comments' },			// one line comments
			{ regex: r.multiLineCComments,							css: 'comments' },			// multiline comments
			{ regex: /\s*#.*/gm,									css: 'preprocessor' },		// preprocessor tags like #region and #endregion
			{ regex: new RegExp(this.getKeywords(keywords), 'gm'),	css: 'keyword' }			// keywords
			];
	
		this.forHtmlScript(r.scriptScriptTags);
	};

	Brush.prototype	= new SyntaxHighlighter.Highlighter();
	Brush.aliases	= ['js', 'jscript', 'javascript'];

	SyntaxHighlighter.brushes.JScript = Brush;

	// CommonJS
	typeof(exports) != 'undefined' ? exports.Brush = Brush : null;
})();
/*}}}*/
//{{{
/**
 * SyntaxHighlighter
 * http://alexgorbatchev.com/SyntaxHighlighter
 *
 * SyntaxHighlighter is donationware. If you are using it, please donate.
 * http://alexgorbatchev.com/SyntaxHighlighter/donate.html
 *
 * @version
 * 3.0.83 (July 02 2010)
 * 
 * @copyright
 * Copyright (C) 2004-2010 Alex Gorbatchev.
 *
 * @license
 * Dual licensed under the MIT and GPL licenses.
 */
;(function()
{
	// CommonJS
	typeof(require) != 'undefined' ? SyntaxHighlighter = require('shCore').SyntaxHighlighter : null;

	function Brush()
	{
	};

	Brush.prototype	= new SyntaxHighlighter.Highlighter();
	Brush.aliases	= ['text', 'plain'];

	SyntaxHighlighter.brushes.Plain = Brush;

	// CommonJS
	typeof(exports) != 'undefined' ? exports.Brush = Brush : null;
})();
//}}}
//{{{
/**
 * SyntaxHighlighter
 * http://alexgorbatchev.com/SyntaxHighlighter
 *
 * SyntaxHighlighter is donationware. If you are using it, please donate.
 * http://alexgorbatchev.com/SyntaxHighlighter/donate.html
 *
 * @version
 * 3.0.83 (July 02 2010)
 * 
 * @copyright
 * Copyright (C) 2004-2010 Alex Gorbatchev.
 *
 * @license
 * Dual licensed under the MIT and GPL licenses.
 */
;(function()
{
	// CommonJS
	typeof(require) != 'undefined' ? SyntaxHighlighter = require('shCore').SyntaxHighlighter : null;

	function Brush()
	{
		// Contributed by Gheorghe Milas and Ahmad Sherif
	
		var keywords =  'and assert break class continue def del elif else ' +
						'except exec finally for from global if import in is ' +
						'lambda not or pass print raise return try yield while';

		var funcs = '__import__ abs all any apply basestring bin bool buffer callable ' +
					'chr classmethod cmp coerce compile complex delattr dict dir ' +
					'divmod enumerate eval execfile file filter float format frozenset ' +
					'getattr globals hasattr hash help hex id input int intern ' +
					'isinstance issubclass iter len list locals long map max min next ' +
					'object oct open ord pow print property range raw_input reduce ' +
					'reload repr reversed round set setattr slice sorted staticmethod ' +
					'str sum super tuple type type unichr unicode vars xrange zip';

		var special =  'None True False self cls class_';

		this.regexList = [
				{ regex: SyntaxHighlighter.regexLib.singleLinePerlComments, css: 'comments' },
				{ regex: /^\s*@\w+/gm, 										css: 'decorator' },
				{ regex: /(['\"]{3})([^\1])*?\1/gm, 						css: 'comments' },
				{ regex: /"(?!")(?:\.|\\\"|[^\""\n])*"/gm, 					css: 'string' },
				{ regex: /'(?!')(?:\.|(\\\')|[^\''\n])*'/gm, 				css: 'string' },
				{ regex: /\+|\-|\*|\/|\%|=|==/gm, 							css: 'keyword' },
				{ regex: /\b\d+\.?\w*/g, 									css: 'value' },
				{ regex: new RegExp(this.getKeywords(funcs), 'gmi'),		css: 'functions' },
				{ regex: new RegExp(this.getKeywords(keywords), 'gm'), 		css: 'keyword' },
				{ regex: new RegExp(this.getKeywords(special), 'gm'), 		css: 'color1' }
				];
			
		this.forHtmlScript(SyntaxHighlighter.regexLib.aspScriptTags);
	};

	Brush.prototype	= new SyntaxHighlighter.Highlighter();
	Brush.aliases	= ['py', 'python'];

	SyntaxHighlighter.brushes.Python = Brush;

	// CommonJS
	typeof(exports) != 'undefined' ? exports.Brush = Brush : null;
})();
//}}}
//{{{
/**
 * SyntaxHighlighter
 * http://alexgorbatchev.com/SyntaxHighlighter
 *
 * SyntaxHighlighter is donationware. If you are using it, please donate.
 * http://alexgorbatchev.com/SyntaxHighlighter/donate.html
 *
 * @version
 * 3.0.83 (July 02 2010)
 * 
 * @copyright
 * Copyright (C) 2004-2010 Alex Gorbatchev.
 *
 * @license
 * Dual licensed under the MIT and GPL licenses.
 */
;(function()
{
	// CommonJS
	typeof(require) != 'undefined' ? SyntaxHighlighter = require('shCore').SyntaxHighlighter : null;

	function Brush()
	{
		function process(match, regexInfo)
		{
			var constructor = SyntaxHighlighter.Match,
				code = match[0],
				tag = new XRegExp('(&lt;|<)[\\s\\/\\?]*(?<name>[:\\w-\\.]+)', 'xg').exec(code),
				result = []
				;
		
			if (match.attributes != null) 
			{
				var attributes,
					regex = new XRegExp('(?<name> [\\w:\\-\\.]+)' +
										'\\s*=\\s*' +
										'(?<value> ".*?"|\'.*?\'|\\w+)',
										'xg');

				while ((attributes = regex.exec(code)) != null) 
				{
					result.push(new constructor(attributes.name, match.index + attributes.index, 'color1'));
					result.push(new constructor(attributes.value, match.index + attributes.index + attributes[0].indexOf(attributes.value), 'string'));
				}
			}

			if (tag != null)
				result.push(
					new constructor(tag.name, match.index + tag[0].indexOf(tag.name), 'keyword')
				);

			return result;
		}
	
		this.regexList = [
			{ regex: new XRegExp('(\\&lt;|<)\\!\\[[\\w\\s]*?\\[(.|\\s)*?\\]\\](\\&gt;|>)', 'gm'),			css: 'color2' },	// <![ ... [ ... ]]>
			{ regex: SyntaxHighlighter.regexLib.xmlComments,												css: 'comments' },	// <!-- ... -->
			{ regex: new XRegExp('(&lt;|<)[\\s\\/\\?]*(\\w+)(?<attributes>.*?)[\\s\\/\\?]*(&gt;|>)', 'sg'), func: process }
		];
	};

	Brush.prototype	= new SyntaxHighlighter.Highlighter();
	Brush.aliases	= ['xml', 'xhtml', 'xslt', 'html'];

	SyntaxHighlighter.brushes.Xml = Brush;

	// CommonJS
	typeof(exports) != 'undefined' ? exports.Brush = Brush : null;
})();
//}}}
/*{{{*/
/**
 * SyntaxHighlighter
 * http://alexgorbatchev.com/SyntaxHighlighter
 *
 * SyntaxHighlighter is donationware. If you are using it, please donate.
 * http://alexgorbatchev.com/SyntaxHighlighter/donate.html
 *
 * @version
 * 3.0.83 (July 02 2010)
 * 
 * @copyright
 * Copyright (C) 2004-2010 Alex Gorbatchev.
 *
 * @license
 * Dual licensed under the MIT and GPL licenses.
 */
.syntaxhighlighter a,
.syntaxhighlighter div,
.syntaxhighlighter code,
.syntaxhighlighter table,
.syntaxhighlighter table td,
.syntaxhighlighter table tr,
.syntaxhighlighter table tbody,
.syntaxhighlighter table thead,
.syntaxhighlighter table caption,
.syntaxhighlighter textarea {
  -moz-border-radius: 0 0 0 0 !important;
  -webkit-border-radius: 0 0 0 0 !important;
  background: none !important;
  border: 0 !important;
  bottom: auto !important;
  float: none !important;
  height: auto !important;
  left: auto !important;
  line-height: 1.1em !important;
  margin: 0 !important;
  outline: 0 !important;
  overflow: visible !important;
  padding: 0 !important;
  position: static !important;
  right: auto !important;
  text-align: left !important;
  top: auto !important;
  vertical-align: baseline !important;
  width: auto !important;
  box-sizing: content-box !important;
  font-family: "Consolas", "Bitstream Vera Sans Mono", "Courier New", Courier, monospace !important;
  font-weight: normal !important;
  font-style: normal !important;
  font-size: 1em !important;
  min-height: inherit !important;
  min-height: auto !important;
}

.syntaxhighlighter {
  width: 100% !important;
  margin: 1em 0 1em 0 !important;
  position: relative !important;
  overflow: auto !important;
  font-size: .9em !important;
}
.syntaxhighlighter.source {
  overflow: hidden !important;
}
.syntaxhighlighter .bold {
  font-weight: bold !important;
}
.syntaxhighlighter .italic {
  font-style: italic !important;
}
.syntaxhighlighter .line {
  white-space: pre !important;
}
.syntaxhighlighter table {
  width: 100% !important;
}
.syntaxhighlighter table caption {
  text-align: left !important;
  padding: .5em 0 0.5em 1em !important;
}
.syntaxhighlighter table td.code {
  width: 100% !important;
}
.syntaxhighlighter table td.code .container {
  position: relative !important;
}
.syntaxhighlighter table td.code .container textarea {
  box-sizing: border-box !important;
  position: absolute !important;
  left: 0 !important;
  top: 0 !important;
  width: 100% !important;
  height: 100% !important;
  border: none !important;
  background: white !important;
  padding-left: 1em !important;
  overflow: hidden !important;
  white-space: pre !important;
}
.syntaxhighlighter table td.gutter .line {
  text-align: right !important;
  padding: 0 0.5em 0 1em !important;
}
.syntaxhighlighter table td.code .line {
  padding: 0 1em !important;
}
.syntaxhighlighter.nogutter td.code .container textarea, .syntaxhighlighter.nogutter td.code .line {
  padding-left: 0em !important;
}
.syntaxhighlighter.show {
  display: block !important;
}
.syntaxhighlighter.collapsed table {
  display: none !important;
}
.syntaxhighlighter.collapsed .toolbar {
  padding: 0.1em 0.8em 0em 0.8em !important;
  font-size: 1em !important;
  position: static !important;
  width: auto !important;
  height: auto !important;
}
.syntaxhighlighter.collapsed .toolbar span {
  display: inline !important;
  margin-right: 1em !important;
}
.syntaxhighlighter.collapsed .toolbar span a {
  padding: 0 !important;
  display: none !important;
}
.syntaxhighlighter.collapsed .toolbar span a.expandSource {
  display: inline !important;
}
.syntaxhighlighter .toolbar {
  position: absolute !important;
  right: 1px !important;
  top: 1px !important;
  width: 11px !important;
  height: 11px !important;
  font-size: 10px !important;
  z-index: 10 !important;
}
.syntaxhighlighter .toolbar span.title {
  display: inline !important;
}
.syntaxhighlighter .toolbar a {
  display: block !important;
  text-align: center !important;
  text-decoration: none !important;
  padding-top: 1px !important;
}
.syntaxhighlighter .toolbar a.expandSource {
  display: none !important;
}
.syntaxhighlighter.ie {
  font-size: .9em !important;
  padding: 1px 0 1px 0 !important;
}
.syntaxhighlighter.ie .toolbar {
  line-height: 8px !important;
}
.syntaxhighlighter.ie .toolbar a {
  padding-top: 0px !important;
}
.syntaxhighlighter.printing .line.alt1 .content,
.syntaxhighlighter.printing .line.alt2 .content,
.syntaxhighlighter.printing .line.highlighted .number,
.syntaxhighlighter.printing .line.highlighted.alt1 .content,
.syntaxhighlighter.printing .line.highlighted.alt2 .content {
  background: none !important;
}
.syntaxhighlighter.printing .line .number {
  color: #bbbbbb !important;
}
.syntaxhighlighter.printing .line .content {
  color: black !important;
}
.syntaxhighlighter.printing .toolbar {
  display: none !important;
}
.syntaxhighlighter.printing a {
  text-decoration: none !important;
}
.syntaxhighlighter.printing .plain, .syntaxhighlighter.printing .plain a {
  color: black !important;
}
.syntaxhighlighter.printing .comments, .syntaxhighlighter.printing .comments a {
  color: #008200 !important;
}
.syntaxhighlighter.printing .string, .syntaxhighlighter.printing .string a {
  color: blue !important;
}
.syntaxhighlighter.printing .keyword {
  color: #006699 !important;
  font-weight: bold !important;
}
.syntaxhighlighter.printing .preprocessor {
  color: gray !important;
}
.syntaxhighlighter.printing .variable {
  color: #aa7700 !important;
}
.syntaxhighlighter.printing .value {
  color: #009900 !important;
}
.syntaxhighlighter.printing .functions {
  color: #ff1493 !important;
}
.syntaxhighlighter.printing .constants {
  color: #0066cc !important;
}
.syntaxhighlighter.printing .script {
  font-weight: bold !important;
}
.syntaxhighlighter.printing .color1, .syntaxhighlighter.printing .color1 a {
  color: gray !important;
}
.syntaxhighlighter.printing .color2, .syntaxhighlighter.printing .color2 a {
  color: #ff1493 !important;
}
.syntaxhighlighter.printing .color3, .syntaxhighlighter.printing .color3 a {
  color: red !important;
}
.syntaxhighlighter.printing .break, .syntaxhighlighter.printing .break a {
  color: black !important;
}
/*}}}*/
/***
|Name|ShCore.js|
***/
/**
 * SyntaxHighlighter
 * http://alexgorbatchev.com/SyntaxHighlighter
 *
 * SyntaxHighlighter is donationware. If you are using it, please donate.
 * http://alexgorbatchev.com/SyntaxHighlighter/donate.html
 *
 * @version
 * 3.0.83 (July 02 2010)
 * 
 * @copyright
 * Copyright (C) 2004-2010 Alex Gorbatchev.
 *
 * @license
 * Dual licensed under the MIT and GPL licenses.
 */
//{{{
eval(function(p,a,c,k,e,d){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--){d[e(c)]=k[c]||e(c)}k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1};while(c--){if(k[c]){p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c])}}return p}('K M;I(M)1S 2U("2a\'t 4k M 4K 2g 3l 4G 4H");(6(){6 r(f,e){I(!M.1R(f))1S 3m("3s 15 4R");K a=f.1w;f=M(f.1m,t(f)+(e||""));I(a)f.1w={1m:a.1m,19:a.19?a.19.1a(0):N};H f}6 t(f){H(f.1J?"g":"")+(f.4s?"i":"")+(f.4p?"m":"")+(f.4v?"x":"")+(f.3n?"y":"")}6 B(f,e,a,b){K c=u.L,d,h,g;v=R;5K{O(;c--;){g=u[c];I(a&g.3r&&(!g.2p||g.2p.W(b))){g.2q.12=e;I((h=g.2q.X(f))&&h.P===e){d={3k:g.2b.W(b,h,a),1C:h};1N}}}}5v(i){1S i}5q{v=11}H d}6 p(f,e,a){I(3b.Z.1i)H f.1i(e,a);O(a=a||0;a<f.L;a++)I(f[a]===e)H a;H-1}M=6(f,e){K a=[],b=M.1B,c=0,d,h;I(M.1R(f)){I(e!==1d)1S 3m("2a\'t 5r 5I 5F 5B 5C 15 5E 5p");H r(f)}I(v)1S 2U("2a\'t W 3l M 59 5m 5g 5x 5i");e=e||"";O(d={2N:11,19:[],2K:6(g){H e.1i(g)>-1},3d:6(g){e+=g}};c<f.L;)I(h=B(f,c,b,d)){a.U(h.3k);c+=h.1C[0].L||1}Y I(h=n.X.W(z[b],f.1a(c))){a.U(h[0]);c+=h[0].L}Y{h=f.3a(c);I(h==="[")b=M.2I;Y I(h==="]")b=M.1B;a.U(h);c++}a=15(a.1K(""),n.Q.W(e,w,""));a.1w={1m:f,19:d.2N?d.19:N};H a};M.3v="1.5.0";M.2I=1;M.1B=2;K C=/\\$(?:(\\d\\d?|[$&`\'])|{([$\\w]+)})/g,w=/[^5h]+|([\\s\\S])(?=[\\s\\S]*\\1)/g,A=/^(?:[?*+]|{\\d+(?:,\\d*)?})\\??/,v=11,u=[],n={X:15.Z.X,1A:15.Z.1A,1C:1r.Z.1C,Q:1r.Z.Q,1e:1r.Z.1e},x=n.X.W(/()??/,"")[1]===1d,D=6(){K f=/^/g;n.1A.W(f,"");H!f.12}(),y=6(){K f=/x/g;n.Q.W("x",f,"");H!f.12}(),E=15.Z.3n!==1d,z={};z[M.2I]=/^(?:\\\\(?:[0-3][0-7]{0,2}|[4-7][0-7]?|x[\\29-26-f]{2}|u[\\29-26-f]{4}|c[A-3o-z]|[\\s\\S]))/;z[M.1B]=/^(?:\\\\(?:0(?:[0-3][0-7]{0,2}|[4-7][0-7]?)?|[1-9]\\d*|x[\\29-26-f]{2}|u[\\29-26-f]{4}|c[A-3o-z]|[\\s\\S])|\\(\\?[:=!]|[?*+]\\?|{\\d+(?:,\\d*)?}\\??)/;M.1h=6(f,e,a,b){u.U({2q:r(f,"g"+(E?"y":"")),2b:e,3r:a||M.1B,2p:b||N})};M.2n=6(f,e){K a=f+"/"+(e||"");H M.2n[a]||(M.2n[a]=M(f,e))};M.3c=6(f){H r(f,"g")};M.5l=6(f){H f.Q(/[-[\\]{}()*+?.,\\\\^$|#\\s]/g,"\\\\$&")};M.5e=6(f,e,a,b){e=r(e,"g"+(b&&E?"y":""));e.12=a=a||0;f=e.X(f);H b?f&&f.P===a?f:N:f};M.3q=6(){M.1h=6(){1S 2U("2a\'t 55 1h 54 3q")}};M.1R=6(f){H 53.Z.1q.W(f)==="[2m 15]"};M.3p=6(f,e,a,b){O(K c=r(e,"g"),d=-1,h;h=c.X(f);){a.W(b,h,++d,f,c);c.12===h.P&&c.12++}I(e.1J)e.12=0};M.57=6(f,e){H 6 a(b,c){K d=e[c].1I?e[c]:{1I:e[c]},h=r(d.1I,"g"),g=[],i;O(i=0;i<b.L;i++)M.3p(b[i],h,6(k){g.U(d.3j?k[d.3j]||"":k[0])});H c===e.L-1||!g.L?g:a(g,c+1)}([f],0)};15.Z.1p=6(f,e){H J.X(e[0])};15.Z.W=6(f,e){H J.X(e)};15.Z.X=6(f){K e=n.X.1p(J,14),a;I(e){I(!x&&e.L>1&&p(e,"")>-1){a=15(J.1m,n.Q.W(t(J),"g",""));n.Q.W(f.1a(e.P),a,6(){O(K c=1;c<14.L-2;c++)I(14[c]===1d)e[c]=1d})}I(J.1w&&J.1w.19)O(K b=1;b<e.L;b++)I(a=J.1w.19[b-1])e[a]=e[b];!D&&J.1J&&!e[0].L&&J.12>e.P&&J.12--}H e};I(!D)15.Z.1A=6(f){(f=n.X.W(J,f))&&J.1J&&!f[0].L&&J.12>f.P&&J.12--;H!!f};1r.Z.1C=6(f){M.1R(f)||(f=15(f));I(f.1J){K e=n.1C.1p(J,14);f.12=0;H e}H f.X(J)};1r.Z.Q=6(f,e){K a=M.1R(f),b,c;I(a&&1j e.58()==="3f"&&e.1i("${")===-1&&y)H n.Q.1p(J,14);I(a){I(f.1w)b=f.1w.19}Y f+="";I(1j e==="6")c=n.Q.W(J,f,6(){I(b){14[0]=1f 1r(14[0]);O(K d=0;d<b.L;d++)I(b[d])14[0][b[d]]=14[d+1]}I(a&&f.1J)f.12=14[14.L-2]+14[0].L;H e.1p(N,14)});Y{c=J+"";c=n.Q.W(c,f,6(){K d=14;H n.Q.W(e,C,6(h,g,i){I(g)5b(g){24"$":H"$";24"&":H d[0];24"`":H d[d.L-1].1a(0,d[d.L-2]);24"\'":H d[d.L-1].1a(d[d.L-2]+d[0].L);5a:i="";g=+g;I(!g)H h;O(;g>d.L-3;){i=1r.Z.1a.W(g,-1)+i;g=1Q.3i(g/10)}H(g?d[g]||"":"$")+i}Y{g=+i;I(g<=d.L-3)H d[g];g=b?p(b,i):-1;H g>-1?d[g+1]:h}})})}I(a&&f.1J)f.12=0;H c};1r.Z.1e=6(f,e){I(!M.1R(f))H n.1e.1p(J,14);K a=J+"",b=[],c=0,d,h;I(e===1d||+e<0)e=5D;Y{e=1Q.3i(+e);I(!e)H[]}O(f=M.3c(f);d=f.X(a);){I(f.12>c){b.U(a.1a(c,d.P));d.L>1&&d.P<a.L&&3b.Z.U.1p(b,d.1a(1));h=d[0].L;c=f.12;I(b.L>=e)1N}f.12===d.P&&f.12++}I(c===a.L){I(!n.1A.W(f,"")||h)b.U("")}Y b.U(a.1a(c));H b.L>e?b.1a(0,e):b};M.1h(/\\(\\?#[^)]*\\)/,6(f){H n.1A.W(A,f.2S.1a(f.P+f[0].L))?"":"(?:)"});M.1h(/\\((?!\\?)/,6(){J.19.U(N);H"("});M.1h(/\\(\\?<([$\\w]+)>/,6(f){J.19.U(f[1]);J.2N=R;H"("});M.1h(/\\\\k<([\\w$]+)>/,6(f){K e=p(J.19,f[1]);H e>-1?"\\\\"+(e+1)+(3R(f.2S.3a(f.P+f[0].L))?"":"(?:)"):f[0]});M.1h(/\\[\\^?]/,6(f){H f[0]==="[]"?"\\\\b\\\\B":"[\\\\s\\\\S]"});M.1h(/^\\(\\?([5A]+)\\)/,6(f){J.3d(f[1]);H""});M.1h(/(?:\\s+|#.*)+/,6(f){H n.1A.W(A,f.2S.1a(f.P+f[0].L))?"":"(?:)"},M.1B,6(){H J.2K("x")});M.1h(/\\./,6(){H"[\\\\s\\\\S]"},M.1B,6(){H J.2K("s")})})();1j 2e!="1d"&&(2e.M=M);K 1v=6(){6 r(a,b){a.1l.1i(b)!=-1||(a.1l+=" "+b)}6 t(a){H a.1i("3e")==0?a:"3e"+a}6 B(a){H e.1Y.2A[t(a)]}6 p(a,b,c){I(a==N)H N;K d=c!=R?a.3G:[a.2G],h={"#":"1c",".":"1l"}[b.1o(0,1)]||"3h",g,i;g=h!="3h"?b.1o(1):b.5u();I((a[h]||"").1i(g)!=-1)H a;O(a=0;d&&a<d.L&&i==N;a++)i=p(d[a],b,c);H i}6 C(a,b){K c={},d;O(d 2g a)c[d]=a[d];O(d 2g b)c[d]=b[d];H c}6 w(a,b,c,d){6 h(g){g=g||1P.5y;I(!g.1F){g.1F=g.52;g.3N=6(){J.5w=11}}c.W(d||1P,g)}a.3g?a.3g("4U"+b,h):a.4y(b,h,11)}6 A(a,b){K c=e.1Y.2j,d=N;I(c==N){c={};O(K h 2g e.1U){K g=e.1U[h];d=g.4x;I(d!=N){g.1V=h.4w();O(g=0;g<d.L;g++)c[d[g]]=h}}e.1Y.2j=c}d=e.1U[c[a]];d==N&&b!=11&&1P.1X(e.13.1x.1X+(e.13.1x.3E+a));H d}6 v(a,b){O(K c=a.1e("\\n"),d=0;d<c.L;d++)c[d]=b(c[d],d);H c.1K("\\n")}6 u(a,b){I(a==N||a.L==0||a=="\\n")H a;a=a.Q(/</g,"&1y;");a=a.Q(/ {2,}/g,6(c){O(K d="",h=0;h<c.L-1;h++)d+=e.13.1W;H d+" "});I(b!=N)a=v(a,6(c){I(c.L==0)H"";K d="";c=c.Q(/^(&2s;| )+/,6(h){d=h;H""});I(c.L==0)H d;H d+\'<17 1g="\'+b+\'">\'+c+"</17>"});H a}6 n(a,b){a.1e("\\n");O(K c="",d=0;d<50;d++)c+="                    ";H a=v(a,6(h){I(h.1i("\\t")==-1)H h;O(K g=0;(g=h.1i("\\t"))!=-1;)h=h.1o(0,g)+c.1o(0,b-g%b)+h.1o(g+1,h.L);H h})}6 x(a){H a.Q(/^\\s+|\\s+$/g,"")}6 D(a,b){I(a.P<b.P)H-1;Y I(a.P>b.P)H 1;Y I(a.L<b.L)H-1;Y I(a.L>b.L)H 1;H 0}6 y(a,b){6 c(k){H k[0]}O(K d=N,h=[],g=b.2D?b.2D:c;(d=b.1I.X(a))!=N;){K i=g(d,b);I(1j i=="3f")i=[1f e.2L(i,d.P,b.23)];h=h.1O(i)}H h}6 E(a){K b=/(.*)((&1G;|&1y;).*)/;H a.Q(e.3A.3M,6(c){K d="",h=N;I(h=b.X(c)){c=h[1];d=h[2]}H\'<a 2h="\'+c+\'">\'+c+"</a>"+d})}6 z(){O(K a=1E.36("1k"),b=[],c=0;c<a.L;c++)a[c].3s=="20"&&b.U(a[c]);H b}6 f(a){a=a.1F;K b=p(a,".20",R);a=p(a,".3O",R);K c=1E.4i("3t");I(!(!a||!b||p(a,"3t"))){B(b.1c);r(b,"1m");O(K d=a.3G,h=[],g=0;g<d.L;g++)h.U(d[g].4z||d[g].4A);h=h.1K("\\r");c.39(1E.4D(h));a.39(c);c.2C();c.4C();w(c,"4u",6(){c.2G.4E(c);b.1l=b.1l.Q("1m","")})}}I(1j 3F!="1d"&&1j M=="1d")M=3F("M").M;K e={2v:{"1g-27":"","2i-1s":1,"2z-1s-2t":11,1M:N,1t:N,"42-45":R,"43-22":4,1u:R,16:R,"3V-17":R,2l:11,"41-40":R,2k:11,"1z-1k":11},13:{1W:"&2s;",2M:R,46:11,44:11,34:"4n",1x:{21:"4o 1m",2P:"?",1X:"1v\\n\\n",3E:"4r\'t 4t 1D O: ",4g:"4m 4B\'t 51 O 1z-1k 4F: ",37:\'<!4T 1z 4S "-//4V//3H 4W 1.0 4Z//4Y" "1Z://2y.3L.3K/4X/3I/3H/3I-4P.4J"><1z 4I="1Z://2y.3L.3K/4L/5L"><3J><4N 1Z-4M="5G-5M" 6K="2O/1z; 6J=6I-8" /><1t>6L 1v</1t></3J><3B 1L="25-6M:6Q,6P,6O,6N-6F;6y-2f:#6x;2f:#6w;25-22:6v;2O-3D:3C;"><T 1L="2O-3D:3C;3w-32:1.6z;"><T 1L="25-22:6A-6E;">1v</T><T 1L="25-22:.6C;3w-6B:6R;"><T>3v 3.0.76 (72 73 3x)</T><T><a 2h="1Z://3u.2w/1v" 1F="38" 1L="2f:#3y">1Z://3u.2w/1v</a></T><T>70 17 6U 71.</T><T>6T 6X-3x 6Y 6D.</T></T><T>6t 61 60 J 1k, 5Z <a 2h="6u://2y.62.2w/63-66/65?64=5X-5W&5P=5O" 1L="2f:#3y">5R</a> 5V <2R/>5U 5T 5S!</T></T></3B></1z>\'}},1Y:{2j:N,2A:{}},1U:{},3A:{6n:/\\/\\*[\\s\\S]*?\\*\\//2c,6m:/\\/\\/.*$/2c,6l:/#.*$/2c,6k:/"([^\\\\"\\n]|\\\\.)*"/g,6o:/\'([^\\\\\'\\n]|\\\\.)*\'/g,6p:1f M(\'"([^\\\\\\\\"]|\\\\\\\\.)*"\',"3z"),6s:1f M("\'([^\\\\\\\\\']|\\\\\\\\.)*\'","3z"),6q:/(&1y;|<)!--[\\s\\S]*?--(&1G;|>)/2c,3M:/\\w+:\\/\\/[\\w-.\\/?%&=:@;]*/g,6a:{18:/(&1y;|<)\\?=?/g,1b:/\\?(&1G;|>)/g},69:{18:/(&1y;|<)%=?/g,1b:/%(&1G;|>)/g},6d:{18:/(&1y;|<)\\s*1k.*?(&1G;|>)/2T,1b:/(&1y;|<)\\/\\s*1k\\s*(&1G;|>)/2T}},16:{1H:6(a){6 b(i,k){H e.16.2o(i,k,e.13.1x[k])}O(K c=\'<T 1g="16">\',d=e.16.2x,h=d.2X,g=0;g<h.L;g++)c+=(d[h[g]].1H||b)(a,h[g]);c+="</T>";H c},2o:6(a,b,c){H\'<2W><a 2h="#" 1g="6e 6h\'+b+" "+b+\'">\'+c+"</a></2W>"},2b:6(a){K b=a.1F,c=b.1l||"";b=B(p(b,".20",R).1c);K d=6(h){H(h=15(h+"6f(\\\\w+)").X(c))?h[1]:N}("6g");b&&d&&e.16.2x[d].2B(b);a.3N()},2x:{2X:["21","2P"],21:{1H:6(a){I(a.V("2l")!=R)H"";K b=a.V("1t");H e.16.2o(a,"21",b?b:e.13.1x.21)},2B:6(a){a=1E.6j(t(a.1c));a.1l=a.1l.Q("47","")}},2P:{2B:6(){K a="68=0";a+=", 18="+(31.30-33)/2+", 32="+(31.2Z-2Y)/2+", 30=33, 2Z=2Y";a=a.Q(/^,/,"");a=1P.6Z("","38",a);a.2C();K b=a.1E;b.6W(e.13.1x.37);b.6V();a.2C()}}}},35:6(a,b){K c;I(b)c=[b];Y{c=1E.36(e.13.34);O(K d=[],h=0;h<c.L;h++)d.U(c[h]);c=d}c=c;d=[];I(e.13.2M)c=c.1O(z());I(c.L===0)H d;O(h=0;h<c.L;h++){O(K g=c[h],i=a,k=c[h].1l,j=3W 0,l={},m=1f M("^\\\\[(?<2V>(.*?))\\\\]$"),s=1f M("(?<27>[\\\\w-]+)\\\\s*:\\\\s*(?<1T>[\\\\w-%#]+|\\\\[.*?\\\\]|\\".*?\\"|\'.*?\')\\\\s*;?","g");(j=s.X(k))!=N;){K o=j.1T.Q(/^[\'"]|[\'"]$/g,"");I(o!=N&&m.1A(o)){o=m.X(o);o=o.2V.L>0?o.2V.1e(/\\s*,\\s*/):[]}l[j.27]=o}g={1F:g,1n:C(i,l)};g.1n.1D!=N&&d.U(g)}H d},1M:6(a,b){K c=J.35(a,b),d=N,h=e.13;I(c.L!==0)O(K g=0;g<c.L;g++){b=c[g];K i=b.1F,k=b.1n,j=k.1D,l;I(j!=N){I(k["1z-1k"]=="R"||e.2v["1z-1k"]==R){d=1f e.4l(j);j="4O"}Y I(d=A(j))d=1f d;Y 6H;l=i.3X;I(h.2M){l=l;K m=x(l),s=11;I(m.1i("<![6G[")==0){m=m.4h(9);s=R}K o=m.L;I(m.1i("]]\\>")==o-3){m=m.4h(0,o-3);s=R}l=s?m:l}I((i.1t||"")!="")k.1t=i.1t;k.1D=j;d.2Q(k);b=d.2F(l);I((i.1c||"")!="")b.1c=i.1c;i.2G.74(b,i)}}},2E:6(a){w(1P,"4k",6(){e.1M(a)})}};e.2E=e.2E;e.1M=e.1M;e.2L=6(a,b,c){J.1T=a;J.P=b;J.L=a.L;J.23=c;J.1V=N};e.2L.Z.1q=6(){H J.1T};e.4l=6(a){6 b(j,l){O(K m=0;m<j.L;m++)j[m].P+=l}K c=A(a),d,h=1f e.1U.5Y,g=J,i="2F 1H 2Q".1e(" ");I(c!=N){d=1f c;O(K k=0;k<i.L;k++)(6(){K j=i[k];g[j]=6(){H h[j].1p(h,14)}})();d.28==N?1P.1X(e.13.1x.1X+(e.13.1x.4g+a)):h.2J.U({1I:d.28.17,2D:6(j){O(K l=j.17,m=[],s=d.2J,o=j.P+j.18.L,F=d.28,q,G=0;G<s.L;G++){q=y(l,s[G]);b(q,o);m=m.1O(q)}I(F.18!=N&&j.18!=N){q=y(j.18,F.18);b(q,j.P);m=m.1O(q)}I(F.1b!=N&&j.1b!=N){q=y(j.1b,F.1b);b(q,j.P+j[0].5Q(j.1b));m=m.1O(q)}O(j=0;j<m.L;j++)m[j].1V=c.1V;H m}})}};e.4j=6(){};e.4j.Z={V:6(a,b){K c=J.1n[a];c=c==N?b:c;K d={"R":R,"11":11}[c];H d==N?c:d},3Y:6(a){H 1E.4i(a)},4c:6(a,b){K c=[];I(a!=N)O(K d=0;d<a.L;d++)I(1j a[d]=="2m")c=c.1O(y(b,a[d]));H J.4e(c.6b(D))},4e:6(a){O(K b=0;b<a.L;b++)I(a[b]!==N)O(K c=a[b],d=c.P+c.L,h=b+1;h<a.L&&a[b]!==N;h++){K g=a[h];I(g!==N)I(g.P>d)1N;Y I(g.P==c.P&&g.L>c.L)a[b]=N;Y I(g.P>=c.P&&g.P<d)a[h]=N}H a},4d:6(a){K b=[],c=2u(J.V("2i-1s"));v(a,6(d,h){b.U(h+c)});H b},3U:6(a){K b=J.V("1M",[]);I(1j b!="2m"&&b.U==N)b=[b];a:{a=a.1q();K c=3W 0;O(c=c=1Q.6c(c||0,0);c<b.L;c++)I(b[c]==a){b=c;1N a}b=-1}H b!=-1},2r:6(a,b,c){a=["1s","6i"+b,"P"+a,"6r"+(b%2==0?1:2).1q()];J.3U(b)&&a.U("67");b==0&&a.U("1N");H\'<T 1g="\'+a.1K(" ")+\'">\'+c+"</T>"},3Q:6(a,b){K c="",d=a.1e("\\n").L,h=2u(J.V("2i-1s")),g=J.V("2z-1s-2t");I(g==R)g=(h+d-1).1q().L;Y I(3R(g)==R)g=0;O(K i=0;i<d;i++){K k=b?b[i]:h+i,j;I(k==0)j=e.13.1W;Y{j=g;O(K l=k.1q();l.L<j;)l="0"+l;j=l}a=j;c+=J.2r(i,k,a)}H c},49:6(a,b){a=x(a);K c=a.1e("\\n");J.V("2z-1s-2t");K d=2u(J.V("2i-1s"));a="";O(K h=J.V("1D"),g=0;g<c.L;g++){K i=c[g],k=/^(&2s;|\\s)+/.X(i),j=N,l=b?b[g]:d+g;I(k!=N){j=k[0].1q();i=i.1o(j.L);j=j.Q(" ",e.13.1W)}i=x(i);I(i.L==0)i=e.13.1W;a+=J.2r(g,l,(j!=N?\'<17 1g="\'+h+\' 5N">\'+j+"</17>":"")+i)}H a},4f:6(a){H a?"<4a>"+a+"</4a>":""},4b:6(a,b){6 c(l){H(l=l?l.1V||g:g)?l+" ":""}O(K d=0,h="",g=J.V("1D",""),i=0;i<b.L;i++){K k=b[i],j;I(!(k===N||k.L===0)){j=c(k);h+=u(a.1o(d,k.P-d),j+"48")+u(k.1T,j+k.23);d=k.P+k.L+(k.75||0)}}h+=u(a.1o(d),c()+"48");H h},1H:6(a){K b="",c=["20"],d;I(J.V("2k")==R)J.1n.16=J.1n.1u=11;1l="20";J.V("2l")==R&&c.U("47");I((1u=J.V("1u"))==11)c.U("6S");c.U(J.V("1g-27"));c.U(J.V("1D"));a=a.Q(/^[ ]*[\\n]+|[\\n]*[ ]*$/g,"").Q(/\\r/g," ");b=J.V("43-22");I(J.V("42-45")==R)a=n(a,b);Y{O(K h="",g=0;g<b;g++)h+=" ";a=a.Q(/\\t/g,h)}a=a;a:{b=a=a;h=/<2R\\s*\\/?>|&1y;2R\\s*\\/?&1G;/2T;I(e.13.46==R)b=b.Q(h,"\\n");I(e.13.44==R)b=b.Q(h,"");b=b.1e("\\n");h=/^\\s*/;g=4Q;O(K i=0;i<b.L&&g>0;i++){K k=b[i];I(x(k).L!=0){k=h.X(k);I(k==N){a=a;1N a}g=1Q.4q(k[0].L,g)}}I(g>0)O(i=0;i<b.L;i++)b[i]=b[i].1o(g);a=b.1K("\\n")}I(1u)d=J.4d(a);b=J.4c(J.2J,a);b=J.4b(a,b);b=J.49(b,d);I(J.V("41-40"))b=E(b);1j 2H!="1d"&&2H.3S&&2H.3S.1C(/5s/)&&c.U("5t");H b=\'<T 1c="\'+t(J.1c)+\'" 1g="\'+c.1K(" ")+\'">\'+(J.V("16")?e.16.1H(J):"")+\'<3Z 5z="0" 5H="0" 5J="0">\'+J.4f(J.V("1t"))+"<3T><3P>"+(1u?\'<2d 1g="1u">\'+J.3Q(a)+"</2d>":"")+\'<2d 1g="17"><T 1g="3O">\'+b+"</T></2d></3P></3T></3Z></T>"},2F:6(a){I(a===N)a="";J.17=a;K b=J.3Y("T");b.3X=J.1H(a);J.V("16")&&w(p(b,".16"),"5c",e.16.2b);J.V("3V-17")&&w(p(b,".17"),"56",f);H b},2Q:6(a){J.1c=""+1Q.5d(1Q.5n()*5k).1q();e.1Y.2A[t(J.1c)]=J;J.1n=C(e.2v,a||{});I(J.V("2k")==R)J.1n.16=J.1n.1u=11},5j:6(a){a=a.Q(/^\\s+|\\s+$/g,"").Q(/\\s+/g,"|");H"\\\\b(?:"+a+")\\\\b"},5f:6(a){J.28={18:{1I:a.18,23:"1k"},1b:{1I:a.1b,23:"1k"},17:1f M("(?<18>"+a.18.1m+")(?<17>.*?)(?<1b>"+a.1b.1m+")","5o")}}};H e}();1j 2e!="1d"&&(2e.1v=1v);',62,441,'||||||function|||||||||||||||||||||||||||||||||||||return|if|this|var|length|XRegExp|null|for|index|replace|true||div|push|getParam|call|exec|else|prototype||false|lastIndex|config|arguments|RegExp|toolbar|code|left|captureNames|slice|right|id|undefined|split|new|class|addToken|indexOf|typeof|script|className|source|params|substr|apply|toString|String|line|title|gutter|SyntaxHighlighter|_xregexp|strings|lt|html|test|OUTSIDE_CLASS|match|brush|document|target|gt|getHtml|regex|global|join|style|highlight|break|concat|window|Math|isRegExp|throw|value|brushes|brushName|space|alert|vars|http|syntaxhighlighter|expandSource|size|css|case|font|Fa|name|htmlScript|dA|can|handler|gm|td|exports|color|in|href|first|discoveredBrushes|light|collapse|object|cache|getButtonHtml|trigger|pattern|getLineHtml|nbsp|numbers|parseInt|defaults|com|items|www|pad|highlighters|execute|focus|func|all|getDiv|parentNode|navigator|INSIDE_CLASS|regexList|hasFlag|Match|useScriptTags|hasNamedCapture|text|help|init|br|input|gi|Error|values|span|list|250|height|width|screen|top|500|tagName|findElements|getElementsByTagName|aboutDialog|_blank|appendChild|charAt|Array|copyAsGlobal|setFlag|highlighter_|string|attachEvent|nodeName|floor|backref|output|the|TypeError|sticky|Za|iterate|freezeTokens|scope|type|textarea|alexgorbatchev|version|margin|2010|005896|gs|regexLib|body|center|align|noBrush|require|childNodes|DTD|xhtml1|head|org|w3|url|preventDefault|container|tr|getLineNumbersHtml|isNaN|userAgent|tbody|isLineHighlighted|quick|void|innerHTML|create|table|links|auto|smart|tab|stripBrs|tabs|bloggerMode|collapsed|plain|getCodeLinesHtml|caption|getMatchesHtml|findMatches|figureOutLineNumbers|removeNestedMatches|getTitleHtml|brushNotHtmlScript|substring|createElement|Highlighter|load|HtmlScript|Brush|pre|expand|multiline|min|Can|ignoreCase|find|blur|extended|toLowerCase|aliases|addEventListener|innerText|textContent|wasn|select|createTextNode|removeChild|option|same|frame|xmlns|dtd|twice|1999|equiv|meta|htmlscript|transitional|1E3|expected|PUBLIC|DOCTYPE|on|W3C|XHTML|TR|EN|Transitional||configured|srcElement|Object|after|run|dblclick|matchChain|valueOf|constructor|default|switch|click|round|execAt|forHtmlScript|token|gimy|functions|getKeywords|1E6|escape|within|random|sgi|another|finally|supply|MSIE|ie|toUpperCase|catch|returnValue|definition|event|border|imsx|constructing|one|Infinity|from|when|Content|cellpadding|flags|cellspacing|try|xhtml|Type|spaces|2930402|hosted_button_id|lastIndexOf|donate|active|development|keep|to|xclick|_s|Xml|please|like|you|paypal|cgi|cmd|webscr|bin|highlighted|scrollbars|aspScriptTags|phpScriptTags|sort|max|scriptScriptTags|toolbar_item|_|command|command_|number|getElementById|doubleQuotedString|singleLinePerlComments|singleLineCComments|multiLineCComments|singleQuotedString|multiLineDoubleQuotedString|xmlComments|alt|multiLineSingleQuotedString|If|https|1em|000|fff|background|5em|xx|bottom|75em|Gorbatchev|large|serif|CDATA|continue|utf|charset|content|About|family|sans|Helvetica|Arial|Geneva|3em|nogutter|Copyright|syntax|close|write|2004|Alex|open|JavaScript|highlighter|July|02|replaceChild|offset|83'.split('|'),0,{}))
//}}}
/*{{{*/
/**
 * SyntaxHighlighter
 * http://alexgorbatchev.com/SyntaxHighlighter
 *
 * SyntaxHighlighter is donationware. If you are using it, please donate.
 * http://alexgorbatchev.com/SyntaxHighlighter/donate.html
 *
 * @version
 * 3.0.83 (July 02 2010)
 * 
 * @copyright
 * Copyright (C) 2004-2010 Alex Gorbatchev.
 *
 * @license
 * Dual licensed under the MIT and GPL licenses.
 */
.syntaxhighlighter {
  background-color: white !important;
}
.syntaxhighlighter .line.alt1 {
  background-color: white !important;
}
.syntaxhighlighter .line.alt2 {
  background-color: white !important;
}
.syntaxhighlighter .line.highlighted.alt1, .syntaxhighlighter .line.highlighted.alt2 {
  background-color: #e0e0e0 !important;
}
.syntaxhighlighter .line.highlighted.number {
  color: black !important;
}
.syntaxhighlighter table caption {
  color: black !important;
}
.syntaxhighlighter .gutter {
  color: #afafaf !important;
}
.syntaxhighlighter .gutter .line {
  border-right: 3px solid #6ce26c !important;
}
.syntaxhighlighter .gutter .line.highlighted {
  background-color: #6ce26c !important;
  color: white !important;
}
.syntaxhighlighter.printing .line .content {
  border: none !important;
}
.syntaxhighlighter.collapsed {
  overflow: visible !important;
}
.syntaxhighlighter.collapsed .toolbar {
  color: blue !important;
  background: white !important;
  border: 1px solid #6ce26c !important;
}
.syntaxhighlighter.collapsed .toolbar a {
  color: blue !important;
}
.syntaxhighlighter.collapsed .toolbar a:hover {
  color: red !important;
}
.syntaxhighlighter .toolbar {
  color: white !important;
  background: #6ce26c !important;
  border: none !important;
}
.syntaxhighlighter .toolbar a {
  color: white !important;
}
.syntaxhighlighter .toolbar a:hover {
  color: black !important;
}
.syntaxhighlighter .plain, .syntaxhighlighter .plain a {
  color: black !important;
}
.syntaxhighlighter .comments, .syntaxhighlighter .comments a {
  color: #008200 !important;
}
.syntaxhighlighter .string, .syntaxhighlighter .string a {
  color: blue !important;
}
.syntaxhighlighter .keyword {
  color: #006699 !important;
}
.syntaxhighlighter .preprocessor {
  color: gray !important;
}
.syntaxhighlighter .variable {
  color: #aa7700 !important;
}
.syntaxhighlighter .value {
  color: #009900 !important;
}
.syntaxhighlighter .functions {
  color: #ff1493 !important;
}
.syntaxhighlighter .constants {
  color: #0066cc !important;
}
.syntaxhighlighter .script {
  font-weight: bold !important;
  color: #006699 !important;
  background-color: none !important;
}
.syntaxhighlighter .color1, .syntaxhighlighter .color1 a {
  color: gray !important;
}
.syntaxhighlighter .color2, .syntaxhighlighter .color2 a {
  color: #ff1493 !important;
}
.syntaxhighlighter .color3, .syntaxhighlighter .color3 a {
  color: red !important;
}

.syntaxhighlighter .keyword {
  font-weight: bold !important;
}
/*}}}*/
/***
<<highlightSyntax>>
***/
/***
|Name|SinglePageModePlugin|
|Source|http://www.TiddlyTools.com/#SinglePageModePlugin|
|Documentation|http://www.TiddlyTools.com/#SinglePageModePluginInfo|
|Version|2.9.7|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|Show tiddlers one at a time with automatic permalink, or always open tiddlers at top/bottom of page.|
This plugin allows you to configure TiddlyWiki to navigate more like a traditional multipage web site with only one tiddler displayed at a time.
!!!!!Documentation
>see [[SinglePageModePluginInfo]]
!!!!!Configuration
<<<
<<option chkSinglePageMode>> Display one tiddler at a time
><<option chkSinglePagePermalink>> Automatically permalink current tiddler
><<option chkSinglePageKeepFoldedTiddlers>> Don't close tiddlers that are folded
><<option chkSinglePageKeepEditedTiddlers>> Don't close tiddlers that are being edited
<<option chkTopOfPageMode>> Open tiddlers at the top of the page
<<option chkBottomOfPageMode>> Open tiddlers at the bottom of the page
<<option chkSinglePageAutoScroll>> Automatically scroll tiddler into view (if needed)

Notes:
* The "display one tiddler at a time" option can also be //temporarily// set/reset by including a 'paramifier' in the document URL: {{{#SPM:true}}} or {{{#SPM:false}}}.
* If more than one display mode is selected, 'one at a time' display takes precedence over both 'top' and 'bottom' settings, and if 'one at a time' setting is not used, 'top of page' takes precedence over 'bottom of page'.
* When using Apple's Safari browser, automatically setting the permalink causes an error and is disabled.
<<<
!!!!!Revisions
<<<
2010.11.30 2.9.7 use story.getTiddler()
2008.10.17 2.9.6 changed chkSinglePageAutoScroll default to false
| Please see [[SinglePageModePluginInfo]] for previous revision details |
2005.08.15 1.0.0 Initial Release.  Support for BACK/FORWARD buttons adapted from code developed by Clint Checketts.
<<<
!!!!!Code
***/
//{{{
version.extensions.SinglePageModePlugin= {major: 2, minor: 9, revision: 7, date: new Date(2010,11,30)};
//}}}
//{{{
config.paramifiers.SPM = { onstart: function(v) {
	config.options.chkSinglePageMode=eval(v);
	if (config.options.chkSinglePageMode && config.options.chkSinglePagePermalink && !config.browser.isSafari) {
		config.lastURL = window.location.hash;
		if (!config.SPMTimer) config.SPMTimer=window.setInterval(function() {checkLastURL();},1000);
	}
} };
//}}}
//{{{
if (config.options.chkSinglePageMode==undefined)
	config.options.chkSinglePageMode=false;
if (config.options.chkSinglePagePermalink==undefined)
	config.options.chkSinglePagePermalink=true;
if (config.options.chkSinglePageKeepFoldedTiddlers==undefined)
	config.options.chkSinglePageKeepFoldedTiddlers=false;
if (config.options.chkSinglePageKeepEditedTiddlers==undefined)
	config.options.chkSinglePageKeepEditedTiddlers=false;
if (config.options.chkTopOfPageMode==undefined)
	config.options.chkTopOfPageMode=false;
if (config.options.chkBottomOfPageMode==undefined)
	config.options.chkBottomOfPageMode=false;
if (config.options.chkSinglePageAutoScroll==undefined)
	config.options.chkSinglePageAutoScroll=false;
//}}}
//{{{
config.SPMTimer = 0;
config.lastURL = window.location.hash;
function checkLastURL()
{
	if (!config.options.chkSinglePageMode)
		{ window.clearInterval(config.SPMTimer); config.SPMTimer=0; return; }
	if (config.lastURL == window.location.hash) return; // no change in hash
	var tids=decodeURIComponent(window.location.hash.substr(1)).readBracketedList();
	if (tids.length==1) // permalink (single tiddler in URL)
		story.displayTiddler(null,tids[0]);
	else { // restore permaview or default view
		config.lastURL = window.location.hash;
		if (!tids.length) tids=store.getTiddlerText("DefaultTiddlers").readBracketedList();
		story.closeAllTiddlers();
		story.displayTiddlers(null,tids);
	}
}


if (Story.prototype.SPM_coreDisplayTiddler==undefined)
	Story.prototype.SPM_coreDisplayTiddler=Story.prototype.displayTiddler;
Story.prototype.displayTiddler = function(srcElement,tiddler,template,animate,slowly)
{
	var title=(tiddler instanceof Tiddler)?tiddler.title:tiddler;
	var tiddlerElem=story.getTiddler(title); // ==null unless tiddler is already displayed
	var opt=config.options;
	var single=opt.chkSinglePageMode && !startingUp;
	var top=opt.chkTopOfPageMode && !startingUp;
	var bottom=opt.chkBottomOfPageMode && !startingUp;
	if (single) {
		story.forEachTiddler(function(tid,elem) {
			// skip current tiddler and, optionally, tiddlers that are folded.
			if (	tid==title
				|| (opt.chkSinglePageKeepFoldedTiddlers && elem.getAttribute("folded")=="true"))
				return;
			// if a tiddler is being edited, ask before closing
			if (elem.getAttribute("dirty")=="true") {
				if (opt.chkSinglePageKeepEditedTiddlers) return;
				// if tiddler to be displayed is already shown, then leave active tiddler editor as is
				// (occurs when switching between view and edit modes)
				if (tiddlerElem) return;
				// otherwise, ask for permission
				var msg="'"+tid+"' is currently being edited.\n\n";
				msg+="Press OK to save and close this tiddler\nor press Cancel to leave it opened";
				if (!confirm(msg)) return; else story.saveTiddler(tid);
			}
			story.closeTiddler(tid);
		});
	}
	else if (top)
		arguments[0]=null;
	else if (bottom)
		arguments[0]="bottom";
	if (single && opt.chkSinglePagePermalink && !config.browser.isSafari) {
		window.location.hash = encodeURIComponent(String.encodeTiddlyLink(title));
		config.lastURL = window.location.hash;
		document.title = wikifyPlain("SiteTitle") + " - " + title;
		if (!config.SPMTimer) config.SPMTimer=window.setInterval(function() {checkLastURL();},1000);
	}
	if (tiddlerElem && tiddlerElem.getAttribute("dirty")=="true") { // editing... move tiddler without re-rendering
		var isTopTiddler=(tiddlerElem.previousSibling==null);
		if (!isTopTiddler && (single || top))
			tiddlerElem.parentNode.insertBefore(tiddlerElem,tiddlerElem.parentNode.firstChild);
		else if (bottom)
			tiddlerElem.parentNode.insertBefore(tiddlerElem,null);
		else this.SPM_coreDisplayTiddler.apply(this,arguments); // let CORE render tiddler
	} else
		this.SPM_coreDisplayTiddler.apply(this,arguments); // let CORE render tiddler
	var tiddlerElem=story.getTiddler(title);
	if (tiddlerElem&&opt.chkSinglePageAutoScroll) {
		// scroll to top of page or top of tiddler
		var isTopTiddler=(tiddlerElem.previousSibling==null);
		var yPos=isTopTiddler?0:ensureVisible(tiddlerElem);
		// if animating, defer scroll until after animation completes
		var delay=opt.chkAnimate?config.animDuration+10:0;
		setTimeout("window.scrollTo(0,"+yPos+")",delay); 
	}
}

if (Story.prototype.SPM_coreDisplayTiddlers==undefined)
	Story.prototype.SPM_coreDisplayTiddlers=Story.prototype.displayTiddlers;
Story.prototype.displayTiddlers = function() {
	// suspend single/top/bottom modes when showing multiple tiddlers
	var opt=config.options;
	var saveSPM=opt.chkSinglePageMode; opt.chkSinglePageMode=false;
	var saveTPM=opt.chkTopOfPageMode; opt.chkTopOfPageMode=false;
	var saveBPM=opt.chkBottomOfPageMode; opt.chkBottomOfPageMode=false;
	this.SPM_coreDisplayTiddlers.apply(this,arguments);
	opt.chkBottomOfPageMode=saveBPM;
	opt.chkTopOfPageMode=saveTPM;
	opt.chkSinglePageMode=saveSPM;
}
//}}}
/***
|Name|SinglePageModePluginInfo|
|Source|http://www.TiddlyTools.com/#SinglePageModePlugin|
|Documentation|http://www.TiddlyTools.com/#SinglePageModePluginInfo|
|Version|2.9.6|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|documentation|
|Description|Documentation for SinglePageModePlugin|
Normally, as you click on the links in TiddlyWiki, more and more tiddlers are displayed on the page. The order of this tiddler display depends upon when and where you have clicked. Some people like this non-linear method of reading the document, while others have reported that when many tiddlers have been opened, it can get somewhat confusing.  SinglePageModePlugin allows you to configure TiddlyWiki to navigate more like a traditional multipage web site with only one item displayed at a time.
!!!!!Usage
<<<
When the plugin is enabled, only one tiddler will be displayed at a time and the browser window's titlebar is updated to include the current tiddler title.  The browser's location URL is also updated with a 'permalink' for the current tiddler so that it is easier to create a browser 'bookmark' for the current tiddler.  Alternatively, even when displaying multiple tiddlers //is// permitted, you can still reduce the potential for confusion by forcing  tiddlers to always open at the top (or bottom) of the page instead of being displayed following the tiddler containing the link that was clicked.
<<<
!!!!!Configuration
<<<
<<option chkSinglePageMode>> Display one tiddler at a time
><<option chkSinglePagePermalink>> Automatically permalink current tiddler
><<option chkSinglePageKeepFoldedTiddlers>> Don't close tiddlers that are folded
><<option chkSinglePageKeepEditedTiddlers>> Don't close tiddlers that are being edited
<<option chkTopOfPageMode>> Open tiddlers at the top of the page
<<option chkBottomOfPageMode>> Open tiddlers at the bottom of the page
<<option chkSinglePageAutoScroll>> Automatically scroll tiddler into view (if needed)

Notes:
* {{block{
The "display one tiddler at a time" option can also be //temporarily// set/reset by including a 'paramifier' in the document URL: {{{#SPM:true}}} or {{{#SPM:false}}}. You can also use {{{SPM:expression}}}, where 'expression' is any javascript statement that evaluates to true or false.  This allows you to create hard-coded links in other documents that can selectively enable/disable the use of this option based on various programmatic conditions, such as the current username. For example, using
&nbsp;&nbsp;&nbsp;{{{#SPM:config.options.txtUserName!="SomeName"}}}
enables 'one tiddler at a time' display for all users //other than// "~SomeName")}}}
* If more than one display mode is selected, 'one at a time' display takes precedence over both 'top' and 'bottom' settings, and if 'one at a time' setting is not used, 'top of page' takes precedence over 'bottom of page'.
* When using Apple's Safari browser, automatically setting the permalink causes an error and is disabled.
<<<
!!!!!Revisions
<<<
2008.10.17 2.9.6 changed chkSinglePageAutoScroll default to false
2008.06.12 2.9.5 corrected 'scroll to top of page' logic in auto-scroll handling
2008.06.11 2.9.4 added chkSinglePageKeepEditedTiddlers option
2008.06.05 2.9.3 in displayTiddler(), bypass single/top/bottom mode handling if startingUp.  Allows multiple tiddlers to be displayed during startup processing (e.g., #story:DefaultTiddlers), even if single/top/bottom mode is enabled.
2008.04.18 2.9.2 in displayTiddler() and checkLastURL(), handling for Unicode in tiddler titles (remove explicit conversion between Unicode and UTF, as this is apparently done automatically by encode/decodeURIComponent, resulting in double-encoding!
2008.04.08 2.9.1 don't automatically add options to AdvancedOptions shadow tiddler
2008.04.02 2.9.0 in displayTiddler(), when single-page mode is in use and a tiddler is being edited, ask for permission to save-and-close that tiddler, instead of just leaving it open.
2008.03.29 2.8.3 in displayTiddler(), get title from tiddler object (if needed).  Fixes errors caused when calling function passes a tiddler *object* instead of a tiddler *title*
2008.03.14 2.8.2 in displayTiddler(), if editing specified tiddler, just move it to top/bottom of story *without* re-rendering (prevents discard of partial edits).
2008.03.06 2.8.1 in paramifier handler, start 'checkURL' timer if chkSinglePageMode is enabled
2008.03.06 2.8.0 added option, {{{config.options.chkSinglePageKeepFoldedTiddlers}}}, so folded tiddlers won't be closed when using single-page mode.  Also, in checkURL(), if hash is a ''permaview'' (e.g., "#foo bar baz"), then display multiple tiddlers rather than attempting to display "foo bar baz" as a single tiddler
2008.03.05 2.7.0 added support for "SPM:" URL paramifier
2008.03.01 2.6.0 in hijack of displayTiddler(), added 'title' argument to closeAllTiddlers() so that target tiddler isn't closed-and-reopened if it was already displayed.  Also, added config.options.chkSinglePageAutoScrolloption to bypass automatic 'scroll into view' logic (note: core still does it's own ensureVisible() handling)
2007.12.22 2.5.3 in checkLastURL(), use decodeURIComponent() instead of decodeURI so that tiddler titles with commas (and/or other punctuation) are correctly handled.
2007.10.26 2.5.2 documentation cleanup
2007.10.08 2.5.1 in displayTiddler(), when using single-page or top-of-page mode, scrollTo(0,0) to ensure that page header is in view.
2007.09.13 2.5.0 for TPM/BPM modes, don't force tiddler to redisplay if already shown.  Allows transition between view/edit or collapsed/view templates, without repositioning displayed tiddler.
2007.09.12 2.4.0 added option to disable automatic permalink feature.  Also, Safari is now excluded from permalinking action to avoid bug where tiddlers don't display after hash is updated.
2007.03.03 2.3.1 fix typo when adding BPM option to AdvancedOptions (prevented checkbox from appearing)
2007.03.03 2.3.0 added support for BottomOfPageMode (BPM) based on request from DaveGarbutt
2007.02.06 2.2.3 in Story.prototype.displayTiddler(), use convertUnicodeToUTF8() for correct I18N string handling when creating URL hash string from tiddler title (based on bug report from BidiX)
2007.01.08 2.2.2 use apply() to invoke hijacked core functions
2006.07.04 2.2.1 in hijack for displayTiddlers(), suspend TPM as well as SPM so that DefaultTiddlers displays in the correct order.
2006.06.01 2.2.0 added chkTopOfPageMode (TPM) handling
2006.02.04 2.1.1 moved global variable declarations to config.* to avoid FireFox 1.5.0.1 crash bug when assigning to globals
2005.12.27 2.1.0 hijack displayTiddlers() so that SPM can be suspended during startup while displaying the DefaultTiddlers (or #hash list).  Also, corrected initialization for undefined SPM flag to "false", so default behavior is to display multiple tiddlers
2005.12.27 2.0.0 Update for TW2.0
2005.11.24 1.1.2 When the back and forward buttons are used, the page now changes to match the URL.  Based on code added by Clint Checketts
2005.10.14 1.1.1 permalink creation now calls encodeTiddlyLink() to handle tiddler titles with spaces in them
2005.10.14 1.1.0 added automatic setting of window title and location bar ('auto-permalink').  feature suggestion by David Dickens.
2005.10.09 1.0.1 combined documentation and code in a single tiddler
2005.08.15 1.0.0 Initial Release
<<<
Customizable Wookiepedia style infoboxes
Infoboxes
#mainMenu {width:15em;}
#displayArea {margin:1em 17em 0 18em;}

[[ShCore.css]]
[[ShThemeDefault.css]]
/***
|''Name''|SyntaxHighlighterPlugin3|
|''Description''|Enables syntax highlighting|
|''Author''|PMario|
|''Version''|0.2.1|
|''Status''|''beta''|
|''Source''|http://syntaxhighlighter.tiddlyspace.com/#SyntaxHighlighterPlugin3|
|''License''|[[BSD|http://www.opensource.org/licenses/bsd-license.php]]|
|''CoreVersion''|2.5.0|
|''Requires''|ShCore.js|
|''Keywords''|syntax highlighting color code|
!Documentation
*see: [[SyntaxHighlighterPlugin3Info]]
!Description
Enables syntax highlighting for <pre> and <code> blocks. Adds a new formatter for {{{<code class='brush:???'>}}} 
!Usage
!!!!StyleSheet
<<<
*add this to your StyleSheet
{{{
[[ShCore.css]]
[[ShThemeDefault.css]]
}}}
<<<
!!!!Macro
<<<
*The macro is only needed if you have inline html blocks. see: [[SyntaxHighlighterPlugin3Info]]
<<<
!!!!ViewTemplate
<<<
*Same as macro, but will be executed automatically for every tiddler. see: [[SyntaxHighlighterPlugin3Info]]
<<<
!!!!Parameters
<<<
{{{<<highlightSyntax [tagName]>> }}}
*will render all blocks, with any defined tag name. eg: tagName = code.
*[tagName] is optional. Default is "pre".
<<<
!!!!Configuration options
<<<
Guess syntax: <<option chkGuessSyntax>> .. If activated, ~TiddlyWiky <pre> blocks will be rendered according to there block braces. see [[SyntaxHighlighterPlugin3Info]]
Expert mode: <<option chkExpertSyntax>> .. If activated, additional values below will be used. see [[SyntaxHighlighterPlugin3Info]]

{{{ {{{ }}} txtShText: <<option txtShText>> eg: 'brush:text tab-size:4 + options'
{{{ /*{{{* / }}} txtShCss: <<option txtShCss>> eg: 'brush:css  + options'
{{{ //{{{ }}} txtShPlugin: <<option txtShPlugin>> 'brush:js  + options'
{{{ <!--{{{-->> }}} txtShXml: <<option txtShXml>> 'brush:xml  + options'

Additional options can be found at: [[SyntaxHighlighter homepage|http://alexgorbatchev.com/SyntaxHighlighter/manual/configuration/]]
<<<
!!!!Revision History
<<<
*V 0.2.1 2011-08-01
**fix wrong error text
*V 0.2.0 2010-08-22
**New formatter for {{{<code class='brush:???'>}}} is available now
**expert mode uses config options now
<<<
!!!!ToDo
<<<
*
<<<
!!!Code
***/

//{{{
version.extensions.SyntaxHighlighterPlugin3 = {major: 0, minor: 2, revision: 1, date: new Date(2011,8,1)};

(function($) {

if(!window.SyntaxHighlighter) {
	throw "Missing dependency: ShCore.js (check brushes too)";
}

config.macros.highlightSyntax = {
	getElementsByClass: function (searchClass,node,tag) {
		var classElements = [];
        if ( node == null ) node = document;
        if ( tag == null )  tag = '*';
		
		var els = node.getElementsByTagName(tag);
		var elsLen = els.length;
		var pattern = new RegExp("(^|\\s)"+searchClass+"(:|\\s|$)");
		for (i = 0, j = 0; i < elsLen; i++) {
			if ( pattern.test(els[i].className) ) {
				classElements[j] = els[i];
				j++;
			}
		}
		return classElements;
	},
	
	handler: function(place, macroName, params, wikifier, paramString, tiddler) {
		// the configured tagName can be temporarily overwritten by the macro.
		var tagName = params[0] || SyntaxHighlighter.config.tagName;
		var arr = this.getElementsByClass('brush', story.findContainingTiddler(place), tagName);
		for (i=0; i<arr.length; i++) {
			SyntaxHighlighter.highlight(null, arr[i]);
		}			
	} // handler
};

})(jQuery);
//}}}
/***
!!!!!New formatter for {{{<code class='brush:??'>}}}
***/
//{{{
config.formatters.push({
	name: "highlightSyntax",
	match: "^<code[\\s]+[^>]+>\\n",
	element: "pre",
	handler: function(w)
	{
        this.lookaheadRegExp = /<code[\s]+class.*=.*["'](.*)["'].*>\n((?:^[^\n]*\n)+?)(^<\/code>$\n?)/img;
		this.lookaheadRegExp.lastIndex = w.matchStart;
		var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
		if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
            var options = lookaheadMatch[1];
			var text = lookaheadMatch[2];
			if(config.browser.isIE)
				text = text.replace(/\n/g,"\r");
			var element = createTiddlyElement(w.output,this.element,null,options,text);
            SyntaxHighlighter.highlight(null, element);
			w.nextMatch = lookaheadMatch.index + lookaheadMatch[0].length;
		}
	}
});
//}}}
/***
!!!!!Add class attribute to pre, if defined
***/
//{{{
(function(formatters) { //# set up alias
	var helper = {};	
	helper.enclosedTextHelper = function(w){
		var attr;
		var co = config.options;
		var expert = (co.chkExpertSyntax != undefined)? co.chkExpertSyntax : false;
		var guess  = (co.chkGuessSyntax != undefined)? co.chkGuessSyntax : true;
		
		this.lookaheadRegExp.lastIndex = w.matchStart;
		var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
		if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
			var text = lookaheadMatch[1];
			if(config.browser.isIE)
				text = text.replace(/\n/g,"\r");

			switch(w.matchText) {
			case "{{{\n": // text
				attr = (expert) ? (co.txtShText) ? (co.txtShText) : 'brush:text' : 'brush:text' ;
				break;
			case "/*{{{*/\n": // CSS
				attr = (expert) ? (co.txtShCss) ? (co.txtShCss) : 'brush:css' : 'brush:css';
				break;
			case "//{{{\n": // plugin
				attr = (expert) ? (co.txtShPlugin) ? (co.txtShPlugin) : 'brush:js' : 'brush:js';
				break;
			case "<!--{{{-->\n": //template
				attr =  (expert) ? (co.txtShXml) ? (co.txtShXml) : 'brush:xml' : 'brush:xml';
				break;
			}
			var element = createTiddlyElement(w.output,this.element,null,attr,text);		
	        if (guess || expert) SyntaxHighlighter.highlight(null, element);

			w.nextMatch = lookaheadMatch.index + lookaheadMatch[0].length;
		}
	};
	// merge the new helper function into formatterHelpers. 
	merge(config.formatterHelpers, helper);

})(config.formatters); //# end of alias
//}}}
|''Name''|SyntaxHighlighterPlugin3Info|
|''Description''|Documentation for [[SyntaxHighlighterPlugin3]]|
|''Author''|PMario|
|''Version''|0.2.0|
|''Source''|http://syntaxhighlighter.tiddlyspace.com/#SyntaxHighlighterPlugin3|
|''Documentation''|http://syntaxhighlighter.tiddlyspace.com/#SyntaxHighlighterPlugin3Info|
|''License''|[[BSD|http://www.opensource.org/licenses/bsd-license.php]], libraries used: see the according files: [[ShCore.js]] |
|''Keywords''|syntax highlighting color code|
!Usage
!!!!StyleSheet
<<<
*add this to your StyleSheet
{{{
[[ShCore.css]]
[[ShThemeDefault.css]]
}}}
<<<
!! Feedback / Support
Feedback is very welcome at [[TiddlyWiki group|http://groups.google.com/group/tiddlywiki]]
!!Examples
!!!!Code sample
<<<
<!--{{{-->
<code class="brush:js highlight:[1,3]">
// comment
var a = b = 0;
a = 17;
</code>
<!--}}}-->
will render like 
<code class="brush:js highlight:[1,3]">
// comment
var a = b = 0;
a = 17;
</code>
<<<
!!!!Text
<<<
{{{
 {{{
 this will be rendered as text!
 }}}
}}}
<<<
!!!!CSS
<<<
{{{
 /*{{{*/
 .cssClass {
	display: block; !important;
 }
 /*}}}*/
}}}
will render like:
/*{{{*/
	.cssClass {
		display: block; !important;
	}
/*}}}*/
<<<
!!!!XML
<<<
{{{
<!--{{{-->
<html>
	<div id='myId' class='dp50'>some text </div>
</html>
<!--}}}-->
}}}
will render like:
<!--{{{-->
<html>
	<div id='myId' class='dp50'>some text </div>
</html>
<!--}}}-->
<<<
!!!!Plugin
<<<
{{{
//{{{
(function($) {
	config.macros.highlightSyntax = {
		var a = b = 0;
		// your code here!
	}
})(jQuery);
//}}}
}}}
will render like:
//{{{
(function($) {
	config.macros.highlightSyntax = {
		var a = b = 0;
		// your code here!
	}
})(jQuery);
//}}}
<<<
!!Advanced Options
<<<
Guess syntax: <<option chkGuessSyntax>> .. If activated, ~TiddlyWiky <pre> blocks will be rendered according to there block braces, like described obove.
Expert mode: <<option chkExpertSyntax>> .. If activated, additional values below will be used

{{{ {{{ }}} txtShText: <<option txtShText>> eg: 'brush:text tab-size:4 + options'
{{{ /*{{{*/ }}} txtShCss: <<option txtShCss>> eg: 'brush:css  + options'
{{{ //{{{ }}} txtShPlugin: <<option txtShPlugin>> 'brush:js  + options'
{{{ <!--{{{-->> }}} txtShXml: <<option txtShXml>> 'brush:xml  + options'

If you want to change the default values eg for C++, add the following to a [[zzConfig]] tiddler and tag it "systemConfig"
//{{{
config.options.chkGuessSyntax = true;
config.options.chkExpertSyntax = true;

config.options.txtShPlugin = 'brush:cpp tab-size:4';
//}}}
and use the following backets to cover your code
{{{
//{{{
   cpp code comes here.
//}}}
}}}

All possible SyntaxHighlighter options can be found at: [[SyntaxHighlighter homepage|http://alexgorbatchev.com/SyntaxHighlighter/manual/configuration/]]
<<<
!! You need a different brush?
* Go to [[syntaxhighlighter brushes page| http://alexgorbatchev.com/SyntaxHighlighter/manual/brushes/]] 
* Select your brush
* Copy paste it into a tiddler eg: ShBrushCpp.js
** Tag the new tiddler ''systemConfig''
** Save and reload
* Have a look at Advanced options or use the {{{<code class="brush: ... >}}} tag described above.

!!Needed: list tagged syntax
<<list filter [tag[syntax]]>>

!!!Macro
<<<
*The macro is only needed if you have inline html blocks, like shown below.
<!--{{{-->
<html>
	<pre class='brush:pascal tab-size:3'>
		// your code 
	<pre>
</html>

<<highlightSyntax>> .. will render the <pre> blocks shown above.
<!--}}}-->
<<<
!!!!ViewTemplate
<<<
*Same as macro, but will be executed automatically for every tiddler.
<!--{{{-->
<div class='tagging' macro='tagging'></div>
<div macro='highlightSyntax'></div>  <!-- insert this line -->
<div class='tagClear'></div>
<!--}}}-->
<<<
!!!!Parameters
<<<
{{{<<highlightSyntax [tagName]>>}}}
*will render all blocks, with any defined tag name. eg: tagName = code.
*[tagName] is optional. Default is "pre".
<<<
!!!Revision History
*V 0.2.0 2010-08-22
**New formatter for {{{<code class='brush:???'>}}} is available now
**expert mode uses config options now
*V 0.1.0 2010-08-17
**initial release
txtUserName: "Kristjan"
chkAutoSave: false
chkInfoboxInfoEditToolbar: true
chkInfoboxInfoViewToolbar: true
chkSaveBackups: false
chkSinglePageMode: true
chkSinglePagePermalink: false
/***
|Name|TiddlerTweakerPlugin|
|Source|http://www.TiddlyTools.com/#TiddlerTweakerPlugin|
|Version|2.4.5|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|select multiple tiddlers and modify author, created, modified and/or tag values|
~TiddlerTweaker is a 'power tool' for TiddlyWiki authors.  Select multiple tiddlers from a listbox and 'bulk modify' the creator, author, created, modified and/or tag values of those tiddlers using a compact set of form fields.  The values you enter into the fields simultaneously overwrite the existing values in all tiddlers you have selected.
!!!!!Usage
<<<
{{{<<tiddlerTweaker>>}}}
{{smallform{<<tiddlerTweaker>>}}}
By default, any tags you enter into the TiddlerTweaker will //replace// the existing tags in all the tiddlers you have selected.  However, you can also use TiddlerTweaker to quickly filter specified tags from the selected tiddlers, while leaving any other tags assigned to those tiddlers unchanged:
>Any tag preceded by a '+' (plus) or '-' (minus), will be added or removed from the existing tags //instead of replacing the entire tag definition// of each tiddler (e.g., enter '-excludeLists' to remove that tag from all selected tiddlers.  When using this syntax, care should be taken to ensure that //every// tag is preceded by '+' or '-', to avoid inadvertently overwriting any other existing tags on the selected tiddlers.  (note: the '+' or '-' prefix on each tag value is NOT part of the tag value, and is only used by TiddlerTweaker to control how that tag value is processed)
Important Notes:
* TiddlerTweaker is a 'power user' tool that can make changes to many tiddlers at once.  ''You should always have a recent backup of your document (or 'save changes' just *before* tweaking the tiddlers), just in case you accidentally 'shoot yourself in the foot'.''
* The date and author information on any tiddlers you tweak will ONLY be updated if the corresponding checkboxes have been selected.  As a general rule, after using TiddlerTweaker, always ''//remember to save your document//'' when you are done, even though the tiddler timeline tab may not show any recently modified tiddlers.
* Selecting and updating all tiddlers in a document can take a while.  Your browser may warn about an 'unresponsive script'.  Usually, if you allow it to continue, it should complete the processing... eventually.  Nonetheless, be sure to save your work before you begin tweaking lots of tiddlers, just in case something does get stuck.
<<<
!!!!!Revisions
<<<
2011.01.21 2.4.5 auto-selection: use "-" for untagged tiddlers.  Also, added 'opened', 'invert'
2009.09.15 2.4.4 added 'edit' button. moved html definition to separate section
2009.09.13 2.4.3 in settiddlers(), convert backslashed chars (\n\b\s\t) in replacement text
2009.06.26 2.4.2 only add brackets around tags containing spaces
2009.06.22 2.4.1 in setFields(), add brackets around all tags shown tweaker edit field
2009.03.30 2.4.0 added 'sort by modifier'
2009.01.22 2.3.0 added support for text pattern find/replace
2008.10.27 2.2.3 in setTiddlers(), fixed Safari bug by replacing static Array.concat(...) with new Array().concat(...)
2008.09.07 2.2.2 added removeCookie() function for compatibility with [[CookieManagerPlugin]]
2008.05.12 2.2.1 replace built-in backstage tweak task with tiddler tweaker control panel (moved from BackstageTweaks)
2008.01.13 2.2.0 added 'auto-selection' links: all, changed, tags, title, text
2007.12.26 2.1.0 added support for managing 'creator' custom field (see [[CoreTweaks]])
2007.11.01 2.0.3 added config.options.txtTweakerSortBy for cookie-based persistence of list display order preference setting.
2007.09.28 2.0.2 in settiddlers() and deltiddlers(), added suspend/resume notification handling (improves performance when operating on multiple tiddlers)
2007.08.03 2.0.1 added shadow definition for [[TiddlerTweaker]] tiddler for use as parameter references with {{{<<tiddler>>, <<slider>> or <<tabs>>}}} macros.
2007.08.03 2.0.0 converted from inline script
2006.01.01 1.0.0 initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.TiddlerTweakerPlugin= {major: 2, minor: 4, revision: 5, date: new Date(2011,1,21)};

// shadow tiddler
config.shadowTiddlers.TiddlerTweaker='<<tiddlerTweaker>>';

// defaults
if (config.options.txtTweakerSortBy==undefined) config.options.txtTweakerSortBy='modified';

// backstage task
if (config.tasks) { // for TW2.2b3 or above
	config.tasks.tweak.tooltip='review/modify tiddler internals: dates, authors, tags, etc.';
	config.tasks.tweak.content='{{smallform small groupbox{<<tiddlerTweaker>>}}}';
}

// if removeCookie() function is not defined by TW core, define it here.
if (window.removeCookie===undefined) {
	window.removeCookie=function(name) {
		document.cookie = name+'=; expires=Thu, 01-Jan-1970 00:00:01 UTC; path=/;'; 
	}
}

config.macros.tiddlerTweaker = {
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		var span=createTiddlyElement(place,'span');
		span.innerHTML=store.getTiddlerText('TiddlerTweakerPlugin##html');
		this.init(span.getElementsByTagName('form')[0],config.options.txtTweakerSortBy);
	},
	init: function(f,sortby) { // set form controls
		if (!f) return; // form might not be rendered yet...
		while (f.list.options[0]) f.list.options[0]=null; // empty the list
		var tids=store.getTiddlers(sortby);
		if (sortby=='size') // descending order
			tids.sort(function(a,b) {return a.text.length > b.text.length ? -1 : (a.text.length == b.text.length ? 0 : +1);});
		var who='';
		for (i=0; i<tids.length; i++) { var t=tids[i];
			var label=t.title; var value=t.title;
			switch (sortby) {
				case 'modified':
				case 'created':
					var t=tids[tids.length-i-1]; // reverse order
					var when=t[sortby].formatString('YY.0MM.0DD 0hh:0mm ');
					label=when+t.title;
					value=t.title;
					break;
				case 'size':
					label='['+t.text.length+'] '+label;
					break;
				case 'modifier':
				case 'creator':
					if (who!=t[sortby]) {
						who=t[sortby];
						f.list.options[f.list.length]=new Option('by '+who+':','',false,false);
					}
					label='\xa0\xa0\xa0'+label; // indent
					break;
			}
			f.list.options[f.list.length]=new Option(label,value,false,false);
		}
		f.title.value=f.who.value=f.creator.value=f.tags.value='';
		f.cm.value=f.cd.value=f.cy.value=f.ch.value=f.cn.value='';
		f.mm.value=f.md.value=f.my.value=f.mh.value=f.mn.value='';
		f.stats.disabled=f.set.disabled=f.del.disabled=f.edit.disabled=f.display.disabled=true;
		f.settitle.disabled=false;
		config.options.txtTweakerSortBy=sortby;
		f.sortby.value=sortby; // sync droplist
		if (sortby!='modified') saveOptionCookie('txtTweakerSortBy');
		else removeCookie('txtTweakerSortBy');
	},
	enablefields: function(here) { // enables/disables inputs based on #items selected
		var f=here.form; var list=f.list;
		var c=0; for (i=0;i<list.length;i++) if (list.options[i].selected) c++;
		if (c>1) f.title.disabled=true;
		if (c>1) f.settitle.checked=false;
		f.set.disabled=(c==0);
		f.del.disabled=(c==0);
		f.edit.disabled=(c==0);
		f.display.disabled=(c==0);
		f.settitle.disabled=(c>1);
		f.stats.disabled=(c==0);
		var msg=(c==0)?'select tiddlers':(c+' tiddler'+(c!=1?'s':'')+' selected');
		here.previousSibling.firstChild.firstChild.nextSibling.innerHTML=msg;
		if (c) clearMessage(); else displayMessage('no tiddlers selected');
	},
	setfields: function(here) { // set fields from first selected tiddler
		var f=here.form;
		if (!here.value.length) {
			f.title.value=f.who.value=f.creator.value=f.tags.value='';
			f.cm.value=f.cd.value=f.cy.value=f.ch.value=f.cn.value='';
			f.mm.value=f.md.value=f.my.value=f.mh.value=f.mn.value='';
			return;
		}
		var tid=store.getTiddler(here.value); if (!tid) return;
		f.title.value=tid.title;
		f.who.value=tid.modifier;
		f.creator.value=tid.fields['creator']||''; // custom field - might not exist
		f.tags.value=tid.tags.map(function(t){return String.encodeTiddlyLink(t)}).join(' ');
		var c=tid.created; var m=tid.modified;
		f.cm.value=c.getMonth()+1;
		f.cd.value=c.getDate();
		f.cy.value=c.getFullYear();
		f.ch.value=c.getHours();
		f.cn.value=c.getMinutes();
		f.mm.value=m.getMonth()+1;
		f.md.value=m.getDate();
		f.my.value=m.getFullYear();
		f.mh.value=m.getHours();
		f.mn.value=m.getMinutes();
	},
	selecttiddlers: function(here,callback) {
		var f=here; while (f&&f.nodeName.toLowerCase()!='form')f=f.parentNode;
		for (var t=f.list.options.length-1; t>=0; t--)
			f.list.options[t].selected=callback(f.list.options[t]);
		config.macros.tiddlerTweaker.enablefields(f.list);
		return false;
	},
	settiddlers: function(here) {
		var f=here.form; var list=f.list;
		var tids=[];
		for (i=0;i<list.length;i++) if (list.options[i].selected) tids.push(list.options[i].value);
		if (!tids.length) { alert('please select at least one tiddler'); return; }
		var cdate=new Date(f.cy.value,f.cm.value-1,f.cd.value,f.ch.value,f.cn.value);
		var mdate=new Date(f.my.value,f.mm.value-1,f.md.value,f.mh.value,f.mn.value);
		if (tids.length>1 && !confirm('Are you sure you want to update these tiddlers:\n\n'+tids.join(', '))) return;
		store.suspendNotifications();
		for (t=0;t<tids.length;t++) {
			var tid=store.getTiddler(tids[t]); if (!tid) continue;
			var title=!f.settitle.checked?tid.title:f.title.value;
			var who=!f.setwho.checked?tid.modifier:f.who.value;
			var text=tid.text;
			if (f.replacetext.checked) {
				var r=f.replacement.value.replace(/\\t/mg,'\t').unescapeLineBreaks();
				text=text.replace(new RegExp(f.pattern.value,'mg'),r);
			}				
			var tags=tid.tags;
			if (f.settags.checked) { 
				var intags=f.tags.value.readBracketedList();
				var addtags=[]; var deltags=[]; var reptags=[];
				for (i=0;i<intags.length;i++) {
					if (intags[i].substr(0,1)=='+')
						addtags.push(intags[i].substr(1));
					else if (intags[i].substr(0,1)=='-')
						deltags.push(intags[i].substr(1));
					else
						reptags.push(intags[i]);
				}
				if (reptags.length)
					tags=reptags;
				if (addtags.length)
					tags=new Array().concat(tags,addtags);
				if (deltags.length)
					for (i=0;i<deltags.length;i++)
						{ var pos=tags.indexOf(deltags[i]); if (pos!=-1) tags.splice(pos,1); }
			}
			if (!f.setcdate.checked) cdate=tid.created;
			if (!f.setmdate.checked) mdate=tid.modified;
			store.saveTiddler(tid.title,title,text,who,mdate,tags,tid.fields);
			if (f.setcreator.checked) store.setValue(tid.title,'creator',f.creator.value); // set creator
			if (f.setcdate.checked) tid.assign(null,null,null,null,null,cdate); // set create date
		}
		store.resumeNotifications();
		this.init(f,f.sortby.value);
	},
	displaytiddlers: function(here,edit) {
		var f=here.form; var list=f.list;
		var tids=[];
		for (i=0; i<list.length;i++) if (list.options[i].selected) tids.push(list.options[i].value);
		if (!tids.length) { alert('please select at least one tiddler'); return; }
		story.displayTiddlers(story.findContainingTiddler(f),tids,edit?DEFAULT_EDIT_TEMPLATE:null);
	},
	deltiddlers: function(here) {
		var f=here.form; var list=f.list;
		var tids=[];
		for (i=0;i<list.length;i++) if (list.options[i].selected) tids.push(list.options[i].value);
		if (!tids.length) { alert('please select at least one tiddler'); return; }
		if (!confirm('Are you sure you want to delete these tiddlers:\n\n'+tids.join(', '))) return;
		store.suspendNotifications();
		for (t=0;t<tids.length;t++) {
			var tid=store.getTiddler(tids[t]); if (!tid) continue;
			if (tid.tags.contains('systemConfig')) {
				var msg=tid.title+' is tagged with systemConfig.'
					+'\n\nRemoving this tiddler may cause unexpected results.  Are you sure?';
				if (!confirm(msg)) continue;
			}
			store.removeTiddler(tid.title);
			story.closeTiddler(tid.title);
		}
		store.resumeNotifications();
		this.init(f,f.sortby.value);
	},
	stats: function(here) {
		var f=here.form; var list=f.list; var tids=[]; var out=''; var tot=0;
		var target=f.nextSibling;
		for (i=0;i<list.length;i++) if (list.options[i].selected) tids.push(list.options[i].value);
		if (!tids.length) { alert('please select at least one tiddler'); return; }
		for (t=0;t<tids.length;t++) {
			var tid=store.getTiddler(tids[t]); if (!tid) continue;
			out+='[['+tid.title+']] '+tid.text.length+'\n'; tot+=tid.text.length;
		}
		var avg=tot/tids.length;
		out=tot+' bytes in '+tids.length+' selected tiddlers ('+avg+' bytes/tiddler)\n<<<\n'+out+'<<<\n';
		removeChildren(target);
		target.innerHTML="<hr><font size=-2><a href='javascript:;' style='float:right' "
			+"onclick='this.parentNode.parentNode.style.display=\"none\"'>close</a></font>";
		wikify(out,target);
		target.style.display='block';
	}
};
//}}}
/***
//{{{
!html
<style>
.tiddlerTweaker table,
.tiddlerTweaker table tr,
.tiddlerTweaker table td
	{ padding:0;margin:0;border:0;white-space:nowrap; }
</style><form class='tiddlerTweaker'><!--
--><table style="width:100%"><tr valign="top"><!--
--><td style="text-align:center;width:99%;"><!--
	--><font size=-2><div style="text-align:left;"><span style="float:right"><!--
	-->&nbsp; <a href="javascript:;" 
		title="select all tiddlers"
		onclick="return config.macros.tiddlerTweaker.selecttiddlers(this,function(opt){
			return opt.value.length;
		});">all</a><!--
	-->&nbsp; <a href="javascript:;" 
		title="select tiddlers currently displayed in the story column"
		onclick="return config.macros.tiddlerTweaker.selecttiddlers(this,function(opt){
			return story.getTiddler(opt.value);
		});">opened</a><!--
	-->&nbsp; <a href="javascript:;" 
		title="select tiddlers that are new/changed since the last file save"
		onclick="var lastmod=new Date(document.lastModified);
			return config.macros.tiddlerTweaker.selecttiddlers(this,function(opt){
				var tid=store.getTiddler(opt.value);
				return tid&&tid.modified>lastmod;
			});
		">changed</a><!--
	-->&nbsp; <a href="javascript:;" 
		title="select tiddlers with at least one matching tag"
		onclick="var t=prompt('Enter space-separated tags (match one or more).  Use \x22-\x22 to match untagged tiddlers');
			if (!t||!t.length) return false;
			var tags=t.readBracketedList();
			return config.macros.tiddlerTweaker.selecttiddlers(this,function(opt){
				var tid=store.getTiddler(opt.value);
				return tid&&tags[0]=='-'?!tid.tags.length:tid.tags.containsAny(tags);
			});
		">tags</a><!--
	-->&nbsp; <a href="javascript:;" 
		title="select tiddlers whose titles include matching text"
		onclick="var t=prompt('Enter a title (or portion of a title) to match');
			if (!t||!t.length) return false;
			return config.macros.tiddlerTweaker.selecttiddlers(this,function(opt){
				return opt.value.indexOf(t)!=-1;
			});
		">titles</a><!--
	-->&nbsp; <a href="javascript:;" 
		title="select tiddlers containing matching text"
		onclick="var t=prompt('Enter tiddler text (content) to match');
			if (!t||!t.length) return false;
			return config.macros.tiddlerTweaker.selecttiddlers(this,function(opt){
				var tt=store.getTiddlerText(opt.value,'');
				return tt.indexOf(t)!=-1;
			});
		">text</a><!--
	-->&nbsp; <a href="javascript:;" 
		title="reverse selection of all list items"
		onclick="return config.macros.tiddlerTweaker.selecttiddlers(this,function(opt){
			return !opt.selected;
		});">invert</a><!--
	--></span><span>select tiddlers</span><!--
	--></div><!--
	--></font><select multiple name=list size="11" style="width:99.99%" 
		title="use click, shift-click and/or ctrl-click to select multiple tiddler titles" 
		onclick="config.macros.tiddlerTweaker.enablefields(this)" 
		onchange="config.macros.tiddlerTweaker.setfields(this)"><!--
	--></select><br><!--
	-->show<input type=text size=1 value="11" 
		onchange="this.form.list.size=this.value; this.form.list.multiple=(this.value>1);"><!--
	-->by<!--
	--><select name=sortby size=1 
		onchange="config.macros.tiddlerTweaker.init(this.form,this.value)"><!--
	--><option value="title">title</option><!--
	--><option value="size">size</option><!--
	--><option value="modified">modified</option><!--
	--><option value="created">created</option><!--
	--><option value="modifier">modifier</option><!--
	--></select><!--
	--><input type="button" value="refresh" 
		onclick="config.macros.tiddlerTweaker.init(this.form,this.form.sortby.value)"<!--
	--> <input type="button" name="stats" disabled value="totals..." 
		onclick="config.macros.tiddlerTweaker.stats(this)"><!--
--></td><td style="width:1%"><!--
	--><div style="text-align:left"><font size=-2>&nbsp;modify values</font></div><!--
	--><table style="width:100%;"><tr><!--
	--><td style="padding:1px"><!--
		--><input type=checkbox name=settitle unchecked 
			title="allow changes to tiddler title (rename tiddler)" 
			onclick="this.form.title.disabled=!this.checked">title<!--
	--></td><td style="padding:1px"><!--
		--><input type=text name=title size=35 style="width:98%" disabled><!--
	--></td></tr><tr><td style="padding:1px"><!--
		--><input type=checkbox name=setcreator unchecked 
			title="allow changes to tiddler creator" 
			onclick="this.form.creator.disabled=!this.checked">created by<!--
	--></td><td style="padding:1px;"><!--
		--><input type=text name=creator size=35 style="width:98%" disabled><!--
	--></td></tr><tr><td style="padding:1px"><!--
		--><input type=checkbox name=setwho unchecked 
			title="allow changes to tiddler author" 
			onclick="this.form.who.disabled=!this.checked">modified by<!--
	--></td><td style="padding:1px"><!--
		--><input type=text name=who size=35 style="width:98%" disabled><!--
	--></td></tr><tr><td style="padding:1px"><!--
		--><input type=checkbox name=setcdate unchecked 
			title="allow changes to created date" 
			onclick="var f=this.form;
				f.cm.disabled=f.cd.disabled=f.cy.disabled=f.ch.disabled=f.cn.disabled=!this.checked"><!--
		-->created on<!--
	--></td><td style="padding:1px"><!--
		--><input type=text name=cm size=2 style="width:2em;padding:0;text-align:center" disabled><!--
		--> / <input type=text name=cd size=2 style="width:2em;padding:0;text-align:center" disabled><!--
		--> / <input type=text name=cy size=4 style="width:3em;padding:0;text-align:center" disabled><!--
		--> at <input type=text name=ch size=2 style="width:2em;padding:0;text-align:center" disabled><!--
		--> : <input type=text name=cn size=2 style="width:2em;padding:0;text-align:center" disabled><!--
	--></td></tr><tr><td style="padding:1px"><!--
		--><input type=checkbox name=setmdate unchecked 
			title="allow changes to modified date" 
			onclick="var f=this.form;
				f.mm.disabled=f.md.disabled=f.my.disabled=f.mh.disabled=f.mn.disabled=!this.checked"><!--
		-->modified on<!--
	--></td><td style="padding:1px"><!--
		--><input type=text name=mm size=2 style="width:2em;padding:0;text-align:center" disabled><!--
		--> / <input type=text name=md size=2 style="width:2em;padding:0;text-align:center" disabled><!--
		--> / <input type=text name=my size=4 style="width:3em;padding:0;text-align:center" disabled><!--
		--> at <input type=text name=mh size=2 style="width:2em;padding:0;text-align:center" disabled><!--
		--> : <input type=text name=mn size=2 style="width:2em;padding:0;text-align:center" disabled><!--
	--></td></tr><tr><td style="padding:1px"><!--
		--><input type=checkbox name=replacetext unchecked
			title="find/replace matching text" 
			onclick="this.form.pattern.disabled=this.form.replacement.disabled=!this.checked">replace text<!--
	--></td><td style="padding:1px"><!--
		--><input type=text name=pattern size=15 value="" style="width:40%" disabled 
			title="enter TEXT PATTERN (regular expression)"> with<!--
		--><input type=text name=replacement size=15 value="" style="width:40%" disabled 
			title="enter REPLACEMENT TEXT"><!--
	--></td></tr><tr><td style="padding:1px"><!--
		--><input type=checkbox name=settags checked 
			title="allow changes to tiddler tags" 
			onclick="this.form.tags.disabled=!this.checked">tags<!--
	--></td><td style="padding:1px"><!--
		--><input type=text name=tags size=35 value="" style="width:98%" 
			title="enter new tags or use '+tag' and '-tag' to add/remove tags from existing tags"><!--
	--></td></tr></table><!--
	--><div style="text-align:center"><!--
	--><nobr><input type=button name=display disabled style="width:24%" value="display" 
		title="show selected tiddlers"
		onclick="config.macros.tiddlerTweaker.displaytiddlers(this,false)"><!--
	--> <input type=button name=edit disabled style="width:23%" value="edit" 
		title="edit selected tiddlers"
		onclick="config.macros.tiddlerTweaker.displaytiddlers(this,true)"><!--
	--> <input type=button name=del disabled style="width:24%" value="delete" 
		title="remove selected tiddlers"
		onclick="config.macros.tiddlerTweaker.deltiddlers(this)"><!--
	--> <input type=button name=set disabled style="width:24%" value="update" 
		title="update selected tiddlers"
		onclick="config.macros.tiddlerTweaker.settiddlers(this)"></nobr><!--
	--></div><!--
--></td></tr></table><!--
--></form><span style="display:none"><!--content replaced by tiddler "stats"--></span>
!end
//}}}
***/
 
/***
|Name|[[TiddlyFileImportr|TiddlyFileImportr]]|
|Version|0.2.7|
|Status|experimental|
|Source|https://github.com/jdlrobson/TiddlyWikiPlugins/tree/master/apps/fileimport|
|Latest|http://repository.tiddlyspace.com/TiddlyFileImportr|
***/
//{{{
var ImportWizard, WizardMaker;

(function($) {
window.WizardMaker = function(place, wizard) {
	var steps = wizard[0];
	var options = wizard[1] || {};
	$("<h1 />").text(options.heading || "Wizard").appendTo(place);
	var wizard = this;
	$('<button class="button">restart wizard</button>').click(function(ev) {
		wizard.jumpTo(0);
		}).appendTo(place)[0];
	this.currentStep = 0;
	this.body = $('<div class="wizardBody"/>').appendTo(place)[0];
	this.steps = steps;
	this.values = {};
	this.createStep(0);
};

WizardMaker.prototype = {
	/*
	OPTIONS
	step: [function, options]
	*/
	createStep: function(stepNumber) {
		$(this.body).empty();
		var step = this.steps[stepNumber];
		if(!step) {
			throw "invalid step (" + stepNumber + ")"
		}
		var options = step[1] || {};
		var humanStep = stepNumber + 1;
		var heading = "Step " + humanStep;
		if(options.heading) {
			heading += ": " + options.heading;
		}
		$("<h2 />").text(heading).appendTo(this.body);
		var container = $('<div class="wizardStep" />').appendTo(this.body)[0];
		step[0](container, this);
	},
	next: function() {
		if(this.currentStep < this.steps.length - 1) {
			this.currentStep += 1;
		}
		this.createStep(this.currentStep);
	},
	jumpTo: function(step) {
		this.currentStep = step;
		this.createStep(step);
	},
	setValue: function(name, val) {
		this.values[name] = val;
	},
	getValue: function(name) {
		return this.values[name];
	}
};

if(window.FileReader) {
	window.ImportWizard = function(options) {
		var proxy = options.proxy, saveFunction = options.save,
			internalizeTiddler = options.internalizeTiddler, proxyType = options.proxyType || "GET";
		return [
			[
				[function(body, wizard) {
					$(body).html('Where do you want to import from? <select><option value="1">file</option><option value="2">the web</option></select><button class="button">ok</button>');
					$("button", body).click(function(ev) {
						var opt = $("select", body).val();
						if(opt === "1") {
							wizard.next();
						} else {
							wizard.jumpTo(2);
						}
					});
				},
				{ heading: "File or Web?" }],
				[function(body, wizard) {
					$(body).html('Browse for a file: <input type="file" size="50" name="txtBrowse"><br><hr><div class="wizardFooter"><div class="message"></div></div>');
					function handleFileSelect(evt) {
						reader = new FileReader();
						reader.onerror = function(e, msg) {
							alert("Error occurred")
						};
						reader.onabort = function(e) {
							alert('File read cancelled');
						};
						reader.onload = function(e) {
							var html = reader.result;
							wizard.setValue("html", html);
							wizard.jumpTo(3)
						}
						// Read in the image file as a binary string.
						window.reader = reader;
						reader.readAsText(evt.target.files[0]);
					}
					$("[type=file]", body)[0].addEventListener('change', handleFileSelect, false);
				}, { heading: "Locate TiddlyWiki file" }],
				[function(body, wizard) {
					$(body).html('Enter the URL or pathname here: <div class="message"></div><input type="text" size="50" name="txtPath"><button class="button">open</button>');

					$("button", body).click(function(ev) {
						var url = proxy.replace("%0", $("input", body).val())
						ajaxReq({
							type: options.proxyType,
							url: url,
							success: function(html) {
								wizard.setValue("html", html);
								wizard.jumpTo(3);
							},
							error: function() {
								$(".message").html("There is something wrong with that url please try another.");
								$("input", body).addClass("error");
							}
						})
					})
				},
				{ heading: "Import from Web" }],
				[function(body, wizard) {
					var html = wizard.getValue("html");
					var doc = $(html);
					var store;
					$(html).each(function(i, el) {
						if(el.id === "storeArea") {
							store = el;
						}
					});
					if(store) {
						var tiddlers = [];
						$(store).children().each(function(i, el) {
							var title = $(el).attr("title");
							tiddlers.push(internalizeTiddler(el));
						});
						$("<div />").text("Choose tiddlers that you wish to import");
						var table = $("<table />").appendTo(body)[0];
						$("<tr />").html('<th><input type="checkbox" checked/></th><th>title</th>').
							appendTo(table)
						$("input", table).change(function(ev) {
							var checked = $(ev.target).is(':checked');
							$("input[type=checkbox]", body).attr("checked", checked);
						});
						for(var i = 0; i < tiddlers.length; i++) {
							var title = tiddlers[i].title;
							var row = $("<tr />").data("tiddler", tiddlers[i]).appendTo(table)[0];
							$("<td />").html('<input type="checkbox" checked="checked"/>').appendTo(row);
							$("<td />").text(title).appendTo(row);
						}
						$('<button class="button">import all selected tiddlers</button>').click(function(ev) {
							var tids = [];
							$("input[type=checkbox]:checked").each(function(i, chk) {
								var tiddler = $(chk).parents("tr").data("tiddler");
								if(tiddler) {
									tids.push(tiddler);
								}
							});
							wizard.setValue("selected", tids);
							wizard.jumpTo(4)
						}).prependTo(body);
					}
				},
				{ heading: "Choose tiddlers" }],
				[function(body, wizard) {
					var tids = wizard.getValue("selected");
					$(body).text("Please wait");
					// do import
					var save = 0;
					var complete = function() {
						save += 1;
						if(save === tids.length) {
							wizard.jumpTo(5);
						}
					};
					$(body).text("Please wait (Importing " + tids.length + " tiddlers)");
					for(var i = 0; i < tids.length; i++) {
						var tid = tids[i];
						$(body).text("Please wait (Importing " + tid.title + ")");
						saveFunction(tid, complete);
					}
				},
				{ heading: "Importing" }],
				[function(body, wizard) {
					$(body).html("Good news! Everything is now imported.");
				},
				{ heading: "Finished!" }]
			],
			{
				heading: "Import tiddlers from another file or server"
			}
		];
	}
} else {
  $("#container").addClass("error").text("Your browser is not modern enough to support this app.");
}

})(jQuery);
(function($) {

if(window.ImportWizard) {
	var proxy = "%0", proxyType = "GET";
	if(config.extensions.tiddlyspace) {
		proxy = "/reflector?uri=%0";
		proxyType: "POST";
	}
	var loader = new TW21Loader();
	var internalizer = function(node) {
		var title = $(node).attr("title");
		var tiddler = new Tiddler(title);
		loader.internalizeTiddler(store, tiddler, title, node);
		return tiddler;
	};

	var importer = ImportWizard({proxy:"%0", save: function(tid, callback) {
		merge(tid.fields, config.defaultCustomFields);
		delete tid.fields["server.page.revision"];
		delete tid.fields["server.etag"];
		tid = store.saveTiddler(tid.title, tid.title, tid.text,
			tid.modifier, tid.modified, tid.tags, tid.fields, null, tid.created, tid.creator);
		autoSaveChanges(null, [tid]);
		callback();
	}, internalizeTiddler: internalizer, proxyType: proxyType });

	config.macros.importTiddlers = {
		handler: function(place) {
			var container = $("<div />").appendTo(place)[0];
			new WizardMaker(container, importer);
		}
	};
} else if(config.macros.importTiddlers) {
	var _import = config.macros.importTiddlers.handler;
	config.macros.importTiddlers.handler = function(place) {
		_import.apply(this, arguments);
		jQuery("<div class='annotation error' />").text("Please upgrade your browser to take advantage of the modernised file import mechanism of the TiddlyFileImportr plugin.").prependTo(place);
	};
}

})(jQuery);
//}}}
/***
Description: Contains the stuff you need to use Tiddlyspot
Note, you also need UploadPlugin, PasswordOptionPlugin and LoadRemoteFileThroughProxy
from http://tiddlywiki.bidix.info for a complete working Tiddlyspot site.
***/
//{{{

// edit this if you are migrating sites or retrofitting an existing TW
config.tiddlyspotSiteId = 'infoboxes';

// make it so you can by default see edit controls via http
config.options.chkHttpReadOnly = false;
window.readOnly = false; // make sure of it (for tw 2.2)
window.showBackstage = true; // show backstage too

// disable autosave in d3
if (window.location.protocol != "file:")
	config.options.chkGTDLazyAutoSave = false;

// tweak shadow tiddlers to add upload button, password entry box etc
with (config.shadowTiddlers) {
	SiteUrl = 'http://'+config.tiddlyspotSiteId+'.tiddlyspot.com';
	SideBarOptions = SideBarOptions.replace(/(<<saveChanges>>)/,"$1<<tiddler TspotSidebar>>");
	OptionsPanel = OptionsPanel.replace(/^/,"<<tiddler TspotOptions>>");
	DefaultTiddlers = DefaultTiddlers.replace(/^/,"[[WelcomeToTiddlyspot]] ");
	MainMenu = MainMenu.replace(/^/,"[[WelcomeToTiddlyspot]] ");
}

// create some shadow tiddler content
merge(config.shadowTiddlers,{

'TspotOptions':[
 "tiddlyspot password:",
 "<<option pasUploadPassword>>",
 ""
].join("\n"),

'TspotControls':[
 "| tiddlyspot password:|<<option pasUploadPassword>>|",
 "| site management:|<<upload http://" + config.tiddlyspotSiteId + ".tiddlyspot.com/store.cgi index.html . .  " + config.tiddlyspotSiteId + ">>//(requires tiddlyspot password)//<br>[[control panel|http://" + config.tiddlyspotSiteId + ".tiddlyspot.com/controlpanel]], [[download (go offline)|http://" + config.tiddlyspotSiteId + ".tiddlyspot.com/download]]|",
 "| links:|[[tiddlyspot.com|http://tiddlyspot.com/]], [[FAQs|http://faq.tiddlyspot.com/]], [[blog|http://tiddlyspot.blogspot.com/]], email [[support|mailto:support@tiddlyspot.com]] & [[feedback|mailto:feedback@tiddlyspot.com]], [[donate|http://tiddlyspot.com/?page=donate]]|"
].join("\n"),

'WelcomeToTiddlyspot':[
 "This document is a ~TiddlyWiki from tiddlyspot.com.  A ~TiddlyWiki is an electronic notebook that is great for managing todo lists, personal information, and all sorts of things.",
 "",
 "@@font-weight:bold;font-size:1.3em;color:#444; //What now?// &nbsp;&nbsp;@@ Before you can save any changes, you need to enter your password in the form below.  Then configure privacy and other site settings at your [[control panel|http://" + config.tiddlyspotSiteId + ".tiddlyspot.com/controlpanel]] (your control panel username is //" + config.tiddlyspotSiteId + "//).",
 "<<tiddler TspotControls>>",
 "See also GettingStarted.",
 "",
 "@@font-weight:bold;font-size:1.3em;color:#444; //Working online// &nbsp;&nbsp;@@ You can edit this ~TiddlyWiki right now, and save your changes using the \"save to web\" button in the column on the right.",
 "",
 "@@font-weight:bold;font-size:1.3em;color:#444; //Working offline// &nbsp;&nbsp;@@ A fully functioning copy of this ~TiddlyWiki can be saved onto your hard drive or USB stick.  You can make changes and save them locally without being connected to the Internet.  When you're ready to sync up again, just click \"upload\" and your ~TiddlyWiki will be saved back to tiddlyspot.com.",
 "",
 "@@font-weight:bold;font-size:1.3em;color:#444; //Help!// &nbsp;&nbsp;@@ Find out more about ~TiddlyWiki at [[TiddlyWiki.com|http://tiddlywiki.com]].  Also visit [[TiddlyWiki.org|http://tiddlywiki.org]] for documentation on learning and using ~TiddlyWiki. New users are especially welcome on the [[TiddlyWiki mailing list|http://groups.google.com/group/TiddlyWiki]], which is an excellent place to ask questions and get help.  If you have a tiddlyspot related problem email [[tiddlyspot support|mailto:support@tiddlyspot.com]].",
 "",
 "@@font-weight:bold;font-size:1.3em;color:#444; //Enjoy :)// &nbsp;&nbsp;@@ We hope you like using your tiddlyspot.com site.  Please email [[feedback@tiddlyspot.com|mailto:feedback@tiddlyspot.com]] with any comments or suggestions."
].join("\n"),

'TspotSidebar':[
 "<<upload http://" + config.tiddlyspotSiteId + ".tiddlyspot.com/store.cgi index.html . .  " + config.tiddlyspotSiteId + ">><html><a href='http://" + config.tiddlyspotSiteId + ".tiddlyspot.com/download' class='button'>download</a></html>"
].join("\n")

});
//}}}
| !date | !user | !location | !storeUrl | !uploadDir | !toFilename | !backupdir | !origin |
| 22/04/2013 12:57:52 | Kristjan | [[/|http://infoboxes.tiddlyspot.com/]] | [[store.cgi|http://infoboxes.tiddlyspot.com/store.cgi]] | . | [[index.html | http://infoboxes.tiddlyspot.com/index.html]] | . |
| 13/03/2014 18:50:56 | Kristjan | [[/|http://infoboxes.tiddlyspot.com/]] | [[store.cgi|http://infoboxes.tiddlyspot.com/store.cgi]] | . | [[index.html | http://infoboxes.tiddlyspot.com/index.html]] | . |
| 05/04/2018 15:41:23 | Kristjan | [[/|http://infoboxes.tiddlyspot.com/]] | [[store.cgi|http://infoboxes.tiddlyspot.com/store.cgi]] | . | [[index.html | http://infoboxes.tiddlyspot.com/index.html]] | . |
| 18/04/2018 09:51:33 | Kristjan | [[/|http://infoboxes.tiddlyspot.com/]] | [[store.cgi|http://infoboxes.tiddlyspot.com/store.cgi]] | . | [[index.html | http://infoboxes.tiddlyspot.com/index.html]] | . |
| 18/04/2018 09:52:12 | "Kristjan" | [[/|http://infoboxes.tiddlyspot.com/]] | [[store.cgi|http://infoboxes.tiddlyspot.com/store.cgi]] | . | [[index.html | http://infoboxes.tiddlyspot.com/index.html]] | . |
| 18/04/2018 09:53:04 | Kristjan | [[/|http://infoboxes.tiddlyspot.com/]] | [[store.cgi|http://infoboxes.tiddlyspot.com/store.cgi]] | . | [[index.html | http://infoboxes.tiddlyspot.com/index.html]] | . |
| 18/04/2018 09:54:43 | Kristjan | [[/|http://infoboxes.tiddlyspot.com/]] | [[store.cgi|http://infoboxes.tiddlyspot.com/store.cgi]] | . | [[index.html | http://infoboxes.tiddlyspot.com/index.html]] | . |
| 19/05/2020 11:33:17 | "Kristjan" | [[/|http://infoboxes.tiddlyspot.com/]] | [[store.cgi|http://infoboxes.tiddlyspot.com/store.cgi]] | . | [[index.html | http://infoboxes.tiddlyspot.com/index.html]] | . |
| 19/05/2020 12:08:19 | Kristjan | [[/|http://infoboxes.tiddlyspot.com/]] | [[store.cgi|http://infoboxes.tiddlyspot.com/store.cgi]] | . | [[index.html | http://infoboxes.tiddlyspot.com/index.html]] | . |
| 19/05/2020 12:08:53 | "Kristjan" | [[/|http://infoboxes.tiddlyspot.com/]] | [[store.cgi|http://infoboxes.tiddlyspot.com/store.cgi]] | . | [[index.html | http://infoboxes.tiddlyspot.com/index.html]] | . |
/***
|''Name:''|UploadPlugin|
|''Description:''|Save to web a TiddlyWiki|
|''Version:''|4.1.3|
|''Date:''|Feb 24, 2008|
|''Source:''|http://tiddlywiki.bidix.info/#UploadPlugin|
|''Documentation:''|http://tiddlywiki.bidix.info/#UploadPluginDoc|
|''Author:''|BidiX (BidiX (at) bidix (dot) info)|
|''License:''|[[BSD open source license|http://tiddlywiki.bidix.info/#%5B%5BBSD%20open%20source%20license%5D%5D ]]|
|''~CoreVersion:''|2.2.0|
|''Requires:''|PasswordOptionPlugin|
***/
//{{{
version.extensions.UploadPlugin = {
	major: 4, minor: 1, revision: 3,
	date: new Date("Feb 24, 2008"),
	source: 'http://tiddlywiki.bidix.info/#UploadPlugin',
	author: 'BidiX (BidiX (at) bidix (dot) info',
	coreVersion: '2.2.0'
};

//
// Environment
//

if (!window.bidix) window.bidix = {}; // bidix namespace
bidix.debugMode = false;	// true to activate both in Plugin and UploadService
	
//
// Upload Macro
//

config.macros.upload = {
// default values
	defaultBackupDir: '',	//no backup
	defaultStoreScript: "store.php",
	defaultToFilename: "index.html",
	defaultUploadDir: ".",
	authenticateUser: true	// UploadService Authenticate User
};
	
config.macros.upload.label = {
	promptOption: "Save and Upload this TiddlyWiki with UploadOptions",
	promptParamMacro: "Save and Upload this TiddlyWiki in %0",
	saveLabel: "save to web", 
	saveToDisk: "save to disk",
	uploadLabel: "upload"	
};

config.macros.upload.messages = {
	noStoreUrl: "No store URL in parmeters or options",
	usernameOrPasswordMissing: "Username or password missing"
};

config.macros.upload.handler = function(place,macroName,params) {
	if (readOnly)
		return;
	var label;
	if (document.location.toString().substr(0,4) == "http") 
		label = this.label.saveLabel;
	else
		label = this.label.uploadLabel;
	var prompt;
	if (params[0]) {
		prompt = this.label.promptParamMacro.toString().format([this.destFile(params[0], 
			(params[1] ? params[1]:bidix.basename(window.location.toString())), params[3])]);
	} else {
		prompt = this.label.promptOption;
	}
	createTiddlyButton(place, label, prompt, function() {config.macros.upload.action(params);}, null, null, this.accessKey);
};

config.macros.upload.action = function(params)
{
		// for missing macro parameter set value from options
		if (!params) params = {};
		var storeUrl = params[0] ? params[0] : config.options.txtUploadStoreUrl;
		var toFilename = params[1] ? params[1] : config.options.txtUploadFilename;
		var backupDir = params[2] ? params[2] : config.options.txtUploadBackupDir;
		var uploadDir = params[3] ? params[3] : config.options.txtUploadDir;
		var username = params[4] ? params[4] : config.options.txtUploadUserName;
		var password = config.options.pasUploadPassword; // for security reason no password as macro parameter	
		// for still missing parameter set default value
		if ((!storeUrl) && (document.location.toString().substr(0,4) == "http")) 
			storeUrl = bidix.dirname(document.location.toString())+'/'+config.macros.upload.defaultStoreScript;
		if (storeUrl.substr(0,4) != "http")
			storeUrl = bidix.dirname(document.location.toString()) +'/'+ storeUrl;
		if (!toFilename)
			toFilename = bidix.basename(window.location.toString());
		if (!toFilename)
			toFilename = config.macros.upload.defaultToFilename;
		if (!uploadDir)
			uploadDir = config.macros.upload.defaultUploadDir;
		if (!backupDir)
			backupDir = config.macros.upload.defaultBackupDir;
		// report error if still missing
		if (!storeUrl) {
			alert(config.macros.upload.messages.noStoreUrl);
			clearMessage();
			return false;
		}
		if (config.macros.upload.authenticateUser && (!username || !password)) {
			alert(config.macros.upload.messages.usernameOrPasswordMissing);
			clearMessage();
			return false;
		}
		bidix.upload.uploadChanges(false,null,storeUrl, toFilename, uploadDir, backupDir, username, password); 
		return false; 
};

config.macros.upload.destFile = function(storeUrl, toFilename, uploadDir) 
{
	if (!storeUrl)
		return null;
		var dest = bidix.dirname(storeUrl);
		if (uploadDir && uploadDir != '.')
			dest = dest + '/' + uploadDir;
		dest = dest + '/' + toFilename;
	return dest;
};

//
// uploadOptions Macro
//

config.macros.uploadOptions = {
	handler: function(place,macroName,params) {
		var wizard = new Wizard();
		wizard.createWizard(place,this.wizardTitle);
		wizard.addStep(this.step1Title,this.step1Html);
		var markList = wizard.getElement("markList");
		var listWrapper = document.createElement("div");
		markList.parentNode.insertBefore(listWrapper,markList);
		wizard.setValue("listWrapper",listWrapper);
		this.refreshOptions(listWrapper,false);
		var uploadCaption;
		if (document.location.toString().substr(0,4) == "http") 
			uploadCaption = config.macros.upload.label.saveLabel;
		else
			uploadCaption = config.macros.upload.label.uploadLabel;
		
		wizard.setButtons([
				{caption: uploadCaption, tooltip: config.macros.upload.label.promptOption, 
					onClick: config.macros.upload.action},
				{caption: this.cancelButton, tooltip: this.cancelButtonPrompt, onClick: this.onCancel}
				
			]);
	},
	options: [
		"txtUploadUserName",
		"pasUploadPassword",
		"txtUploadStoreUrl",
		"txtUploadDir",
		"txtUploadFilename",
		"txtUploadBackupDir",
		"chkUploadLog",
		"txtUploadLogMaxLine"		
	],
	refreshOptions: function(listWrapper) {
		var opts = [];
		for(i=0; i<this.options.length; i++) {
			var opt = {};
			opts.push();
			opt.option = "";
			n = this.options[i];
			opt.name = n;
			opt.lowlight = !config.optionsDesc[n];
			opt.description = opt.lowlight ? this.unknownDescription : config.optionsDesc[n];
			opts.push(opt);
		}
		var listview = ListView.create(listWrapper,opts,this.listViewTemplate);
		for(n=0; n<opts.length; n++) {
			var type = opts[n].name.substr(0,3);
			var h = config.macros.option.types[type];
			if (h && h.create) {
				h.create(opts[n].colElements['option'],type,opts[n].name,opts[n].name,"no");
			}
		}
		
	},
	onCancel: function(e)
	{
		backstage.switchTab(null);
		return false;
	},
	
	wizardTitle: "Upload with options",
	step1Title: "These options are saved in cookies in your browser",
	step1Html: "<input type='hidden' name='markList'></input><br>",
	cancelButton: "Cancel",
	cancelButtonPrompt: "Cancel prompt",
	listViewTemplate: {
		columns: [
			{name: 'Description', field: 'description', title: "Description", type: 'WikiText'},
			{name: 'Option', field: 'option', title: "Option", type: 'String'},
			{name: 'Name', field: 'name', title: "Name", type: 'String'}
			],
		rowClasses: [
			{className: 'lowlight', field: 'lowlight'} 
			]}
};

//
// upload functions
//

if (!bidix.upload) bidix.upload = {};

if (!bidix.upload.messages) bidix.upload.messages = {
	//from saving
	invalidFileError: "The original file '%0' does not appear to be a valid TiddlyWiki",
	backupSaved: "Backup saved",
	backupFailed: "Failed to upload backup file",
	rssSaved: "RSS feed uploaded",
	rssFailed: "Failed to upload RSS feed file",
	emptySaved: "Empty template uploaded",
	emptyFailed: "Failed to upload empty template file",
	mainSaved: "Main TiddlyWiki file uploaded",
	mainFailed: "Failed to upload main TiddlyWiki file. Your changes have not been saved",
	//specific upload
	loadOriginalHttpPostError: "Can't get original file",
	aboutToSaveOnHttpPost: 'About to upload on %0 ...',
	storePhpNotFound: "The store script '%0' was not found."
};

bidix.upload.uploadChanges = function(onlyIfDirty,tiddlers,storeUrl,toFilename,uploadDir,backupDir,username,password)
{
	var callback = function(status,uploadParams,original,url,xhr) {
		if (!status) {
			displayMessage(bidix.upload.messages.loadOriginalHttpPostError);
			return;
		}
		if (bidix.debugMode) 
			alert(original.substr(0,500)+"\n...");
		// Locate the storeArea div's 
		var posDiv = locateStoreArea(original);
		if((posDiv[0] == -1) || (posDiv[1] == -1)) {
			alert(config.messages.invalidFileError.format([localPath]));
			return;
		}
		bidix.upload.uploadRss(uploadParams,original,posDiv);
	};
	
	if(onlyIfDirty && !store.isDirty())
		return;
	clearMessage();
	// save on localdisk ?
	if (document.location.toString().substr(0,4) == "file") {
		var path = document.location.toString();
		var localPath = getLocalPath(path);
		saveChanges();
	}
	// get original
	var uploadParams = new Array(storeUrl,toFilename,uploadDir,backupDir,username,password);
	var originalPath = document.location.toString();
	// If url is a directory : add index.html
	if (originalPath.charAt(originalPath.length-1) == "/")
		originalPath = originalPath + "index.html";
	var dest = config.macros.upload.destFile(storeUrl,toFilename,uploadDir);
	var log = new bidix.UploadLog();
	log.startUpload(storeUrl, dest, uploadDir,  backupDir);
	displayMessage(bidix.upload.messages.aboutToSaveOnHttpPost.format([dest]));
	if (bidix.debugMode) 
		alert("about to execute Http - GET on "+originalPath);
	var r = doHttp("GET",originalPath,null,null,username,password,callback,uploadParams,null);
	if (typeof r == "string")
		displayMessage(r);
	return r;
};

bidix.upload.uploadRss = function(uploadParams,original,posDiv) 
{
	var callback = function(status,params,responseText,url,xhr) {
		if(status) {
			var destfile = responseText.substring(responseText.indexOf("destfile:")+9,responseText.indexOf("\n", responseText.indexOf("destfile:")));
			displayMessage(bidix.upload.messages.rssSaved,bidix.dirname(url)+'/'+destfile);
			bidix.upload.uploadMain(params[0],params[1],params[2]);
		} else {
			displayMessage(bidix.upload.messages.rssFailed);			
		}
	};
	// do uploadRss
	if(config.options.chkGenerateAnRssFeed) {
		var rssPath = uploadParams[1].substr(0,uploadParams[1].lastIndexOf(".")) + ".xml";
		var rssUploadParams = new Array(uploadParams[0],rssPath,uploadParams[2],'',uploadParams[4],uploadParams[5]);
		var rssString = generateRss();
		// no UnicodeToUTF8 conversion needed when location is "file" !!!
		if (document.location.toString().substr(0,4) != "file")
			rssString = convertUnicodeToUTF8(rssString);	
		bidix.upload.httpUpload(rssUploadParams,rssString,callback,Array(uploadParams,original,posDiv));
	} else {
		bidix.upload.uploadMain(uploadParams,original,posDiv);
	}
};

bidix.upload.uploadMain = function(uploadParams,original,posDiv) 
{
	var callback = function(status,params,responseText,url,xhr) {
		var log = new bidix.UploadLog();
		if(status) {
			// if backupDir specified
			if ((params[3]) && (responseText.indexOf("backupfile:") > -1))  {
				var backupfile = responseText.substring(responseText.indexOf("backupfile:")+11,responseText.indexOf("\n", responseText.indexOf("backupfile:")));
				displayMessage(bidix.upload.messages.backupSaved,bidix.dirname(url)+'/'+backupfile);
			}
			var destfile = responseText.substring(responseText.indexOf("destfile:")+9,responseText.indexOf("\n", responseText.indexOf("destfile:")));
			displayMessage(bidix.upload.messages.mainSaved,bidix.dirname(url)+'/'+destfile);
			store.setDirty(false);
			log.endUpload("ok");
		} else {
			alert(bidix.upload.messages.mainFailed);
			displayMessage(bidix.upload.messages.mainFailed);
			log.endUpload("failed");			
		}
	};
	// do uploadMain
	var revised = bidix.upload.updateOriginal(original,posDiv);
	bidix.upload.httpUpload(uploadParams,revised,callback,uploadParams);
};

bidix.upload.httpUpload = function(uploadParams,data,callback,params)
{
	var localCallback = function(status,params,responseText,url,xhr) {
		url = (url.indexOf("nocache=") < 0 ? url : url.substring(0,url.indexOf("nocache=")-1));
		if (xhr.status == 404)
			alert(bidix.upload.messages.storePhpNotFound.format([url]));
		if ((bidix.debugMode) || (responseText.indexOf("Debug mode") >= 0 )) {
			alert(responseText);
			if (responseText.indexOf("Debug mode") >= 0 )
				responseText = responseText.substring(responseText.indexOf("\n\n")+2);
		} else if (responseText.charAt(0) != '0') 
			alert(responseText);
		if (responseText.charAt(0) != '0')
			status = null;
		callback(status,params,responseText,url,xhr);
	};
	// do httpUpload
	var boundary = "---------------------------"+"AaB03x";	
	var uploadFormName = "UploadPlugin";
	// compose headers data
	var sheader = "";
	sheader += "--" + boundary + "\r\nContent-disposition: form-data; name=\"";
	sheader += uploadFormName +"\"\r\n\r\n";
	sheader += "backupDir="+uploadParams[3] +
				";user=" + uploadParams[4] +
				";password=" + uploadParams[5] +
				";uploaddir=" + uploadParams[2];
	if (bidix.debugMode)
		sheader += ";debug=1";
	sheader += ";;\r\n"; 
	sheader += "\r\n" + "--" + boundary + "\r\n";
	sheader += "Content-disposition: form-data; name=\"userfile\"; filename=\""+uploadParams[1]+"\"\r\n";
	sheader += "Content-Type: text/html;charset=UTF-8" + "\r\n";
	sheader += "Content-Length: " + data.length + "\r\n\r\n";
	// compose trailer data
	var strailer = new String();
	strailer = "\r\n--" + boundary + "--\r\n";
	data = sheader + data + strailer;
	if (bidix.debugMode) alert("about to execute Http - POST on "+uploadParams[0]+"\n with \n"+data.substr(0,500)+ " ... ");
	var r = doHttp("POST",uploadParams[0],data,"multipart/form-data; ;charset=UTF-8; boundary="+boundary,uploadParams[4],uploadParams[5],localCallback,params,null);
	if (typeof r == "string")
		displayMessage(r);
	return r;
};

// same as Saving's updateOriginal but without convertUnicodeToUTF8 calls
bidix.upload.updateOriginal = function(original, posDiv)
{
	if (!posDiv)
		posDiv = locateStoreArea(original);
	if((posDiv[0] == -1) || (posDiv[1] == -1)) {
		alert(config.messages.invalidFileError.format([localPath]));
		return;
	}
	var revised = original.substr(0,posDiv[0] + startSaveArea.length) + "\n" +
				store.allTiddlersAsHtml() + "\n" +
				original.substr(posDiv[1]);
	var newSiteTitle = getPageTitle().htmlEncode();
	revised = revised.replaceChunk("<title"+">","</title"+">"," " + newSiteTitle + " ");
	revised = updateMarkupBlock(revised,"PRE-HEAD","MarkupPreHead");
	revised = updateMarkupBlock(revised,"POST-HEAD","MarkupPostHead");
	revised = updateMarkupBlock(revised,"PRE-BODY","MarkupPreBody");
	revised = updateMarkupBlock(revised,"POST-SCRIPT","MarkupPostBody");
	return revised;
};

//
// UploadLog
// 
// config.options.chkUploadLog :
//		false : no logging
//		true : logging
// config.options.txtUploadLogMaxLine :
//		-1 : no limit
//      0 :  no Log lines but UploadLog is still in place
//		n :  the last n lines are only kept
//		NaN : no limit (-1)

bidix.UploadLog = function() {
	if (!config.options.chkUploadLog) 
		return; // this.tiddler = null
	this.tiddler = store.getTiddler("UploadLog");
	if (!this.tiddler) {
		this.tiddler = new Tiddler();
		this.tiddler.title = "UploadLog";
		this.tiddler.text = "| !date | !user | !location | !storeUrl | !uploadDir | !toFilename | !backupdir | !origin |";
		this.tiddler.created = new Date();
		this.tiddler.modifier = config.options.txtUserName;
		this.tiddler.modified = new Date();
		store.addTiddler(this.tiddler);
	}
	return this;
};

bidix.UploadLog.prototype.addText = function(text) {
	if (!this.tiddler)
		return;
	// retrieve maxLine when we need it
	var maxLine = parseInt(config.options.txtUploadLogMaxLine,10);
	if (isNaN(maxLine))
		maxLine = -1;
	// add text
	if (maxLine != 0) 
		this.tiddler.text = this.tiddler.text + text;
	// Trunck to maxLine
	if (maxLine >= 0) {
		var textArray = this.tiddler.text.split('\n');
		if (textArray.length > maxLine + 1)
			textArray.splice(1,textArray.length-1-maxLine);
			this.tiddler.text = textArray.join('\n');		
	}
	// update tiddler fields
	this.tiddler.modifier = config.options.txtUserName;
	this.tiddler.modified = new Date();
	store.addTiddler(this.tiddler);
	// refresh and notifiy for immediate update
	story.refreshTiddler(this.tiddler.title);
	store.notify(this.tiddler.title, true);
};

bidix.UploadLog.prototype.startUpload = function(storeUrl, toFilename, uploadDir,  backupDir) {
	if (!this.tiddler)
		return;
	var now = new Date();
	var text = "\n| ";
	var filename = bidix.basename(document.location.toString());
	if (!filename) filename = '/';
	text += now.formatString("0DD/0MM/YYYY 0hh:0mm:0ss") +" | ";
	text += config.options.txtUserName + " | ";
	text += "[["+filename+"|"+location + "]] |";
	text += " [[" + bidix.basename(storeUrl) + "|" + storeUrl + "]] | ";
	text += uploadDir + " | ";
	text += "[[" + bidix.basename(toFilename) + " | " +toFilename + "]] | ";
	text += backupDir + " |";
	this.addText(text);
};

bidix.UploadLog.prototype.endUpload = function(status) {
	if (!this.tiddler)
		return;
	this.addText(" "+status+" |");
};

//
// Utilities
// 

bidix.checkPlugin = function(plugin, major, minor, revision) {
	var ext = version.extensions[plugin];
	if (!
		(ext  && 
			((ext.major > major) || 
			((ext.major == major) && (ext.minor > minor))  ||
			((ext.major == major) && (ext.minor == minor) && (ext.revision >= revision))))) {
			// write error in PluginManager
			if (pluginInfo)
				pluginInfo.log.push("Requires " + plugin + " " + major + "." + minor + "." + revision);
			eval(plugin); // generate an error : "Error: ReferenceError: xxxx is not defined"
	}
};

bidix.dirname = function(filePath) {
	if (!filePath) 
		return;
	var lastpos;
	if ((lastpos = filePath.lastIndexOf("/")) != -1) {
		return filePath.substring(0, lastpos);
	} else {
		return filePath.substring(0, filePath.lastIndexOf("\\"));
	}
};

bidix.basename = function(filePath) {
	if (!filePath) 
		return;
	var lastpos;
	if ((lastpos = filePath.lastIndexOf("#")) != -1) 
		filePath = filePath.substring(0, lastpos);
	if ((lastpos = filePath.lastIndexOf("/")) != -1) {
		return filePath.substring(lastpos + 1);
	} else
		return filePath.substring(filePath.lastIndexOf("\\")+1);
};

bidix.initOption = function(name,value) {
	if (!config.options[name])
		config.options[name] = value;
};

//
// Initializations
//

// require PasswordOptionPlugin 1.0.1 or better
bidix.checkPlugin("PasswordOptionPlugin", 1, 0, 1);

// styleSheet
setStylesheet('.txtUploadStoreUrl, .txtUploadBackupDir, .txtUploadDir {width: 22em;}',"uploadPluginStyles");

//optionsDesc
merge(config.optionsDesc,{
	txtUploadStoreUrl: "Url of the UploadService script (default: store.php)",
	txtUploadFilename: "Filename of the uploaded file (default: in index.html)",
	txtUploadDir: "Relative Directory where to store the file (default: . (downloadService directory))",
	txtUploadBackupDir: "Relative Directory where to backup the file. If empty no backup. (default: ''(empty))",
	txtUploadUserName: "Upload Username",
	pasUploadPassword: "Upload Password",
	chkUploadLog: "do Logging in UploadLog (default: true)",
	txtUploadLogMaxLine: "Maximum of lines in UploadLog (default: 10)"
});

// Options Initializations
bidix.initOption('txtUploadStoreUrl','');
bidix.initOption('txtUploadFilename','');
bidix.initOption('txtUploadDir','');
bidix.initOption('txtUploadBackupDir','');
bidix.initOption('txtUploadUserName','');
bidix.initOption('pasUploadPassword','');
bidix.initOption('chkUploadLog',true);
bidix.initOption('txtUploadLogMaxLine','10');


// Backstage
merge(config.tasks,{
	uploadOptions: {text: "upload", tooltip: "Change UploadOptions and Upload", content: '<<uploadOptions>>'}
});
config.backstageTasks.push("uploadOptions");


//}}}