<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<script type="text/javascript">
//<![CDATA[
var version = {title: "TiddlyWiki", major: 2, minor: 2, revision: 1, date: new Date("Jun 8, 2007"), extensions: {}};
//]]>
</script>
<!--
TiddlyWiki created by Jeremy Ruston, (jeremy [at] osmosoft [dot] com)

Copyright (c) UnaMesa Association 2004-2007

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or other
materials provided with the distribution.

Neither the name of the Osmosoft Limited nor the names of its contributors may be
used to endorse or promote products derived from this software without specific
prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
-->
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
<!--PRE-HEAD-START-->
<!--{{{-->
<link rel='alternate' type='application/rss+xml' title='RSS' href='index.xml'/>
<!--}}}-->
<!--PRE-HEAD-END-->
<title> Schlanger's Wiki - Busting his guts to make things work </title>
<style type="text/css">
#saveTest {display:none;}
#messageArea {display:none;}
#copyright {display:none;}
#storeArea {display:none;}
#storeArea div {padding:0.5em; margin:1em 0em 0em 0em; border-color:#fff #666 #444 #ddd; border-style:solid; border-width:2px; overflow:auto;}
#shadowArea {display:none;}
#javascriptWarning {width:100%; text-align:center; font-weight:bold; background-color:#dd1100; color:#fff; padding:1em 0em;}
</style>
<!--POST-HEAD-START-->

<!--POST-HEAD-END-->
</head>
<div id="shadowArea">
<div title="ColorPalette">
<pre>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</pre>
</div>
<div title="StyleSheetColors">
<pre>/*{{{*/
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]];}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

#backstageArea {background:[[ColorPalette::Foreground]]; color:[[ColorPalette::TertiaryMid]];}
#backstageArea a {background:[[ColorPalette::Foreground]]; color:[[ColorPalette::Background]]; border:none;}
#backstageArea a:hover {background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]]; }
#backstageArea a.backstageSelTab {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}
#backstageButton a {background:none; color:[[ColorPalette::Background]]; border:none;}
#backstageButton a:hover {background:[[ColorPalette::Foreground]]; color:[[ColorPalette::Background]]; border:none;}
#backstagePanel {background:[[ColorPalette::Background]]; border-color: [[ColorPalette::Background]] [[ColorPalette::TertiaryDark]] [[ColorPalette::TertiaryDark]] [[ColorPalette::TertiaryDark]];}
.backstagePanelFooter .button {border:none; color:[[ColorPalette::Background]];}
.backstagePanelFooter .button:hover {color:[[ColorPalette::Foreground]];}
#backstageCloak {background:[[ColorPalette::Foreground]]; opacity:0.6; filter:'alpha(opacity:60)';}
/*}}}*/</pre>
</div>
<div title="StyleSheetLayout">
<pre>/*{{{*/
* 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 0em 1em 1em; left:-1px; top:-1px;}
.headerForeground {position:absolute; padding:4.5em 0em 1em 1em; left:0px; top:0px;}

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

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

#sidebar {position:absolute; right:3px; width:16em; font-size:.9em;}
#sidebarOptions {padding-top:0.3em;}
#sidebarOptions a {margin:0em 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 .3em 0;}
#sidebarTabs .tabContents {width:15em; overflow:hidden;}

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

#messageArea {position:absolute; top:2em; right:0em; margin:0.5em; padding:0.5em; z-index:200;}
*[id='messageArea'] {position:fixed !important; z-index:200;}
.messageToolbar {display:block; text-align:right; padding:0.2em 0.2em 0.2em 0.2em;}
#messageArea a {text-decoration:underline;}

.tiddlerPopupButton {padding:0.2em 0.2em 0.2em 0.2em;}
.popupTiddler {position: absolute; z-index:300; padding:1em 1em 1em 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 0em;}
.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 0em 0em 0.5em;}
.tab {margin:0em 0em 0em 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 0em 14em;}

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

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

.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:0em 0.25em; padding:0em 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;}

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

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

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

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

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

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

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

.whenBackstage {display:none;}
.backstageVisible .whenBackstage {display:block;}
/*}}}*/</pre>
</div>
<div title="StyleSheetLocale">
<pre>/***
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 use a logographic writing system and 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;}

.htmlarea .toolbarHA table {border:1px solid ButtonFace; margin:0em 0em;}
/*}}}*/</pre>
</div>
<div title="StyleSheetPrint">
<pre>/*{{{*/
@media print {
#mainMenu, #sidebar, #messageArea, .toolbar {display: none ! important;}
#displayArea {margin: 1em 1em 0em 1em;}
/* Fixes a feature in Firefox 1.5.0.2 where print preview displays the noscript content */
noscript {display:none;}
}
/*}}}*/</pre>
</div>
<div title="PageTemplate">
<pre>&lt;!--{{{--&gt;
&lt;div class='header' macro='gradient vert [[ColorPalette::PrimaryLight]] [[ColorPalette::PrimaryMid]]'&gt;
&lt;div class='headerShadow'&gt;
&lt;span class='siteTitle' refresh='content' tiddler='SiteTitle'&gt;&lt;/span&gt;&amp;nbsp;
&lt;span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;div class='headerForeground'&gt;
&lt;span class='siteTitle' refresh='content' tiddler='SiteTitle'&gt;&lt;/span&gt;&amp;nbsp;
&lt;span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id='mainMenu' refresh='content' tiddler='MainMenu'&gt;&lt;/div&gt;
&lt;div id='sidebar'&gt;
&lt;div id='sidebarOptions' refresh='content' tiddler='SideBarOptions'&gt;&lt;/div&gt;
&lt;div id='sidebarTabs' refresh='content' force='true' tiddler='SideBarTabs'&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div id='displayArea'&gt;
&lt;div id='messageArea'&gt;&lt;/div&gt;
&lt;div id='tiddlerDisplay'&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;!--}}}--&gt;</pre>
</div>
<div title="ViewTemplate">
<pre>&lt;!--{{{--&gt;
&lt;div class='toolbar' macro='toolbar closeTiddler closeOthers +editTiddler &gt; fields syncing permalink references jump'&gt;&lt;/div&gt;
&lt;div class='title' macro='view title'&gt;&lt;/div&gt;
&lt;div class='subtitle'&gt;&lt;span macro='view modifier link'&gt;&lt;/span&gt;, &lt;span macro='view modified date'&gt;&lt;/span&gt; (&lt;span macro='message views.wikified.createdPrompt'&gt;&lt;/span&gt; &lt;span macro='view created date'&gt;&lt;/span&gt;)&lt;/div&gt;
&lt;div class='tagging' macro='tagging'&gt;&lt;/div&gt;
&lt;div class='tagged' macro='tags'&gt;&lt;/div&gt;
&lt;div class='viewer' macro='view text wikified'&gt;&lt;/div&gt;
&lt;div class='tagClear'&gt;&lt;/div&gt;
&lt;!--}}}--&gt;</pre>
</div>
<div title="EditTemplate">
<pre>&lt;!--{{{--&gt;
&lt;div class='toolbar' macro='toolbar +saveTiddler -cancelTiddler deleteTiddler'&gt;&lt;/div&gt;
&lt;div class='title' macro='view title'&gt;&lt;/div&gt;
&lt;div class='editor' macro='edit title'&gt;&lt;/div&gt;
&lt;div macro='annotations'&gt;&lt;/div&gt;
&lt;div class='editor' macro='edit text'&gt;&lt;/div&gt;
&lt;div class='editor' macro='edit tags'&gt;&lt;/div&gt;&lt;div class='editorFooter'&gt;&lt;span macro='message views.editor.tagPrompt'&gt;&lt;/span&gt;&lt;span macro='tagChooser'&gt;&lt;/span&gt;&lt;/div&gt;
&lt;!--}}}--&gt;</pre>
</div>
<div title="GettingStarted">
<pre>To get started with this blank TiddlyWiki, you'll need to modify the following tiddlers:
* SiteTitle &amp; 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: &lt;&lt;option txtUserName&gt;&gt;</pre>
</div>
<div title="OptionsPanel">
<pre>These InterfaceOptions for customising TiddlyWiki are saved in your browser

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

&lt;&lt;option txtUserName&gt;&gt;
&lt;&lt;option chkSaveBackups&gt;&gt; SaveBackups
&lt;&lt;option chkAutoSave&gt;&gt; AutoSave
&lt;&lt;option chkRegExpSearch&gt;&gt; RegExpSearch
&lt;&lt;option chkCaseSensitiveSearch&gt;&gt; CaseSensitiveSearch
&lt;&lt;option chkAnimate&gt;&gt; EnableAnimations

----
Also see AdvancedOptions</pre>
</div>
</div>
<!--POST-SHADOWAREA-->
<body onload="main();" onunload="if(window.checkUnsavedChanges) checkUnsavedChanges(); if(window.scrubNodes) scrubNodes(document.body);">
<!--PRE-BODY-START-->

<!--PRE-BODY-END-->
<div id="copyright">
Welcome to TiddlyWiki by Jeremy Ruston, Copyright &copy; 2007 Osmosoft Limited
</div>
<noscript>
        <div id="javascriptWarning">This page requires JavaScript to function properly.<br /><br />If you are using Microsoft Internet Explorer you may need to click on the yellow bar above and select 'Allow Blocked Content'. You must then click 'Yes' on the following security warning.</div>
</noscript>
<div id="saveTest"></div>
<div id="backstageCloak"></div>
<div id="backstageButton"></div>
<div id="backstageArea"><div id="backstageToolbar"></div></div>
<div id="backstage">
        <div id="backstagePanel"></div>
</div>
<div id="contentWrapper"></div>
<div id="contentStash"></div>
<div id="storeArea">
<div title="4096 Color wheel" modifier="giffmex" modified="200708231921" created="200708231918" changecount="2">
<pre>Source: http://www.ficml.org/jemimap/style/color/wheel.html 
&lt;html&gt;&lt;iframe name=&quot;content&quot; src=&quot;http://www.ficml.org/jemimap/style/color/wheel.html&quot; width=100% height=600&gt;&lt;/iframe&gt;&lt;/html&gt;</pre>
</div>
<div title="A plug for Plugins" modifier="giffmex" modified="200709011826" created="200708232054" changecount="3">
<pre>*[[How to install a plugin]]
*[[TiddlyVault: your source for macros, plugins and themes]]</pre>
</div>
<div title="A visual guide to the TiddlyWiki layout" modifier="GiffMex" modified="200703071355" created="200612231733">
<pre>Here are the basic elements in a typical ~TiddlyWiki layout (this tutorial uses a modification that places the ~MainMenu at the top in a horizontal fashion). Below the graphic are links to other screen captures with more information.

[img[http://www.giffmex.org/images/mainscreen.GIF]]

[[The header]]
[[The main menu]]
[[The right hand menu]]
[[Anatomy of a Tiddler]]

</pre>
</div>
<div title="Access files, folders, etc from within TiddlyWiki" modifier="giffmex" modified="200708251529" created="200708251518" changecount="5">
<pre>With these tools you can practically make your ~TiddlyWiki file your command central for your computer!

*[[Use IFrames to embed other webpages in your TiddlyWiki]]
*[[Open the indexes of your hard drive, CD or USB files from inside your TiddlyWiki]]
*[[Browse your files and folders from within TiddlyWiki]]
*[[Launch applications from within TiddlyWiki]]</pre>
</div>
<div title="Advanced ideas for tags" modifier="churu1" modified="200706041451" created="200703051602">
<pre>Tags are great for grouping tiddlers into categories. For example, you can tag all your recipes with a 'recipe' tag, and then whenever you want to see a list of your recipes, you go to the tabbed list 'Tags' and click on 'recipe' to see a list of your recipes. You can use this idea to sort books by topic, sort music by genre, sort contacts by contact type, etc. ''There are a couple tags with special functions:''
*The excludeSearch tag is a handy one for excluding a tiddler from appearing in searches.
*The excludeLists tag is handy for excluding a tiddler from the tabbed lists to the right.

!Index a tag
You can ''create indexes for specific tags'' and put these indexes in your ~MainMenu. Here's how:
#''Import the ~ForEachTiddler plugin: ''
##Open ImportTiddlers
##Paste the following URL (http://tiddlywiki.abego-software.de/)
##Select the ~ForEachTiddler plugin from the list that appears by checking the checkbox next to it. 
##Go to the bottom and in the dropdown box select &quot;Import these tiddlers.&quot;
##Reload your file by clicking your browser's refresh or reload button.
#''Create a new tiddler'' and give it a title that reflects the function of the index you are creating
#Paste the text below into the tiddler and substitute the name of your tag where I have the letters XXXX.
/*{{{*/
&lt;&lt;forEachTiddler 
where 
'tiddler.tags.contains(&quot;XXXX&quot;)
sortBy
'tiddler.title'&gt;&gt;
/*}}}*/
Click done. You should now have an index of tiddlers containing your tag. This index is automatically updated every tiime you add a new tiddler with this tag.

!Index all your tags
You can get a list of all your tags with the tiddlers associated with each tag. Here's how:
#Import the InlineJavascriptPlugin (this step is not necessary if you are using a TW based on this tutorial). 
##Open ImportTiddlers
##Paste the following URL (http://tiddlywiki.abego-software.de/)
##Select the ~InlineJavascript plugin from the list that appears by checking the checkbox next to it. 
##Go to the bottom and in the dropdown box select &quot;Import these tiddlers.&quot;
##Reload your file by clicking your browser's refresh or reload button.
#Create a new tiddler. I suggest the title ~ShowAllByTags.
#Add the text below to your tiddler, add the tag 'script' to your tiddler (without quotes), then click done. You should now have an index of all your tags.
/*{{{*/
&lt;script&gt;
        var tags = store.getTags();
        if(tags.length == 0) return &quot;no tags in document&quot;;
        var out=&quot;&quot;;
        for(var t=0; t&lt;tags.length; t++) {
                out+=&quot;*[[&quot;+tags[t][0]+&quot;]] (&quot;+tags[t][1]+&quot;)&quot;+&quot;\n&quot;;
                var tids=store.getTaggedTiddlers(tags[t][0]);
                for (i=0; i&lt;tids.length; i++) out+=&quot;##[[&quot;+tids[i].title+&quot;]]\n&quot;;
        }
        return out;
&lt;/script&gt;
/*}}}*/



</pre>
</div>
<div title="Align the text in a cell at the top instead of the center" modifier="giffmex" created="200708250021" changecount="3">
<pre>To align a cell so that its text displays at the top rather than the center, add 

{{{vertical-align:top;}}} 

at the beginning of the cell.

</pre>
</div>
<div title="Alternate the color of table rows" modifier="giffmex" modified="200708250046" created="200708250035" changecount="16">
<pre>To alternate the colors of the rows of the tables in a ~TiddlyWiki, add the following code to your StyleSheet:
{{{
.viewer tr.oddRow { background-color: #bbbbbb; }
.viewer tr.evenRow { background-color: #fff; } 
}}}

Your table rows will alternate between gray and white. Of course, you can substitute any colors you wish, using tools such as [[4096 Color wheel]] and [[Coloria color names]] to find the correct code.

You can also create a special CSS class for a particular table or series of tables, to format them differently than your default table style. In your stylesheet you add the following code, substituting &quot;FOO&quot; with any title you prefer:

{{{
.viewer .FOO table tr.oddRow { background-color: #bbbbbb; }
.viewer .FOO table tr.evenRow { background-color: #fff; } 
}}}

Then wrap your table with
{{{
{{FOO{ and }}}
}}}

Here is the result:

{{FOO{
|tablke|table|
|gakgjne|vbskjngeo|
}}}</pre>
</div>
<div title="Anatomy of a Tiddler" modifier="GiffMex" modified="200612241432" created="200612232238">
<pre>! The main elements of a Tiddler
[img[http://www.giffmex.org/images/tiddler.GIF]]

! The Tiddler's hidden buttons
[img[http://www.giffmex.org/images/buttonseng.GIF]]

! A tiddler in 'edit' mode
When you double-click on a Tiddler or click the edit button, the Tiddler opens up into edit mode. Here is what it looks like:

[img[http://www.giffmex.org/images/editmode.GIF]]

When you are done editing the Tiddler, here are the options.
[img[http://www.giffmex.org/images/donecanceldelete.GIF]]</pre>
</div>
<div title="Apples" modifier="GiffMex" modified="200701271319" created="200701271312" tags="palette">
<pre>Background: #ddff88
Foreground: #000
PrimaryPale: #bbee66
PrimaryLight: #aa0033
PrimaryMid: #440000
PrimaryDark: #000
SecondaryPale: #ffc
SecondaryLight: #99cc00
SecondaryMid: #db4
SecondaryDark: #440000
TertiaryPale: #bbee66
TertiaryLight: #EEC591
TertiaryMid: #440044
TertiaryDark: #000
</pre>
</div>
<div title="Blueberry" modifier="GiffMex" modified="200701271329" created="200701271325" tags="palette">
<pre>Background: #bbbbff
Foreground: #000
PrimaryPale: #99aacc
PrimaryLight: #006699
PrimaryMid: #002244
PrimaryDark: #000
SecondaryPale: #ffc
SecondaryLight: #fe8
SecondaryMid: #db4
SecondaryDark: #002244
TertiaryPale: #99aacc
TertiaryLight: #aaaaff
TertiaryMid: #000
TertiaryDark: #8B7355 </pre>
</div>
<div title="Brown color scheme" modifier="GiffMex" modified="200612270359" created="200612100534">
<pre>Background: #FFFFFF
Foreground: #000
PrimaryPale: #FF8C69
PrimaryLight: #FF8C69
PrimaryMid: #8B4C39
PrimaryDark: #410
SecondaryPale: #ffc
SecondaryLight: #fe8
SecondaryMid: #db4
SecondaryDark: #841
TertiaryPale: #FFD39B
TertiaryLight: #EEC591
TertiaryMid: #CDAA7D
TertiaryDark: #8B7355 </pre>
</div>
<div title="Browse your files and folders from within TiddlyWiki" modifier="giffmex" modified="200708251525" created="200708251520" changecount="10">
<pre>The following code added to your tiddler:

{{{
&lt;html&gt;&lt;div align=&quot;left&quot;&gt;&lt;FORM name=form1&gt;&lt;INPUT type=file name=cmuds&gt; &lt;INPUT onclick=&quot;whatFile()&quot; type=button value=OpenFile name=button&gt;&lt;/FORM&gt;&lt;/div&gt;&lt;br&gt;&lt;/html&gt;
}}}

Produces this:

&lt;html&gt;&lt;div align=&quot;left&quot;&gt;&lt;FORM name=form1&gt;&lt;INPUT type=file name=cmuds&gt; &lt;INPUT onclick=&quot;whatFile()&quot; type=button value=OpenFile name=button&gt;&lt;/FORM&gt;&lt;/div&gt;&lt;br&gt;&lt;/html&gt;
You will need to refresh or reload your ~TiddlyWiki for the code to work.</pre>
</div>
<div title="Browser-specific issues" modifier="tiddlyvault" created="200710011422" changecount="1">
<pre>[[Special note for users of Internet Explorer]]
[[Tips for making Mozilla Firefox run faster]]</pre>
</div>
<div title="Can I have both a left-hand menu AND a top menu, each with different items?" modifier="GiffMex" modified="200703071341" created="200702221506">
<pre>Why, golly gee whillickers, you both can and may. Depending on which MainMenu you already have, follow the instructions already given to add the missing menu, either a [[topmenu|How do I remove the left-hand menu of a typical TiddlyWiki and create a top menu for it?]] or a [[left-hand menu|How do I remove the top menu and have a normal left-hand menu?]].

Now what you need to do is decide which menu will draw its information from the MainMenu tiddler, and which menu will draw its information from a tiddler menu that you create, let's call it ~SecondMenu. Create the Tiddler SecondMenu and add a few random menu items to it, like {{{[[TabTags]]}}} and {{{SiteUrl]]}}}. Save the tiddler.

Now in PageTemplate, if you have made the adjustments above, you should see the following lines:

&lt;!--{{{--&gt;
&lt;!-- horizontal MainMenu --&gt;
&lt;div id='topMenu' refresh='content' tiddler='MainMenu'&gt;&lt;/div&gt;
&lt;!--original MainMenu menu--&gt;
&lt;div id='mainMenu' refresh='content' tiddler='MainMenu'&gt;&lt;/div&gt;
&lt;!--}}}--&gt;

In either the second or the fourth line above you are going to replace {{{tiddler='MainMenu'}}} with {{{tiddler='SecondMenu' }}}. If you want the menu items you placed in ~SecondMenu to be in the top menu, then modify the second line above. If you want the ~SecondMenu menu items to appear in the left-hand menu, then modify the fourth line above.

When you save and close PageTemplate you should see both menus, one containing the ~MainMenu contents and one containing ~SecondMenu contents. Now change the contents of ~SecondMenu to suit your needs.

</pre>
</div>
<div title="Capuccino color scheme" modifier="GiffMex" created="200612100531">
<pre>Background: #ddcc99
Foreground: #000
PrimaryPale: #998855
PrimaryLight: #664411
PrimaryMid: #221111
PrimaryDark: #410
SecondaryPale: #ffc
SecondaryLight: #fe8
SecondaryMid: #db4
SecondaryDark: #841
TertiaryPale: #998855
TertiaryLight: #EEC591
TertiaryMid: #841
TertiaryDark: #8B7355
</pre>
</div>
<div title="Capuccino2 color scheme" modifier="GiffMex" created="200612231400">
<pre>Background: #ffdd77
Foreground: #000
PrimaryPale: #aa8855
PrimaryLight: #dd9922
PrimaryMid: #554422
PrimaryDark: #000
SecondaryPale: #ffc
SecondaryLight: #fe8
SecondaryMid: #db4
SecondaryDark: #841
TertiaryPale: #aa8855
TertiaryLight: #EEC591
TertiaryMid: #000
TertiaryDark: #8B7355</pre>
</div>
<div title="Changing the colors of a TiddlyWiki" modifier="giffmex" modified="200708231923" created="200701182142" changecount="4">
<pre>You can change the colors by clicking on the ColorPalette tiddler and using html color codes to adjust the colors of different sections of the file. Click on [[ColorPalette color designations]] to see which parts of the ColorPalette affect which parts of the screen.

(To let you test it out I made [[a few sample color schemes|ColorSchemes]] for you. Copy and paste each one in the ColorPalette tiddler to see if you like it. If you want the current color scheme back, copy and paste the 'lilac' color scheme into the ColorPalette.)

For my two favorite tools for picking colors, see these tiddlers:

[[4096 Color wheel]]
[[Coloria color names]]

</pre>
</div>
<div title="Changing the look of a tiddler in editing mode - understanding the EditTemplate" modifier="giffmex" modified="200708232136" created="200708232127" changecount="9">
<pre>The EditTemplate controls the look of tiddlers when they are in editing mode. Below is the code for the EditTemplate for a standard ~TiddlyWiki. Each div class is an element of the tiddler that can be removed. Do you prefer the tag window above the text window in edit mode like I have in this tutorial? Just slide the line that says: 

&lt;!--{{{--&gt;
&lt;div class='editor' macro='edit tags'&gt;&lt;/div&gt;&lt;div class='editorFooter'&gt;&lt;span macro='message views.editor.tagPrompt'&gt;&lt;/span&gt;&lt;span macro='tagChooser'&gt;&lt;/span&gt;&lt;/div&gt;
&lt;!--}}}--&gt;

Above the line that says:
&lt;!--{{{--&gt;
&lt;div class='editor' macro='edit text'&gt;&lt;/div&gt;
&lt;!--}}}--&gt;

''Here is the full EditTemplate code:''
!The toolbar
&lt;div class='toolbar' macro='toolbar +saveTiddler -cancelTiddler deleteTiddler'&gt;&lt;/div&gt;
!The tiddler title
&lt;div class='title' macro='view title'&gt;&lt;/div&gt;
&lt;div class='editor' macro='edit title'&gt;&lt;/div&gt;
&lt;div macro='annotations'&gt;&lt;/div&gt;
!The text
&lt;div class='editor' macro='edit text'&gt;&lt;/div&gt;
!The tags
&lt;div class='editor' macro='edit tags'&gt;&lt;/div&gt;&lt;div class='editorFooter'&gt;&lt;span macro='message views.editor.tagPrompt'&gt;&lt;/span&gt;&lt;span macro='tagChooser'&gt;&lt;/span&gt;&lt;/div&gt;

</pre>
</div>
<div title="Changing the look of a tiddler in viewing mode - understanding the ViewTemplate" modifier="giffmex" created="200708232126" changecount="2">
<pre>The ViewTemplate controls the look of tiddlers when they are in viewing mode. Below is the code for the ViewTemplate. Each div class is an element of the tiddler that can be removed. Don't like seeing those pesky 'tagging' and 'tagged' boxes on your tiddlers? Neither do I. All my ~TWs have those boxes eliminated from the ViewTemplate. 

&lt;!--{{{--&gt;
&lt;div class='toolbar' macro='toolbar closeTiddler closeOthers +editTiddler &gt; fields syncing permalink references jump'&gt;&lt;/div&gt;
&lt;div class='title' macro='view title'&gt;&lt;/div&gt;
&lt;div class='subtitle'&gt;&lt;span macro='view modifier link'&gt;&lt;/span&gt;, &lt;span macro='view modified date'&gt;&lt;/span&gt; (&lt;span macro='message views.wikified.createdPrompt'&gt;&lt;/span&gt; &lt;span macro='view created date'&gt;&lt;/span&gt;)&lt;/div&gt;
&lt;div class='tagging' macro='tagging'&gt;&lt;/div&gt;
&lt;div class='tagged' macro='tags'&gt;&lt;/div&gt;
&lt;div class='viewer' macro='view text wikified'&gt;&lt;/div&gt;
&lt;div class='tagClear'&gt;&lt;/div&gt;
&lt;!--}}}--&gt;</pre>
</div>
<div title="Changing the look of the basic page layout - understanding the PageTemplate" modifier="giffmex" modified="200708232121" created="200708232108" changecount="5">
<pre>The PageTemplate controls the basic page layout of a ~TiddlyWiki. Below is the code for the PageTemplate and my annotations.

!The header
Here is where you can change the colors of the gradient in the header, or change what is included in the header, if you wish. 
&lt;!--{{{--&gt;
&lt;div class='header' macro='gradient vert [[ColorPalette::PrimaryLight]] [[ColorPalette::PrimaryMid]]'&gt;
&lt;div class='headerShadow'&gt;
&lt;span class='siteTitle' refresh='content' tiddler='SiteTitle'&gt;&lt;/span&gt;&amp;nbsp;
&lt;span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;div class='headerForeground'&gt;
&lt;span class='siteTitle' refresh='content' tiddler='SiteTitle'&gt;&lt;/span&gt;&amp;nbsp;
&lt;span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;!--}}}--&gt;
!The main menu of a typical ~TiddlyWiki
This is the part you can replace with a topmenu code if you prefer a topmenu like this tutorial has. See [[Top menus versus left hand main menus]] for details.
&lt;!--{{{--&gt;
&lt;div id='mainMenu' refresh='content' tiddler='MainMenu'&gt;&lt;/div&gt;
&lt;!--}}}--&gt;
!The right hand sidebar
If you wish, you can remove the topmost sidebar options, the advanced options, or the tabs from the right sidebar by deleting their div id's below.
&lt;!--{{{--&gt;
&lt;div id='sidebar'&gt;
&lt;div id='sidebarOptions' refresh='content' tiddler='SideBarOptions'&gt;&lt;/div&gt;
&lt;div id='sidebarTabs' refresh='content' force='true' tiddler='SideBarTabs'&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;!--}}}--&gt;
!The middle display area where the tiddlers appear
&lt;!--{{{--&gt;
&lt;div id='displayArea'&gt;
&lt;div id='messageArea'&gt;&lt;/div&gt;
&lt;div id='tiddlerDisplay'&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;!--}}}--&gt;

</pre>
</div>
<div title="Changing the page layout" modifier="giffmex" modified="200708232143" created="200708232100" changecount="7">
<pre>*[[Changing the look of the basic page layout - understanding the PageTemplate]]
*[[Changing the look of a tiddler in viewing mode - understanding the ViewTemplate]]
*[[Changing the look of a tiddler in editing mode - understanding the EditTemplate]]
*[[Top menus versus left hand main menus]]
*[[Toggle the right hand menu]]
*TiddlyThemes
</pre>
</div>
<div title="ColorPalette" modifier="tiddlyvault" modified="200710011519" created="200703021321" tags="palette" changecount="4">
<pre>Background: #eeeeff
Foreground: #000
PrimaryPale: #ddccff
PrimaryLight: #eeeeff
PrimaryMid: #330066
PrimaryDark: #000
SecondaryPale: #ffc
SecondaryLight: #fe8
SecondaryMid: #db4
SecondaryDark: #330066
TertiaryPale: #ddccff
TertiaryLight: #EEC591
TertiaryMid: #000
TertiaryDark: #8B7355</pre>
</div>
<div title="ColorPalette color designations" modifier="GiffMex" modified="200703071342" created="200701071420">
<pre>Here is a list of the color codes in the ColorPalette, and the sections of this ~TiddlyWiki that they affect. Please note that authors of other ~TiddlyWikis may have configured theirs differently in the StyleSheet. But experimenting with these will give you practice so that you can more easily reconfigure the colors of any ~TiddlyWiki.


''Background:'' This controls the color of the background or 'paper', and the text in the title and subtitle.

''Foreground:'' This controls the color of the text.

''~PrimaryPale:'' This controls the color of the Interface Options box.

''~PrimaryLight:'' This controls the color of the top of the Header gradient.

''~PrimaryMid:'' This controls the color of the text in the ~MainMenu, the color of the text for links, the color of the text in the lists of tiddlers and tags, and the color of the bottom of the Header gradient.

''~PrimaryDark:'' This controls the color of the text of the items in the top of the right hand menu and the text of the buttons on the tiddlers.

''~SecondaryPale:'' This controls the color of the background of the boxes in those tiddlers that show snippets of the ~TiddlyWiki code.

''~SecondaryLight:'' This controls the color that appears when the tiddler buttons or items in the right hand menu are highlighted.

''~SecondaryMid:'' This controls the color of the title cells in tables, that is, cells which begin with an exclamation mark (!). It also controls the color of the box that appears when changes have been saved, and the color of the tiddler buttons when they are selected.

''~SecondaryDark:'' This controls the color of the titles of the tiddlers.

''~TertiaryPale:'' This controls the color of the right hand menu that shows lists of tags and tiddlers, as well as the color of the tag button on the tiddlers.

''~TertiaryLight:'' This controls the color of the borders around the right hand menus.

''~TertiaryMid:'' This controls the color of the unselected tabs behind the list of tags and tiddlers in the bottom right hand menu.

''~TertiaryDark:'' This controls the color of the subtitle of each tiddler, that is, the author of the tiddler, the most recent date it was modified and date it was created.

</pre>
</div>
<div title="ColorSchemes" modifier="GiffMex" modified="200703071342" created="200612100530">
<pre>Open up any of the following Tiddlers and copy its contents. Then paste those contents into the ColorPalette Tiddler and click 'done.' The color scheme of ~TiddlyWiki will change to the color scheme you selected. To return to the original color scheme, replace the ~ColorPalette contents with the contents of the Lilac color scheme below.

[[Apples]] - @@new and improved Jan. 27@@
[[Blueberry]] - @@new and improved Jan. 27@@
[[Brown color scheme]] - (the original color scheme of this file)
[[Capuccino color scheme]]
[[Capuccino2 color scheme]]
[[Giffmex's dining room color scheme]]
[[greenishgray]] @@new march 2@@
[[Lilac]]
[[Mauve]] - @@new Jan. 27@@
[[Mocha]] - @@new Jan. 27@@
[[Purple and gold color scheme]]
[[Romanos color scheme]]
[[Slate 'Batman' color scheme]]
[[Strawberry color scheme]]

</pre>
</div>
<div title="Coloria color names" modifier="giffmex" modified="200708231923" created="200708231922" changecount="2">
<pre>Source: http://www.coloria.net/bonus/colornames.htm.
&lt;html&gt;&lt;iframe src=&quot;http://www.coloria.net/bonus/colornames.htm&quot; width=100% height=600&gt;&lt;/iframe&gt;&lt;/html&gt;</pre>
</div>
<div title="Colors, images, gradients, stylesheets and other visuals" modifier="giffmex" modified="200708260053" created="200708232051" changecount="7">
<pre>*[[Changing the colors of a TiddlyWiki]]
*[[The SelectPaletteMacro]]
*[[Messing with StyleSheets]]
*[[How to create gradients]]
*[[How to add background images]]
*[[TiddlyThemes]]</pre>
</div>
<div title="Create forms with editable fields" modifier="GiffMex" modified="200703071354" created="200703051727">
<pre>I'm not going to show you how to do this. You will need to download the ~FormTiddlerPlugin and the ~DataTiddlerPlugin from Abego Extensions and consult the documentation for specific instructions. But if you would like to see a form in action, check out my ~NewBookTemplate in ~BibblyWiki, a ~TiddlyWiki I created to manage bibliographies, take book notes and organize personal libraries.

The template is [[here|http://www.giffmex.org/bibblywiki.html#NewBookTemplate]]:
A tiddler based on the template is [[here|http://www.giffmex.org/bibblywiki.html#%5B%5BWright%2C%20N.T.%2C%20Jesus%20and%20the%20Victory%20of%20God%5D%5D]]. 

I recommend you doubleclick them both to see what they look like in edit mode.

''To create a button'' which creates a new tiddler based on the template, here is the macro syntax:

{{{&lt;&lt;newTiddler label:&quot;XXXX&quot; text:{{&quot;&lt;&lt;formTiddler ZZZZ\&gt;\&gt;&quot;}} tag:&quot;OOOO&quot;&gt;&gt;}}}

Replace XXXX with the name for your macro label. (ex: &quot;Add a new book&quot;)
Replace ZZZZ with the name of the template tiddler. (ex: ~NewBookTemplate)
Replace OOOO with any tag you would like to have appended to every tiddler created by this macro (ex: &quot;booknote&quot;)

You can place your new macro in SideBarOptions or in a tiddler accessible from the ~MainMenu.

</pre>
</div>
<div title="Credits" modifier="giffmex" modified="200708231755" created="200612030318" changecount="5">
<pre>''~TiddlyWiki'' is © 2006 [[osmosoft|http://www.osmosoft.com]]. ~TiddlyWiki is a free program created under an Open Source License by Jeremy Ruston. (see at http://tiddlywiki.com). 

''~TiddlyWiki for the rest of us'' is an instruction manual written by DaveGifford (his website is http://www.giffmex.org) and he can be contacted at //giff (at) giffmex (dot) org//
</pre>
</div>
<div title="DaveGifford" modifier="GiffMex" modified="200703071343" created="200701181321">
<pre>I am a missionary with the Christian Reformed Church in Mexico City. I created this tutorial in English and Spanish because I think ~TiddlyWiki is a great tool, but knew my friends wouldn't buy into it unless there was a simpler way to learn it. But it has suddenly become a fairly popular site for others as well.

If you have questions about ~TiddlyWiki, you will be better served by the ~TiddlyWiki group at Google [[link here|http://groups-beta.google.com/group/TiddlyWiki]] than by contacting me. If you want to know more about me, visit my website [[link here|http://www.giffmex.org/bloghome.html]], which has personal info, articles, links to our photos on Flickr, links to my other ~TiddlyWiki resources, links to my Spanish resources, etc.

If you absolutely ''must'' contact me, my e-mail is contacto (at) giffmex (dot) org. Please, no spam. My thoughts on spam can be found [[here|http://www.giffmex.org/gniknow.html]].

</pre>
</div>
<div title="Decide on saving options" modifier="giffmex" modified="200708231906" created="200701271212" changecount="1">
<pre>In the right-hand Interface options panel, there are several options with check boxes beside them, and two of them are {{{SaveBackups}}} and {{{AutoSave}}}. When {{{SaveBackups}}} is checked, ~TiddlyWiki automatically makes an entire backup copy of itself in the folder where it is located or in a folder designated by you in AdvancedOptions whenever changes are saved.  When {{{AutoSave}}} is checked, ~TiddlyWiki saves changes immediately after they are made.

Below is a chart on the pros and cons of checking and unchecking these items.

|! ''SaveBackups'' |! ''AutoSave'' |! Description |!  ''Use these options together...'' |
|vertical-align:top;[X]&lt;&lt;br&gt;&gt;(checked)|vertical-align:top;[X]&lt;&lt;br&gt;&gt;(checked)|vertical-align:top;~TiddlyWiki saves every change immediately to the current file, and also creates an entire backup copy of itself with every change.&lt;&lt;br&gt;&gt;&lt;&lt;br&gt;&gt;If you make a mistake, just go to the backup of the previously saved version and rename it to the original file's name. |vertical-align:top;...if you really need a backup copy for every change you make, as a safety net so that you don't lose valuable information because of mistakes.&lt;&lt;br&gt;&gt;&lt;&lt;br&gt;&gt;...if you don't want to hit &quot;save changes&quot; yourself but you need to save your data at every step.&lt;&lt;br&gt;&gt;&lt;&lt;br&gt;&gt;...if you don't mind the delay in automatic saves and backups as your file gets larger.&lt;&lt;br&gt;&gt;&lt;&lt;br&gt;&gt;...if you are willing to manually delete all those backup files (they add up fast!)&lt;&lt;br&gt;&gt;&lt;&lt;br&gt;&gt;|
|bgcolor(#eeeeee):vertical-align:top;[_]&lt;&lt;br&gt;&gt;(unchecked)|bgcolor(#eeeeee):vertical-align:top;[_]&lt;&lt;br&gt;&gt;(unchecked)|bgcolor(#eeeeee):vertical-align:top;~TiddlyWiki saves nothing until you click &quot;save changes&quot; in the right-hand sidebar. Changes are saved to the current file. |bgcolor(#eeeeee):vertical-align:top;...if you don't need the safety net of backup copies in case of mistakes, and would prefer changes to be saved to the current file.&lt;&lt;br&gt;&gt;&lt;&lt;br&gt;&gt;...if you prefer to save changes manually at regular intervals rather than wait while ~TiddlyWiki saves your changes for you.&lt;&lt;br&gt;&gt;&lt;&lt;br&gt;&gt;...if you don't have the hard drive space for multiple backup copes or don't like deleting them.&lt;&lt;br&gt;&gt;&lt;&lt;br&gt;&gt;...if you are confident that your computer won't crash between your manual saves.&lt;&lt;br&gt;&gt;&lt;&lt;br&gt;&gt;|
|vertical-align:top;[X]&lt;&lt;br&gt;&gt;(checked)|vertical-align:top;[_]&lt;&lt;br&gt;&gt;(unchecked)|vertical-align:top;~TiddlyWiki saves an entire backup copy of itself, but only when you save changes manually.|vertical-align:top;...if you want the safety net of backup copies in case of mistakes, but you don't want one for every single change you make. &lt;&lt;br&gt;&gt;&lt;&lt;br&gt;&gt;...if you prefer to save changes manually at regular intervals rather than have ~TiddlyWiki save changes at every step.&lt;&lt;br&gt;&gt;&lt;&lt;br&gt;&gt;...if you are willing to manually delete backup files later.&lt;&lt;br&gt;&gt;&lt;&lt;br&gt;&gt;...if you are confident that your computer won't crash between your manual saves.&lt;&lt;br&gt;&gt;&lt;&lt;br&gt;&gt;|
|vertical-align:top;bgcolor(#eeeeee):[_]&lt;&lt;br&gt;&gt;(unchecked)|bgcolor(#eeeeee):vertical-align:top;[X]&lt;&lt;br&gt;&gt;(checked)|bgcolor(#eeeeee):vertical-align:top;~TiddlyWiki saves every change immediately to the current file, but does not create a backup copy of itself.|bgcolor(#eeeeee):vertical-align:top;...if you prefer changes to be saved to the current file rather than have the safety net of backup copies.&lt;&lt;br&gt;&gt;&lt;&lt;br&gt;&gt;...if you prefer ~TiddlyWiki to save your changes automatically rather than have to hit 'save changes' every now and then.&lt;&lt;br&gt;&gt;&lt;&lt;br&gt;&gt;...if you don't have the hard drive space for multiple backup copes or don't like deleting them.&lt;&lt;br&gt;&gt;&lt;&lt;br&gt;&gt;...if you don't mind waiting for ~TiddlyWiki to save every change, because you want to make sure your changes are saved at every step.&lt;&lt;br&gt;&gt;&lt;&lt;br&gt;&gt;...if you are confident that you won't irretrievably lose valuable information by making a mistake.&lt;&lt;br&gt;&gt;&lt;&lt;br&gt;&gt;|

</pre>
</div>
<div title="DefaultTiddlers" modifier="YourName" modified="200701121528" created="200612030310">
<pre>[[How do you use a TiddlyWiki?]]</pre>
</div>
<div title="E.A.S.E" modifier="YannPerrin" modified="200702072052" created="200701131437" tags="systemConfig E.A.S.E Framework ForBlogUse Plugins">
<pre>/***
|!''Name:''|!''E''asily ''A''daptable ''S''ource ''E''ditor|
|''Description:''|this framework allows you to easily create commands that work on the current tiddler text selection in edit mode|
|''Version:''|0.1.0|
|''Date:''|13/01/2007|
|''Source:''|http://yann.perrin.googlepages.com/twkd.html#E.A.S.E|
|''Author:''|[[Yann Perrin|YannPerrin]]|
|''License:''|[[BSD open source license]]|
|''~CoreVersion:''|2.x|
|''Browser:''|Firefox 1.0.4+; Firefox 1.5; InternetExplorer 6.0|
***/
////Messages Definition
//{{{
config.messages.Ease = {
noselection:&quot;nothing selected&quot;,
asktitle:&quot;enter the new tiddler title&quot;,
exists:&quot; already exists, please enter another title&quot;,
askForTagsLabel:&quot;enter the new tiddler tags&quot;,
tiddlercreated:&quot; tiddler created&quot;
}
//}}}
////
//{{{
if (!window.TWkd) window.TWkd={context:{}};
if (!TWkd.Ease)
 TWkd.Ease = function (text,tooltip){
 this.text = text;
 this.tooltip = tooltip;
 this.modes = [];
 this.addMode = function(modeDefinition) {this.modes.push(modeDefinition);};
 this.handler = function(event,src,title) {
 TWkd.context.command = this;
 TWkd.context.selection=this.getSelection(title);
 if (this.modes.length==1) {
 this.modes[0].operation();
 }
 else {
 var popup = Popup.create(src);
 if(popup) {
 for (var i=0; i&lt;this.modes.length; i++) {
 createTiddlyButton(createTiddlyElement(popup,&quot;li&quot;), this.modes[i].name, this.modes[i].tooltip, this.OperateFromButton, null, 'id'+i, null);
 }
 Popup.show(popup,false);
 event.cancelBubble = true;
 if (event.stopPropagation) event.stopPropagation();
 return false;
 }
 }
 };
 };

TWkd.Ease.prototype.OperateFromButton = function(e){
 var commandMode=this.getAttribute('Id').replace('id','');
 TWkd.context.command.modes[commandMode].operation();
};

TWkd.Ease.prototype.getTiddlerEditField = function(title,field){
 var tiddler = document.getElementById(story.idPrefix + title);
 if(tiddler != null){
 var children = tiddler.getElementsByTagName(&quot;*&quot;)
 var e = null;
 for (var t=0; t&lt;children.length; t++){
 var c = children[t];
 if(c.tagName.toLowerCase() == &quot;input&quot; || c.tagName.toLowerCase() == &quot;textarea&quot;){
 if(!e) {e = c;}
 if(c.getAttribute(&quot;edit&quot;) == field){e = c;}
 }
 }
 if(e){return e;}
 }
} // closes getTiddlerEditField function definition
 
TWkd.Ease.prototype.getSelection = function(title,quiet) {
 var tiddlerTextArea = this.getTiddlerEditField(title,&quot;text&quot;);
 var result = {};
 if (document.selection != null &amp;&amp; tiddlerTextArea.selectionStart == null) {
 tiddlerTextArea.focus();
 var range = document.selection.createRange();
 var bookmark = range.getBookmark();
 var contents = tiddlerTextArea.value;
 var originalContents = contents;
 var marker = &quot;##SELECTION_MARKER_&quot; + Math.random() + &quot;##&quot;;
 while(contents.indexOf(marker) != -1) {
 marker = &quot;##SELECTION_MARKER_&quot; + Math.random() + &quot;##&quot;;
 }
 var selection = range.text;
 range.text = marker + range.text + marker;
 contents = tiddlerTextArea.value;
 result.start = contents.indexOf(marker);
 contents = contents.replace(marker, &quot;&quot;);
 result.end = contents.indexOf(marker);
 tiddlerTextArea.value = originalContents;
 range.moveToBookmark(bookmark);
 range.select();
 }
 else {
 result.start=tiddlerTextArea.selectionStart;
 result.end=tiddlerTextArea.selectionEnd;
 }
 result.content=tiddlerTextArea.value.substring(result.start,result.end);
 result.source=title;
 if (!result.content&amp;&amp;!quiet) displayMessage(config.messages.Ease.noselection);
 return(result);
}//closes getSelection function definition

// replace selection or insert new content
TWkd.Ease.prototype.putInPlace=function(content,workplace) {
 var tiddlerText = this.getTiddlerEditField(workplace.source,&quot;text&quot;);
 tiddlerText.value = tiddlerText.value.substring(0,workplace.start)+content+tiddlerText.value.substring(workplace.end);
}

// asking for title
TWkd.Ease.prototype.askForTitle = function(suggestion) {
 if (!suggestion)
 suggestion = &quot;&quot;;
 var newtitle;
 while (!newtitle||store.tiddlerExists(newtitle))
 {
 if (store.tiddlerExists(newtitle))
 displayMessage(newtitle+config.messages.Ease.exists);
 newtitle = prompt(config.messages.Ease.asktitle,suggestion);
 if (newtitle==null)
 {
 displayMessage(config.messages.Ease.titlecancel);
 return(false);
 }
 }
 return(newtitle);
}//closes askForTitle function definition

// creation of a new tiddler
TWkd.Ease.prototype.newTWkdLibTiddler = function(title,content,from,askForTags){
 var tiddler = new Tiddler();
 tiddler.title = title;
 tiddler.modifier = config.options.txtUserName;
 tiddler.text = content;
 (from) ? tiddler.tags = [from] : tiddler.tags=[];
 if (askForTags)
 tiddler.tags = prompt(config.messages.Ease.askForTagsLabel,'[['+from+']]').readBracketedList();
 store.addTiddler(tiddler);
 //store.notifyAll();
 displayMessage(title+config.messages.Ease.tiddlercreated);
}

if (!TWkd.Mode)
 TWkd.Mode = function (name,tooltip,ask,operation) {
 this.name = name;
 this.tooltip = tooltip;
 this.ask = ask;
 this.operation = operation;
 };
//}}}</pre>
</div>
<div title="EditTemplate" modifier="YannPerrin" modified="200701281908" created="200610181335" tags="html Template">
<pre>&lt;div class=&quot;toolbar&quot; macro=&quot;toolbar +saveTiddler closeOthers -cancelTiddler deleteTiddler&quot;&gt;&lt;/div&gt;
&lt;div class=&quot;title&quot; macro=&quot;view title&quot;&gt;&lt;/div&gt;
&lt;div class=&quot;editLabel&quot;&gt;Title&lt;/div&gt;&lt;div class=&quot;editor&quot; macro=&quot;edit title&quot;&gt;&lt;/div&gt;
&lt;div class=&quot;editLabel&quot;&gt;Tags&lt;/div&gt;&lt;div class=&quot;editor&quot; macro=&quot;edit tags&quot;&gt;&lt;/div&gt;
&lt;div class=&quot;editorFooter&quot;&gt;&lt;span macro=&quot;message views.editor.tagPrompt&quot;&gt;&lt;/span&gt;&lt;span macro=&quot;tagChooser&quot;&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div macro='hideWhen ((tiddler.tags.contains(&quot;Contacts&quot;))||(tiddler.title==&quot;New Contact&quot;))'&gt;[[EditToolbar]]&lt;div class='editor' macro='edit text'&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div macro='showWhen ((tiddler.tags.contains(&quot;Contacts&quot;))||(tiddler.title==&quot;New Contact&quot;))'&gt;&lt;div class='editor'&gt;
&lt;table width='100%'&gt;
&lt;tr&gt;&lt;th&gt;Name&lt;/th&gt;&lt;td&gt;&lt;span macro='edit ContactFirstName'&gt;&lt;/span&gt;&lt;span macro='edit ContactLastName'&gt;&lt;/span&gt;&lt;/td&gt;&lt;td rowspan='4' width='50%' macro='edit text'&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;Adress&lt;/th&gt;&lt;td&gt;&lt;span macro='edit ContactStreetNumber'&gt;&lt;/span&gt;&lt;span macro='edit ContactStreetName'&gt;&lt;/span&gt;&lt;span macro='edit ContactZipCode'&gt;&lt;/span&gt;&lt;span macro='edit ContactCity'&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;Phone&lt;/th&gt;&lt;td&gt;&lt;span macro='edit ContactPhone'&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;Email&lt;/th&gt;&lt;td&gt;&lt;span macro='edit ContactMail'&gt;&lt;span&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
</pre>
</div>
<div title="EditToolbar" modifier="churu1" modified="200705261321" created="200701281908" tags="Template">
<pre>&lt;div macro='toolbar format slice tongue'&gt;&lt;/div&gt;</pre>
</div>
<div title="For advanced users: Customize your TW experience" modifier="giffmex" modified="200709011829" created="200612031417" changecount="38">
<pre>{{invisibletable{
|width:25em; Okay, so you know how to use ~TiddlyWiki, but now you want more. You want to change the color or layout. You want to add features to it. As the subtitle says, this is an entry-level introduction, so I am not going to show you how to do every possible thing you can do with ~TiddlyWiki. I probably don't know half of what can be done. Advanced documentation such as that found at http://www.tiddlywiki.org/wiki and http://tiddlyspot.com/twhelp/ can hopefully expand your horizons. What I will tell you is that there is a LOT more you can do with ~TiddlyWiki if you are interested and determined enough.|Here are a few ideas to get you started.&lt;br&gt;&lt;br&gt;[[Advanced ideas for tags]]&lt;br&gt;&lt;br&gt;[[More information on tables]]&lt;br&gt;&lt;br&gt;[[Colors, images, gradients, stylesheets and other visuals]]&lt;br&gt;&lt;br&gt;[[Changing the page layout]]&lt;br&gt;&lt;br&gt;[[More with macros]]&lt;br&gt;&lt;br&gt;[[A plug for Plugins]]&lt;br&gt;&lt;br&gt;[[TiddlyVault collection of plugins and macros|TiddlyVault: your source for macros, plugins and themes]]&lt;br&gt;&lt;br&gt;[[How to create new tiddlers based on a template tiddler]]&lt;br&gt;&lt;br&gt;[[Create forms with editable fields]]&lt;br&gt;&lt;br&gt;[[Access files, folders, etc from within TiddlyWiki]]&lt;br&gt;&lt;br&gt;[[TiddlySnip Firefox addon]]|
}}}

I want to thank all the fine people at the Google group for ~TiddlyWiki. If it weren't for them, I wouldn't ever have been able to do these things, let alone explain them to you. It's rare to find such a helpful group of people available every day with same day answers. They are another reason ~TiddlyWiki is so great.

</pre>
</div>
<div title="For beginners: reading TiddlyWikis on the Internet" modifier="GiffMex" modified="200703071346" created="200612031309" tags="beginners reading">
<pre>Reading ~TiddlyWikis is easy, but takes some getting used to. Rather than scrolling up and down a long web page or word processing document, you open small chunks of information (&quot;microcontent&quot;) written in boxes called &quot;tiddlers.&quot; You read what you need from a tiddler, then close it with the ''close'' button at the top right hand corner of the tiddler.

Tiddlers are linked to each other in different ways: 
*[[through a MainMenu]]
*[[through hyperlinks]]
*[[through tags]]
When a tiddler is opened up, it appears at the top of the screen or below the tiddler used to link to it. After opening a few tiddlers in succession, you might feel overwhelmed by all the open tiddlers. Not to worry. 
*You can close every tiddler but the one you are using by clicking on the ''close others'' button.
*If you have multiple tiddlers open, you can use the ''jump'' button to quickly go to the open tiddler you desire without having to scroll up and down.
*See [[here|Anatomy of a Tiddler]] for information on the other buttons at the top right of the tiddler.
To ''search for a tiddler'', you can use the search window at the top right of the screen. All the tiddlers that contain the word that you search for will appear. Or, you can look for the relevant tiddler in the tabbed menu at the bottom of the right hand menu. See [[here|The right hand menu]] for more information on the right hand menu.

</pre>
</div>
<div title="For medium users: adding your own material to a TiddlyWiki file" modifier="giffmex" modified="200708232200" created="200612031348" changecount="16">
<pre>If your ~TiddlyWiki file is saved correctly to your computer, you can add your own notes, create your own tiddlers, add tags to tiddlers and even save the file with a new name to create your own ~TiddlyWiki file.

|bgcolor(#dddddd):''Edit existing tiddlers''|You can ''edit an existing tiddler'' either by double-clicking on it or by clicking the hidden 'edit' button at the top right of the tiddler. The tiddler will then go into 'edit' mode, and you type whatever you want to type into it. Click the hidden 'done' button in the upper right corner ''to finish your changes'' and go back to 'reading' mode.|
|bgcolor(#dddddd):''Create new tiddlers''|You can ''create a new tiddler'' in various ways.&lt;br&gt;*Click on the 'New tiddler' or 'New journal' options in the right hand menu.&lt;br&gt;*Create a WikiWord within an existing tiddler and click on it when you go back to reading mode.&lt;br&gt;*Write a word or phrase enclosed by double brackets {{{[[this is an example]]}}} and click on it when you go back to reading mode.&lt;br&gt;&lt;br&gt;I recommend that you be as specific as possible in naming tiddlers. There cannot be two tiddlers with the same name.|
|bgcolor(#dddddd):''Format text''|To see how to format a special way (for example, how to do boldfaced type), just go into edit mode and view the code for the formatting. A list of most of the [[Special formatting]].&lt;br&gt;&lt;br&gt;I added Yann Perrin's [[easyFormat]] plugin to make some formatting easier. Go into edit mode, select some text, and click on &quot;Format&quot; to see a dropdown list of formats that will automatically be applied when you select them.|
|bgcolor(#dddddd):''Add tags''|When a tiddler is in edit mode you can add ''tags'' to the narrow window at the bottom of the tiddler. [[Advanced ideas for tags]]|
|bgcolor(#dddddd):''Edit the main menu''|I use the main menu as the table of contents for my files. To edit the main menu, click on the word MainMenu, and double-click on its tiddler. Add and remove items as you wish.|
</pre>
</div>
<div title="Force the text in a cell not to wrap to the next line at a space" modifier="giffmex" modified="200708250033" created="200708250024" changecount="15">
<pre>Tables with one narrow column and one long column often force line breaks in the narrow column where words are separated by a space, as in this example:

|narrow column|narrow column|very wide column very wide column very wide column very wide column very wide column very wide column very wide column very wide column very wide column very wide column very wide column |

To force those narrow cells onto one line, add the following code at the beginning of the cells:

{{{
@@white-space: nowrap;YOUR-TEXT-HERE@@
}}}

Here is the result:

|@@white-space: nowrap;narrow column@@|@@white-space: nowrap;narrow column@@|very wide column very wide column very wide column very wide column very wide column very wide column very wide column very wide column very wide column very wide column very wide column |
</pre>
</div>
<div title="Format ASCII symbols, foreign symbols, math symbols" modifier="giffmex" created="200708232030" changecount="1">
<pre>Morris Gray has very nice lists of how to do ASCII symbols, Greek and Latin symbols, HTML entities and Math symbols at his wonderful TW Help site. To see these lists at his site, [[click here|http://twhelp.tiddlyspot.com/#Entities-Codes]].</pre>
</div>
<div title="Format blockquotes" modifier="giffmex" created="200708232002" changecount="1">
<pre>''Line-by-line blockquotes:''
{{{&gt;level 1}}}
{{{&gt;level 1}}}
{{{&gt;&gt;level 2}}}
{{{&gt;&gt;level 2}}}
{{{&gt;&gt;&gt;level 3}}}
{{{&gt;&gt;&gt;level 3}}}
{{{&gt;&gt;level 2}}}
{{{&gt;level 1}}}

produces:
&gt;level 1
&gt;level 1
&gt;&gt;level 2
&gt;&gt;level 2
&gt;&gt;&gt;level 3
&gt;&gt;&gt;level 3
&gt;&gt;level 2
&gt;level 1

''Extended blockquotes:''
{{{&lt;&lt;&lt;}}}
{{{Extended blockquotesExtended blockquotesExtended blockquotesExtended blockquotesExtended blockquotesExtended blockquotesExtended blockquotesExtended blockquotesExtended blockquotesExtended blockquotesExtended blockquotesExtended blockquotesExtended blockquotesExtended blockquotesExtended blockquotesExtended blockquotesExtended blockquotesExtended blockquotes}}}
{{{&lt;&lt;&lt;}}} 

produces:
&lt;&lt;&lt;
Extended blockquotesExtended blockquotesExtended blockquotesExtended blockquotesExtended blockquotesExtended blockquotesExtended blockquotesExtended blockquotesExtended blockquotesExtended blockquotesExtended blockquotesExtended blockquotesExtended blockquotesExtended blockquotesExtended blockquotesExtended blockquotesExtended blockquotesExtended blockquotes
&lt;&lt;&lt;

</pre>
</div>
<div title="Format links and images" modifier="giffmex" modified="200708232003" created="200708231959" changecount="4">
<pre>|bgcolor(#dddddd):Links with wikiwords|EnchiLada (inactive link - no tiddler yet)&lt;br&gt;WikiWord (active link to tiddler)|{{{EnchiLada}}}&lt;br&gt;{{{WikiWord}}}|
|bgcolor(#dddddd):~De-Wikify a ~WikiWord|~WikiWord, ~EnchiLada|{{{~WikiWord, ~EnchiLada}}}|
|bgcolor(#dddddd):Links with brackets|[[How to add background images]]|{{{[[How to add background images]]}}}|
|bgcolor(#dddddd):Pretty links|[[display text|ColorSchemes]] - links to the tiddler of color schemes|{{{[[display text|ColorSchemes]]}}}|
|bgcolor(#dddddd):External links work the same way:|http://groups.google.com/group/TiddlyWiki &lt;br&gt;&lt;br&gt;[[TiddlyWiki Google group|http://groups.google.com/group/TiddlyWiki]]|{{{http://groups.google.com/group/TiddlyWiki}}} &lt;br&gt;&lt;br&gt; {{{[[TiddlyWiki Google group|http://groups.google.com/group/TiddlyWiki]]}}}|
|bgcolor(#dddddd):Links to local files|To a file on a CD in your D drive: &lt;br&gt;&lt;br&gt;To a file on your USB stick on your e drive: &lt;br&gt;&lt;br&gt;To a file in your hard drive:|{{{file:///D:/filename.doc/}}}&lt;br&gt;&lt;br&gt;{{{file:///E:/filename.doc/}}}&lt;br&gt;&lt;br&gt;{{{file:///C:/filepath/filename.doc/}}}|

''Images:''
{{{[img[http://farm1.static.flickr.com/39/122259544_6913ca58f3_m.jpg]]}}} is the formatting for:

[img[http://farm1.static.flickr.com/39/122259544_6913ca58f3_m.jpg]]
</pre>
</div>
<div title="Format lists" modifier="giffmex" modified="200708232000" created="200708231959" changecount="2">
<pre>''Numbered lists:''
{{{#item one }}}
{{{##Item 1a}}}
{{{###Item 1ai}}} 

produces:
#item one   
##Item 1a 
###Item 1ai 
''Bulleted lists:''
{{{*Bullet one}}}
{{{**Bullet two}}}
{{{***Bullet three}}}
 
produces:
*Bullet one    
**Bullet two    
***Bullet level three    
</pre>
</div>
<div title="Format tables" modifier="giffmex" modified="200708250017" created="200708232001" changecount="3">
<pre>!This is the formatting:

{{{|!Table header|!Column Two|}}}
{{{|&gt;| colspan |}}}
{{{| rowspan |left aligned|}}}
{{{|~| right aligned|}}}
{{{|bgcolor(#DC1A1A):colored| centered |}}}
{{{||*lists&lt;br&gt;*within&lt;br&gt;*tables&lt;br&gt;&lt;br&gt;and double-spaced too|}}}
{{{|caption|c}}}

!This is the result:

|!Table header|!Column Two|
|&gt;| colspan |
| rowspan |left aligned|
|~| right aligned|
|bgcolor(#DC1A1A):colored| centered |
||*lists&lt;br&gt;*within&lt;br&gt;*tables&lt;br&gt;&lt;br&gt;and double-spaced too|
|caption|c

[[More information on tables]]</pre>
</div>
<div title="Format text" modifier="giffmex" modified="200708242338" created="200703051332" changecount="22">
<pre>!Format text
|!Format|!It will look like this...|!...if you format it like this...|
|Bold-faced type|''text''|{{{''text''}}}|
|Italic text|//text//|{{{//text//}}}|
|Underlined text|__text__|{{{__text__}}}|
|Strike-through text|--text--|{{{--text--}}}|
|Colored text|@@color(green):green colored@@|{{{@@color(green):green colored@@}}}|
|Text with colored background|@@bgcolor(#ff0000):color(#ffffff):red colored@@|{{{@@bgcolor(#ff0000):color(#ffffff):red colored@@}}}|
|Highlighting|@@text@@|{{{@@text@@}}}|
|Superscript|2^^3^^=8|{{{2^^3^^=8}}}|
|Subscript|a~~ij~~ = -a~~ji~~|{{{a~~ij~~ = -a~~ji~~}}}|

!Make the first letter of a paragraph extra large
(from Morris Gray's TW Help)

''Sample'':

{{firstletter{
 @@color:#bbbbbb;O@@}}}kay, so you know how to use ~TiddlyWiki, but now you want more. You want to change the color or layout. You want to add features to it. As the subtitle says, this is an entry-level introduction, so I am not going to show you how to do every possible thing you can do with ~TiddlyWiki. I probably don't know half of what can be done. Advanced documentation such as that found at http://www.tiddlywiki.org/wiki and http://tiddlyspot.com/twhelp/ can hopefully expand your horizons. 

''How to do it:''

1. Add the following code to your StyleSheet:

 {{{
.firstletter{ float:left; width:0.75em; font-size:400%; font-family:times,arial; line-height:60%; }
}}}

2. Add the following code to your tiddler at the place where your enlarged letter would go (replacing &quot;O&quot; with the appropriate letter):
{{{
{{firstletter{
 @@color:#c06;O@@
 }}}
}}}</pre>
</div>
<div title="Giffmex's dining room color scheme" modifier="GiffMex" modified="200701181435" created="200612100531">
<pre>&lt;html&gt;&lt;a href=&quot;http://www.flickr.com/photos/giffmex/104273681/&quot; title=&quot;Photo Sharing&quot;&gt;&lt;img src=&quot;http://farm1.static.flickr.com/38/104273681_fa9947a962_m.jpg&quot; width=&quot;240&quot; height=&quot;160&quot; alt=&quot;100_1474b&quot; /&gt;&lt;/a&gt;&lt;/html&gt;

Background: #ffee55
Foreground: #000
PrimaryPale: #ffbb33
PrimaryLight: #88bbff
PrimaryMid: #0066cc
PrimaryDark: #000
SecondaryPale: #ffc
SecondaryLight: #ff9933
SecondaryMid: #db4
SecondaryDark: #cc3300
TertiaryPale: #ffbb33
TertiaryLight: #EEC591
TertiaryMid: #440044
TertiaryDark: #000
</pre>
</div>
<div title="HideWhenPlugin" modifier="YannPerrin" modified="200701311908" created="200610180258" tags="systemConfig MonkeyPirateTW">
<pre>/***
| Name:|HideWhenPlugin|
| Description:|Allows conditional inclusion/exclusion in templates|
| Version:|6.9.3|
| Date:|30-Sep-2006|
| Source:|http://mptw.tiddlyspot.com/#HideWhenPlugin|
| Author:|Simon Baird &lt;simon.baird@gmail.com&gt;|
For use in ViewTemplate and EditTemplate. Eg
{{{&lt;div macro=&quot;showWhen tiddler.tags.contains('Task')&quot;&gt;[[TaskToolbar]]&lt;/div&gt;}}}
{{{&lt;div macro=&quot;showWhen tiddler.modifier == 'BartSimpson'&quot;&gt;&lt;img src=&quot;bart.gif&quot;/&gt;&lt;/div&gt;}}}
***/
//{{{
merge(config.macros,{

 hideWhen: { handler: function (place,macroName,params,wikifier,paramString,tiddler) {
 if (eval(paramString)) {
 removeChildren(place);
 place.parentNode.removeChild(place);
 }
 }},

 showWhen: { handler: function (place,macroName,params,wikifier,paramString,tiddler) {
 config.macros.hideWhen.handler(place,macroName,params,wikifier,'!('+paramString+')',tiddler);
 }}

});

//}}}

</pre>
</div>
<div title="Host your TiddlyWiki online" modifier="giffmex" modified="200803101355" created="200708232149" changecount="21">
<pre>TiddlyWiki was designed to be a &quot;client-side&quot; wiki - a wiki that you can use while offline, as opposed to an online &quot;server-side&quot; wiki such as Wikipedia. Nevertheless, you may wish to have your TW online, as a blog, or maybe to have it handy to edit from other locations. If so, there are several ways to host your ~TiddlyWiki online.

''If you need free hosting'', check out the following sites:
*''Tiddlyspot'' at http://tiddlyspot.com. They even have several flavors of ~TWs to choose from.
*''~ServerSideWiki'' at http://serversidewiki.com.

''If you have your own website,'' here is the best option I know of:
*~BidiXTW's ''~UploadPlugin'' at http://tiddlywiki.bidix.info/ - [[Simple instructions for BidiX's UploadPlugin]]

You'll have to know what you're doing for the options below. The documentation isn't straightforward for beginners.
*''ccTiddly'' at http://cctiddly.sourceforge.net
*''~MiniTiddlerServer'' at http://www.minitiddlyserver.com
*''~PrinceTiddlyWiki'' at http://ptw.sourceforge.net
*''~PHPTiddlyWiki'' at http://www.patrickcurry.com/tiddly

</pre>
</div>
<div title="How do I remove the left-hand menu of a typical TiddlyWiki and create a top menu for it?" modifier="GiffMex" modified="200703071353" created="200702221523">
<pre>Let's say you're using a more typical ~TiddlyWiki file, one that has a left-hand ~MainMenu, and you want to have a top menu just like this tutorial does. (You make me blush with pride). Here's how:

!Step one: Add the horizontal menu code to your StyleSheet
There are many style tweaks you could give to your top menu. The following code is from the Monkey Pirate ~TiddlyWiki theme by Simon Baird. Add this code to your StyleSheet tiddler:
/*{{{*/

/* horizontal main menu */

#displayArea { margin: 1em 15.5em 0em 1em; } /* use the full horizontal width */

#topMenu { background: [[ColorPalette::PrimaryMid]]; color: [[ColorPalette::PrimaryPale]]; padding: 0.2em 0.2em 0.2em 0.5em; border-bottom: 2px solid #000000; }

#topMenu br { display: none; }

#topMenu .button, #topMenu .tiddlyLink, #topMenu a { margin-left: 0.25em; margin-right: 0.25em; padding-left: 0.5em; padding-right: 0.5em; color: [[ColorPalette::PrimaryPale]]; font-size: 1.15em; }

#topMenu .button:hover, #topMenu .tiddlyLink:hover { background: [[ColorPalette::PrimaryDark]]; }

/*}}}*/

!Step two: add the horizontal menu rule to the PageTemplate
In PageTemplate, right above this code for your regular MainMenu:

&lt;!--{{{--&gt;
&lt;div id='mainMenu' refresh='content' tiddler='MainMenu'&gt;&lt;/div&gt;
&lt;!--}}}--&gt;

Add the following three lines:

&lt;!--{{{--&gt;
&lt;!-- horizontal MainMenu --&gt;
&lt;div id='topMenu' refresh='content' tiddler='MainMenu'&gt;&lt;/div&gt;
&lt;!--original MainMenu menu--&gt;
&lt;!--}}}--&gt;

(The first of the three lines above is the name for the topmenu code. The second is the actual topmenu code. The third is the name for the original mainmenu code, and it should now be right above the original code.

</pre>
</div>
<div title="How do I remove the top menu and have a normal left-hand menu?" modifier="GiffMex" modified="200703071348" created="200702221455">
<pre>Let's say you're working with a file based on this tutorial or some other ~TiddlyWiki that has a top menu. You will need to do three things to get rid of that top menu and make the left-hand menu visible.

!Step one: remove the top menu lines from the PageTemplate.
Open PageTemplate and delete the following two lines:

&lt;!--{{{--&gt;
&lt;!-- horizontal MainMenu --&gt;
&lt;div id='topMenu' refresh='content' tiddler='MainMenu'&gt;&lt;/div&gt;
&lt;!--}}}--&gt;

!Step two: remove the 'safety guards' from the original MainMenu code
In PageTemplate still, change this line:
&lt;!--{{{--&gt;
&lt;!--&lt;div id='mainMenu' refresh='content' tiddler='MainMenu'&gt;&lt;/div&gt;--&gt;
&lt;!--}}}--&gt;
So that it looks like this:
&lt;!--{{{--&gt;
&lt;div id='mainMenu' refresh='content' tiddler='MainMenu'&gt;&lt;/div&gt;
&lt;!--}}}--&gt;

!Step three: Adjust the MainMenu and display area in the StyleSheet:
In StyleSheet, add this code, which widens the left-hand MainMenu area and narrows the Tiddler display area:

&lt;!--{{{--&gt;
/* Widens the mainmenu and adds padding between right-aligned menu text and the right edge of the menu. */

#mainMenu {
 width: 13em;
 padding: 4em 2em 2em 0.5 em;
}

/* Moves tiddler display area to the right to account for widened mainmenu */

#displayArea {
 margin: 0em 1em 0em 15em;
}
&lt;!--}}}--&gt;

That should be it! If you still have problems, let me know at giff (at) giffmex (dot) org.

</pre>
</div>
<div title="How do you use a TiddlyWiki?" modifier="tiddlyvault" modified="200710011422" created="200612030317" changecount="78">
<pre>{{invisibletable{
|width:25em; When I became acquainted with ~TiddlyWiki in September 2006 I //instantly// realized how useful it would be for me. But at the time there was not much documentation, and what little existed was written by and for computer geniuses. Their documentation assumed that the reader already knew quite a bit about various computer codes and the inner workings of ~TiddlyWiki.&lt;br&gt;&lt;br&gt;So I had to learn ~TiddlyWiki the hard, slow way. The people at the ~TiddlyWiki Google group were very helpful in guiding me along. But I knew not every newcomer like me would want to go through such a tedious learning process. So I decided to create this simple tutorial. If you've heard about ~TiddlyWiki but don't know &quot;Tiddly squat&quot; about it, then this tutorial is for you. Enjoy!|''Basic instructions:''&lt;br&gt;[[What in the world is a TiddlyWiki?]]&lt;br&gt;[[For beginners: reading TiddlyWikis on the Internet]]&lt;br&gt;[[Save a TiddlyWiki file to your computer]]&lt;br&gt;[[Browser-specific issues]]&lt;br&gt;[[Printing from a TiddlyWiki file]]&lt;br&gt;[[For medium users: adding your own material to a TiddlyWiki file]]&lt;br&gt;[[For advanced users: Customize your TW experience]]&lt;br&gt;[[Host your TiddlyWiki online]]&lt;br&gt;&lt;br&gt;''Also helpful:''&lt;br&gt;[[A visual guide to the TiddlyWiki layout]]&lt;br&gt;[[Version 2.2]]&lt;br&gt;[[Special formatting]]&lt;br&gt;[[Where to go for more information]]&lt;br&gt;&lt;br&gt;If you found this tutorial helpful, would you consider helping me buy books via an Amazon gift certificate?&lt;br&gt;&lt;br&gt;&lt;html&gt;&lt;a href=&quot;https://www.amazon.com/gp/registry/wishlist/1OTJM9IE7SPVS/ref=wl_web/&quot;&gt;&lt;img src=&quot;https://images-na.ssl-images-amazon.com/images/G/01/gifts/registries/wishlist/v2/web/wl-btn-74-b._V46774601_.gif&quot; width=&quot;74&quot; alt=&quot;My Amazon.com Wish List&quot; height=&quot;42&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;/html&gt;|
}}}


</pre>
</div>
<div title="How to add background images" modifier="churu1" modified="200706041414" created="200702230200">
<pre>Add the following code to the StyleSheet tiddler, being sure to place your image url inside the paretheses:

&lt;!--{{{--&gt;
body {background-image: url();
background-repeat: repeat; background-position: left; backgound-color: transparent; font-family: Helvetica;} 
&lt;!--}}}--&gt;

Obviously if it is an image on the Internet, you will only have access to the image while online.

</pre>
</div>
<div title="How to create gradients" modifier="giffmex" modified="200708272334" created="200702230213" changecount="2">
<pre>I honestly don't remember when or where I found the information below. But I've cut-and-pasted it here (with a few minor adjustments) because it is a nice visual explanation of gradients.

&lt;&lt;gradient horiz #bbbbbb #eeeeee #ffffff&gt;&gt;The new GradientMacro allows simple horizontal and vertical coloured gradients. They are constructed from coloured HTML elements, and don't require any images to work.&gt;&gt;

The syntax for the gradient macro looks like this:
{{{
&lt;&lt;gradient vert #ffffff #ffdddd #ff8888&gt;&gt;gradient fill&gt;&gt;
}}}

Inside double angle brackets there are ''four elements:'' 
#&quot;gradient&quot; tells ~TiddlyWiki what kind of macro this is.
#&quot;vert&quot; is for vertical gradients and &quot;horiz&quot; is for horizontal gradients.
#What follows is a sequence of the code for the two or more colors that you want in your gradient. You may use CSS or RGB ways of indicating colors. For more on colors, see [[here|Changing the colors of a TiddlyWiki]].
#&quot;&gt;&gt;gradient fill&gt;&gt;&quot; finishes off your macro.

''Here is another gradient example:''
| &lt;&lt;gradient vert #ffffff #ffdddd #ff8888&gt;&gt;No images were harmed in the making of this gradient fill&gt;&gt; | &lt;&lt;gradient vert #ffffff #ddffdd #88ff88&gt;&gt;No images were harmed in the making of this gradient fill&gt;&gt; | &lt;&lt;gradient vert #ffffff #ddddff #8888ff&gt;&gt;No images were harmed in the making of this gradient fill&gt;&gt; |

Here's the code for the image above.
{{{
| &lt;&lt;gradient vert #ffffff #ffdddd #ff8888&gt;&gt;No images were harmed in the making of this gradient fill&gt;&gt; | &lt;&lt;gradient vert #ffffff #ddffdd #88ff88&gt;&gt;No images were harmed in the making of this gradient fill&gt;&gt; | &lt;&lt;gradient vert #ffffff #ddddff #8888ff&gt;&gt;No images were harmed in the making of this gradient fill&gt;&gt; |
}}}

Inline CSS definitions can be added to gradient fills like this:

&lt;&lt;gradient vert #000000 #660000 #aa2222&gt;&gt;color:#ffffff;font-size:12pt;Darkness&gt;&gt;

Here's the code for the image above.
{{{
&lt;&lt;gradient vert #000000 #660000 #aa2222&gt;&gt;color:#ffffff;font-size:12pt;Darkness&gt;&gt;
}}}

</pre>
</div>
<div title="How to create new tiddlers based on a template tiddler" modifier="churu1" modified="200706050035" created="200703051705">
<pre>If you create tiddlers with the same information over and over (contacts, quotations, recipes, etc), you are probably going to want a template tiddler to save time. Then you are going to want a macro that creates a new tiddler that includes the information from the template. Here's how:

#''Create the template tiddler.'' Put text and tables and formatting exactly the way you want your new tiddlers based on this template to appear.
#''Create a macro that will open a new tiddler based on your template.''&lt;br&gt;Where I have listed YYYY, insert the words you want to appear in the label for your macro. Where I have listed ZZZZ, insert the exact title of the template tiddler that each new tiddler will be based on. Where I have XXXX insert any tags that you want to be appended to each tiddler that the macro creates.
/*{{{*/
&lt;&lt;newTiddler label:&quot;YYYY&quot; tag:&quot;XXXX&quot; text:{{store.getTiddlerText('ZZZZ')}}&gt;&gt;
/*}}}*/

3. ''Decide where you are going to store your macro.'' You can add it to the SideBarOptions menu under 'new tiddler' and 'new journal.' Or you can add it to a tiddler that you can access from your MainMenu. 

</pre>
</div>
<div title="How to install a plugin" modifier="churu1" modified="200706081419" created="200701182128" changecount="2">
<pre>Plugins are tiddlers embedded with codes that add special functions to ~TiddlyWiki files. Plugins are easier to install than I thought they would be. Here's how:
*Find the plugin you want and grab the url of the page it's on. (Copy the url from your browser's search window).
*In your own ~TiddlyWiki file, click on ImportTiddlers, found in the backstage area for versions 2.2 and beyond, and on the InterfaceOptions panel in the righthand sidebar of earlier versions.
*Paste the url you've copied into the top window of the import tiddlers tiddler that appears. Then click Fetch.
*A list of all the tiddlers found in the other file will appear. Find the tiddler of the plugin you want, then check the box next to it.
*Below the list is a menu that says &quot;More actions...&quot; Choose &quot;Import these tiddlers.&quot;
*Your screen will blink and change several times while your file is being updated. If you have your ~TiddlyWiki configured to automatically save every change (which is default), the box will appear in the top right corner saying it has saved the change. If you have it configured another way, then click on &quot;save changes&quot;.
*Hit the 'refresh' or 'reload' button on your browser.
*The plugin should now be installed and usable on your file. That's it!

</pre>
</div>
<div title="InlineJavascriptPlugin" modifier="churu1" created="200706041426" tags="systemConfig includeNew TidIDEPackage BackstagePackage MenuPackage MediaPackage">
<pre>/***
|Name|InlineJavascriptPlugin|
|Source|http://www.TiddlyTools.com/#InlineJavascriptPlugin|
|Version|1.6.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements &lt;&lt;br&gt;&gt;and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Description|Insert Javascript executable code directly into your tiddler content.|

''Call directly into TW core utility routines, define new functions, calculate values, add dynamically-generated TiddlyWiki-formatted output'' into tiddler content, or perform any other programmatic actions each time the tiddler is rendered.
!!!!!Usage
&lt;&lt;&lt;
When installed, this plugin adds new wiki syntax for surrounding tiddler content with {{{&lt;script&gt;}}} and {{{&lt;/script&gt;}}} markers, so that it can be treated as embedded javascript and executed each time the tiddler is rendered.

''Deferred execution from an 'onClick' link''
By including a {{{label=&quot;...&quot;}}} parameter in the initial {{{&lt;script&gt;}}} marker, the plugin will create a link to an 'onclick' script that will only be executed when that specific link is clicked, rather than running the script each time the tiddler is rendered.  You may also include a {{{title=&quot;...&quot;}}} parameter to specify the 'tooltip' text that will appear whenever the mouse is moved over the onClick link text

''External script source files:''
You can also load javascript from an external source URL, by including a src=&quot;...&quot; parameter in the initial {{{&lt;script&gt;}}} marker (e.g., {{{&lt;script src=&quot;demo.js&quot;&gt;&lt;/script&gt;}}}).  This is particularly useful when incorporating third-party javascript libraries for use in custom extensions and plugins.  The 'foreign' javascript code remains isolated in a separate file that can be easily replaced whenever an updated library file becomes available.

''Display script source in tiddler output''
By including the keyword parameter &quot;show&quot;, in the initial {{{&lt;script&gt;}}} marker, the plugin will include the script source code in the output that it displays in the tiddler.

''Defining javascript functions and libraries:''
Although the external javascript file is loaded while the tiddler content is being rendered, any functions it defines will not be available for use until //after// the rendering has been completed.  Thus, you cannot load a library and //immediately// use it's functions within the same tiddler.  However, once that tiddler has been loaded, the library functions can be freely used in any tiddler (even the one in which it was initially loaded).

To ensure that your javascript functions are always available when needed, you should load the libraries from a tiddler that will be rendered as soon as your TiddlyWiki document is opened.  For example, you could put your {{{&lt;script src=&quot;...&quot;&gt;&lt;/script&gt;}}} syntax into a tiddler called LoadScripts, and then add {{{&lt;&lt;tiddler LoadScripts&gt;&gt;}}} in your MainMenu tiddler.

Since the MainMenu is always rendered immediately upon opening your document, the library will always be loaded before any other tiddlers that rely upon the functions it defines.  Loading an external javascript library does not produce any direct output in the tiddler, so these definitions should have no impact on the appearance of your MainMenu.

''Creating dynamic tiddler content''
An important difference between this implementation of embedded scripting and conventional embedded javascript techniques for web pages is the method used to produce output that is dynamically inserted into the document:
* In a typical web document, you use the document.write() function to output text sequences (often containing HTML tags) that are then rendered when the entire document is first loaded into the browser window.
* However, in a ~TiddlyWiki document, tiddlers (and other DOM elements) are created, deleted, and rendered &quot;on-the-fly&quot;, so writing directly to the global 'document' object does not produce the results you want (i.e., replacing the embedded script within the tiddler content), and completely replaces the entire ~TiddlyWiki document in your browser window.
* To allow these scripts to work unmodified, the plugin automatically converts all occurences of document.write() so that the output is inserted into the tiddler content instead of replacing the entire ~TiddlyWiki document.

If your script does not use document.write() to create dynamically embedded content within a tiddler, your javascript can, as an alternative, explicitly return a text value that the plugin can then pass through the wikify() rendering engine to insert into the tiddler display.  For example, using {{{return &quot;thistext&quot;}}} will produce the same output as {{{document.write(&quot;thistext&quot;)}}}.

//Note: your script code is automatically 'wrapped' inside a function, {{{_out()}}}, so that any return value you provide can be correctly handled by the plugin and inserted into the tiddler.  To avoid unpredictable results (and possibly fatal execution errors), this function should never be redefined or called from ''within'' your script code.//

''Accessing the ~TiddlyWiki DOM''
The plugin provides one pre-defined variable, 'place', that is passed in to your javascript code so that it can have direct access to the containing DOM element into which the tiddler output is currently being rendered.

Access to this DOM element allows you to create scripts that can:
* vary their actions based upon the specific location in which they are embedded
* access 'tiddler-relative' information (use findContainingTiddler(place))
* perform direct DOM manipulations (when returning wikified text is not enough)
&lt;&lt;&lt;
!!!!!Examples
&lt;&lt;&lt;
an &quot;alert&quot; message box:
&gt;&lt;script show&gt;
        alert('InlineJavascriptPlugin: this is a demonstration message');
&lt;/script&gt;
dynamic output:
&gt;&lt;script show&gt;
        return (new Date()).toString();
&lt;/script&gt;
wikified dynamic output:
&gt;&lt;script show&gt;
        return &quot;link to current user: [[&quot;+config.options.txtUserName+&quot;]]&quot;;
&lt;/script&gt;
dynamic output using 'place' to get size information for current tiddler:
&gt;&lt;script show&gt;
   if (!window.story) window.story=window;
   var title=story.findContainingTiddler(place).id.substr(7);
   return title+&quot; is using &quot;+store.getTiddlerText(title).length+&quot; bytes&quot;;
&lt;/script&gt;
creating an 'onclick' button/link that runs a script:
&gt;&lt;script label=&quot;click here&quot; title=&quot;clicking this link will show an 'alert' box&quot; show&gt;
   if (!window.story) window.story=window;
   alert(&quot;Hello World!\nlinktext='&quot;+place.firstChild.data+&quot;'\ntiddler='&quot;+story.findContainingTiddler(place).id.substr(7)+&quot;'&quot;);
&lt;/script&gt;
loading a script from a source url:
&gt;http://www.TiddlyTools.com/demo.js contains:
&gt;&gt;{{{function demo() { alert('this output is from demo(), defined in demo.js') } }}}
&gt;&gt;{{{alert('InlineJavascriptPlugin: demo.js has been loaded'); }}}
&gt;&lt;script src=&quot;demo.js&quot; show&gt;
        return &quot;loading demo.js...&quot;
&lt;/script&gt;
&gt;&lt;script label=&quot;click to execute demo() function&quot; show&gt;
        demo()
&lt;/script&gt;
&lt;&lt;&lt;
!!!!!Installation
&lt;&lt;&lt;
import (or copy/paste) the following tiddlers into your document:
''InlineJavascriptPlugin'' (tagged with &lt;&lt;tag systemConfig&gt;&gt;)
&lt;&lt;&lt;
!!!!!Revision History
&lt;&lt;&lt;
''2007.02.19 [1.6.0]'' added support for title=&quot;...&quot; to specify mouseover tooltip when using an onclick (label=&quot;...&quot;) script
''2006.10.16 [1.5.2]'' add newline before closing '}' in 'function out_' wrapper.  Fixes error caused when last line of script is a comment.
''2006.06.01 [1.5.1]'' when calling wikify() on script return value, pass hightlightRegExp and tiddler params so macros that rely on these values can render properly
''2006.04.19 [1.5.0]'' added 'show' parameter to force display of javascript source code in tiddler output
''2006.01.05 [1.4.0]'' added support 'onclick' scripts.  When label=&quot;...&quot; param is present, a button/link is created using the indicated label text, and the script is only executed when the button/link is clicked.  'place' value is set to match the clicked button/link element.
''2005.12.13 [1.3.1]'' when catching eval error in IE, e.description contains the error text, instead of e.toString().  Fixed error reporting so IE shows the correct response text.  Based on a suggestion by UdoBorkowski
''2005.11.09 [1.3.0]'' for 'inline' scripts (i.e., not scripts loaded with src=&quot;...&quot;), automatically replace calls to 'document.write()' with 'place.innerHTML+=' so script output is directed into tiddler content.  Based on a suggestion by BradleyMeck
''2005.11.08 [1.2.0]'' handle loading of javascript from an external URL via src=&quot;...&quot; syntax
''2005.11.08 [1.1.0]'' pass 'place' param into scripts to provide direct DOM access 
''2005.11.08 [1.0.0]'' initial release
&lt;&lt;&lt;
!!!!!Credits
&lt;&lt;&lt;
This feature was developed by EricShulman from [[ELS Design Studios|http:/www.elsdesign.com]]
&lt;&lt;&lt;
!!!!!Code
***/
//{{{
version.extensions.inlineJavascript= {major: 1, minor: 6, revision: 0, date: new Date(2007,2,19)};

config.formatters.push( {
        name: &quot;inlineJavascript&quot;,
        match: &quot;\\&lt;script&quot;,
        lookahead: &quot;\\&lt;script(?: src=\\\&quot;((?:.|\\n)*?)\\\&quot;)?(?: label=\\\&quot;((?:.|\\n)*?)\\\&quot;)?(?: title=\\\&quot;((?:.|\\n)*?)\\\&quot;)?( show)?\\&gt;((?:.|\\n)*?)\\&lt;/script\\&gt;&quot;,

        handler: function(w) {
                var lookaheadRegExp = new RegExp(this.lookahead,&quot;mg&quot;);
                lookaheadRegExp.lastIndex = w.matchStart;
                var lookaheadMatch = lookaheadRegExp.exec(w.source)
                if(lookaheadMatch &amp;&amp; lookaheadMatch.index == w.matchStart) {
                        if (lookaheadMatch[1]) { // load a script library
                                // make script tag, set src, add to body to execute, then remove for cleanup
                                var script = document.createElement(&quot;script&quot;); script.src = lookaheadMatch[1];
                                document.body.appendChild(script); document.body.removeChild(script);
                        }
                        if (lookaheadMatch[5]) { // there is script code
                                if (lookaheadMatch[4]) // show inline script code in tiddler output
                                        wikify(&quot;{{{\n&quot;+lookaheadMatch[0]+&quot;\n}}}\n&quot;,w.output);
                                if (lookaheadMatch[2]) { // create a link to an 'onclick' script
                                        // add a link, define click handler, save code in link (pass 'place'), set link attributes
                                        var link=createTiddlyElement(w.output,&quot;a&quot;,null,&quot;tiddlyLinkExisting&quot;,lookaheadMatch[2]);
                                        link.onclick=function(){try{return(eval(this.code))}catch(e){alert(e.description?e.description:e.toString())}}
                                        link.code=&quot;function _out(place){&quot;+lookaheadMatch[5]+&quot;\n};_out(this);&quot;
                                        link.setAttribute(&quot;title&quot;,lookaheadMatch[3]?lookaheadMatch[3]:&quot;&quot;);
                                        link.setAttribute(&quot;href&quot;,&quot;javascript:;&quot;);
                                        link.style.cursor=&quot;pointer&quot;;
                                }
                                else { // run inline script code
                                        var code=&quot;function _out(place){&quot;+lookaheadMatch[5]+&quot;\n};_out(w.output);&quot;
                                        code=code.replace(/document.write\(/gi,'place.innerHTML+=(');
                                        try { var out = eval(code); } catch(e) { out = e.description?e.description:e.toString(); }
                                        if (out &amp;&amp; out.length) wikify(out,w.output,w.highlightRegExp,w.tiddler);
                                }
                        }
                        w.nextMatch = lookaheadMatch.index + lookaheadMatch[0].length;
                }
        }
} )
//}}}</pre>
</div>
<div title="Journal Entry by HSC" modifier="Schlanger" modified="200805051020" created="200805050859" tags="Journal" changecount="2">
<pre>Type the text for '5 May 2008'</pre>
</div>
<div title="Launch applications from within TiddlyWiki" modifier="giffmex" created="200708251531" changecount="2">
<pre>The ''~LaunchApplicationsPlugin'' allows you to launch other programs (Outlook, Word, etc) from within ~TiddlyWiki. 

You can access it either [[here|http://www.Remotely-Helpful.com/TiddlyWiki/LaunchApplication.html]] or [[here|http://www.Remotely-Helpful.com/TiddlyWiki/LaunchApplication.html|]]. Be aware that there are security risks involved with some uses of this plugin. See Morris Gray's help file [[here|http://twhelp.tiddlyspot.com/#%5B%5BLaunch%20Applications%20Plugin%5D%5D]] for more information.</pre>
</div>
<div title="List of built-in macros" modifier="churu1" modified="200706041504" created="200703051459">
<pre>This information taken from Julian Knight's ~TiddlyWiki, which can be [[found here|http://knighjm.googlepages.com/knightnet-default-tw.html]].

Macros let you write tiddlers containing more exotic objects than just text. Here are the built-in macros:

|!Macro|!Description|!Syntax|
|allTags|List all the tags used in the current ~TiddlyWiki file&lt;&lt;br&gt;&gt;Each entry is a button that pops up the list of tiddlers for that tag&lt;&lt;br&gt;&gt;&lt;&lt;slider sliderID [[Internal Macros/tags]] 'Click to show example output'&gt;&gt;|{{{&lt;&lt;allTags&gt;&gt;}}}|
|br|Force a line break|{{{&lt;&lt;br&gt;&gt;}}}|
|closeAll|Displays a button to close all displayed Tiddlers&lt;&lt;br&gt;&gt;&lt;&lt;closeAll&gt;&gt;|{{{&lt;&lt;closeAll&gt;&gt;}}}|
|gradient|&lt;&lt;gradient [horiz|vert] #bbbbbb #eeeeee #ffffff&gt;&gt;Produces a horizontal or vertical background gradient fill&gt;&gt;&lt;&lt;br&gt;&gt;There can be 2 or more colours in the format: #rrggbb (hex), or RGB(r,g,b) (CSS)&lt;&lt;br&gt;&gt;Other CSS formatting can also be added, e.g. {{{&lt;&lt;gradient vert #000000 #660000 #aa2222&gt;&gt;color:#ffffff;font-size:12pt;Darkness&gt;&gt;}}}|{{{&lt;&lt;gradient [horiz|vert] #bbbbbb #eeeeee #ffffff&gt;&gt;Some text here&gt;&gt;}}}|
|list all|List all Tiddlers in a Tiddler|{{{&lt;&lt;list all&gt;&gt;}}}|
|list missing|List all missing tiddlers|{{{&lt;&lt;list missing&gt;&gt;}}}|
|list orphans|List all orphaned tiddlers|{{{&lt;&lt;list orphans&gt;&gt;}}}|
|newJournal|Displays a button to create new date &amp; Time stamped Tiddler (Date/time format optional)&lt;&lt;br&gt;&gt;&lt;&lt;newJournal &quot;DD MMM YYYY, hh:mm&quot;&gt;&gt; &lt;&lt;br&gt;&gt;You can also add optional tag names after the date format: &lt;&lt;newJournal &quot;DD MMM YYYY, hh:mm&quot; tag1 TagTwo&gt;&gt; |{{{&lt;&lt;newJournal [DateFormatString]&gt;&gt;}}} &lt;&lt;br&gt;&gt; {{{&lt;&lt;newJournal &quot;DD MMM YYYY, hh:mm&quot; tag1 TagTwo&gt;&gt;}}} |
|newTiddler|Displays a button to create new Tiddler&lt;&lt;br&gt;&gt;&lt;&lt;newTiddler&gt;&gt;|{{{&lt;&lt;newTiddler&gt;&gt;}}}|
|permaview|Displays a button to change the URL link for all open Tiddlers - or the containing tiddler if used in the command bar (See the ViewTemplate)&lt;&lt;br&gt;&gt;&lt;&lt;permaview&gt;&gt;|{{{&lt;&lt;permaview&gt;&gt;}}}|
|saveChanges |Button to save all ~TiddlyWiki changes (or the current tiddler if used in the command bar (see EditTemplate)&lt;&lt;br&gt;&gt;&lt;&lt;saveChanges&gt;&gt;|{{{&lt;&lt;saveChanges&gt;&gt;}}}|
|search|Display a Search box&lt;&lt;br&gt;&gt;&lt;&lt;search&gt;&gt;|{{{&lt;&lt;search&gt;&gt;}}}|
|slider|Display a Slider (a collapsable display of another tiddler)&lt;&lt;br&gt;&gt;See the allTags entry for an example. Note: Put quotes around the label if needing spaces&lt;&lt;br&gt;&gt;where: ''ID''=cookie name to be used to save the state of the slider, ''Tiddler''=name of the tiddler to include in the slider, ''Label''=label text of the slider button, ''tooltip''=text of the buttons tooltip|{{{&lt;&lt;slider ID Tiddler [Label] [toolTip]&gt;&gt;}}}|
|sparkline|Produces a sparkline graphic&lt;&lt;br&gt;&gt;e.g. &lt;&lt;sparkline 163 218 231 236 232 266 176 249 289 1041 1835 2285 3098 2101 1755 3283 3353 3335 2898 2224 1404 1354 1825 1839 2142 1942 1784 1145 979 1328 1611&gt;&gt;|{{{&lt;&lt;sparkline num1 num2 ... numN&gt;&gt;}}}|
|tabs|Display Tabbed content (contents of tab provided by another tiddler)|{{{&lt;&lt;tabs identifier tabLabel tabName Tiddlername&gt;&gt;}}}|
|tag|Display a Tag ~PopUp&lt;&lt;br&gt;&gt;&lt;&lt;tag _Config&gt;&gt;|{{{&lt;&lt;tag tagName&gt;&gt;}}}|
|tagChooser|Used in EditTemplate to add tags to the tags field. Doesn't actually add anything unless in edit mode (though it does show the list)&lt;&lt;br&gt;&gt;&lt;&lt;tagChooser&gt;&gt;|{{{&lt;&lt;tagChooser&gt;&gt;}}}|
|tagging|&lt;&lt;tiddler [[Internal Macros/tagging]]&gt;&gt;|{{{&lt;&lt;tagging [TiddlerTitle]&gt;&gt;}}}|
|tiddler|Display contents of another tiddler inline|{{{&lt;&lt;tiddler Tiddler&gt;&gt;}}}|
|timeline|Display a timeline list of tiddlers&lt;&lt;br&gt;&gt;where the sortfield is the sort order (&quot;modified&quot; or &quot;created&quot;) and maxentries is the maximum number of entries|{{{&lt;&lt;timeline [sortfield] [maxentries]&gt;&gt;}}}|
|today|Display Today's Date&lt;&lt;br&gt;&gt;e.g. &lt;&lt;today&gt;&gt;|{{{&lt;&lt;today [DateFormatString]&gt;&gt;}}}|
|version|Display ~TiddlyWiki's version&lt;&lt;br&gt;&gt;e.g. &lt;&lt;version&gt;&gt;|{{{&lt;&lt;version&gt;&gt;}}}|

!DateFormatString
Several Macros including the today macro take a DateFormatString as an optional argument. This string can be a combination of ordinary text, with some special characters that get substituted by parts of the date:
* DDD - day of week in full (eg, &quot;Monday&quot;)
* DD - day of month, 0DD - adds a leading zero
* MMM - month in full (eg, &quot;July&quot;)
* MM - month number, 0MM - adds leading zero
* YYYY - full year, YY - two digit year
* hh - hours
* mm - minutes
* ss - seconds
!Notes
If you need to supply a parameter that should be evaluated (e.g. a JavaScript variable), enclose the parameter in {{{{{}}} and {{{}}}}} rather than quotes. Note however, that the scope used in the evaluation is {{{global}}} rather than {{{local}}}. In other words, the evaluation is done ''before'' the parameter is passed to the macro/plugin so it cannot access any of the variables or functions defined within the macro/plugin.
!Commands supported by the toolbar macro
{{{
config.commands = {
 closeTiddler: {text: &quot;close&quot;, tooltip: &quot;Close this tiddler&quot;},
 closeOthers: {text: &quot;close others&quot;, tooltip: &quot;Close all other tiddlers&quot;},
 editTiddler: {text: &quot;edit&quot;, tooltip: &quot;Edit this tiddler&quot;, readOnlyText: &quot;view&quot;, readOnlyTooltip: &quot;View the source of this tiddler&quot;},
 saveTiddler: {text: &quot;done&quot;, tooltip: &quot;Save changes to this tiddler&quot;, readOnlyText: &quot;done&quot;, readOnlyTooltip: &quot;View this tiddler normally&quot;},
 cancelTiddler: {text: &quot;cancel&quot;, tooltip: &quot;Undo changes to this tiddler&quot;, hideReadOnly: true},
 deleteTiddler: {text: &quot;delete&quot;, tooltip: &quot;Delete this tiddler&quot;, warning: &quot;Are you sure you want to delete '%0'?&quot;, hideReadOnly: true},
 permalink: {text: &quot;permalink&quot;, tooltip: &quot;Permalink for this tiddler&quot;},
 references: {text: &quot;references&quot;, tooltip: &quot;Show tiddlers that link to this one&quot;, popupNone: &quot;No references&quot;},
 jump: {text: &quot;jump&quot;, tooltip: &quot;Jump to another open tiddler&quot;}
 };
}}}
(Julian Knight, 2006-04-06)
&lt;part tagging hidden&gt;
Produces a list (NB: &lt;ul&gt; ''not'' a popup) of links to tiddlers that carry the specified tag. If no tag is specified, it looks for tiddlers tagged with the name of the current tiddler.
In HTML, the list is formatted like so:
{{{
&lt;ul&gt;
&lt;li class=&quot;listTitle&quot;&gt;List title label&lt;/li&gt;
&lt;li&gt;&lt;a class=&quot;tiddlyLink ...&quot; href=&quot;javascript:;&quot; onclick=&quot;...&quot;
    refresh=&quot;link&quot; tiddlyLink=&quot;ExampleOne&quot;&gt;ExampleOne&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
}}}
&lt;/part&gt;
&lt;part tags hidden&gt;
&lt;&lt;allTags&gt;&gt;
&lt;/part&gt;</pre>
</div>
<div title="Macros" modifier="churu1" modified="200706041356" created="200701182241">
<pre>Macros are basically shortcuts. If you open up the ImportTiddlers tiddler, you will see an elaborate layout with text boxes and various colors and instructions. But if you double-click on it to go into edit mode, you will see only the following: {{{ &lt;&lt;importTiddlers&gt;&gt; }}}. This is a macro that creates the elaborate Import Tiddlers layout. 

Here is Julian Knight's fairly complete list of the macros built into ~TiddlyWiki, and what each macro does.  [[List of built-in macros]]

You can add your favorite macros to any tiddler, including the MainMenu and SideBarOptions.

</pre>
</div>
<div title="MainMenu" modifier="Schlanger" modified="200805050901" created="200612030310" changecount="6">
<pre>[[How to use|How do you use a TiddlyWiki?]]
[[Glossary|TW glossary]]
[[Save this file|twfortherestofus.html]]
[[Credits]]
[[Recent changes|Most recent changes]]
&lt;&lt;tiddler ToggleRightSidebar&gt;&gt;</pre>
</div>
<div title="MarkupPostBody" modifier="tiddlyvault" modified="200709182142" created="200706291532" tags="script" changecount="23">
<pre></pre>
</div>
<div title="Messing with StyleSheets" modifier="churu1" modified="200706041400" created="200701182148">
<pre>The style sheets are the parts of ~TiddlyWiki that control and display the default code for the colors (StyleSheetColors), the page layout (StyleSheetLayout) and printing features (StyleSheetPrint) of a ~TiddlyWiki. You can override these defaults by adding code to the StyleSheet tiddler.

''Note:'' I used to make changes directly to the three original style sheets and in earlier versions of this tutorial I directed others to do the same. Others kindly pointed out the drawbacks of that approach: 
*If you make mistakes in the three main style sheets, they can't be undone. They must be restored from a back up copy or another ~TiddlyWiki. Making changes to ~StyleSheet allows you to retain the original code of the three main style sheets.
*If in the future you upgrade to a newer version of ~TiddlyWiki, you will lose the changes you made to the three main style sheets as they are upgraded. So it's better to have your changes saved in ~StyleSheet.
This file already has its own ~StyleSheet. I have provided captions to explain my own tweaks, so that you can see how it is done. Feel free to tweak it as needed.

</pre>
</div>
<div title="Miscellaneous formats" modifier="giffmex" modified="200708232005" created="200708232004" changecount="5">
<pre>''Simple indenting:''

{{{ {{indent{text }}} produces:

{{indent{text


''Headlines'':

{{{!Text}}} produces:
!Text
{{{!!Text}}} produces:
!!Text
{{{!!!Text}}} produces:
!!!Text
and so on.


''Dotted horizontal lines:'' 

{{{----}}} produces the following line:
----


</pre>
</div>
<div title="Mocha" modifier="GiffMex" modified="200701271308" created="200701271301" tags="palette">
<pre>Background: #eeddaa
Foreground: #000
PrimaryPale: #ddcc99
PrimaryLight: #bb8833
PrimaryMid: #553322
PrimaryDark: #000
SecondaryPale: #ffc
SecondaryLight: #fe8
SecondaryMid: #cccccc
SecondaryDark: #553322
TertiaryPale: #ddcc99
TertiaryLight: #EEC591
TertiaryMid: #553322
TertiaryDark: #8B7355</pre>
</div>
<div title="More information on tables" modifier="giffmex" modified="200708251723" created="200708250021" changecount="3">
<pre>*[[Alternate the color of table rows]]
*[[Force the text in a cell not to wrap to the next line at a space]]
*[[Align the text in a cell at the top instead of the center]]
</pre>
</div>
<div title="More with macros" modifier="giffmex" modified="200709011827" created="200708232053" changecount="3">
<pre>*[[Macros]]
*[[Slider macros]]
*[[The macro for tabbed lists]]
*[[TiddlyVault: your source for macros, plugins and themes]]</pre>
</div>
<div title="Most recent changes" modifier="tiddlyvault" modified="200709191209" created="200612241312" changecount="16">
<pre>As always, you can check the timeline in the tabbed menu to the right to view recent changes. But to save you time, here are the newest changes:

''August 25, 2007''
*[[Access files, folders, etc from within TiddlyWiki]] and the tiddlers contained therein.
*Updated [[The macro for tabbed lists]]
*[[Special note on modifying shadow tiddlers]]
*[[The SelectPaletteMacro]]
*[[TiddlySnip Firefox addon]]

''August 24, 2007''
*[[Use IFrames to embed other webpages in your TiddlyWiki]]
*Large initial letters in [[Format text]]
*[[More information on tables]] and the tiddlers contained therein.

''August 23, 2007''
*Added iframes to show the [[Coloria color names]] and the [[4096 Color wheel]]. Swiped the idea from Morris Gray's tutorial. Good thinking, Morris!
*Added a couple items to the glossary.
*Cleaned up a few tiddlers to make them less cluttered, including [[How do you use a TiddlyWiki?]] and [[For medium users: adding your own material to a TiddlyWiki file]].
*[[Format ASCII symbols, foreign symbols, math symbols]]
*[[Open the indexes of your hard drive, CD or USB files from inside your TiddlyWiki]]
*[[Toggle the right hand menu]]
*[[Changing the look of the basic page layout - understanding the PageTemplate]]
*[[Changing the look of a tiddler in viewing mode - understanding the ViewTemplate]]
*[[Changing the look of a tiddler in editing mode - understanding the EditTemplate]]
*[[Host your TiddlyWiki online]]

''July 4, 2007''
*[[Tips for speeding up performance on large TiddlyWikis]]

''June 8, 2007''
*Upgraded to version 2.2.1, with instructions at [[Version 2.2]]. Most pertinent tiddlers changed, but the guide to the TW screen will need to be adjusted soon to account for the fact that ImportTiddlers has been moved.

''June 4, 2007''
*Basically cleaned up a few texts to simplify and correct what I had written before. I also mention the &quot;My Notes&quot; ~TiddlyWiki I created for more powerful categorization of notes. 

''May 26, 2007''
*Added the [[easyFormat]] plugin and the other tiddlers needed to make it work. This allows you to quickly add formatting to selected text within a tiddler. Edit this tiddler and click on the word &quot;Format&quot; to see a dropdown menu of formatting options.
*Changed the layout of the page.

''March 26, 2007''
*Added a plugin to allow users to toggle the sidebar. 

''March 5, 2007''
*Finally cleaned up the [[How to Format Text]] tiddler. This is much improved, and adds a few items such as lists in tables and links to local files.
*[[How to create new tiddlers based on a template tiddler]] in the advanced section.
*[[Create forms with editable fields]] in the advanced section.
*[[Some great &quot;power&quot; plugins]] in the advanced section.
*[[Advanced ideas for tags]], includes how to create an index for a tag and how to create an index for all tiddlers by tag. Accessible from the medium and advanced sections.
*Added a few terms to the glossary.
*Adjusted Stylesheet so that topmenu doesn't print.
*Deleted dead links to blogjones.
*Cut and pasted Julian Knight's info on macros in [[List of built-in macros]] just in case that becomes a dead link, too! 

''March 2, 2007''
*Added [[greenishgray]] color scheme.

''Feb. 22, 2007''
*Added a section on how to create [[Slider macros]].
*Added a section on [[Top menus versus left hand main menus]], including how to change them back and forth.
*Added a section on [[How to add background images]] and one on [[How to create gradients]].
*Added link to ''~TiddlyWiki in Action'' in [[What are TiddlyWikis being used for?]].

''Feb. 10, 2007''
*Moved the MainMenu to the header and reworded the tiddlers that refer to it.

''Jan. 27 2007''
*Made corrections and clean-up to the section [[Messing with StyleSheets]]
*Added my own StyleSheet with captions
*Added two new color schemes, [[Mauve]] and [[Mocha]], and improved [[Apples]] and [[Blueberry]].
*Added note about our new personal organizer in [[What are TiddlyWikis being used for?]]

''Jan. 24 2007'':
*Added a link to a list of TW macros in [[Macros]].
*Added a link to another TW tutorial in [[Where to go for more information]]

''other recent changes'':
*Double-spacing between items on bulleted and numbered lists
*A tiddler on DaveGifford (information about the author of this tutorial)
*[[How to install a plugin]] and [[My favorite plugins]]
*[[Macros]]
*[[Messing with StyleSheets]] and a description of the tweaks I made to the {{{StyleSheetLayout}}} of this file.
*Link to the Spanish version is in the MainMenu. 
*[[TW glossary]] begun.
</pre>
</div>
<div title="My favorite &quot;goodies&quot; plugins" modifier="GiffMex" modified="200703070407" created="200701182133">
<pre>There are many plugins that expand the usefulness of ~TiddlyWiki. 

''Calendars:'' 
Here are links to three calendars: 

{{indent{Two are plugins, 
{{indent{http://www.rumsby.org/yatwa/#CalendarPlugin and {{indent{http://www.math.ist.utl.pt/~psoares/addons.html#PlasticCalendarPlugin, 

{{indent{and the other is a tool to help you make calendars in table format: 
{{indent{http://33ad.org/tools/gtdtwcal.php

''Tag clouds:'' 
They take your tags and visualize them for you, from most frequent to least frequent. Here is a good one by Clint Checkett: http://15black.bluedepot.com/twtests/tagcloud.htm#%5B%5BtagCloud%20plugin%5D%5D

''Colored boxes:'' 
I think these are cool, even though I haven't actually used them. http://www.math.ist.utl.pt/~psoares/addons.html#BoxesPlugin

''Light boxes'' 
Click on a photo, and the photo illuminates while the rest of the screen goes dark. Here is the link: http://solo.dc3.com/tw/#DC3.LightBox

''Check boxes'' 
http://www.TiddlyTools.com/#CheckboxPlugin

''Contact information plugins'' 
http://macrolinz.com/macrolinz/tiddlyware/macrolinz.html#ContactInfoPlugin

''Various foreign language translations'' of the TiddlyWiki buttons and menus. See my temporary fix for the Spanish language here: http://www.giffmex.org/twtutorialespanol.html#SpanishLingoGiffmex. There is a permanent version in the works.

I would be remiss if I didn't also mention the HUGE list of plugins at TiddlyTools. http://www.tiddlytools.com/

</pre>
</div>
<div title="Open the indexes of your hard drive, CD or USB files from inside your TiddlyWiki" modifier="giffmex" modified="200708281258" created="200708232037" changecount="2">
<pre>If you save this ~TiddlyWiki file to your computer and then check out this tiddler, you will see buttons that allow you to access an index of your C, D, E, or F files. Why ever leave your ~TiddlyWiki again? Thanks to Morris Gray whose [[TW Help site|http://twhelp.tiddlyspot.com]] drew this to my attention.

|&lt;html&gt;&lt;FORM action=&quot;file:///c:/&quot; target=&quot;_blank&quot;&gt;&lt;INPUT type=submit value=&quot;c:\ drive&quot; name=&quot;button&quot; class=&quot;btn&quot; name=submit2&gt;&lt;/FORM&gt;&lt;/html&gt;|&lt;html&gt;&lt;FORM action=&quot;file:///d:/&quot; target=&quot;_blank&quot;&gt;&lt;INPUT type=submit value=&quot;d:\ drive&quot; name=&quot;button&quot; class=&quot;btn&quot; name=submit2&gt;&lt;/FORM&gt;&lt;/html&gt;|&lt;html&gt;&lt;FORM action=&quot;file:///e:/&quot; target=&quot;_blank&quot;&gt;&lt;INPUT type=submit value=&quot;e:\ drive&quot; name=&quot;button&quot; class=&quot;btn&quot; name=submit2&gt;&lt;/FORM&gt;&lt;/html&gt;|&lt;html&gt;&lt;FORM action=&quot;file:///f:/&quot; target=&quot;_blank&quot;&gt;&lt;INPUT type=submit value=&quot;f:\ drive&quot; name=&quot;button&quot; class=&quot;btn&quot; name=submit2&gt;&lt;/FORM&gt;&lt;/html&gt;|</pre>
</div>
<div title="PageTemplate" modifier="churu1" modified="200707041845" created="200702101511" changecount="2">
<pre>&lt;!--{{{--&gt;
&lt;div class='header' macro='gradient vert [[ColorPalette::PrimaryLight]] [[ColorPalette::PrimaryMid]]'&gt;
        &lt;div class='headerShadow'&gt;
                &lt;span class='siteTitle' refresh='content' tiddler='SiteTitle'&gt;&lt;/span&gt;&amp;nbsp;
                &lt;span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'&gt;&lt;/span&gt;
        &lt;/div&gt;
        &lt;div class='headerForeground'&gt;
                &lt;span class='siteTitle' refresh='content' tiddler='SiteTitle'&gt;&lt;/span&gt;&amp;nbsp;
                &lt;span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'&gt;&lt;/span&gt;
        &lt;/div&gt;
&lt;/div&gt;
&lt;!-- horizontal MainMenu --&gt;
&lt;div id='topMenu' refresh='content' tiddler='MainMenu'&gt;&lt;/div&gt;
&lt;div id='sidebar'&gt;
        &lt;div id='sidebarOptions' refresh='content' tiddler='SideBarOptions'&gt;&lt;/div&gt;
        &lt;div id='sidebarTabs' refresh='content' force='true' tiddler='SideBarTabs'&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div id='displayArea'&gt;
        &lt;div id='messageArea'&gt;&lt;/div&gt;
        &lt;div id='tiddlerDisplay'&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;!--}}}--&gt;
</pre>
</div>
<div title="PeriodicTable" modifier="GiffMex" created="200612061823">
<pre>|Standard Periodic Table (ref. Wikipedia)|c
|| !1 | !2 |!| !3 | !4 | !5 | !6 | !7 | !8 | !9 | !10 | !11 | !12 | !13 | !14 | !15 | !16 | !17 | !18 |
|!1|bgcolor(#a0ffa0): @@color(red):H@@ |&gt;|&gt;|&gt;|&gt;|&gt;|&gt;|&gt;|&gt;|&gt;|&gt;|&gt;|&gt;|&gt;|&gt;|&gt;|&gt;||bgcolor(#c0ffff): @@color(red):He@@ |
|!2|bgcolor(#ff6666): Li |bgcolor(#ffdead): Be |&gt;|&gt;|&gt;|&gt;|&gt;|&gt;|&gt;|&gt;|&gt;|&gt;||bgcolor(#cccc99): B |bgcolor(#a0ffa0): C |bgcolor(#a0ffa0): @@color(red):N@@ |bgcolor(#a0ffa0): @@color(red):O@@ |bgcolor(#ffff99): @@color(red):F@@ |bgcolor(#c0ffff): @@color(red):Ne@@ |
|!3|bgcolor(#ff6666): Na |bgcolor(#ffdead): Mg |&gt;|&gt;|&gt;|&gt;|&gt;|&gt;|&gt;|&gt;|&gt;|&gt;||bgcolor(#cccccc): Al |bgcolor(#cccc99): Si |bgcolor(#a0ffa0): P |bgcolor(#a0ffa0): S |bgcolor(#ffff99): @@color(red):Cl@@ |bgcolor(#c0ffff): @@color(red):Ar@@ |
|!4|bgcolor(#ff6666): K |bgcolor(#ffdead): Ca ||bgcolor(#ffc0c0): Sc |bgcolor(#ffc0c0): Ti |bgcolor(#ffc0c0): V |bgcolor(#ffc0c0): Cr |bgcolor(#ffc0c0): Mn |bgcolor(#ffc0c0): Fe |bgcolor(#ffc0c0): Co |bgcolor(#ffc0c0): Ni |bgcolor(#ffc0c0): Cu |bgcolor(#ffc0c0): Zn |bgcolor(#cccccc): Ga |bgcolor(#cccc99): Ge |bgcolor(#cccc99): As |bgcolor(#a0ffa0): Se |bgcolor(#ffff99): @@color(green):Br@@ |bgcolor(#c0ffff): @@color(red):Kr@@ |
|!5|bgcolor(#ff6666): Rb |bgcolor(#ffdead): Sr ||bgcolor(#ffc0c0): Y |bgcolor(#ffc0c0): Zr |bgcolor(#ffc0c0): Nb |bgcolor(#ffc0c0): Mo |bgcolor(#ffc0c0): Tc |bgcolor(#ffc0c0): Ru |bgcolor(#ffc0c0): Rh |bgcolor(#ffc0c0): Pd |bgcolor(#ffc0c0): Ag |bgcolor(#ffc0c0): Cd |bgcolor(#cccccc): In |bgcolor(#cccccc): Sn |bgcolor(#cccc99): Sb |bgcolor(#cccc99): Te |bgcolor(#ffff99): I |bgcolor(#c0ffff): @@color(red):Xe@@ |
|!6|bgcolor(#ff6666): Cs |bgcolor(#ffdead): Ba |bgcolor(#ffbfff):^^*1^^|bgcolor(#ffc0c0): Lu |bgcolor(#ffc0c0): Hf |bgcolor(#ffc0c0): Ta |bgcolor(#ffc0c0): W |bgcolor(#ffc0c0): Re |bgcolor(#ffc0c0): Os |bgcolor(#ffc0c0): Ir |bgcolor(#ffc0c0): Pt |bgcolor(#ffc0c0): Au |bgcolor(#ffc0c0): @@color(green):Hg@@ |bgcolor(#cccccc): Tl |bgcolor(#cccccc): Pb |bgcolor(#cccccc): Bi |bgcolor(#cccc99): Po |bgcolor(#ffff99): At |bgcolor(#c0ffff): @@color(red):Rn@@ |
|!7|bgcolor(#ff6666): Fr |bgcolor(#ffdead): Ra |bgcolor(#ff99cc):^^*2^^|bgcolor(#ffc0c0): Lr |bgcolor(#ffc0c0): Rf |bgcolor(#ffc0c0): Db |bgcolor(#ffc0c0): Sq |bgcolor(#ffc0c0): Bh |bgcolor(#ffc0c0): Hs |bgcolor(#ffc0c0): Mt |bgcolor(#ffc0c0): Ds |bgcolor(#ffc0c0): Rg |bgcolor(#ffc0c0): @@color(green):Uub@@ |bgcolor(#cccccc): Uut |bgcolor(#cccccc): Uuq |bgcolor(#cccccc): Uup |bgcolor(#cccccc): Uuh |bgcolor(#fcfecc): @@color(#cccccc):Uus@@ |bgcolor(#ecfefc): @@color(#cccccc):Uuo@@ |

| !Lanthanides^^*1^^|bgcolor(#ffbfff): La |bgcolor(#ffbfff): Ce |bgcolor(#ffbfff): Pr |bgcolor(#ffbfff): Nd |bgcolor(#ffbfff): Pm |bgcolor(#ffbfff): Sm |bgcolor(#ffbfff): Eu |bgcolor(#ffbfff): Gd |bgcolor(#ffbfff): Tb |bgcolor(#ffbfff): Dy |bgcolor(#ffbfff): Ho |bgcolor(#ffbfff): Er |bgcolor(#ffbfff): Tm |bgcolor(#ffbfff): Yb |
| !Actinides^^*2^^|bgcolor(#ff99cc): Ac |bgcolor(#ff99cc): Th |bgcolor(#ff99cc): Pa |bgcolor(#ff99cc): U |bgcolor(#ff99cc): Np |bgcolor(#ff99cc): Pu |bgcolor(#ff99cc): Am |bgcolor(#ff99cc): Cm |bgcolor(#ff99cc): Bk |bgcolor(#ff99cc): Cf |bgcolor(#ff99cc): Es |bgcolor(#ff99cc): Fm |bgcolor(#ff99cc): Md |bgcolor(#ff99cc): No |

*Chemical Series of the Periodic Table
**@@bgcolor(#ff6666): Alkali metals@@
**@@bgcolor(#ffdead): Alkaline earth metals@@
**@@bgcolor(#ffbfff): Lanthanides@@
**@@bgcolor(#ff99cc): Actinides@@
**@@bgcolor(#ffc0c0): Transition metals@@
**@@bgcolor(#cccccc): Poor metals@@
**@@bgcolor(#cccc99): Metalloids@@
**@@bgcolor(#a0ffa0): Nonmetals@@
**@@bgcolor(#ffff99): Halogens@@
**@@bgcolor(#c0ffff): Noble gases@@

*State at standard temperature and pressure
**those in @@color(red):red@@ are gases
**those in @@color(green):green@@ are liquids
**those in black are solids
</pre>
</div>
<div title="Printing from a TiddlyWiki file" modifier="giffmex" modified="200708231854" created="200612082244" changecount="4">
<pre>Printing from a ~TiddlyWiki file is just like printing any webpage using the print function of your browser. Wow, that was easy to explain! For an extra tip, try this:

[[Printing just tiddler titles and text without all the TiddlyWiki stuff around it]]
</pre>
</div>
<div title="Printing just tiddler titles and text without all the TiddlyWiki stuff around it" modifier="giffmex" created="200708231853" changecount="2">
<pre>You may find you don't want to print your file's ''header'', ''main menu'', the right hand ''sidebar'', or elements within the tiddlers such as its ''subtitle, buttons toolbar, and tags''. If so, well, here is your first chance to foray into the world of ~TiddlyWiki behind-the-scenes code. Here are the instructions:
# Double-click this tiddler to go into edit mode..
# Each line below represents a part of ~TiddlyWiki that you don't want to print. Decide what you want and don't want to print, then insert the appropriate lines of code from below into the StyleSheet tiddler.
&lt;!--{{{--&gt;
@media print {#mainMenu {display: none ! important;}}
@media print {#topMenu {display: none ! important;}}
@media print {#sidebar {display: none ! important;}}
@media print {#messageArea {display: none ! important;}} 
@media print {#toolbar {display: none ! important;}}
@media print {.header {display: none ! important;}}
@media print {.tiddler .subtitle {display: none ! important;}}
@media print {.tiddler .toolbar {display; none ! important; }}
@media print {.tiddler .tagging {display; none ! important; }}
@media print {.tiddler .tagged {display; none ! important; }}
&lt;!--}}}--&gt;
3.  Open the StyleSheet tiddler and doubleclick on it to put it into edit mode. Paste the code you copied into it.

4. Close both tiddlers. Now use your browser's print preview function to see what will be printed. Did you remove all the elements that you wanted to? I hope so.
</pre>
</div>
<div title="Purple and gold color scheme" modifier="GiffMex" created="200612100532">
<pre>Background: #FFcc00
Foreground: #000
PrimaryPale: #FF8C69
PrimaryLight: #cc66ff
PrimaryMid: #440044
PrimaryDark: #410
SecondaryPale: #ffc
SecondaryLight: #fe8
SecondaryMid: #db4
SecondaryDark: #440044
TertiaryPale: #ffff99
TertiaryLight: #EEC591
TertiaryMid: #440044
TertiaryDark: #8B7355
</pre>
</div>
<div title="Romanos color scheme" modifier="GiffMex" created="200612231356">
<pre>Background: #ccaabb
Foreground: #000
PrimaryPale: #eeaaff
PrimaryLight: #ff0033
PrimaryMid: #464544
PrimaryDark: #000
SecondaryPale: #ffc
SecondaryLight: #fe8
SecondaryMid: #db4
SecondaryDark: #841
TertiaryPale: #eeaaff
TertiaryLight: #EEC591
TertiaryMid: #000
TertiaryDark: #8B7355</pre>
</div>
<div title="SalsaRecipes" modifier="giffmex" created="200708260234" changecount="1">
<pre>I have no salsa recipes for you. Try &quot;Salsa recipes for the rest of us.&quot;

</pre>
</div>
<div title="Save a TiddlyWiki file to your computer" modifier="churu1" modified="200707181755" created="200612031324" changecount="1">
<pre>~TiddlyWikis should not be saved to your computer using the conventional &quot;save&quot; methods. To save this ~TiddlyWiki to your computer, go to the menu above, {{italic{right-click}}} where it says &quot;save this file&quot;, and select &quot;save target as&quot; or &quot;save link as&quot;. Give the file whatever name you want to give it, and save it in a convenient place on your computer.

After you do this, then close your browser, and open your saved version of the document from Start button &gt; Documents. Your saved version will have the name you just gave it. 

! Customizing your newly saved ~TiddlyWiki file
# ''Change the SiteTitle and SiteSubtitle Tiddlers'' to reflect the content of the Tiddly you are creating. Your new title and subtitle will appear in the header at the top.
# ''Open the MainMenu Tiddler'', doubleclick on it, and remove any undesired items. Then add items to the main menu with double brackets. Example: {{{[[Car maintenance]]}}}
# If you want certain Tiddlers to appear every time you open the file, go to [[DefaultTiddlers]] and edit it to include the Tiddlers you want to appear at startup.
# Also you will definitely want to [[Decide on saving options]].


</pre>
</div>
<div title="SideBarTabs" modifier="churu1" modified="200706041515" created="200706041510">
<pre>&lt;&lt;tabs txtMainTab Timeline Timeline TabTimeline All 'All tiddlers' TabAll Tags 'All tags' TabTags More 'More lists' TabMore&gt;&gt;</pre>
</div>
<div title="Simple instructions for BidiX's UploadPlugin" modifier="giffmex" modified="200803101359" created="200803101327" changecount="10">
<pre>The great ~BidiX himself helped me create these simple instructions for his plugin!
#''Import the plugin and its friends.'' In your ~TiddlyWiki file, go to the backstage section and import the following tiddlers from http://tiddlywiki.bidix.info/
##~PasswordOptionPlugin
##~UploadPlugin
##store.php
#''Save changes'' to your file ''and reload'' / refresh your browser.
#''Create a store.php file.'' Open the store.php tiddler in your file and copy its contents. In Notepad, or whatever program you use to create webpages, paste the contents you've copied, and save the file as store.php. Be sure your program hasn't added any extensions such as .html, etc. The file should be called 'store' and its extension should be .php.
#''Set your username and password.'' In the store.php file, add your username(s) and password(s). Do this by going to the line {{{$USERS = array( '~UserName1'=&gt;'Password1', etc) and replacing Username1 with your username, and Password1 with your password. Be sure to leave all the punctuation and code, such as the single quotes, intact. Save your file.
#''Upload store.php.'' Use your FTP client (the program you use to upload files to your website - I use ~FileZilla) to upload store.php to the directory (folder) where you are going to put your ~TiddlyWiki file. If it's been uploaded correctly, you should be able to open your file from your browser (e.g. &quot;http://www.giffmex.org/experiments/store.php&quot;) and see Bidix's message.
#''Go to the Upload options panel.'' Now go to your ~TiddlyWiki file and in the backstage area at the top you should be able to see an 'upload' button. Click it.
#''Fill in the Upload options panel.'' 
##Set the same username and password that you placed in your store.php file
##Add the url of your store.php file (e.g., http://www.giffmex.org/experiments/store.php)
##Leave the Relative directory blank, and it will use default settings
##For filename, add the filename of the ~TiddlyWiki you are uploading
##If you have created a special directory on your site for backups, enter it in the Relative Directory for backups line. You don't add the entire url, just the name of the directory.
##Decide whether you want the ~UploadLog tiddler in your file to display the new logging data every time you save changes to the web, and check the box accordingly.
##Decide how many lines of data you want to appear in ~UploadLog, or leave it at a default of 10.
#''Click 'Upload' in the Upload with options panel.'' There will be a delay as your file is uploaded, but a message area should appear saying that your file is saved and about to upload. When done it should say 'Main ~TiddlyWiki file uploaded'. You are done!
#''Upload to your heart's content.'' Now, every time you want to upload the changes from your local file to the file on your website, go to the upload section of the backstage area, be sure your username and password are correct, and hit the upload button. That's it!

</pre>
</div>
<div title="SiteSubtitle" modifier="Schlanger" modified="200805050859" created="200612030310" tags="tutorial script" changecount="6">
<pre>Busting his guts to make things work</pre>
</div>
<div title="SiteTitle" modifier="Schlanger" modified="200805050857" created="200612031549" changecount="1">
<pre>Schlanger's Wiki</pre>
</div>
<div title="Slate 'Batman' color scheme" modifier="GiffMex" created="200612231355">
<pre>Background: #cccccc
Foreground: #000
PrimaryPale: #999999
PrimaryLight: #667788
PrimaryMid: #334444
PrimaryDark: #000
SecondaryPale: #ffc
SecondaryLight: #fe8
SecondaryMid: #db4
SecondaryDark: #555566
TertiaryPale: #999999
TertiaryLight: #EEC591
TertiaryMid: #000
TertiaryDark: #8B7355</pre>
</div>
<div title="Slider macros" modifier="GiffMex" modified="200703070406" created="200702221356">
<pre>Sliders are macros that create expandable and collapsible text, such as dropdown menus or information you only want exposed when the user clicks on it.

For the power version of sliders, you might need the Nested Sliders plugin ([[here is the link|http://www.tiddlytools.com/#NestedSlidersPlugin]]). Nevertheless, slider macros are nice easy solutions for simple expandable text. Below is an example of a slider. Click on it to see the items that appear:

&lt;&lt;slider fortabTags TabTags TabTags&gt;&gt;

The ''syntax'' for the slider macro above looks like this:

{{{&lt;&lt;slider fortabTags TabTags TabTags&gt;&gt;}}}

''There are four elements to the syntax,'' enclosed by double angle brackets, each divided by a space:
#The word 'slider' so that ~TiddlyWiki knows what kind of macro it is
#A name for your slider so that ~TiddlyWiki distinguishes it from other sliders.
#The name of the Tiddler that you want to open by clicking on the slider. Clicking the macro above opens the tiddler that lists all the tags in this ~TiddlyWiki file.
#The label for your slider - in other words, the text you want to appear in your slider box. For example, you could change the slider above to say 'Spaghetti'.

''You can customize the look of your slider with some knowledge of CSS.''
For example, ocat has created a nice custom slider that uses gray horizontal three-dimensional bars rather than a gold box. Below is an image of his customization with the top bar opening the GettingStarted tiddler.

[img[http://www.giffmex.org/images/ocat.GIF]]

If you want to try out this style on a slider, add the text below to your StyleSheet Tiddler:

/*{{{*/
/*AccordionEffect, Designed by oc ( http://b-oo-k.net/blog/ ). */

.viewer .button{ display: block; color: #fff; text-align: left;
font-weight: bold;
border-top: solid 1px #bbb;
border-left: solid 1px #bbb;
border-right: solid 1px #888;
border-bottom: solid 1px #888;
background: #999;
margin-left: -0.3em;
padding: 0 1px 1px 20px;
}

.viewer .button:hover{
border-top: solid 1px #777;
border-left: solid 1px #777;
border-right: solid 1px #bbb;
border-bottom: solid 1px #bbb;
background: #888;
padding: 1px 0 0 21px;
}

/*}}}*/




</pre>
</div>
<div title="Some great &quot;power&quot; plugins" modifier="giffmex" modified="200708251531" created="200703051751" changecount="5">
<pre>These plugins are for extra ~TiddlyWiki mileage. They increase your filesize significantly, but they also add significantly to your file's capabilities.

!Favorites from [[Abego Extensions|http://tiddlywiki.abego-software.de/]]
*''~ForEachTiddlerPlugin'' lets you sort tiddlers and portions of tiddlers in many clever and helpful ways. I use it to index tags and tiddler titles. See [[Advanced ideas for tags]].
*''~FormTiddlerPlugin'' and ''~DataTiddlerPlugin'' work together to [[Create forms with editable fields]].
*The ''~IncludePlugin'' allows you to create a portal TW that accesses tiddlers from multiple other TiddlyWiki files as read-only tiddlers. Very nice for having a lot of data in one file without bloating the file.

!Favorites from [[Lewcid Extensions|http://tw.lewcid.org/]]
*''~FontsizePlugin'' lets you adjust the font size in a tiddler with + and - buttons.
*''~IconMacro'' and ''~ToolbarIconsPluigin'' let you replace the usual TW features with icons.
*''~SplashScreenPlugin'' calls up an introductory message while users wait for your file to open.

!Favorites from [[TiddlyTools|http://www.tiddlytools.com/]]
*''~NestedSlidersPlugin'' is a plugin for more advanced sliders than you can get from the [[Slider macros]].
*''~SearchOptionsPlugin''. When this plugin is loaded and you do a search, you get a list of tiddlers containing the word you are searching for, rather than having all those tiddlers open. I don't have it installed here, because I want newbies to see what happens normally with searching. But I think this plugin is a must.
*''~CoreTweaks'' adds some helpful tweaks to the TW core.

!From [[MonkeyPirate (old beta site)|http://mptw-beta.tiddlyspot.com/]]
*''~SelectPaletteMacro'' is technically a macro, but I'm including it here. It lets you select from a dropdown list of color palettes, and automatically reconfigures your color scheme based on your selection.  

!From [[MonkeyPirate|http://mptw.tiddlyspot.com/]]
*''~TagglyTagging'' is a unique and handy way to use tags for organizing information. It's easier to use than it is to explain. 

!From [[Yann Perrin|http://yann.perrin.googlepages.com/twkd.html]]
*The ''easyFormat'' plugin is included in this tutorial. It allows you to format selected text by using a dropdown list. Edit this tiddler and click on &quot;Format&quot; to see which styles I have included in my adapted version of this plugin. 

!~LaunchApplicationPlugin
*The ''~LaunchApplicationsPlugin'' allows you to launch other programs (Outlook, Word, etc) from within ~TiddlyWiki. You can access it either [[here|http://www.Remotely-Helpful.com/TiddlyWiki/LaunchApplication.html]] or [[here|http://www.Remotely-Helpful.com/TiddlyWiki/LaunchApplication.html|]]. Be aware that there are security risks involved with some uses of this plugin. See Morris Gray's help file [[here|http://twhelp.tiddlyspot.com/#%5B%5BLaunch%20Applications%20Plugin%5D%5D]] for more information.
</pre>
</div>
<div title="SoupRecipes" modifier="giffmex" created="200708260235" changecount="1">
<pre>''Soup recipe''
*Buy Ramen Pride.
*Boil water and mix.

</pre>
</div>
<div title="Special formatting" modifier="giffmex" modified="200708271534" created="200708232158" changecount="3">
<pre>*[[Format text]]
*[[Format links and images]]
*[[Format lists]]
*[[Format tables]]
*[[Format blockquotes]]
*[[Miscellaneous formats]]
*[[Format ASCII symbols, foreign symbols, math symbols]]</pre>
</div>
<div title="Special note for users of Internet Explorer" modifier="GiffMex" modified="200703070405" created="200612031335">
<pre>If you are using Internet Explorer (IE) to open this document, please keep in mind the following items:
# For reading ~TiddlyWikis, any browser will do. But for editing a TW file or creating your own, Mozilla's free Firefox browser is optimal, whereas Internet Explorer will require you to take the steps below. You can download Firefox for free from [[here|http://www.mozilla.com/firefox/]]. It really is a great browser. Think about it!
# However, ''if you prefer to continue using Internet Explorer'', you will need version 6.x or higher, preferably version 7. If you want to upgrade to the latest version of IE, you can do so [[here|http://www.microsoft.com/windows/ie/downloads/default.mspx]]. 
# If you are using anything less than version 7, you will just need to ''enable active content''. Go to Tools &gt;&gt; Internet Options &gt;&gt; Advanced &gt;&gt; and check the boxes that say &quot;Allow active content to run on files in My Computer&quot;, &quot;Java logging enabled&quot; and &quot;Java Console enabled.&quot; Also you will want to click on the options link on the right-hand side of ~TiddlyWiki and check the &quot;Auto Save&quot; option.
# The ''only known issues with Internet Explorer'' itself have to do with gradients and series of consecutive spaces in Tiddler titles, neither of which should be on this version.
# ''If you have Micrososft XP Service Pack 2'', there is one hiccup. Internet Explorer Windows XP SP2 keeps track of html files saved from the internet, and stores saved changes in an 'Internet' zone regardless of attempts to rename or modify the file. But, in order to be able to save changes, ~TiddlyWiki needs to run in the 'My Computer' zone. The solution is to right-click on the ~TiddlyWiki html file and choose Properties. If the file is blocked, you'll see an 'Unblock' button on the resulting property sheet that removes the protection and allows the file to open in the 'My Computer' zone. Then open the file in Internet Explorer - it might put up its information bar asking you whether you want to run it. You need to 'Allow blocked content' to let ~TiddlyWiki do its stuff.</pre>
</div>
<div title="Special note on modifying shadow tiddlers" modifier="giffmex" modified="200708260150" created="200708260045" changecount="2">
<pre>Shadow tiddlers are the behind the scenes tiddlers found in the tiddler TabMoreShadowed and which appear in the &quot;Shadowed&quot; tab in the &quot;more&quot; section in the righthand sidebar tabs. Technically speaking, when you modify these tiddlers, you are not actually modifying them. You are creating a &quot;twin&quot; tiddler that overrides the original shadowed tiddler. 

So if you ever feel the need to revert to the default settings of a shadow tiddler such as StyleSheet or PageTemplate, all you have to do is open the tiddler and delete it. The &quot;twin&quot; tiddler you modified will be deleted and the original shadowed tiddler will return once again to take its place.</pre>
</div>
<div title="Strawberry color scheme" modifier="GiffMex" created="200612100533">
<pre>Background: #FFBCAD
Foreground: #000
PrimaryPale: #F67276
PrimaryLight: #FF6633
PrimaryMid: #A73853
PrimaryDark: #000
SecondaryPale: #ffc
SecondaryLight: #fe8
SecondaryMid: #db4
SecondaryDark: #841
TertiaryPale: #FFBCAD
TertiaryLight: #EEC591
TertiaryMid: #000
TertiaryDark: #8B7355 </pre>
</div>
<div title="StyleSheet" modifier="giffmex" modified="200708250041" created="200703252307" changecount="14">
<pre>/*{{{*/
/* horizontal main menu */

#displayArea { margin: 1em 15.5em 0em 1em; } /* use the full horizontal width */

#topMenu { background: [[ColorPalette::PrimaryMid]]; color: [[ColorPalette::PrimaryPale]]; padding: 0.2em 0.2em 0.2em 0.5em; border-bottom: 2px solid #000000; }

#topMenu br { display: none; }

#topMenu .button, #topMenu .tiddlyLink, #topMenu a { margin-left: 0.25em; margin-right: 0.25em; padding-left: 0.5em; padding-right: 0.5em; color: [[ColorPalette::PrimaryPale]]; font-size: 1.15em; }

#topMenu .button:hover, #topMenu .tiddlyLink:hover { background: [[ColorPalette::PrimaryDark]]; }

 .firstletter{ float:left; width:0.75em; font-size:400%; font-family:times,arial; line-height:60%; }

.viewer .FOO table tr.oddRow { background-color: #bbbbbb; }
.viewer .FOO table tr.evenRow { background-color: #fff; } 


/*Invisible table*/

.viewer .invisibletable table { 
border-color: white;
 }

.viewer .invisibletable table td { 
font-size: 1em;
font-family: Verdana;
border-color: white;
padding: 10px 20px 10px 0px;
text-align: left;
vertical-align: top;


.viewer .invisibletable table th { 
color: #005566;
background-color: white;
border-color: white;
font-family: Verdana;
font-size: 1.2em;
font-weight: bold;
padding: 10px 20px 10px 0px;
text-align: left;
vertical-align: top;


/* GIFFMEX TWEAKS TO STYLESHEETPRINT (so that nothing but tiddler title and text are printed) */


@media print {#mainMenu {display: none ! important;}}
@media print {#topMenu {display: none ! important;}}
@media print {#sidebar {display: none ! important;}}
@media print {#messageArea {display: none ! important;}} 
@media print {#toolbar {display: none ! important;}}
@media print {.header {display: none ! important;}}
@media print {.tiddler .subtitle {display: none ! important;}}
@media print {.tiddler .toolbar {display; none ! important; }}
@media print {.tiddler .tagging {display; none ! important; }}
@media print {.tiddler .tagged {display; none ! important; }}
@media print {#displayArea {margin: 1em 1em 0em 1em;}}
@media print {.pageBreak {page-break-before: always;}}

a.button{
 border: 0;



/*Color changes*/


#sidebarOptions input {
        border: 1px solid [[ColorPalette::TertiaryPale]];
}

#sidebarOptions .sliderPanel {
        background: [[ColorPalette::TertiaryPale]];
}

#sidebarOptions .sliderPanel a {
        border: none;
        color: [[ColorPalette::PrimaryMid]];
}

#sidebarOptions .sliderPanel a:hover {
        color: [[ColorPalette::Background]];
        background: [[ColorPalette::TertiaryPale]];
}

#sidebarOptions .sliderPanel a:active {
        color: [[ColorPalette::PrimaryMid]];
        background: [[ColorPalette::TertiaryPale]];
}

/*Makes sliders bold*/

.tuduSlider .button{font-weight: bold;
}

/* (2) Adjusts the color for all headlines so they are both readable and match my color schemes. */

h1,h2,h3,h4,h5 {
 color: #000;
 background: [[ColorPalette::TertiaryPale]];
}

.title {
color: [[ColorPalette::PrimaryMid]];
}

/* (2) Makes text verdana. */

body {
 font-family: verdana;
font-size: 9pt;
}

/* (4) Allows for Greek - one way */

   .greek {
      font-family: Palatino Linotype;
      font-style: normal;
      font-size: 150%;
   }

/* (5) Shortens the height of the Header */

.headerShadow {
 padding: 1.5em 0em 1em 1em;
}

.headerForeground {
 padding: 2em 0em 1em 1em;
}

/* (8) Makes ordered and unordered lists double-spaced between items but single-spaced within items. */

.viewer li {
   padding-top: 0.5em;
   padding-bottom: 0.5em;



/*Makes block quotes line-less*/

.viewer blockquote {
border-left: 0px;
margin-top:0em;
margin-bottom:0em; 
}

/* Cosmetic fixes that probably should be included in a future TW... */

.viewer .listTitle { list-style-type:none; margin-left:-2em; }
.editorFooter .button { padding-top: 0px; padding-bottom:0px; }

Important stuff. See TagglyTaggingStyles and HorizontalMainMenuStyles

[[Styles TagglyTagging]]
[[Styles HorizontalMainMenu]]

Just colours, fonts, tweaks etc. See MessageTopRight and SideBarWhiteAndGrey

body { 
  background: #eee; }
.headerForeground a { 
  color: #6fc;}
.headerShadow { 
  left: 2px; 
  top: 2px; }
.siteSubtitle { 
  padding-left: 1.5em; }

.shadow .title {
  color: #999; }

.viewer pre { 
  background-color: #f8f8ff; 
  border-color: #ddf }

.tiddler {
  border-top:    1px solid #ccc; 
  border-left:   1px solid #ccc; 
  border-bottom: 3px solid #ccc; 
  border-right:  3px solid #ccc; 
  margin: 0.5em; 
  background:#fff; 
  padding: 0.5em; 
  -moz-border-radius: 1em; }

#messageArea { 
  background-color: #eee; 
  border-color: #8ab; 
  border-width: 4px; 
  border-style: dotted; 
  font-size: 90%; 
  padding: 0.5em; 
  -moz-border-radius: 1em; }

#messageArea .button { text-decoration:none; font-weight:bold; background:transparent; border:0px; }

#messageArea .button:hover {background: #acd; }

.editorFooter .button { 
  padding-top: 0px; 
  padding-bottom:0px; 
  background: #fff;
  color: #000; 
  border-top:    1px solid #ccc; 
  border-left:   1px solid #ccc; 
  border-bottom: 2px solid #ccc; 
  border-right:  2px solid #ccc; 
  margin-left: 3px;
  padding-top: 1px;
  padding-bottom: 1px;
  padding-left: 5px;
  padding-right: 5px; }
  
.editorFooter .button:hover { 
  border-top:    2px solid #ccc; 
  border-left:   2px solid #ccc; 
  border-bottom: 1px solid #ccc; 
  border-right:  1px solid #ccc; 
  margin-left: 3px;
  padding-top: 1px;
  padding-bottom: 1px;
  padding-left: 5px;
  padding-right: 5px; }

.tagged {
  padding: 0.5em;
  background-color: #eee;
  border-top:    1px solid #ccc; 
  border-left:   1px solid #ccc; 
  border-bottom: 3px solid #ccc; 
  border-right:  3px solid #ccc; 
  -moz-border-radius: 1em; }

.selected .tagged {
  padding: 0.5em;
  background-color: #eee;
  border-top:    1px solid #ccc; 
  border-left:   1px solid #ccc; 
  border-bottom: 3px solid #ccc; 
  border-right:  3px solid #ccc; 
  -moz-border-radius: 1em; }

Clint's fix for weird IE behaviour
body {position:static;}
.tagClear{margin-top:1em;clear:both;}


/*}}}*/

/*{{{*/

/* text alignments */
.left
        { display:block;text-align:left; }
.center
        { display:block;text-align:center; }
.right        
        { display:block;text-align:right; }
.justify
        { display:block;text-align:justify; }
.indent
        { margin:0;padding:0;border:0;margin-left:2em; }
.floatleft
        { float:left; }
.floatright
        { float:right; }
.clear
        { clear:both; }
.wrap
        { white-space:normal; }
.nowrap
        { white-space:nowrap; }
.hidden
        { display:none; }
.span
        { display:span; }
.block
        { display:blockquote; }

/* font sizes */
.big
        { font-size:14pt;line-height:120% }
.medium
        { font-size:12pt;line-height:120% }
.normal
        { font-size:9pt;line-height:120% }
.small
        { font-size:8pt;line-height:120% }
.fine
        { font-size:7pt;line-height:120% }
.tiny
        { font-size:6pt;line-height:120% }
.larger
        { font-size:120%; }
.smaller
        { font-size:80%; }

/* font styles */
.bold
        { font-weight:bold; }
.italics
        { font-style:italics; }
.underline
        { text-decoration:underline; }

/* multi-column tiddler content (not supported in Internet Explorer) */
.twocolumns
        { display:block; -moz-column-count:2; -moz-column-gap:1em; -moz-column-width:50%;}
.threecolumns
        { display:block; -moz-column-count:3; -moz-column-gap:1em; -moz-column-width:33%}
.fourcolumns
        { display:block; -moz-column-count:4; -moz-column-gap:1em; -moz-column-width:25%}

/* borderless tables */
.borderless, .borderless table, .borderless td, .borderless tr, .borderless th, .borderless tbody
        { border:0 !important; margin:0 !important; padding:0 !important; }

/* thumbnail images (fixed-sized scaled images) */
.thumbnail img { height:5em !important; }

/* grouped content */
.outline
        { display:block; padding:1em; -moz-border-radius:1em; border:1px solid; }
.menubox
        { display:block; padding:1em; -moz-border-radius:1em; border:1px solid; background:#ccccff; color:#000; }
.menubox .button, .menubox .tiddlyLinkExisting, .menubox .tiddlyLinkNonExisting
        { color:#009 !important; }
.groupbox
        { display:block; padding:1em; -moz-border-radius:1em; border:1px solid; background:#ffe; color:#000; }
.groupbox a, .groupbox .button, .groupbox .tiddlyLinkExisting, .groupbox .tiddlyLinkNonExisting
        { color:#009 !important; }
.groupbox code
        { color:#333 !important; }
.borderleft
        { margin:0;padding:0;border:0;margin-left:1em; border-left:1px dotted; padding-left:.5em; }
.borderright
        { margin:0;padding:0;border:0;margin-right:1em; border-right:1px dotted; padding-right:.5em; }
.borderbottom
        { margin:0;padding:1px 0;border:0;border-bottom:1px dotted; margin-bottom:1px; padding-bottom:1px; }
.bordertop
        { margin:0;padding:0;border:0;border-top:1px dotted; margin-top:1px; padding-top:1px; }

/* compact form */
.smallform
        { white-space:nowrap; }
.smallform input, .smallform textarea, .smallform button, .smallform checkbox, .smallform radio, .smallform select
        { font-size:8pt; }

/* colors */
.green { color:#6f6 !important }
.red { color:#f66 !important }
.blue { color:#99f !important }

/*}}}*/</pre>
</div>
<div title="TW glossary" modifier="giffmex" modified="200708260039" created="200701191335" changecount="8">
<pre>|bgcolor(#dddddd):''Case-senstive search''|A function of ~TiddlyWiki whereby the user can search for a word or phrase with precise upper and lowercase specifications.|
|bgcolor(#dddddd):''Client-side''|A ~TiddlyWiki file that is edited offline by the user or client, hence &quot;On the client's side.&quot; These cannot be edited through the Internet when the file is located on a web server.|
|bgcolor(#dddddd):''CSS''|CSS is the computer code used to create custom style sheets. Style sheets are pages that control the look of html webpages. The style sheets for a ~TiddlyWiki file are internal. They are the three default style sheets [[StyleSheetColors]], [[StyleSheetLayout]], [[StyleSheetPrint]] and the one you use to override the other three, named simply [[StyleSheet]].&lt;br&gt;&lt;br&gt;To learn more about CSS, see [[here|http://www.htmldog.com/reference/cssproperties/]]. |
|bgcolor(#dddddd):''Default Tiddlers''|This is a tiddler that contains the tiddlers that are viewed when your file opens up. You can customize this tiddler or empty it out if you wish.|
|bgcolor(#dddddd):''HTML''|HTML is the computer language used to create webpages. A ~TiddlyWiki file is a modified HTML file.|
|bgcolor(#dddddd):''~JavaScript''|~JavaScript is a computer language used for special functions. It is made of up scripts or instructions that tell a webpage what to do under certain conditions. Java scripts are used to create and run many ~TiddlyWiki plugins.|
|bgcolor(#dddddd):''Macro''|See [[this tiddler|Macros]]|
|bgcolor(#dddddd):''~MainMenu''|The menu normally found on the left hand side of the screen. In the present file it is found in the header. It acts as a table of contents.|
|bgcolor(#dddddd):''Options panel''|The menu in the middle of the right hand menu. Sometimes it is hidden, and you can open it by clicking &quot;options &gt;&gt;&quot;.|
|bgcolor(#dddddd):''Permalink''|A ~TiddlyWiki button on the tiddlers that places the exact url of the tiddler in your browser search window. Helpful for placing links to a specific tiddler in e-mails and webpages. |
|bgcolor(#dddddd):''Permaview''|A ~TiddlyWiki option on the right hand menu that places the exact url of the present file when all the currently open tiddlers are open. Helpful for placing links to a specific combination of tiddlers in e-mails and webpages.|
|bgcolor(#dddddd):''Plugin''|A tiddler with a special code that adds extra functionality to a ~TiddlyWiki file. For more information, see [[this tiddler|How to install a plugin]]|
|bgcolor(#dddddd):''Server-side''|A ~TiddlyWiki file that is able to be edited while the file is located on a web server. This gives users the ability to edit it from any online computer. |
|bgcolor(#dddddd):''Shadow tiddlers''|Tiddlers that work in the background and affect the functioning of ~TiddlyWiki. See also [[Special note on modifying shadow tiddlers]]|
|bgcolor(#dddddd):''~SideBar''|The options at the top of the right hand menu.|
|bgcolor(#dddddd):''Slider''|An expandable-and-collapsible menu that you can place in any tiddler. See [[here (external link)|]] for a helpful showcase of four sliders and what to use them for.|
|bgcolor(#dddddd):''~StyleSheet''|A tiddler with the code that controls the appearance, layout and printing properties of a ~TiddlyWiki file. For more information, see [[this tiddler|Messing with StyleSheets]]|
|bgcolor(#dddddd):''systemConfig tag''| A tag that tells ~TiddlyWiki that the tiddler contains Javascript that should be run when the file opens. Usually appended to plugins.|
|bgcolor(#dddddd):''Tabs''|The menu at the bottom of the right hand menu. They are called tabs because they have what looks like the tabs on file folders protruding from the top of them. |
|bgcolor(#dddddd):''Tag''|A label that a user adds to a tiddler to index it according to topic. In other words, the tag is the topic or category by which you want to index and search for your tiddler. This provides an extra way to find tiddlers, because the user can go to the Tags tab in the right hand tabbed menu and browse his or her personal list of tags. See [[this tidder|through tags]]|
|bgcolor(#dddddd):''Tiddler''|A 'window' containing text or code in ~TiddlyWiki. Tiddlers are like 3x5 note cards to which the user adds content and links with other tiddlers using tags and hyperlinks. For more on tiddlers, see [[this tiddler|Anatomy of a Tiddler]]. |
|bgcolor(#dddddd):''~WikiWord''|See [[this tiddler|WikiWord]]|





</pre>
</div>
<div title="The SelectPaletteMacro" modifier="giffmex" created="200708260057" changecount="1">
<pre>Simon Baird has a wonderful macro that displays a dropdown menu of various color palettes. You select the palette you desire from the list, and the colors of your ~TiddlyWiki instantly change!

Get the ~SelectPaletteMacro [[here|http://mptw-beta.tiddlyspot.com/#SelectPaletteMacro]].</pre>
</div>
<div title="The header" modifier="GiffMex" modified="200703070403" created="200612241303">
<pre>The header contains the Title and Subtitle of your document. After downloading a ~TiddlyWiki file to your computer, you can alter these by opening and editing the Tiddlers SiteTitle and SiteSubtitle.

[img[http://www.giffmex.org/images/headerimage.GIF]]</pre>
</div>
<div title="The macro for tabbed lists" modifier="tiddlyvault" modified="200710140312" created="200706041506" changecount="4">
<pre>Tabbed lists, like the ones to the right listing all tiddlers and tags, are a macro. Here is what the macro looks like:
//{{{
&lt;&lt;tabs identifier tabLabel tabName Tiddlername&gt;&gt;
//}}}
*You leave &quot;tabs&quot; alone. That tells ~TiddlyWiki that this macro is a tabs macro.
*Replace &quot;identifier&quot; with the name that you want to give your //macro//. 
*Replace &quot;tabLabel&quot; with the text you want to appear on the tab.
*Replace &quot;tabName&quot; with the name you want to give to that tab.
*Replace &quot;Tiddlername&quot; with the tiddler whose contents will appear when you open that tab.
*For each new tab, insert &quot;tabLabel tabName Tiddlername&quot; within the macro and edit to reflect the contents of the new tab. 

Here is a sample tabbed list, and its code. I have placed the sections of the code on separate lines to make it easier to see the separate sections.

&lt;&lt;tabs salsas &quot;Salsa recipes&quot; &quot;Salsa recipes&quot; SalsaRecipes &quot;Soup recipes&quot; &quot;Soup recipes&quot; SoupRecipes&gt;&gt;
{{{
&lt;&lt;tabs salsas 
&quot;Salsa recipes&quot; &quot;Salsa recipes&quot; SalsaRecipes 
&quot;Soup recipes&quot; &quot;Soup recipes&quot; SoupRecipes&gt;&gt;
}}}</pre>
</div>
<div title="The main menu" modifier="GiffMex" modified="200703071352" created="200612241338">
<pre>The ~MainMenu is basically a table of contents by which you can quickly access the main contents of your file. You can edit any and all aspects of the ~MainMenu by opening and editing the MainMenu Tiddler. Below is a main menu of another of my ~TiddlyWiki documents ([[link here|http://www.giffmex.org/philemontiddlywiki.html]]). In the present tutorial file, the ~MainMenu has been placed in the header to allow more room for the text.

[img[http://www.giffmex.org/images/mainmenu.GIF]]</pre>
</div>
<div title="The right hand menu" modifier="churu1" modified="200707050346" created="200612241349" changecount="2">
<pre>What I call the right hand menu or sidebar menu is filled with tools. 

!The top of the menu
At the top of the right hand menu there are several features:
[img[http://www.giffmex.org/images/rhtop.GIF]]

!Interface options
Clicking the ''options &gt;&gt;'' link opens up the Interface Options menu:
[img[http://www.giffmex.org/images/interfaceoptions.GIF]]

(Note: in version 2.2, Plugin Manager and Import Tiddlers have been moved to the backstage area.)
!Lists of Tiddlers and tags
At the bottom of the right hand menu are lists of all the Tiddlers and tags in your ~TiddlyWiki file:

[img[http://www.giffmex.org/images/tidlist.GIF]]</pre>
</div>
<div title="TiddlySnip Firefox addon" modifier="giffmex" created="200708260029" changecount="1">
<pre>~TiddlySnip is a Firefox add-on that allows you to quickly &quot;snip&quot; selected text from webpages and paste it directly into a ~TiddlyWiki file. You can even specify categories and when you snip the text, and ~TiddlySnip will add a tag with the category you specify. Check it out at http://tiddlysnip.com/#About. 

</pre>
</div>
<div title="TiddlyThemes" modifier="giffmex" modified="200708232142" created="200708232141" changecount="2">
<pre>Not too crazy about the default colors and layout, but you're not ready to tinker behind the scenes with your ~TiddlyWiki? Try out one of the many themes  at http://tiddlythemes.com. They even have themes that look like blogs.

</pre>
</div>
<div title="TiddlyVault: your source for macros, plugins and themes" modifier="giffmex" modified="200709011827" created="200709011825" changecount="2">
<pre>Want a calendar plugin? A tag cloud plugin? A plugin for an address book? There is now a growing index of over 100 ~TiddlyWiki plugins, macros, scripts and themes, organized by categories. Check it out at http://www.giffmex.org/twvault.html.

</pre>
</div>
<div title="Tips for making Mozilla Firefox run faster" modifier="tiddlyvault" created="200710011427" changecount="1">
<pre>Why reinvent the wheel? Morris Gray has a number of tips [[here|http://tiddlyspot.com/twhelp/#%5B%5BFireFox%20Tips%5D%5D]] at his excellent tutorial.</pre>
</div>
<div title="Tips for speeding up performance on large TiddlyWikis" modifier="tiddlyvault" modified="200709191212" created="200707041832" changecount="15">
<pre>*''Disable the animations.'' It may be cute to have tiddlers open with cool animation, but the animation slows performance way down. Open the OptionsPanel and uncheck ~EnableAnimations.
*''Save less often.'' Uncheck 'Autosave' and 'Save backups', and save manually every few minutes instead of saving every single change.
*''Hide the growing tabbed lists in your SideBarTabs.'' Every time you create a new tiddler, TabAll and TabTimeline have to refresh to add the new tiddler's title. As the list of tiddlers gets longer, these tabs take longer to refresh, slowing down your ~TiddlyWiki. There are three ways I know of to hide these lists:
##The easiest way is to click on the More tab. The lists in More don't grow like the other lists. This should be a good enough solution for most users.
##You can use the ToggleRightSidebar plugin to hide the entire right hand sidebar of your ~TiddlyWiki screen. This plugin happens to be included in this tutorial.
##I don't necessarily recommend the following for newer users, but to remove the right hand sidebar tabs from view altogether, open PageTemplate and delete the following:
&lt;!--{{{--&gt;
        &lt;div id='sidebarTabs' refresh='content' force='true' tiddler='SideBarTabs'&gt;&lt;/div&gt;
&lt;!--}}}--&gt;
*''Michael Cimino offered this suggestion by e-mail:''
&quot;...(1) add the following to the end of SidebarOptions: {{{&lt;&lt;slider chkSliderContents [[TabContents]] 'contents »' 'contents'&gt;&gt;}}}
(2) cut out the text from SidebarTabs and save it, leaving it blank.
(3) create a new tiddler TabContents and paste the text that used to be in SidebarTabs, which should be:
{{{&lt;&lt;tabs txtMainTab &quot;Timeline&quot; &quot;Timeline&quot; TabTimeline &quot;All&quot; &quot;All tiddlers&quot; TabAll &quot;Tags&quot; &quot;All tags&quot; TabTags &quot;More&quot; &quot;More lists&quot; TabMore&gt;&gt;}}}

Now, you can collapse that area of the Sidebar whenever you wish, and its state will be saved in a cookie! I hope this helps!&quot;</pre>
</div>
<div title="Toggle the right hand menu" modifier="giffmex" modified="200708232105" created="200708232104" changecount="3">
<pre>Look at our top menu. The last item says, (depending on what you have or haven't done with it), either &quot;Hide Sidebar&quot;, &quot;Need more room?&quot; or &quot;Need the sidebar?&quot; When you click on those words, the right hand sidebar disappears and reappears. This is done with the ToggleRightSidebar script from ~TiddlyTools. See [[here|http://www.TiddlyTools.com/#ToggleRightSidebar]] for more details. ~TiddlyTools also offers a ~ToggleLeftSidebar script for ~TWs with left hand main menus.

</pre>
</div>
<div title="ToggleRightSidebar" modifier="churu1" modified="200706041426" created="200607182328" tags="script includeNew MenuPackage">
<pre>/%
|Name|ToggleRightSidebar|
|Source|http://www.TiddlyTools.com/#ToggleRightSidebar|
|Version|0.0.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements &lt;&lt;br&gt;&gt;and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|script|
|Requires||
|Overrides||
|Description||
%/&lt;script label=&quot;show/hide right sidebar&quot;&gt;
        var show=document.getElementById('sidebar').style.display=='none';
        if (!show) {
                document.getElementById('sidebar').style.display='none';
                var margin='1em';
        }
        else {
                document.getElementById('sidebar').style.display='block';
                var margin=config.options.txtDisplayAreaRightMargin?config.options.txtDisplayAreaRightMargin:&quot;&quot;;
        }
        place.innerHTML=(show?&quot;Need More Room?&quot;:&quot;Need the Sidebar?&quot;); // SET LINK TEXT
        place.title=show?&quot;hide sidebar&quot;:&quot;show sidebar&quot;; // SET TOOLTIP
        document.getElementById('displayArea').style.marginRight=margin;
        config.options.chkShowRightSidebar=show;
        saveOptionCookie('chkShowRightSidebar');
        var sm=document.getElementById(&quot;storyMenu&quot;); if (sm) config.refreshers.content(sm);
        return false;
&lt;/script&gt;&lt;script&gt;
        if (config.options.chkShowRightSidebar==undefined)
                config.options.chkShowRightSidebar=true;
        if (!config.options.txtDisplayAreaRightMargin||!config.options.txtDisplayAreaRightMargin.length)
                config.options.txtDisplayAreaRightMargin=&quot;15em&quot;;
        var show=config.options.chkShowRightSidebar;
        document.getElementById('sidebar').style.display=show?&quot;block&quot;:&quot;none&quot;;
        document.getElementById('displayArea').style.marginRight=show?config.options.txtDisplayAreaRightMargin:&quot;1em&quot;;
        place.lastChild.innerHTML=(show?&quot;Hide Sidebar;&quot;:&quot;Show Sidebar;&quot;); // SET LINK TEXT
        place.lastChild.title=show?&quot;hide sidebar&quot;:&quot;show sidebar&quot;; // SET TOOLTIP
        place.lastChild.style.fontWeight=&quot;normal&quot;;
&lt;/script&gt;</pre>
</div>
<div title="Top menus versus left hand main menus" modifier="GiffMex" modified="200703071351" created="200702221441">
<pre>If you compare this tutorial with Jeremy Ruston's original ~TiddlyWiki file ([[here|http://www.tiddlywiki.com]]), you will notice that his file has the ~MainMenu in a left-hand sidebar, while I have the ~MainMenu built into the header. Mine is called a ~TopMenu. Top menus have the advantage of saving horizontal space. Tiddlers can get pretty squished inbetween a left-hand ~MainMenu and a right hand options sidebar. So to free up room for wider tiddlers, I moved the menu to the top.

The way I see it, there are three things you might want to know about moving the ~MainMenu from one place to another:

[[How do I remove the top menu and have a normal left-hand menu?]]
[[How do I remove the left-hand menu of a typical TiddlyWiki and create a top menu for it?]]
[[Can I have both a left-hand menu AND a top menu, each with different items?]]

</pre>
</div>
<div title="Use IFrames to embed other webpages in your TiddlyWiki" modifier="giffmex" modified="200708251229" created="200708242346" changecount="13">
<pre>~IFrames are HTML elements that allow you to have a frame containing a different document within a Tiddler. 

''The code'' to add to your tiddler:
{{{
&lt;html&gt;&lt;div align=&quot;center&quot;&gt;&lt;iframe src=&quot;WEBPAGEURLHERE&quot; frameborder=&quot;0&quot; width=&quot;100%&quot; height=&quot;600&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;/html&gt;
}}}
You can. of course, adjust the webpage url, the frame border, the width and the height with this code. You can also have an iframe of an html document or an image that is stored in your local hard drive. Instead of the webpage url you would substitute your file pathname, something like this:
{{{
&quot;file:///c:/My%20Documents/Folder/document.html&quot;
}}}
Here is an ~IFrame of our online bio page. Try clicking on a link to see what happens.
&lt;html&gt;&lt;div align=&quot;center&quot;&gt;&lt;iframe src=&quot;http://www.giffmex.org/aboutus/giffordsbio.html&quot; frameborder=&quot;0&quot; width=&quot;100%&quot; height=&quot;600&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;/html&gt;

</pre>
</div>
<div title="Version 2.2" modifier="churu1" modified="200706081409" created="200706081341" changecount="21">
<pre>!What does it include?
Version 2.2 is the latest version of ~TiddlyWiki. It has a &quot;backstage&quot; area with extra functions. As Jeremy Ruston explains [[here|http://www.tiddlywiki.com/#BackstageArea]], the idea of the backstage is to make some of the advanced sidebar options available to power users while eliminating the clutter and confusion for newer users who just want to read a ~TiddlyWiki. For example, some authors want to drastically change the page layout of their ~TiddlyWiki, but still want quick access to advanced features. The backstage gives them a way to have their cake and eat it too.

This tutorial is now upgraded to version 2.2.1. You can check out the backstage clicking &quot;backstage&quot; in the far upper right corner of the screen. This calls up a hidden menu with the following 5 options:
*''save'' - saves your ~TiddlyWiki just as you would by clicking &quot;Save changes&quot; in the right hand sidebar options.
*''sync'' - allows you to sync the changes in your ~TiddlyWiki file with other ~TiddlyWiki files on your hard drive and your server. I will try to write more about this as I play with it more myself.
*''import'' - this is the new location for ImportTiddlers, formerly available on the right hand options sidebar. This is a macro that allows you to import tiddlers from other ~TiddlyWiki files on your hard drive or on the Internet.
*''tweak'' - this is the new location for AdvancedOptions. This is still available on the right hand options side bar, but the backstage appears to be its new home. AdvancedOptions gives you, well, advanced options for saving, searching, editing and other functions. This is a good place to start when you save a new ~TiddlyWiki file and are fairly particular about how you want it to function.
*''plugins'' - this is the new location for Manage Plugins. You can see a list of your plugins. For more on plugins, see the following tiddlers if you haven't already: 
**[[How to install a plugin]]
**[[My favorite &quot;goodies&quot; plugins]]
** [[Some great &quot;power&quot; plugins]]
For more on version 2.2, see Jeremy Ruston's explanation [[here|http://www.tiddlywiki.com/#Release2.2]].
!How do I upgrade?

Jeremy Ruston's helpful instructions for upgrading to the latest version can be found [[here|http://www.tiddlywiki.com/#HowToUpgrade]] (external link to www.tiddlywiki.com). 

@@Please note!@@ In earlier versions of this tutorial I erroneously advised you to make style changes to your StyleSheetLayout, StyleSheetPrint and StyleSheetColors. This was incorrect. All style changes should actually be done on the StyleSheet tiddler. This will override the above three default stylesheets. The reason I'm telling you this is that if you have made changes to the 3 default stylesheets, you may find that the backstage doesn't work right. If that is the case, all you need to do is delete your three default stylesheets and save changes, and you should be okay. However, before you do, you should transfer all your style changes to the StyleSheet tiddler. I apologize for any inconvenience that my misinformation has caused you.

If you find any other difficulties in upgrading, please consult the TiddlyWiki Google Group at http://groups.google.com/group/TiddlyWiki. Please do a search for your problem first, before posting your problem in a brand new thread. You may find someone has already asked about your problem and that the solutions are already there waiting for you.

</pre>
</div>
<div title="What are TiddlyWikis being used for?" modifier="churu1" modified="200706041447" created="200612030320">
<pre>!~TiddlyWiki in Action
The best way to see what ~TiddlyWikis are being used for is to visit &quot;~TiddlyWiki in Action&quot;, our very own showcase of ~TiddlyWikis around the world. There are screenshots, brief descriptions and links to many ~TiddlyWikis, including some listed below. The link is: http://giffmex.tiddlyspot.com.

! List of ideas

|bgcolor(#dddddd):''To-do lists and project task management''|For example, there are several versions adapted to function according to the GTD (“Getting Things Done”) to-do list system. Here are two examples: [[GTD|http://shared.snapgrid.com/index.html]] and [[d3|http://www.dcubed.ca/]]. My own to-do list system can be found [[here|http://www.giffmex.org/tiddlydu.html]]|
|bgcolor(#dddddd):''Blogs and journals''|Others use them as blogs and journals, since one feature of most ~TiddlyWikis is clicking a button to create a new, automatically dated journal entry.|
|bgcolor(#dddddd):''Course packets''|Some teachers are using them to give students information packets that they can easily edit and take notes on. TW is really a good way of taking notes. See these philosophy notes [[here|http://parmenides.objectis.net/reason/]]|
|bgcolor(#dddddd):''Organizing research notes''|Eclectic Bill is using it to organize his research notes for his Ph. D. [[see here|http://eclecticbill.blogspot.com/2005/11/tiddlywiki-example-research-notes.html]] |
|bgcolor(#dddddd):''Slideshow presentations''|A student at the University of Adelaide used ~TiddlyWiki to create a slide-show presentation on the ideology of a Hollywood motion picture: [[see here|http://lewcid.googlepages.com/tots.html#Bibliography]]|
|bgcolor(#dddddd):''Recipes''|Jackson Boyle, among others, are using ~TiddlyWiki to organize recipes. [[See here|http://jacksonboyle.com/kitchen.htm.]]|
|bgcolor(#dddddd):''Photo albums''|I am using TW as a photo album. See [[here|http://www.giffmex.org/giffr.html]]|
|bgcolor(#dddddd):''Miniature databases''|Editable custom form fields can be used in conjunction with ~TiddlyWiki to make it a database. I am using it to create a database of sorts of my notes. See a template version [[here|http://www.giffmex.org/emptynotestw.html]]|
|bgcolor(#dddddd):''Novels''|A few people are using TWs to write non-linear novels and editable novels.|

~TiddlyWikis are basically good for organizing any small to medium sized masses of information where a non-linear, non-cluttered format is desirable.

</pre>
</div>
<div title="What are the benefits of TiddlyWikis?" modifier="GiffMex" modified="200703070401" created="200612030321">
<pre>''~TiddlyWikis:''
*Are free
*Are self-contained - no need for programs other than an Internet browser
*Are easy to edit
*Are portable - a USB memory stick becomes a &quot;Wiki on a Stick&quot; that can be edited on any relatively new computer with a relatively recent Internet browser
*Are uncluttered - one can look at bite-sized chunks of information (microcontent) at a time rather than read through a long article in a linear fashion. One click closes all Tiddlers but the one you are reading
*Are fast - you navigate quickly through the Tiddlers that you want to read, in the order that you determine.
*Are non-linear - instead of scrolling up and down long files or webpages, the content is connected by hyperlinks
*Are searchable by tags that you assign to Tiddlers
*Are a handy way to create blogs and to-do lists
*Can create glossaries, notes and bibliographies that link to any Tiddler you desire
*Can be modified with a number of macros and plugins created specifically for ~TiddlyWiki.
*Can cook and sew. Okay, maybe they can't do everything.</pre>
</div>
<div title="What are the limitations of TiddlyWikis?" modifier="giffmex" modified="200708231856" created="200612030322" changecount="7">
<pre>There are ''a few minor drawbacks'': 

A drawback to using ~TiddlyWiki for ''larger amounts of information'' is that the file size becomes unwieldy either for storing or for uploading / downloading. They tend to START at 200kb-400kb. Larger ~TiddlyWikis still run fine, though. I have a few large ones myself. Here are a few [[Tips for speeding up performance on large TiddlyWikis]].

''Tables'' have to be created anew rather than copied and pasted from a Word Processor. Simple tables are fairly easy to create, but larger or more complicated tables would be better transferred as embedded images. Also, any fancy formatting, color changes, etc, take longer to do. Remember, an advantage of ~TiddlyWiki is that it runs using nothing more than a browser. But this advantage means that any fancy fiddling must be done with code, not with toolbars as in Word.

Some versions of ''Internet Explorer'' give ~TiddlyWikis hiccups. But then, you have already switched to Mozilla Firefox by now, I would hope. It is a superior browser with some handy plug-ins. So this isn’t really a drawback, just a push for you to switch to a better browser. For more information, see the Tiddler [[Special note for users of Internet Explorer]].

For special formatting such as italics, bold, bulleted and numbered lists, headings and subheadings, ''you need to know a minimum of code.'' I found this to be extremely easy to learn—as in a few minutes of practice—and really is not a major drawback for those willing to learn a limited number of new tricks. See [[How to Format Text]] to quickly see how this is done.

Every time you add Tiddlers or edit existing Tiddlers, ''the file saves a backup copy of itself.'' This is a good thing, to keep you from losing valuable information. But these files are generally 300kb or more. So either you need to delete all the backup copies each time you finish using ~TiddlyWiki, or uncheck the &quot;save backups&quot; box in the right-hand menu and save changes manually by clicking &quot;save changes&quot;, also in the right-hand menu.


</pre>
</div>
<div title="What in the world is a TiddlyWiki?" modifier="giffmex" modified="200708231846" created="200612030316" changecount="11">
<pre>~TiddlyWiki is an ingenious free application that is ideal for taking and organizing notes, organizing to-do lists, and even managing small personal databases. It is basically an html file (a webpage) stuffed with special code that allows you to create small snippets of information called Tiddlers. These tiddlers can be linked by tags and hyperlinks, and tucked away. When you need them again, you can use a search window, your own personalized tables of contents, or any number of handy tiddler indexes to find them quickly. Think of ~TiddlyWiki as an easily-searchable catalog of 3x5 cards and post-it notes all linked together in one file.

You don't need to buy a program to use ~TiddlyWiki. It is an html file that you can read and edit using nothing more than your Internet browser. And you don't need to be online to use ~TiddlyWiki. You can quickly download any ~TiddlyWiki to your computer to use offline. You can then take it with you wherever you go, on a USB memory stick (called a “Wiki on a Stick”) and edit it on any computer that has a relatively recent web browser, preferably Mozilla’s free browser Firefox. 

~TiddlyWikis were invented by Jeremy Ruston. His site, with the original documentation and other information, can be found at http://www.tiddlywiki.com/. 

[[What are TiddlyWikis being used for?]]
[[What are the benefits of TiddlyWikis?]]
[[What are the limitations of TiddlyWikis?]]




</pre>
</div>
<div title="Where to go for more information" modifier="giffmex" modified="200708240454" created="200612031615" changecount="3">
<pre>This is the best tutorial for those who know a bit more: http://tiddlyspot.com/twhelp/ by Morris Gray

The in-process official documentation site: http://www.tiddlywiki.org/wiki

The Google Group devoted to ~TiddlyWiki: http://groups-beta.google.com/group/TiddlyWiki

A ~TiddlyWiki FAQ - http://twfaq.tiddlyspot.com

A Tiddly Guides wikipedia type document: http://tiddlywikiguides.org/index.php?title=TiddlyWiki_Guides

</pre>
</div>
<div title="WikiWord" modifier="GiffMex" modified="200703071349" created="200612031340">
<pre>A WikiWord is a word that combines upper and lowercase letters. Examples: ~WikiWord, ~GiffMex, ~MainMenu, ~AbrahamLincoln, etc.</pre>
</div>
<div title="bold, colored" modifier="GiffMex" created="200612031312">
<pre>You see? </pre>
</div>
<div title="easyFormat" modifier="churu1" modified="200705261616" created="200701131439" tags="systemConfig E.A.S.E Extensions ForBlogUse">
<pre>/***
|!''Name:''|!easyFormat|
|''Description:''|the format command format selection according to your choice|
|''Version:''|0.1.0|
|''Date:''|13/01/2007|
|''Source:''|[[TWkd|http://yann.perrin.googlepages.com/twkd.html#easyFormat]]|
|''Author:''|[[Yann Perrin|YannPerrin]]|
|''License:''|[[BSD open source license]]|
|''~CoreVersion:''|2.x|
|''Browser:''|Firefox 1.0.4+; Firefox 1.5; InternetExplorer 6.0|
|''Requires:''|@@color:red;''E.A.S.E''@@|
***/
//{{{
config.commands.format = new TWkd.Ease('Format','format selection accordingly to chosen mode');
config.commands.format.addMode({
 name:'Bold',
 tooltip:'turns selection into bold text',
 operation:function(){
 config.commands.format.putInPlace(&quot;''&quot;+TWkd.context.selection.content+&quot;''&quot;,TWkd.context.selection);
 }
});
config.commands.format.addMode({
 name:'Italic',
 tooltip:'turns selection into italic text',
 operation:function(){
 config.commands.format.putInPlace(&quot;//&quot;+TWkd.context.selection.content+&quot;//&quot;,TWkd.context.selection);
 }
});
config.commands.format.addMode({
 name:'Blockquote',
 tooltip:'turns selection into blocked text',
 operation:function(){
config.commands.format.putInPlace(&quot;&gt;&quot;+TWkd.context.selection.content+&quot;&gt;&quot;,TWkd.context.selection);
 }
});
config.commands.format.addMode({
 name:'2block',
 tooltip:'turns selection into doubly blocked text',
 operation:function(){
config.commands.format.putInPlace(&quot;&gt;&gt;&quot;+TWkd.context.selection.content+&quot;&gt;&gt;&quot;,TWkd.context.selection);
 }
});
config.commands.format.addMode({
 name:'3block',
 tooltip:'turns selection into triply blocked text',
 operation:function(){
config.commands.format.putInPlace(&quot;&gt;&gt;&gt;&quot;+TWkd.context.selection.content+&quot;&gt;&gt;&gt;&quot;,TWkd.context.selection);
 }
});
config.commands.format.addMode({
 name:'4block',
 tooltip:'turns selection into quadruplly blocked text',
 operation:function(){
config.commands.format.putInPlace(&quot;&gt;&gt;&gt;&gt;&quot;+TWkd.context.selection.content+&quot;&gt;&gt;&gt;&gt;&quot;,TWkd.context.selection);
 }
});
config.commands.format.addMode({
 name:'Highlight',
 tooltip:'highlight selection',
 operation:function(){
 config.commands.format.putInPlace(&quot;@@&quot;+TWkd.context.selection.content+&quot;@@&quot;,TWkd.context.selection);
 }
});
config.commands.format.addMode({
 name:'Code window',
 tooltip:'Show a window to backstage TW code',
 operation:function(){
 config.commands.format.putInPlace(&quot;//{{{&quot;+TWkd.context.selection.content+&quot;//}}}&quot;,TWkd.context.selection);
 }
});
config.commands.format.addMode({
 name:'Group box',
 tooltip:'Enclose text in a box',
 operation:function(){
 config.commands.format.putInPlace(&quot;{{menubox{&quot;+TWkd.context.selection.content+&quot;}}}&quot;,TWkd.context.selection);
 }
});
config.commands.format.addMode({
 name:'Greek',
 tooltip:'turns selection into unicode text, for Greek characters',
 operation:function(){
 config.commands.format.putInPlace(&quot;{{greek{&quot;+TWkd.context.selection.content+&quot;}}}&quot;,TWkd.context.selection);
 }
});
//}}}</pre>
</div>
<div title="greenishgray" modifier="GiffMex" created="200703021320">
<pre>Background: #eeffcc
Foreground: #000
PrimaryPale: #bbcc99
PrimaryLight: #bbdd88
PrimaryMid: #445533
PrimaryDark: #000
SecondaryPale: #ffc
SecondaryLight: #99dd55
SecondaryMid: #cccccc
SecondaryDark: #445533
TertiaryPale: #bbcc99
TertiaryLight: #EEC591
TertiaryMid: #552233
TertiaryDark: #8B7355</pre>
</div>
<div title="through a MainMenu" modifier="giffmex" modified="200708271450" created="200612031310" changecount="1">
<pre>*The MainMenu is like a table of contents. It's normally found in a left hand menu bar. The ~MainMenu for this file is found in the header. Click on any item and a tiddler will open up. You can create various levels of a table of contents starting with the ~MainMenu.</pre>
</div>
<div title="through hyperlinks" modifier="GiffMex" modified="200612310554" created="200612031312">
<pre>*Hyperlinks are links between files and between places within a file. The hyperlinks in this file are shown in [[bold, colored]] text. Click on the words &quot;bold, colored&quot; and TW will take you to another tiddler.

</pre>
</div>
<div title="through tags" modifier="Giffmex" modified="200703241306" created="200612031313" tags="beginners reading">
<pre>Tags are words attached to tiddlers to aid readers in finding and sorting them. In the colored box to the right side of this tiddler are listed two tags attached to this tiddler: &quot;beginners&quot; and &quot;reading&quot;. Tags are like categories or topics that you want to assign to a tiddler. If you want to search for a specific tiddler without wading through the levels of the ~MainMenu, you can use the special menu at the bottom of the right-hand column to search for tiddlers and tags. See [[here|The right hand menu]] for more information on the right hand menu.

</pre>
</div>
</div>
<!--POST-STOREAREA-->
<!--POST-BODY-START-->

<!--POST-BODY-END-->
<script type="text/javascript">
//<![CDATA[
//
// Please note:
// 
// * This code is designed to be readable but for compactness it only includes brief comments. You can see fuller comments
//   in the project Subversion repository at http://svn.tiddlywiki.org/Trunk/core/
//
// * You should never need to modify this source code directly. TiddlyWiki is carefully designed to allow deep customisation
//   without changing the core code. Please consult the development group at http://groups.google.com/group/TiddlyWikiDev
// 

//--
//-- Configuration repository
//--

// Miscellaneous options
var config = {
        numRssItems: 20, // Number of items in the RSS feed
        animDuration: 400, // Duration of UI animations in milliseconds
        cascadeFast: 20, // Speed for cascade animations (higher == slower)
        cascadeSlow: 60, // Speed for EasterEgg cascade animations
        cascadeDepth: 5 // Depth of cascade animation
};

// Adaptors
config.adaptors = {};

// Backstage tasks
config.tasks = {};

// Annotations
config.annotations = {};

// Custom fields to be automatically added to new tiddlers
config.defaultCustomFields = {};

// Messages
config.messages = {
        messageClose: {},
        dates: {},
        tiddlerPopup: {}
};

// Options that can be set in the options panel and/or cookies
config.options = {
        chkRegExpSearch: false,
        chkCaseSensitiveSearch: false,
        chkAnimate: true,
        chkSaveBackups: true,
        chkAutoSave: false,
        chkGenerateAnRssFeed: false,
        chkSaveEmptyTemplate: false,
        chkOpenInNewWindow: true,
        chkToggleLinks: false,
        chkHttpReadOnly: true,
        chkForceMinorUpdate: false,
        chkConfirmDelete: true,
        chkInsertTabs: false,
        chkUsePreForStorage: true, // Whether to use <pre> format for storage
        chkDisplayStartupTime: false,
        txtBackupFolder: "",
        txtMainTab: "tabTimeline",
        txtMoreTab: "moreTabAll",
        txtMaxEditRows: "30",
        txtFileSystemCharSet: "UTF-8"
        };
config.optionsDesc = {};
        
// List of notification functions to be called when certain tiddlers are changed or deleted
config.notifyTiddlers = [
        {name: "StyleSheetLayout", notify: refreshStyles},
        {name: "StyleSheetColors", notify: refreshStyles},
        {name: "StyleSheet", notify: refreshStyles},
        {name: "StyleSheetPrint", notify: refreshStyles},
        {name: "PageTemplate", notify: refreshPageTemplate},
        {name: "SiteTitle", notify: refreshPageTitle},
        {name: "SiteSubtitle", notify: refreshPageTitle},
        {name: "ColorPalette", notify: refreshColorPalette},
        {name: null, notify: refreshDisplay}
];

// Default tiddler templates
var DEFAULT_VIEW_TEMPLATE = 1;
var DEFAULT_EDIT_TEMPLATE = 2;
config.tiddlerTemplates = {
        1: "ViewTemplate",
        2: "EditTemplate"
};

// More messages (rather a legacy layout that shouldn't really be like this)
config.views = {
        wikified: {
                tag: {}
        },
        editor: {
                tagChooser: {}
        }
};

// Backstage tasks
config.backstageTasks = ["save","sync","importTask","tweak","plugins"];

// Macros; each has a 'handler' member that is inserted later
config.macros = {
        today: {},
        version: {},
        search: {sizeTextbox: 15},
        tiddler: {},
        tag: {},
        tags: {},
        tagging: {},
        timeline: {},
        allTags: {},
        list: {
                all: {},
                missing: {},
                orphans: {},
                shadowed: {},
                touched: {}
        },
        closeAll: {},
        permaview: {},
        saveChanges: {},
        slider: {},
        option: {},
        options: {},
        newTiddler: {},
        newJournal: {},
        sparkline: {},
        tabs: {},
        gradient: {},
        message: {},
        view: {},
        edit: {},
        tagChooser: {},
        toolbar: {},
        br: {},
        plugins: {},
        refreshDisplay: {},
        importTiddlers: {},
        sync: {},
        annotations: {}
};

// Commands supported by the toolbar macro
config.commands = {
        closeTiddler: {},
        closeOthers: {},
        editTiddler: {},
        saveTiddler: {hideReadOnly: true},
        cancelTiddler: {},
        deleteTiddler: {hideReadOnly: true},
        permalink: {},
        references: {type: "popup"},
        jump: {type: "popup"},
        syncing: {type: "popup"},
        fields: {type: "popup"}
};

// Browser detection... In a very few places, there's nothing else for it but to know what browser we're using.
config.userAgent = navigator.userAgent.toLowerCase();
config.browser = {
        isIE: config.userAgent.indexOf("msie") != -1 && config.userAgent.indexOf("opera") == -1,
        isGecko: config.userAgent.indexOf("gecko") != -1,
        ieVersion: /MSIE (\d.\d)/i.exec(config.userAgent), // config.browser.ieVersion[1], if it exists, will be the IE version string, eg "6.0"
        isSafari: config.userAgent.indexOf("applewebkit") != -1,
        isBadSafari: !((new RegExp("[\u0150\u0170]","g")).test("\u0150")),
        firefoxDate: /gecko\/(\d{8})/i.exec(config.userAgent), // config.browser.firefoxDate[1], if it exists, will be Firefox release date as "YYYYMMDD"
        isOpera: config.userAgent.indexOf("opera") != -1,
        isLinux: config.userAgent.indexOf("linux") != -1,
        isUnix: config.userAgent.indexOf("x11") != -1,
        isMac: config.userAgent.indexOf("mac") != -1,
        isWindows: config.userAgent.indexOf("win") != -1
};

// Basic regular expressions
config.textPrimitives = {
        upperLetter: "[A-Z\u00c0-\u00de\u0150\u0170]",
        lowerLetter: "[a-z0-9_\\-\u00df-\u00ff\u0151\u0171]",
        anyLetter:   "[A-Za-z0-9_\\-\u00c0-\u00de\u00df-\u00ff\u0150\u0170\u0151\u0171]",
        anyLetterStrict: "[A-Za-z0-9\u00c0-\u00de\u00df-\u00ff\u0150\u0170\u0151\u0171]"
};
if(config.browser.isBadSafari) {
        config.textPrimitives = {
                upperLetter: "[A-Z\u00c0-\u00de]",
                lowerLetter: "[a-z0-9_\\-\u00df-\u00ff]",
                anyLetter:   "[A-Za-z0-9_\\-\u00c0-\u00de\u00df-\u00ff]",
                anyLetterStrict: "[A-Za-z0-9\u00c0-\u00de\u00df-\u00ff]"
        };
}
config.textPrimitives.sliceSeparator = "::";
config.textPrimitives.urlPattern = "[a-z]{3,8}:[^\\s:'\"][^\\s'\"]*(?:/|\\b)";
config.textPrimitives.unWikiLink = "~";
config.textPrimitives.wikiLink = "(?:(?:" + config.textPrimitives.upperLetter + "+" +
        config.textPrimitives.lowerLetter + "+" +
        config.textPrimitives.upperLetter +
        config.textPrimitives.anyLetter + "*)|(?:" +
        config.textPrimitives.upperLetter + "{2,}" +
        config.textPrimitives.lowerLetter + "+))";

config.textPrimitives.cssLookahead = "(?:(" + config.textPrimitives.anyLetter + "+)\\(([^\\)\\|\\n]+)(?:\\):))|(?:(" + config.textPrimitives.anyLetter + "+):([^;\\|\\n]+);)";
config.textPrimitives.cssLookaheadRegExp = new RegExp(config.textPrimitives.cssLookahead,"mg");

config.textPrimitives.brackettedLink = "\\[\\[([^\\]]+)\\]\\]";
config.textPrimitives.titledBrackettedLink = "\\[\\[([^\\[\\]\\|]+)\\|([^\\[\\]\\|]+)\\]\\]";
config.textPrimitives.tiddlerForcedLinkRegExp = new RegExp("(?:" + config.textPrimitives.titledBrackettedLink + ")|(?:" +
        config.textPrimitives.brackettedLink + ")|(?:" + 
        config.textPrimitives.urlPattern + ")","mg");
config.textPrimitives.tiddlerAnyLinkRegExp = new RegExp("("+ config.textPrimitives.wikiLink + ")|(?:" +
        config.textPrimitives.titledBrackettedLink + ")|(?:" +
        config.textPrimitives.brackettedLink + ")|(?:" +
        config.textPrimitives.urlPattern + ")","mg");

config.glyphs = {
        browsers: [
                function() {return config.browser.isIE;},
                function() {return true}
        ],
        currBrowser: null,
        codes: {
                downTriangle: ["\u25BC","\u25BE"],
                downArrow: ["\u2193","\u2193"],
                bentArrowLeft: ["\u2190","\u21A9"],
                bentArrowRight: ["\u2192","\u21AA"]
        }
};

//--
//-- Shadow tiddlers
//--

config.shadowTiddlers = {
        StyleSheet: "",
        MarkupPreHead: "<!--{{{-->\n<link rel='alternate' type='application/rss+xml' title='RSS' href='index.xml'/>\n<!--}}}-->",
        MarkupPostHead: "",
        MarkupPreBody: "",
        MarkupPostBody: "",
        TabTimeline: '<<timeline>>',
        TabAll: '<<list all>>',
        TabTags: '<<allTags excludeLists>>',
        TabMoreMissing: '<<list missing>>',
        TabMoreOrphans: '<<list orphans>>',
        TabMoreShadowed: '<<list shadowed>>',
        AdvancedOptions: '<<options>>',
        PluginManager: '<<plugins>>',
        ImportTiddlers: '<<importTiddlers>>'
};

//--
//-- Translateable strings
//--

// Strings in "double quotes" should be translated; strings in 'single quotes' should be left alone

merge(config.options,{
        txtUserName: "YourName"});

merge(config.tasks,{
        save: {text: "save", tooltip: "Save your changes to this TiddlyWiki", action: saveChanges},
        sync: {text: "sync", tooltip: "Synchronise changes with other TiddlyWiki files and servers", content: '<<sync>>'},
        importTask: {text: "import", tooltip: "Import tiddlers and plugins from other TiddlyWiki files and servers", content: '<<importTiddlers>>'},
        tweak: {text: "tweak", tooltip: "Tweak the appearance and behaviour of TiddlyWiki", content: '<<options>>'},
        plugins: {text: "plugins", tooltip: "Manage installed plugins", content: '<<plugins>>'}
});

// Options that can be set in the options panel and/or cookies
merge(config.optionsDesc,{
        txtUserName: "Username for signing your edits",
        chkRegExpSearch: "Enable regular expressions for searches",
        chkCaseSensitiveSearch: "Case-sensitive searching",
        chkAnimate: "Enable animations",
        chkSaveBackups: "Keep backup file when saving changes",
        chkAutoSave: "Automatically save changes",
        chkGenerateAnRssFeed: "Generate an RSS feed when saving changes",
        chkSaveEmptyTemplate: "Generate an empty template when saving changes",
        chkOpenInNewWindow: "Open external links in a new window",
        chkToggleLinks: "Clicking on links to open tiddlers causes them to close",
        chkHttpReadOnly: "Hide editing features when viewed over HTTP",
        chkForceMinorUpdate: "Don't update modifier username and date when editing tiddlers",
        chkConfirmDelete: "Require confirmation before deleting tiddlers",
        chkInsertTabs: "Use the tab key to insert tab characters instead of moving between fields",
        txtBackupFolder: "Name of folder to use for backups",
        txtMaxEditRows: "Maximum number of rows in edit boxes",
        txtFileSystemCharSet: "Default character set for saving changes (Firefox/Mozilla only)"});

merge(config.messages,{
        customConfigError: "Problems were encountered loading plugins. See PluginManager for details",
        pluginError: "Error: %0",
        pluginDisabled: "Not executed because disabled via 'systemConfigDisable' tag",
        pluginForced: "Executed because forced via 'systemConfigForce' tag",
        pluginVersionError: "Not executed because this plugin needs a newer version of TiddlyWiki",
        nothingSelected: "Nothing is selected. You must select one or more items first",
        savedSnapshotError: "It appears that this TiddlyWiki has been incorrectly saved. Please see http://www.tiddlywiki.com/#DownloadSoftware for details",
        subtitleUnknown: "(unknown)",
        undefinedTiddlerToolTip: "The tiddler '%0' doesn't yet exist",
        shadowedTiddlerToolTip: "The tiddler '%0' doesn't yet exist, but has a pre-defined shadow value",
        tiddlerLinkTooltip: "%0 - %1, %2",
        externalLinkTooltip: "External link to %0",
        noTags: "There are no tagged tiddlers",
        notFileUrlError: "You need to save this TiddlyWiki to a file before you can save changes",
        cantSaveError: "It's not possible to save changes. Possible reasons include:\n- your browser doesn't support saving (Firefox, Internet Explorer, Safari and Opera all work if properly configured)\n- the pathname to your TiddlyWiki file contains illegal characters\n- the TiddlyWiki HTML file has been moved or renamed",
        invalidFileError: "The original file '%0' does not appear to be a valid TiddlyWiki",
        backupSaved: "Backup saved",
        backupFailed: "Failed to save backup file",
        rssSaved: "RSS feed saved",
        rssFailed: "Failed to save RSS feed file",
        emptySaved: "Empty template saved",
        emptyFailed: "Failed to save empty template file",
        mainSaved: "Main TiddlyWiki file saved",
        mainFailed: "Failed to save main TiddlyWiki file. Your changes have not been saved",
        macroError: "Error in macro <<\%0>>",
        macroErrorDetails: "Error while executing macro <<\%0>>:\n%1",
        missingMacro: "No such macro",
        overwriteWarning: "A tiddler named '%0' already exists. Choose OK to overwrite it",
        unsavedChangesWarning: "WARNING! There are unsaved changes in TiddlyWiki\n\nChoose OK to save\nChoose CANCEL to discard",
        confirmExit: "--------------------------------\n\nThere are unsaved changes in TiddlyWiki. If you continue you will lose those changes\n\n--------------------------------",
        saveInstructions: "SaveChanges",
        unsupportedTWFormat: "Unsupported TiddlyWiki format '%0'",
        tiddlerSaveError: "Error when saving tiddler '%0'",
        tiddlerLoadError: "Error when loading tiddler '%0'",
        wrongSaveFormat: "Cannot save with storage format '%0'. Using standard format for save.",
        invalidFieldName: "Invalid field name %0",
        fieldCannotBeChanged: "Field '%0' cannot be changed",
        loadingMissingTiddler: "Attempting to retrieve the tiddler '%0' from the '%1' server at:\n\n'%2' in the workspace '%3'"});

merge(config.messages.messageClose,{
        text: "close",
        tooltip: "close this message area"});

config.messages.backstage = {
        open: {text: "backstage", tooltip: "Open the backstage area to perform authoring and editing tasks"},
        close: {text: "close", tooltip: "Close the backstage area"},
        prompt: "backstage: ",
        decal: {
                edit: {text: "edit", tooltip: "Edit the tiddler '%0'"}
        }
};

config.messages.listView = {
        tiddlerTooltip: "Click for the full text of this tiddler",
        previewUnavailable: "(preview not available)"
};

config.messages.dates.months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November","December"];
config.messages.dates.days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
config.messages.dates.shortMonths = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
config.messages.dates.shortDays = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
// suffixes for dates, eg "1st","2nd","3rd"..."30th","31st"
config.messages.dates.daySuffixes = ["st","nd","rd","th","th","th","th","th","th","th",
                "th","th","th","th","th","th","th","th","th","th",
                "st","nd","rd","th","th","th","th","th","th","th",
                "st"];
config.messages.dates.am = "am";
config.messages.dates.pm = "pm";

merge(config.messages.tiddlerPopup,{
        });

merge(config.views.wikified.tag,{
        labelNoTags: "no tags",
        labelTags: "tags: ",
        openTag: "Open tag '%0'",
        tooltip: "Show tiddlers tagged with '%0'",
        openAllText: "Open all",
        openAllTooltip: "Open all of these tiddlers",
        popupNone: "No other tiddlers tagged with '%0'"});

merge(config.views.wikified,{
        defaultText: "The tiddler '%0' doesn't yet exist. Double-click to create it",
        defaultModifier: "(missing)",
        shadowModifier: "(built-in shadow tiddler)",
        dateFormat: "DD MMM YYYY",
        createdPrompt: "created"});

merge(config.views.editor,{
        tagPrompt: "Type tags separated with spaces, [[use double square brackets]] if necessary, or add existing",
        defaultText: "Type the text for '%0'"});

merge(config.views.editor.tagChooser,{
        text: "tags",
        tooltip: "Choose existing tags to add to this tiddler",
        popupNone: "There are no tags defined",
        tagTooltip: "Add the tag '%0'"});

merge(config.messages,{
        sizeTemplates:
                [
                {unit: 1024*1024*1024, template: "%0\u00a0GB"},
                {unit: 1024*1024, template: "%0\u00a0MB"},
                {unit: 1024, template: "%0\u00a0KB"},
                {unit: 1, template: "%0\u00a0B"}
                ]});

merge(config.macros.search,{
        label: "search",
        prompt: "Search this TiddlyWiki",
        accessKey: "F",
        successMsg: "%0 tiddlers found matching %1",
        failureMsg: "No tiddlers found matching %0"});

merge(config.macros.tagging,{
        label: "tagging: ",
        labelNotTag: "not tagging",
        tooltip: "List of tiddlers tagged with '%0'"});

merge(config.macros.timeline,{
        dateFormat: "DD MMM YYYY"});

merge(config.macros.allTags,{
        tooltip: "Show tiddlers tagged with '%0'",
        noTags: "There are no tagged tiddlers"});

config.macros.list.all.prompt = "All tiddlers in alphabetical order";
config.macros.list.missing.prompt = "Tiddlers that have links to them but are not defined";
config.macros.list.orphans.prompt = "Tiddlers that are not linked to from any other tiddlers";
config.macros.list.shadowed.prompt = "Tiddlers shadowed with default contents";
config.macros.list.touched.prompt = "Tiddlers that have been modified locally";

merge(config.macros.closeAll,{
        label: "close all",
        prompt: "Close all displayed tiddlers (except any that are being edited)"});

merge(config.macros.permaview,{
        label: "permaview",
        prompt: "Link to an URL that retrieves all the currently displayed tiddlers"});

merge(config.macros.saveChanges,{
        label: "save changes",
        prompt: "Save all tiddlers to create a new TiddlyWiki",
        accessKey: "S"});

merge(config.macros.newTiddler,{
        label: "new tiddler",
        prompt: "Create a new tiddler",
        title: "New Tiddler",
        accessKey: "N"});

merge(config.macros.newJournal,{
        label: "new journal",
        prompt: "Create a new tiddler from the current date and time",
        accessKey: "J"});

merge(config.macros.options,{
        wizardTitle: "Tweak advanced options",
        step1Title: "These options are saved in cookies in your browser",
        step1Html: "<input type='hidden' name='markList'></input><br><input type='checkbox' checked='false' name='chkUnknown'>Show unknown options</input>",
        unknownDescription: "//(unknown)//",
        listViewTemplate: {
                columns: [
                        {name: 'Option', field: 'option', title: "Option", type: 'String'},
                        {name: 'Description', field: 'description', title: "Description", type: 'WikiText'},
                        {name: 'Name', field: 'name', title: "Name", type: 'String'}
                        ],
                rowClasses: [
                        {className: 'lowlight', field: 'lowlight'} 
                        ]}
        });

merge(config.macros.plugins,{
        wizardTitle: "Manage plugins",
        step1Title: "Currently loaded plugins",
        step1Html: "<input type='hidden' name='markList'></input>", // DO NOT TRANSLATE
        skippedText: "(This plugin has not been executed because it was added since startup)",
        noPluginText: "There are no plugins installed",
        confirmDeleteText: "Are you sure you want to delete these plugins:\n\n%0",
        removeLabel: "remove systemConfig tag",
        removePrompt: "Remove systemConfig tag",
        deleteLabel: "delete",
        deletePrompt: "Delete these tiddlers forever",
        listViewTemplate: {
                columns: [
                        {name: 'Selected', field: 'Selected', rowName: 'title', type: 'Selector'},
                        {name: 'Tiddler', field: 'tiddler', title: "Tiddler", type: 'Tiddler'},
                        {name: 'Size', field: 'size', tiddlerLink: 'size', title: "Size", type: 'Size'},
                        {name: 'Forced', field: 'forced', title: "Forced", tag: 'systemConfigForce', type: 'TagCheckbox'},
                        {name: 'Disabled', field: 'disabled', title: "Disabled", tag: 'systemConfigDisable', type: 'TagCheckbox'},
                        {name: 'Executed', field: 'executed', title: "Loaded", type: 'Boolean', trueText: "Yes", falseText: "No"},
                        {name: 'Startup Time', field: 'startupTime', title: "Startup Time", type: 'String'},
                        {name: 'Error', field: 'error', title: "Status", type: 'Boolean', trueText: "Error", falseText: "OK"},
                        {name: 'Log', field: 'log', title: "Log", type: 'StringList'}
                        ],
                rowClasses: [
                        {className: 'error', field: 'error'},
                        {className: 'warning', field: 'warning'}
                        ]}
        });

merge(config.macros.toolbar,{
        moreLabel: "more",
        morePrompt: "Reveal further commands"
        });

merge(config.macros.refreshDisplay,{
        label: "refresh",
        prompt: "Redraw the entire TiddlyWiki display"
        });

merge(config.macros.importTiddlers,{
        readOnlyWarning: "You cannot import into a read-only TiddlyWiki file. Try opening it from a file:// URL",
        wizardTitle: "Import tiddlers from another file or server",
        step1Title: "Step 1: Locate the server or TiddlyWiki file",
        step1Html: "Specify the type of the server: <select name='selTypes'><option value=''>Choose...</option></select><br>Enter the URL or pathname here: <input type='text' size=50 name='txtPath'><br>...or browse for a file: <input type='file' size=50 name='txtBrowse'><br><hr>...or select a pre-defined feed: <select name='selFeeds'><option value=''>Choose...</option></select>",
        openLabel: "open",
        openPrompt: "Open the connection to this file or server",
        openError: "There were problems fetching the tiddlywiki file",
        statusOpenHost: "Opening the host",
        statusGetWorkspaceList: "Getting the list of available workspaces",
        step2Title: "Step 2: Choose the workspace",
        step2Html: "Enter a workspace name: <input type='text' size=50 name='txtWorkspace'><br>...or select a workspace: <select name='selWorkspace'><option value=''>Choose...</option></select>",
        cancelLabel: "cancel",
        cancelPrompt: "Cancel this import",
        statusOpenWorkspace: "Opening the workspace",
        statusGetTiddlerList: "Getting the list of available tiddlers",
        step3Title: "Step 3: Choose the tiddlers to import",
        step3Html: "<input type='hidden' name='markList'></input><br><input type='checkbox' checked='true' name='chkSync'>Keep these tiddlers linked to this server so that you can synchronise subsequent changes</input><br><input type='checkbox' name='chkSave'>Save the details of this server in a 'systemServer' tiddler called:</input> <input type='text' size=25 name='txtSaveTiddler'>",
        importLabel: "import",
        importPrompt: "Import these tiddlers",
        confirmOverwriteText: "Are you sure you want to overwrite these tiddlers:\n\n%0",
        step4Title: "Step 4: Importing %0 tiddler(s)",
        step4Html: "<input type='hidden' name='markReport'></input>", // DO NOT TRANSLATE
        doneLabel: "done",
        donePrompt: "Close this wizard",
        statusDoingImport: "Importing tiddlers",
        statusDoneImport: "All tiddlers imported",
        systemServerNamePattern: "%2 on %1",
        systemServerNamePatternNoWorkspace: "%1",
        confirmOverwriteSaveTiddler: "The tiddler '%0' already exists. Click 'OK' to overwrite it with the details of this server, or 'Cancel' to leave it unchanged",
        serverSaveTemplate: "|''Type:''|%0|\n|''URL:''|%1|\n|''Workspace:''|%2|\n\nThis tiddler was automatically created to record the details of this server",
        serverSaveModifier: "(System)",
        listViewTemplate: {
                columns: [
                        {name: 'Selected', field: 'Selected', rowName: 'title', type: 'Selector'},
                        {name: 'Tiddler', field: 'tiddler', title: "Tiddler", type: 'Tiddler'},
                        {name: 'Size', field: 'size', tiddlerLink: 'size', title: "Size", type: 'Size'},
                        {name: 'Tags', field: 'tags', title: "Tags", type: 'Tags'}
                        ],
                rowClasses: [
                        ]}
        });

merge(config.macros.sync,{
        listViewTemplate: {
                columns: [
                        {name: 'Selected', field: 'selected', rowName: 'title', type: 'Selector'},
                        {name: 'Tiddler', field: 'tiddler', title: "Tiddler", type: 'Tiddler'},
                        {name: 'Server Type', field: 'serverType', title: "Server type", type: 'String'},
                        {name: 'Server Host', field: 'serverHost', title: "Server host", type: 'String'},
                        {name: 'Server Workspace', field: 'serverWorkspace', title: "Server workspace", type: 'String'},
                        {name: 'Status', field: 'status', title: "Synchronisation status", type: 'String'},
                        {name: 'Server URL', field: 'serverUrl', title: "Server URL", text: "View", type: 'Link'}
                        ],
                rowClasses: [
                        ],
                buttons: [
                        {caption: "Sync these tiddlers", name: 'sync'}
                        ]},
        wizardTitle: "Synchronize with external servers and files",
        step1Title: "Choose the tiddlers you want to synchronize",
        step1Html: "<input type='hidden' name='markList'></input>", // DO NOT TRANSLATE
        syncLabel: "sync",
        syncPrompt: "Sync these tiddlers",
        hasChanged: "Changed while unplugged",
        hasNotChanged: "Unchanged while unplugged",
        syncStatusList: {
                none: {text: "...", color: "none"},
                changedServer: {text: "Changed on server", color: '#80ff80'},
                changedLocally: {text: "Changed while unplugged", color: '#80ff80'},
                changedBoth: {text: "Changed while unplugged and on server", color: '#ff8080'},
                notFound: {text: "Not found on server", color: '#ffff80'},
                putToServer: {text: "Saved update on server", color: '#ff80ff'},
                gotFromServer: {text: "Retrieved update from server", color: '#80ffff'}
                }
        });

merge(config.macros.annotations,{
        });

merge(config.commands.closeTiddler,{
        text: "close",
        tooltip: "Close this tiddler"});

merge(config.commands.closeOthers,{
        text: "close others",
        tooltip: "Close all other tiddlers"});

merge(config.commands.editTiddler,{
        text: "edit",
        tooltip: "Edit this tiddler",
        readOnlyText: "view",
        readOnlyTooltip: "View the source of this tiddler"});

merge(config.commands.saveTiddler,{
        text: "done",
        tooltip: "Save changes to this tiddler"});

merge(config.commands.cancelTiddler,{
        text: "cancel",
        tooltip: "Undo changes to this tiddler",
        warning: "Are you sure you want to abandon your changes to '%0'?",
        readOnlyText: "done",
        readOnlyTooltip: "View this tiddler normally"});

merge(config.commands.deleteTiddler,{
        text: "delete",
        tooltip: "Delete this tiddler",
        warning: "Are you sure you want to delete '%0'?"});

merge(config.commands.permalink,{
        text: "permalink",
        tooltip: "Permalink for this tiddler"});

merge(config.commands.references,{
        text: "references",
        tooltip: "Show tiddlers that link to this one",
        popupNone: "No references"});

merge(config.commands.jump,{
        text: "jump",
        tooltip: "Jump to another open tiddler"});

merge(config.commands.syncing,{
        text: "syncing",
        tooltip: "Control synchronisation of this tiddler with a server or external file",
        currentlySyncing: "<div>Currently syncing via <span class='popupHighlight'>'%0'</span> to:</"+"div><div>host: <span class='popupHighlight'>%1</span></"+"div><div>workspace: <span class='popupHighlight'>%2</span></"+"div>", // Note escaping of closing <div> tag
        notCurrentlySyncing: "Not currently syncing",
        captionUnSync: "Stop synchronising this tiddler",
        chooseServer: "Synchronise this tiddler with another server:",
        currServerMarker: "\u25cf ",
        notCurrServerMarker: "  "});

merge(config.commands.fields,{
        text: "fields",
        tooltip: "Show the extended fields of this tiddler",
        emptyText: "There are no extended fields for this tiddler",
        listViewTemplate: {
                columns: [
                        {name: 'Field', field: 'field', title: "Field", type: 'String'},
                        {name: 'Value', field: 'value', title: "Value", type: 'String'}
                        ],
                rowClasses: [
                        ],
                buttons: [
                        ]}});

merge(config.shadowTiddlers,{
        DefaultTiddlers: "GettingStarted",
        MainMenu: "GettingStarted",
        SiteTitle: "My TiddlyWiki",
        SiteSubtitle: "a reusable non-linear personal web notebook",
        SiteUrl: "http://www.tiddlywiki.com/",
        SideBarOptions: '<<search>><<closeAll>><<permaview>><<newTiddler>><<newJournal "DD MMM YYYY">><<saveChanges>><<slider chkSliderOptionsPanel OptionsPanel "options »" "Change TiddlyWiki advanced options">>',
        SideBarTabs: '<<tabs txtMainTab "Timeline" "Timeline" TabTimeline "All" "All tiddlers" TabAll "Tags" "All tags" TabTags "More" "More lists" TabMore>>',
        TabMore: '<<tabs txtMoreTab "Missing" "Missing tiddlers" TabMoreMissing "Orphans" "Orphaned tiddlers" TabMoreOrphans "Shadowed" "Shadowed tiddlers" TabMoreShadowed>>'});

merge(config.annotations,{
        AdvancedOptions: "This shadow tiddler provides access to several advanced options",
        ColorPalette: "These values in this shadow tiddler determine the colour scheme of the ~TiddlyWiki user interface",
        DefaultTiddlers: "The tiddlers listed in this shadow tiddler will be automatically displayed when ~TiddlyWiki starts up",
        EditTemplate: "The HTML template in this shadow tiddler determines how tiddlers look while they are being edited",
        GettingStarted: "This shadow tiddler provides basic usage instructions",
        ImportTiddlers: "This shadow tiddler provides access to importing tiddlers",
        MainMenu: "This shadow tiddler is used as the contents of the main menu in the left-hand column of the screen",
        MarkupPreHead: "This tiddler is inserted at the top of the <head> section of the TiddlyWiki HTML file",
        MarkupPostHead: "This tiddler is inserted at the bottom of the <head> section of the TiddlyWiki HTML file",
        MarkupPreBody: "This tiddler is inserted at the top of the <body> section of the TiddlyWiki HTML file",
        MarkupPostBody: "This tiddler is inserted at the end of the <body> section of the TiddlyWiki HTML file immediately before the script block",
        OptionsPanel: "This shadow tiddler is used as the contents of the options panel slider in the right-hand sidebar",
        PageTemplate: "The HTML template in this shadow tiddler determines the overall ~TiddlyWiki layout",
        PluginManager: "This shadow tiddler provides access to the plugin manager",
        SideBarOptions: "This shadow tiddler is used as the contents of the option panel in the right-hand sidebar",
        SideBarTabs: "This shadow tiddler is used as the contents of the tabs panel in the right-hand sidebar",
        SiteSubtitle: "This shadow tiddler is used as the second part of the page title",
        SiteTitle: "This shadow tiddler is used as the first part of the page title",
        SiteUrl: "This shadow tiddler should be set to the full target URL for publication",
        StyleSheetColours: "This shadow tiddler contains CSS definitions related to the color of page elements",
        StyleSheet: "This tiddler can contain custom CSS definitions",
        StyleSheetLayout: "This shadow tiddler contains CSS definitions related to the layout of page elements",
        StyleSheetLocale: "This shadow tiddler contains CSS definitions related to the translation locale",
        StyleSheetPrint: "This shadow tiddler contains CSS definitions for printing",
        TabAll: "This shadow tiddler contains the contents of the 'All' tab in the right-hand sidebar",
        TabMore: "This shadow tiddler contains the contents of the 'More' tab in the right-hand sidebar",
        TabMoreMissing: "This shadow tiddler contains the contents of the 'Missing' tab in the right-hand sidebar",
        TabMoreOrphans: "This shadow tiddler contains the contents of the 'Orphans' tab in the right-hand sidebar",
        TabMoreShadowed: "This shadow tiddler contains the contents of the 'Shadowed' tab in the right-hand sidebar",
        TabTags: "This shadow tiddler contains the contents of the 'Tags' tab in the right-hand sidebar",
        TabTimeline: "This shadow tiddler contains the contents of the 'Timeline' tab in the right-hand sidebar",
        ViewTemplate: "The HTML template in this shadow tiddler determines how tiddlers look"
        });

//--
//-- Main
//--

var params = null; // Command line parameters
var store = null; // TiddlyWiki storage
var story = null; // Main story
var formatter = null; // Default formatters for the wikifier
config.parsers = {}; // Hashmap of alternative parsers for the wikifier
var anim = new Animator(); // Animation engine
var readOnly = false; // Whether we're in readonly mode
var highlightHack = null; // Embarrassing hack department...
var hadConfirmExit = false; // Don't warn more than once
var safeMode = false; // Disable all plugins and cookies
var installedPlugins = []; // Information filled in when plugins are executed
var startingUp = false; // Whether we're in the process of starting up
var pluginInfo,tiddler; // Used to pass information to plugins in loadPlugins()

// Whether to use the JavaSaver applet
var useJavaSaver = config.browser.isSafari || config.browser.isOpera;

// Starting up
function main()
{
        var t9,t8,t7,t6,t5,t4,t3,t2,t1,t0 = new Date();
        startingUp = true;
        window.onbeforeunload = function(e) {if(window.confirmExit) return confirmExit();};
        params = getParameters();
        if(params)
                params = params.parseParams("open",null,false);
        store = new TiddlyWiki();
        invokeParamifier(params,"oninit");
        story = new Story("tiddlerDisplay","tiddler");
        addEvent(document,"click",Popup.onDocumentClick);
        saveTest();
        loadOptionsCookie();
        for(var s=0; s<config.notifyTiddlers.length; s++)
                store.addNotification(config.notifyTiddlers[s].name,config.notifyTiddlers[s].notify);
        t1 = new Date();
        store.loadFromDiv("storeArea","store",true);
        t2 = new Date();
        loadShadowTiddlers();
        t3 = new Date();
        invokeParamifier(params,"onload");
        t4 = new Date();
        readOnly = (window.location.protocol == "file:") ? false : config.options.chkHttpReadOnly;
        var pluginProblem = loadPlugins();
        t5 = new Date();
        formatter = new Formatter(config.formatters);
        invokeParamifier(params,"onconfig");
        t6 = new Date();
        store.notifyAll();
        t7 = new Date();
        restart();
        t8 = new Date();
        if(pluginProblem) {
                story.displayTiddler(null,"PluginManager");
                displayMessage(config.messages.customConfigError);
        }
        for(var m in config.macros) {
                if(config.macros[m].init)
                        config.macros[m].init();
        }
        if(!readOnly)
                backstage.init();
        t9 = new Date();
        if(config.options.chkDisplayStartupTime) {
                displayMessage("Load in " + (t2-t1) + " ms");
                displayMessage("Loadshadows in " + (t3-t2) + " ms");
                displayMessage("Loadplugins in " + (t5-t4) + " ms");
                displayMessage("Notify in " + (t7-t6) + " ms");
                displayMessage("Restart in " + (t8-t7) + " ms");
                displayMessage("Total startup in " + (t9-t0) + " ms");
        }
        startingUp = false;
}

// Restarting
function restart()
{
        invokeParamifier(params,"onstart");
        if(story.isEmpty()) {
                var defaultParams = store.getTiddlerText("DefaultTiddlers").parseParams("open",null,false);
                invokeParamifier(defaultParams,"onstart");
        }
        window.scrollTo(0,0);
}

function saveTest()
{
        var s = document.getElementById("saveTest");
        if(s.hasChildNodes())
                alert(config.messages.savedSnapshotError);
        s.appendChild(document.createTextNode("savetest"));
}

function loadShadowTiddlers()
{
        var shadows = new TiddlyWiki();
        shadows.loadFromDiv("shadowArea","shadows",true);
        shadows.forEachTiddler(function(title,tiddler){config.shadowTiddlers[title] = tiddler.text;});
        delete shadows;
}

function loadPlugins()
{
        if(safeMode)
                return false;
        var tiddlers = store.getTaggedTiddlers("systemConfig");
        var toLoad = [];
        var nLoaded = 0;
        var map = {};
        var nPlugins = tiddlers.length;
        installedPlugins = [];
        for(var i=0; i<nPlugins; i++) {
                var p = getPluginInfo(tiddlers[i]);
                installedPlugins[i] = p;
                var n = p.Name;
                if(n) 
                        map[n] = p;
                if(n = p.Source) 
                        map[n] = p;
        }
        var visit = function(p) {
                if(!p || p.done)
                        return;
                p.done = 1;
                var reqs = p.Requires;
                if(reqs) {
                        reqs = reqs.readBracketedList();
                        for(var i=0; i<reqs.length; i++)
                                visit(map[reqs[i]]);
                }
                toLoad.push(p);
        };
        for(i=0; i<nPlugins; i++) 
                visit(installedPlugins[i]);        
        for(i=0; i<toLoad.length; i++) {
                p = toLoad[i];
                pluginInfo = p;
                tiddler = p.tiddler;
                if(isPluginExecutable(p)) {
                        if(isPluginEnabled(p)) {
                                p.executed = true;
                                var startTime = new Date();
                                try {
                                        if(tiddler.text)
                                                window.eval(tiddler.text);
                                        nLoaded++;
                                } catch(ex) {
                                        p.log.push(config.messages.pluginError.format([exceptionText(ex)]));
                                        p.error = true;
                                }
                                pluginInfo.startupTime = String((new Date()) - startTime) + "ms"; 
                        } else {
                                nPlugins--;
                        }
                } else {
                        p.warning = true;
                }
        }
        return nLoaded != nPlugins;
}

function getPluginInfo(tiddler)
{
        var p = store.getTiddlerSlices(tiddler.title,["Name","Description","Version","Requires","CoreVersion","Date","Source","Author","License","Browsers"]);
        p.tiddler = tiddler;
        p.title = tiddler.title;
        p.log = [];
        return p;
}

// Check that a particular plugin is valid for execution
function isPluginExecutable(plugin)
{
        if(plugin.tiddler.isTagged("systemConfigForce"))
                return verifyTail(plugin,true,config.messages.pluginForced);
        if(plugin["CoreVersion"]) {
                var coreVersion = plugin["CoreVersion"].split(".");
                var w = parseInt(coreVersion[0]) - version.major;
                if(w == 0 && coreVersion[1])
                        w = parseInt(coreVersion[1]) - version.minor;
                if(w == 0 && coreVersion[2])
                         w = parseInt(coreVersion[2]) - version.revision;
                if(w > 0)
                        return verifyTail(plugin,false,config.messages.pluginVersionError);
                }
        return true;
}

function isPluginEnabled(plugin)
{
        if(plugin.tiddler.isTagged("systemConfigDisable"))
                return verifyTail(plugin,false,config.messages.pluginDisabled);
        return true;
}

function verifyTail(plugin,result,message)
{
        plugin.log.push(message);
        return result;
}

function invokeMacro(place,macro,params,wikifier,tiddler)
{
        try {
                var m = config.macros[macro];
                if(m && m.handler)
                        m.handler(place,macro,params.readMacroParams(),wikifier,params,tiddler);
                else
                        createTiddlyError(place,config.messages.macroError.format([macro]),config.messages.macroErrorDetails.format([macro,config.messages.missingMacro]));
        } catch(ex) {
                createTiddlyError(place,config.messages.macroError.format([macro]),config.messages.macroErrorDetails.format([macro,ex.toString()]));
        }
}

//--
//-- Paramifiers
//--

function getParameters()
{
        var p = null;
        if(window.location.hash) {
                p = decodeURI(window.location.hash.substr(1));
                if(config.browser.firefoxDate != null && config.browser.firefoxDate[1] < "20051111")
                        p = convertUTF8ToUnicode(p);
        }
        return p;
}

function invokeParamifier(params,handler)
{
        if(!params || params.length == undefined || params.length <= 1)
                return;
        for(var t=1; t<params.length; t++) {
                var p = config.paramifiers[params[t].name];
                if(p && p[handler] instanceof Function)
                        p[handler](params[t].value);
        }
}

config.paramifiers = {};

config.paramifiers.start = {
        oninit: function(v) {
                safeMode = v.toLowerCase() == "safe";
        }
};

config.paramifiers.open = {
        onstart: function(v) {
                story.displayTiddler("bottom",v,null,false,null);
        }
};

config.paramifiers.story = {
        onstart: function(v) {
                var list = store.getTiddlerText(v,"").parseParams("open",null,false);
                invokeParamifier(list,"onstart");
        }
};

config.paramifiers.search = {
        onstart: function(v) {
                story.search(v,false,false);
        }
};

config.paramifiers.searchRegExp = {
        onstart: function(v) {
                story.prototype.search(v,false,true);
        }
};

config.paramifiers.tag = {
        onstart: function(v) {
                var tagged = store.getTaggedTiddlers(v,"title");
                for(var t=0; t<tagged.length; t++)
                        story.displayTiddler("bottom",tagged[t].title,null,false,null);
        }
};

config.paramifiers.newTiddler = {
        onstart: function(v) {
                if(!readOnly) {
                        story.displayTiddler(null,v,DEFAULT_EDIT_TEMPLATE);
                        story.focusTiddler(v,"text");
                }
        }
};

config.paramifiers.newJournal = {
        onstart: function(v) {
                if(!readOnly) {
                        var now = new Date();
                        var title = now.formatString(v.trim());
                        story.displayTiddler(null,title,DEFAULT_EDIT_TEMPLATE);
                        story.focusTiddler(title,"text");
                }
        }
};

config.paramifiers.readOnly = {
        onconfig: function(v) {
                var p = v.toLowerCase();
                readOnly = p == "yes" ? true : (p == "no" ? false : readOnly);
        }
};

//--
//-- Formatter helpers
//--

function Formatter(formatters)
{
        this.formatters = [];
        var pattern = [];
        for(var n=0; n<formatters.length; n++) {
                pattern.push("(" + formatters[n].match + ")");
                this.formatters.push(formatters[n]);
        }
        this.formatterRegExp = new RegExp(pattern.join("|"),"mg");
}

config.formatterHelpers = {

        createElementAndWikify: function(w)
        {
                w.subWikifyTerm(createTiddlyElement(w.output,this.element),this.termRegExp);
        },
        
        inlineCssHelper: function(w)
        {
                var styles = [];
                config.textPrimitives.cssLookaheadRegExp.lastIndex = w.nextMatch;
                var lookaheadMatch = config.textPrimitives.cssLookaheadRegExp.exec(w.source);
                while(lookaheadMatch && lookaheadMatch.index == w.nextMatch) {
                        var s,v;
                        if(lookaheadMatch[1]) {
                                s = lookaheadMatch[1].unDash();
                                v = lookaheadMatch[2];
                        } else {
                                s = lookaheadMatch[3].unDash();
                                v = lookaheadMatch[4];
                        }
                        if (s=="bgcolor")
                                s = "backgroundColor";
                        styles.push({style: s, value: v});
                        w.nextMatch = lookaheadMatch.index + lookaheadMatch[0].length;
                        config.textPrimitives.cssLookaheadRegExp.lastIndex = w.nextMatch;
                        lookaheadMatch = config.textPrimitives.cssLookaheadRegExp.exec(w.source);
                }
                return styles;
        },

        applyCssHelper: function(e,styles)
        {
                for(var t=0; t< styles.length; t++) {
                        try {
                                e.style[styles[t].style] = styles[t].value;
                        } catch (ex) {
                        }
                }
        },

        enclosedTextHelper: function(w)
        {
                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");
                        createTiddlyElement(w.output,this.element,null,null,text);
                        w.nextMatch = lookaheadMatch.index + lookaheadMatch[0].length;
                }
        },

        isExternalLink: function(link)
        {
                if(store.tiddlerExists(link) || store.isShadowTiddler(link)) {
                        return false;
                }
                var urlRegExp = new RegExp(config.textPrimitives.urlPattern,"mg");
                if(urlRegExp.exec(link)) {
                        return true;
                }
                if (link.indexOf(".")!=-1 || link.indexOf("\\")!=-1 || link.indexOf("/")!=-1){
                        return true;
                }
                return false;
        }

};

//--
//-- Standard formatters
//--

config.formatters = [
{
        name: "table",
        match: "^\\|(?:[^\\n]*)\\|(?:[fhck]?)$",
        lookaheadRegExp: /^\|([^\n]*)\|([fhck]?)$/mg,
        rowTermRegExp: /(\|(?:[fhck]?)$\n?)/mg,
        cellRegExp: /(?:\|([^\n\|]*)\|)|(\|[fhck]?$\n?)/mg,
        cellTermRegExp: /((?:\x20*)\|)/mg,
        rowTypes: {"c":"caption", "h":"thead", "":"tbody", "f":"tfoot"},

        handler: function(w)
        {
                var table = createTiddlyElement(w.output,"table");
                var prevColumns = [];
                var currRowType = null;
                var rowContainer;
                var rowCount = 0;
                w.nextMatch = w.matchStart;
                this.lookaheadRegExp.lastIndex = w.nextMatch;
                var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
                while(lookaheadMatch && lookaheadMatch.index == w.nextMatch) {
                        var nextRowType = lookaheadMatch[2];
                        if(nextRowType == "k") {
                                table.className = lookaheadMatch[1];
                                w.nextMatch += lookaheadMatch[0].length+1;
                        } else {
                                if(nextRowType != currRowType) {
                                        rowContainer = createTiddlyElement(table,this.rowTypes[nextRowType]);
                                        currRowType = nextRowType;
                                }
                                if(currRowType == "c") {
                                        // Caption
                                        w.nextMatch++;
                                        if(rowContainer != table.firstChild)
                                                table.insertBefore(rowContainer,table.firstChild);
                                        rowContainer.setAttribute("align",rowCount == 0?"top":"bottom");
                                        w.subWikifyTerm(rowContainer,this.rowTermRegExp);
                                } else {
                                        this.rowHandler(w,createTiddlyElement(rowContainer,"tr",null,(rowCount&1)?"oddRow":"evenRow"),prevColumns);
                                        rowCount++;
                                }
                        }
                        this.lookaheadRegExp.lastIndex = w.nextMatch;
                        lookaheadMatch = this.lookaheadRegExp.exec(w.source);
                }
        },
        rowHandler: function(w,e,prevColumns)
        {
                var col = 0;
                var colSpanCount = 1;
                var prevCell = null;
                this.cellRegExp.lastIndex = w.nextMatch;
                var cellMatch = this.cellRegExp.exec(w.source);
                while(cellMatch && cellMatch.index == w.nextMatch) {
                        if(cellMatch[1] == "~") {
                                // Rowspan
                                var last = prevColumns[col];
                                if(last) {
                                        last.rowSpanCount++;
                                        last.element.setAttribute("rowspan",last.rowSpanCount);
                                        last.element.setAttribute("rowSpan",last.rowSpanCount); // Needed for IE
                                        last.element.valign = "center";
                                }
                                w.nextMatch = this.cellRegExp.lastIndex-1;
                        } else if(cellMatch[1] == ">") {
                                // Colspan
                                colSpanCount++;
                                w.nextMatch = this.cellRegExp.lastIndex-1;
                        } else if(cellMatch[2]) {
                                // End of row
                                if(prevCell && colSpanCount > 1) {
                                        prevCell.setAttribute("colspan",colSpanCount);
                                        prevCell.setAttribute("colSpan",colSpanCount); // Needed for IE
                                }
                                w.nextMatch = this.cellRegExp.lastIndex;
                                break;
                        } else {
                                // Cell
                                w.nextMatch++;
                                var styles = config.formatterHelpers.inlineCssHelper(w);
                                var spaceLeft = false;
                                var chr = w.source.substr(w.nextMatch,1);
                                while(chr == " ") {
                                        spaceLeft = true;
                                        w.nextMatch++;
                                        chr = w.source.substr(w.nextMatch,1);
                                }
                                var cell;
                                if(chr == "!") {
                                        cell = createTiddlyElement(e,"th");
                                        w.nextMatch++;
                                } else {
                                        cell = createTiddlyElement(e,"td");
                                }
                                prevCell = cell;
                                prevColumns[col] = {rowSpanCount:1,element:cell};
                                if(colSpanCount > 1) {
                                        cell.setAttribute("colspan",colSpanCount);
                                        cell.setAttribute("colSpan",colSpanCount); // Needed for IE
                                        colSpanCount = 1;
                                }
                                config.formatterHelpers.applyCssHelper(cell,styles);
                                w.subWikifyTerm(cell,this.cellTermRegExp);
                                if(w.matchText.substr(w.matchText.length-2,1) == " ") // spaceRight
                                        cell.align = spaceLeft ? "center" : "left";
                                else if(spaceLeft)
                                        cell.align = "right";
                                w.nextMatch--;
                        }
                        col++;
                        this.cellRegExp.lastIndex = w.nextMatch;
                        cellMatch = this.cellRegExp.exec(w.source);
                }
        }
},

{
        name: "heading",
        match: "^!{1,6}",
        termRegExp: /(\n)/mg,
        handler: function(w)
        {
                w.subWikifyTerm(createTiddlyElement(w.output,"h" + w.matchLength),this.termRegExp);
        }
},

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

{
        name: "quoteByBlock",
        match: "^<<<\\n",
        termRegExp: /(^<<<(\n|$))/mg,
        element: "blockquote",
        handler: config.formatterHelpers.createElementAndWikify
},

{
        name: "quoteByLine",
        match: "^>+",
        lookaheadRegExp: /^>+/mg,
        termRegExp: /(\n)/mg,
        element: "blockquote",
        handler: function(w)
        {
                var stack = [w.output];
                var currLevel = 0;
                var newLevel = w.matchLength;
                var t;
                do {
                        if(newLevel > currLevel) {
                                for(t=currLevel; t<newLevel; t++)
                                        stack.push(createTiddlyElement(stack[stack.length-1],this.element));
                        } else if(newLevel < currLevel) {
                                for(t=currLevel; t>newLevel; t--)
                                        stack.pop();
                        }
                        currLevel = newLevel;
                        w.subWikifyTerm(stack[stack.length-1],this.termRegExp);
                        createTiddlyElement(stack[stack.length-1],"br");
                        this.lookaheadRegExp.lastIndex = w.nextMatch;
                        var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
                        var matched = lookaheadMatch && lookaheadMatch.index == w.nextMatch;
                        if(matched) {
                                newLevel = lookaheadMatch[0].length;
                                w.nextMatch += lookaheadMatch[0].length;
                        }
                } while(matched);
        }
},

{
        name: "rule",
        match: "^----+$\\n?",
        handler: function(w)
        {
                createTiddlyElement(w.output,"hr");
        }
},

{
        name: "monospacedByLine",
        match: "^\\{\\{\\{\\n",
        lookaheadRegExp: /^\{\{\{\n((?:^[^\n]*\n)+?)(^\}\}\}$\n?)/mg,
        element: "pre",
        handler: config.formatterHelpers.enclosedTextHelper
},

{
        name: "monospacedByLineForCSS",
        match: "^/\\*\\{\\{\\{\\*/\\n",
        lookaheadRegExp: /\/\*\{\{\{\*\/\n*((?:^[^\n]*\n)+?)(\n*^\/\*\}\}\}\*\/$\n?)/mg,
        element: "pre",
        handler: config.formatterHelpers.enclosedTextHelper
},

{
        name: "monospacedByLineForPlugin",
        match: "^//\\{\\{\\{\\n",
        lookaheadRegExp: /^\/\/\{\{\{\n\n*((?:^[^\n]*\n)+?)(\n*^\/\/\}\}\}$\n?)/mg,
        element: "pre",
        handler: config.formatterHelpers.enclosedTextHelper
},

{
        name: "monospacedByLineForTemplate",
        match: "^<!--\\{\\{\\{-->\\n",
        lookaheadRegExp: /<!--\{\{\{-->\n*((?:^[^\n]*\n)+?)(\n*^<!--\}\}\}-->$\n?)/mg,
        element: "pre",
        handler: config.formatterHelpers.enclosedTextHelper
},

{
        name: "wikifyCommentForPlugin",
        match: "^/\\*\\*\\*\\n",
        termRegExp: /(^\*\*\*\/\n)/mg,
        handler: function(w)
        {
                w.subWikifyTerm(w.output,this.termRegExp);
        }
},

{
        name: "wikifyCommentForTemplate",
        match: "^<!---\\n",
        termRegExp: /(^--->\n)/mg,
        handler: function(w) 
        {
                w.subWikifyTerm(w.output,this.termRegExp);
        }
},

{
        name: "macro",
        match: "<<",
        lookaheadRegExp: /<<([^>\s]+)(?:\s*)((?:[^>]|(?:>(?!>)))*)>>/mg,
        handler: function(w)
        {
                this.lookaheadRegExp.lastIndex = w.matchStart;
                var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
                if(lookaheadMatch && lookaheadMatch.index == w.matchStart && lookaheadMatch[1]) {
                        w.nextMatch = this.lookaheadRegExp.lastIndex;
                        invokeMacro(w.output,lookaheadMatch[1],lookaheadMatch[2],w,w.tiddler);
                }
        }
},

{
        name: "prettyLink",
        match: "\\[\\[",
        lookaheadRegExp: /\[\[(.*?)(?:\|(~)?(.*?))?\]\]/mg,
        handler: function(w)
        {
                this.lookaheadRegExp.lastIndex = w.matchStart;
                var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
                if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
                        var e;
                        var text = lookaheadMatch[1];
                        if(lookaheadMatch[3]) {
                                // Pretty bracketted link
                                var link = lookaheadMatch[3];
                                e = (!lookaheadMatch[2] && config.formatterHelpers.isExternalLink(link)) ?
                                                createExternalLink(w.output,link) : createTiddlyLink(w.output,link,false,null,w.isStatic,w.tiddler);
                        } else {
                                // Simple bracketted link
                                e = createTiddlyLink(w.output,text,false,null,w.isStatic,w.tiddler);
                        }
                        createTiddlyText(e,text);
                        w.nextMatch = this.lookaheadRegExp.lastIndex;
                }
        }
},

{
        name: "unWikiLink",
        match: config.textPrimitives.unWikiLink+config.textPrimitives.wikiLink,
        handler: function(w)
        {
                w.outputText(w.output,w.matchStart+1,w.nextMatch);
        }
},

{
        name: "wikiLink",
        match: config.textPrimitives.wikiLink,
        handler: function(w)
        {
                if(w.matchStart > 0) {
                        var preRegExp = new RegExp(config.textPrimitives.anyLetterStrict,"mg");
                        preRegExp.lastIndex = w.matchStart-1;
                        var preMatch = preRegExp.exec(w.source);
                        if(preMatch.index == w.matchStart-1) {
                                w.outputText(w.output,w.matchStart,w.nextMatch);
                                return;
                        }
                }
                if(w.autoLinkWikiWords == true || store.isShadowTiddler(w.matchText)) {
                        var link = createTiddlyLink(w.output,w.matchText,false,null,w.isStatic,w.tiddler);
                        w.outputText(link,w.matchStart,w.nextMatch);
                } else {
                        w.outputText(w.output,w.matchStart,w.nextMatch);
                }
        }
},

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

{
        name: "image",
        match: "\\[[<>]?[Ii][Mm][Gg]\\[",
        lookaheadRegExp: /\[([<]?)(>?)[Ii][Mm][Gg]\[(?:([^\|\]]+)\|)?([^\[\]\|]+)\](?:\[([^\]]*)\])?\]/mg,
        handler: function(w)
        {
                this.lookaheadRegExp.lastIndex = w.matchStart;
                var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
                if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
                        var e = w.output;
                        if(lookaheadMatch[5]) {
                                var link = lookaheadMatch[5];
                                e = config.formatterHelpers.isExternalLink(link) ? createExternalLink(w.output,link) : createTiddlyLink(w.output,link,false,null,w.isStatic,w.tiddler);
                                addClass(e,"imageLink");
                        }
                        var img = createTiddlyElement(e,"img");
                        if(lookaheadMatch[1])
                                img.align = "left";
                        else if(lookaheadMatch[2])
                                img.align = "right";
                        if(lookaheadMatch[3])
                                img.title = lookaheadMatch[3];
                        img.src = lookaheadMatch[4];
                        w.nextMatch = this.lookaheadRegExp.lastIndex;
                }
        }
},

{
        name: "html",
        match: "<[Hh][Tt][Mm][Ll]>",
        lookaheadRegExp: /<[Hh][Tt][Mm][Ll]>((?:.|\n)*?)<\/[Hh][Tt][Mm][Ll]>/mg,
        handler: function(w)
        {
                this.lookaheadRegExp.lastIndex = w.matchStart;
                var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
                if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
                        createTiddlyElement(w.output,"span").innerHTML = lookaheadMatch[1];
                        w.nextMatch = this.lookaheadRegExp.lastIndex;
                }
        }
},

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

{
        name: "boldByChar",
        match: "''",
        termRegExp: /('')/mg,
        element: "strong",
        handler: config.formatterHelpers.createElementAndWikify
},

{
        name: "italicByChar",
        match: "//",
        termRegExp: /(\/\/)/mg,
        element: "em",
        handler: config.formatterHelpers.createElementAndWikify
},

{
        name: "underlineByChar",
        match: "__",
        termRegExp: /(__)/mg,
        element: "u",
        handler: config.formatterHelpers.createElementAndWikify
},

{
        name: "strikeByChar",
        match: "--(?!\\s|$)",
        termRegExp: /((?!\s)--|(?=\n\n))/mg,
        element: "strike",
        handler: config.formatterHelpers.createElementAndWikify
},

{
        name: "superscriptByChar",
        match: "\\^\\^",
        termRegExp: /(\^\^)/mg,
        element: "sup",
        handler: config.formatterHelpers.createElementAndWikify
},

{
        name: "subscriptByChar",
        match: "~~",
        termRegExp: /(~~)/mg,
        element: "sub",
        handler: config.formatterHelpers.createElementAndWikify
},

{
        name: "monospacedByChar",
        match: "\\{\\{\\{",
        lookaheadRegExp: /\{\{\{((?:.|\n)*?)\}\}\}/mg,
        handler: function(w)
        {
                this.lookaheadRegExp.lastIndex = w.matchStart;
                var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
                if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
                        createTiddlyElement(w.output,"code",null,null,lookaheadMatch[1]);
                        w.nextMatch = this.lookaheadRegExp.lastIndex;
                }
        }
},

{
        name: "styleByChar",
        match: "@@",
        termRegExp: /(@@)/mg,
        handler: function(w)
        {
                var e = createTiddlyElement(w.output,"span");
                var styles = config.formatterHelpers.inlineCssHelper(w);
                if(styles.length == 0)
                        e.className = "marked";
                else
                        config.formatterHelpers.applyCssHelper(e,styles);
                w.subWikifyTerm(e,this.termRegExp);
        }
},

{
        name: "lineBreak",
        match: "\\n|<br ?/?>",
        handler: function(w)
        {
                createTiddlyElement(w.output,"br");
        }
},

{
        name: "rawText",
        match: "\\\"{3}|<nowiki>",
        lookaheadRegExp: /(?:\"{3}|<nowiki>)((?:.|\n)*?)(?:\"{3}|<\/nowiki>)/mg,
        handler: function(w)
        {
                this.lookaheadRegExp.lastIndex = w.matchStart;
                var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
                if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
                        createTiddlyElement(w.output,"span",null,null,lookaheadMatch[1]);
                        w.nextMatch = this.lookaheadRegExp.lastIndex;
                }
        }
},

{
        name: "mdash",
        match: "--",
        handler: function(w)
        {
                createTiddlyElement(w.output,"span").innerHTML = "&mdash;";
        }
},

{
        name: "htmlEntitiesEncoding",
        match: "(?:(?:&#?[a-zA-Z0-9]{2,8};|.)(?:&#?(?:x0*(?:3[0-6][0-9a-fA-F]|1D[c-fC-F][0-9a-fA-F]|20[d-fD-F][0-9a-fA-F]|FE2[0-9a-fA-F])|0*(?:76[89]|7[7-9][0-9]|8[0-7][0-9]|761[6-9]|76[2-7][0-9]|84[0-3][0-9]|844[0-7]|6505[6-9]|6506[0-9]|6507[0-1]));)+|&#?[a-zA-Z0-9]{2,8};)",
        handler: function(w)
        {
                createTiddlyElement(w.output,"span").innerHTML = w.matchText;
        }
},

{
        name: "customClasses",
        match: "\\{\\{",
        termRegExp: /(\}\}\})/mg,
        lookaheadRegExp: /\{\{[\s]*([\w]+[\s\w]*)[\s]*\{(\n?)/mg,
        handler: function(w)
        {
                this.lookaheadRegExp.lastIndex = w.matchStart;
                var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
                if(lookaheadMatch) {
                        var e = createTiddlyElement(w.output,lookaheadMatch[2] == "\n" ? "div" : "span",null,lookaheadMatch[1]);
                        w.nextMatch = this.lookaheadRegExp.lastIndex;
                        w.subWikifyTerm(e,this.termRegExp);
                }
        }
}

];

//--
//-- Wikifier
//--

function getParser(tiddler,format)
{
        if(tiddler) {
                if(!format)
                        format = tiddler.fields["wikiformat"];
                if(format) {
                        for(var i in config.parsers) {
                                if(format == config.parsers[i].format)
                                        return config.parsers[i];
                        }
                } else {
                        for(var i in config.parsers) {
                                if(tiddler.isTagged(config.parsers[i].formatTag))
                                        return config.parsers[i];
                        }
                }
        }
        return formatter;
}

function wikify(source,output,highlightRegExp,tiddler)
{
        if(source && source != "") {
                var wikifier = new Wikifier(source,getParser(tiddler),highlightRegExp,tiddler);
                wikifier.subWikifyUnterm(output);
        }
}

function wikifyStatic(source,highlightRegExp,tiddler,format)
{
        var e = createTiddlyElement(document.body,"div");
        e.style.display = "none";
        var html = "";
        if(source && source != "") {
                var wikifier = new Wikifier(source,getParser(tiddler,format),highlightRegExp,tiddler);
                wikifier.isStatic = true;
                wikifier.subWikifyUnterm(e);
                html = e.innerHTML;
                removeNode(e);
        }
        return html;
}

function wikifyPlain(title,theStore,limit)
{
        if(!theStore)
                theStore = store;
        if(theStore.tiddlerExists(title) || theStore.isShadowTiddler(title)) {
                return wikifyPlainText(theStore.getTiddlerText(title),limit,tiddler);
        } else {
                return "";
        }
}

function wikifyPlainText(text,limit,tiddler)
{
        if(limit > 0)
                text = text.substr(0,limit);
        var wikifier = new Wikifier(text,formatter,null,tiddler);
        return wikifier.wikifyPlain();
}

function highlightify(source,output,highlightRegExp,tiddler)
{
        if(source && source != "") {
                var wikifier = new Wikifier(source,formatter,highlightRegExp,tiddler);
                wikifier.outputText(output,0,source.length);
        }
}

function Wikifier(source,formatter,highlightRegExp,tiddler)
{
        this.source = source;
        this.output = null;
        this.formatter = formatter;
        this.nextMatch = 0;
        this.autoLinkWikiWords = tiddler && tiddler.autoLinkWikiWords() == false ? false : true;
        this.highlightRegExp = highlightRegExp;
        this.highlightMatch = null;
        this.isStatic = false;
        if(highlightRegExp) {
                highlightRegExp.lastIndex = 0;
                this.highlightMatch = highlightRegExp.exec(source);
        }
        this.tiddler = tiddler;
}

Wikifier.prototype.wikifyPlain = function()
{
        var e = createTiddlyElement(document.body,"div");
        this.subWikify(e);
        var text = getPlainText(e);
        removeNode(e);
        return text;
};

Wikifier.prototype.subWikify = function(output,terminator)
{
        if(terminator)
                this.subWikifyTerm(output,new RegExp("(" + terminator + ")","mg"));
        else
                this.subWikifyUnterm(output);
};

Wikifier.prototype.subWikifyUnterm = function(output)
{
        // subWikify() can be indirectly recursive, so we need to save the old output pointer
        var oldOutput = this.output;
        this.output = output;
        this.formatter.formatterRegExp.lastIndex = this.nextMatch;
        var formatterMatch = this.formatter.formatterRegExp.exec(this.source);
        while(formatterMatch) {
                // Output any text before the match
                if(formatterMatch.index > this.nextMatch)
                        this.outputText(this.output,this.nextMatch,formatterMatch.index);
                // Set the match parameters for the handler
                this.matchStart = formatterMatch.index;
                this.matchLength = formatterMatch[0].length;
                this.matchText = formatterMatch[0];
                this.nextMatch = this.formatter.formatterRegExp.lastIndex;
                for(var t=1; t<formatterMatch.length; t++) {
                        if(formatterMatch[t]) {
                                this.formatter.formatters[t-1].handler(this);
                                this.formatter.formatterRegExp.lastIndex = this.nextMatch;
                                break;
                        }
                }
                formatterMatch = this.formatter.formatterRegExp.exec(this.source);
        }
        if(this.nextMatch < this.source.length) {
                this.outputText(this.output,this.nextMatch,this.source.length);
                this.nextMatch = this.source.length;
        }
        this.output = oldOutput;
};

Wikifier.prototype.subWikifyTerm = function(output,terminatorRegExp)
{
        // subWikify() can be indirectly recursive, so we need to save the old output pointer
        var oldOutput = this.output;
        this.output = output;
        // Get the first matches for the formatter and terminator RegExps
        terminatorRegExp.lastIndex = this.nextMatch;
        var terminatorMatch = terminatorRegExp.exec(this.source);
        this.formatter.formatterRegExp.lastIndex = this.nextMatch;
        var formatterMatch = this.formatter.formatterRegExp.exec(terminatorMatch ? this.source.substr(0,terminatorMatch.index) : this.source);
        while(terminatorMatch || formatterMatch) {
                if(terminatorMatch && (!formatterMatch || terminatorMatch.index <= formatterMatch.index)) {
                        if(terminatorMatch.index > this.nextMatch)
                                this.outputText(this.output,this.nextMatch,terminatorMatch.index);
                        this.matchText = terminatorMatch[1];
                        this.matchLength = terminatorMatch[1].length;
                        this.matchStart = terminatorMatch.index;
                        this.nextMatch = this.matchStart + this.matchLength;
                        this.output = oldOutput;
                        return;
                }
                if(formatterMatch.index > this.nextMatch)
                        this.outputText(this.output,this.nextMatch,formatterMatch.index);
                this.matchStart = formatterMatch.index;
                this.matchLength = formatterMatch[0].length;
                this.matchText = formatterMatch[0];
                this.nextMatch = this.formatter.formatterRegExp.lastIndex;
                for(var t=1; t<formatterMatch.length; t++) {
                        if(formatterMatch[t]) {
                                this.formatter.formatters[t-1].handler(this);
                                this.formatter.formatterRegExp.lastIndex = this.nextMatch;
                                break;
                        }
                }
                terminatorRegExp.lastIndex = this.nextMatch;
                terminatorMatch = terminatorRegExp.exec(this.source);
                formatterMatch = this.formatter.formatterRegExp.exec(terminatorMatch ? this.source.substr(0,terminatorMatch.index) : this.source);
        }
        if(this.nextMatch < this.source.length) {
                this.outputText(this.output,this.nextMatch,this.source.length);
                this.nextMatch = this.source.length;
        }
        this.output = oldOutput;
};

Wikifier.prototype.outputText = function(place,startPos,endPos)
{
        while(this.highlightMatch && (this.highlightRegExp.lastIndex > startPos) && (this.highlightMatch.index < endPos) && (startPos < endPos)) {
                if(this.highlightMatch.index > startPos) {
                        createTiddlyText(place,this.source.substring(startPos,this.highlightMatch.index));
                        startPos = this.highlightMatch.index;
                }
                var highlightEnd = Math.min(this.highlightRegExp.lastIndex,endPos);
                var theHighlight = createTiddlyElement(place,"span",null,"highlight",this.source.substring(startPos,highlightEnd));
                startPos = highlightEnd;
                if(startPos >= this.highlightRegExp.lastIndex)
                        this.highlightMatch = this.highlightRegExp.exec(this.source);
        }
        if(startPos < endPos) {
                createTiddlyText(place,this.source.substring(startPos,endPos));
        }
};

//--
//-- Macro definitions
//--

config.macros.today.handler = function(place,macroName,params)
{
        var now = new Date();
        var text;
        if(params[0])
                text = now.formatString(params[0].trim());
        else
                text = now.toLocaleString();
        createTiddlyElement(place,"span",null,null,text);
};

config.macros.version.handler = function(place)
{
        createTiddlyElement(place,"span",null,null,version.major + "." + version.minor + "." + version.revision + (version.beta ? " (beta " + version.beta + ")" : ""));
};

config.macros.list.handler = function(place,macroName,params)
{
        var type = params[0] ? params[0] : "all";
        var list = document.createElement("ul");
        place.appendChild(list);
        if(this[type].prompt)
                createTiddlyElement(list,"li",null,"listTitle",this[type].prompt);
        var results;
        if(this[type].handler)
                results = this[type].handler(params);
        for(var t = 0; t < results.length; t++) {
                var li = document.createElement("li");
                list.appendChild(li);
                createTiddlyLink(li,typeof results[t] == "string" ? results[t] : results[t].title,true);
        }
};

config.macros.list.all.handler = function(params)
{
        return store.reverseLookup("tags","excludeLists",false,"title");
};

config.macros.list.missing.handler = function(params)
{
        return store.getMissingLinks();
};

config.macros.list.orphans.handler = function(params)
{
        return store.getOrphans();
};

config.macros.list.shadowed.handler = function(params)
{
        return store.getShadowed();
};

config.macros.list.touched.handler = function(params)
{
        return store.getTouched();
};

config.macros.allTags.handler = function(place,macroName,params)
{
        var tags = store.getTags(params[0]);
        var ul = createTiddlyElement(place,"ul");
        if(tags.length == 0)
                createTiddlyElement(ul,"li",null,"listTitle",this.noTags);
        for(var t=0; t<tags.length; t++) {
                var title = tags[t][0];
                var info = getTiddlyLinkInfo(title);
                var li =createTiddlyElement(ul,"li");
                var btn = createTiddlyButton(li,title + " (" + tags[t][1] + ")",this.tooltip.format([title]),onClickTag,info.classes);
                btn.setAttribute("tag",title);
                btn.setAttribute("refresh","link");
                btn.setAttribute("tiddlyLink",title);
        }
};

config.macros.timeline.handler = function(place,macroName,params)
{
        var field = params[0] ? params[0] : "modified";
        var tiddlers = store.reverseLookup("tags","excludeLists",false,field);
        var lastDay = "";
        var last = params[1] ? tiddlers.length-Math.min(tiddlers.length,parseInt(params[1])) : 0;
        for(var t=tiddlers.length-1; t>=last; t--) {
                var tiddler = tiddlers[t];
                var theDay = tiddler[field].convertToLocalYYYYMMDDHHMM().substr(0,8);
                if(theDay != lastDay) {
                        var theDateList = document.createElement("ul");
                        place.appendChild(theDateList);
                        createTiddlyElement(theDateList,"li",null,"listTitle",tiddler[field].formatString(this.dateFormat));
                        lastDay = theDay;
                }
                var theDateListItem = createTiddlyElement(theDateList,"li",null,"listLink");
                theDateListItem.appendChild(createTiddlyLink(place,tiddler.title,true));
        }
};

config.macros.search.handler = function(place,macroName,params)
{
        var searchTimeout = null;
        var btn = createTiddlyButton(place,this.label,this.prompt,this.onClick);
        var txt = createTiddlyElement(place,"input",null,"txtOptionInput");
        if(params[0])
                txt.value = params[0];
        txt.onkeyup = this.onKeyPress;
        txt.onfocus = this.onFocus;
        txt.setAttribute("size",this.sizeTextbox);
        txt.setAttribute("accessKey",this.accessKey);
        txt.setAttribute("autocomplete","off");
        txt.setAttribute("lastSearchText","");
        if(config.browser.isSafari) {
                txt.setAttribute("type","search");
                txt.setAttribute("results","5");
        } else {
                txt.setAttribute("type","text");
        }
};

// Global because there's only ever one outstanding incremental search timer
config.macros.search.timeout = null;

config.macros.search.doSearch = function(txt)
{
        if(txt.value.length > 0) {
                story.search(txt.value,config.options.chkCaseSensitiveSearch,config.options.chkRegExpSearch);
                txt.setAttribute("lastSearchText",txt.value);
        }
};

config.macros.search.onClick = function(e)
{
        config.macros.search.doSearch(this.nextSibling);
        return false;
};

config.macros.search.onKeyPress = function(e)
{
        if(!e) var e = window.event;
        switch(e.keyCode) {
                case 13: // Ctrl-Enter
                case 10: // Ctrl-Enter on IE PC
                        config.macros.search.doSearch(this);
                        break;
                case 27: // Escape
                        this.value = "";
                        clearMessage();
                        break;
        }
        if(this.value.length > 2) {
                if(this.value != this.getAttribute("lastSearchText")) {
                        if(config.macros.search.timeout)
                                clearTimeout(config.macros.search.timeout);
                        var txt = this;
                        config.macros.search.timeout = setTimeout(function() {config.macros.search.doSearch(txt);},500);
                }
        } else {
                if(config.macros.search.timeout)
                        clearTimeout(config.macros.search.timeout);
        }
};

config.macros.search.onFocus = function(e)
{
        this.select();
};

config.macros.tiddler.handler = function(place,macroName,params,wikifier,paramString,tiddler)
{
        params = paramString.parseParams("name",null,true,false,true);
        var names = params[0]["name"];
        var tiddlerName = names[0];
        var className = names[1] ? names[1] : null;
        var args = params[0]["with"];
        var wrapper = createTiddlyElement(place,"span",null,className);
        if(!args) {
                wrapper.setAttribute("refresh","content");
                wrapper.setAttribute("tiddler",tiddlerName);
        }
        var text = store.getTiddlerText(tiddlerName);
        if(text) {
                var stack = config.macros.tiddler.tiddlerStack;
                if(stack.indexOf(tiddlerName) !== -1)
                        return;
                stack.push(tiddlerName);
                try {
                        var n = args ? Math.min(args.length,9) : 0;
                        for(var i=0; i<n; i++) {
                                var placeholderRE = new RegExp("\\$" + (i + 1),"mg");
                                text = text.replace(placeholderRE,args[i]);
                        }
                        config.macros.tiddler.renderText(wrapper,text,tiddlerName,params);
                } finally {
                        stack.pop();
                }
        }
};

config.macros.tiddler.renderText = function(place,text,tiddlerName,params) 
{
        wikify(text,place,null,store.getTiddler(tiddlerName));
};

config.macros.tiddler.tiddlerStack = [];

config.macros.tag.handler = function(place,macroName,params)
{
        createTagButton(place,params[0]);
};

config.macros.tags.handler = function(place,macroName,params,wikifier,paramString,tiddler)
{
        params = paramString.parseParams("anon",null,true,false,false);
        var theList = createTiddlyElement(place,"ul");
        var title = getParam(params,"anon","");
        if(title && store.tiddlerExists(title))
                tiddler = store.getTiddler(title);
        var sep = getParam(params,"sep"," ");
        var lingo = config.views.wikified.tag;
        var prompt = tiddler.tags.length == 0 ? lingo.labelNoTags : lingo.labelTags;
        createTiddlyElement(theList,"li",null,"listTitle",prompt.format([tiddler.title]));
        for(var t=0; t<tiddler.tags.length; t++) {
                createTagButton(createTiddlyElement(theList,"li"),tiddler.tags[t],tiddler.title);
                if(t<tiddler.tags.length-1)
                        createTiddlyText(theList,sep);
        }
};

config.macros.tagging.handler = function(place,macroName,params,wikifier,paramString,tiddler)
{
        params = paramString.parseParams("anon",null,true,false,false);
        var theList = createTiddlyElement(place,"ul");
        var title = getParam(params,"anon","");
        if(title == "" && tiddler instanceof Tiddler)
                title = tiddler.title;
        var sep = getParam(params,"sep"," ");
        theList.setAttribute("title",this.tooltip.format([title]));
        var tagged = store.getTaggedTiddlers(title);
        var prompt = tagged.length == 0 ? this.labelNotTag : this.label;
        createTiddlyElement(theList,"li",null,"listTitle",prompt.format([title,tagged.length]));
        for(var t=0; t<tagged.length; t++) {
                createTiddlyLink(createTiddlyElement(theList,"li"),tagged[t].title,true);
                if(t<tagged.length-1)
                        createTiddlyText(theList,sep);
        }
};

config.macros.closeAll.handler = function(place)
{
        createTiddlyButton(place,this.label,this.prompt,this.onClick);
};

config.macros.closeAll.onClick = function(e)
{
        story.closeAllTiddlers();
        return false;
};

config.macros.permaview.handler = function(place)
{
        createTiddlyButton(place,this.label,this.prompt,this.onClick);
};

config.macros.permaview.onClick = function(e)
{
        story.permaView();
        return false;
};

config.macros.saveChanges.handler = function(place)
{
        if(!readOnly)
                createTiddlyButton(place,this.label,this.prompt,this.onClick,null,null,this.accessKey);
};

config.macros.saveChanges.onClick = function(e)
{
        saveChanges();
        return false;
};

config.macros.slider.onClickSlider = function(e)
{
        if(!e) var e = window.event;
        var n = this.nextSibling;
        var cookie = n.getAttribute("cookie");
        var isOpen = n.style.display != "none";
        if(config.options.chkAnimate && anim && typeof Slider == "function")
                anim.startAnimating(new Slider(n,!isOpen,null,"none"));
        else
                n.style.display = isOpen ? "none" : "block";
        config.options[cookie] = !isOpen;
        saveOptionCookie(cookie);
        return false;
};

config.macros.slider.createSlider = function(place,cookie,title,tooltip)
{
        var cookie = cookie ? cookie : "";
        var btn = createTiddlyButton(place,title,tooltip,this.onClickSlider);
        var panel = createTiddlyElement(null,"div",null,"sliderPanel");
        panel.setAttribute("cookie",cookie);
        panel.style.display = config.options[cookie] ? "block" : "none";
        place.appendChild(panel);
        return panel;
};

config.macros.slider.handler = function(place,macroName,params)
{
        var panel = this.createSlider(place,params[0],params[2],params[3]);
        var text = store.getTiddlerText(params[1]);
        panel.setAttribute("refresh","content");
        panel.setAttribute("tiddler",params[1]);
        if(text)
                wikify(text,panel,null,store.getTiddler(params[1]));
};

config.macros.option.genericCreate = function(place,type,opt,className,desc)
{
        var typeInfo = config.macros.option.types[type];
        var c = document.createElement(typeInfo.elementType);
        if(typeInfo.typeValue)
                c.setAttribute("type",typeInfo.typeValue);
        c[typeInfo.eventName] = typeInfo.onChange;
        c.setAttribute("option",opt);
        if(className)
                c.className = className;
        else
                c.className = typeInfo.className;
        if(config.optionsDesc[opt])
                c.setAttribute("title",config.optionsDesc[opt]);
        place.appendChild(c);
        if(desc != "no")
                createTiddlyText(place,config.optionsDesc[opt] ? config.optionsDesc[opt] : opt);
        c[typeInfo.valueField] = config.options[opt];
        return c;
};

config.macros.option.genericOnChange = function(e)
{
        var opt = this.getAttribute("option");
        if(opt) {
                var optType = opt.substr(0,3);
                var handler = config.macros.option.types[optType];
                if (handler.elementType && handler.valueField)
                        config.macros.option.propagateOption(opt,handler.valueField,this[handler.valueField],handler.elementType);
                }
        return true;
};

config.macros.option.types = {
        'txt': {
                elementType: "input",
                valueField: "value",
                eventName: "onkeyup",
                className: "txtOptionInput",
                create: config.macros.option.genericCreate,
                onChange: config.macros.option.genericOnChange
        },
        'chk': {
                elementType: "input",
                valueField: "checked",
                eventName: "onclick",
                className: "chkOptionInput",
                typeValue: "checkbox",
                create: config.macros.option.genericCreate,
                onChange: config.macros.option.genericOnChange
        }
};

config.macros.option.propagateOption = function(opt,valueField,value,elementType)
{
        config.options[opt] = value;
        saveOptionCookie(opt);
        var nodes = document.getElementsByTagName(elementType);
        for(var t=0; t<nodes.length; t++) {
                var optNode = nodes[t].getAttribute("option");
                if(opt == optNode)
                        nodes[t][valueField] = value;
                }
};

config.macros.option.handler = function(place,macroName,params,wikifier,paramString,tiddler)
{
        params = paramString.parseParams("anon",null,true,false,false);
        var opt = (params[1] && params[1].name == "anon") ? params[1].value : getParam(params,"name",null);
        var className = (params[2] && params[2].name == "anon") ? params[2].value : getParam(params,"class",null);
        var desc = getParam(params,"desc","no");
        var type = opt.substr(0,3);
        var h = config.macros.option.types[type];
        if (h && h.create)
                h.create(place,type,opt,className,desc);
};

config.macros.options.handler = function(place,macroName,params,wikifier,paramString,tiddler)
{
        params = paramString.parseParams("anon",null,true,false,false);
        var showUnknown = getParam(params,"showUnknown","no");
        var wizard = new Wizard();
        wizard.createWizard(place,this.wizardTitle);
        wizard.addStep(this.step1Title,this.step1Html);
        var markList = wizard.getElement("markList");
        var chkUnknown = wizard.getElement("chkUnknown");
        chkUnknown.checked = showUnknown == "yes";
        chkUnknown.onchange = this.onChangeUnknown;
        var listWrapper = document.createElement("div");
        markList.parentNode.insertBefore(listWrapper,markList);
        wizard.setValue("listWrapper",listWrapper);
        this.refreshOptions(listWrapper,showUnknown == "yes");
};

config.macros.options.refreshOptions = function(listWrapper,showUnknown)
{        
        var opts = [];
        for(var n in config.options) {
                var opt = {};
                opt.option = "";
                opt.name = n;
                opt.lowlight = !config.optionsDesc[n];
                opt.description = opt.lowlight ? this.unknownDescription : config.optionsDesc[n];
                if(!opt.lowlight || showUnknown)
                        opts.push(opt);
        }
        opts.sort(function(a,b) {return a.name.substr(3) < b.name.substr(3) ? -1 : (a.name.substr(3) == b.name.substr(3) ? 0 : +1);});
        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,null,"no");
                }
        }
};

config.macros.options.onChangeUnknown = function(e)
{
        var wizard = new Wizard(this);
        var listWrapper = wizard.getValue("listWrapper");
        removeChildren(listWrapper);
        config.macros.options.refreshOptions(listWrapper,this.checked);
        return false;
};

config.macros.newTiddler.createNewTiddlerButton = function(place,title,params,label,prompt,accessKey,newFocus,isJournal)
{
        var tags = [];
        for(var t=1; t<params.length; t++) {
                if((params[t].name == "anon" && t != 1) || (params[t].name == "tag"))
                        tags.push(params[t].value);
        }
        label = getParam(params,"label",label);
        prompt = getParam(params,"prompt",prompt);
        accessKey = getParam(params,"accessKey",accessKey);
        newFocus = getParam(params,"focus",newFocus);
        var customFields = getParam(params,"fields");
        if(!customFields && !store.isShadowTiddler(title))
                customFields = String.encodeHashMap(config.defaultCustomFields);
        var btn = createTiddlyButton(place,label,prompt,this.onClickNewTiddler,null,null,accessKey);
        btn.setAttribute("newTitle",title);
        btn.setAttribute("isJournal",isJournal ? "true" : "false");
        btn.setAttribute("params",tags.join("|"));
        btn.setAttribute("newFocus",newFocus);
        btn.setAttribute("newTemplate",getParam(params,"template",DEFAULT_EDIT_TEMPLATE));
        btn.setAttribute("customFields",customFields);
        var text = getParam(params,"text");
        if(text !== undefined) 
                btn.setAttribute("newText",text);
        return btn;
};

config.macros.newTiddler.onClickNewTiddler = function()
{
        var title = this.getAttribute("newTitle");
        if(this.getAttribute("isJournal") == "true") {
                var now = new Date();
                title = now.formatString(title.trim());
        }
        var params = this.getAttribute("params").split("|");
        var focus = this.getAttribute("newFocus");
        var template = this.getAttribute("newTemplate");
        var customFields = this.getAttribute("customFields");
        story.displayTiddler(null,title,template,false,null,customFields);
        var text = this.getAttribute("newText");
        if(typeof text == "string")
                story.getTiddlerField(title,"text").value = text.format([title]);
        for(var t=0;t<params.length;t++)
                story.setTiddlerTag(title,params[t],+1);
        story.focusTiddler(title,focus);
        return false;
};

config.macros.newTiddler.handler = function(place,macroName,params,wikifier,paramString,tiddler)
{
        if(!readOnly) {
                params = paramString.parseParams("anon",null,true,false,false);
                var title = params[1] && params[1].name == "anon" ? params[1].value : this.title;
                title = getParam(params,"title",title);
                this.createNewTiddlerButton(place,title,params,this.label,this.prompt,this.accessKey,"title",false);
        }
};

config.macros.newJournal.handler = function(place,macroName,params,wikifier,paramString,tiddler)
{
        if(!readOnly) {
                params = paramString.parseParams("anon",null,true,false,false);
                var title = params[1] && params[1].name == "anon" ? params[1].value : "";
                title = getParam(params,"title",title);
                config.macros.newTiddler.createNewTiddlerButton(place,title,params,this.label,this.prompt,this.accessKey,"text",true);
        }
};

config.macros.sparkline.handler = function(place,macroName,params)
{
        var data = [];
        var min = 0;
        var max = 0;
        for(var t=0; t<params.length; t++) {
                var v = parseInt(params[t]);
                if(v < min)
                        min = v;
                if(v > max)
                        max = v;
                data.push(v);
        }
        if(data.length < 1)
                return;
        var box = createTiddlyElement(place,"span",null,"sparkline",String.fromCharCode(160));
        box.title = data.join(",");
        var w = box.offsetWidth;
        var h = box.offsetHeight;
        box.style.paddingRight = (data.length * 2 - w) + "px";
        box.style.position = "relative";
        for(var d=0; d<data.length; d++) {
                var tick = document.createElement("img");
                tick.border = 0;
                tick.className = "sparktick";
                tick.style.position = "absolute";
                tick.src = "data:image/gif,GIF89a%01%00%01%00%91%FF%00%FF%FF%FF%00%00%00%C0%C0%C0%00%00%00!%F9%04%01%00%00%02%00%2C%00%00%00%00%01%00%01%00%40%02%02T%01%00%3B";
                tick.style.left = d*2 + "px";
                tick.style.width = "2px";
                var v = Math.floor(((data[d] - min)/(max-min)) * h);
                tick.style.top = (h-v) + "px";
                tick.style.height = v + "px";
                box.appendChild(tick);
        }
};

config.macros.tabs.handler = function(place,macroName,params)
{
        var cookie = params[0];
        var numTabs = (params.length-1)/3;
        var wrapper = createTiddlyElement(null,"div",null,cookie);
        var tabset = createTiddlyElement(wrapper,"div",null,"tabset");
        tabset.setAttribute("cookie",cookie);
        var validTab = false;
        for(var t=0; t<numTabs; t++) {
                var label = params[t*3+1];
                var prompt = params[t*3+2];
                var content = params[t*3+3];
                var tab = createTiddlyButton(tabset,label,prompt,this.onClickTab,"tab tabUnselected");
                tab.setAttribute("tab",label);
                tab.setAttribute("content",content);
                tab.title = prompt;
                if(config.options[cookie] == label)
                        validTab = true;
        }
        if(!validTab)
                config.options[cookie] = params[1];
        place.appendChild(wrapper);
        this.switchTab(tabset,config.options[cookie]);
};

config.macros.tabs.onClickTab = function(e)
{
        config.macros.tabs.switchTab(this.parentNode,this.getAttribute("tab"));
        return false;
};

config.macros.tabs.switchTab = function(tabset,tab)
{
        var cookie = tabset.getAttribute("cookie");
        var theTab = null;
        var nodes = tabset.childNodes;
        for(var t=0; t<nodes.length; t++) {
                if(nodes[t].getAttribute && nodes[t].getAttribute("tab") == tab) {
                        theTab = nodes[t];
                        theTab.className = "tab tabSelected";
                } else {
                        nodes[t].className = "tab tabUnselected";
                }
        }
        if(theTab) {
                if(tabset.nextSibling && tabset.nextSibling.className == "tabContents")
                        removeNode(tabset.nextSibling);
                var tabContent = createTiddlyElement(null,"div",null,"tabContents");
                tabset.parentNode.insertBefore(tabContent,tabset.nextSibling);
                var contentTitle = theTab.getAttribute("content");
                wikify(store.getTiddlerText(contentTitle),tabContent,null,store.getTiddler(contentTitle));
                if(cookie) {
                        config.options[cookie] = tab;
                        saveOptionCookie(cookie);
                }
        }
};

// <<gradient [[tiddler name]] vert|horiz rgb rgb rgb rgb... >>
config.macros.gradient.handler = function(place,macroName,params,wikifier)
{
        var terminator = ">>";
        var panel;
        if(wikifier)
                panel = createTiddlyElement(place,"div",null,"gradient");
        else
                panel = place;
        panel.style.position = "relative";
        panel.style.overflow = "hidden";
        panel.style.zIndex = "0";
        var t;
        if(wikifier) {
                var styles = config.formatterHelpers.inlineCssHelper(wikifier);
                config.formatterHelpers.applyCssHelper(panel,styles);
        }
        var colours = [];
        for(t=1; t<params.length; t++) {
                var c = new RGB(params[t]);
                if(c)
                        colours.push(c);
        }
        drawGradient(panel,params[0] != "vert",colours);
        if(wikifier)
                wikifier.subWikify(panel,terminator);
        if(document.all) {
                panel.style.height = "100%";
                panel.style.width = "100%";
        }
};

config.macros.message.handler = function(place,macroName,params)
{
        if(params[0]) {
                var m = config;
                var p = params[0].split(".");
                for(var t=0; t<p.length; t++) {
                        if(p[t] in m)
                                m = m[p[t]];
                        else
                                break;
                }
                createTiddlyText(place,m.toString().format(params.splice(1)));
        }
};

config.macros.view.handler = function(place,macroName,params,wikifier,paramString,tiddler)
{
        if((tiddler instanceof Tiddler) && params[0]) {
                var value = store.getValue(tiddler,params[0]);
                if(value != undefined) {
                        switch(params[1]) {
                                case undefined:
                                        highlightify(value,place,highlightHack,tiddler);
                                        break;
                                case "link":
                                        createTiddlyLink(place,value,true);
                                        break;
                                case "wikified":
                                        wikify(value,place,highlightHack,tiddler);
                                        break;
                                case "date":
                                        value = Date.convertFromYYYYMMDDHHMM(value);
                                        createTiddlyText(place,value.formatString(params[2] ? params[2] : config.views.wikified.dateFormat));
                                        break;
                        }
                }
        }
};

config.macros.edit.handler = function(place,macroName,params,wikifier,paramString,tiddler)
{
        var field = params[0];
        var rows = params[1];
        if((tiddler instanceof Tiddler) && field) {
                story.setDirty(tiddler.title,true);
                if(field != "text" && !rows) {
                        var e = createTiddlyElement(null,"input");
                        if(tiddler.isReadOnly())
                                e.setAttribute("readOnly","readOnly");
                        e.setAttribute("edit",field);
                        e.setAttribute("type","text");
                        var v = store.getValue(tiddler,field);
                        if(!v) 
                                v = "";
                        e.value = v;
                        e.setAttribute("size","40");
                        e.setAttribute("autocomplete","off");
                        place.appendChild(e);
                } else {
                        var wrapper1 = createTiddlyElement(null,"fieldset",null,"fieldsetFix");
                        var wrapper2 = createTiddlyElement(wrapper1,"div");
                        var e = createTiddlyElement(wrapper2,"textarea");
                        if(tiddler.isReadOnly())
                                e.setAttribute("readOnly","readOnly");
                        var v = store.getValue(tiddler,field);
                        if(!v) 
                                v = "";
                        e.value = v;
                        var rows = rows ? rows : 10;
                        var lines = v.match(/\n/mg);
                        var maxLines = Math.max(parseInt(config.options.txtMaxEditRows),5);
                        if(lines != null && lines.length > rows)
                                rows = lines.length + 5;
                        rows = Math.min(rows,maxLines);
                        e.setAttribute("rows",rows);
                        e.setAttribute("edit",field);
                        place.appendChild(wrapper1);
                }
        }
};

config.macros.tagChooser.onClick = function(e)
{
        if(!e) var e = window.event;
        var lingo = config.views.editor.tagChooser;
        var popup = Popup.create(this);
        var tags = store.getTags();
        if(tags.length == 0)
                createTiddlyText(createTiddlyElement(popup,"li"),lingo.popupNone);
        for(var t=0; t<tags.length; t++) {
                var theTag = createTiddlyButton(createTiddlyElement(popup,"li"),tags[t][0],lingo.tagTooltip.format([tags[t][0]]),config.macros.tagChooser.onTagClick);
                theTag.setAttribute("tag",tags[t][0]);
                theTag.setAttribute("tiddler",this.getAttribute("tiddler"));
        }
        Popup.show();
        e.cancelBubble = true;
        if(e.stopPropagation) e.stopPropagation();
        return false;
};

config.macros.tagChooser.onTagClick = function(e)
{
        if(!e) var e = window.event;
        var tag = this.getAttribute("tag");
        var title = this.getAttribute("tiddler");
        if(!readOnly)
                story.setTiddlerTag(title,tag,0);
        return false;
};

config.macros.tagChooser.handler = function(place,macroName,params,wikifier,paramString,tiddler)
{
        if(tiddler instanceof Tiddler) {
                var title = tiddler.title;
                var lingo = config.views.editor.tagChooser;
                var btn = createTiddlyButton(place,lingo.text,lingo.tooltip,this.onClick);
                btn.setAttribute("tiddler",title);
        }
};

// Create a toolbar command button
config.macros.toolbar.createCommand = function(place,commandName,tiddler,theClass)
{
        if(typeof commandName != "string") {
                var c = null;
                for(var t in config.commands) {
                        if(config.commands[t] == commandName)
                                c = t;
                }
                commandName = c;
        }
        if((tiddler instanceof Tiddler) && (typeof commandName == "string")) {
                var command = config.commands[commandName];
                if(command.isEnabled ? command.isEnabled(tiddler) : this.isCommandEnabled(command,tiddler)) {
                        var text = command.getText ? command.getText(tiddler) : this.getCommandText(command,tiddler);
                        var tooltip = command.getTooltip ? command.getTooltip(tiddler) : this.getCommandTooltip(command,tiddler);
                        var cmd;
                        switch(command.type) {
                                case "popup":
                                        cmd = this.onClickPopup;
                                        break;
                                case "command":
                                default:
                                        cmd = this.onClickCommand;
                                        break;
                        }
                        var btn = createTiddlyButton(null,text,tooltip,cmd);
                        btn.setAttribute("commandName",commandName);
                        btn.setAttribute("tiddler",tiddler.title);
                        if(theClass)
                                addClass(btn,theClass);
                        place.appendChild(btn);
                }
        }
};

config.macros.toolbar.isCommandEnabled = function(command,tiddler)
{
        var title = tiddler.title;
        var ro = tiddler.isReadOnly();
        var shadow = store.isShadowTiddler(title) && !store.tiddlerExists(title);
        return (!ro || (ro && !command.hideReadOnly)) && !(shadow && command.hideShadow);
};

config.macros.toolbar.getCommandText = function(command,tiddler)
{
        return tiddler.isReadOnly() && command.readOnlyText ? command.readOnlyText : command.text;
};

config.macros.toolbar.getCommandTooltip = function(command,tiddler)
{
        return tiddler.isReadOnly() && command.readOnlyTooltip ? command.readOnlyTooltip : command.tooltip;
};

config.macros.toolbar.onClickCommand = function(e)
{
        if(!e) var e = window.event;
        e.cancelBubble = true;
        if (e.stopPropagation) e.stopPropagation();
        var command = config.commands[this.getAttribute("commandName")];
        return command.handler(e,this,this.getAttribute("tiddler"));
};

config.macros.toolbar.onClickPopup = function(e)
{
        if(!e) var e = window.event;
        e.cancelBubble = true;
        if (e.stopPropagation) e.stopPropagation();
        var popup = Popup.create(this);
        var command = config.commands[this.getAttribute("commandName")];
        var title = this.getAttribute("tiddler");
        var tiddler = store.fetchTiddler(title);
        popup.setAttribute("tiddler",title);
        command.handlePopup(popup,title);
        Popup.show();
        return false;
};

// Invoke the first command encountered from a given place that is tagged with a specified class
config.macros.toolbar.invokeCommand = function(place,theClass,event)
{
        var children = place.getElementsByTagName("a");
        for(var t=0; t<children.length; t++) {
                var c = children[t];
                if(hasClass(c,theClass) && c.getAttribute && c.getAttribute("commandName")) {
                        if(c.onclick instanceof Function)
                                c.onclick.call(c,event);
                        break;
                }
        }
};

config.macros.toolbar.onClickMore = function(e)
{
        var e = this.nextSibling;
        e.style.display = "inline";
        removeNode(this);
        return false;
};

config.macros.toolbar.handler = function(place,macroName,params,wikifier,paramString,tiddler)
{
        for(var t=0; t<params.length; t++) {
                var c = params[t];
                switch(c) {
                        case '>':
                                var btn = createTiddlyButton(place,this.moreLabel,this.morePrompt,config.macros.toolbar.onClickMore);
                                addClass(btn,"moreCommand");
                                var e = createTiddlyElement(place,"span",null,"moreCommand");
                                e.style.display = "none";
                                place = e;
                                break;
                        default:
                                var theClass = "";
                                switch(c.substr(0,1)) {
                                        case "+":
                                                theClass = "defaultCommand";
                                                c = c.substr(1);
                                                break;
                                        case "-":
                                                theClass = "cancelCommand";
                                                c = c.substr(1);
                                                break;
                                }
                                if(c in config.commands)
                                        this.createCommand(place,c,tiddler,theClass);
                                break;
                }
        }
};

config.macros.refreshDisplay.handler = function(place)
{
        createTiddlyButton(place,this.label,this.prompt,this.onClick);
};

config.macros.refreshDisplay.onClick = function(e)
{
        refreshAll();
        return false;
};

config.macros.annotations.handler = function(place,macroName,params,wikifier,paramString,tiddler)
{
        var title = tiddler ? tiddler.title : null;
        var a = title ? config.annotations[title] : null;
        if(!tiddler || !title || !a)
                return;
        var text = a.format([title]);
        wikify(text,createTiddlyElement(place,"div",null,"annotation"),null,tiddler);
};

//--
//-- Menu and toolbar commands
//--

config.commands.closeTiddler.handler = function(event,src,title)
{
        story.closeTiddler(title,true);
        return false;
};

config.commands.closeOthers.handler = function(event,src,title)
{
        story.closeAllTiddlers(title);
        return false;
};

config.commands.editTiddler.handler = function(event,src,title)
{
        clearMessage();
        var tiddlerElem = document.getElementById(story.idPrefix + title);
        var fields = tiddlerElem.getAttribute("tiddlyFields");
        story.displayTiddler(null,title,DEFAULT_EDIT_TEMPLATE,false,null,fields);
        story.focusTiddler(title,"text");
        return false;
};

config.commands.saveTiddler.handler = function(event,src,title)
{
        var newTitle = story.saveTiddler(title,event.shiftKey);
        if(newTitle)
                story.displayTiddler(null,newTitle);
        return false;
};

config.commands.cancelTiddler.handler = function(event,src,title)
{
        if(story.hasChanges(title) && !readOnly) {
                if(!confirm(this.warning.format([title])))
                        return false;
        }
        story.setDirty(title,false);
        story.displayTiddler(null,title);
        return false;
};

config.commands.deleteTiddler.handler = function(event,src,title)
{
        var deleteIt = true;
        if (config.options.chkConfirmDelete)
                deleteIt = confirm(this.warning.format([title]));
        if (deleteIt) {
                store.removeTiddler(title);
                story.closeTiddler(title,true);
                autoSaveChanges();
        }
        return false;
};

config.commands.permalink.handler = function(event,src,title)
{
        var t = encodeURIComponent(String.encodeTiddlyLink(title));
        if(window.location.hash != t)
                window.location.hash = t;
        return false;
};

config.commands.references.handlePopup = function(popup,title)
{
        var references = store.getReferringTiddlers(title);
        var c = false;
        for(var r=0; r<references.length; r++) {
                if(references[r].title != title && !references[r].isTagged("excludeLists")) {
                        createTiddlyLink(createTiddlyElement(popup,"li"),references[r].title,true);
                        c = true;
                }
        }
        if(!c)
                createTiddlyText(createTiddlyElement(popup,"li",null,"disabled"),this.popupNone);
};

config.commands.jump.handlePopup = function(popup,title)
{
        story.forEachTiddler(function(title,element) {
                createTiddlyLink(createTiddlyElement(popup,"li"),title,true,null,false,null,true);
                });
};

config.commands.syncing.handlePopup = function(popup,title)
{
        var tiddler = store.fetchTiddler(title);
        if(!tiddler)
                return;
        var serverType = tiddler.getServerType();
        var serverHost = tiddler.fields['server.host'];
        var serverWorkspace = tiddler.fields['server.workspace'];
        if(!serverWorkspace)
                serverWorkspace = "";
        if(serverType) {
                var e = createTiddlyElement(popup,"li",null,"popupMessage");
                e.innerHTML = config.commands.syncing.currentlySyncing.format([serverType,serverHost,serverWorkspace]);
        } else {
                createTiddlyElement(popup,"li",null,"popupMessage",config.commands.syncing.notCurrentlySyncing);
        }
        if(serverType) {
                createTiddlyElement(createTiddlyElement(popup,"li",null,"listBreak"),"div");
                var btn = createTiddlyButton(createTiddlyElement(popup,"li"),this.captionUnSync,null,config.commands.syncing.onChooseServer);
                btn.setAttribute("tiddler",title);
                btn.setAttribute("server.type","");
        }
        createTiddlyElement(createTiddlyElement(popup,"li",null,"listBreak"),"div");
        createTiddlyElement(popup,"li",null,"popupMessage",config.commands.syncing.chooseServer);
        var feeds = store.getTaggedTiddlers("systemServer","title");
        for(var t=0; t<feeds.length; t++) {
                var f = feeds[t];
                var feedServerType = store.getTiddlerSlice(f.title,"Type");
                if(!feedServerType)
                        feedServerType = "file";
                var feedServerHost = store.getTiddlerSlice(f.title,"URL");
                if(!feedServerHost)
                        feedServerHost = "";
                var feedServerWorkspace = store.getTiddlerSlice(f.title,"Workspace");
                if(!feedServerWorkspace)
                        feedServerWorkspace = "";
                var caption = f.title;
                if(serverType == feedServerType && serverHost == feedServerHost && serverWorkspace == feedServerWorkspace) {
                        caption = config.commands.syncing.currServerMarker + caption;
                } else {
                        caption = config.commands.syncing.notCurrServerMarker + caption;
                }
                btn = createTiddlyButton(createTiddlyElement(popup,"li"),caption,null,config.commands.syncing.onChooseServer);
                btn.setAttribute("tiddler",title);
                btn.setAttribute("server.type",feedServerType);
                btn.setAttribute("server.host",feedServerHost);
                btn.setAttribute("server.workspace",feedServerWorkspace);
        }
};

config.commands.syncing.onChooseServer = function(e)
{
        var tiddler = this.getAttribute("tiddler");
        var serverType = this.getAttribute("server.type");
        if(serverType) {
                store.addTiddlerFields(tiddler,{
                        'server.type': serverType,
                        'server.host': this.getAttribute("server.host"),
                        'server.workspace': this.getAttribute("server.workspace")
                        });
        } else {
                store.setValue(tiddler,'server',null);
        }
        return false;
};

config.commands.fields.handlePopup = function(popup,title)
{
        var tiddler = store.fetchTiddler(title);
        if(!tiddler)
                return;
        var fields = {};
        store.forEachField(tiddler,function(tiddler,fieldName,value) {fields[fieldName] = value;},true);
        var items = [];
        for(var t in fields) {
                items.push({field: t,value: fields[t]});
        }
        items.sort(function(a,b) {return a.field < b.field ? -1 : (a.field == b.field ? 0 : +1);});
        if(items.length > 0)
                ListView.create(popup,items,this.listViewTemplate);
        else
                createTiddlyElement(popup,"div",null,null,this.emptyText);
};

//--
//-- Tiddler() object
//--

function Tiddler(title)
{
        this.title = title;
        this.text = null;
        this.modifier = null;
        this.modified = new Date();
        this.created = new Date();
        this.links = [];
        this.linksUpdated = false;
        this.tags = [];
        this.fields = {};
        return this;
}

Tiddler.prototype.getLinks = function()
{
        if(this.linksUpdated==false)
                this.changed();
        return this.links;
};

// Returns the fields that are inherited in string field:"value" field2:"value2" format
Tiddler.prototype.getInheritedFields = function()
{
        var f = {};
        for(i in this.fields) {
                if(i=="server.host" || i=="server.workspace" || i=="wikiformat"|| i=="server.type") {
                        f[i] = this.fields[i];
                }
        }
        return String.encodeHashMap(f);
};

// Increment the changeCount of a tiddler
Tiddler.prototype.incChangeCount = function()
{
        var c = this.fields['changecount'];
        c = c ? parseInt(c) : 0;
        this.fields['changecount'] = String(c+1);
};

// Clear the changeCount of a tiddler
Tiddler.prototype.clearChangeCount = function()
{
        if(this.fields['changecount']) {
                delete this.fields['changecount'];
        }
};

// Returns true if the tiddler has been updated since the tiddler was created or downloaded
Tiddler.prototype.isTouched = function()
{
        var changeCount = this.fields['changecount'];
        if(changeCount === undefined)
                changeCount = 0;
        return changeCount > 0;
};

// Format the text for storage in an RSS item
Tiddler.prototype.saveToRss = function(url)
{
        var s = [];
        s.push("<item>");
        s.push("<title" + ">" + this.title.htmlEncode() + "</title" + ">");
        s.push("<description>" + wikifyStatic(this.text,null,this).htmlEncode() + "</description>");
        for(var t=0; t<this.tags.length; t++)
                s.push("<category>" + this.tags[t] + "</category>");
        s.push("<link>" + url + "#" + encodeURIComponent(String.encodeTiddlyLink(this.title)) + "</link>");
        s.push("<pubDate>" + this.modified.toGMTString() + "</pubDate>");
        s.push("</item>");
        return s.join("\n");
};

// Change the text and other attributes of a tiddler
Tiddler.prototype.set = function(title,text,modifier,modified,tags,created,fields)
{
        this.assign(title,text,modifier,modified,tags,created,fields);
        this.changed();
        return this;
};

// Change the text and other attributes of a tiddler without triggered a tiddler.changed() call
Tiddler.prototype.assign = function(title,text,modifier,modified,tags,created,fields)
{
        if(title != undefined)
                this.title = title;
        if(text != undefined)
                this.text = text;
        if(modifier != undefined)
                this.modifier = modifier;
        if(modified != undefined)
                this.modified = modified;
        if(created != undefined)
                this.created = created;
        if(fields != undefined)
                this.fields = fields;
        if(tags != undefined)
                this.tags = (typeof tags == "string") ? tags.readBracketedList() : tags;
        else if(this.tags == undefined)
                this.tags = [];
        return this;
};

// Get the tags for a tiddler as a string (space delimited, using [[brackets]] for tags containing spaces)
Tiddler.prototype.getTags = function()
{
        return String.encodeTiddlyLinkList(this.tags);
};

// Test if a tiddler carries a tag
Tiddler.prototype.isTagged = function(tag)
{
        return this.tags.indexOf(tag) != -1;
};

// Static method to convert "\n" to newlines, "\s" to "\"
Tiddler.unescapeLineBreaks = function(text)
{
        return text ? text.unescapeLineBreaks() : "";
};

// Convert newlines to "\n", "\" to "\s"
Tiddler.prototype.escapeLineBreaks = function()
{
        return this.text.escapeLineBreaks();
};

// Updates the secondary information (like links[] array) after a change to a tiddler
Tiddler.prototype.changed = function()
{
        this.links = [];
        var t = this.autoLinkWikiWords() ? 0 : 1;
        var tiddlerLinkRegExp = t==0 ? config.textPrimitives.tiddlerAnyLinkRegExp : config.textPrimitives.tiddlerForcedLinkRegExp;
        tiddlerLinkRegExp.lastIndex = 0;
        var formatMatch = tiddlerLinkRegExp.exec(this.text);
        while(formatMatch) {
                var lastIndex = tiddlerLinkRegExp.lastIndex;
                if(t==0 && formatMatch[1] && formatMatch[1] != this.title) {
                        // wikiWordLink
                        if(formatMatch.index > 0) {
                                var preRegExp = new RegExp(config.textPrimitives.unWikiLink+"|"+config.textPrimitives.anyLetter,"mg");
                                preRegExp.lastIndex = formatMatch.index-1;
                                var preMatch = preRegExp.exec(this.text);
                                if(preMatch.index != formatMatch.index-1)
                                        this.links.pushUnique(formatMatch[1]);
                        } else {
                                this.links.pushUnique(formatMatch[1]);
                        }
                }
                else if(formatMatch[2-t] && !config.formatterHelpers.isExternalLink(formatMatch[3-t])) // titledBrackettedLink
                        this.links.pushUnique(formatMatch[3-t]);
                else if(formatMatch[4-t] && formatMatch[4-t] != this.title) // brackettedLink
                        this.links.pushUnique(formatMatch[4-t]);
                tiddlerLinkRegExp.lastIndex = lastIndex;
                formatMatch = tiddlerLinkRegExp.exec(this.text);
        }
        this.linksUpdated = true;
};

Tiddler.prototype.getSubtitle = function()
{
        var theModifier = this.modifier;
        if(!theModifier)
                theModifier = config.messages.subtitleUnknown;
        var theModified = this.modified;
        if(theModified)
                theModified = theModified.toLocaleString();
        else
                theModified = config.messages.subtitleUnknown;
        return config.messages.tiddlerLinkTooltip.format([this.title,theModifier,theModified]);
};

Tiddler.prototype.isReadOnly = function()
{
        return readOnly;
};

Tiddler.prototype.autoLinkWikiWords = function()
{
        return !(this.isTagged("systemConfig") || this.isTagged("excludeMissing"));
};

Tiddler.prototype.generateFingerprint = function()
{
        return "0x" + Crypto.hexSha1Str(this.text);
};

Tiddler.prototype.getServerType = function()
{
        var serverType = null;
        if(this.fields && this.fields['server.type'])
                serverType = this.fields['server.type'];
        if(!serverType)
                serverType = this.fields['wikiformat'];
        if(serverType && !config.adaptors[serverType])
                serverType = null;
        return serverType;
};

Tiddler.prototype.getAdaptor = function()
{
        var serverType = this.getServerType();
        if(serverType)
                return new config.adaptors[serverType];
        else
                return null;
};

//--
//-- TiddlyWiki() object contains Tiddler()s
//--

function TiddlyWiki()
{
        var tiddlers = {}; // Hashmap by name of tiddlers
        this.tiddlersUpdated = false;
        this.namedNotifications = []; // Array of {name:,notify:} of notification functions
        this.notificationLevel = 0;
        this.slices = {}; // map tiddlerName->(map sliceName->sliceValue). Lazy.
        this.clear = function() {
                tiddlers = {};
                this.setDirty(false);
        };
        this.fetchTiddler = function(title) {
                return tiddlers[title];
        };
        this.deleteTiddler = function(title) {
                delete this.slices[title];
                delete tiddlers[title];
        };
        this.addTiddler = function(tiddler) {
                delete this.slices[tiddler.title];
                tiddlers[tiddler.title] = tiddler;
        };
        this.forEachTiddler = function(callback) {
                for(var t in tiddlers) {
                        var tiddler = tiddlers[t];
                        if(tiddler instanceof Tiddler)
                                callback.call(this,t,tiddler);
                }
        };
}

TiddlyWiki.prototype.setDirty = function(dirty)
{
        this.dirty = dirty;
};

TiddlyWiki.prototype.isDirty = function()
{
        return this.dirty;
};

TiddlyWiki.prototype.suspendNotifications = function()
{
        this.notificationLevel--;
};

TiddlyWiki.prototype.resumeNotifications = function()
{
        this.notificationLevel++;
};

// Invoke the notification handlers for a particular tiddler
TiddlyWiki.prototype.notify = function(title,doBlanket)
{
        if(!this.notificationLevel) {
                for(var t=0; t<this.namedNotifications.length; t++) {
                        var n = this.namedNotifications[t];
                        if((n.name == null && doBlanket) || (n.name == title))
                                n.notify(title);
                }
        }
};

// Invoke the notification handlers for all tiddlers
TiddlyWiki.prototype.notifyAll = function()
{
        if(!this.notificationLevel) {
                for(var t=0; t<this.namedNotifications.length; t++) {
                        var n = this.namedNotifications[t];
                        if(n.name)
                                n.notify(n.name);
                }
        }
};

// Add a notification handler to a tiddler
TiddlyWiki.prototype.addNotification = function(title,fn)
{
        for(var i=0; i<this.namedNotifications.length; i++) {
                if((this.namedNotifications[i].name == title) && (this.namedNotifications[i].notify == fn))
                        return this;
        }
        this.namedNotifications.push({name: title, notify: fn});
        return this;
};

TiddlyWiki.prototype.removeTiddler = function(title)
{
        var tiddler = this.fetchTiddler(title);
        if(tiddler) {
                this.deleteTiddler(title);
                this.notify(title,true);
                this.setDirty(true);
        }
};

TiddlyWiki.prototype.tiddlerExists = function(title)
{
        var t = this.fetchTiddler(title);
        return t != undefined;
};

TiddlyWiki.prototype.isShadowTiddler = function(title)
{
        return typeof config.shadowTiddlers[title] == "string";
};

TiddlyWiki.prototype.getTiddler = function(title)
{
        var t = this.fetchTiddler(title);
        if(t != undefined)
                return t;
        else
                return null;
};

TiddlyWiki.prototype.getTiddlerText = function(title,defaultText)
{
        var tiddler = this.fetchTiddler(title);
        if(tiddler)
                return tiddler.text;
        if(!title)
                return defaultText;
        var pos = title.indexOf(config.textPrimitives.sliceSeparator);
        if(pos != -1) {
                var slice = this.getTiddlerSlice(title.substr(0,pos),title.substr(pos + config.textPrimitives.sliceSeparator.length));
                if(slice)
                        return slice;
        }
        if(this.isShadowTiddler(title))
                return config.shadowTiddlers[title];
        if(defaultText != undefined)
                return defaultText;
        return null;
};

TiddlyWiki.prototype.slicesRE = /(?:[\'\/]*~?([\.\w]+)[\'\/]*\:[\'\/]*\s*(.*?)\s*$)|(?:\|[\'\/]*~?([\.\w]+)\:?[\'\/]*\|\s*(.*?)\s*\|)/gm;

// @internal
TiddlyWiki.prototype.calcAllSlices = function(title)
{
        var slices = {};
        var text = this.getTiddlerText(title,"");
        this.slicesRE.lastIndex = 0;
        do {
                var m = this.slicesRE.exec(text);
                if(m) {
                        if(m[1])
                                slices[m[1]] = m[2];
                        else
                                slices[m[3]] = m[4];
                }
        } while(m);
        return slices;
};

// Returns the slice of text of the given name
TiddlyWiki.prototype.getTiddlerSlice = function(title,sliceName)
{
        var slices = this.slices[title];
        if(!slices) {
                slices = this.calcAllSlices(title);
                this.slices[title] = slices;
        }
        return slices[sliceName];
};

// Build an hashmap of the specified named slices of a tiddler
TiddlyWiki.prototype.getTiddlerSlices = function(title,sliceNames)
{
        var r = {};
        for(var t=0; t<sliceNames.length; t++) {
                var slice = this.getTiddlerSlice(title,sliceNames[t]);
                if(slice)
                        r[sliceNames[t]] = slice;
        }
        return r;
};

TiddlyWiki.prototype.getRecursiveTiddlerText = function(title,defaultText,depth)
{
        var bracketRegExp = new RegExp("(?:\\[\\[([^\\]]+)\\]\\])","mg");
        var text = this.getTiddlerText(title,null);
        if(text == null)
                return defaultText;
        var textOut = [];
        var lastPos = 0;
        do {
                var match = bracketRegExp.exec(text);
                if(match) {
                        textOut.push(text.substr(lastPos,match.index-lastPos));
                        if(match[1]) {
                                if(depth <= 0)
                                        textOut.push(match[1]);
                                else
                                        textOut.push(this.getRecursiveTiddlerText(match[1],"[[" + match[1] + "]]",depth-1));
                        }
                        lastPos = match.index + match[0].length;
                } else {
                        textOut.push(text.substr(lastPos));
                }
        } while(match);
        return textOut.join("");
};

TiddlyWiki.prototype.setTiddlerTag = function(title,status,tag)
{
        var tiddler = this.fetchTiddler(title);
        if(tiddler) {
                var t = tiddler.tags.indexOf(tag);
                if(t != -1)
                        tiddler.tags.splice(t,1);
                if(status)
                        tiddler.tags.push(tag);
                tiddler.changed();
                this.incChangeCount(title);
                this.notify(title,true);
                this.setDirty(true);
        }
};

TiddlyWiki.prototype.addTiddlerFields = function(title,fields)
{
        var tiddler = this.fetchTiddler(title);
        if(!tiddler)
                return;
        merge(tiddler.fields,fields);
        tiddler.changed();
        this.incChangeCount(title);
        this.notify(title,true);
        this.setDirty(true);
};

TiddlyWiki.prototype.saveTiddler = function(title,newTitle,newBody,modifier,modified,tags,fields,clearChangeCount,created)
{
        var tiddler = this.fetchTiddler(title);
        if(tiddler) {
                created = created ? created : tiddler.created; // Preserve created date
                this.deleteTiddler(title);
        } else {
                created = created ? created : modified;
                tiddler = new Tiddler();
        }
        tiddler.set(newTitle,newBody,modifier,modified,tags,created,fields);
        this.addTiddler(tiddler);
        if(clearChangeCount)
                tiddler.clearChangeCount();
        else
                tiddler.incChangeCount();
        if(title != newTitle)
                this.notify(title,true);
        this.notify(newTitle,true);
        this.setDirty(true);
        return tiddler;
};

// Reset the sync status of a freshly synced tiddler
TiddlyWiki.prototype.resetTiddler = function(title)
{
        var tiddler = this.fetchTiddler(title);
        if(tiddler) {
                tiddler.clearChangeCount();
                this.notify(title,true);
                this.setDirty(true);
        }
};

TiddlyWiki.prototype.incChangeCount = function(title)
{
        var tiddler = this.fetchTiddler(title);
        if(tiddler)
                tiddler.incChangeCount();
};

TiddlyWiki.prototype.createTiddler = function(title)
{
        var tiddler = this.fetchTiddler(title);
        if(!tiddler) {
                tiddler = new Tiddler();
                tiddler.title = title;
                this.addTiddler(tiddler);
                this.setDirty(true);
        }
        return tiddler;
};

// Load contents of a TiddlyWiki from an HTML DIV
TiddlyWiki.prototype.loadFromDiv = function(src,idPrefix,noUpdate)
{
        this.idPrefix = idPrefix;
        var storeElem = (typeof src == "string") ? document.getElementById(src) : src;
        if(!storeElem)
                return;
        var tiddlers = this.getLoader().loadTiddlers(this,storeElem.childNodes);
        this.setDirty(false);
        if(!noUpdate) {
                for(var i = 0;i<tiddlers.length; i++)
                        tiddlers[i].changed();
        }
};

// Load contents of a TiddlyWiki from a string
// Returns null if there's an error
TiddlyWiki.prototype.importTiddlyWiki = function(text)
{
        var posDiv = locateStoreArea(text);
        if(!posDiv)
                return null;
        var content = "<" + "html><" + "body>" + text.substring(posDiv[0],posDiv[1] + endSaveArea.length) + "<" + "/body><" + "/html>";
        // Create the iframe
        var iframe = document.createElement("iframe");
        iframe.style.display = "none";
        document.body.appendChild(iframe);
        var doc = iframe.document;
        if(iframe.contentDocument)
                doc = iframe.contentDocument; // For NS6
        else if(iframe.contentWindow)
                doc = iframe.contentWindow.document; // For IE5.5 and IE6
        // Put the content in the iframe
        doc.open();
        doc.writeln(content);
        doc.close();
        // Load the content into a TiddlyWiki() object
        var storeArea = doc.getElementById("storeArea");
        this.loadFromDiv(storeArea,"store");
        // Get rid of the iframe
        iframe.parentNode.removeChild(iframe);
        return this;
};

TiddlyWiki.prototype.updateTiddlers = function()
{
        this.tiddlersUpdated = true;
        this.forEachTiddler(function(title,tiddler) {
                tiddler.changed();
        });
};

// Return all tiddlers formatted as an HTML string
TiddlyWiki.prototype.allTiddlersAsHtml = function()
{
        return store.getSaver().externalize(store);
};

// Return an array of tiddlers matching a search regular expression
TiddlyWiki.prototype.search = function(searchRegExp,sortField,excludeTag)
{
        var candidates = this.reverseLookup("tags",excludeTag,false);
        var results = [];
        for(var t=0; t<candidates.length; t++) {
                if((candidates[t].title.search(searchRegExp) != -1) || (candidates[t].text.search(searchRegExp) != -1))
                        results.push(candidates[t]);
        }
        if(!sortField)
                sortField = "title";
        results.sort(function(a,b) {return a[sortField] < b[sortField] ? -1 : (a[sortField] == b[sortField] ? 0 : +1);});
        return results;
};

// Return an array of all the tags in use. Each member of the array is another array where [0] is the name of the tag and [1] is the number of occurances
TiddlyWiki.prototype.getTags = function(excludeTag)
{
        var results = [];
        this.forEachTiddler(function(title,tiddler) {
                for(var g=0; g<tiddler.tags.length; g++) {
                        var tag = tiddler.tags[g];
                        if(excludeTag) {
                                var t = store.fetchTiddler(tag);
                                if(t && t.isTagged(excludeTag))
                                        return false;
                        }
                        var f = false;
                        for(var c=0; c<results.length; c++) {
                                if(results[c][0] == tag) {
                                        f = true;
                                        results[c][1]++;
                                }
                        }
                        if(!f)
                                results.push([tag,1]);
                }
        });
        results.sort(function(a,b) {return a[0].toLowerCase() < b[0].toLowerCase() ? -1 : (a[0].toLowerCase() == b[0].toLowerCase() ? 0 : +1);});
        return results;
};

// Return an array of the tiddlers that are tagged with a given tag
TiddlyWiki.prototype.getTaggedTiddlers = function(tag,sortField)
{
        return this.reverseLookup("tags",tag,true,sortField);
};

// Return an array of the tiddlers that link to a given tiddler
TiddlyWiki.prototype.getReferringTiddlers = function(title,unusedParameter,sortField)
{
        if(!this.tiddlersUpdated)
                this.updateTiddlers();
        return this.reverseLookup("links",title,true,sortField);
};

// Return an array of the tiddlers that do or do not have a specified entry in the specified storage array (ie, "links" or "tags")
// lookupMatch == true to match tiddlers, false to exclude tiddlers
TiddlyWiki.prototype.reverseLookup = function(lookupField,lookupValue,lookupMatch,sortField)
{
        var results = [];
        this.forEachTiddler(function(title,tiddler) {
                var f = !lookupMatch;
                for(var lookup=0; lookup<tiddler[lookupField].length; lookup++) {
                        if(tiddler[lookupField][lookup] == lookupValue)
                                f = lookupMatch;
                }
                if(f)
                        results.push(tiddler);
        });
        if(!sortField)
                sortField = "title";
        results.sort(function(a,b) {return a[sortField] < b[sortField] ? -1 : (a[sortField] == b[sortField] ? 0 : +1);});
        return results;
};

// Return the tiddlers as a sorted array
TiddlyWiki.prototype.getTiddlers = function(field,excludeTag)
{
        var results = [];
        this.forEachTiddler(function(title,tiddler) {
                if(excludeTag == undefined || !tiddler.isTagged(excludeTag))
                        results.push(tiddler);
        });
        if(field)
                results.sort(function(a,b) {return a[field] < b[field] ? -1 : (a[field] == b[field] ? 0 : +1);});
        return results;
};

// Return array of names of tiddlers that are referred to but not defined
TiddlyWiki.prototype.getMissingLinks = function(sortField)
{
        if(!this.tiddlersUpdated)
                this.updateTiddlers();
        var results = [];
        this.forEachTiddler(function (title,tiddler) {
                if(tiddler.isTagged("excludeMissing") || tiddler.isTagged("systemConfig"))
                        return;
                for(var n=0; n<tiddler.links.length;n++) {
                        var link = tiddler.links[n];
                        if(this.fetchTiddler(link) == null && !this.isShadowTiddler(link))
                                results.pushUnique(link);
                }
        });
        results.sort();
        return results;
};

// Return an array of names of tiddlers that are defined but not referred to
TiddlyWiki.prototype.getOrphans = function()
{
        var results = [];
        this.forEachTiddler(function (title,tiddler) {
                if(this.getReferringTiddlers(title).length == 0 && !tiddler.isTagged("excludeLists"))
                        results.push(title);
        });
        results.sort();
        return results;
};

// Return an array of names of all the shadow tiddlers
TiddlyWiki.prototype.getShadowed = function()
{
        var results = [];
        for(var t in config.shadowTiddlers) {
                if(typeof config.shadowTiddlers[t] == "string")
                        results.push(t);
        }
        results.sort();
        return results;
};

// Return an array of tiddlers that have been touched since they were downloaded or created
TiddlyWiki.prototype.getTouched = function()
{
        var results = [];
        this.forEachTiddler(function(title,tiddler) {
                if(tiddler.isTouched())
                        results.push(tiddler);
                });
        results.sort();
        return results;
};

// Resolves a Tiddler reference or tiddler title into a Tiddler object, or null if it doesn't exist
TiddlyWiki.prototype.resolveTiddler = function(tiddler)
{
        var t = (typeof tiddler == 'string') ? this.getTiddler(tiddler) : tiddler;
        return t instanceof Tiddler ? t : null;
};

TiddlyWiki.prototype.getLoader = function()
{
        if(!this.loader)
                this.loader = new TW21Loader();
        return this.loader;
};

TiddlyWiki.prototype.getSaver = function()
{
        if(!this.saver)
                this.saver = new TW21Saver();
        return this.saver;
};

// Returns true if path is a valid field name (path),
// i.e. a sequence of identifiers, separated by '.'
TiddlyWiki.isValidFieldName = function(name)
{
        var match = /[a-zA-Z_]\w*(\.[a-zA-Z_]\w*)*/.exec(name);
        return match && (match[0] == name);
};

// Throws an exception when name is not a valid field name.
TiddlyWiki.checkFieldName = function(name)
{
        if(!TiddlyWiki.isValidFieldName(name))
                throw config.messages.invalidFieldName.format([name]);
};

function StringFieldAccess(n,readOnly)
{
        this.set = readOnly ?
                        function(t,v) {if(v != t[n]) throw config.messages.fieldCannotBeChanged.format([n]);} :
                        function(t,v) {if(v != t[n]) {t[n] = v; return true;}};
        this.get = function(t) {return t[n];};
}

function DateFieldAccess(n)
{
        this.set = function(t,v) {
                var d = v instanceof Date ? v : Date.convertFromYYYYMMDDHHMM(v);
                if(d != t[n]) {
                        t[n] = d; return true;
                }
        };
        this.get = function(t) {return t[n].convertToYYYYMMDDHHMM();};
}

function LinksFieldAccess(n)
{
        this.set = function(t,v) {
                var s = (typeof v == "string") ? v.readBracketedList() : v;
                if(s.toString() != t[n].toString()) {
                        t[n] = s; return true;
                }
        };
        this.get = function(t) {return String.encodeTiddlyLinkList(t[n]);};
}

TiddlyWiki.standardFieldAccess = {
        // The set functions return true when setting the data has changed the value.
        "title":    new StringFieldAccess("title",true),
        // Handle the "tiddler" field name as the title
        "tiddler":  new StringFieldAccess("title",true),
        "text":     new StringFieldAccess("text"),
        "modifier": new StringFieldAccess("modifier"),
        "modified": new DateFieldAccess("modified"),
        "created":  new DateFieldAccess("created"),
        "tags":     new LinksFieldAccess("tags")
};

TiddlyWiki.isStandardField = function(name)
{
        return TiddlyWiki.standardFieldAccess[name] != undefined;
};

// Sets the value of the given field of the tiddler to the value.
// Setting an ExtendedField's value to null or undefined removes the field.
// Setting a namespace to undefined removes all fields of that namespace.
// The fieldName is case-insensitive.
// All values will be converted to a string value.
TiddlyWiki.prototype.setValue = function(tiddler,fieldName,value)
{
        TiddlyWiki.checkFieldName(fieldName);
        var t = this.resolveTiddler(tiddler);
        if(!t)
                return;
        fieldName = fieldName.toLowerCase();
        var isRemove = (value === undefined) || (value === null);
        var accessor = TiddlyWiki.standardFieldAccess[fieldName];
        if(accessor) {
                if(isRemove)
                        // don't remove StandardFields
                        return;
                var h = TiddlyWiki.standardFieldAccess[fieldName];
                if(!h.set(t,value))
                        return;
        } else {
                var oldValue = t.fields[fieldName];
                if(isRemove) {
                        if(oldValue !== undefined) {
                                // deletes a single field
                                delete t.fields[fieldName];
                        } else {
                                // no concrete value is defined for the fieldName
                                // so we guess this is a namespace path.
                                // delete all fields in a namespace
                                var re = new RegExp('^'+fieldName+'\\.');
                                var dirty = false;
                                for(var n in t.fields) {
                                        if(n.match(re)) {
                                                delete t.fields[n];
                                                dirty = true;
                                        }
                                }
                                if(!dirty)
                                        return;
                        }
                } else {
                        // the "normal" set case. value is defined (not null/undefined)
                        // For convenience provide a nicer conversion Date->String
                        value = value instanceof Date ? value.convertToYYYYMMDDHHMMSSMMM() : String(value);
                        if(oldValue == value)
                                return;
                        t.fields[fieldName] = value;
                }
        }
        // When we are here the tiddler/store really was changed.
        this.notify(t.title,true);
        if(!fieldName.match(/^temp\./))
                this.setDirty(true);
};

// Returns the value of the given field of the tiddler.
// The fieldName is case-insensitive.
// Will only return String values (or undefined).
TiddlyWiki.prototype.getValue = function(tiddler,fieldName)
{
        var t = this.resolveTiddler(tiddler);
        if(!t)
                return undefined;
        fieldName = fieldName.toLowerCase();
        var accessor = TiddlyWiki.standardFieldAccess[fieldName];
        if(accessor) {
                return accessor.get(t);
        }
        return t.fields[fieldName];
};

// Calls the callback function for every field in the tiddler.
// When callback function returns a non-false value the iteration stops
// and that value is returned.
// The order of the fields is not defined.
// @param callback a function(tiddler,fieldName,value).
TiddlyWiki.prototype.forEachField = function(tiddler,callback,onlyExtendedFields)
{
        var t = this.resolveTiddler(tiddler);
        if(!t)
                return undefined;
        for(var n in t.fields) {
                var result = callback(t,n,t.fields[n]);
                if(result)
                        return result;
                }
        if(onlyExtendedFields)
                return undefined;
        for(var n in TiddlyWiki.standardFieldAccess) {
                if(n == "tiddler")
                        // even though the "title" field can also be referenced through the name "tiddler"
                        // we only visit this field once.
                        continue;
                var result = callback(t,n,TiddlyWiki.standardFieldAccess[n].get(t));
                if(result)
                        return result;
        }
        return undefined;
};

//--
//-- Story functions
//--

function Story(container,idPrefix)
{
        this.container = container;
        this.idPrefix = idPrefix;
        this.highlightRegExp = null;
}

Story.prototype.forEachTiddler = function(fn)
{
        var place = document.getElementById(this.container);
        if(!place)
                return;
        var e = place.firstChild;
        while(e) {
                var n = e.nextSibling;
                var title = e.getAttribute("tiddler");
                fn.call(this,title,e);
                e = n;
        }
};

Story.prototype.displayTiddlers = function(srcElement,titles,template,animate,unused,customFields,toggle)
{
        for(var t = titles.length-1;t>=0;t--)
                this.displayTiddler(srcElement,titles[t],template,animate,unused,customFields);
};

Story.prototype.displayTiddler = function(srcElement,title,template,animate,unused,customFields,toggle)
{
        var place = document.getElementById(this.container);
        var tiddlerElem = document.getElementById(this.idPrefix + title);
        if(tiddlerElem) {
                if(toggle)
                        this.closeTiddler(title,true);
                else
                        this.refreshTiddler(title,template,false,customFields);
        } else {
                var before = this.positionTiddler(srcElement);
                tiddlerElem = this.createTiddler(place,before,title,template,customFields);
        }
        if(srcElement && typeof srcElement !== "string") {
                if(config.options.chkAnimate && (animate == undefined || animate == true) && anim && typeof Zoomer == "function" && typeof Scroller == "function")
                        anim.startAnimating(new Zoomer(title,srcElement,tiddlerElem),new Scroller(tiddlerElem));
                else
                        window.scrollTo(0,ensureVisible(tiddlerElem));
        }
};

Story.prototype.positionTiddler = function(srcElement)
{
        var place = document.getElementById(this.container);
        var before = null;
        if(typeof srcElement == "string") {
                switch(srcElement) {
                        case "top":
                                before = place.firstChild;
                                break;
                        case "bottom":
                                before = null;
                                break;
                }
        } else {
                var after = this.findContainingTiddler(srcElement);
                if(after == null) {
                        before = place.firstChild;
                } else if(after.nextSibling) {
                        before = after.nextSibling;
                        if(before.nodeType != 1)
                                before = null;
                }
        }
        return before;
};

Story.prototype.createTiddler = function(place,before,title,template,customFields)
{
        var tiddlerElem = createTiddlyElement(null,"div",this.idPrefix + title,"tiddler");
        tiddlerElem.setAttribute("refresh","tiddler");
        if(customFields)
                tiddlerElem.setAttribute("tiddlyFields",customFields);
        place.insertBefore(tiddlerElem,before);
        var defaultText = null;
        if(!store.tiddlerExists(title) && !store.isShadowTiddler(title))
                defaultText = this.loadMissingTiddler(title,customFields,tiddlerElem);
        this.refreshTiddler(title,template,false,customFields,defaultText);
        return tiddlerElem;
};

Story.prototype.loadMissingTiddler = function(title,fields,tiddlerElem)
{
        var tiddler = new Tiddler(title);
        tiddler.fields = typeof fields == "string" ?  fields.decodeHashMap() : (fields ? fields : {});
        var serverType = tiddler.getServerType();
        var host = tiddler.fields['server.host'];
        var workspace = tiddler.fields['server.workspace'];
        if(!serverType | !host)
                return null;
        var sm = new SyncMachine(serverType,{
                        start: function() {
                                return this.openHost(host,"openWorkspace");
                        },
                        openWorkspace: function() {
                                return this.openWorkspace(workspace,"getTiddler");
                        },
                        getTiddler: function() {
                                return this.getTiddler(title,"gotTiddler");
                        },
                        gotTiddler: function(tiddler) {
                                if(tiddler && tiddler.text) {
                                        var downloaded = new Date();
                                        if(!tiddler.created)
                                                tiddler.created = downloaded;
                                        if(!tiddler.modified)
                                                tiddler.modified = tiddler.created;
                                        store.saveTiddler(tiddler.title,tiddler.title,tiddler.text,tiddler.modifier,tiddler.modified,tiddler.tags,tiddler.fields,true,tiddler.created);
                                        autoSaveChanges();
                                }
                                delete this;
                                return true;
                        },
                        error: function(message) {
                                displayMessage("Error loading missing tiddler from %0: %1".format([host,message]));
                        }
                });
        sm.go();
        return config.messages.loadingMissingTiddler.format([title,serverType,host,workspace]);
};

Story.prototype.chooseTemplateForTiddler = function(title,template)
{
        if(!template)
                template = DEFAULT_VIEW_TEMPLATE;
        if(template == DEFAULT_VIEW_TEMPLATE || template == DEFAULT_EDIT_TEMPLATE)
                template = config.tiddlerTemplates[template];
        return template;
};

Story.prototype.getTemplateForTiddler = function(title,template,tiddler)
{
        return store.getRecursiveTiddlerText(template,null,10);
};

Story.prototype.refreshTiddler = function(title,template,force,customFields,defaultText)
{
        var tiddlerElem = document.getElementById(this.idPrefix + title);
        if(tiddlerElem) {
                if(tiddlerElem.getAttribute("dirty") == "true" && !force)
                        return tiddlerElem;
                template = this.chooseTemplateForTiddler(title,template);
                var currTemplate = tiddlerElem.getAttribute("template");
                if((template != currTemplate) || force) {
                        var tiddler = store.getTiddler(title);
                        if(!tiddler) {
                                tiddler = new Tiddler();
                                if(store.isShadowTiddler(title)) {
                                        tiddler.set(title,store.getTiddlerText(title),config.views.wikified.shadowModifier,version.date,[],version.date);
                                } else {
                                        var text = template=="EditTemplate" ?
                                                                config.views.editor.defaultText.format([title]) :
                                                                config.views.wikified.defaultText.format([title]);
                                        text = defaultText ? defaultText : text;
                                        var fields = customFields ? customFields.decodeHashMap() : null;
                                        tiddler.set(title,text,config.views.wikified.defaultModifier,version.date,[],version.date,fields);
                                }
                        }
                        tiddlerElem.setAttribute("tags",tiddler.tags.join(" "));
                        tiddlerElem.setAttribute("tiddler",title);
                        tiddlerElem.setAttribute("template",template);
                        var me = this;
                        tiddlerElem.onmouseover = this.onTiddlerMouseOver;
                        tiddlerElem.onmouseout = this.onTiddlerMouseOut;
                        tiddlerElem.ondblclick = this.onTiddlerDblClick;
                        tiddlerElem[window.event?"onkeydown":"onkeypress"] = this.onTiddlerKeyPress;
                        var html = this.getTemplateForTiddler(title,template,tiddler);
                        tiddlerElem.innerHTML = html;
                        applyHtmlMacros(tiddlerElem,tiddler);
                        if(store.getTaggedTiddlers(title).length > 0)
                                addClass(tiddlerElem,"isTag");
                        else
                                removeClass(tiddlerElem,"isTag");
                        if(!store.tiddlerExists(title)) {
                                if(store.isShadowTiddler(title))
                                        addClass(tiddlerElem,"shadow");
                                else
                                        addClass(tiddlerElem,"missing");
                        } else {
                                removeClass(tiddlerElem,"shadow");
                                removeClass(tiddlerElem,"missing");
                        }
                        if(customFields)
                                this.addCustomFields(tiddlerElem,customFields);
                        forceReflow();
                }
        }
        return tiddlerElem;
};

Story.prototype.addCustomFields = function(place,customFields)
{
        var fields = customFields.decodeHashMap();
        var w = document.createElement("div");
        w.style.display = "none";
        place.appendChild(w);
        for(var t in fields) {
                var e = document.createElement("input");
                e.setAttribute("type","text");
                e.setAttribute("value",fields[t]);
                w.appendChild(e);
                e.setAttribute("edit",t);
        }
};

Story.prototype.refreshAllTiddlers = function() 
{
        var place = document.getElementById(this.container);
        var e = place.firstChild;
        if(!e)
                return;
        this.refreshTiddler(e.getAttribute("tiddler"),e.getAttribute("template"),true);
        while((e = e.nextSibling) != null) 
                this.refreshTiddler(e.getAttribute("tiddler"),e.getAttribute("template"),true);
};

Story.prototype.onTiddlerMouseOver = function(e)
{
        if(window.addClass instanceof Function)
                addClass(this,"selected");
};

Story.prototype.onTiddlerMouseOut = function(e)
{
        if(window.removeClass instanceof Function)
                removeClass(this,"selected");
};

Story.prototype.onTiddlerDblClick = function(e)
{
        if(!e) var e = window.event;
        var theTarget = resolveTarget(e);
        if(theTarget && theTarget.nodeName.toLowerCase() != "input" && theTarget.nodeName.toLowerCase() != "textarea") {
                if(document.selection && document.selection.empty)
                        document.selection.empty();
                config.macros.toolbar.invokeCommand(this,"defaultCommand",e);
                e.cancelBubble = true;
                if(e.stopPropagation) e.stopPropagation();
                return true;
        } else {
                return false;
        }
};

Story.prototype.onTiddlerKeyPress = function(e)
{
        if(!e) var e = window.event;
        clearMessage();
        var consume = false; 
        var title = this.getAttribute("tiddler");
        var target = resolveTarget(e);
        switch(e.keyCode) {
                case 9: // Tab
                        if(config.options.chkInsertTabs && target.tagName.toLowerCase() == "textarea") {
                                replaceSelection(target,String.fromCharCode(9));
                                consume = true; 
                        }
                        if(config.isOpera) {
                                target.onblur = function() {
                                        this.focus();
                                        this.onblur = null;
                                };
                        }
                        break;
                case 13: // Ctrl-Enter
                case 10: // Ctrl-Enter on IE PC
                case 77: // Ctrl-Enter is "M" on some platforms
                        if(e.ctrlKey) {
                                blurElement(this);
                                config.macros.toolbar.invokeCommand(this,"defaultCommand",e);
                                consume = true;
                        }
                        break; 
                case 27: // Escape
                        blurElement(this);
                        config.macros.toolbar.invokeCommand(this,"cancelCommand",e);
                        consume = true;
                        break;
        }
        e.cancelBubble = consume;
        if(consume) {
                if(e.stopPropagation) e.stopPropagation(); // Stop Propagation
                e.returnValue = true; // Cancel The Event in IE
                if(e.preventDefault ) e.preventDefault(); // Cancel The Event in Moz
        }
        return !consume;
};

Story.prototype.getTiddlerField = function(title,field)
{
        var tiddlerElem = document.getElementById(this.idPrefix + title);
        var e = null;
        if(tiddlerElem != null) {
                var children = tiddlerElem.getElementsByTagName("*");
                for(var t=0; t<children.length; t++) {
                        var c = children[t];
                        if(c.tagName.toLowerCase() == "input" || c.tagName.toLowerCase() == "textarea") {
                                if(!e)
                                        e = c;
                                if(c.getAttribute("edit") == field)
                                        e = c;
                        }
                }
        }
        return e;
};

Story.prototype.focusTiddler = function(title,field)
{
        var e = this.getTiddlerField(title,field);
        if(e) {
                e.focus();
                e.select();
        }
};

Story.prototype.blurTiddler = function(title)
{
        var tiddlerElem = document.getElementById(this.idPrefix + title);
        if(tiddlerElem != null && tiddlerElem.focus && tiddlerElem.blur) {
                tiddlerElem.focus();
                tiddlerElem.blur();
        }
};

Story.prototype.setTiddlerField = function(title,tag,mode,field)
{
        var c = story.getTiddlerField(title,field);

        var tags = c.value.readBracketedList();
        tags.setItem(tag,mode);
        c.value = String.encodeTiddlyLinkList(tags);
};

Story.prototype.setTiddlerTag = function(title,tag,mode)
{
        Story.prototype.setTiddlerField(title,tag,mode,"tags");
};

Story.prototype.closeTiddler = function(title,animate,unused)
{
        var tiddlerElem = document.getElementById(this.idPrefix + title);
        if(tiddlerElem != null) {
                clearMessage();
                this.scrubTiddler(tiddlerElem);
                if(config.options.chkAnimate && animate && anim && typeof Slider == "function")
                        anim.startAnimating(new Slider(tiddlerElem,false,null,"all"));
                else {
                        removeNode(tiddlerElem);
                        forceReflow();
                }
        }
};

Story.prototype.scrubTiddler = function(tiddlerElem)
{
        tiddlerElem.id = null;
};

Story.prototype.setDirty = function(title,dirty)
{
        var tiddlerElem = document.getElementById(this.idPrefix + title);
        if(tiddlerElem != null)
                tiddlerElem.setAttribute("dirty",dirty ? "true" : "false");
};

Story.prototype.isDirty = function(title)
{
        var tiddlerElem = document.getElementById(this.idPrefix + title);
        if(tiddlerElem != null)
                return tiddlerElem.getAttribute("dirty") == "true";
        return null;
};

Story.prototype.areAnyDirty = function()
{
        var r = false;
        this.forEachTiddler(function(title,element) {
                if(this.isDirty(title))
                        r = true;
        });
        return r;
};

Story.prototype.closeAllTiddlers = function(exclude)
{
        clearMessage();
        this.forEachTiddler(function(title,element) {
                if((title != exclude) && element.getAttribute("dirty") != "true")
                        this.closeTiddler(title);
        });
        window.scrollTo(0,ensureVisible(this.container));
};

Story.prototype.isEmpty = function()
{
        var place = document.getElementById(this.container);
        return place && place.firstChild == null;
};

Story.prototype.search = function(text,useCaseSensitive,useRegExp)
{
        this.closeAllTiddlers();
        highlightHack = new RegExp(useRegExp ?         text : text.escapeRegExp(),useCaseSensitive ? "mg" : "img");
        var matches = store.search(highlightHack,"title","excludeSearch");
        var titles = [];
        for(var t=0;t<matches.length;t++)
                titles.push(matches[t].title);
        this.displayTiddlers(null,titles);
        highlightHack = null;
        var q = useRegExp ? "/" : "'";
        if(matches.length > 0)
                displayMessage(config.macros.search.successMsg.format([titles.length.toString(),q + text + q]));
        else
                displayMessage(config.macros.search.failureMsg.format([q + text + q]));
};

Story.prototype.findContainingTiddler = function(e)
{
        while(e && !hasClass(e,"tiddler"))
                e = e.parentNode;
        return e;
};

Story.prototype.gatherSaveFields = function(e,fields)
{
        if(e && e.getAttribute) {
                var f = e.getAttribute("edit");
                if(f)
                        fields[f] = e.value.replace(/\r/mg,"");
                if(e.hasChildNodes()) {
                        var c = e.childNodes;
                        for(var t=0; t<c.length; t++)
                                this.gatherSaveFields(c[t],fields);
                }
        }
};

Story.prototype.hasChanges = function(title)
{
        var e = document.getElementById(this.idPrefix + title);
        if(e != null) {
                var fields = {};
                this.gatherSaveFields(e,fields);
                var tiddler = store.fetchTiddler(title);
                if(!tiddler)
                        return false;
                for(var n in fields) {
                        if(store.getValue(title,n) != fields[n])
                                return true;
                }
        }
        return false;
};

Story.prototype.saveTiddler = function(title,minorUpdate)
{
        var tiddlerElem = document.getElementById(this.idPrefix + title);
        if(tiddlerElem != null) {
                var fields = {};
                this.gatherSaveFields(tiddlerElem,fields);
                var newTitle = fields.title ? fields.title : title;
                if(store.tiddlerExists(newTitle) && newTitle != title) {
                        if(!confirm(config.messages.overwriteWarning.format([newTitle.toString()])))
                                return null;
                }
                if(newTitle != title)
                        this.closeTiddler(newTitle,false);
                tiddlerElem.id = this.idPrefix + newTitle;
                tiddlerElem.setAttribute("tiddler",newTitle);
                tiddlerElem.setAttribute("template",DEFAULT_VIEW_TEMPLATE);
                tiddlerElem.setAttribute("dirty","false");
                if(config.options.chkForceMinorUpdate)
                        minorUpdate = !minorUpdate;
                if(!store.tiddlerExists(newTitle))
                        minorUpdate = false;
                var newDate = new Date();
                var extendedFields = store.tiddlerExists(newTitle) ? store.fetchTiddler(newTitle).fields : {};
                for(var n in fields) {
                        if(!TiddlyWiki.isStandardField(n))
                                extendedFields[n] = fields[n];
                        }
                var tiddler = store.saveTiddler(title,newTitle,fields.text,minorUpdate ? undefined : config.options.txtUserName,minorUpdate ? undefined : newDate,fields.tags,extendedFields);
                autoSaveChanges(null,[tiddler]);
                return newTitle;
        }
        return null;
};

Story.prototype.permaView = function()
{
        var links = [];
        this.forEachTiddler(function(title,element) {
                links.push(String.encodeTiddlyLink(title));
        });
        var t = encodeURIComponent(links.join(" "));
        if(t == "")
                t = "#";
        if(window.location.hash != t)
                window.location.hash = t;
};

//--
//-- Backstage
//--

var backstage = {
        area: null,
        toolbar: null,
        button: null,
        showButton: null,
        hideButton: null,
        cloak: null,
        panel: null,
        panelBody: null,
        panelFooter: null,
        currTabName: null,
        currTabElem: null,
        content: null,

        init: function() {
                var cmb = config.messages.backstage;
                this.area = document.getElementById("backstageArea");
                this.toolbar = document.getElementById("backstageToolbar");
                this.button = document.getElementById("backstageButton");
                this.button.style.display = "block";
                var t = cmb.open.text + " " + glyph("bentArrowLeft");
                this.showButton = createTiddlyButton(this.button,t,cmb.open.tooltip,
                                                function (e) {backstage.show(); return false;},null,"backstageShow");
                t = glyph("bentArrowRight") + " " + cmb.close.text;
                this.hideButton = createTiddlyButton(this.button,t,cmb.close.tooltip,
                                                function (e) {backstage.hide(); return false;},null,"backstageHide");
                this.cloak = document.getElementById("backstageCloak");
                this.panel = document.getElementById("backstagePanel");
                this.panelFooter = createTiddlyElement(this.panel,"div",null,"backstagePanelFooter");
                this.panelBody = createTiddlyElement(this.panel,"div",null,"backstagePanelBody");
                this.cloak.onmousedown = function(e) {
                        backstage.switchTab(null);
                };
                createTiddlyText(this.toolbar,cmb.prompt);
                for(t=0; t<config.backstageTasks.length; t++) {
                        var taskName = config.backstageTasks[t];
                        var task = config.tasks[taskName];
                        var handler = task.action ? this.onClickCommand : this.onClickTab;
                        var text = task.text + (task.action ? "" : glyph("downTriangle"));
                        var btn = createTiddlyButton(this.toolbar,text,task.tooltip,handler,"backstageTab");
                        btn.setAttribute("task",taskName);
                        addClass(btn,task.action ? "backstageAction" : "backstageTask");
                        }
                this.content = document.getElementById("contentWrapper");
                if(config.options.chkBackstage)
                        this.show();
                else
                        this.hide();
        },
        
        isVisible: function () {
                return this.area ? this.area.style.display == "block" : false;
        },
        
        show: function() {
                this.area.style.display = "block";
                if(anim && config.options.chkAnimate) {
                        backstage.toolbar.style.left = findWindowWidth() + "px";
                        var p = [
                                {style: "left", start: findWindowWidth(), end: 0, template: "%0px"}
                        ];
                        anim.startAnimating(new Morpher(backstage.toolbar,config.animDuration,p));
                } else {
                        backstage.area.style.left = "0px";
                }
                this.showButton.style.display = "none";
                this.hideButton.style.display = "block";
                config.options.chkBackstage = true;
                saveOptionCookie("chkBackstage");
                addClass(this.content,"backstageVisible");
        },

        hide: function() {
                if(this.currTabElem) {
                        this.switchTab(null);
                } else {
                        backstage.toolbar.style.left = "0px";
                        if(anim && config.options.chkAnimate) {
                                var p = [
                                        {style: "left", start: 0, end: findWindowWidth(), template: "%0px"}
                                ];
                                var c = function(element,properties) {backstage.area.style.display = "none";};
                                anim.startAnimating(new Morpher(backstage.toolbar,config.animDuration,p,c));
                        } else {
                                this.area.style.display = "none";
                        }
                        this.showButton.style.display = "block";
                        this.hideButton.style.display = "none";
                        config.options.chkBackstage = false;
                        saveOptionCookie("chkBackstage");
                        removeClass(this.content,"backstageVisible");
                }
        },

        onClickCommand: function(e) {
                var task = config.tasks[this.getAttribute("task")];
                displayMessage(task);
                if(task.action) {
                        backstage.switchTab(null);
                        task.action();
                }
                return false;
        },

        onClickTab: function(e) {
                backstage.switchTab(this.getAttribute("task"));
                return false;
        },

        // Switch to a given tab, or none if null is passed
        switchTab: function(tabName) {
                var tabElem = null;
                var e = this.toolbar.firstChild;
                while(e)
                        {
                        if(e.getAttribute && e.getAttribute("task") == tabName)
                                tabElem = e;
                        e = e.nextSibling;
                        }
                if(tabName == backstage.currTabName)
                        return;
                if(backstage.currTabElem) {
                        removeClass(this.currTabElem,"backstageSelTab");
                }
                if(tabElem && tabName) {
                        backstage.preparePanel();
                        addClass(tabElem,"backstageSelTab");
                        var task = config.tasks[tabName];
                        wikify(task.content,backstage.panelBody,null,null);
                        backstage.showPanel();
                } else if(backstage.currTabElem) {
                        backstage.hidePanel();
                }
                backstage.currTabName = tabName;
                backstage.currTabElem = tabElem;
        },

        isPanelVisible: function() {
                return backstage.panel ? backstage.panel.style.display == "block" : false;
        },

        preparePanel: function() {
                backstage.cloak.style.height = findWindowHeight() + "px";
                backstage.cloak.style.display = "block";
                removeChildren(backstage.panelBody);
                return backstage.panelBody;
        },
        
        showPanel: function() {
                backstage.panel.style.display = "block";
                if(anim && config.options.chkAnimate) {
                        backstage.panel.style.top = (-backstage.panel.offsetHeight) + "px";
                        var p = [
                                {style: "top", start: -backstage.panel.offsetHeight, end: 0, template: "%0px"}
                        ];
                        anim.startAnimating(new Morpher(backstage.panel,config.animDuration,p),new Scroller(backstage.panel,false));
                } else {
                        backstage.panel.style.top = "0px";
                }
                return backstage.panelBody;
        },
        
        hidePanel: function() {
                backstage.currTabName = null;
                backstage.currTabElem = null;
                if(anim && config.options.chkAnimate) {
                        var p = [
                                {style: "top", start: 0, end: -(backstage.panel.offsetHeight), template: "%0px"},
                                {style: "display", atEnd: "none"}
                        ];
                        var c = function(element,properties) {backstage.cloak.style.display = "none";};
                        anim.startAnimating(new Morpher(backstage.panel,config.animDuration,p,c));
                 } else {
                        backstage.panel.style.display = "none";
                        backstage.cloak.style.display = "none";
                }
        }
};

config.macros.backstage = {};

config.macros.backstage.handler = function(place,macroName,params,wikifier,paramString,tiddler)
{
        var backstageTask = config.tasks[params[0]];
        if(backstageTask)
                createTiddlyButton(place,backstageTask.text,backstageTask.tooltip,function(e) {backstage.switchTab(params[0]); return false;});
};

//--
//-- ImportTiddlers macro
//--

config.macros.importTiddlers.handler = function(place,macroName,params,wikifier,paramString,tiddler)
{
        if(readOnly) {
                createTiddlyElement(place,"div",null,"marked",this.readOnlyWarning);
                return;
        }
        var w = new Wizard();
        w.createWizard(place,this.wizardTitle);
        this.restart(w);
};

config.macros.importTiddlers.onCancel = function(e)
{
        var wizard = new Wizard(this);
        var place = wizard.clear();
        config.macros.importTiddlers.restart(wizard);
        return false;
};

config.macros.importTiddlers.restart = function(wizard)
{
        wizard.addStep(this.step1Title,this.step1Html);
        var s = wizard.getElement("selTypes");
        for(var t in config.adaptors) {
                var e = createTiddlyElement(s,"option",null,null,t);
                e.value = t;
        }
        s = wizard.getElement("selFeeds");
        var feeds = this.getFeeds();
        for(t in feeds) {
                e = createTiddlyElement(s,"option",null,null,t);
                e.value = t;
        }
        wizard.setValue("feeds",feeds);
        s.onchange = config.macros.importTiddlers.onFeedChange;
        var fileInput = wizard.getElement("txtBrowse");
        fileInput.onchange = config.macros.importTiddlers.onBrowseChange;
        fileInput.onkeyup = config.macros.importTiddlers.onBrowseChange;
        wizard.setButtons([{caption: this.openLabel, tooltip: this.openPrompt, onClick: config.macros.importTiddlers.onOpen}]);
};

config.macros.importTiddlers.getFeeds = function()
{
        var feeds = {};
        var tagged = store.getTaggedTiddlers("systemServer","title");
        for(var t=0; t<tagged.length; t++) {
                var title = tagged[t].title;
                var serverType = store.getTiddlerSlice(title,"Type");
                if(!serverType)
                        serverType = "file";
                feeds[title] = {title: title,
                                                url: store.getTiddlerSlice(title,"URL"),
                                                workspace: store.getTiddlerSlice(title,"Workspace"),
                                                workspaceList: store.getTiddlerSlice(title,"WorkspaceList"),
                                                tiddlerFilter: store.getTiddlerSlice(title,"TiddlerFilter"),
                                                serverType: serverType,
                                                description: store.getTiddlerSlice(title,"Description")};
        }
        return feeds;
};

config.macros.importTiddlers.onFeedChange = function(e)
{
        var wizard = new Wizard(this);
        var selTypes = wizard.getElement("selTypes");
        var fileInput = wizard.getElement("txtPath");
        var feeds = wizard.getValue("feeds");
        var f = feeds[this.value];
        if(f) {
                selTypes.value = f.serverType;
                fileInput.value = f.url;
                this.selectedIndex = 0;
                wizard.setValue("feedName",f.serverType);
                wizard.setValue("feedHost",f.url);
                wizard.setValue("feedWorkspace",f.workspace);
                wizard.setValue("feedWorkspaceList",f.workspaceList);
                wizard.setValue("feedTiddlerFilter",f.tiddlerFilter);
        }
        return false;
};

config.macros.importTiddlers.onBrowseChange = function(e)
{
        var wizard = new Wizard(this);
        var fileInput = wizard.getElement("txtPath");
        fileInput.value = "file://" + this.value;
        return false;
};

config.macros.importTiddlers.onOpen = function(e)
{
        var wizard = new Wizard(this);
        var fileInput = wizard.getElement("txtPath");
        var url = fileInput.value;
        var serverType = wizard.getElement("selTypes").value;
        var adaptor = new config.adaptors[serverType];
        wizard.setValue("adaptor",adaptor);
        wizard.setValue("serverType",serverType);
        wizard.setValue("host",url);
        var context = {};
        var ret = adaptor.openHost(url,context,wizard,config.macros.importTiddlers.onOpenHost);
        if(ret !== true)
                displayMessage(ret);
        wizard.setButtons([{caption: config.macros.importTiddlers.cancelLabel, tooltip: config.macros.importTiddlers.cancelPrompt, onClick: config.macros.importTiddlers.onCancel}],config.macros.importTiddlers.statusOpenHost);
        return false;
};

config.macros.importTiddlers.onOpenHost = function(context,wizard)
{
        var adaptor = wizard.getValue("adaptor");
        if(context.status !== true)
                displayMessage("Error in importTiddlers.onOpenHost: " + context.statusText);
        var ret = adaptor.getWorkspaceList(context,wizard,config.macros.importTiddlers.onGetWorkspaceList);
        if(ret !== true)
                displayMessage(ret);
        wizard.setButtons([{caption: config.macros.importTiddlers.cancelLabel, tooltip: config.macros.importTiddlers.cancelPrompt, onClick: config.macros.importTiddlers.onCancel}],config.macros.importTiddlers.statusGetWorkspaceList);
};

config.macros.importTiddlers.onGetWorkspaceList = function(context,wizard)
{
        if(context.status !== true)
                displayMessage("Error in importTiddlers.onGetWorkspaceList: " + context.statusText);
        wizard.addStep(config.macros.importTiddlers.step2Title,config.macros.importTiddlers.step2Html);
        var s = wizard.getElement("selWorkspace");
        s.onchange = config.macros.importTiddlers.onWorkspaceChange;
        for(var t=0; t<context.workspaces.length; t++) {
                var e = createTiddlyElement(s,"option",null,null,context.workspaces[t].title);
                e.value = context.workspaces[t].title;
        }
        var workspaceList = wizard.getValue("feedWorkspaceList");
        if(workspaceList) {
                var list = workspaceList.parseParams("workspace",null,false,true);
                for(var n=1; n<list.length; n++) {
                        if(context.workspaces.findByField("title",list[n].value) == null) {
                                e = createTiddlyElement(s,"option",null,null,list[n].value);
                                e.value = list[n].value;
                        }
                }
        }
        var workspace = wizard.getValue("feedWorkspace");
        if(workspace) {
                t = wizard.getElement("txtWorkspace");
                t.value = workspace;
        }
        wizard.setButtons([{caption: config.macros.importTiddlers.openLabel, tooltip: config.macros.importTiddlers.openPrompt, onClick: config.macros.importTiddlers.onChooseWorkspace}]);
};

config.macros.importTiddlers.onWorkspaceChange = function(e)
{
        var wizard = new Wizard(this);
        var t = wizard.getElement("txtWorkspace");
        t.value  = this.value;
        this.selectedIndex = 0;
        return false;
};

config.macros.importTiddlers.onChooseWorkspace = function(e)
{
        var wizard = new Wizard(this);
        var adaptor = wizard.getValue("adaptor");
        var workspace = wizard.getElement("txtWorkspace").value;
        wizard.setValue("workspace",workspace);
        var context = {};
        var ret = adaptor.openWorkspace(workspace,context,wizard,config.macros.importTiddlers.onOpenWorkspace);
        if(ret !== true)
                displayMessage(ret);
        wizard.setButtons([{caption: config.macros.importTiddlers.cancelLabel, tooltip: config.macros.importTiddlers.cancelPrompt, onClick: config.macros.importTiddlers.onCancel}],config.macros.importTiddlers.statusOpenWorkspace);
        return false;
};

config.macros.importTiddlers.onOpenWorkspace = function(context,wizard)
{
        if(context.status !== true)
                displayMessage("Error in importTiddlers.onOpenWorkspace: " + context.statusText);
        var adaptor = wizard.getValue("adaptor");
        var ret = adaptor.getTiddlerList(context,wizard,config.macros.importTiddlers.onGetTiddlerList,wizard.getValue("feedTiddlerFilter"));
        if(ret !== true)
                displayMessage(ret);
        wizard.setButtons([{caption: config.macros.importTiddlers.cancelLabel, tooltip: config.macros.importTiddlers.cancelPrompt, onClick: config.macros.importTiddlers.onCancel}],config.macros.importTiddlers.statusGetTiddlerList);
};

config.macros.importTiddlers.onGetTiddlerList = function(context,wizard)
{
        if(context.status !== true)
                displayMessage("Error in importTiddlers.onGetTiddlerList: " + context.statusText);
        // Extract data for the listview
        var listedTiddlers = [];
        if(context.tiddlers) {
                for(var n=0; n<context.tiddlers.length; n++) {
                        var tiddler = context.tiddlers[n];
                        listedTiddlers.push({
                                title: tiddler.title,
                                modified: tiddler.modified,
                                modifier: tiddler.modifier,
                                text: tiddler.text ? wikifyPlainText(tiddler.text,100) : "",
                                tags: tiddler.tags,
                                size: tiddler.text ? tiddler.text.length : 0,
                                tiddler: tiddler
                        });
                }
        }
        listedTiddlers.sort(function(a,b) {return a.title < b.title ? -1 : (a.title == b.title ? 0 : +1);});
        // Display the listview
        wizard.addStep(config.macros.importTiddlers.step3Title,config.macros.importTiddlers.step3Html);
        var markList = wizard.getElement("markList");
        var listWrapper = document.createElement("div");
        markList.parentNode.insertBefore(listWrapper,markList);
        var listView = ListView.create(listWrapper,listedTiddlers,config.macros.importTiddlers.listViewTemplate);
        wizard.setValue("listView",listView);
        var txtSaveTiddler = wizard.getElement("txtSaveTiddler");
        txtSaveTiddler.value = config.macros.importTiddlers.generateSystemServerName(wizard);
        wizard.setButtons([
                        {caption: config.macros.importTiddlers.cancelLabel, tooltip: config.macros.importTiddlers.cancelPrompt, onClick: config.macros.importTiddlers.onCancel},
                        {caption: config.macros.importTiddlers.importLabel, tooltip: config.macros.importTiddlers.importPrompt, onClick:  config.macros.importTiddlers.doImport}
                ]);
};

config.macros.importTiddlers.generateSystemServerName = function(wizard)
{
        var serverType = wizard.getValue("serverType");
        var host = wizard.getValue("host");
        var workspace = wizard.getValue("workspace");
        var pattern = config.macros.importTiddlers[workspace ? "systemServerNamePattern" : "systemServerNamePatternNoWorkspace"];
        return pattern.format([serverType,host,workspace]);
};

config.macros.importTiddlers.saveServerTiddler = function(wizard)
{
        var txtSaveTiddler = wizard.getElement("txtSaveTiddler").value;
        if(store.tiddlerExists(txtSaveTiddler)) {
                if(!confirm(config.macros.importTiddlers.confirmOverwriteSaveTiddler.format([txtSaveTiddler])))
                        return;
                store.suspendNotifications();
                store.removeTiddler(txtSaveTiddler);
                store.resumeNotifications();
        }
        var serverType = wizard.getValue("serverType");
        var host = wizard.getValue("host");
        var workspace = wizard.getValue("workspace");
        var text = config.macros.importTiddlers.serverSaveTemplate.format([serverType,host,workspace]);
        store.saveTiddler(txtSaveTiddler,txtSaveTiddler,text,config.macros.importTiddlers.serverSaveModifier,new Date(),["systemServer"]);
};

config.macros.importTiddlers.doImport = function(e)
{
        var wizard = new Wizard(this);
        if(wizard.getElement("chkSave").checked)
                config.macros.importTiddlers.saveServerTiddler(wizard);
        var chkSync = wizard.getElement("chkSync").checked;
        wizard.setValue("sync",chkSync);
        var listView = wizard.getValue("listView");
        var rowNames = ListView.getSelectedRows(listView);
        var adaptor = wizard.getValue("adaptor");
        var overwrite = new Array();
        var t;
        for(t=0; t<rowNames.length; t++) {
                if(store.tiddlerExists(rowNames[t]))
                        overwrite.push(rowNames[t]);
        }
        if(overwrite.length > 0) {
                if(!confirm(config.macros.importTiddlers.confirmOverwriteText.format([overwrite.join(", ")])))
                        return false;
        }
        wizard.addStep(config.macros.importTiddlers.step4Title.format([rowNames.length]),config.macros.importTiddlers.step4Html);
        for(t=0; t<rowNames.length; t++) {
                var link = document.createElement("div");
                createTiddlyLink(link,rowNames[t],true);
                var place = wizard.getElement("markReport");
                place.parentNode.insertBefore(link,place);
        }
        wizard.setValue("remainingImports",rowNames.length);
        wizard.setButtons([
                        {caption: config.macros.importTiddlers.cancelLabel, tooltip: config.macros.importTiddlers.cancelPrompt, onClick: config.macros.importTiddlers.onCancel}
                ],config.macros.importTiddlers.statusDoingImport);
        for(t=0; t<rowNames.length; t++) {
                var context = {};
                context.allowSynchronous = true;
                var inbound = adaptor.getTiddler(rowNames[t],context,wizard,config.macros.importTiddlers.onGetTiddler);
        }
        return false;
};

config.macros.importTiddlers.onGetTiddler = function(context,wizard)
{
        if(!context.status)
                displayMessage("Error in importTiddlers.onGetTiddler: " + context.statusText);
        var tiddler = context.tiddler;
        store.suspendNotifications();
        store.saveTiddler(tiddler.title, tiddler.title, tiddler.text, tiddler.modifier, tiddler.modified, tiddler.tags, tiddler.fields, true, tiddler.created);
        if(!wizard.getValue("sync")) {
                store.setValue(tiddler.title,'server',null);
        }
        store.resumeNotifications();
        if(!context.isSynchronous) 
                store.notify(tiddler.title,true);
        var remainingImports = wizard.getValue("remainingImports")-1;
        wizard.setValue("remainingImports",remainingImports);
        if(remainingImports == 0) {
                if(context.isSynchronous) {
                        store.notifyAll();
                        refreshDisplay();
                }
                wizard.setButtons([
                                {caption: config.macros.importTiddlers.doneLabel, tooltip: config.macros.importTiddlers.donePrompt, onClick: config.macros.importTiddlers.onCancel}
                        ],config.macros.importTiddlers.statusDoneImport);
                autoSaveChanges();
        }
};

//--
//-- Sync macro
//--

// Synchronisation handlers
config.syncers = {};

// Sync state.
var currSync = null;

// sync macro
config.macros.sync.handler = function(place,macroName,params,wikifier,paramString,tiddler)
{
        if(!wikifier.isStatic)
                this.startSync(place);
};

config.macros.sync.startSync = function(place)
{
        if(currSync)
                config.macros.sync.cancelSync();
        currSync = {};
        currSync.syncList = this.getSyncableTiddlers();
        this.createSyncTasks();
        this.preProcessSyncableTiddlers();
        var wizard = new Wizard();
        currSync.wizard = 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);
        currSync.listView = ListView.create(listWrapper,currSync.syncList,this.listViewTemplate);
        this.processSyncableTiddlers();
        wizard.setButtons([
                        {caption: this.syncLabel, tooltip: this.syncPrompt, onClick: this.doSync}
                ]);
};

config.macros.sync.getSyncableTiddlers = function ()
{
        var list = [];
        store.forEachTiddler(function(title,tiddler) {
                var syncItem = {};
                syncItem.serverType = tiddler.getServerType();
                syncItem.serverHost = tiddler.fields['server.host'];
                syncItem.serverWorkspace = tiddler.fields['server.workspace'];
                syncItem.tiddler = tiddler;
                syncItem.title = tiddler.title;
                syncItem.isTouched = tiddler.isTouched();
                syncItem.selected = syncItem.isTouched;
                syncItem.syncStatus = config.macros.sync.syncStatusList[syncItem.isTouched ? "changedLocally" : "none"];
                syncItem.status = syncItem.syncStatus.text;
                if(syncItem.serverType && syncItem.serverHost)
                        list.push(syncItem);
                });
        list.sort(function(a,b) {return a.title < b.title ? -1 : (a.title == b.title ? 0 : +1);});
        return list;
};

config.macros.sync.preProcessSyncableTiddlers = function()
{
        for(var t=0; t<currSync.syncList.length; t++) {
                si = currSync.syncList[t];
                var ti = si.syncTask.syncMachine.generateTiddlerInfo(si.tiddler);
                si.serverUrl = ti.uri;
        }
};

config.macros.sync.processSyncableTiddlers = function()
{
        for(var t=0; t<currSync.syncList.length; t++) {
                si = currSync.syncList[t];
                si.rowElement.style.backgroundColor = si.syncStatus.color;
        }
};

config.macros.sync.createSyncTasks = function()
{
        currSync.syncTasks = [];
        for(var t=0; t<currSync.syncList.length; t++) {
                var si = currSync.syncList[t];
                var r = null;
                for(var st=0; st<currSync.syncTasks.length; st++) {
                        var cst = currSync.syncTasks[st];
                        if(si.serverType == cst.serverType && si.serverHost == cst.serverHost && si.serverWorkspace == cst.serverWorkspace)
                                r = cst;
                }
                if(r == null) {
                        si.syncTask = this.createSyncTask(si);
                        currSync.syncTasks.push(si.syncTask);
                } else {
                        si.syncTask = r;
                        r.syncItems.push(si);
                }
        }
};

config.macros.sync.createSyncTask = function(syncItem)
{
        var st = {};
        st.serverType = syncItem.serverType;
        st.serverHost = syncItem.serverHost;
        st.serverWorkspace = syncItem.serverWorkspace;
        st.syncItems = [syncItem];
        st.syncMachine = new SyncMachine(st.serverType,{
                start: function() {
                        return this.openHost(st.serverHost,"openWorkspace");
                },
                openWorkspace: function() {
                        return this.openWorkspace(st.serverWorkspace,"getTiddlerList");
                },
                getTiddlerList: function() {
                        return this.getTiddlerList("gotTiddlerList");
                },
                gotTiddlerList: function(tiddlers) {
                        for(var t=0; t<st.syncItems.length; t++) {
                                var si = st.syncItems[t];
                                var f = tiddlers.findByField("title",si.title);
                                if(f !== null) {
                                        if(tiddlers[f].fields['server.page.revision'] > si.tiddler.fields['server.page.revision']) {
                                                si.syncStatus = config.macros.sync.syncStatusList[si.isTouched ? 'changedBoth' : 'changedServer'];
                                        }
                                } else {
                                        si.syncStatus = config.macros.sync.syncStatusList.notFound;
                                }
                                config.macros.sync.updateSyncStatus(si);
                        }
                },
                getTiddler: function(title) {
                        return this.getTiddler(title,"onGetTiddler");
                },
                onGetTiddler: function(tiddler) {
                        var syncItem = st.syncItems.findByField("title",tiddler.title);
                        if(syncItem !== null) {
                                syncItem = st.syncItems[syncItem];
                                store.saveTiddler(tiddler.title, tiddler.title, tiddler.text, tiddler.modifier, tiddler.modified, tiddler.tags, tiddler.fields, true, tiddler.created);
                                syncItem.syncStatus = config.macros.sync.syncStatusList.gotFromServer;
                                config.macros.sync.updateSyncStatus(syncItem);
                        }
                },
                putTiddler: function(tiddler) {
                        return this.putTiddler(tiddler,"onPutTiddler");
                },
                onPutTiddler: function(tiddler) {
                        var syncItem = st.syncItems.findByField("title",tiddler.title);
                        if(syncItem !== null) {
                                syncItem = st.syncItems[syncItem];
                                store.resetTiddler(tiddler.title);
                                syncItem.syncStatus = config.macros.sync.syncStatusList.putToServer;
                                config.macros.sync.updateSyncStatus(syncItem);
                        }
                }
        });
        st.syncMachine.go();
        return st;
};

config.macros.sync.updateSyncStatus = function(syncItem)
{
        var e = syncItem.colElements["status"];
        removeChildren(e);
        createTiddlyText(e,syncItem.syncStatus.text);
        syncItem.rowElement.style.backgroundColor = syncItem.syncStatus.color;
};

config.macros.sync.doSync = function(e)
{
        var rowNames = ListView.getSelectedRows(currSync.listView);
        for(var t=0; t<currSync.syncList.length; t++) {
                var si = currSync.syncList[t];
                if(rowNames.indexOf(si.title) != -1) {
                        config.macros.sync.doSyncItem(si);
                }
        }
        return false;
};

config.macros.sync.doSyncItem = function(syncItem)
{
        var r = true;
        var sl = config.macros.sync.syncStatusList;
        switch(syncItem.syncStatus) {
                case sl.changedServer:
                        r = syncItem.syncTask.syncMachine.go("getTiddler",syncItem.title);
                        break;
                case sl.notFound:
                case sl.changedLocally:
                case sl.changedBoth:
                        r = syncItem.syncTask.syncMachine.go("putTiddler",syncItem.tiddler);
                        break;
                default:
                        break;
        }
        if(r !== true)
                displayMessage("Error in doSyncItem: " + r);
};

config.macros.sync.cancelSync = function()
{
        currSync = null;
};

function SyncMachine(serverType,steps)
{
        this.serverType = serverType;
        this.adaptor = new config.adaptors[serverType];
        this.steps = steps;
}

SyncMachine.prototype.go = function(step,varargs)
{
        if(!step)
                step = "start";
        var h = this.steps[step];
        if(!h)
                return null;
        var a = [];
        for(var t=1; t<arguments.length; t++)
                a.push(arguments[t]);
        var r = h.apply(this,a);
        if(typeof r == "string")
                this.invokeError(r);
        return r;
};

SyncMachine.prototype.invokeError = function(message)
{
        if(this.steps.error)
                this.steps.error(message);
};

SyncMachine.prototype.openHost = function(host,nextStep)
{
        var me = this;
        return me.adaptor.openHost(host,null,null,function(context) {
                if(typeof context.status == "string")
                        me.invokeError(context.status);
                else
                        me.go(nextStep);
        });
};

SyncMachine.prototype.getWorkspaceList = function(nextStep)
{
        var me = this;
        return me.adaptor.getWorkspaceList(null,null,function(context) {
                if(typeof context.status == "string")
                        me.invokeError(context.status);
                else
                        me.go(nextStep,context.workspaces);
        });
};

SyncMachine.prototype.openWorkspace = function(workspace,nextStep)
{
        var me = this;
        return me.adaptor.openWorkspace(workspace,null,null,function(context) {
                if(typeof context.status == "string")
                        me.invokeError(context.status);
                else
                        me.go(nextStep);
        });
};

SyncMachine.prototype.getTiddlerList = function(nextStep)
{
        var me = this;
        return me.adaptor.getTiddlerList(null,null,function(context) {
                if(typeof context.status == "string")
                        me.invokeError(context.status);
                else
                        me.go(nextStep,context.tiddlers);
        });
};

SyncMachine.prototype.generateTiddlerInfo = function(tiddler)
{
        return this.adaptor.generateTiddlerInfo(tiddler);
};

SyncMachine.prototype.getTiddler = function(title,nextStep)
{
        var me = this;
        return me.adaptor.getTiddler(title,null,null,function(context) {
                if(typeof context.status == "string")
                        me.invokeError(context.status);
                else
                        me.go(nextStep,context.tiddler);
        });
};

SyncMachine.prototype.putTiddler = function(tiddler,nextStep)
{
        var me = this;
        return me.adaptor.putTiddler(tiddler,null,null,function(context) {
                if(typeof context.status == "string")
                        me.invokeError(context.status);
                else
                        me.go(nextStep,tiddler);
        });
};

//--
//-- Manager UI for groups of tiddlers
//--

config.macros.plugins.handler = function(place,macroName,params,wikifier,paramString,tiddler)
{
        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);
        listWrapper.setAttribute("refresh","macro");
        listWrapper.setAttribute("macroName","plugins");
        listWrapper.setAttribute("params",paramString);
        this.refresh(listWrapper,paramString);
};

config.macros.plugins.refresh = function(listWrapper,params)
{
        var wizard = new Wizard(listWrapper);
        var selectedRows = [];
        ListView.forEachSelector(listWrapper,function(e,rowName) {
                        if(e.checked)
                                selectedRows.push(e.getAttribute("rowName"));
                });
        removeChildren(listWrapper);
        params = params.parseParams("anon");
        var plugins = installedPlugins.slice(0);
        var t,tiddler,p;
        var configTiddlers = store.getTaggedTiddlers("systemConfig");
        for(t=0; t<configTiddlers.length; t++) {
                tiddler = configTiddlers[t];
                if(plugins.findByField("title",tiddler.title) == null) {
                        p = getPluginInfo(tiddler);
                        p.executed = false;
                        p.log.splice(0,0,this.skippedText);
                        plugins.push(p);
                }
        }
        for(t=0; t<plugins.length; t++) {
                p = plugins[t];
                p.size = p.tiddler.text ? p.tiddler.text.length : 0;
                p.forced = p.tiddler.isTagged("systemConfigForce");
                p.disabled = p.tiddler.isTagged("systemConfigDisable");
                p.Selected = selectedRows.indexOf(plugins[t].title) != -1;
        }
        if(plugins.length == 0) {
                createTiddlyElement(listWrapper,"em",null,null,this.noPluginText);
                wizard.setButtons([]);
        } else {
                var listView = ListView.create(listWrapper,plugins,this.listViewTemplate,this.onSelectCommand);
                wizard.setValue("listView",listView);
                wizard.setButtons([
                                {caption: config.macros.plugins.removeLabel, tooltip: config.macros.plugins.removePrompt, onClick:  config.macros.plugins.doRemoveTag},
                                {caption: config.macros.plugins.deleteLabel, tooltip: config.macros.plugins.deletePrompt, onClick:  config.macros.plugins.doDelete}
                        ]);
        }
};

config.macros.plugins.doRemoveTag = function(e)
{
        var wizard = new Wizard(this);
        var listView = wizard.getValue("listView");
        var rowNames = ListView.getSelectedRows(listView);
        if(rowNames.length == 0) {
                alert(config.messages.nothingSelected);
        } else {
                for(var t=0; t<rowNames.length; t++)
                        store.setTiddlerTag(rowNames[t],false,"systemConfig");
        }
};

config.macros.plugins.doDelete = function(e)
{
        var wizard = new Wizard(this);
        var listView = wizard.getValue("listView");
        var rowNames = ListView.getSelectedRows(listView);
        if(rowNames.length == 0) {
                alert(config.messages.nothingSelected);
        } else {
                if(confirm(config.macros.plugins.confirmDeleteText.format([rowNames.join(", ")]))) {
                        for(t=0; t<rowNames.length; t++) {
                                store.removeTiddler(rowNames[t]);
                                story.closeTiddler(rowNames[t],true);
                        }
                }
        }
};

//--
//-- Message area
//--

function getMessageDiv()
{
        var msgArea = document.getElementById("messageArea");
        if(!msgArea)
                return null;
        if(!msgArea.hasChildNodes())
                createTiddlyButton(createTiddlyElement(msgArea,"div",null,"messageToolbar"),
                        config.messages.messageClose.text,
                        config.messages.messageClose.tooltip,
                        clearMessage);
        msgArea.style.display = "block";
        return createTiddlyElement(msgArea,"div");
}

function displayMessage(text,linkText)
{
        var e = getMessageDiv();
        if(!e) {
                alert(text);
                return;
        }
        if(linkText) {
                var link = createTiddlyElement(e,"a",null,null,text);
                link.href = linkText;
                link.target = "_blank";
        } else {
                e.appendChild(document.createTextNode(text));
        }
}

function clearMessage()
{
        var msgArea = document.getElementById("messageArea");
        if(msgArea) {
                removeChildren(msgArea);
                msgArea.style.display = "none";
        }
        return false;
}

//--
//-- Refresh mechanism
//--

config.refreshers = {
        link: function(e,changeList)
                {
                var title = e.getAttribute("tiddlyLink");
                refreshTiddlyLink(e,title);
                return true;
                },
        
        tiddler: function(e,changeList)
                {
                var title = e.getAttribute("tiddler");
                var template = e.getAttribute("template");
                if(changeList && changeList.indexOf(title) != -1 && !story.isDirty(title))
                        story.refreshTiddler(title,template,true);
                else
                        refreshElements(e,changeList);
                return true;
                },

        content: function(e,changeList)
                {
                var title = e.getAttribute("tiddler");
                var force = e.getAttribute("force");
                if(force != null || changeList == null || changeList.indexOf(title) != -1) {
                        removeChildren(e);
                        wikify(store.getTiddlerText(title,title),e,null);
                        return true;
                } else
                        return false;
                },

        macro: function(e,changeList)
                {
                var macro = e.getAttribute("macroName");
                var params = e.getAttribute("params");
                if(macro)
                        macro = config.macros[macro];
                if(macro && macro.refresh)
                        macro.refresh(e,params);
                return true;
                }
};

function refreshElements(root,changeList)
{
        var nodes = root.childNodes;
        for(var c=0; c<nodes.length; c++) {
                var e = nodes[c], type = null;
                if(e.getAttribute  && (e.tagName ? e.tagName != "IFRAME" : true))
                        type = e.getAttribute("refresh");
                var refresher = config.refreshers[type];
                var refreshed = false;
                if(refresher != undefined)
                        refreshed = refresher(e,changeList);
                if(e.hasChildNodes() && !refreshed)
                        refreshElements(e,changeList);
        }
}

function applyHtmlMacros(root,tiddler)
{
        var e = root.firstChild;
        while(e) {
                var nextChild = e.nextSibling;
                if(e.getAttribute) {
                        var macro = e.getAttribute("macro");
                        if(macro) {
                                var params = "";
                                var p = macro.indexOf(" ");
                                if(p != -1) {
                                        params = macro.substr(p+1);
                                        macro = macro.substr(0,p);
                                }
                                invokeMacro(e,macro,params,null,tiddler);
                        }
                }
                if(e.hasChildNodes())
                        applyHtmlMacros(e,tiddler);
                e = nextChild;
        }
}

function refreshPageTemplate(title)
{
        var stash = createTiddlyElement(document.body,"div");
        stash.style.display = "none";
        var display = document.getElementById("tiddlerDisplay");
        var nodes,t;
        if(display) {
                nodes = display.childNodes;
                for(t=nodes.length-1; t>=0; t--)
                        stash.appendChild(nodes[t]);
        }
        var wrapper = document.getElementById("contentWrapper");
        if(!title)
                title = "PageTemplate";
        var html = store.getRecursiveTiddlerText(title,null,10);
        wrapper.innerHTML = html;
        applyHtmlMacros(wrapper);
        refreshElements(wrapper);
        display = document.getElementById("tiddlerDisplay");
        removeChildren(display);
        if(!display)
                display = createTiddlyElement(wrapper,"div","tiddlerDisplay");
        nodes = stash.childNodes;
        for(t=nodes.length-1; t>=0; t--)
                display.appendChild(nodes[t]);
        removeNode(stash);
}

function refreshDisplay(hint)
{
        if(typeof hint == "string")
                hint = [hint];
        var e = document.getElementById("contentWrapper");
        refreshElements(e,hint);
        if(backstage.isPanelVisible()) {
                e = document.getElementById("backstage");
                refreshElements(e,hint);
        }
}

function refreshPageTitle()
{
        document.title = getPageTitle();
}

function getPageTitle()
{
        var st = wikifyPlain("SiteTitle");
        var ss = wikifyPlain("SiteSubtitle");
        return st + ((st == "" || ss == "") ? "" : " - ") + ss;
}

function refreshStyles(title,doc)
{
        if(!doc)
                doc = document;
        setStylesheet(title == null ? "" : store.getRecursiveTiddlerText(title,"",10),title,doc);
}

function refreshColorPalette(title)
{
        if(!startingUp)
                refreshAll();
}

function refreshAll()
{
        refreshPageTemplate();
        refreshDisplay();
        refreshStyles("StyleSheetLayout");
        refreshStyles("StyleSheetColors");
        refreshStyles("StyleSheet");
        refreshStyles("StyleSheetPrint");
}

//--
//-- Options cookie stuff
//--

config.optionHandlers = {
        'txt': {
                get: function(name) {return encodeCookie(config.options[name].toString());},
                set: function(name,value) {config.options[name] = decodeCookie(value);}
        },
        'chk': {
                get: function(name) {return config.options[name] ? "true" : "false";},
                set: function(name,value) {config.options[name] = value == "true";}
        }
};

function loadOptionsCookie()
{
        if(safeMode)
                return;
        var cookies = document.cookie.split(";");
        for(var c=0; c<cookies.length; c++) {
                var p = cookies[c].indexOf("=");
                if(p != -1) {
                        var name = cookies[c].substr(0,p).trim();
                        var value = cookies[c].substr(p+1).trim();
                        var optType = name.substr(0,3);
                        if(config.optionHandlers[optType] && config.optionHandlers[optType].set)
                                config.optionHandlers[optType].set(name,value);
                }
        }
}

function saveOptionCookie(name)
{
        if(safeMode)
                return;
        var c = name + "=";
        var optType = name.substr(0,3);
        if(config.optionHandlers[optType] && config.optionHandlers[optType].get)
                c += config.optionHandlers[optType].get(name);
        c += "; expires=Fri, 1 Jan 2038 12:00:00 UTC; path=/";
        document.cookie = c;
}

function encodeCookie(s)
{
        return escape(manualConvertUnicodeToUTF8(s));
}

function decodeCookie(s)
{
        s = unescape(s);
        var re = /&#[0-9]{1,5};/g;
        return s.replace(re,function($0) {return String.fromCharCode(eval($0.replace(/[&#;]/g,"")));});
}

//--
//-- Saving
//--

var saveUsingSafari = false;

var startSaveArea = '<div id="' + 'storeArea">'; // Split up into two so that indexOf() of this source doesn't find it
var endSaveArea = '</d' + 'iv>';

// If there are unsaved changes, force the user to confirm before exitting
function confirmExit()
{
        hadConfirmExit = true;
        if((store && store.isDirty && store.isDirty()) || (story && story.areAnyDirty && story.areAnyDirty()))
                return config.messages.confirmExit;
}

// Give the user a chance to save changes before exitting
function checkUnsavedChanges()
{
        if(store && store.isDirty && store.isDirty() && window.hadConfirmExit === false) {
                if(confirm(config.messages.unsavedChangesWarning))
                        saveChanges();
        }
}

function updateLanguageAttribute(s)
{
        if(config.locale) {
                var mRE = /(<html(?:.*?)?)(?: xml:lang\="([a-z]+)")?(?: lang\="([a-z]+)")?>/;
                var m = mRE.exec(s);
                if(m) {
                        var t = m[1];
                        if(m[2])
                                t += ' xml:lang="' + config.locale + '"';
                        if(m[3])
                                t += ' lang="' + config.locale + '"';
                        t += ">";
                        s = s.substr(0,m.index) + t + s.substr(m.index+m[0].length);
                }
        }
        return s;
}

function updateMarkupBlock(s,blockName,tiddlerName)
{
        return s.replaceChunk(
                        "<!--%0-START-->".format([blockName]),
                        "<!--%0-END-->".format([blockName]),
                        "\n" + store.getRecursiveTiddlerText(tiddlerName,"") + "\n");
}

function updateOriginal(original,posDiv)
{
        if(!posDiv)
                posDiv = locateStoreArea(original);
        if(!posDiv) {
                alert(config.messages.invalidFileError.format([localPath]));
                return null;
        }
        var revised = original.substr(0,posDiv[0] + startSaveArea.length) + "\n" +
                                convertUnicodeToUTF8(store.allTiddlersAsHtml()) + "\n" +
                                original.substr(posDiv[1]);
        var newSiteTitle = convertUnicodeToUTF8(getPageTitle()).htmlEncode();
        revised = revised.replaceChunk("<title"+">","</title"+">"," " + newSiteTitle + " ");
        revised = updateLanguageAttribute(revised);
        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;
}

function locateStoreArea(original)
{
        // Locate the storeArea div's
        var posOpeningDiv = original.indexOf(startSaveArea);
        var limitClosingDiv = original.indexOf("<"+"!--POST-STOREAREA--"+">");
        if(limitClosingDiv == -1)
                limitClosingDiv = original.indexOf("<"+"!--POST-BODY-START--"+">");
        var posClosingDiv = original.lastIndexOf(endSaveArea,limitClosingDiv == -1 ? original.length : limitClosingDiv);
        return (posOpeningDiv != -1 && posClosingDiv != -1) ? [posOpeningDiv,posClosingDiv] : null;
}

function autoSaveChanges(onlyIfDirty,tiddlers)
{
        if(config.options.chkAutoSave)
                saveChanges(onlyIfDirty,tiddlers);
}

// Save this tiddlywiki with the pending changes
function saveChanges(onlyIfDirty,tiddlers)
{
        if(onlyIfDirty && !store.isDirty())
                return;
        clearMessage();
        // Get the URL of the document
        var originalPath = document.location.toString();
        // Check we were loaded from a file URL
        if(originalPath.substr(0,5) != "file:") {
                alert(config.messages.notFileUrlError);
                if(store.tiddlerExists(config.messages.saveInstructions))
                        story.displayTiddler(null,config.messages.saveInstructions);
                return;
        }
        var localPath = getLocalPath(originalPath);
        // Load the original file
        var original = loadFile(localPath);
        if(original == null) {
                alert(config.messages.cantSaveError);
                if(store.tiddlerExists(config.messages.saveInstructions))
                        story.displayTiddler(null,config.messages.saveInstructions);
                return;
        }
        // Locate the storeArea div's
        var posDiv = locateStoreArea(original);
        if(!posDiv) {
                alert(config.messages.invalidFileError.format([localPath]));
                return;
        }
        saveBackup(localPath,original);
        saveRss(localPath);
        saveEmpty(localPath,original,posDiv);
        saveMain(localPath,original,posDiv);
}

function saveBackup(localPath,original)
{
        // Save the backup
        if(config.options.chkSaveBackups) {
                var backupPath = getBackupPath(localPath);
                var backup = config.browser.isIE ? ieCopyFile(backupPath,localPath) : saveFile(backupPath,original);
                if(backup)
                        displayMessage(config.messages.backupSaved,"file://" + backupPath);
                else
                        alert(config.messages.backupFailed);
        }
}

function saveRss(localPath)
{
        if(config.options.chkGenerateAnRssFeed) {
                var rssPath = localPath.substr(0,localPath.lastIndexOf(".")) + ".xml";
                var rssSave = saveFile(rssPath,convertUnicodeToUTF8(generateRss()));
                if(rssSave)
                        displayMessage(config.messages.rssSaved,"file://" + rssPath);
                else
                        alert(config.messages.rssFailed);
        }
}

function saveEmpty(localPath,original,posDiv)
{
        if(config.options.chkSaveEmptyTemplate) {
                var emptyPath,p;
                if((p = localPath.lastIndexOf("/")) != -1)
                        emptyPath = localPath.substr(0,p) + "/empty.html";
                else if((p = localPath.lastIndexOf("\\")) != -1)
                        emptyPath = localPath.substr(0,p) + "\\empty.html";
                else
                        emptyPath = localPath + ".empty.html";
                var empty = original.substr(0,posDiv[0] + startSaveArea.length) + original.substr(posDiv[1]);
                var emptySave = saveFile(emptyPath,empty);
                if(emptySave)
                        displayMessage(config.messages.emptySaved,"file://" + emptyPath);
                else
                        alert(config.messages.emptyFailed);
        }
}

function saveMain(localPath,original,posDiv)
{
        var save;
        try {
                var revised = updateOriginal(original,posDiv);
                save = saveFile(localPath,revised);
        } catch (ex) {
                showException(ex);
        }
        if(save) {
                displayMessage(config.messages.mainSaved,"file://" + localPath);
                store.setDirty(false);
        } else {
                alert(config.messages.mainFailed);
        }
}

function getLocalPath(origPath)
{
        var originalPath = convertUriToUTF8(origPath,config.options.txtFileSystemCharSet);
        // Remove any location or query part of the URL
        var argPos = originalPath.indexOf("?");
        if(argPos != -1)
                originalPath = originalPath.substr(0,argPos);
        var hashPos = originalPath.indexOf("#");
        if(hashPos != -1)
                originalPath = originalPath.substr(0,hashPos);
        // Convert file://localhost/ to file:///
        if(originalPath.indexOf("file://localhost/") == 0)
                originalPath = "file://" + originalPath.substr(16);
        // Convert to a native file format
        var localPath;
        if(originalPath.charAt(9) == ":") // pc local file
                localPath = unescape(originalPath.substr(8)).replace(new RegExp("/","g"),"\\");
        else if(originalPath.indexOf("file://///") == 0) // FireFox pc network file
                localPath = "\\\\" + unescape(originalPath.substr(10)).replace(new RegExp("/","g"),"\\");
        else if(originalPath.indexOf("file:///") == 0) // mac/unix local file
                localPath = unescape(originalPath.substr(7));
        else if(originalPath.indexOf("file:/") == 0) // mac/unix local file
                localPath = unescape(originalPath.substr(5));
        else // pc network file
                localPath = "\\\\" + unescape(originalPath.substr(7)).replace(new RegExp("/","g"),"\\");
        return localPath;
}

function getBackupPath(localPath)
{
        var backSlash = true;
        var dirPathPos = localPath.lastIndexOf("\\");
        if(dirPathPos == -1) {
                dirPathPos = localPath.lastIndexOf("/");
                backSlash = false;
        }
        var backupFolder = config.options.txtBackupFolder;
        if(!backupFolder || backupFolder == "")
                backupFolder = ".";
        var backupPath = localPath.substr(0,dirPathPos) + (backSlash ? "\\" : "/") + backupFolder + localPath.substr(dirPathPos);
        backupPath = backupPath.substr(0,backupPath.lastIndexOf(".")) + "." + (new Date()).convertToYYYYMMDDHHMMSSMMM() + ".html";
        return backupPath;
}

function generateRss()
{
        var s = [];
        var d = new Date();
        var u = store.getTiddlerText("SiteUrl");
        // Assemble the header
        s.push("<" + "?xml version=\"1.0\"?" + ">");
        s.push("<rss version=\"2.0\">");
        s.push("<channel>");
        s.push("<title" + ">" + wikifyPlain("SiteTitle").htmlEncode() + "</title" + ">");
        if(u)
                s.push("<link>" + u.htmlEncode() + "</link>");
        s.push("<description>" + wikifyPlain("SiteSubtitle").htmlEncode() + "</description>");
        s.push("<language>en-us</language>");
        s.push("<copyright>Copyright " + d.getFullYear() + " " + config.options.txtUserName.htmlEncode() + "</copyright>");
        s.push("<pubDate>" + d.toGMTString() + "</pubDate>");
        s.push("<lastBuildDate>" + d.toGMTString() + "</lastBuildDate>");
        s.push("<docs>http://blogs.law.harvard.edu/tech/rss</docs>");
        s.push("<generator>TiddlyWiki " + version.major + "." + version.minor + "." + version.revision + "</generator>");
        // The body
        var tiddlers = store.getTiddlers("modified","excludeLists");
        var n = config.numRssItems > tiddlers.length ? 0 : tiddlers.length-config.numRssItems;
        for (var t=tiddlers.length-1; t>=n; t--)
                s.push(tiddlers[t].saveToRss(u));
        // And footer
        s.push("</channel>");
        s.push("</rss>");
        // Save it all
        return s.join("\n");
}

//--
//-- Filesystem code
//--

function convertUTF8ToUnicode(u)
{
        if(window.netscape == undefined)
                return manualConvertUTF8ToUnicode(u);
        else
                return mozConvertUTF8ToUnicode(u);
}

function manualConvertUTF8ToUnicode(utf)
{
        var uni = utf;
        var src = 0;
        var dst = 0;
        var b1, b2, b3;
        var c;
        while(src < utf.length) {
                b1 = utf.charCodeAt(src++);
                if(b1 < 0x80) {
                        dst++;
                } else if(b1 < 0xE0) {
                        b2 = utf.charCodeAt(src++);
                        c = String.fromCharCode(((b1 & 0x1F) << 6) | (b2 & 0x3F));
                        uni = uni.substring(0,dst++).concat(c,utf.substr(src));
                } else {
                        b2 = utf.charCodeAt(src++);
                        b3 = utf.charCodeAt(src++);
                        c = String.fromCharCode(((b1 & 0xF) << 12) | ((b2 & 0x3F) << 6) | (b3 & 0x3F));
                        uni = uni.substring(0,dst++).concat(c,utf.substr(src));
                }
        }
        return uni;
}

function mozConvertUTF8ToUnicode(u)
{
        try {
                netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
                var converter = Components.classes["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Components.interfaces.nsIScriptableUnicodeConverter);
                converter.charset = "UTF-8";
        } catch(ex) {
                return manualConvertUTF8ToUnicode(u);
        } // fallback
        var s = converter.ConvertToUnicode(u);
        var fin = converter.Finish();
        return (fin.length > 0) ? s+fin : s;
}

function convertUnicodeToUTF8(s)
{
        if(window.netscape == undefined)
                return manualConvertUnicodeToUTF8(s);
        else
                return mozConvertUnicodeToUTF8(s);
}

function manualConvertUnicodeToUTF8(s)
{
        var re = /[^\u0000-\u007F]/g ;
        return s.replace(re,function($0) {return "&#" + $0.charCodeAt(0).toString() + ";";});
}

function mozConvertUnicodeToUTF8(s)
{
        try {
                netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
                var converter = Components.classes["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Components.interfaces.nsIScriptableUnicodeConverter);
                converter.charset = "UTF-8";
        } catch(ex) {
                return manualConvertUnicodeToUTF8(s);
        } // fallback
        var u = converter.ConvertFromUnicode(s);
        var fin = converter.Finish();
        if(fin.length > 0)
                return u + fin;
        else
                return u;
}

function convertUriToUTF8(uri,charSet)
{
        if(window.netscape == undefined || charSet == undefined || charSet == "")
                return uri;
        try {
                netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
                var converter = Components.classes["@mozilla.org/intl/utf8converterservice;1"].getService(Components.interfaces.nsIUTF8ConverterService);
        } catch(ex) {
                return uri;
        }
        return converter.convertURISpecToUTF8(uri,charSet);
}

function saveFile(fileUrl,content)
{
        var r = null;
        if(!r)
                r = mozillaSaveFile(fileUrl,content);
        if(!r)
                r = ieSaveFile(fileUrl,content);
        if(!r)
                r = javaSaveFile(fileUrl,content);
        return r;
}

function loadFile(fileUrl)
{
        var r = null;
        if((r == null) || (r == false))
                r = mozillaLoadFile(fileUrl);
        if((r == null) || (r == false))
                r = ieLoadFile(fileUrl);
        if((r == null) || (r == false))
                r = javaLoadFile(fileUrl);
        return r;
}

// Returns null if it can't do it, false if there's an error, true if it saved OK
function ieSaveFile(filePath,content)
{
        try {
                var fso = new ActiveXObject("Scripting.FileSystemObject");
        } catch(ex) {
                return null;
        }
        var file = fso.OpenTextFile(filePath,2,-1,0);
        file.Write(content);
        file.Close();
        return true;
}

// Returns null if it can't do it, false if there's an error, or a string of the content if successful
function ieLoadFile(filePath)
{
        try {
                var fso = new ActiveXObject("Scripting.FileSystemObject");
                var file = fso.OpenTextFile(filePath,1);
                var content = file.ReadAll();
                file.Close();
        } catch(ex) {
                return null;
        }
        return content;
}

function ieCopyFile(dest,source)
{
        try {
                var fso = new ActiveXObject("Scripting.FileSystemObject");
                fso.GetFile(source).Copy(dest);
        } catch(ex) {
                return false;
        }
        return true;
}

// Returns null if it can't do it, false if there's an error, true if it saved OK
function mozillaSaveFile(filePath,content)
{
        if(window.Components) {
                try {
                        netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
                        var file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
                        file.initWithPath(filePath);
                        if(!file.exists())
                                file.create(0,0664);
                        var out = Components.classes["@mozilla.org/network/file-output-stream;1"].createInstance(Components.interfaces.nsIFileOutputStream);
                        out.init(file,0x20|0x02,00004,null);
                        out.write(content,content.length);
                        out.flush();
                        out.close();
                        return true;
                } catch(ex) {
                        return false;
                }
        }
        return null;
}

// Returns null if it can't do it, false if there's an error, or a string of the content if successful
function mozillaLoadFile(filePath)
{
        if(window.Components) {
                try {
                        netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
                        var file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
                        file.initWithPath(filePath);
                        if(!file.exists())
                                return null;
                        var inputStream = Components.classes["@mozilla.org/network/file-input-stream;1"].createInstance(Components.interfaces.nsIFileInputStream);
                        inputStream.init(file,0x01,00004,null);
                        var sInputStream = Components.classes["@mozilla.org/scriptableinputstream;1"].createInstance(Components.interfaces.nsIScriptableInputStream);
                        sInputStream.init(inputStream);
                        return sInputStream.read(sInputStream.available());
                } catch(ex) {
                        return false;
                }
        }
        return null;
}

function javaUrlToFilename(url)
{
        var f = "//localhost";
        if(url.indexOf(f) == 0)
                return url.substring(f.length);
        var i = url.indexOf(":");
        if(i > 0)
                return url.substring(i-1);
        return url;
}

function javaSaveFile(filePath,content)
{
        try {
                if(document.applets["TiddlySaver"])
                        return document.applets["TiddlySaver"].saveFile(javaUrlToFilename(filePath),"UTF-8",content);
        } catch(ex) {
        }
        try {
                var s = new java.io.PrintStream(new java.io.FileOutputStream(javaUrlToFilename(filePath)));
                s.print(content);
                s.close();
        } catch(ex) {
                return null;
        }
        return true;
}

function javaLoadFile(filePath)
{
        try {
                if(document.applets["TiddlySaver"])
                        return String(document.applets["TiddlySaver"].loadFile(javaUrlToFilename(filePath),"UTF-8"));
        } catch(ex) {
        }
        var content = [];
        try {
                var r = new java.io.BufferedReader(new java.io.FileReader(javaUrlToFilename(filePath)));
                var line;
                while((line = r.readLine()) != null)
                        content.push(new String(line));
                r.close();
        } catch(ex) {
                return null;
        }
        return content.join("\n");
}

//--
//-- Server adaptor for talking to static files
//--

function FileAdaptor()
{
        this.host = null;
        this.store = null;
        return this;
}

FileAdaptor.NotLoadedError = "TiddlyWiki file has not been loaded";
FileAdaptor.serverType = 'file';

// Open the specified host/server
FileAdaptor.prototype.openHost = function(host,context,userParams,callback)
{
        this.host = host;
        if(!context)
                context = {};
        context.adaptor = this;
        context.callback = callback;
        context.userParams = userParams;
        var ret = loadRemoteFile(host,FileAdaptor.openHostCallback,context);
        return typeof(ret) == "string" ? ret : true;
};

FileAdaptor.openHostCallback = function(status,context,responseText,url,xhr)
{
        var adaptor = context.adaptor;
        context.status = status;
        if(!status) {
                context.statusText = "Error reading file: " + xhr.statusText;
        } else {
                // Load the content into a TiddlyWiki() object
                adaptor.store = new TiddlyWiki();
                if(!adaptor.store.importTiddlyWiki(responseText))
                        context.statusText = config.messages.invalidFileError.format([url]);
        }
        context.callback(context,context.userParams);
};

// Gets the list of workspaces on a given server
FileAdaptor.prototype.getWorkspaceList = function(context,userParams,callback)
{
        if(!context)
                context = {};
        context.workspaces = [{title:"(default)"}];
        context.status = true;
        window.setTimeout(function() {callback(context,userParams);},10);
        return true;
};

// Open the specified workspace
FileAdaptor.prototype.openWorkspace = function(workspace,context,userParams,callback)
{
        if(!context)
                context = {};
        context.status = true;
        window.setTimeout(function() {callback(context,userParams);},10);
        return true;
};

// Gets the list of tiddlers within a given workspace
FileAdaptor.prototype.getTiddlerList = function(context,userParams,callback)
{
        if(!this.store)
                return FileAdaptor.NotLoadedError;
        if(!context)
                context = {};
        context.tiddlers = [];
        this.store.forEachTiddler(function(title,tiddler)
                {
                var t = new Tiddler(title);
                t.text = tiddler.text;
                t.modified = tiddler.modified;
                t.modifier = tiddler.modifier;
                t.fields['server.page.revision'] = tiddler.modified.convertToYYYYMMDDHHMM();
                t.tags = tiddler.tags;
                context.tiddlers.push(t);
                });
        context.status = true;
        window.setTimeout(function() {callback(context,userParams);},10);
        return true;
};

FileAdaptor.prototype.generateTiddlerInfo = function(tiddler)
{
        var info = {};
        info.uri = tiddler.fields['server.host'] + "#" + tiddler.title;
        return info;
};

// Retrieves a tiddler from a given workspace on a given server
FileAdaptor.prototype.getTiddler = function(title,context,userParams,callback)
{
        if(!this.store)
                return FileAdaptor.NotLoadedError;
        if(!context)
                context = {};
        context.tiddler = this.store.fetchTiddler(title);
        if(context.tiddler) {
                context.tiddler.fields['server.type'] = FileAdaptor.serverType;
                context.tiddler.fields['server.host'] = this.host;
                context.tiddler.fields['server.page.revision'] = context.tiddler.modified.convertToYYYYMMDDHHMM();
        }
        context.status = true;
        if(context.allowSynchronous) {
                context.isSynchronous = true;
                callback(context,userParams);
        } else {
                window.setTimeout(function() {callback(context,userParams);},10);
        }
        return true;
};

FileAdaptor.prototype.close = function()
{
        delete this.store;
        this.store = null;
};

config.adaptors[FileAdaptor.serverType] = FileAdaptor;

//--
//-- Remote HTTP requests
//--

function loadRemoteFile(url,callback,params)
{
        return doHttp("GET",url,null,null,null,null,callback,params,null);
}

// HTTP status codes
var httpStatus = {
        OK: 200,
        ContentCreated: 201,
        NoContent: 204,
        Unauthorized: 401,
        Forbidden: 403,
        NotFound: 404,
        MethodNotAllowed: 405
};

function doHttp(type,url,data,contentType,username,password,callback,params,headers)
{
        // Get an xhr object
        var x = getXMLHttpRequest();
        if(!x)
                return "Can't create XMLHttpRequest object";
        // Install callback
        x.onreadystatechange = function() {
                if (x.readyState == 4 && callback && (x.status !== undefined)) {
                        if([0, httpStatus.OK, httpStatus.ContentCreated, httpStatus.NoContent].contains(x.status))
                                callback(true,params,x.responseText,url,x);
                        else
                                callback(false,params,null,url,x);
                        x.onreadystatechange = function(){};
                        x = null;
                }
        };
        // Send request
        if(window.Components && window.netscape && window.netscape.security && document.location.protocol.indexOf("http") == -1)
                window.netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");
        try {
                url = url + (url.indexOf("?") < 0 ? "?" : "&") + "nocache=" + Math.random();
                x.open(type,url,true,username,password);
                if (data)
                        x.setRequestHeader("Content-Type", contentType ? contentType : "application/x-www-form-urlencoded");
                if (x.overrideMimeType)
                        x.setRequestHeader("Connection", "close");
                if(headers) {
                        for(n in headers)
                                x.setRequestHeader(n,headers[n]);
                }
                x.setRequestHeader("X-Requested-With", "TiddlyWiki " + version.major + "." + version.minor + "." + version.revision + (version.beta ? " (beta " + version.beta + ")" : ""));
                x.send(data);
        } catch (ex) {
                return exceptionText(ex);
        }
        return x;
}

function getXMLHttpRequest()
{
        try {
                var x = new XMLHttpRequest(); // Modern
        } catch(ex) {
                try {
                        x = new ActiveXObject("Msxml2.XMLHTTP"); // IE 6
                } catch (ex2) {
                        return null;
                }
        }
        return x;
}

//--
//-- TiddlyWiki-specific utility functions
//--

function createTiddlyButton(theParent,theText,theTooltip,theAction,theClass,theId,theAccessKey)
{
        var theButton = document.createElement("a");
        if(theAction) {
                theButton.onclick = theAction;
                theButton.setAttribute("href","javascript:;");
        }
        if(theTooltip)
                theButton.setAttribute("title",theTooltip);
        if(theText)
                theButton.appendChild(document.createTextNode(theText));
        if(theClass)
                theButton.className = theClass;
        else
                theButton.className = "button";
        if(theId)
                theButton.id = theId;
        if(theParent)
                theParent.appendChild(theButton);
        if(theAccessKey)
                theButton.setAttribute("accessKey",theAccessKey);
        return theButton;
}

function createTiddlyLink(place,title,includeText,theClass,isStatic,linkedFromTiddler,noToggle)
{
        var text = includeText ? title : null;
        var i = getTiddlyLinkInfo(title,theClass);
        var btn = isStatic ? createExternalLink(place,store.getTiddlerText("SiteUrl",null) + "#" + title) : createTiddlyButton(place,text,i.subTitle,onClickTiddlerLink,i.classes);
        btn.setAttribute("refresh","link");
        btn.setAttribute("tiddlyLink",title);
        if(noToggle)
                btn.setAttribute("noToggle","true");
        if(linkedFromTiddler) {
                var fields = linkedFromTiddler.getInheritedFields();
                btn.setAttribute("tiddlyFields",fields);
        }
        return btn;
}

function refreshTiddlyLink(e,title)
{
        var i = getTiddlyLinkInfo(title,e.className);
        e.className = i.classes;
        e.title = i.subTitle;
}

function getTiddlyLinkInfo(title,currClasses)
{
        var classes = currClasses ? currClasses.split(" ") : [];
        classes.pushUnique("tiddlyLink");
        var tiddler = store.fetchTiddler(title);
        var subTitle;
        if(tiddler) {
                subTitle = tiddler.getSubtitle();
                classes.pushUnique("tiddlyLinkExisting");
                classes.remove("tiddlyLinkNonExisting");
                classes.remove("shadow");
        } else {
                classes.remove("tiddlyLinkExisting");
                classes.pushUnique("tiddlyLinkNonExisting");
                if(store.isShadowTiddler(title)) {
                        subTitle = config.messages.shadowedTiddlerToolTip.format([title]);
                        classes.pushUnique("shadow");
                } else {
                        subTitle = config.messages.undefinedTiddlerToolTip.format([title]);
                        classes.remove("shadow");
                }
        }
        if(config.annotations[title])
                subTitle = config.annotations[title];
        return {classes: classes.join(" "),subTitle: subTitle};
}

function createExternalLink(place,url)
{
        var theLink = document.createElement("a");
        theLink.className = "externalLink";
        theLink.href = url;
        theLink.title = config.messages.externalLinkTooltip.format([url]);
        if(config.options.chkOpenInNewWindow)
                theLink.target = "_blank";
        place.appendChild(theLink);
        return theLink;
}

// Event handler for clicking on a tiddly link
function onClickTiddlerLink(e)
{
        if(!e) e = window.event;
        var theTarget = resolveTarget(e);
        var theLink = theTarget;
        var title = null;
        var fields = null;
        var noToggle = null;
        do {
                title = theLink.getAttribute("tiddlyLink");
                fields = theLink.getAttribute("tiddlyFields");
                noToggle = theLink.getAttribute("noToggle");
                theLink = theLink.parentNode;
        } while(title == null && theLink != null);
        if(!fields && !store.isShadowTiddler(title))
                fields = String.encodeHashMap(config.defaultCustomFields);
        if(title) {
                var toggling = e.metaKey || e.ctrlKey;
                if(config.options.chkToggleLinks)
                        toggling = !toggling;
                if(noToggle)
                        toggling = false;
                story.displayTiddler(theTarget,title,null,true,null,fields,toggling);
        }
        clearMessage();
        return false;
}

// Create a button for a tag with a popup listing all the tiddlers that it tags
function createTagButton(place,tag,excludeTiddler)
{
        var theTag = createTiddlyButton(place,tag,config.views.wikified.tag.tooltip.format([tag]),onClickTag);
        theTag.setAttribute("tag",tag);
        if(excludeTiddler)
                theTag.setAttribute("tiddler",excludeTiddler);
        return theTag;
}

// Event handler for clicking on a tiddler tag
function onClickTag(e)
{
        if(!e) var e = window.event;
        var theTarget = resolveTarget(e);
        var popup = Popup.create(this);
        var tag = this.getAttribute("tag");
        var title = this.getAttribute("tiddler");
        if(popup && tag) {
                var tagged = store.getTaggedTiddlers(tag);
                var titles = [];
                var li,r;
                for(r=0;r<tagged.length;r++) {
                        if(tagged[r].title != title)
                                titles.push(tagged[r].title);
                }
                var lingo = config.views.wikified.tag;
                if(titles.length > 0) {
                        var openAll = createTiddlyButton(createTiddlyElement(popup,"li"),lingo.openAllText.format([tag]),lingo.openAllTooltip,onClickTagOpenAll);
                        openAll.setAttribute("tag",tag);
                        createTiddlyElement(createTiddlyElement(popup,"li",null,"listBreak"),"div");
                        for(r=0; r<titles.length; r++) {
                                createTiddlyLink(createTiddlyElement(popup,"li"),titles[r],true);
                        }
                } else {
                        createTiddlyText(createTiddlyElement(popup,"li",null,"disabled"),lingo.popupNone.format([tag]));
                }
                createTiddlyElement(createTiddlyElement(popup,"li",null,"listBreak"),"div");
                var h = createTiddlyLink(createTiddlyElement(popup,"li"),tag,false);
                createTiddlyText(h,lingo.openTag.format([tag]));
        }
        Popup.show();
        e.cancelBubble = true;
        if(e.stopPropagation) e.stopPropagation();
        return false;
}

// Event handler for 'open all' on a tiddler popup
function onClickTagOpenAll(e)
{
        if(!e) var e = window.event;
        var tag = this.getAttribute("tag");
        var tagged = store.getTaggedTiddlers(tag);
        var titles = [];
        for(var t=0; t<tagged.length; t++)
                titles.push(tagged[t].title);
        story.displayTiddlers(this,titles);
        return false;
}

function onClickError(e)
{
        if(!e) var e = window.event;
        var popup = Popup.create(this);
        var lines = this.getAttribute("errorText").split("\n");
        for(var t=0; t<lines.length; t++)
                createTiddlyElement(popup,"li",null,null,lines[t]);
        Popup.show();
        e.cancelBubble = true;
        if(e.stopPropagation) e.stopPropagation();
        return false;
}

function createTiddlyDropDown(place,onchange,options,defaultValue)
{
        var sel = createTiddlyElement(place,"select");
        sel.onchange = onchange;
        for(var t=0; t<options.length; t++) {
                var e = createTiddlyElement(sel,"option",null,null,options[t].caption);
                e.value = options[t].name;
                if(options[t].name == defaultValue)
                        e.selected = true;
        }
        return sel;
}

function createTiddlyPopup(place,caption,tooltip,tiddler)
{
        if(tiddler.text) {
                createTiddlyLink(place,caption,true);
                var btn = createTiddlyButton(place,glyph("downArrow"),tooltip,onClickTiddlyPopup,"tiddlerPopupButton");
                btn.tiddler = tiddler;
        } else {
                createTiddlyText(place,caption);
        }
}

function onClickTiddlyPopup(e)
{
        var tiddler = this.tiddler;
        if(tiddler.text) {
                var popup = Popup.create(this,"div","popupTiddler");
                wikify(tiddler.text,popup,null,tiddler);
                Popup.show();
        }
        if(e) e.cancelBubble = true;
        if(e && e.stopPropagation) e.stopPropagation();
        return false;
}

function createTiddlyError(place,title,text)
{
        var btn = createTiddlyButton(place,title,null,onClickError,"errorButton");
        if(text) btn.setAttribute("errorText",text);
}

function merge(dst,src,preserveExisting)
{
        for(p in src) {
                if(!preserveExisting || dst[p] === undefined)
                        dst[p] = src[p];
        }
        return dst;
}

// Returns a string containing the description of an exception, optionally prepended by a message
function exceptionText(e,message)
{
        var s = e.description ? e.description : e.toString();
        return message ? "%0:\n%1".format([message,s]) : s;
}

// Displays an alert of an exception description with optional message
function showException(e,message)
{
        alert(exceptionText(e,message));
}

function alertAndThrow(m)
{
        alert(m);
        throw(m);
}

function glyph(name)
{
        var g = config.glyphs;
        var b = g.currBrowser;
        if(b == null) {
                b = 0;
                while(!g.browsers[b]() && b < g.browsers.length-1)
                        b++;
                g.currBrowser = b;
        }
        if(!g.codes[name])
                return "";
        return g.codes[name][b];
}
//-
//- Animation engine
//-

function Animator()
{
        this.running = 0; // Incremented at start of each animation, decremented afterwards. If zero, the interval timer is disabled
        this.timerID = 0; // ID of the timer used for animating
        this.animations = []; // List of animations in progress
        return this;
}

// Start animation engine
Animator.prototype.startAnimating = function() // Variable number of arguments
{
        for(var t=0; t<arguments.length; t++)
                this.animations.push(arguments[t]);
        if(this.running == 0) {
                var me = this;
                this.timerID = window.setInterval(function() {me.doAnimate(me);},10);
        }
        this.running += arguments.length;
};

// Perform an animation engine tick, calling each of the known animation modules
Animator.prototype.doAnimate = function(me)
{
        var a = 0;
        while(a < me.animations.length) {
                var animation = me.animations[a];
                if(animation.tick()) {
                        a++;
                } else {
                        me.animations.splice(a,1);
                        if(--me.running == 0)
                                window.clearInterval(me.timerID);
                }
        }
};

// Map a 0..1 value to 0..1, but slow down at the start and end
Animator.slowInSlowOut = function(progress)
{
        return(1-((Math.cos(progress * Math.PI)+1)/2));
};

//--
//-- Morpher animation
//--

// Animate a set of properties of an element
function Morpher(element,duration,properties,callback)
{
        this.element = element;
        this.duration = duration;
        this.properties = properties;
        this.startTime = new Date();
        this.endTime = Number(this.startTime) + duration;
        this.callback = callback;
        this.tick();
        return this;
}

Morpher.prototype.assignStyle = function(element,style,value)
{
        switch(style) {
                case "-tw-vertScroll":
                        window.scrollTo(findScrollX(),value);
                        break;
                case "-tw-horizScroll":
                        window.scrollTo(value,findScrollY());
                        break;
                default:
                        element.style[style] = value;
                        break;
        }
};

Morpher.prototype.stop = function()
{
        for(var t=0; t<this.properties.length; t++) {
                var p = this.properties[t];
                if(p.atEnd !== undefined) {
                        this.assignStyle(this.element,p.style,p.atEnd);
                }
        }
        if(this.callback)
                this.callback(this.element,this.properties);
};

Morpher.prototype.tick = function()
{
        var currTime = Number(new Date());
        progress = Animator.slowInSlowOut(Math.min(1,(currTime-this.startTime)/this.duration));
        for(var t=0; t<this.properties.length; t++) {
                var p = this.properties[t];
                if(p.start !== undefined && p.end !== undefined) {
                        var template = p.template ? p.template : "%0";
                        switch(p.format) {
                                case undefined:
                                case "style":
                                        var v = p.start + (p.end-p.start) * progress;
                                        this.assignStyle(this.element,p.style,template.format([v]));
                                        break;
                                case "color":
                                        break;
                        }
                }
        }
        if(currTime >= this.endTime) {
                this.stop();
                return false;
        }
        return true;
};

//--
//-- Zoomer animation
//--

function Zoomer(text,startElement,targetElement,unused)
{
        var e = createTiddlyElement(document.body,"div",null,"zoomer");
        createTiddlyElement(e,"div",null,null,text);
        var winWidth = findWindowWidth();
        var winHeight = findWindowHeight();
        var p = [
                {style: 'left', start: findPosX(startElement), end: findPosX(targetElement), template: '%0px'},
                {style: 'top', start: findPosY(startElement), end: findPosY(targetElement), template: '%0px'},
                {style: 'width', start: Math.min(startElement.scrollWidth,winWidth), end: Math.min(targetElement.scrollWidth,winWidth), template: '%0px', atEnd: 'auto'},
                {style: 'height', start: Math.min(startElement.scrollHeight,winHeight), end: Math.min(targetElement.scrollHeight,winHeight), template: '%0px', atEnd: 'auto'},
                {style: 'fontSize', start: 8, end: 24, template: '%0pt'}
        ];
        var c = function(element,properties) {removeNode(element);};
        return new Morpher(e,config.animDuration,p,c);
}

//--
//-- Scroller animation
//--

function Scroller(targetElement,unused)
{
        var p = [
                {style: '-tw-vertScroll', start: findScrollY(), end: ensureVisible(targetElement)}
        ];
        return new Morpher(targetElement,config.animDuration,p);
}

//--
//-- Slider animation
//--

// deleteMode - "none", "all" [delete target element and it's children], [only] "children" [but not the target element]
function Slider(element,opening,unused,deleteMode)
{
        element.style.overflow = 'hidden';
        if(opening)
                element.style.height = '0px'; // Resolves a Firefox flashing bug
        element.style.display = 'block';
        var left = findPosX(element);
        var width = element.scrollWidth;
        var height = element.scrollHeight;
        var winWidth = findWindowWidth();
        var p = [];
        var c = null;
        if(opening) {
                p.push({style: 'height', start: 0, end: height, template: '%0px', atEnd: 'auto'});
                p.push({style: 'opacity', start: 0, end: 1, template: '%0'});
                p.push({style: 'filter', start: 0, end: 100, template: 'alpha(opacity:%0)'});
        } else {
                p.push({style: 'height', start: height, end: 0, template: '%0px'});
                p.push({style: 'display', atEnd: 'none'});
                p.push({style: 'opacity', start: 1, end: 0, template: '%0'});
                p.push({style: 'filter', start: 100, end: 0, template: 'alpha(opacity:%0)'});
                switch(deleteMode) {
                        case "all":
                                c = function(element,properties) {removeNode(element);};
                                break;
                        case "children":
                                c = function(element,properties) {removeChildren(element);};
                                break;
                }
        }
        return new Morpher(element,config.animDuration,p,c);
}

//--
//-- Popup menu
//--

var Popup = {
        stack: [] // Array of objects with members root: and popup:
        };

Popup.create = function(root,elem,theClass)
{
        Popup.remove();
        var popup = createTiddlyElement(document.body,elem ? elem : "ol","popup",theClass ? theClass : "popup");
        Popup.stack.push({root: root, popup: popup});
        return popup;
};

Popup.onDocumentClick = function(e)
{
        if (!e) var e = window.event;
        var target = resolveTarget(e);
        if(e.eventPhase == undefined)
                Popup.remove();
        else if(e.eventPhase == Event.BUBBLING_PHASE || e.eventPhase == Event.AT_TARGET)
                Popup.remove();
        return true;
};

Popup.show = function(unused1,unused2)
{
        var curr = Popup.stack[Popup.stack.length-1];
        var rootLeft = findPosX(curr.root);
        var rootTop = findPosY(curr.root);
        var rootHeight = curr.root.offsetHeight;
        var popupLeft = rootLeft;
        var popupTop = rootTop + rootHeight;
        var winWidth = findWindowWidth();
        if(curr.popup.offsetWidth > winWidth*0.75)
                curr.popup.style.width = winWidth*0.75 + "px";
        var popupWidth = curr.popup.offsetWidth;
        if(popupLeft + popupWidth > winWidth)
                popupLeft = winWidth - popupWidth;
        curr.popup.style.left = popupLeft + "px";
        curr.popup.style.top = popupTop + "px";
        curr.popup.style.display = "block";
        addClass(curr.root,"highlight");
        if(config.options.chkAnimate && anim && typeof Scroller == "function")
                anim.startAnimating(new Scroller(curr.popup));
        else
                window.scrollTo(0,ensureVisible(curr.popup));
};

Popup.remove = function()
{
        if(Popup.stack.length > 0) {
                Popup.removeFrom(0);
        }
};

Popup.removeFrom = function(from)
{
        for(var t=Popup.stack.length-1; t>=from; t--) {
                var p = Popup.stack[t];
                removeClass(p.root,"highlight");
                removeNode(p.popup);
        }
        Popup.stack = Popup.stack.slice(0,from);
};

//--
//-- Wizard support
//--

function Wizard(elem)
{
        if(elem) {
                this.formElem = findRelated(elem,"wizard","className");
                this.bodyElem = findRelated(this.formElem.firstChild,"wizardBody","className","nextSibling");
                this.footElem = findRelated(this.formElem.firstChild,"wizardFooter","className","nextSibling");
        } else {
                this.formElem = null;
                this.bodyElem = null;
                this.footElem = null;
        }
}

Wizard.prototype.setValue = function(name,value)
{
        if(this.formElem)
                this.formElem[name] = value;
};

Wizard.prototype.getValue = function(name)
{
        return this.formElem ? this.formElem[name] : null;
};

Wizard.prototype.createWizard = function(place,title)
{
        this.formElem = createTiddlyElement(place,"form",null,"wizard");
        createTiddlyElement(this.formElem,"h1",null,null,title);
        this.bodyElem = createTiddlyElement(this.formElem,"div",null,"wizardBody");
        this.footElem = createTiddlyElement(this.formElem,"div",null,"wizardFooter");
};

Wizard.prototype.clear = function()
{
        removeChildren(this.bodyElem);
};

Wizard.prototype.setButtons = function(buttonInfo,status)
{
        removeChildren(this.footElem);
        for(var t=0; t<buttonInfo.length; t++) {
                createTiddlyButton(this.footElem,buttonInfo[t].caption,buttonInfo[t].tooltip,buttonInfo[t].onClick);
                insertSpacer(this.footElem);
                }
        if(typeof status == "string") {
                createTiddlyElement(this.footElem,"span",null,"status",status);
        }
};

Wizard.prototype.addStep = function(stepTitle,html)
{
        removeChildren(this.bodyElem);
        var w = createTiddlyElement(this.bodyElem,"div");
        createTiddlyElement(w,"h2",null,null,stepTitle);
        var step = createTiddlyElement(w,"div",null,"wizardStep");
        step.innerHTML = html;
        applyHtmlMacros(step,tiddler);
};

Wizard.prototype.getElement = function(name)
{
        return this.formElem.elements[name];
};

//--
//-- ListView gadget
//--

var ListView = {};

// Create a listview
ListView.create = function(place,listObject,listTemplate,callback,className)
{
        var table = createTiddlyElement(place,"table",null,className ? className : "listView");
        var thead = createTiddlyElement(table,"thead");
        var r = createTiddlyElement(thead,"tr");
        for(var t=0; t<listTemplate.columns.length; t++) {
                var columnTemplate = listTemplate.columns[t];
                var c = createTiddlyElement(r,"th");
                var colType = ListView.columnTypes[columnTemplate.type];
                if(colType && colType.createHeader)
                        colType.createHeader(c,columnTemplate,t);
        }
        var tbody = createTiddlyElement(table,"tbody");
        for(var rc=0; rc<listObject.length; rc++) {
                rowObject = listObject[rc];
                r = createTiddlyElement(tbody,"tr");
                for(c=0; c<listTemplate.rowClasses.length; c++) {
                        if(rowObject[listTemplate.rowClasses[c].field])
                                addClass(r,listTemplate.rowClasses[c].className);
                }
                rowObject.rowElement = r;
                rowObject.colElements = {};
                for(var cc=0; cc<listTemplate.columns.length; cc++) {
                        c = createTiddlyElement(r,"td");
                        columnTemplate = listTemplate.columns[cc];
                        var field = columnTemplate.field;
                        colType = ListView.columnTypes[columnTemplate.type];
                        if(colType && colType.createItem)
                                colType.createItem(c,rowObject,field,columnTemplate,cc,rc);
                        rowObject.colElements[field] = c;
                }
        }
        if(callback && listTemplate.actions)
                createTiddlyDropDown(place,ListView.getCommandHandler(callback),listTemplate.actions);
        if(callback && listTemplate.buttons) {
                for(t=0; t<listTemplate.buttons.length; t++) {
                        var a = listTemplate.buttons[t];
                        if(a && a.name != "")
                                createTiddlyButton(place,a.caption,null,ListView.getCommandHandler(callback,a.name,a.allowEmptySelection));
                }
        }
        return table;
};

ListView.getCommandHandler = function(callback,name,allowEmptySelection)
{
        return function(e) {
                var view = findRelated(this,"TABLE",null,"previousSibling");
                var tiddlers = [];
                ListView.forEachSelector(view,function(e,rowName) {
                                        if(e.checked)
                                                tiddlers.push(rowName);
                                        });
                if(tiddlers.length == 0 && !allowEmptySelection) {
                        alert(config.messages.nothingSelected);
                } else {
                        if(this.nodeName.toLowerCase() == "select") {
                                callback(view,this.value,tiddlers);
                                this.selectedIndex = 0;
                        } else {
                                callback(view,name,tiddlers);
                        }
                }
        };
};

// Invoke a callback for each selector checkbox in the listview
ListView.forEachSelector = function(view,callback)
{
        var checkboxes = view.getElementsByTagName("input");
        var hadOne = false;
        for(var t=0; t<checkboxes.length; t++) {
                var cb = checkboxes[t];
                if(cb.getAttribute("type") == "checkbox") {
                        var rn = cb.getAttribute("rowName");
                        if(rn) {
                                callback(cb,rn);
                                hadOne = true;
                        }
                }
        }
        return hadOne;
};

ListView.getSelectedRows = function(view)
{
        var rowNames = [];
        ListView.forEachSelector(view,function(e,rowName) {
                                if(e.checked)
                                        rowNames.push(rowName);
                                });
        return rowNames;
};

ListView.columnTypes = {};

ListView.columnTypes.String = {
        createHeader: function(place,columnTemplate,col)
                {
                        createTiddlyText(place,columnTemplate.title);
                },
        createItem: function(place,listObject,field,columnTemplate,col,row)
                {
                        var v = listObject[field];
                        if(v != undefined)
                                createTiddlyText(place,v);
                }
};

ListView.columnTypes.WikiText = {
        createHeader: ListView.columnTypes.String.createHeader,
        createItem: function(place,listObject,field,columnTemplate,col,row)
                {
                        var v = listObject[field];
                        if(v != undefined)
                                wikify(v,place,null,null);
                }
};

ListView.columnTypes.Tiddler = {
        createHeader: ListView.columnTypes.String.createHeader,
        createItem: function(place,listObject,field,columnTemplate,col,row)
                {
                        var v = listObject[field];
                        if(v != undefined && v.title)
                                createTiddlyPopup(place,v.title,config.messages.listView.tiddlerTooltip,v);
                }
};

ListView.columnTypes.Size = {
        createHeader: ListView.columnTypes.String.createHeader,
        createItem: function(place,listObject,field,columnTemplate,col,row)
                {
                        var v = listObject[field];
                        if(v != undefined) {
                                var t = 0;
                                while(t<config.messages.sizeTemplates.length-1 && v<config.messages.sizeTemplates[t].unit)
                                        t++;
                                createTiddlyText(place,config.messages.sizeTemplates[t].template.format([Math.round(v/config.messages.sizeTemplates[t].unit)]));
                        }
                }
};

ListView.columnTypes.Link = {
        createHeader: ListView.columnTypes.String.createHeader,
        createItem: function(place,listObject,field,columnTemplate,col,row)
                {
                        var v = listObject[field];
                        var c = columnTemplate.text;
                        if(v != undefined)
                                createTiddlyText(createExternalLink(place,v),c ? c : v);
                }
};

ListView.columnTypes.Date = {
        createHeader: ListView.columnTypes.String.createHeader,
        createItem: function(place,listObject,field,columnTemplate,col,row)
                {
                        var v = listObject[field];
                        if(v != undefined)
                                createTiddlyText(place,v.formatString(columnTemplate.dateFormat));
                }
};

ListView.columnTypes.StringList = {
        createHeader: ListView.columnTypes.String.createHeader,
        createItem: function(place,listObject,field,columnTemplate,col,row)
                {
                        var v = listObject[field];
                        if(v != undefined) {
                                for(var t=0; t<v.length; t++) {
                                        createTiddlyText(place,v[t]);
                                        createTiddlyElement(place,"br");
                                }
                        }
                }
};

ListView.columnTypes.Selector = {
        createHeader: function(place,columnTemplate,col)
                {
                        createTiddlyCheckbox(place,null,false,this.onHeaderChange);
                },
        createItem: function(place,listObject,field,columnTemplate,col,row)
                {
                        var e = createTiddlyCheckbox(place,null,listObject[field],null);
                        e.setAttribute("rowName",listObject[columnTemplate.rowName]);
                },
        onHeaderChange: function(e)
                {
                        var state = this.checked;
                        var view = findRelated(this,"TABLE");
                        if(!view)
                                return;
                        ListView.forEachSelector(view,function(e,rowName) {
                                                                e.checked = state;
                                                        });
                }
};

ListView.columnTypes.Tags = {
        createHeader: ListView.columnTypes.String.createHeader,
        createItem: function(place,listObject,field,columnTemplate,col,row)
                {
                        var tags = listObject[field];
                        createTiddlyText(place,String.encodeTiddlyLinkList(tags));
                }
};

ListView.columnTypes.Boolean = {
        createHeader: ListView.columnTypes.String.createHeader,
        createItem: function(place,listObject,field,columnTemplate,col,row)
                {
                        if(listObject[field] == true)
                                createTiddlyText(place,columnTemplate.trueText);
                        if(listObject[field] == false)
                                createTiddlyText(place,columnTemplate.falseText);
                }
};

ListView.columnTypes.TagCheckbox = {
        createHeader: ListView.columnTypes.String.createHeader,
        createItem: function(place,listObject,field,columnTemplate,col,row)
                {
                        var e = createTiddlyCheckbox(place,null,listObject[field],this.onChange);
                        e.setAttribute("tiddler",listObject.title);
                        e.setAttribute("tag",columnTemplate.tag);
                },
        onChange : function(e)
                {
                        var tag = this.getAttribute("tag");
                        var tiddler = this.getAttribute("tiddler");
                        store.setTiddlerTag(tiddler,this.checked,tag);
                }
};

ListView.columnTypes.TiddlerLink = {
        createHeader: ListView.columnTypes.String.createHeader,
        createItem: function(place,listObject,field,columnTemplate,col,row)
                {
                        var v = listObject[field];
                        if(v != undefined) {
                                var link = createTiddlyLink(place,listObject[columnTemplate.tiddlerLink],false,null);
                                createTiddlyText(link,listObject[field]);
                        }
                }
};

//--
//-- Augmented methods for the JavaScript Number(), Array(), String() and Date() objects
//--

// Clamp a number to a range
Number.prototype.clamp = function(min,max)
{
        var c = this;
        if(c < min)
                c = min;
        if(c > max)
                c = max;
        return c;
};

// Add indexOf function if browser does not support it
if(!Array.indexOf) {
Array.prototype.indexOf = function(item,from)
{
        if(!from)
                from = 0;
        for(var i=from; i<this.length; i++) {
                if(this[i] === item)
                        return i;
        }
        return -1;
};}

// Find an entry in a given field of the members of an array
Array.prototype.findByField = function(field,value)
{
        for(var t=0; t<this.length; t++) {
                if(this[t][field] == value)
                        return t;
        }
        return null;
};

// Return whether an entry exists in an array
Array.prototype.contains = function(item)
{
        return this.indexOf(item) != -1;
};

// Adds, removes or toggles a particular value within an array
//  value - value to add
//  mode - +1 to add value, -1 to remove value, 0 to toggle it
Array.prototype.setItem = function(value,mode)
{
        var p = this.indexOf(value);
        if(mode == 0)
                mode = (p == -1) ? +1 : -1;
        if(mode == +1) {
                if(p == -1)
                        this.push(value);
        } else if(mode == -1) {
                if(p != -1)
                        this.splice(p,1);
        }
};

// Return whether one of a list of values exists in an array
Array.prototype.containsAny = function(items)
{
        for(var i=0; i<items.length; i++) {
                if (this.indexOf(items[i]) != -1)
                        return true;
        }
        return false;
};

// Return whether all of a list of values exists in an array
Array.prototype.containsAll = function(items)
{
        for (var i = 0; i<items.length; i++) {
                if (this.indexOf(items[i]) == -1)
                        return false;
        }
        return true;
};

// Push a new value into an array only if it is not already present in the array. If the optional unique parameter is false, it reverts to a normal push
Array.prototype.pushUnique = function(item,unique)
{
        if(unique === false) {
                this.push(item);
        } else {
                if(this.indexOf(item) == -1)
                        this.push(item);
        }
};

Array.prototype.remove = function(item)
{
        var p = this.indexOf(item);
        if(p != -1)
                this.splice(p,1);
};

// Get characters from the right end of a string
String.prototype.right = function(n)
{
        return n < this.length ? this.slice(this.length-n) : this;
};

// Trim whitespace from both ends of a string
String.prototype.trim = function()
{
        return this.replace(/^\s*|\s*$/g,"");
};

// Convert a string from a CSS style property name to a JavaScript style name ("background-color" -> "backgroundColor")
String.prototype.unDash = function()
{
        var s = this.split("-");
        if(s.length > 1) {
                for(var t=1; t<s.length; t++)
                        s[t] = s[t].substr(0,1).toUpperCase() + s[t].substr(1);
        }
        return s.join("");
};

// Substitute substrings from an array into a format string that includes '%1'-type specifiers
String.prototype.format = function(substrings)
{
        var subRegExp = /(?:%(\d+))/mg;
        var currPos = 0;
        var r = [];
        do {
                var match = subRegExp.exec(this);
                if(match && match[1]) {
                        if(match.index > currPos)
                                r.push(this.substring(currPos,match.index));
                        r.push(substrings[parseInt(match[1])]);
                        currPos = subRegExp.lastIndex;
                }
        } while(match);
        if(currPos < this.length)
                r.push(this.substring(currPos,this.length));
        return r.join("");
};

// Escape any special RegExp characters with that character preceded by a backslash
String.prototype.escapeRegExp = function()
{
        var s = "\\^$*+?()=!|,{}[].";
        var c = this;
        for(var t=0; t<s.length; t++)
                c = c.replace(new RegExp("\\" + s.substr(t,1),"g"),"\\" + s.substr(t,1));
        return c;
};

// Convert "\" to "\s", newlines to "\n" (and remove carriage returns)
String.prototype.escapeLineBreaks = function()
{
        return this.replace(/\\/mg,"\\s").replace(/\n/mg,"\\n").replace(/\r/mg,"");
};

// Convert "\n" to newlines, "\b" to " ", "\s" to "\" (and remove carriage returns)
String.prototype.unescapeLineBreaks = function()
{
        return this.replace(/\\n/mg,"\n").replace(/\\b/mg," ").replace(/\\s/mg,"\\").replace(/\r/mg,"");
};

// Convert & to "&amp;", < to "&lt;", > to "&gt;" and " to "&quot;"
String.prototype.htmlEncode = function()
{
        return this.replace(/&/mg,"&amp;").replace(/</mg,"&lt;").replace(/>/mg,"&gt;").replace(/\"/mg,"&quot;");
};

// Convert "&amp;" to &, "&lt;" to <, "&gt;" to > and "&quot;" to "
String.prototype.htmlDecode = function()
{
        return this.replace(/&amp;/mg,"&").replace(/&lt;/mg,"<").replace(/&gt;/mg,">").replace(/&quot;/mg,"\"");
};

// Convert a string to it's JSON representation by encoding control characters, double quotes and backslash. See json.org
String.prototype.toJSONString = function()
{
        var m = {
                '\b': '\\b',
                '\f': '\\f',
                '\n': '\\n',
                '\r': '\\r',
                '\t': '\\t',
                '"' : '\\"',
                '\\': '\\\\'
                };
        var replaceFn = function(a,b) {
                var c = m[b];
                if(c)
                        return c;
                c = b.charCodeAt();
                return '\\u00' + Math.floor(c / 16).toString(16) + (c % 16).toString(16);
                };
        if(/["\\\x00-\x1f]/.test(this))
                return '"' + this.replace(/([\x00-\x1f\\"])/g,replaceFn) + '"';
        return '"' + this + '"';
};

// Parse a space-separated string of name:value parameters
// The result is an array of objects:
//   result[0] = object with a member for each parameter name, value of that member being an array of values
//   result[1..n] = one object for each parameter, with 'name' and 'value' members
String.prototype.parseParams = function(defaultName,defaultValue,allowEval,noNames,cascadeDefaults)
{
        var parseToken = function(match,p) {
                var n;
                if(match[p]) // Double quoted
                        n = match[p];
                else if(match[p+1]) // Single quoted
                        n = match[p+1];
                else if(match[p+2]) // Double-square-bracket quoted
                        n = match[p+2];
                else if(match[p+3]) // Double-brace quoted
                        try {
                                n = match[p+3];
                                if(allowEval)
                                        n = window.eval(n);
                        } catch(ex) {
                                throw "Unable to evaluate {{" + match[p+3] + "}}: " + exceptionText(ex);
                        }
                else if(match[p+4]) // Unquoted
                        n = match[p+4];
                else if(match[p+5]) // empty quote
                        n = "";
                return n;
        };
        var r = [{}];
        var dblQuote = "(?:\"((?:(?:\\\\\")|[^\"])+)\")";
        var sngQuote = "(?:'((?:(?:\\\\\')|[^'])+)')";
        var dblSquare = "(?:\\[\\[((?:\\s|\\S)*?)\\]\\])";
        var dblBrace = "(?:\\{\\{((?:\\s|\\S)*?)\\}\\})";
        var unQuoted = noNames ? "([^\"'\\s]\\S*)" : "([^\"':\\s][^\\s:]*)";
        var emptyQuote = "((?:\"\")|(?:''))";
        var skipSpace = "(?:\\s*)";
        var token = "(?:" + dblQuote + "|" + sngQuote + "|" + dblSquare + "|" + dblBrace + "|" + unQuoted + "|" + emptyQuote + ")";
        var re = noNames ? new RegExp(token,"mg") : new RegExp(skipSpace + token + skipSpace + "(?:(\\:)" + skipSpace + token + ")?","mg");
        var params = [];
        do {
                var match = re.exec(this);
                if(match) {
                        var n = parseToken(match,1);
                        if(noNames) {
                                r.push({name:"",value:n});
                        } else {
                                var v = parseToken(match,8);
                                if(v == null && defaultName) {
                                        v = n;
                                        n = defaultName;
                                } else if(v == null && defaultValue) {
                                        v = defaultValue;
                                }
                                r.push({name:n,value:v});
                                if(cascadeDefaults) {
                                        defaultName = n;
                                        defaultValue = v;
                                }
                        }
                }
        } while(match);
        // Summarise parameters into first element
        for(var t=1; t<r.length; t++) {
                if(r[0][r[t].name])
                        r[0][r[t].name].push(r[t].value);
                else
                        r[0][r[t].name] = [r[t].value];
        }
        return r;
};

// Process a string list of macro parameters into an array. Parameters can be quoted with "", '',
// [[]], {{ }} or left unquoted (and therefore space-separated). Double-braces {{}} results in
// an *evaluated* parameter: e.g. {{config.options.txtUserName}} results in the current user's name.
String.prototype.readMacroParams = function()
{
        var p = this.parseParams("list",null,true,true);
        var n = [];
        for(var t=1; t<p.length; t++)
                n.push(p[t].value);
        return n;
};

// Process a string list of unique tiddler names into an array. Tiddler names that have spaces in them must be [[bracketed]]
String.prototype.readBracketedList = function(unique)
{
        var p = this.parseParams("list",null,false,true);
        var n = [];
        for(var t=1; t<p.length; t++)
                n.pushUnique(p[t].value,unique);
        return n;
};

// Returns array with start and end index of chunk between given start and end marker, or undefined.
String.prototype.getChunkRange = function(start,end) 
{
        var s = this.indexOf(start);
        if(s != -1) {
                s += start.length;
                var e = this.indexOf(end,s);
                if(e != -1)
                        return [s,e];
        }
};

// Replace a chunk of a string given start and end markers
String.prototype.replaceChunk = function(start,end,sub)
{
        var r = this.getChunkRange(start,end);
        return r ? this.substring(0,r[0]) + sub + this.substring(r[1]) : this;
};

// Returns a chunk of a string between start and end markers, or undefined
String.prototype.getChunk = function(start,end)
{
        var r = this.getChunkRange(start,end);
        if(r)
                return this.substring(r[0],r[1]);
};


// Static method to bracket a string with double square brackets if it contains a space
String.encodeTiddlyLink = function(title)
{
        return title.indexOf(" ") == -1 ? title : "[[" + title + "]]";
};

// Static method to encodeTiddlyLink for every item in an array and join them with spaces
String.encodeTiddlyLinkList = function(list)
{
        if(list) {
                var results = [];
                for(var t=0; t<list.length; t++)
                        results.push(String.encodeTiddlyLink(list[t]));
                return results.join(" ");
        } else {
                return "";
        }
};

// Convert a string as a sequence of name:"value" pairs into a hashmap
String.prototype.decodeHashMap = function()
{
        var fields = this.parseParams("anon","",false);
        var r = {};
        for(var t=1; t<fields.length; t++)
                r[fields[t].name] = fields[t].value;
        return r;
};

// Static method to encode a hashmap into a name:"value"... string
String.encodeHashMap = function(hashmap)
{
        var r = [];
        for(var t in hashmap)
                r.push(t + ':"' + hashmap[t] + '"');
        return r.join(" ");
};

// Static method to left-pad a string with 0s to a certain width
String.zeroPad = function(n,d)
{
        var s = n.toString();
        if(s.length < d)
                s = "000000000000000000000000000".substr(0,d-s.length) + s;
        return s;
};

String.prototype.startsWith = function(prefix) 
{
        return !prefix || this.substring(0,prefix.length) == prefix;
};

// Returns the first value of the given named parameter.
function getParam(params,name,defaultValue)
{
        if(!params)
                return defaultValue;
        var p = params[0][name];
        return p ? p[0] : defaultValue;
}

// Returns the first value of the given boolean named parameter.
function getFlag(params,name,defaultValue)
{
        return !!getParam(params,name,defaultValue);
}

// Substitute date components into a string
Date.prototype.formatString = function(template)
{
        var t = template.replace(/0hh12/g,String.zeroPad(this.getHours12(),2));
        t = t.replace(/hh12/g,this.getHours12());
        t = t.replace(/0hh/g,String.zeroPad(this.getHours(),2));
        t = t.replace(/hh/g,this.getHours());
        t = t.replace(/mmm/g,config.messages.dates.shortMonths[this.getMonth()]);
        t = t.replace(/0mm/g,String.zeroPad(this.getMinutes(),2));
        t = t.replace(/mm/g,this.getMinutes());
        t = t.replace(/0ss/g,String.zeroPad(this.getSeconds(),2));
        t = t.replace(/ss/g,this.getSeconds());
        t = t.replace(/[ap]m/g,this.getAmPm().toLowerCase());
        t = t.replace(/[AP]M/g,this.getAmPm().toUpperCase());
        t = t.replace(/wYYYY/g,this.getYearForWeekNo());
        t = t.replace(/wYY/g,String.zeroPad(this.getYearForWeekNo()-2000,2));
        t = t.replace(/YYYY/g,this.getFullYear());
        t = t.replace(/YY/g,String.zeroPad(this.getFullYear()-2000,2));
        t = t.replace(/MMM/g,config.messages.dates.months[this.getMonth()]);
        t = t.replace(/0MM/g,String.zeroPad(this.getMonth()+1,2));
        t = t.replace(/MM/g,this.getMonth()+1);
        t = t.replace(/0WW/g,String.zeroPad(this.getWeek(),2));
        t = t.replace(/WW/g,this.getWeek());
        t = t.replace(/DDD/g,config.messages.dates.days[this.getDay()]);
        t = t.replace(/ddd/g,config.messages.dates.shortDays[this.getDay()]);
        t = t.replace(/0DD/g,String.zeroPad(this.getDate(),2));
        t = t.replace(/DDth/g,this.getDate()+this.daySuffix());
        t = t.replace(/DD/g,this.getDate());
        return t;
};

Date.prototype.getWeek = function()
{
        var dt = new Date(this.getTime());
        var d = dt.getDay();
        if (d==0) d=7;// JavaScript Sun=0, ISO Sun=7
        dt.setTime(dt.getTime()+(4-d)*86400000);// shift day to Thurs of same week to calculate weekNo
        var n = Math.floor((dt.getTime()-new Date(dt.getFullYear(),0,1)+3600000)/86400000); 
        return Math.floor(n/7)+1;
};

Date.prototype.getYearForWeekNo = function()
{
        var dt = new Date(this.getTime());
        var d = dt.getDay();
        if (d==0) d=7;// JavaScript Sun=0, ISO Sun=7
        dt.setTime(dt.getTime()+(4-d)*86400000);// shift day to Thurs of same week
        return dt.getFullYear();
};

Date.prototype.getHours12 = function()
{
        var h = this.getHours();
        return h > 12 ? h-12 : ( h > 0 ? h : 12 );
};

Date.prototype.getAmPm = function()
{
        return this.getHours() >= 12 ? config.messages.dates.pm : config.messages.dates.am;
};

Date.prototype.daySuffix = function()
{
        return config.messages.dates.daySuffixes[this.getDate()-1];
};

// Convert a date to local YYYYMMDDHHMM string format
Date.prototype.convertToLocalYYYYMMDDHHMM = function()
{
        return String.zeroPad(this.getFullYear(),4) + String.zeroPad(this.getMonth()+1,2) + String.zeroPad(this.getDate(),2) + String.zeroPad(this.getHours(),2) + String.zeroPad(this.getMinutes(),2);
};

// Convert a date to UTC YYYYMMDDHHMM string format
Date.prototype.convertToYYYYMMDDHHMM = function()
{
        return String.zeroPad(this.getUTCFullYear(),4) + String.zeroPad(this.getUTCMonth()+1,2) + String.zeroPad(this.getUTCDate(),2) + String.zeroPad(this.getUTCHours(),2) + String.zeroPad(this.getUTCMinutes(),2);
};

// Convert a date to UTC YYYYMMDD.HHMMSSMMM string format
Date.prototype.convertToYYYYMMDDHHMMSSMMM = function()
{
        return String.zeroPad(this.getUTCFullYear(),4) + String.zeroPad(this.getUTCMonth()+1,2) + String.zeroPad(this.getUTCDate(),2) + "." + String.zeroPad(this.getUTCHours(),2) + String.zeroPad(this.getUTCMinutes(),2) + String.zeroPad(this.getUTCSeconds(),2) + String.zeroPad(this.getUTCMilliseconds(),4);
};

// Static method to create a date from a UTC YYYYMMDDHHMM format string
Date.convertFromYYYYMMDDHHMM = function(d)
{
        return new Date(Date.UTC(parseInt(d.substr(0,4),10),
                        parseInt(d.substr(4,2),10)-1,
                        parseInt(d.substr(6,2),10),
                        parseInt(d.substr(8,2),10),
                        parseInt(d.substr(10,2),10),0,0));
};

//--
//-- Crypto functions and associated conversion routines
//--

// Crypto "namespace"
function Crypto() {}

// Convert a string to an array of big-endian 32-bit words
Crypto.strToBe32s = function(str)
{
        var be = Array();
        var len = Math.floor(str.length/4);
        var i, j;
        for(i=0, j=0; i<len; i++, j+=4) {
                be[i] = ((str.charCodeAt(j)&0xff) << 24)|((str.charCodeAt(j+1)&0xff) << 16)|((str.charCodeAt(j+2)&0xff) << 8)|(str.charCodeAt(j+3)&0xff);
        }
        while (j<str.length) {
                be[j>>2] |= (str.charCodeAt(j)&0xff)<<(24-(j*8)%32);
                j++;
        }
        return be;
};

// Convert an array of big-endian 32-bit words to a string
Crypto.be32sToStr = function(be)
{
        var str = "";
        for(var i=0;i<be.length*32;i+=8)
                str += String.fromCharCode((be[i>>5]>>>(24-i%32)) & 0xff);
        return str;
};

// Convert an array of big-endian 32-bit words to a hex string
Crypto.be32sToHex = function(be)
{
        var hex = "0123456789ABCDEF";
        var str = "";
        for(var i=0;i<be.length*4;i++)
                str += hex.charAt((be[i>>2]>>((3-i%4)*8+4))&0xF) + hex.charAt((be[i>>2]>>((3-i%4)*8))&0xF);
        return str;
};

// Return, in hex, the SHA-1 hash of a string
Crypto.hexSha1Str = function(str)
{
        return Crypto.be32sToHex(Crypto.sha1Str(str));
};

// Return the SHA-1 hash of a string
Crypto.sha1Str = function(str)
{
        return Crypto.sha1(Crypto.strToBe32s(str),str.length);
};

// Calculate the SHA-1 hash of an array of blen bytes of big-endian 32-bit words
Crypto.sha1 = function(x,blen)
{
        // Add 32-bit integers, wrapping at 32 bits
        add32 = function(a,b)
        {
                var lsw = (a&0xFFFF)+(b&0xFFFF);
                var msw = (a>>16)+(b>>16)+(lsw>>16);
                return (msw<<16)|(lsw&0xFFFF);
        };
        // Add five 32-bit integers, wrapping at 32 bits
        add32x5 = function(a,b,c,d,e)
        {
                var lsw = (a&0xFFFF)+(b&0xFFFF)+(c&0xFFFF)+(d&0xFFFF)+(e&0xFFFF);
                var msw = (a>>16)+(b>>16)+(c>>16)+(d>>16)+(e>>16)+(lsw>>16);
                return (msw<<16)|(lsw&0xFFFF);
        };
        // Bitwise rotate left a 32-bit integer by 1 bit
        rol32 = function(n)
        {
                return (n>>>31)|(n<<1);
        };

        var len = blen*8;
        // Append padding so length in bits is 448 mod 512
        x[len>>5] |= 0x80 << (24-len%32);
        // Append length
        x[((len+64>>9)<<4)+15] = len;
        var w = Array(80);

        var k1 = 0x5A827999;
        var k2 = 0x6ED9EBA1;
        var k3 = 0x8F1BBCDC;
        var k4 = 0xCA62C1D6;

        var h0 = 0x67452301;
        var h1 = 0xEFCDAB89;
        var h2 = 0x98BADCFE;
        var h3 = 0x10325476;
        var h4 = 0xC3D2E1F0;

        for(var i=0;i<x.length;i+=16) {
                var j,t;
                var a = h0;
                var b = h1;
                var c = h2;
                var d = h3;
                var e = h4;
                for(j = 0;j<16;j++) {
                        w[j] = x[i+j];
                        t = add32x5(e,(a>>>27)|(a<<5),d^(b&(c^d)),w[j],k1);
                        e=d; d=c; c=(b>>>2)|(b<<30); b=a; a = t;
                }
                for(j=16;j<20;j++) {
                        w[j] = rol32(w[j-3]^w[j-8]^w[j-14]^w[j-16]);
                        t = add32x5(e,(a>>>27)|(a<<5),d^(b&(c^d)),w[j],k1);
                        e=d; d=c; c=(b>>>2)|(b<<30); b=a; a = t;
                }
                for(j=20;j<40;j++) {
                        w[j] = rol32(w[j-3]^w[j-8]^w[j-14]^w[j-16]);
                        t = add32x5(e,(a>>>27)|(a<<5),b^c^d,w[j],k2);
                        e=d; d=c; c=(b>>>2)|(b<<30); b=a; a = t;
                }
                for(j=40;j<60;j++) {
                        w[j] = rol32(w[j-3]^w[j-8]^w[j-14]^w[j-16]);
                        t = add32x5(e,(a>>>27)|(a<<5),(b&c)|(d&(b|c)),w[j],k3);
                        e=d; d=c; c=(b>>>2)|(b<<30); b=a; a = t;
                }
                for(j=60;j<80;j++) {
                        w[j] = rol32(w[j-3]^w[j-8]^w[j-14]^w[j-16]);
                        t = add32x5(e,(a>>>27)|(a<<5),b^c^d,w[j],k4);
                        e=d; d=c; c=(b>>>2)|(b<<30); b=a; a = t;
                }

                h0 = add32(h0,a);
                h1 = add32(h1,b);
                h2 = add32(h2,c);
                h3 = add32(h3,d);
                h4 = add32(h4,e);
        }
        return Array(h0,h1,h2,h3,h4);
};

//--
//-- RGB colour object
//--

// Construct an RGB colour object from a '#rrggbb', '#rgb' or 'rgb(n,n,n)' string or from separate r,g,b values
function RGB(r,g,b)
{
        this.r = 0;
        this.g = 0;
        this.b = 0;
        if(typeof r == "string") {
                if(r.substr(0,1) == "#") {
                        if(r.length == 7) {
                                this.r = parseInt(r.substr(1,2),16)/255;
                                this.g = parseInt(r.substr(3,2),16)/255;
                                this.b = parseInt(r.substr(5,2),16)/255;
                        } else {
                                this.r = parseInt(r.substr(1,1),16)/15;
                                this.g = parseInt(r.substr(2,1),16)/15;
                                this.b = parseInt(r.substr(3,1),16)/15;
                        }
                } else {
                        var rgbPattern = /rgb\s*\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)/;
                        var c = r.match(rgbPattern);
                        if(c) {
                                this.r = parseInt(c[1],10)/255;
                                this.g = parseInt(c[2],10)/255;
                                this.b = parseInt(c[3],10)/255;
                        }
                }
        } else {
                this.r = r;
                this.g = g;
                this.b = b;
        }
        return this;
}

// Mixes this colour with another in a specified proportion
// c = other colour to mix
// f = 0..1 where 0 is this colour and 1 is the new colour
// Returns an RGB object
RGB.prototype.mix = function(c,f)
{
        return new RGB(this.r + (c.r-this.r) * f,this.g + (c.g-this.g) * f,this.b + (c.b-this.b) * f);
};

// Return an rgb colour as a #rrggbb format hex string
RGB.prototype.toString = function()
{
        return "#" + ("0" + Math.floor(this.r.clamp(0,1) * 255).toString(16)).right(2) +
                                 ("0" + Math.floor(this.g.clamp(0,1) * 255).toString(16)).right(2) +
                                 ("0" + Math.floor(this.b.clamp(0,1) * 255).toString(16)).right(2);
};

//--
//-- DOM utilities - many derived from www.quirksmode.org
//--

function drawGradient(place,horiz,colours)
{
        for(var t=0; t<= 100; t+=2) {
                var bar = document.createElement("div");
                place.appendChild(bar);
                bar.style.position = "absolute";
                bar.style.left = horiz ? t + "%" : 0;
                bar.style.top = horiz ? 0 : t + "%";
                bar.style.width = horiz ? (101-t) + "%" : "100%";
                bar.style.height = horiz ? "100%" : (101-t) + "%";
                bar.style.zIndex = -1;
                var f = t/100;
                var p = f*(colours.length-1);
                bar.style.backgroundColor = colours[Math.floor(p)].mix(colours[Math.ceil(p)],p-Math.floor(p)).toString();
        }
}

function createTiddlyText(theParent,theText)
{
        return theParent.appendChild(document.createTextNode(theText));
}

function createTiddlyCheckbox(theParent,caption,checked,onChange)
{
        var cb = document.createElement("input");
        cb.setAttribute("type","checkbox");
        cb.onclick = onChange;
        theParent.appendChild(cb);
        cb.checked = checked;
        cb.className = "chkOptionInput";
        if(caption)
                wikify(caption,theParent);
        return cb;
}

function createTiddlyElement(theParent,theElement,theID,theClass,theText)
{
        var e = document.createElement(theElement);
        if(theClass != null)
                e.className = theClass;
        if(theID != null)
                e.setAttribute("id",theID);
        if(theText != null)
                e.appendChild(document.createTextNode(theText));
        if(theParent != null)
                theParent.appendChild(e);
        return e;
}

function addEvent(obj,type,fn)
{
        if(obj.attachEvent) {
                obj['e'+type+fn] = fn;
                obj[type+fn] = function(){obj['e'+type+fn](window.event);};
                obj.attachEvent('on'+type,obj[type+fn]);
        } else {
                obj.addEventListener(type,fn,false);
        }
}

function removeEvent(obj,type,fn)
{
        if(obj.detachEvent) {
                obj.detachEvent('on'+type,obj[type+fn]);
                obj[type+fn] = null;
        } else {
                obj.removeEventListener(type,fn,false);
        }
}

function addClass(e,theClass)
{
        var currClass = e.className.split(" ");
        if(currClass.indexOf(theClass) == -1)
                e.className += " " + theClass;
}

function removeClass(e,theClass)
{
        var currClass = e.className.split(" ");
        var i = currClass.indexOf(theClass);
        while(i != -1) {
                currClass.splice(i,1);
                i = currClass.indexOf(theClass);
        }
        e.className = currClass.join(" ");
}

function hasClass(e,theClass)
{
        if(e.className) {
                if(e.className.split(" ").indexOf(theClass) != -1)
                        return true;
        }
        return false;
}

// Find the closest relative with a given property value (property defaults to tagName, relative defaults to parentNode)
function findRelated(e,value,name,relative)
{
        name = name ? name : "tagName";
        relative = relative ? relative : "parentNode";
        if(name == "className") {
                while(e && !hasClass(e,value)) {
                        e = e[relative];
                }
        } else {
                while(e && e[name] != value) {
                        e = e[relative];
                }
        }
        return e;
}

// Resolve the target object of an event
function resolveTarget(e)
{
        var obj;
        if(e.target)
                obj = e.target;
        else if(e.srcElement)
                obj = e.srcElement;
        if(obj.nodeType == 3) // defeat Safari bug
                obj = obj.parentNode;
        return obj;
}

// Return the content of an element as plain text with no formatting
function getPlainText(e)
{
        var text = "";
        if(e.innerText)
                text = e.innerText;
        else if(e.textContent)
                text = e.textContent;
        return text;
}

// Get the scroll position for window.scrollTo necessary to scroll a given element into view
function ensureVisible(e)
{
        var posTop = findPosY(e);
        var posBot = posTop + e.offsetHeight;
        var winTop = findScrollY();
        var winHeight = findWindowHeight();
        var winBot = winTop + winHeight;
        if(posTop < winTop) {
                return posTop;
        } else if(posBot > winBot) {
                if(e.offsetHeight < winHeight)
                        return posTop - (winHeight - e.offsetHeight);
                else
                        return posTop;
        } else {
                return winTop;
        }
}

// Get the current width of the display window
function findWindowWidth()
{
        return window.innerWidth ? window.innerWidth : document.documentElement.clientWidth;
}

// Get the current height of the display window
function findWindowHeight()
{
        return window.innerHeight ? window.innerHeight : document.documentElement.clientHeight;
}

// Get the current horizontal page scroll position
function findScrollX()
{
        return window.scrollX ? window.scrollX : document.documentElement.scrollLeft;
}

// Get the current vertical page scroll position
function findScrollY()
{
        return window.scrollY ? window.scrollY : document.documentElement.scrollTop;
}

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

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

// Blur a particular element
function blurElement(e)
{
        if(e != null && e.focus && e.blur) {
                e.focus();
                e.blur();
        }
}

// Create a non-breaking space
function insertSpacer(place)
{
        var e = document.createTextNode(String.fromCharCode(160));
        if(place)
                place.appendChild(e);
        return e;
}

// Remove all children of a node
function removeChildren(e)
{
        while(e && e.hasChildNodes())
                removeNode(e.firstChild);
}

// Remove a node and all it's children
function removeNode(e)
{
        scrubNode(e);
        e.parentNode.removeChild(e);
}

// Remove any event handlers or non-primitve custom attributes
function scrubNode(e)
{
        var att = e.attributes;
        if(att) {
                for(var t=0; t<att.length; t++) {
                        var n = att[t].name;
                        if(n !== 'style' && (typeof e[n] === 'function' || (typeof e[n] === 'object' && e[n] != null))) {
                                try {
                                        e[n] = null;
                                } catch(ex) {
                                }
                        }
                }
        }
        var c = e.firstChild;
        while(c) {
                scrubNode(c);
                c = c.nextSibling;
        }
}

// Add a stylesheet, replacing any previous custom stylesheet
function setStylesheet(s,id,doc)
{
        if(!id)
                id = "customStyleSheet";
        if(!doc)
                doc = document;
        var n = doc.getElementById(id);
        if(doc.createStyleSheet) {
                // Test for IE's non-standard createStyleSheet method
                if(n)
                        n.parentNode.removeChild(n);
                // This failed without the &nbsp;
                doc.getElementsByTagName("head")[0].insertAdjacentHTML("beforeEnd","&nbsp;<style id='" + id + "'>" + s + "</style>");
        } else {
                if(n) {
                        n.replaceChild(doc.createTextNode(s),n.firstChild);
                } else {
                        n = doc.createElement("style");
                        n.type = "text/css";
                        n.id = id;
                        n.appendChild(doc.createTextNode(s));
                        doc.getElementsByTagName("head")[0].appendChild(n);
                }
        }
}

// Force the browser to do a document reflow when needed to workaround browser bugs
function forceReflow()
{
        if(config.browser.isGecko) {
                setStylesheet("body {top:-1em;margin-top:1em;}");
                setStylesheet("");
        }
}

// Replace the current selection of a textarea or text input and scroll it into view
function replaceSelection(e,text)
{
        if(e.setSelectionRange) {
                var oldpos = e.selectionStart;
                var isRange = e.selectionEnd > e.selectionStart;
                e.value = e.value.substr(0,e.selectionStart) + text + e.value.substr(e.selectionEnd);
                e.setSelectionRange(isRange ? oldpos : oldpos + text.length,oldpos + text.length);
                var linecount = e.value.split('\n').length;
                var thisline = e.value.substr(0,e.selectionStart).split('\n').length-1;
                e.scrollTop = Math.floor((thisline - e.rows / 2) * e.scrollHeight / linecount);
        } else if(document.selection) {
                var range = document.selection.createRange();
                if(range.parentElement() == e) {
                        var isCollapsed = range.text == "";
                        range.text = text;
                        if(!isCollapsed) {
                                range.moveStart('character', -text.length);
                                range.select();
                        }
                }
        }
}

// Returns the text of the given (text) node, possibly merging subsequent text nodes
function getNodeText(e)
{
        var t = ""; 
        while(e && e.nodeName == "#text") {
                t += e.nodeValue;
                e = e.nextSibling;
        }
        return t;
}

//--
//-- LoaderBase and SaverBase
//--

function LoaderBase() {}

LoaderBase.prototype.loadTiddler = function(store,node,tiddlers)
{
        var title = this.getTitle(store,node);
        if(title) {
                var tiddler = store.createTiddler(title);
                this.internalizeTiddler(store,tiddler,title,node);
                tiddlers.push(tiddler);
        }
};

LoaderBase.prototype.loadTiddlers = function(store,nodes)
{
        var tiddlers = [];
        for(var t = 0; t < nodes.length; t++) {
                try {
                        this.loadTiddler(store,nodes[t],tiddlers);
                } catch(ex) {
                        showException(ex,config.messages.tiddlerLoadError.format([this.getTitle(store,nodes[t])]));
                }
        }
        return tiddlers;
};

function SaverBase() {}

SaverBase.prototype.externalize = function(store)
{
        var results = [];
        var tiddlers = store.getTiddlers("title");
        for(var t = 0; t < tiddlers.length; t++)
                results.push(this.externalizeTiddler(store,tiddlers[t]));
        return results.join("\n");
};

//--
//-- TW21Loader (inherits from LoaderBase)
//--

function TW21Loader() {}

TW21Loader.prototype = new LoaderBase();

TW21Loader.prototype.getTitle = function(store,node)
{
        var title = null;
        if(node.getAttribute) {
                title = node.getAttribute("title");
                if(!title)
                        title = node.getAttribute("tiddler");
        }
        if(!title && node.id) {
                var lenPrefix = store.idPrefix.length;
                if (node.id.substr(0,lenPrefix) == store.idPrefix)
                        title = node.id.substr(lenPrefix);
        }
        return title;
};

TW21Loader.prototype.internalizeTiddler = function(store,tiddler,title,node)
{
        var e = node.firstChild;
        var text = null;
        if(node.getAttribute("tiddler")) {
                text = getNodeText(e).unescapeLineBreaks();
        } else {
                while(e.nodeName!="PRE" && e.nodeName!="pre") {
                        e = e.nextSibling;
                }
                text = e.innerHTML.replace(/\r/mg,"").htmlDecode();
        }
        var modifier = node.getAttribute("modifier");
        var c = node.getAttribute("created");
        var m = node.getAttribute("modified");
        var created = c ? Date.convertFromYYYYMMDDHHMM(c) : version.date;
        var modified = m ? Date.convertFromYYYYMMDDHHMM(m) : created;
        var tags = node.getAttribute("tags");
        var fields = {};
        var attrs = node.attributes;
        for(var i = attrs.length-1; i >= 0; i--) {
                var name = attrs[i].name;
                if (attrs[i].specified && !TiddlyWiki.isStandardField(name)) {
                        fields[name] = attrs[i].value.unescapeLineBreaks();
                }
        }
        tiddler.assign(title,text,modifier,modified,tags,created,fields);
        return tiddler;
};

//--
//-- TW21Saver (inherits from SaverBase)
//--

function TW21Saver() {}

TW21Saver.prototype = new SaverBase();

TW21Saver.prototype.externalizeTiddler = function(store,tiddler)
{
        try {
                var extendedAttributes = "";
                var usePre = config.options.chkUsePreForStorage;
                store.forEachField(tiddler,
                        function(tiddler,fieldName,value) {
                                // don't store stuff from the temp namespace
                                if(typeof value != "string")
                                        value = "";
                                if (!fieldName.match(/^temp\./))
                                        extendedAttributes += ' %0="%1"'.format([fieldName,value.escapeLineBreaks().htmlEncode()]);
                        },true);
                var created = tiddler.created.convertToYYYYMMDDHHMM();
                var modified = tiddler.modified.convertToYYYYMMDDHHMM();
                var vdate = version.date.convertToYYYYMMDDHHMM();
                var attributes = tiddler.modifier ? ' modifier="' + tiddler.modifier.htmlEncode() + '"' : "";
                attributes += (usePre && modified == created) ? "" : ' modified="' + modified +'"';
                attributes += (usePre && created == vdate) ? "" :' created="' + created + '"';
                var tags = tiddler.getTags();
                if(!usePre || tags)
                        attributes += ' tags="' + tags.htmlEncode() + '"';
                return ('<div %0="%1"%2%3>%4</'+'div>').format([
                                usePre ? "title" : "tiddler",
                                tiddler.title.htmlEncode(),
                                attributes,
                                extendedAttributes,
                                usePre ? "\n<pre>" + tiddler.text.htmlEncode() + "</pre>\n" : tiddler.text.escapeLineBreaks().htmlEncode()
                        ]);
        } catch (ex) {
                throw exceptionText(ex,config.messages.tiddlerSaveError.format([tiddler.title]));
        }
};

//--
//-- Deprecated code
//--

// @Deprecated: Use createElementAndWikify and this.termRegExp instead
config.formatterHelpers.charFormatHelper = function(w)
{
        w.subWikify(createTiddlyElement(w.output,this.element),this.terminator);
};

// @Deprecated: Use enclosedTextHelper and this.lookaheadRegExp instead
config.formatterHelpers.monospacedByLineHelper = function(w)
{
        var lookaheadRegExp = new RegExp(this.lookahead,"mg");
        lookaheadRegExp.lastIndex = w.matchStart;
        var lookaheadMatch = lookaheadRegExp.exec(w.source);
        if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
                var text = lookaheadMatch[1];
                if(config.browser.isIE)
                        text = text.replace(/\n/g,"\r");
                createTiddlyElement(w.output,"pre",null,null,text);
                w.nextMatch = lookaheadRegExp.lastIndex;
        }
};

// @Deprecated: Use <br> or <br /> instead of <<br>>
config.macros.br.handler = function(place)
{
        createTiddlyElement(place,"br");
};

// Find an entry in an array. Returns the array index or null
// @Deprecated: Use indexOf instead
Array.prototype.find = function(item)
{
        var i = this.indexOf(item);
        return i == -1 ? null : i;
};

// Load a tiddler from an HTML DIV. The caller should make sure to later call Tiddler.changed()
// @Deprecated: Use store.getLoader().internalizeTiddler instead
Tiddler.prototype.loadFromDiv = function(divRef,title)
{
        return store.getLoader().internalizeTiddler(store,this,title,divRef);
};

// Format the text for storage in an HTML DIV
// @Deprecated Use store.getSaver().externalizeTiddler instead.
Tiddler.prototype.saveToDiv = function()
{
        return store.getSaver().externalizeTiddler(store,this);
};

// @Deprecated: Use store.allTiddlersAsHtml() instead
function allTiddlersAsHtml()
{
        return store.allTiddlersAsHtml();
}

// @Deprecated: Use refreshPageTemplate instead
function applyPageTemplate(title)
{
        refreshPageTemplate(title);
}

// @Deprecated: Use story.displayTiddlers instead
function displayTiddlers(srcElement,titles,template,unused1,unused2,animate,unused3)
{
        story.displayTiddlers(srcElement,titles,template,animate);
}

// @Deprecated: Use story.displayTiddler instead
function displayTiddler(srcElement,title,template,unused1,unused2,animate,unused3)
{
        story.displayTiddler(srcElement,title,template,animate);
}

// @Deprecated: Use functions on right hand side directly instead
var createTiddlerPopup = Popup.create;
var scrollToTiddlerPopup = Popup.show;
var hideTiddlerPopup = Popup.remove;

// @Deprecated: Use right hand side directly instead
var regexpBackSlashEn = new RegExp("\\\\n","mg");
var regexpBackSlash = new RegExp("\\\\","mg");
var regexpBackSlashEss = new RegExp("\\\\s","mg");
var regexpNewLine = new RegExp("\n","mg");
var regexpCarriageReturn = new RegExp("\r","mg");
//--
//-- End of scripts
//--
//]]>
</script>
<script type="text/javascript">
//<![CDATA[
if(useJavaSaver)
        document.write("<applet style='position:absolute;left:-1px' name='TiddlySaver' code='TiddlySaver.class' archive='TiddlySaver.jar' width='1' height='1'></applet>");
//]]>
</script>
<!--POST-SCRIPT-START-->

<!--POST-SCRIPT-END-->
</body>
</html>