TiddlyTools... Small Tools for Big Ideasâ„¢
savetest
 foldfocuscloseclose others|gotosearchviewundorefresh|moreâ–¼ About Tuesday, July 8th 2008
TiddlyTools presents Technologies, Techniques, Tricks, Tips, Tweaks and Tutorials for TiddlyWiki readers, authors and developers, using a combination of plugins, macros, scripts, templates, and stylesheets created by Eric L Shulman (ELS Design Studios) to customize the default features and functions provided by the TiddlyWiki standard distribution.

Think of TiddlyTools as a kind of virtual hardware store and "demonstration showroom", offering tools, parts and techniques that help you to build your own TiddlyWiki documents.
The standard TiddlyWiki system provides the basic structure and utilities: the foundation, framing, walls, roof, windows/doors, plumbing, heating, electrical, etc. needed to construct a solid, general-purpose "info-house". TiddlyTools helps you with all the "finish work" — the paint, wallpaper, carpeting, lighting, appliances, cabinets, fixtures, furniture, etc. — that lets you turn your "info-house" into a comfortable, custom-built "info-home", optimized to best fit your specific needs and preferences.
This tiddler is included in the PageTemplate as a hidden SPAN. You can use it include macros or inline scripts that are automatically invoked whenever the document is loaded.
SetTiddlerColumns
sets the number of tiddler columns to display using the -moz-column-count, -moz-column-width, and -moz-column-gap CSS attributes (currently supported by Firefox only).
<<tiddler SetTiddlerColumns>>
tiddler columns:
SetSidebarTabsHeight
sets a fixed or percentage height for the sidebar tabs, or 'auto' (default) to allow as much room it needs.
<<tiddler SetSidebarTabsHeight>>
tabs height:
SetPopupsHeight
sets a fixed or percentage height for popup displays (e.g., tab popups), or 'auto' (default) to allow as much room needed.
<<tiddler SetPopupsHeight>>
popup height:
SetStoryHeight
sets a fixed or percentage height for the story column, or 'auto' (default) to allow as much room as needed.
<<tiddler SetStoryHeight>>
story height:
SetTiddlerHeight
sets a fixed or percentage height for each tiddler, or 'auto' (default) to allow each tiddler to use as much room as it needs.
<<tiddler SetTiddlerHeight>>
tiddler height:
ToggleSiteTitles
sets the visibility (display:none or display:block) of the SiteTitle/SiteSubtitle display area ('page titles', DOM ID=header)
<<tiddler ToggleSiteTitles>>
hide site titles
ToggleSiteMenu
sets the visibility (display:none or display:block) of the SiteMenu display area ('menubar', DOM ID=siteMenu).
<script show>
// show site menu by default
if (config.options.chkHideSiteMenu==undefined)
	config.options.chkHideSiteMenu="false";
</script>
<<tiddler ToggleSiteMenu>>
hide site menubar
VisitCounter
tracks and displays a quick reminder of how many times you have viewed this document as well as the date and time of your last visit. This information is stored privately in your browser using cookies (txtVisitCount and txtLastVisit), and are never accessible to any other parties.
<<tiddler VisitCounter with: TiddlyTools>>

ToggleLeftSidebar, ToggleRightSidebar
set the visibility (display:none or display:block) of the MainMenu ('left sidebar', DOM ID=mainMenu) and SideBarOptions ('right sidebar', DOM ID=sidebar) displays.
<script show>
	// default sidebar visibility
	if (config.options.chkShowLeftSidebar==undefined)
		config.options.chkShowLeftSidebar=true;
	if (config.options.chkShowRightSidebar==undefined)
		config.options.chkShowRightSidebar=false;
</script>

<<tiddler ToggleLeftSidebar>>â—„
<<tiddler ToggleRightSidebar>>â—„
ToggleScrollingSidebars
sets 'position:fixed' for the sidebars, so that they remain fixed in place (aka, "hover") when the rest of the page content is scrolled.
<<tiddler ToggleScrollingSidebars>>
sidebars scroll with page
<!--{{{-->
<link rel='alternate' type='application/rss+xml' title='RSS' href='index.xml' />
<!--}}}-->
Background: #fff
Foreground: #000
PrimaryPale: #8cf
PrimaryLight: #18f
PrimaryMid: #04b
PrimaryDark: #014
SecondaryPale: #ffc
SecondaryLight: #fe8
SecondaryMid: #db4
SecondaryDark: #841
TertiaryPale: #eee
TertiaryLight: #ccc
TertiaryMid: #999
TertiaryDark: #666
Error: #f88
/*{{{*/
body {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

hr {height:1px;}

a {text-decoration:none;}

dt {font-weight:bold;}

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

.txtOptionInput {width:11em;}

#contentWrapper .chkOptionInput {border:0;}

.externalLink {text-decoration:underline;}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

* html #backstage {width:99%;}
* html #backstageArea {width:99%;}
#backstageArea {display:none; position:relative; overflow: hidden; z-index:150; padding:0.3em 0.5em 0.3em 0.5em;}
#backstageToolbar {position:relative;}
#backstageArea a {font-weight:bold; margin-left:0.5em; padding:0.3em 0.5em 0.3em 0.5em;}
#backstageButton {display:none; position:absolute; z-index:175; top:0em; right:0em;}
#backstageButton a {padding:0.1em 0.4em 0.1em 0.4em; margin:0.1em 0.1em 0.1em 0.1em;}
#backstage {position:relative; width:100%; z-index:50;}
#backstagePanel {display:none; z-index:100; position:absolute; width:90%; margin:0em 3em 0em 3em; padding:1em 1em 1em 1em;}
.backstagePanelFooter {padding-top:0.2em; float:right;}
.backstagePanelFooter a {padding:0.2em 0.4em 0.2em 0.4em;}
#backstageCloak {display:none; z-index: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 1em;}
/* Fixes a feature in Firefox 1.5.0.2 where print preview displays the noscript content */
noscript {display:none;}
}
/*}}}*/
<!--{{{-->
<div class='header' macro='gradient vert [[ColorPalette::PrimaryLight]] [[ColorPalette::PrimaryMid]]'>
<div class='headerShadow'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
</div>
<div class='headerForeground'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
</div>
</div>
<div id='mainMenu' refresh='content' tiddler='MainMenu'></div>
<div id='sidebar'>
<div id='sidebarOptions' refresh='content' tiddler='SideBarOptions'></div>
<div id='sidebarTabs' refresh='content' force='true' tiddler='SideBarTabs'></div>
</div>
<div id='displayArea'>
<div id='messageArea'></div>
<div id='tiddlerDisplay'></div>
</div>
<!--}}}-->
<!--{{{-->
<div class='toolbar' macro='toolbar [[ToolbarCommands::ViewToolbar]]'></div>
<div class='title' macro='view title'></div>
<div class='subtitle'><span macro='view modifier link'></span>, <span macro='view modified date'></span> (<span macro='message views.wikified.createdPrompt'></span> <span macro='view created date'></span>)</div>
<div class='tagging' macro='tagging'></div>
<div class='tagged' macro='tags'></div>
<div class='viewer' macro='view text wikified'></div>
<div class='tagClear'></div>
<!--}}}-->
<!--{{{-->
<div class='toolbar' macro='toolbar [[ToolbarCommands::EditToolbar]]'></div>
<div class='title' macro='view title'></div>
<div class='editor' macro='edit title'></div>
<div macro='annotations'></div>
<div class='editor' macro='edit text'></div>
<div class='editor' macro='edit tags'></div><div class='editorFooter'><span macro='message views.editor.tagPrompt'></span><span macro='tagChooser excludeLists'></span></div>
<!--}}}-->
To get started with this blank TiddlyWiki, you'll need to modify the following tiddlers:
* SiteTitle & SiteSubtitle: The title and subtitle of the site, as shown above (after saving, they will also appear in the browser title bar)
* MainMenu: The menu (usually on the left)
* DefaultTiddlers: Contains the names of the tiddlers that you want to appear when the TiddlyWiki is opened
You'll also need to enter your username for signing your edits: <<option txtUserName>>
These InterfaceOptions for customising TiddlyWiki are saved in your browser

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

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

----
Also see [[AdvancedOptions]]
<<importTiddlers>>
!!!!!Pick up Jeremy:
<<<
Mon 6/16 13:50pm PDT
Virgin Atlantic
International Arrivals
San Francisco International (SFO)
<<<
{{medium{
Meet face-to-face with Eric Shulman, Jeremy Ruston and several other Osmosoftians!}}}
If you plan to attend, you need to {{big{[[sign up here|http://upcoming.yahoo.com/event/780408]]}}}
or send email to ''Phil Whitehouse at: [[hello AT osmosoft DOT com|mailto:hello@osmosoft.com]]''
!!!!!Here's Phil's original annoucement...
<<<
This is an open invitation to anyone who'd like to get together for a TiddlyWiki meeting in San Francisco! We're planning an event called {{medium{//~TiddlyWest//}}}, which will be co-hosted by Eric Shulman and Osmosoft.
>{{big{The event will take place at}}}
>{{big{The Wharton West in San Francisco}}}
>{{big{from 5-9pm on 18 June 2008.}}}
Here's the address:
>''WHARTON WEST, Room 5A, 101 Howard Street, San Francisco, CA''
>{{medium{[[view a map|http://maps.google.com/maps?f=q&hl=en&geocode=&q=101+howard+st,+sf,+ca&sll=37.0625,-95.677068&sspn=68.481636,106.699219&ie=UTF8&ll=37.790896,-122.393725&spn=0.017093,0.042701&z=15]]}}}
<<<
/%
|''URL:''|http://tiddlywiki.abego-software.de/|
|''Description:''|AbegoExtensions for TiddlyWiki|
|''Author:''|UdoBorkowski|
%/
<<tiddler HideTiddlerTags>>[>img(auto,+)[images/eric3.gif]]~TiddlyTools presents ''Technologies, Techniques, Tricks, Tips, Tweaks and Tutorials'' for ~TiddlyWiki readers, authors and developers, using a combination of ''plugins, macros, scripts, templates, and stylesheets'' created by [[Eric L Shulman|http://about.UnaMesa.org/Eric+Shulman]] ([[ELS Design Studios|ELSDesignStudios]]) to customize the default features and functions provided by the ~TiddlyWiki standard distribution.

{{normal bold center{//Think of TiddlyTools as a kind of virtual hardware store and "demonstration showroom", offering ''tools, parts and techniques that help you to build your own TiddlyWiki documents''.//}}}
__//The standard TiddlyWiki system provides the basic structure and utilities//__: the foundation, framing, walls, roof, windows/doors, plumbing, heating, electrical, etc. needed to construct a ''solid, general-purpose "info-house"''.  __//TiddlyTools helps you with all the "finish work"//__ -- the paint, wallpaper, carpeting, lighting, appliances, cabinets, fixtures, furniture, etc. -- that lets you ''turn your "info-house" into a comfortable, custom-built "info-home", optimized to best fit your specific needs and preferences.''
/***
|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;
}
//}}}
/***
|Name|AliasPlugin|
|Source|http://www.TiddlyTools.com/#AliasPlugin|
|Documentation|http://www.TiddlyTools.com/#AliasPluginInfo|
|Version|1.1.2|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|Create text-substitution macros|
Define macros for abbreviations and other "aliases", and then embed them in the rest of your tiddler content to quickly insert common terms, phrases and links without a lot of repetitive typing.
!!!!!Documentation
> see [[AliasPluginInfo]]
!!!!!Revisions
<<<
2012.08.10 1.2.0 handle backslash quoting to allow direct use of macro calls in aliases
2009.09.09 1.1.1 'tiddler' arg passed to wikify() so aliases containing macros render with correct context
| Please see [[AliasPluginInfo]] for previous revision details |
2005.08.12 1.0.0 initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.AliasPlugin= {major: 1, minor: 2, revision: 0, date: new Date(2012,8,10)};
config.macros.alias= { };
config.macros.alias.handler = function(place,macroName,params,wikifier,paramString,tiddler) {
	var alias=params.shift(); if (!alias) return; alias=alias.replace(/ /g,"_"); // don't allow spaces in alias
	if (config.macros[alias]==undefined) { // create new macro (as needed)
		config.macros[alias] = { };
		config.macros[alias].handler =
			function (place,macroName,params,wikifier,paramString,tiddler)
				{ wikify(config.macros[macroName].text.format(params),place,null,tiddler); }
	}
	var t=(params[0]?params.join(' '):alias); // construct paramstring
	t=t.replace(/\\n/g,'\n').replace(/\\t/g,'\t').replace(/\\([<>])/g,'$1'); // fixup escaped chars
	config.macros[alias].text = t; // set alias text
}
//}}}
/***
|Name|AliasPlugin|
|Source|http://www.TiddlyTools.com/#AliasPlugin|
|Documentation|http://www.TiddlyTools.com/#AliasPluginInfo|
|Version|1.2.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|documentation|
|Description|documentation for AliasPlugin|
Define macros for abbreviations and other "aliases", and then embed them in the rest of your tiddler content to quickly insert common terms, phrases and links without a lot of repetitive typing.
!!!!!Usage
<<<
{{{
<<alias keyword "content to display">>
}}}
Select a short keyword or other abbreviated term that is easily input with just a few keystrokes.  When the {{{<<alias>>}}} macro is processed, it creates a new macro for you to embed in tiddler content, using the specified alias keyword as the name for that new macro.  You can choose any keyword you like, but don't include any spaces, as macro names must not contain spaces.

In order to ensure that your aliases are always defined and available for use, you should add your definitions to a tiddler that you are certain will be displayed when your TW is first loaded (e.g., [[MainMenu]]).  The {{{<<alias>>}}} macro itself won't actually produce any visible output, so it can be safely added to practically any tiddler without producing a change in that tiddler's appearance.

To use the aliases you have defined, simply invoke them as you would any other TiddlyWiki macro, e.g.,
{{{<<keyword>>}}}.  If you include parameters when you invoke the macro -- {{{<<keyword param param param...>>}}} -- they can be inserted direclty into the output by replacing corresponding substitution markers, indicated by using "%0" through "%9" in the "text to display" parameter used when the alias was defined.  You can also use standard "backslash quoting" (e.g, "\n" (newline), "\t" (tab), etc.) to insert special characters into the alias output.  Important note: ''//to embed another macro within an alias definition, you must "quote" the closing angle brackets by adding a backslash, like this:// {{{>\>}}}.''

For example, to define a quick alias for inserting a link to any given subject on www.wikipedia.com, you can write:
{{{
<<alias wikipedia "[[Wikipedia:%0|http://www.wikipedia.com/wiki/%0]]">>
}}}
which allows you to then write:
{{{
<<wikipedia TiddlyWiki>>
}}}
which is processed as if you wrote:
{{{
[[Wikipedia:TiddlyWiki|http://www.wikipedia.com/wiki/TiddlyWiki]]
}}}
and is displayed this way:
><<alias wikipedia "[[Wikipedia:%0|http://www.wikipedia.com/wiki/%0]]">><<wikipedia TiddlyWiki>>

Another interesting example uses the substitution markers to automatically display a reference to a TiddlerSlice value:
{{{
<<alias describe "|<<tiddler [[%0::Description]]>\>|\n">>
}}}
which allows you to then write:
{{{
<<describe AliasPlugin>>
}}}
which is processed as if you wrote:
{{{
|<<tiddler [[AliasPlugin::Description]]>>|
}}}
and is displayed this way:
<<alias describe "|\t<<tiddler [[%0::Description]]>\>|\n">><<describe AliasPlugin>>
<<<
!!!!!Revisions
<<<
2012.08.10 1.2.0 handle backslash quoting to allow direct use of macro calls in aliases
2009.09.09 1.1.1 'tiddler' arg passed to wikify() so aliases containing macros render with correct context
2008.03.11 [*.*.*] plugin size reduction - documentation moved to [[AliasPluginInfo]]
2007.03.21 1.1.0 added support for parameter substitution into alias macros, using format() method and%0..%9 markers
2005.10.09 1.0.3 combined documentation and code into a single tiddler
2005.08.12 1.0.0 initial release
<<<
/%
!info
|Name|AllThumbs|
|Source|http://www.TiddlyTools.com/#AllThumbs|
|Version|1.2.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Requires|ThumbThing|
|Description|display a set of thumbnails with full-sized popup images|
Usage:
<<<
{{{
<<tiddler AllThumbs with: TiddlerName thumbsPerRow thumbWidth>>
}}}
*{{{TiddlerName}}} is the title of a tiddler containing a space-separated list of images
*{{{thumbsPerRow}}} is the number of images to show on each row of output.  Omit or use 'auto' for a single row
*{{{thumbWidth, thumbHeight, fullHeight, fullWidth}}} applies CSS to scale thumbnails and popup images.  Omit or use 'auto' for stretch-to-fit/full-size images
See [[ThumbThing]] for additional details
<<<
Examples:
<<<
{{{
<<tiddler AllThumbs with: [[AllThumbs##SampleList]]>>
}}}
Sample List:
<<tiddler AllThumbs##show with:	{{
	'{{{\n'+store.getTiddlerText('AllThumbs##SampleList')+'\n}\}\}\n';
}}>>
<<tiddler AllThumbs with: [[AllThumbs##SampleList]]>>
<<<
!end info

!SampleList
images/california.gif
images/cool_illusion.gif
AttachFileSample2
images/fish.jpg
images/sunset.jpg
!end SampleList

!show
$1
!end show

%/<<tiddler {{'$1'=='$'+'1'?'AllThumbs##info':'AllThumbs##show'}} with: {{
	var list=store.getTiddlerText('$1','').readBracketedList(false);
	var rowsize='$2'; if (rowsize=='$'+'2' || rowsize=='auto') rowsize=list.length;
	var width='$3';	  if (  width=='$'+'3' || width=='auto')   width=95/rowsize+'%';
	var out=[];
	var thumb='<<tiddler ThumbThing with: [[%0]] [[%1]] [[%2] [[%3]] [[%4]]>\>';
	for (var i=0; i<list.length; i++) {
		if (i && i%rowsize==0) out.push('\n');
		out.push(thumb.format([list[i],width,'$4','$5','$6']));
	}
	!out.length||!store.tiddlerExists('ThumbThing')?'<<tiddler AllThumbs##info>\>':out.join('');
}}>>
!usage
{{{<<player flash AnalogClock 400px 400px>>}}}
<<player flash AnalogClock 400px 400px>>
!notes
{{{<<player>>}}} macro requires http://www.TiddlyTools.com/#PlayerPlugin
!type
application/x-shockwave-flash
!file
./clock.swf
!url
http://www.TiddlyTools.com/clock.swf
!data
/***
|Name|AnimationEffectsPlugin|
|Source|http://www.TiddlyTools.com/#AnimationEffectsPlugin|
|Documentation|http://www.TiddlyTools.com/#AnimationEffectsPluginInfo|
|Version|3.1.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.2|
|Type|plugin|
|Description|display content with timer-based animations to manipulate multiple CSS attributes|
|Status|!BETA - EXPERIMENTAL - UNDER DEVELOPMENT - USE WITH CAUTION|
This plugin defines the {{{<<animate>>}}} macro that can be used to peform simple animations of formatted tiddler content by saving/setting/reseting the values of CSS style attributes at specified times.  The macro can also be used to smoothly animate CSS styles that use ''numeric values'', by automatically computing a series of incremental values, ranging from //start// to //stop//, for a specified //duration//, with optional "pause-and-reverse" //cycles// to create repeating animations or continuous loops.
!!!!!Documentation
>see [[AnimationEffectsPluginInfo]] for macro syntax
>see [[AnimationEffectsSampler]] for a live animation example...
!!!!!Revisions
<<<
2008.01.08 [*.*.*] plugin size reduction: documentation moved to [[AnimationEffectsPluginInfo]]
2008.01.07 [3.1.1] when animation is disabled, set inner container to original DIV/SPAN
2007.12.16 [3.1.0] added support for "add/remove" classname functionality.  Also, in handling for "set", only stored previous attribute value if not already saved and, on "reset", clear saved value.  This blocks animations from inadvertently overwriting the saved value while simulaneously processing animation sequences that act on the same attribute.
2007.12.08 [3.0.0] Combined ZoomTextPlugin and AnimateTiddler inline script into single plugin
2007.08.03 [2.1.0] converted from ZoomText inline script
2007.07.16 [2.0.0] added TW2.2-compatible Morpher handling for smoother animation on slower systems
2007.02.17 [1.0.0] initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.AnimationEffectsPlugin= {major: 3, minor: 1, revision: 1, date: new Date(2008,1,7)};
config.macros.animate = {
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		var id=new Date().getTime()+Math.random().toString(); // globally unique ID (GUID)
		if (params[0] && (params[0].toUpperCase()=="DIV"||params[0].toUpperCase()=="SPAN"))
			var nodetype=params.shift().toUpperCase(); // optional param to force DIV/SPAN
		var src=params.shift(); if (!src) src="="; // content is first parameter (if no params, animate container)
		if (src.substr(0,1)=="=") { // content=DOM element... use "=here" or "=" (without ID) for current container
			var target=place;
			if (src.length>1 && src.substr(1).toUpperCase()!='HERE') target=document.getElementById(src.substr(1));
			if (!target) return; // couldn't locate target element... do nothing.
			var nodetype=nodetype||target.nodeName.toUpperCase();
		} else { // use content from tiddler or "inline" param
			if (src.substr(0,1)=="@") src=store.getTiddlerText(src.substr(1)); // "@TiddlerName"
			var nodetype=nodetype||"span";
			var target=createTiddlyElement(place,nodetype);
			wikify(src,target);
		}
		if (params[0]) switch(params[0].toUpperCase()) {
			case "SAVE":
				var s=params[1]; if (!s) return; // must specify style attribute
				if (s.substr(0,1)=="+") s=s.substr(1); // ignore leading "+" (if any)
				var w=(params[2]!=undefined && config.options.chkAnimate)?parseInt(params[2]):0; // wait time before saving
				if (!target.savedStyle) target.savedStyle={};
				if (target.savedStyle[s]!==undefined) return; // value already saved... do nothing.
				if (!w) { target.savedStyle[s]=target.style[s]; return; } // save style immediately... done.
				target.id=target.id||id; // use existing ID if target has one, otherwise assign GUID
				var fn='var e=document.getElementById("'+target.id+'"); \
					if(e&&e.savedStyle["'+s+'"]==undefined) \
					e.savedStyle["'+s+'"]=e.style["'+s+'"]';
				setTimeout(fn,w); return; // timer is set... done.
			case "SET":
				var s=params[1]; if (!s) return; // must specify style attribute
				if (s.substr(0,1)=="+") s=s.substr(1); // ignore leading "+" (if any)
				var v=params[2]!=undefined?params[2]:""; // value to set
				var w=(params[3]!=undefined && config.options.chkAnimate)?parseInt(params[3]):0; // wait time before setting
				if (!w) { target.style[s]=v; return; } // set style immediately... done.
				target.id=target.id||id; // use existing ID if target has one, otherwise assign GUID
				var fn='var e=document.getElementById("'+target.id+'");if(e)e.style["'+s+'"]="'+v+'"';
				setTimeout(fn,w); return; // timer is set... done.
			case "RESET":
				var s=params[1]; if (!s) return; // must specify style attribute
				if (s.substr(0,1)=="+") s=s.substr(1); // ignore leading "+" (if any)
				var w=(params[2]!=undefined && config.options.chkAnimate)?parseInt(params[2]):0; // wait time before reset
				if (!w && target.savedStyle && (s in target.savedStyle))
					{ target.style[s]=target.savedStyle[s]; target.savedStyle[s]=undefined; return; } // reset style immediately
				target.id=target.id||id; // use existing ID if target has one, otherwise assign GUID
				var fn='var e=document.getElementById("'+target.id+'"); \
					if(e&&e.savedStyle&&("'+s+'" in e.savedStyle)) \
					e.style["'+s+'"]=e.savedStyle["'+s+'"]; e.savedStyle["'+s+'"]=undefined';
				setTimeout(fn,w); return; // timer is set... done.
			case "ADD":
				var add=true; // fall-through for further processing
			case "REMOVE":
				var c=params[1]; if (!c) return; // must specify a classname
				if (c.substr(0,1)=="+") c=c.substr(1); // ignore leading "+" (if any)
				var w=(params[2]!=undefined && config.options.chkAnimate)?parseInt(params[2]):0; // wait time before setting
				if (!w) { (add?addClass:removeClass)(target,c); return; } // add class immediately... done.
				target.id=target.id||id; // use existing ID if target has one, otherwise assign GUID
				var fn='var e=document.getElementById("'+target.id+'");if(e)'+(add?'addClass':'removeClass')+'(e,"'+c+'")';
				setTimeout(fn,w); return; // timer is set... done.
		}

		// remove old containers before RE-animating, unless combining effects (using "+style" param)
		if (params[0] && params[0].substr(0,1)!="+") cleanup(target);
		function cleanup(here) { // recursively finds all animation containers
			if (here.childNodes) for (var n=0; n<here.childNodes.length; n++)
				if (here.childNodes[n].className=="animationContainer") cleanup(here.childNodes[n]);
			if (here.className=="animationContainer") { // move content up a level and remove container
				var e=here.firstChild;
				while (e) { var next=e.nextSibling; here.parentNode.insertBefore(e,here); e=next; }
				removeNode(here);
			}
		}
		// create animation outer "clipping" container and inner "formatting" container
		var outer=createTiddlyElement(null,nodetype,null,"animationContainer");
		outer.style.overflow="hidden";
		var inner=createTiddlyElement(outer,nodetype,id,"animationContainer");
		inner.style.position="relative"; inner.style.lineHeight="100%";
		target.insertBefore(outer,target.firstChild);

		// move content elements into the inner container
		var e=target.firstChild.nextSibling;
		while (e) { var next=e.nextSibling; inner.insertBefore(e,null); e=next; }

		// params and defaults for morph
		inner.OriginalType=target.nodeName.toUpperCase(); // SPAN or DIV
		inner.What=params[0]?params[0]:'left';
		if (inner.What.substr(0,1)=="+") inner.What=inner.What.substr(1); // trim off "+" prefix (if any)
		inner.Format=params[1]!=undefined?params[1]:'%0%';
		inner.Start=params[2]!=undefined?parseInt(params[2]):100;
		inner.Stop=params[3]!=undefined?parseInt(params[3]):0;
		inner.Wait=params[4]!=undefined?parseInt(params[4]):0;
		inner.Duration=params[5]!=undefined?parseInt(params[5]):2000;
		inner.Cycle=params[6]!=undefined?parseInt(params[6]):1
		inner.Pause=params[7]!=undefined?parseInt(params[7]):0;

		if (!config.options.chkAnimate) { // if not animating
			if (inner.Cycle && (inner.Cycle % 2)) inner.Start=inner.Stop; // odd # of cycles: apply ending value
			inner.style.display=inner.OriginalType!="DIV"?"inline":"block"; // restore original display style
			var outer=inner.parentNode; if (outer && outer.parentNode) // remove outer clipping container
				{ outer.parentNode.insertBefore(inner,outer); removeNode(outer); }
		}
		inner.style[inner.What]=inner.Format.format([inner.Start]); // set initial style value
		if (inner.What=="fontSize" && inner.Start<=0)  inner.style.display="none"; // hide text if initial size is 0

		if (config.options.chkAnimate) setTimeout("config.macros.animate.morph('"+inner.id+"')",inner.Wait); // ANIMATE!
	},
//}}}
//{{{
	// animation 'tick' handler (timer callback)
	morph: function(id) {
		var inner=document.getElementById(id); if (!inner) return; 
		var p = [{style: inner.What, start: inner.Start, end: inner.Stop, template: inner.Format}];
		var c = function(inner,p) { // reverse and re-animate until cycle count==0 (use -1 for continuous looping)
			if (inner.Cycle==0 || inner.Cycle==1) {
				 // finished animation... discard outer container but keep inner container to display final style(s)
				inner.style.display=inner.OriginalType!="DIV"?"inline":"block"; // restore original display style
				if (p[0].style=="fontSize" && p[0].end<=0) inner.style.display="none"; // hide text if final size=0
				var outer=inner.parentNode; if (outer && outer.parentNode) // remove outer clipping container
					{ outer.parentNode.insertBefore(inner,outer); removeNode(outer); }
			}
			else { // reverse-and-repeat 
	 			inner.Cycle--; var t=inner.Start; inner.Start=inner.Stop; inner.Stop=t;
				setTimeout("config.macros.animate.morph('"+inner.id+"')",inner.Pause);
			}
		};
		inner.style.display=inner.nodeName.toUpperCase()!="DIV"?"inline":"block"; // show starting content
		anim.startAnimating(new Morpher(inner,inner.Duration,p,c));
	}
};
//}}}
//{{{
// for backward-compatibility with retired [[ZoomTextPlugin]]
config.macros.zoomText = {
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		// convert old params to new params and invoke new handler
		var Text=params[0]!=undefined?params[0]:"";
		if (Text.substr(0,1)=="@") Text=store.getTiddlerText(Text.substr(1));
		var Wait=params[1]!=undefined?parseInt(params[1]):0;
		var Start=params[2]!=undefined?parseInt(params[2]):1;
		var Stop=params[3]!=undefined?parseInt(params[3]):100;
		var Duration=params[4]!=undefined?parseInt(params[4]):config.animDuration;
		var Cycle=params[5]!=undefined?parseInt(params[5]):0
		var Pause=params[6]!=undefined?parseInt(params[6]):0;
		var newParams=[Text,"fontSize","%0%",Start,Stop,Wait,Duration,Cycle,Pause];
		var newParamString=["[["+Text+"]]","fontSize","%0%",Start,Stop,Wait,Duration,Cycle,Pause].join(" ");
		return config.macros.animate.handler(place,macroName,newParams,wikifier,newParamString,tiddler)
	}
}
//}}}
/***
|Name|AnimationEffectsPlugin|
|Source|http://www.TiddlyTools.com/#AnimationEffectsPlugin|
|Documentation|http://www.TiddlyTools.com/#AnimationEffectsPluginInfo|
|Version|3.1.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.2|
|Type|documentation|
|Description|documentation for AnimationEffectsPlugin|
|Status|!BETA - EXPERIMENTAL - UNDER DEVELOPMENT - USE WITH CAUTION|
This plugin defines the {{{<<animate>>}}} macro that can be used to peform simple animations of formatted tiddler content by saving/setting/reseting the values of CSS style attributes at specified times.  The macro can also be used to smoothly animate CSS styles that use ''numeric values'', by automatically computing a series of incremental values, ranging from //start// to //stop//, for a specified //duration//, with optional "pause-and-reverse" //cycles// to create repeating animations or continuous loops.
!!!!!Examples
>Please see [[AnimationEffectsSampler]] for a live animation example...
!!!!!Usage
<<<
The macro syntax is:
{{{
<<animate type source style format start stop wait duration cycles pause>>
<<animate type source "set" style value wait>>
<<animate source "save" style wait>>
<<animate source "reset" style wait>>
<<animate source "add" classname wait>>
<<animate source "remove" classname wait>>
}}}
> //note: default values are shown in parentheses for //optional// parameters.  To ensure the correct order and number of parameters in the macro, you should enter these default values as 'placeholders' when using non-default values for other parameters.  Of course, if all the remaining values that follow a non-default parameter are default values, they do not need to be specified, and can be safely omitted.//
where:
* ''//type// (="span")''<br>is either ''div'' or ''span'', and forces the animation container to be a "DIV" or "SPAN" element (i.e., displayed on a separate line, or inline with other content), which can affect how the specified CSS style will be applied.  When this param is omitted (which is the general use case), the animation container defaults to the same type as the original content.  When using a parameter with "inline" content (see below), a span element is created by default.
* ''//source//''<br>specifies the source content to be animated, and can be one of:
**''"text to display"''<br>inline wiki-syntax content, entered directly as a //quoted// macro parameter.  The {{{<<animate>>}}} macro automatically creates a container at the current location and renders the content into it before animating.
**''@~TiddlerName''<br>as above, but retrieves and renders wiki-syntax content from another tiddler.
**''=elementID''<br>indicates a specific DOM element, by assigned ID (e.g., "mainMenu", "displayArea", "sidebar", etc.).  The macro will animate this content from it's original location.
**''='' (or ''=here'')<br>indicates the current containing DOM element (i.e, the one in which the {{{<<animate>>}}} macro is embedded.  The animation will affect all content that //precedes the macro// within the current container.
* ''"set"'', ''"save"'', ''"reset"'', ''"add"'', ''"remove"''<br>are keywords to indicate how to process the rest of the macro parameters.  If ''set'' is used, the remaining parameters are interpeted as //style//, //value//, and //wait//, respectively, and the macro assigns the value to the specified style at the indicated time.  The ''save'' and ''reset'' keywords expect only //style// and //wait// parameters following the keyword, where ''save'' retains a copy of the current CSS style value so that you can later use ''reset'' to re-assign the original saved value back to the specified CSS style.   The ''add'' and ''remove'' keywords expect and //classname// and //wait// value, and adds/removes the specified classname from the animated element.  If no keyword (or ''morph'') is specified, the remaining macro parameters are used to calculate and apply multiple incremental CSS values for smooth animation processing (a.k.a., "morphing").
* ''//style// (="left")''<br>indicates the CSS attribute to be animated (e.g., "left", "marginTop", "width", "fontSize", etc.).  Note: if you embed more than one {{{<<animate>>}}} macro in the same container (to simultaneously alter multiple CSS attributes), only the //''last''// animation effect will be applied.  To combine several effects, you must precede the //style// parameter value with a "+" symbol for all uses of {{{<<animate>>}}} //except// for the first occurrence within that container, which must //NOT// have a "+" symbol).
* ''//format// (="%0%")''<br>provides a 'text template' for generating CSS attribute values during animation, by using "%0" as a substitution marker to be automatically replaced by the current animation value, combined with a CSS measurement type (e.g., px, em, %, in, cm).  For example: "%0px" produces pixel-based values (e.g., "27px", "342.873px", etc.), while "%0%" generates percentage-based relative measurements, (e.g., "-100%", "42%", etc.), and "%0em" results in measurements that are relative to the current font size (em).
* ''//start// (=-100) and //stop// (=0)'' or ''//value// (="")''<br>define the initial and ending values for the CSS attribute being animated.  Note that, except when using the alternative ''set'' keyword syntax, these values must be numeric, as they are used to //calculate// the incremental values for each 'tick' of the animation processing.
* ''//wait// (=0)''<br>indicates the number of milliseconds to wait before starting the animation sequence.  All animation macros that are embedded in the same content begin simultaneously.  The //wait// value allows you to use several effects in sequence, by defining the start of each effect so that it does not begin until the previous one has completed.
* ''//duration// (=2000)''<br>indicates the number of milliseconds during which to animate from the //start// value to the //stop// value.
* ''//cycles// (=1)'' and ''//pause// (=1000)''<br>indicates the number of "reverse-and-repeat" cycles to perform and the pause (in milliseconds) in between each part of the cycle.  When cycles=1 (or zero, or is omitted entirely), animation progresses from //start// to //stop// just once.  However, if cycles>1, then the animation can pause for a specified amount of time before swapping the //start// and //stop// values and continuing ''//in reverse//''.  A value of cycles=2 performs the animation twice, completing a single loop from //start// to //stop// and then back to //start// again, while cycles=3 does 1.5 loops (ending with the //stop// value), and cycles=4 does 2 complete loops (ending with the //start// value), etc.  To loop forever, specify a cycle value of "-1".

In addition to the {{{<<animate>>}}} macro, the plugin also defines the following macro for backward-compatibility with the now retired [[ZoomTextPlugin]]:
{{{
<<zoomText "text to display" wait start stop duration cycles pause>>
<<zoomText @TiddlerName wait start stop duration cycles pause>>
}}}
This permits rendering of existing tiddlers that already contain the {{{<<zoomText>>}}} macro without needing to update those tiddlers.  However, use of this older syntax is deprecated in favor of the more robust and flexible {{{<<animate>>}}} syntax described above.  
<<<
/%
|Name|AnimationEffectsSampler|
|Source|http://www.TiddlyTools.com/#AnimationEffectsSampler|
|Version|2.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|sample|
|Requires|AnimationEffectsPlugin, StyleSheetShortcuts, CloseOtherTiddlers, RefreshTiddler, ReplaceTiddlerTitle|
|Description|demonstrates techniques for animating wiki-formatted content|

SET SPEED MULTIPLIER (global variable) [0:00]
%/<<tiddler {{ 
	window.sec=config.options.txtAnimationEffectsRate||1000; // global abbreviation/default multiplier
	config.options.txtAnimationEffectsRate=window.sec; // user option value initialization
	""; // return blank tiddlername so macro doesn't produce output
}}>>/%

HIDE TIDDLER ELEMENTS [0:00]
%/<html><style>
#tiddlerAnimationEffectsSampler .subtitle,
#tiddlerAnimationEffectsSampler .tagged
	{ display:none !important; }
#tiddlerAnimationEffectsSampler .viewer {
	background-image:none !important;
	background-color:transparent;
	border:0; margin:0; padding:0;
}
</style></html>/%

CLOSE OTHER TIDDLERS [0:00]
%/<<tiddler CloseOtherTiddlers>>/%

HIDE PAGE ELEMENTS BEFORE ANIMATION [0:00]
%/<<animate =mainMenu     save  display       {{0*sec}}>>/%
%/<<animate =mainMenu     set   display none  {{0*sec}}>>/%
%/<<animate =sidebar      save  display       {{0*sec}}>>/%
%/<<animate =sidebar      set   display none  {{0*sec}}>>/%
%/<<animate =storyMenu    save  display       {{0*sec}}>>/%
%/<<animate =storyMenu    set   display none  {{0*sec}}>>/%
%/<<animate =siteTitle    save  display       {{0*sec}}>>/%
%/<<animate =siteTitle    set   display none  {{0*sec}}>>/%
%/<<animate =siteSubtitle save  display       {{0*sec}}>>/%
%/<<animate =siteSubtitle set   display none  {{0*sec}}>>/%
%/<<animate =displayArea  save  marginLeft    {{0*sec}}>>/%
%/<<animate =displayArea  set   marginLeft 0  {{0*sec}}>>/%
%/<<animate =displayArea  save  marginRight   {{0*sec}}>>/%
%/<<animate =displayArea  set   marginRight 0 {{0*sec}}>>/%
%/<<animate =siteMenu     save  visibility        {{0*sec}}>>/%
%/<<animate =siteMenu     set   visibility hidden {{0*sec}}>>/%
%/<<animate =breadCrumbs  save  visibility        {{0*sec}}>>/%
%/<<animate =breadCrumbs  set   visibility hidden {{0*sec}}>>/%

CONTAINER FOR SHOWING TIDDLER VIEWER BACKGROUND AT END OF ANIMATION
%/{{block{/%

LEFT/RIGHT SLIDING TEXT EFFECT [0:00 - 0:10]
%/@@position:absolute;width:100%;{{nowrap italic{/%
	%/<<animate div "{{red{Are you}}}"
		left %0% 0 50 {{0*sec}} {{1.5*sec}} 7>>/%
	%/<<animate div "{{blue{getting dizzy?}}}"
		left %0% 50 0 {{0*sec}} {{1.5*sec}} 7>>/%
	%/<<animate = fontSize    %0% 0 400 {{0*sec}} {{2.5*sec}} 4>>/%
	%/<<animate = +marginTop  %0% 0 10  {{0*sec}} {{1*sec}}   6>>/%
%/}}}@@/%

UP/DOWN SPINNING TEXT EFFECT [0:00 - 0:09]
%/{{big italic{
	<<animate "{{floatleft right green{Are<br>you}}}"
		fontSize %0% 0 300 {{0*sec}}   {{1.5*sec}} 6>>/%
	%/<<animate div "getting<br>dizzy?"
		fontSize %0% 0 300 {{1.5*sec}} {{1.5*sec}} 6>>/%
	%/<<animate = left       %0% 20 35 {{0*sec}} {{1*sec}} 6>>/%
	%/<<animate = +marginTop %0% 0  15 {{0*sec}} {{1*sec}} 6>>/%
	%/<<animate = +right     %0% 0  30 {{5*sec}} {{1*sec}} 6>>/%
%/}}}/%

ALMOST DONE MESSAGE [0:08 - 0:16.5]
%/{{big floatleft green{/%
	%/''//almost done...//''/%
	%/<<animate = set display none {{0*sec}}>>/%
	%/<<animate = set display inline {{8*sec}}>>/%
	%/<<animate = letterSpacing %0px  25 0 {{8*sec}}  {{8*sec}}>>/%
	%/<<animate = +fontSize     %0%  100 0 {{16*sec}} {{.5*sec}}>>/%
%/}}}/%

SIDE-TO-SIDE "SWING" EFFECT (ALL TIDDLER CONTENT) [0:00 - 0:11.2]
%/<<animate = left %0% 45 0 {{0*sec}} {{1.6*sec}} 7>>/%

FINAL COUNTDOWN [0:11.5 - 0:16.5]
%/{{floatleft bold italic{/%
	%/<<animate "5" fontSize %0% 0 400 {{11.5*sec}} {{.5*sec}} 2>>/%
	%/<<animate "4" fontSize %0% 0 350 {{12.5*sec}} {{.5*sec}} 2>>/%
	%/<<animate "3" fontSize %0% 0 300 {{13.5*sec}} {{.5*sec}} 2>>/%
	%/<<animate "2" fontSize %0% 0 250 {{14.5*sec}} {{.5*sec}} 2>>/%
	%/<<animate "1" fontSize %0% 0 200 {{15.5*sec}} {{.5*sec}} 2>>/%
%/}}}/%

RESTORE PAGE ELEMENTS AFTER PRIMARY ANIMATION [0:17]
%/<<animate =mainMenu     reset display     {{17*sec}}>>/%
%/<<animate =sidebar      reset display     {{17*sec}}>>/%
%/<<animate =storyMenu    reset display     {{17*sec}}>>/%
%/<<animate =siteTitle    reset display     {{17*sec}}>>/%
%/<<animate =siteSubtitle reset display     {{17*sec}}>>/%
%/<<animate =displayArea  reset marginLeft  {{17*sec}}>>/%
%/<<animate =displayArea  reset marginRight {{17*sec}}>>/%
%/<<animate =siteMenu     reset visibility  {{17*sec}}>>/%
%/<<animate =breadCrumbs  reset visibility  {{17*sec}}>>/%

SHOW CONTROL PANEL AND SOURCE DISPLAY [0:17 - 0:18.5] (END)
%/{{small{/%
	%/<<animate = set display none {{0*sec}}>>/%
	%/<<animate = set display inline {{17*sec}}>>/%
	%/{{selected{{{toolbar{/%
		%/{{fine{speed: }}}{{threechar smallform{<<option txtAnimationEffectsRate>>}}}/%
		%/{{medium{<<tiddler RefreshTiddler with: "replay" "restart animation sequence">>}}}/%
		%/<<animate = top %0px 200 0 {{17*sec}} {{1.5*sec}}>>/%
	%/}}}}}}/%
	%/{{block{/%
		%/{{green{''animation sequence completed''}}}
		//(see //[[AnimationEffectsPlugin]]// for macro definition/usage)// /%
		%/<<animate = left %0% 100 0 {{17*sec}} {{1.5*sec}}>>/%
	%/}}}/%
	%/{{smallform stretch center clear{/%
		%/<<tiddler AnimationEffectsSampler##showText
			with: {{store.getValue('AnimationEffectsSampler','text').htmlEncode()}}>>/%
!showText
<html><nowiki><div class='editor'><textarea readonly rows='20'>$1</textarea></div></html>
!end
		%/<<animate = left %0% -100 0 {{17*sec}} {{1.5*sec}}>>/%
	%/}}}/%
%/}}}/%

SHOW TIDDLER TITLE [0:17 - 0:18.5] (END)
%/<<tiddler ReplaceTiddlerTitle with:
   "~AnimationEffectsSampler\<\<animate div = left %0% -100 0 {{17*sec}\} {{1.5*sec}\}\>\>">>/%

SHOW VIEWER BACKGROUND [0:18]
%/<<animate = add viewer {{17.5*sec}}>>/%

%/}}}/% END OF CONTAINER FOR VIEWER BACKGROUND %/
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
----
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
[[AttachFilePlugin]] reads binary data from locally-stored files (e.g., images, PDFs, mp3's, etc.) and converts it to base64-encoded text that is stored in tiddlers tagged with<<tag attachment>>. [[AttachFilePluginFormatters]] allows you to use those tiddlers in place of the external path/file references that are normally part of the image and external links wiki syntax.

[[FileDropPlugin]] and [[FileDropPluginConfig]] allow you to quickly create attachment tiddlers simply by dragging files directly from your system's desktop folder display and dropping it onto an open TiddlyWiki document.  Text files are automatically created as simple tiddlers, while binary files are automatically encoded and attached.
/***
|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;
	}
}
//}}}
/***
|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)
<<<
!usage
{{{[img[AttachFileSample]]}}}
[img[AttachFileSample]]
!notes
example of encoded data attachment
!type
image/gif
!file
./images/meow.gif
!url
http://www.TiddlyTools.com/images/meow.gif
!data
data:image/gif;base64,R0lGODlhOABQAPcAAAAACAAAEAAICAgICAgLDBAQCAQQGRAIEBgICBAQEBAQGBAYFBoOEhwUFCEYEBgYGA4cIBkgGyEcHCEhISkYGCkcHCEpHCklIRAgMRkmNSElKSEpNikeKykpKSExQiE5QjEhJTEpITEpKSkpMSkxISk1KTExITExKSktNTEpMTEpOTExMSk5MSkxOSkxQik5PTkrKTkxMTE8KTFCMTExOTExQjE5PTFCPTk3MzlCMTkxQjk5QkI0MzlGPUg9M01JNi88TTlEUkI8REJCSkZDRFBDQkY/UFA/TjNMUkNOS1JKSkpWRj1KWEpKWj9OXEVZZlhMRlVLVVpSUlReUFdSYFVhX1JSa1VfbmBbU11ia2dcV3FjXVpldWVkb2tnb3tnbGZ1ZHV6aWVwe3d5c2N4iXN3gntzgHeBiYd2dYWHeoh/jIKLkJWEfZmUh5CNlJ+VkICPn46XpZiSo5WfoJycnKaemaGcqKWlpZWnraWtqa2qoq2lrZavvKW4xK2lta2ws/8A/7WcjLWllLWlpbWlrb2tnMatnLWtpbWtrb2trbWttb2ttbWtvbW1pca1pbW1ra21va21xrW1tbW1vbW1xrW9tb21rb21tb21vb21xr29rb29tca9sca1vc69rda9ra29wa3GxrW9vbW9xq29zrHGyrPB0rXG1r29vb29xr29zr3Gvb3Gxr3Gzr3G1sa9vcbGtc7GtdbGtcbGvc7GvdbGvd7Gvca9xsa9zsbGxsbGzsbG1s7DyNbGxtbGzs7G1rjQ2MbO0sbO3sbW1s7Owc7OzsbW3sbe3s7O1s7W0tbQx+HUzNDQ29bW1tvb1ufa1sPW6dDW4dbW3trY4sni7dbk797e3tbx9N7n3ufe3t7e597n597i7+fe597s9N73++fn3ufn5+fn7+fv5+fv7+/e5+/r4vfr4ufn9+fv9+fv/+/n7+/v8/Pz7/fv9+/v/+f3++f//+/39+/3/+//9+////f37/f39/f3//f/9/f////37//39//3////9////yH5BAEAAIAALAAAAAA4AFAAQAj+AAEJHEiwoMGDCBMqXIiwiA8tXbxIgXHhgY+FICSIiCFFihIeXRgm9OKlDJMqYs506UIDRIUKD7w8kLCiAw0q0ao8WCFhwgQqDx7E+EJHm0gpUaI0ibKDBo0dXeakazEkxYUOGjRMSQOmQw874eR9IHNPXrFba5Y8CLNDyYULGlZQRVjtzJCmTnew2AGp2j19gAGTC6ctnLvDZfWR07AjCJAd4fTduxctFapbiDKTQ7gjSZcsT6PQqLmCxhA78v4GnuxOHuGzeei8kVLkh5I1b9y80XPp0q1s+lK7E3eQjSIvbqJAEiPGjR0/c9REqyavtTx9rVtn09asmJsvbMb+uLlcrFn3YsqsiRM33M3CDlkUsWMnT978cM206Y/WjH+187cEGOArqKCiCCJ00DEHHXXkIdJBEgQVlEsS1iThAwlg+EAXcNgBySiQQILKJWOM8YYy2Tyo4oqA5HELMtxxVwyLNA5UxAUxxPBWjTjGIIIWNSKUhhddUFFFU0O89BZjQ9DQwYUPVKABCEJg8cYZK5aRxRNM0JDCCimkQMUONXUAwlVOKbGDGHhAMEczgemjTV2jXeCTBqZFoZASVDDRxGildTbHX3zUgJeTZ0Cimj5kBLHDEEM0IU59cd6TDmHm7WFQNHDAwcVoT5m2Qg2tAJPYau6wY01/2ohTjDb+Z91hhiK3FMiILnkcWIw1iLlz0BuPquHEFaDWtEMVclyXWpz1pUNONdKkkkoWyEGSqyKXvYJeNtmEo6pRCEkyaX3ykMPOYOWSw41+2rDTGjndNoMMMsXoUkw05SFzXnlnFaiIikpOIIEUbrzaSit+RPFWByK4ocoordzC74iKKHLGFmm4kQciQSIkgQQIIEAAAQ+Q/IDIIieQAAFROPcHI9heUodh2ujT8c0CzcEdt8Ph7DONGgwxxs+A7BADEUT4SOMEMWyBBRYiEA2ID16oYYYZDsXwQGNOMHGFFUz4ucMFND2qRBdmeDEE0Uq0IccWSuDQwdwXXrBCkxVFKOH+VVB8UceMNHohxhVNipDCEBqkoIGUTu70AA4P3PUEYG6cEQXiM0lwwRBryKNiF1dcwYQQDK+wQxZijGYmnk+tsEIVGrgTZ6VniMHUCHZ3EAWQCWlRxe+X47BCy8UEc08GcmfVwVUxLDHFECPoE01TTWhjTRQimBBDEW64QUYTZczBhBcJCTFEFKODSkMUZcAJWDWMjDJHGW4089df3DiRBRDgwzE7YPLgji5uIQmEzIMaeHgU+nbwqCaEaFEAXI82rqOav8gDLgOzjj5c9YpbXEIR2bjHLQ5yBjdw4QxjGs0OOvA6MQSjGrNLjX2akQ1U0KEMXlACDYh0uS3M4Q3+CeoAHbKBmHuE4yBJ6EEXUveomiBuCKhwA3AqOJmypIMb+ILEH1ChhTXoIUEbqwMiXsELZThjOOEgB8cO4gYqKOEMDNxhFKjQBFmFw4IAZM25uJOKMWyhi35gxFk6WAxnqOcw5wKcQdAgJz84shrVcIMfRpEOSMqjGtGoTnVSJY78dIcRf2ADFPwgsbM0Q2LmaRVmGNKGYmzSPvYxFzsqOZ12dSsbACrlq85Sq1sQ6EBrfBAReHI1baTjUuGIhjZ0UZkC3cI89CqPeQrkBzq4IQ1nWMOCCsijoPhgBUKoQstokJUJQOkBSlADJVqRimKgghEwe4MW0KCxZvisIif+QwCUMnShkD2ABmaQAyQoMYoCXYINdCgGcKRmEAkRQAErI4DKgiIHP/wBEoy4hDvN0wxfMXRFo7CXNYh4j492TBG7VJVJV1oQKDBUCzi6WZQuUAai+UAEPvDRBWikEaTxIGo/EwIP/igFH0hARZoTwRC+8AUtFEFqPlCCFryghZtSRE8H6cIOHnABH0iBWl4wwxGgupIiKUEIPqjAqKhihSY4igYjMGcHUrCDKIS1hFKTAlVFAwIq1W19NMCnhCRQgRBAAQ28SIPP1nCGNBTDaXfZQQoq8LGgYAVSILjQBC6wAyEQAQ11SFGNuvC7P+2ACXO4i+kipNYHdIBMppn+hxteRyYqCEwCOJDCHDyqIixoQQxuleyXojA3rFxgBK57ixcmcNozAOYeeAjCGWZiN7hM4AmjUFEVmpCFJrjuSxEhE1ZAYLq7KQFS0RjU/+5xhjI0YQcauEBesKoQM2QBUp113dzm4CjFZaVM8RWCGwA4u3sAowmq1cAE8GQF+iJECXNkwg6E11kmuCEdGSATCLISlyqAwXkQSI0TuACHdBTjDh0Agwmw0EAyiWElCilCEvDrlKfsoAzC0Ecc9uI6DXDVxxPwwgjuAQc8NSEa3UiDMnghu3v8oXZ3QIYX/KCQIdCxKYGiQhei8dw5tHEIXqjCHGAImHR8QAhAuEL+FsrwP8E0QxdwVogC71JjIXShFdcJDH6sUQxFQJAccHCvE87Qh0WVJRrhCJCBFEKNK0yYgZ3NwgrcAIl0zK414qAPAPPsXQvBSR7TrNiBJKGPNyAkGsbgA1NcxwLXuQEPwrA0s9wRDms8N1XuOOYQJLCF/ESDPwOsVR7glCoSliEOZWCgapNwJDm0AoKSqc49FEGFMtyhVqhIWArWoAgF5WEPLmqDfGTXM4M8oQxXSF2kxpSFHbTADX/wS6XIBatmSKILQzAcpMIkhTSo4Q1pGGM2NqmYg1xhd2sYTQqcdAEqJMENmSywJtnBnVsoopomagMQGVSHQVziFc1AETn+qmNPg1CBCkFwQxC+RKa71bUMsnvuZDRZrmog45138HKu6FCxzGhrVdkQRzhEexAiZRMFe2nSClB3B21AsIrycNav34lDN9wiDwW6TBmdEQ720NoaCTmDGqgghnbvQA7ppt8twnKq+rwLktHIgxbaAIU1+AEVxSgGL3hRSF5tkFt3QEgsdOyGO1zUDWVgxK/1lQ53jbwsnNzOKf2giDdAgQ54zzu/aLgePi9kMqZIRzBGMYpfV6PxlaxGu7BjH3FkwxqrwvYYftDO7jxTl2dBRBsYcongkKtcs4w63AszmGaIA1ZnyTtHzaN5iQVIEXpwj0iw4Abr1OdcFKcPu/T+I/lc8rJftapYbOrAItNhQRHyyLS5CMOffb0qGvqqV949WDE63MEN2qRDbGgUg+WtQARbdnr/cUq6wAg5NwfK1H7TdAl+kAd54AYYswYJ8gpBQllcNTdj4AWMEAxyAAE+JiFKIB6jcAvBUC8jAjNugAUmQgfBVCNBAVsLVwVZwAQPYE5Q8hZ/MAqM0AonqAiDoAXioQdEFyTnVIRBoTIJoAAg0AVyYAeRACIjgghh8AaoMFI+gyEhgwAJoE9QQgBaqAAvWAaBdBmXcQd1ACdl8VE6kk8ZsoVJCFEJMGl2MAdzADOv8AYdpQ+8wFIDUTIj44VBAQgeQlC1ogvNgAouykAHFMiHCkEJqtAK0rQqjKgipWcNvyE7k6gip8QOXTeEmcgQbAAI3VByNBIQAAA7
!usage
{{{[img[AttachFileSample2]]}}}
[img[AttachFileSample2]]
!notes
example of external attachment (no embedded data)
!type
image/jpg
!file
./images/meow2.jpg
!url
http://www.TiddlyTools.com/images/meow2.jpg
!data
/%
!info
|Name|AutoRefresh|
|Source|http://www.TiddlyTools.com/#AutoRefresh|
|Version|2.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Description|set/clear tiddler refresh flags to force/prevent re-rendering when changes occur|
Usage:
<<<
{{{
<<tiddler AutoRefresh>>
<<tiddler AutoRefresh with: mode id>>
}}}
*''mode'' (optional), one of:
**''off'' or ''disable'' - prevents refresh of rendered content (except when PageTemplate is changed!)
**''on'' or ''enable'' - re-render content whenever corresponding tiddler source is changed (default)
**''force'' - re-render content whenever //''ANY''// tiddler is changed
*''id'' (optional), is a unique DOM element identifier on which to operate (e.g., 'mainMenu').  If omitted, the current tiddler (if any) is implied.
<<<
!end
!show
<<tiddler {{
	var here=story.findContainingTiddler(place);
	var target=document.getElementById('$2')||here||place.parentNode;
	if (target==here) { // in a tiddler, get viewer element
		var elems=target.getElementsByTagName('*');
		for (var i=0;i<elems.length;i++)
			if (hasClass(elems[i],'viewer')) { target=elems[i]; break; }
	}
	if (target) {
		var mode='$1'; if (mode=='$'+'1') mode='on';
		if (['on','enable','force'].contains(mode.toLowerCase())) {
			var title=target.getAttribute('tiddler');
			if (!title&&here) title=here.getAttribute('tiddler');
			if (title) target.setAttribute('tiddler',title);
			target.setAttribute('refresh','content');
			target.setAttribute('force',(mode=='force')?'true':'');
		} else if (['off','disable'].contains(mode.toLowerCase())) {
			target.setAttribute('refresh','');
			target.setAttribute('force','');
		}
	}
'';}}>>
!end
%/<<tiddler {{var src='AutoRefresh'; src+(tiddler&&tiddler.title==src?'##info':'##show');}}
	with: [[$1]] [[$2]]>>
/***
|Name|AutoTaggerPlugin|
|Source|http://www.TiddlyTools.com/#AutoTaggerPlugin|
|Documentation|http://www.TiddlyTools.com/#AutoTaggerPluginInfo|
|Version|1.8.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|Tag tiddlers with date, author, etc. and/or scan the tiddler for any tags that are embedded in the content|
~AutoTagger ''automatically generates tag values for all newly created or edited tiddlers''
!!!!!Documentation
> see [[AutoTaggerPluginInfo]]
!!!!!Configuration
<<<
|<<option chkAutoTagAuthor>> add 'created by' author tag //(when a tiddler is first created)//||
|<<option chkAutoTagEditor>> add 'edited by' author tag //(when a tiddler is updated)//||
|<<option chkAutoTagDate>> add 'creation date' tag, using date format:|<<option txtAutoTagFormat>>|
|<<option chkAutoTagModDate>> add 'modification date' tag, using date format:|<<option txtAutoTagModFormat>>|
|<<option chkAutoTagNewTags>> add default tag(s) when creating new tiddlers:|<<option txtAutoTagNewTags>>|
|<<option chkAutoTagDefault>> add default tag(s) when saving tiddlers that are not otherwise tagged:|<<option txtAutoTagDefault>>|
|<<option chkAutoTagTrigger>> scan tiddler content for matching tags when tagged with:|<<option txtAutoTagTrigger>>|
|<<option chkAutoTagAliases>> replace 'aliased' tags using definitions contained in:|<<option txtAutoTagAliases>>|
|borderless|k
<<<
!!!!!Revisions
<<<
2010.06.30 1.8.0 in saveTiddler(), added extra checks for valid alias definitions
| Please see [[AutoTaggerPluginInfo]] for previous revision details |
2005.08.15 1.0.0 Initial Release
<<<
!!!!!Code
***/
//{{{
version.extensions.AutoTaggerPlugin= {major: 1, minor: 8, revision: 0, date: new Date(2010,6,30)};

var co=config.options; // shorthand temp variable
if (co.chkAutoTagDate==undefined) co.chkAutoTagDate=false;
if (co.chkAutoTagModDate==undefined) co.chkAutoTagModDate=false;
if (co.chkAutoTagEditor==undefined) co.chkAutoTagEditor=false;
if (co.chkAutoTagAuthor==undefined) co.chkAutoTagAuthor=false;
if (co.chkAutoTagTrigger==undefined) co.chkAutoTagTrigger=false;
if (co.txtAutoTagTrigger==undefined) co.txtAutoTagTrigger="auto";
if (co.chkAutoTagDefault==undefined) co.chkAutoTagDefault=false;
if (co.txtAutoTagDefault==undefined) co.txtAutoTagDefault="untagged";
if (co.txtAutoTagFormat==undefined) co.txtAutoTagFormat="YYYY.0MM.0DD";
if (co.txtAutoTagModFormat==undefined) co.txtAutoTagModFormat="YYYY.0MM.0DD";
if (co.chkAutoTagNewTags==undefined) co.chkAutoTagNewTags=false;
if (co.txtAutoTagNewTags==undefined) co.txtAutoTagNewTags="";
if (co.chkAutoTagAliases==undefined) co.chkAutoTagAliases=true;
if (co.txtAutoTagAliases==undefined) co.txtAutoTagAliases="AutoTaggerAliases";

// hijack displayTiddler()
Story.prototype.autotagger_displayTiddler=Story.prototype.displayTiddler;
Story.prototype.displayTiddler=function(srcElement,tiddler,template,animate,unused,customFields,toggle)
{
	var title=(tiddler instanceof Tiddler)?tiddler.title:tiddler;
        this.autotagger_displayTiddler.apply(this,arguments);
	if (!config.options.chkAutoTagNewTags) return; // IF add new tags is enabled
	if (!story.isDirty(title)) return; // AND tiddler is being edited
	if (store.tiddlerExists(title)) return; // AND tiddler doesn't exist
	var newtags=config.options.txtAutoTagNewTags.readBracketedList(); // get new tags
	for (var t=0; t<newtags.length; t++)
		story.setTiddlerTag(title,newtags[t],+1); // preload tag edit field
} 

// hijack saveTiddler()
TiddlyWiki.prototype.autotagger_SaveTiddler=TiddlyWiki.prototype.saveTiddler;
TiddlyWiki.prototype.saveTiddler=function(title,newTitle,newBody,modifier,modified,tags,fields)
{
	var co=config.options; // shorthand temp variable
	var newTags = [];
	if (tags) newTags = (typeof tags == "string") ? tags.readBracketedList() : tags;
	var txt=store.getTiddlerText(config.options.txtAutoTagAliases,'')
	if (config.options.chkAutoTagAliases && txt.length) {
		// replace tag aliases with one or more other tags
		var map={};
		var list=txt.split('\n');
		for (var i=0; i<list.length; i++) {
			var parts=list[i].split('=');
			var name=parts.shift(); var val=parts.join('=');
			if (val.length) map[name]=val.readBracketedList();
		}
		for (var a in map) if (newTags.contains(a)) {
			newTags.splice(newTags.indexOf(a),1); // remove alias
			for (var i=0; i<map[a].length; i++) // add replacements
				newTags.pushUnique(map[a][i]);
		}
	}
	var now=new Date().formatString(co.txtAutoTagFormat);
	if (co.chkAutoTagDate && (store.getTiddler(title)==undefined))
		if (newTitle!=now) newTags.pushUnique(now); // created date - don't add to journals
	if (co.chkAutoTagAuthor && (store.getTiddler(title)==undefined))
		newTags.pushUnique(co.txtUserName); // creator
	if (co.chkAutoTagEditor && store.getTiddler(title))
		newTags.pushUnique(co.txtUserName); // modifier
	if (co.chkAutoTagModDate && store.getTiddler(title))
		newTags.pushUnique(new Date().formatString(co.txtAutoTagModFormat)); // modified
	var allTags = store.getTags(); // scan content for tags
	if (co.chkAutoTagTrigger && co.txtAutoTagTrigger.length	&& newTags.contains(co.txtAutoTagTrigger))
		for (var t=0; t<allTags.length; t++) {
			if (allTags[t][0]=='systemConfig') continue; // don't add 'systemConfig'
			if ((newBody.indexOf(allTags[t][0])!=-1) || (newTitle.indexOf(allTags[t][0])!=-1))
				newTags.pushUnique(allTags[t][0]); // autotag
		}
	for (var t=0; t<newTags.length; t++)
		newTags[t]=String.encodeTiddlyLink(newTags[t]); // add brackets around tags
	if (!newTags.length && co.chkAutoTagDefault && co.txtAutoTagDefault.length)
		newTags.push(co.txtAutoTagDefault); // untagged - add default tag
	arguments[5]=newTags.join(" ");
	return this.autotagger_SaveTiddler.apply(this,arguments);
}
//}}}
/***
|Name|AutoTaggerPlugin|
|Source|http://www.TiddlyTools.com/#AutoTaggerPlugin|
|Documentation|http://www.TiddlyTools.com/#AutoTaggerPluginInfo|
|Version|1.8.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|documentation|
|Description|documentation for AutoTaggerPlugin|
~AutoTagger ''automatically generates tag values for all newly created or edited tiddlers''
!!!!!Usage
<<<
Whenever you //create a new tiddler//, ~AutoTagger can add various tags for you:
* original author
* creation date
* default tag(s) (pre-loaded into tiddler editor)
* default tag(s) (when saving tiddlers that are not otherwise tagged)
Whenever you //edit an existing tiddler//, ~AutoTagger can add various tags for you:
* most recent author
* modification date
* default tag(s) (when saving tiddlers that are not otherwise tagged)
If you enter ''//auto//'' as a tiddler tag value, ~AutoTagger ''scans the tiddler content'' (including title) for text that matches any existing tags, and ''automatically adds any embedded tags that it finds''.

You can also create a tiddler that defines a set of [[AutoTaggerAliases]] to ''replace a single tag with one or more alternative tags''.  The alias definitions use this format:
{{{
aliastag=tag1 tag2 tag3...
aliastag=tag4 tag5 tag6...
etc.
}}}
Notes:
* After the new tags have been added to the tiddler, they are treated just as if you had entered them by hand and can be edited to make any changes you want.
* As long as the "auto" tag is still present on a tiddler, ~AutoTagger will re-scan that tiddler's content each time it is edited.  If you DO edit the generated tags, you can remove the "auto" tag from the tiddler to prevent it from being re-scanned when you press 'done' to finish editing.  If you have set the "auto" tag on a tiddler, and then add several tags to your document, those tags will ''not'' be automatically added to the tiddler until you actually edit that tiddler and press 'done' to trigger an AutoTagger scan.  The special-purpose ''"systemConfig" tag is never added automatically, even if matched in the tiddler content'', since this tag should be added manually to ensure it is always used appropriately.
*@@display:inline;Normally, aliases are removed and replaced by the indicated alternatives defined in the [[AutoTaggerAliases]] configuration.  To retain an original alias tag (in addition to it's substitutes), include it in it's set of substitutes, like this:
{{{
aliastag=aliasgtag tag1 tag2 tag3...
}}}
@@
*@@display:inline;Alias definitions are processed in the order they occur in [[AutoTaggerAliases]].  If a given alias definition includes another alias that occurs after it in the configuration, the second alias will be replaced when it's definition is processed.
{{{
aliastag=tag1 anotheraliastag tag2...
anotheraliastag=tag3 tag4...
}}}
which results in: {{{tag1 tag2 tag3 tag4}}}
@@
<<<
!!!!!Configuration
<<<
|<<option chkAutoTagAuthor>> add 'created by' author tag //(when a tiddler is first created)//||
|{{{<<option chkAutoTagAuthor>>}}}||
|<<option chkAutoTagEditor>> add 'edited by' author tag //(when a tiddler is updated)//||
|{{{<<option chkAutoTagEditor>>}}}||
|<<option chkAutoTagDate>> add 'creation date' tag, using date format:|<<option txtAutoTagFormat>>|
|{{{<<option chkAutoTagDate>>}}}|{{{<<option txtAutoTagFormat>>}}}|
|<<option chkAutoTagModDate>> add 'modification date' tag, using date format:|<<option txtAutoTagModFormat>>|
|{{{<<option chkAutoTagModDate>>}}}|{{{<<option txtAutoTagModFormat>>}}}|
|<<option chkAutoTagNewTags>> add default tag(s) when creating new tiddlers:|<<option txtAutoTagNewTags>>|
|{{{<<option chkAutoTagNewTags>>}}}|{{{<<option txtAutoTagNewTags>>}}}|
|<<option chkAutoTagDefault>> add default tag(s) when saving tiddlers that are not otherwise tagged:|<<option txtAutoTagDefault>>|
|{{{<<option chkAutoTagDefault>>}}}|{{{<<option txtAutoTagDefault>>}}}|
|<<option chkAutoTagTrigger>> scan tiddler content for matching tags when tagged with:|<<option txtAutoTagTrigger>>|
|{{{<<option chkAutoTagTrigger>>}}}|{{{<<option txtAutoTagTrigger>>}}}|
|<<option chkAutoTagAliases>> replace 'aliased' tags using definitions contained in:|<<option txtAutoTagAliases>>|
|{{{<<option chkAutoTagAliases>>}}}|{{{<<option txtAutoTagAliases>>}}}|
|borderless|k
<<<
!!!!!Revisions
<<<
2010.06.30 1.8.0 in saveTiddler(), added extra checks for valid alias definitions
2008.03.29 1.7.1 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.27 1.7.0 added aliasing (using [[AutoTaggerAliases]] definition)
2008.03.11 [*.*.*] plugin size reduction - moved documentation to [[AutoTaggerPluginInfo]]
2007.10.18 1.6.0 hijack displayTiddler() to add option to use default tags when creating new tiddlers (preloads tag edit field).  Based on requests from RA and DavidWinfield.
2007.06.28 1.5.1 in hijack of saveChanges(), use apply() to allow additional params (such as "fields") to be correctly passed through to the core
2007.03.14 1.5.0 added support for tagging tiddlers with modification date
2007.01.20 1.4.1 don't add create date tag to dated journal tiddlers (based on request from ConalElliot)
2006.12.10 1.4.0 added option to use default tag value when no tags are specified
2006.08.29 1.3.3 use newTags.contains() instead of newTags.find() to check for 'auto' tag
2006.06.15 1.3.2 hijack TiddlyWiki.prototype.saveTiddler instead of store.saveTiddler.  Permits other plugins to also hijack the function (thanks to Simon Baird for finding this!)
2006.05.31 1.3.1 Re-assemble tags into a space-separated string (use encodeTiddlyLink to add {{{[[...]]}}} as needed) before passing it on to core (or other hijacked function)
2005.10.09 1.3.0 Added 'edited by' tagging. Combined documentation and code into a single tiddler
2005.08.16 1.2.0 Added optional scanning for tags in tiddler content (based on suggestion from Jacques Turbé)
2005.08.15 1.1.0 Added 'created by' tag generation (based on suggestion from Elise Springer). Renamed from DateTag to AutoTagger
2005.08.15 1.0.0 Initial Release
<<<
/***
!!!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; } \
	#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)
//}}}
/%
|''URL:''|http://tiddlywiki.bidix.info/|
|''Description:''|Repository for BidiX's TiddlyWiki Extensions|
|''Author:''|BidiX|
%/
/***
|Name|Blackout|
|Source|http://www.TiddlyTools.com/#Blackout|
|Version|1.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|CSS|
|Description|theme: black/blue-gray/gray backgrounds w/light text|
|StyleSheet|Blackout|
|PageTemplateReadOnly|PageTemplateReadOnly|
|EditTemplateReadOnly|EditTemplateReadOnly|
***/

[[StyleSheetAdjustments]]
[[BrightText]]
/* ==== blackout ==== */
/*{{{*/
body
	{ background-color:#000; }
.menubox
	{ background-color:#111; }
.annotation
	{ background-color: #111; }
.viewer
	{ background-color:#111; border: 1px solid #999; -moz-border-radius:1em;-webkit-border-radius:1em; padding:1em; }
.header
	{ background-image: none; background-color:transparent; color:#ccf; border:0; }
.floatingPanel, .attachPanel, #importPanel, #exportPanel,
	{ background: #eee; background-image: url('[[TexturesParchmentGray]]');}
.floatingPanel a, .attachPanel a, #messageArea a, #importPanel a, #exportPanel a, #sidebarTabs .tabContents a,
.floatingPanel .button, .attachPanel .button, #messageArea .button, #importPanel .button, #exportPanel .button, #sidebarTabs .tabContents .button,
.floatingPanel .tiddlyLinkExisting, .attachPanel .tiddlyLinkExisting, #messageArea .tiddlyLinkExisting, #importPanel .tiddlyLinkExisting, #exportPanel .tiddlyLinkExisting, #sidebarTabs .tabContents .tiddlyLinkExisting
	{ color:#009; }
.siteMenu .floatingPanel, #messageArea 
	{ background: #eee; }
.tiddlyCard { background:#ffd; }

.viewer h1,.viewer h2,.viewer h3,.viewer h4,.viewer h5 { background: #666; color:#fff; }
.viewer .tabContents, #sidebarTabs .tabContents
	{ background-color:#111; color:#fff; }
.tabContents a, .tabContents .button, .tabContents .tiddlyLinkExisting
	{ color:#99f; }
/*}}}*/
/%
|URL:|Enter a URL|
|Description:|enter a description|
|Author:|enter author/moderator info|
%/
enter your notes here
/%
|Description|enter FAQ list item text here|
%/
{{small{
__enter FAQ display title text here__

enter FAQ content here
}}}
/***
|Name|BlankPlugin|
|Source|http://www.TiddlyTools.com/#BlankPlugin|
|Documentation|http://www.TiddlyTools.com/#BlankPluginInfo|
|Version|0.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description||
Summary description of purpose
!!!!!Documentation
>see [[BlankPluginInfo]]
!!!!!Configuration
<<<
checkboxes and input fields for plugin-specific options
<<<
!!!!!Revisions
<<<
2007.01.01 [1.0.0] initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.PLUGINNAME= {major: 0, minor: 0, revision: 0, date: new Date(2008,1,1)};
//}}}
/%
|Name|BlankScript|
|Source|http://www.TiddlyTools.com/#BlankScript|
|Version|0.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|script|
|Requires|InlineJavascriptPlugin|
|Description||
%/<script>
	var here=story.findContainingTiddler(place); if (!here) return;
	var tid=store.getTiddler(here.getAttribute('tiddler'));
	var out="";
	// add code here >>>
	return out;
</script>
/%
!info
|Name|BookmarkList|
|Source|http://www.TiddlyTools.com/#BookmarkList|
|Version|2.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|Type|transclusion|
|Description|generate ~HR-separated list of tiddlers tagged with bookmark for use with MiniBrowser|
Usage
<<<
{{{
<<tiddler BookmarkList>>
<<miniBrowser BookmarkList>>
}}}
@@display:block;height:15em;overflow:auto;<<tiddler BookmarkList##show>>@@
<<<
!end

!out
$1
!end

!show
<<tiddler BookmarkList##out with: {{
	var out=["TiddlyWiki Servers\n"];
	var tids=store.getTaggedTiddlers("bookmark");
	for (var i=0; i<tids.length; i++) {
		var t=tids[i].title;
		var d=store.getTiddlerSlice(t,"Description");
		var u=store.getTiddlerSlice(t,"URL")
		out.push("[[%0]] - %1\n%2".format([t,d,u]));
	}
	out.join("\n----\n");
}}>>
!end

%/<<tiddler {{var src='BookmarkList'; src+(tiddler&&tiddler.title==src?'##info':'##show');}}>>
Tiddlers that are tagged with<<tag bookmark>>can be used to define ''~URLs, descriptions and author information for favorite websites''.

Bookmark tiddlers are displayed using a custom BookmarkViewTemplate (requires use of TaggedTemplateTweak), which automatically embeds the website directly in the tiddler content using an HTML "IFRAME" element.  Most (but not all) of the bookmarks distributed with this TiddlyTools package refer to TiddlyWiki documents and are also tagged with<<tag systemServer>>, allowing them to be selected as import sources when using the TiddlyWiki standard ImportTiddlers function.

To create additional bookmarks, simply copy the BlankBookmark tiddler, edit the URL, description, and author info, tag the new tiddler with<<tag bookmark>>and press 'done' to start viewing the remote URL.  Alternatively, you can add the following """<<newTiddler>>""" macro in your SideBarOptions (or any other tiddler) to insert a<<newTiddler label:'new bookmark' title:'NewBookmark' text:{{store.getTiddlerText('BlankBookmark','')}} tag:'bookmark' prompt:'create a bookmark tiddler'>>command into your document:
{{{
<<newTiddler label:'new bookmark' title:'NewBookmark' tag:'bookmark'
	text:{{store.getTiddlerText('BlankBookmark','')}}>>
}}}
<!--{{{-->
<!--
|Name|BookmarkViewTemplate|
|Source|http://www.TiddlyTools.com/#BookmarkViewTemplate|
|Version||
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|template|
|Requires|WikifyPlugin, TaggedTemplateTweak|
|Description|custom template used to display tiddlers tagged with "Bookmark"|

Usage:
Create a tiddler tagged with "bookmark" (or "Bookmark") and enter URL, description and author using a 'slice table':
	|URL:|Enter a URL|
	|Description:|enter a description|
	|Author:|enter author/moderator info|
-->
<span class='toolbar' macro='toolbar [[ToolbarCommands::ViewToolbar]]'></span>
<span class='title' macro='view title'></span>
<span class='subtitle' style='white-space:nowrap' macro='view modified date [[DDD, MMM DDth YYYY]]'></span>
<div class='tagClear'></div>
<div class='viewer'>
	<div class='floatleft' macro='wikify "{{big{[[%0|%1]]}}}<br>" here::Description here::URL'></div>
	<div class='toolbar'>
		<a class='button' href='javascript:;'
			onclick='window.history.go(-1);' title='go back one page'>back</a>
		<a class='button' href='javascript:;'
			onclick='window.history.go(+1);' title='go foward one page'>forward</a>
		<a class='button' href='javascript:;'
			onclick='var f=this.parentNode.parentNode.getElementsByTagName("iframe")[0];
			f.src=f.src'
			title='reload current page'>reload</a>
		<a class='button' href='javascript:;'
			onclick='var f=this.parentNode.parentNode.getElementsByTagName("iframe")[0];
				var w=prompt("Enter a new frame width (use px, em, cm, in, or %)","100%");
				if (!w||!w.length) return; if (!w.replace(/[0-9]*/,"").length) w+="px";
				f.style.width=w;'
			title='set frame width'>width</a>
		<a class='button' href='javascript:;'
			onclick='var f=this.parentNode.parentNode.getElementsByTagName("iframe")[0];
				var h=prompt("Enter a new frame height (use px, em, cm, or in)","500");
				if (!h||!h.length) return; if (!h.replace(/[0-9]*/,"").length) h+="px";
				f.style.height=h;'
			title='set frame height'>height</a>
		<a class='button' href='javascript:;'
			onclick='var f=this.parentNode.parentNode.getElementsByTagName("iframe")[0];
				var show=f.style.display=="none";
				f.style.display=show?"block":"none";
				this.innerHTML=show?"hide":"show";'
			title="toggle display of this frame (but DON'T reload content)">hide</a>
	</div><div class='tagClear'
		macro='wikify [[<html><iframe src="%0" height="500" width="100%" style="background:#fff"></iframe></html>]] here::URL'>
	</div>
	<div macro='view text wikified'></div>
</div>
<!--}}}-->
/%
!info
|Name|BreadcrumbsCommand|
|Source|http://www.TiddlyTools.com/#BreadcrumbsCommand|
|Version|2.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Requires|BreadcrumbsPlugin|
|Description|"crumbs" command displays current breadcrumbs list in a popup|
Usage
<<<
{{{
<<tiddler BreadcrumbsCommand>>
<<tiddler BreadcrumbsCommand with: label tip>>
}}}
<<<
Example
<<<
{{{<<tiddler BreadcrumbsCommand with: "crumbs">>}}}
<<tiddler BreadcrumbsCommand##show with: "crumbs">>
<<<
!end
!show
<html><nowiki><a href="javascript:;" class="TiddlyLink" title="$2"
	onclick="var p=Popup.create(this); if (!p) return;
		var d=createTiddlyElement(p,'div');
		d.style.whiteSpace='normal'; d.style.width='auto'; d.style.padding='2px';
		wikify('\<\<breadcrumbs [[\<html\>\<hr\>\</html\>]] [[<br>]]\>\>',d);
		Popup.show();
		event.cancelBubble=true;if(event.stopPropagation)event.stopPropagation();
		return false;
">$1</a></html>
!end
%/<<tiddler {{ var src='BreadcrumbsCommand'; src+(tiddler&&tiddler.title==src?'##info':'##show')}}
	with:	{{'$1'!='$'+'1'?'$1':'crumbs'}}
		{{'$2'!='$'+'2'?'$2':'tiddlers viewed during this session'}}>>
/***
|Name|BreadcrumbsPlugin|
|Author|Eric Shulman|
|Source|http://www.TiddlyTools.com/#BreadcrumbsPlugin|
|Documentation|http://www.TiddlyTools.com/#BreadcrumbsPluginInfo|
|Version|2.1.5|
|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
<<<
2012.06.10 2.1.5 refactored default options to eliminate global variable and use init() handling
| Please see [[BreadcrumbsPluginInfo]] for previous revision details |
2006.02.01 1.0.0 initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.BreadcrumbsPlugin = { major: 2, minor: 1, revision: 5, date: new Date(2012,6,10) };
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',
	options: {
		chkShowBreadcrumbs:		true,
		chkReorderBreadcrumbs:		true,
		chkCreateDefaultBreadcrumbs:	true,
		chkShowStartupBreadcrumbs:	false,
		chkBreadcrumbsReverse:		false,
		chkBreadcrumbsLimit:		false,
		txtBreadcrumbsLimit:		5,
		chkBreadcrumbsLimitOpenTiddlers:false,
		txtBreadcrumbsLimitOpenTiddlers:5,
		chkBreadcrumbsHideHomeLink:	false,
		chkBreadcrumbsSave:		false,
		txtBreadcrumbsHomeSeparator:	' | ',
		txtBreadcrumbsCrumbSeparator:	' > '
	},
	init: function() {
		merge(config.options,this.options,true);
	},
	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.5|
|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
<<<
2012.06.10 2.1.5 refactored default options to eliminate global variable and use init() handling
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|BrightText|
|Source|http://www.TiddlyTools.com/#BrightText|
|Version|1.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|CSS|
|Description|adjust font colors for use with dark backgrounds|
***/

/* background images */
/* colors and borders */
a, .button { color:#ccf; }
a:hover, .button:hover { color:#fff; }

#breadCrumbs { color:#ccc; }
#breadCrumbs a { color:#ccf; }
#titleLine { color: #fff; }
#titleLine a { color: #009900; }
.siteMenu { color: #fff; border:0;  }
.siteMenu a, .siteMenu .button, .siteMenu .tiddlyLink { color: #ccf; }
.storyMenu { color: #fff; border:0; }
.storyMenu a, .storyMenu .button, .storyMenu .tiddlyLink { color: #ccf; }
/*
#mainMenu { color: #fff; }
#mainMenu .tiddlyLink { color: #def; }
#mainMenu .tiddlyLink:hover { color: #fff; }
#mainMenu .externalLink { color: #def; }
#mainMenu .externalLink:hover { color: #fff; }
#mainMenu .button, #mainMenu A { color: #def; }
#mainMenu .button:hover, #mainMenu A:hover { color: #fff; }
*/
#messageArea { color: #006; }
#messageArea a:link, #messageArea a:visited { color: #006; }
#messageArea a:hover { color: #f00; }
#messageArea a:active { color: #006; }
#popup { color: #000; }
#popup a { color: #006; }
#popup .viewer a { color: #ccf; }
#popup a:hover { color: #006; }
#popup .viewer a:hover { color: #fff; }
#popup hr { color: #666; }
.tabContents { color: #000; }
.tiddler .button { color: #ccf; }
.tiddler .button:hover { color: #fff; }
.tiddler .button:active { color: #fff; }
.title { color: #def; }
.subtitle { color: #89a; }
.toolbar { color: #aaa; }
.footer { color: #888; }
.selectedTiddler .footer { color: #ddd; }
.annotation { color:#ddd; }
.annotation a:link, .annotation a:visited { color: #ccf; }
.annotation a:hover { color: #fff; }
.viewer { color: #fff; }
.viewer a:link, .viewer a:visited { color: #ccf; }
.viewer a:hover { color: #fff; }
.viewer .button { color: #def; }
.viewer .button:hover { color: #fff; }
.viewer th { color: #fff; }
.viewer td { color: #fff; }
.viewer code { color: #ccc; }
.viewer pre { color: #000; }
.viewer hr { color: #666; }
.viewer .highlight, .viewer .marked { color: #fff; }
.viewer .tabSelected { background-color: #002; color:#fff; border-color:#999; border-width:1px; padding-bottom:1px !important; }
.viewer .tabUnselected { background-color: transparent; color:#999; border-color:#666}
.viewer .tabContents { background-color: #002; color:#fff; border-color:#999; border-width:1px }
.tagging a, .tagged a, .tagging .button, .tagged .button  { color: #009; }
.highlight, .marked { color: #fff; }
.lowlight a { color: #009 !important; }
.editor { color: #402C74; }
.editorFooter { color: #aaa; }
.editorFooter A { color: #930; }
.editorFooter A:hover { color: #cf6; }
.editorFooter A:active { color: #fff; }
#licensePanel A { color: #66f; }
#licensePanel A:hover { color: #fff; }
#licensePanel A:active { color: #fff; }
.errorNoSuchMacro { color: #ff0; }
.zoomer { color: #fff; }

.mouseover 
	{color:#336 !important;}
.mouseover a
	{color:#336 !important;}
.selected .mouseover
	{color:#ccf !important;}
.selected .mouseover .button, .selected .mouseover a
	{color:#ccf !important;}

.selected .mouseover .moveablePanelButton
	{color:#000 !important;}

.floatingPanel .button,
.floatingPanel a:link,
.floatingPanel a:hover,
.floatingPanel a:visited,
.selected .floatingPanel .button,
.selected .floatingPanel a:link,
.selected .floatingPanel a:hover,
.selected .floatingPanel a:visited,
.toolbar .floatingPanel .button,
.toolbar .floatingPanel a:link,
.toolbar .floatingPanel a:hover,
.toolbar .floatingPanel a:visited,
.viewer .floatingPanel .button,
.viewer .floatingPanel a:link,
.viewer .floatingPanel a:hover,
.viewer .floatingPanel a:visited {
	color: #009 !important;
}
.floatingPanel .viewer .button,
.floatingPanel .viewer a:link,
.floatingPanel .viewer a:visited {
	color: #ccf !important;
}
.floatingPanel a:hover,
.viewer .floatingPanel a:hover {
	color: #fff !important;
}
/***
----
***/
/*{{{*/
.attachPanel a, #importPanel a, #exportpanel a,
.attachPanel .button, #importPanel .button, #exportpanel .button,
.attachPanel .tiddlyLinkExisting, #importPanel .tiddlyLinkExisting, #exportpanel .tiddlyLinkExisting,
.attachPanel .tiddlyLinkNonExisting, #importPanel .tiddlyLinkNonExisting, #exportpanel .tiddlyLinkNonExisting,
.tab .button, .tab A,
.tab .tiddlyLinkExisting, .tab .tiddlyLinkNonExisting
	{ color:#009 !important; }
#sidebarOptions, #sidebarOptions .sliderPanel
	{ color: #fff; }
#sidebarOptions .button, #sidebarOptions A,
#sidebarOptions .tiddlyLinkExisting, #sidebarOptions .tiddlyLinkNonExisting,
#sidebarOptions .sliderPanel .button, #sidebarOptions .sliderPanel A,
#sidebarOptions .sliderPanel .tiddlyLinkExisting, #sidebarOptions .sliderPanel .tiddlyLinkNonExisting
	{ color: #def; }
#sidebarTabs, #sidebarTabs .sliderPanel, #sidebarTabs .tabContents
	{ color: #fff; }
#sidebarTabs .tabContents *[class="TOCList"] /* MOZ ONLY */
	{ color:#fff !important; }
#sidebarTabs .button, /* #sidebarTabs A, */
#sidebarTabs .tiddlyLinkExisting, #sidebarTabs .tiddlyLinkNonExisting
	{ color: #def; }
.menubox
	{ color:#fff; border-color:#999; }
.menubox .button, .menubox .tiddlyLinkExisting, .menubox .tiddlyLinkNonExisting
	{ color:#99f !important; }
.QOTD
	{ color:#fff !important; background:inherit !important; }
.groupbox, .groupbox table, .groupbox tbody, .groupbox tr, .groupbox td
	{ color:#000; }
.groupbox a, .groupbox .button, .groupbox .tiddlyLinkExisting, .groupbox .tiddlyLinkNonExisting
	{ color:#009 !important; }
.outline
	{ border-color:#999; }
.floatingPanel, .floatingPanel table, .floatingPanel tbody, .floatingPanel tr, .floatingPanel td
	{ color:#000; }
.toolbar {color:#336 !important;}
.toolbar a {color:#336 !important;}
.selected .toolbar { color:#999 !important; }
.selected .toolbar a {color:#ccf !important;}
.selected .toolbar a:hover {color:#fff !important; }
/*}}}*/
<!--{{{-->
<!--
|Name|CDEditTemplate|
|Source|http://www.TiddlyTools.com/#CDEditTemplate|
|Version||
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|template|
|Requires|ToolbarCommands|
|Description|custom version of edit template used when tiddler is tagged with "CD"|
-->
<span class='toolbar' macro='toolbar +saveTiddler -cancelTiddler ! copyTiddler deleteTiddler ! fields '></span>
<div class='title' macro='view title'></div>
<div style='clear:both'></div>
<div class='viewer'>

<div class='editor' macro='edit title'></div>
<div class='borderless'><span class='small'>album title:</span></div>
<div class='editor' macro='edit albumtitle'></div>
<table class='borderless'><tr>
<td style='width:50%' style='width:100%'>
	<div class='small'>artist:</div>
	<div class='editor' macro='edit artist'></div>
</td><td style='width:10%'>
	<div class='small'>year:</div>
	<div class='editor' macro='edit year'></div>
</td><td style='width:20%'>
	<div class='small'>genre:</div>
	<div class='editor' macro='select genre rows:1 width:100% allowBlank allowOther +CDGenreList allowEdit'></div>
</td><td style='width:20%'>
	<div class='small'>media type:</div>
	<div class='editor' macro='select mediatype rows:1 width:100% allowBlank allowOther cd dvd mp3 cassette lp'></div>
</td></tr></table>
<table class='borderless' style='width:100%'><tr>
<td style='width:33%'>
	<div class='small'>cover image URL (jpg/gif):</div>
	<div class='editor' macro='edit cover'></div>
</td><td style='width:33%'>
	<div class='small'>sample URL (mp3):</div>
	<div class='editor' macro='edit sample'></div>
</td><td style='width:33%'>
	<div class='small'>website URL (html):</div>
	<div class='editor' macro='edit website'></div>
</td></tr></table>
<div class='small borderless'><span class='small'>notes (text):</span></div>
<div class='editor' macro='edit text 10'></div>
<div class='editor' macro='edit tags'></div>
<div class='toolbar editorFooter' style='text-align:left !important;float:left !important'>
	<span macro='message views.editor.tagPrompt'></span>
	<span macro='tagChooser'></span>
</div>
<div style='clear:both'></div>

</div><!-- viewer -->
<!--}}}-->
----
|borderless|k
|1 [[Candlelight|http://www.TiddlyTools.com/vlh/MFSB4/Candlelight.m3u]] (7:50) | &nbsp;&nbsp; |5 [[Fuego|http://www.TiddlyTools.com/vlh/MFSB4/Fuego.m3u]] (7:40) | |
|2 [[Kindling|http://www.TiddlyTools.com/vlh/MFSB4/Kindling.m3u]] (8:17) | |6 [[Flare|http://www.TiddlyTools.com/vlh/MFSB4/Flare.m3u]] (6:46) |
|3 [[Hearth|http://www.TiddlyTools.com/vlh/MFSB4/Hearth.m3u]] (7:14) | |7 [[Cold Fusion|http://www.TiddlyTools.com/vlh/MFSB4/ColdFusion.m3u]] (7:57) |
|4 [[Magma|http://www.TiddlyTools.com/vlh/MFSB4/Magma.m3u]] (8:35) | |8 [[Embers|http://www.TiddlyTools.com/vlh/MFSB4/Embers.m3u]] (7:52) |

{{fine block{
//All songs performed by Vernon L Hohenstein, except drum sequencing on "Kindling" by Eric Shulman.
Recorded at The Nano Studio, Sunnyvale, California USA.  Production/Sound Engineering by Eric Shulman.
(c) 2005 ''Made in U.S.A - all rights reserved'' Cover Photo: Yosemite National Park (c) 2002.//}}}
<!--{{{-->
<!--
|Name|CDViewTemplate|
|Source|http://www.TiddlyTools.com/#CDViewTemplate|
|Version||
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|template|
|Requires|ToolbarCommands|
|Description|custom version of view template used when tiddler is tagged with "CD"|
-->
<span class='toolbar' macro='toolbar [[ToolbarCommands::ViewToolbar]]'></span>
<span class='title'>
	<span class='floatleft' macro='tiddlerIcons' style='cursor:auto !important;'></span>
	<span macro='view title'></span>
</span>
<span class='subtitle'>
	<span style='white-space:nowrap' macro='view modified date [[DDD, MMM DDth YYYY]]'></span>
</span>
<div class='tagClear'></div>
<div class='viewer'>
	<div class='menubox' style='float:left;margin:1em' macro='wikify [img[%0]] cover@here'></div> 
	<div class='menubox'>
		<div class='big' macro='view albumtitle wikified'></div> 
		<div><span macro='view artist wikified'></span> - &copy; <span macro='view year wikified'></span></div>
	</div>
	<div>
		<span class='small'><i>genre:</i></span>
		<span macro='view genre wikified'></span>
	</div>
	<div>
		<span class='small'><i>media type:</i></span>
		<span macro='view mediatype wikified'></span>
	</div>
	<div><span class='small'><i>sample:</i> </span><span macro='view sample wikified'></span></div>
	<div><span class='small'><i>website:</i> </span><span macro='view website wikified'></span></div>
	<div class='small' macro='view text wikified'></div>
</div>
<div class='tagClear'></div>
<!--}}}-->
/***
|Name|CalendarPlugin|
|Source|http://www.TiddlyTools.com/#CalendarPlugin|
|Version|1.5.1|
|Author|Eric Shulman|
|Original Author|SteveRumsby|
|License|unknown|
|~CoreVersion|2.1|
|Type|plugin|
|Description|display monthly and yearly calendars|
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:'#ccccff',
	weekendbg:'#c0c0c0',
	monthbg:'#e0e0e0',
	holidaybg:'#ffc0c0',
	journalDateFmt:'DD MMM YYYY',
	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=6;
config.options.txtCalStartOfWeekend=5;
//}}}

// // override internal default settings for CalendarPlugin:
//{{{
config.macros.calendar.journalDateFmt="DDD MMM 0DD YYYY";
//}}}
/%

TiddlyTools Catalog - PLEASE DO NOT COPY

%/<<tabs "txtCatalogTab"
	"summary" "tiddler statistics and news" SiteSummary
	"quickstart" "download documents with pre-installed packages" QuickStart
	"plugins" "extensions to TiddlyWiki standard features" CatalogTabs##plugins 
	"transclusions" "tiddlers that can be embedded in other tiddlers" CatalogTabs##transclusions
	"packages" "tiddlers grouped by '...Package' tags for easy import" CatalogTabs##packages 
	"tags" "overview of document tags" CatalogTabs##tags
	"themes" "templates and stylesheets for custom page/tiddler layout and features" CatalogTabs##themes 
	"bookmarks" "favorite websites embedded in tiddlers" CatalogTabs##bookmarks
>><<tiddler HideTiddlerBackground>><<tiddler HideTiddlerTags>>/%

!plugins
{{fine{
+++{{floatright{[view plugin manager...]}}}...
	{{groupbox clear{{{small scrollbars height25em{<<plugins>><script>
		place.lastChild.firstChild.style.width="95%"
	</script>}}}}}}{{right{
scroll for more...}}}===
<<tiddlerIcons systemConfig>> There are <script>return store.getTaggedTiddlers("systemConfig").length.toString();</script> plugin tiddlers (tagged with<<tag systemConfig>>)
<<tiddlerIcons pluginInfo>> There are <script>return store.getTaggedTiddlers("pluginInfo").length.toString();</script> plugin documentation tiddlers (tagged with<<tag pluginInfo>>)}}}{{fine scrollbars height25em{
<<grid inline wikify edit
	columns:[[Description Version TiddlerSize]]
	tags:[[systemConfig pluginInfo]] width:95%
>>}}}{{right{
^^scroll for more...^^}}}
!end

!transclusions
{{fine{
These <script>return store.getTaggedTiddlers("transclusion").length.toString();</script> "transclusion tiddlers" use the ''"""<<tiddler TiddlerName with: param param param...>>"""'' macro to embed dynamically-generated output and/or other scripted functionality into your tiddler content.

//Note: Unlike plugins, transclusions are only applied if they are *rendered* somewhere in your document.  To ensure that a transclusion will be always invoked, you can embed it in a tiddler that is displayed whenever the document is loaded, such as //MainMenu//, //SideBarOptions//, or any tiddler listed in //DefaultTiddlers//).  You can hide any unwanted output from an embedded transclusion by enclosing it within a little bit of CSS, like this:// {{{@@display:none;<<tiddler TiddlerName with: param param ...>>@@}}}.}}}{{fine scrollbars height25em{
<<grid inline wikify edit columns:[[Description TiddlerSize]] tags:transclusion width:90%>>}}}{{right{
^^scroll for more...^^}}}
!end

!packages
{{floatleft{<<tiddlerIcons tag>>}}} {{fine{
Special "...Package" tags have been used to define specific collections of plugins, scripts, themes, etc. so you can easily select the particular feature enhancements that you want to import into your own documents.  //Please view individual package definitions below for descriptions and installation instructions.//
}}}{{smallform{<<faqViewer package outline +title " ">>}}}
!end

!tags
{{fine{
| [[Tag Grid|TagGridPlugin]] | [[Tag Cloud|TagCloudPlugin]] |
| //cross-index of tags from:// FavoriteTags | //frequently used tags are shown with larger font// |
| <html><hr></html> | <html><hr></html> |
| <<tagGrid +FavoriteTags +FavoriteTags ffffff 333333 colorAll sortrows sortcolumns>> | {{normal{<<cloud tags excludeMissing excludeLists excludeSearch demotag alpha test>>}}} |
|borderless|k
}}}
!end

!themes
{{floatright center fine borderleft{
&nbsp; current theme:
&nbsp; <<switchTheme width:auto>>
|borderless|k
|&nbsp;&nbsp;&nbsp;<<option chkRandomTheme>>| select a random<br>theme at startup |
}}}{{fine{
There are <script>return store.filterTiddlers("[tag[systemTheme]][tag[CSS]][tag[template]]").length.toString();</script> tiddlers tagged with <<tiddlerIcons CSS>><<tag CSS>>, <<tiddlerIcons template>><<tag template>>, or<<tag systemTheme>>.  These tiddlers define sets of alternative CSS styles and page/tiddler layouts for your document.  Use the droplist control on the right (see [[SwitchThemePlugin]]) to quickly select from the available themes to match your personal style or current mood!  //Note: Many themes and related stylesheets, templates, and image attachments, as well as needed utility plugins, have been tagged with//<<tag ThemePackage>>//so you can quickly install these themes in your own documents using //[[ImportTiddlersPlugin]]}}}{{fine scrollbars height25em{
<<grid inline wikify edit columns:[[Description =tags]] tags:[[systemTheme CSS template]] width:95%>>}}}{{right{
^^scroll for more...^^}}}
!end

!bookmarks
{{floatleft{<<tiddlerIcons bookmark>>}}} {{fine{
There are <script>return store.getTaggedTiddlers("bookmark").length.toString();</script> tiddlers tagged with<<tag bookmark>>, each containing a //slice table// that define the ''~URLs, descriptions and author information for some popular ~TiddlyWiki-related websites''

Bookmark tiddlers are displayed using BookmarkViewTemplate, which automatically embeds the website directly in the tiddler content using an HTML "IFRAME" element.  Most (but not all) bookmarks refer to TiddlyWiki documents and are also tagged with<<tag systemServer>>, allowing them to be selected as import sources when [[ImportTiddlers]].  Select tiddlers tagged with<<tag BookmarkPackage>> to install these bookmarks (and supporting templates/plugins) into your own document.  ''To create more bookmarks, copy the BlankBookmark tiddler, edit the URL, description, and author info, tag the new tiddler with<<tag bookmark>>, and press 'done' to start viewing the remote URL.''}}}{{fine scrollbars height25em{
<<grid inline wikify edit columns:[[Description Author URL]] tags:bookmark width:95%>>}}}{{right{
^^scroll for more...^^}}}
!end
%/
/***
|Name|CheckboxPlugin|
|Source|http://www.TiddlyTools.com/#CheckboxPlugin|
|Documentation|http://www.TiddlyTools.com/#CheckboxPluginInfo|
|Version|2.4.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|Add checkboxes to your tiddler content|
This plugin extends the TiddlyWiki syntax to allow definition of checkboxes that can be embedded directly in tiddler content.  Checkbox states are preserved by:
* by setting/removing tags on specified tiddlers,
* or, by setting custom field values on specified tiddlers,
* or, by saving to a locally-stored cookie ID,
* or, automatically modifying the tiddler content (deprecated)
When an ID is assigned to the checkbox, it enables direct programmatic access to the checkbox DOM element, as well as creating an entry in TiddlyWiki's config.options[ID] internal data.  In addition to tracking the checkbox state, you can also specify custom javascript for programmatic initialization and onClick event handling for any checkbox, so you can provide specialized side-effects in response to state changes.
!!!!!Documentation
>see [[CheckboxPluginInfo]]
!!!!!Revisions
<<<
2008.01.08 [*.*.*] plugin size reduction: documentation moved to [[CheckboxPluginInfo]]
2008.01.05 [2.4.0] set global "window.place" to current checkbox element when processing checkbox clicks.  This allows init/beforeClick/afterClick handlers to reference RELATIVE elements, including using "story.findContainingTiddler(place)".  Also, wrap handlers in "function()" so "return" can be used within handler code.
|please see [[CheckboxPluginInfo]] for additional revision details|
2005.12.07 [0.9.0] initial BETA release
<<<
!!!!!Code
***/
//{{{
version.extensions.CheckboxPlugin = {major: 2, minor: 4, revision:0 , date: new Date(2008,1,5)};
//}}}
//{{{
config.checkbox = { refresh: { tagged:true, tagging:true, container:true } };
config.formatters.push( {
	name: "checkbox",
	match: "\\[[xX_ ][\\]\\=\\(\\{]",
	lookahead: "\\[([xX_ ])(=[^\\s\\(\\]{]+)?(\\([^\\)]*\\))?({[^}]*})?({[^}]*})?({[^}]*})?\\]",
	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) {
			// get params
			var checked=(lookaheadMatch[1].toUpperCase()=="X");
			var id=lookaheadMatch[2];
			var target=lookaheadMatch[3];
			if (target) target=target.substr(1,target.length-2).trim(); // trim off parentheses
			var fn_init=lookaheadMatch[4];
			var fn_clickBefore=lookaheadMatch[5];
			var fn_clickAfter=lookaheadMatch[6];
			var tid=story.findContainingTiddler(w.output);  if (tid) tid=tid.getAttribute("tiddler");
			var srctid=w.tiddler?w.tiddler.title:null;
			config.macros.checkbox.create(w.output,tid,srctid,w.matchStart+1,checked,id,target,config.checkbox.refresh,fn_init,fn_clickBefore,fn_clickAfter);
			w.nextMatch = lookaheadMatch.index + lookaheadMatch[0].length;
		}
	}
} );
config.macros.checkbox = {
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		if(!(tiddler instanceof Tiddler)) { // if no tiddler passed in try to find one
			var here=story.findContainingTiddler(place);
			if (here) tiddler=store.getTiddler(here.getAttribute("tiddler"))
		}
		var srcpos=0; // "inline X" not applicable to macro syntax
		var target=params.shift(); if (!target) target="";
		var defaultState=params[0]=="checked"; if (defaultState) params.shift();
		var id=params.shift(); if (id && !id.length) id=null;
		var fn_init=params.shift(); if (fn_init && !fn_init.length) fn_init=null;
		var fn_clickBefore=params.shift();
		if (fn_clickBefore && !fn_clickBefore.length) fn_clickBefore=null;
		var fn_clickAfter=params.shift();
		if (fn_clickAfter && !fn_clickAfter.length) fn_clickAfter=null;
		var refresh={ tagged:true, tagging:true, container:false };
		this.create(place,tiddler.title,tiddler.title,0,defaultState,id,target,refresh,fn_init,fn_clickBefore,fn_clickAfter);
	},
	create: function(place,tid,srctid,srcpos,defaultState,id,target,refresh,fn_init,fn_clickBefore,fn_clickAfter) {
		// create checkbox element
		var c = document.createElement("input");
		c.setAttribute("type","checkbox");
		c.onclick=this.onClickCheckbox;
		c.srctid=srctid; // remember source tiddler
		c.srcpos=srcpos; // remember location of "X"
		c.container=tid; // containing tiddler (may be null if not in a tiddler)
		c.tiddler=tid; // default target tiddler 
		c.refresh = {};
		c.refresh.container = refresh.container;
		c.refresh.tagged = refresh.tagged;
		c.refresh.tagging = refresh.tagging;
		place.appendChild(c);
		// set default state
		c.checked=defaultState;
		// track state in config.options.ID
		if (id) {
			c.id=id.substr(1); // trim off leading "="
			if (config.options[c.id]!=undefined)
				c.checked=config.options[c.id];
			else
				config.options[c.id]=c.checked;
		}
		// track state in (tiddlername|tagname) or (fieldname@tiddlername)
		if (target) {
			var pos=target.indexOf("@");
			if (pos!=-1) {
				c.field=pos?target.substr(0,pos):"checked"; // get fieldname (or use default "checked")
				c.tiddler=target.substr(pos+1); // get specified tiddler name (if any)
				if (!c.tiddler || !c.tiddler.length) c.tiddler=tid; // if tiddler not specified, default == container
				if (store.getValue(c.tiddler,c.field)!=undefined)
					c.checked=(store.getValue(c.tiddler,c.field)=="true"); // set checkbox from saved state
			} else {
				var pos=target.indexOf("|"); if (pos==-1) var pos=target.indexOf(":");
				c.tag=target;
				if (pos==0) c.tag=target.substr(1); // trim leading "|" or ":"
				if (pos>0) { c.tiddler=target.substr(0,pos); c.tag=target.substr(pos+1); }
				if (!c.tag.length) c.tag="checked";
				var t=store.getTiddler(c.tiddler);
				if (t && t.tags)
					c.checked=t.isTagged(c.tag); // set checkbox from saved state
			}
		}
		// trim off surrounding { and } delimiters from init/click handlers
		if (fn_init) c.fn_init="(function(){"+fn_init.trim().substr(1,fn_init.length-2)+"})()";
		if (fn_clickBefore) c.fn_clickBefore="(function(){"+fn_clickBefore.trim().substr(1,fn_clickBefore.length-2)+"})()";
		if (fn_clickAfter) c.fn_clickAfter="(function(){"+fn_clickAfter.trim().substr(1,fn_clickAfter.length-2)+"})()";
		c.init=true; c.onclick(); c.init=false; // compute initial state and save in tiddler/config/cookie
	},
	onClickCheckbox: function(event) {
		window.place=this;
		if (this.init && this.fn_init) // custom function hook to set initial state (run only once)
			{ try { eval(this.fn_init); } catch(e) { displayMessage("Checkbox init error: "+e.toString()); } }
		if (!this.init && this.fn_clickBefore) // custom function hook to override changes in checkbox state
			{ try { eval(this.fn_clickBefore) } catch(e) { displayMessage("Checkbox onClickBefore error: "+e.toString()); } }
		if (this.id)
			// save state in config AND cookie (only when ID starts with 'chk')
			{ config.options[this.id]=this.checked; if (this.id.substr(0,3)=="chk") saveOptionCookie(this.id); }
		if (this.srctid && this.srcpos>0 && (!this.id || this.id.substr(0,3)!="chk") && !this.tag && !this.field) {
			// save state in tiddler content only if not using cookie, tag or field tracking
			var t=store.getTiddler(this.srctid); // put X in original source tiddler (if any)
			if (t && this.checked!=(t.text.substr(this.srcpos,1).toUpperCase()=="X")) { // if changed
				t.set(null,t.text.substr(0,this.srcpos)+(this.checked?"X":"_")+t.text.substr(this.srcpos+1),null,null,t.tags);
				if (!story.isDirty(t.title)) story.refreshTiddler(t.title,null,true);
				store.setDirty(true);
			}
		}
		if (this.field) {
			if (this.checked && !store.tiddlerExists(this.tiddler))
				store.saveTiddler(this.tiddler,this.tiddler,"",config.options.txtUserName,new Date());
			// set the field value in the target tiddler
			store.setValue(this.tiddler,this.field,this.checked?"true":"false");
			// DEBUG: displayMessage(this.field+"@"+this.tiddler+" is "+this.checked);
		}
		if (this.tag) {
			if (this.checked && !store.tiddlerExists(this.tiddler))
				store.saveTiddler(this.tiddler,this.tiddler,"",config.options.txtUserName,new Date());
			var t=store.getTiddler(this.tiddler);
			if (t) {
				var tagged=(t.tags && t.tags.indexOf(this.tag)!=-1);
				if (this.checked && !tagged) { t.tags.push(this.tag); store.setDirty(true); }
				if (!this.checked && tagged) { t.tags.splice(t.tags.indexOf(this.tag),1); store.setDirty(true); }
			}
			// if tag state has been changed, update display of corresponding tiddlers (unless they are in edit mode...)
			if (this.checked!=tagged) {
				if (this.refresh.tagged) {
					if (!story.isDirty(this.tiddler)) // the TAGGED tiddler in view mode
						story.refreshTiddler(this.tiddler,null,true); 
					else // the TAGGED tiddler in edit mode (with tags field)
						config.macros.checkbox.refreshEditorTagField(this.tiddler,this.tag,this.checked);
				}
				if (this.refresh.tagging)
					if (!story.isDirty(this.tag)) story.refreshTiddler(this.tag,null,true); // the TAGGING tiddler
			}
		}
		if (!this.init && this.fn_clickAfter) // custom function hook to react to changes in checkbox state
			{ try { eval(this.fn_clickAfter) } catch(e) { displayMessage("Checkbox onClickAfter error: "+e.toString()); } }
		// refresh containing tiddler (but not during initial rendering, or we get an infinite loop!) (and not when editing container)
		if (!this.init && this.refresh.container && this.container!=this.tiddler)
			if (!story.isDirty(this.container)) story.refreshTiddler(this.container,null,true); // the tiddler CONTAINING the checkbox
		return true;
	},
	refreshEditorTagField: function(title,tag,set) {
		var tagfield=story.getTiddlerField(title,"tags");
		if (!tagfield||tagfield.getAttribute("edit")!="tags") return; // if no tags field in editor (i.e., custom template)
		var tags=tagfield.value.readBracketedList();
		if (tags.contains(tag)==set) return; // if no change needed
		if (set) tags.push(tag); // add tag
		else tags.splice(tags.indexOf(tag),1); // remove tag
		for (var t=0;t<tags.length;t++) tags[t]=String.encodeTiddlyLink(tags[t]);
		tagfield.value=tags.join(" "); // reassemble tag string (with brackets as needed)
		return;
	}
}
//}}}
|Name|CheckboxPluginInfo|
|Source|http://www.TiddlyTools.com/#CheckboxPlugin|
|Documentation|http://www.TiddlyTools.com/#CheckboxPluginInfo|
|Version|2.4.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|documentation|
|Description|documentation for CheckboxPlugin|
This plugin extends the TiddlyWiki syntax to allow definition of checkboxes that can be embedded directly in tiddler content.  Checkbox states are preserved by:
* setting/removing tags on specified tiddlers,
* or, setting custom field values on specified tiddlers,
* or, saving to a locally-stored cookie ID,
* or, automatically modifying the tiddler source content (deprecated).
When an ID is assigned to the checkbox, it enables direct programmatic access to the checkbox DOM element, as well as creating an entry in TiddlyWiki's config.options[ID] internal data.  In addition to tracking the checkbox state, you can also specify custom javascript for programmatic initialization and onClick event handling for any checkbox, so you can provide specialized side-effects in response to state changes.
!!!!!Inline (wiki syntax) Usage
<<<
//{{{
[ ]or[_] and [x]or[X]
//}}}
Simple checkboxes using 'Inline X' storage.  The current unchecked/checked state is indicated by the character between the {{{[}}} and {{{]}}} brackets ("_" means unchecked, "X" means checked).  When you click on a checkbox, the current state is retained by directly modifying the tiddler content to place the corresponding "_" or "X" character in between the brackets.
>//''NOTE: 'Inline X' syntax has been deprecated...''  This storage format only works properly for checkboxes that are directly embedded and accessed from content in a single tiddler.  However, if that tiddler is 'transcluded' into another (by using the {{{<<tiddler TiddlerName>>}}} macro), the 'Inline X' will be ''erroneously stored in the containing tiddler's source content, resulting in corrupted content in that tiddler.''  For anything but the most simple of "to do list" uses, you should select from the various alternative storage methods described below...//
//{{{
[x=id]
//}}}
Assign an optional ID to the checkbox so you can use {{{document.getElementByID("id")}}} to manipulate the checkbox DOM element, as well as tracking the current checkbox state in {{{config.options["id"]}}}.  If the ID starts with "chk" the checkbox state will also be saved in a cookie, so it can be automatically restored whenever the checkbox is re-rendered (overrides any default {{{[x]}}} or {{{[_]}}} value).  If a cookie value is kept, the "_" or "X" character in the tiddler content remains unchanged, and is only applied as the default when a cookie-based value is not currently defined.
//{{{
[x(title|tag)] or [x(title:tag)]
//}}}
Initializes and tracks the current checkbox state by setting or removing a particular tag value from a specified tiddler.  If you omit the tiddler title (and the | or : separator), the specified tag is assigned to the current tiddler.  If you omit the tag value, as in {{{(title|)}}}, the default tag, {{{checked}}}, is assumed.  Omitting both the title and tag, {{{()}}}, tracks the checkbox state by setting the "checked" tag on the current tiddler.  When tag tracking is used, the "_" or "X" character in the tiddler content remains unchanged, and is not used to set or track the checkbox state.  If a tiddler title named in the tag does not exist, the checkbox state defaults to the "inline X" value.  If this value is //checked//, or is subsequently changed to //checked//, it will automatically create the missing tiddler and then add the tag to it.  //''NOTE: beginning with version 2.1.2 of this plugin, the "|" separator is the preferred separator between the title and tag name, as it avoids syntactic ambiguity when ":" is used within tiddler titles or tag names.''//
//{{{
[x(field@tiddler)]
//}}}
Initializes and tracks the current checkbox state by setting a particular custom field value from a specified tiddler.  If you omit the tiddler title (but not the "@" separator), the specified field on the current tiddler is used.  If you omit the field name, as in {{{(@tiddler)}}}, a default fieldname of {{{checked}}} is assumed.  Omitting both the field and the tiddler title, {{{(@)}}}, defaults to setting the "checked" field on the current tiddler.  When field tracking is used, the "_" or "X" character in the tiddler content remains unchanged, and is not used to set or track the checkbox state.  If the tiddler title named in the parameter does not exist, the checkbox state defaults to the "inline X" value.  If this value is //checked// or is subsequently changed to //checked//, it will automatically create the missing tiddler and then add the field to it.
//{{{
[x{javascript}{javascript}{javascript}]
//}}}
You can define optional javascript code segments to add custom initialization and/or 'onClick' handlers to a checkbox.  The current checkbox state (and it's other DOM attributes) can be set or read from within these code segments by reference to a globally-defined context object, "place" (which can also be referenced as "window.place").

The first code segment will be executed when the checkbox is initially displayed, so that you can programmatically determine it's starting checked/unchecked state.  The second code segment (if present) is executed whenever the checkbox is clicked, but //before the regular checkbox processing in performed// ("onClickBefore"), so that you can apply programmed responses or intercept and override the checkbox state based on custom logic.  The third code segment (if present) is executed whenver the checkbox is clicked, //after the regular checkbox processing has completed// ("onClickAfter"), so that you can include "side-effect" processing based on the checkbox state just applied.

>Note: if you want to use the default checkbox initialization processing with a custom onClickBefore/After function, use this syntax:
>{{{[x(tag){}{javascript}]}}} or {{{[x(tag){}{}{javascript}]}}}
<<<
!!!!!Macro usage
<<<
In addition to embedded checkboxes using the wiki syntax described above, a ''macro-based syntax'' is also provided, for use in templates where wiki syntax cannot be directly used.  This macro syntax can also be used in tiddler content, as an alternative to the wiki syntax.  When embedded in [[PageTemplate]], [[ViewTemplate]], or [[EditTemplate]] (or custom alternative templates), use the following macro syntax:
//{{{
<span macro="checkbox target checked id onInit onClickBefore onClickAfter"></span>
//}}}
or, when embedded in tiddler content, use the following macro syntax:
//{{{
<<checkbox target checked id onInit onClickBefore onClickAfter>>
//}}}
where:
''target''
>is either a tag reference (e.g., ''tagname|tiddlername'') or a field reference (e.g. ''fieldname@tiddlername''), as described above.
''checked'' (optional)
>is a keyword that sets the initial state of the checkbox to "checked".  When omitted, the default checkbox state is "unchecked".
''id'' (optional)
>specifies an internal config.options.* ID, as described above.  If the ID begins with "chk", a cookie-based persistent value will be created to track the checkbox state in between sessions.
''onInit'' (optional)
>contains a javascript event handler to be performed when the checkbox is initially rendered (see details above).
''onClickBefore'' and/or ''onClickAfter'' (optional)
>contains a javascript event handler to be performed each time the checkbox is clicked (see details above).  //note: to use the default onInit handler with a custom onClickBefore/After handler, use "" (empty quotes) or {} (empty function) as a placeholder for the onInit and/or onClickBefore parameters//
<<<
!!!!!Examples
<<<
''checked and unchecked static default ("inline X") values:''
//{{{
[X] label
[_] label
//}}}
>[X] label
>[_] label
''document-based value (id='demo', no cookie):''
//{{{
[_=demo] label
//}}}
>[_=demo] label
''cookie-based value  (id='chkDemo'):''





//{{{
[_=chkDemo] label
//}}}
>[_=chkDemo] label
''tag-based value (TogglyTagging):''
//{{{
[_(CheckboxPluginInfo|demotag)]
[_(CheckboxPluginInfo|demotag){place.refresh.tagged=place.refresh.container=false}]
//}}}
>[_(CheckboxPluginInfo|demotag)] toggle 'demotag' (and refresh tiddler display)
>[_(CheckboxPluginInfo|demotag){place.refresh.tagged=place.refresh.container=false}] toggle 'demotag' (no refresh)
''field-based values:''
//{{{
[_(demofield@CheckboxPluginInfo)] demofield@CheckboxPluginInfo
[_(demofield@)] demofield@ (equivalent to demonfield@ current tiddler)
[_(checked@CheckboxPluginInfo)] checked@CheckboxPluginInfo
[_(@CheckboxPluginInfo)] @CheckboxPluginInfo
[_(@)] @ (equivalent to checked@ current tiddler)
//}}}
>[_(demofield@CheckboxPluginInfo)] demofield@CheckboxPluginInfo
>[_(demofield@)] demofield@ (current tiddler)
>[_(checked@CheckboxPluginInfo)] checked@CheckboxPluginInfo
>[_(@CheckboxPluginInfo)] @CheckboxPluginInfo
>[_(@)] toggle field: @ (defaults to "checked@here")
>click to view current: <<toolbar fields>>
''custom init and onClick functions:''
//{{{
[X{place.checked=true}{alert(place.checked?"on":"off")}] message box with checkbox state
//}}}
>[X{place.checked=true}{alert(place.checked?"on":"off")}] message box with checkbox state
''retrieving option values:''
>config.options['demo']=<script>return config.options['demo']?"true":"false";</script>
>config.options['chkDemo']=<script>return config.options['chkDemo']?"true":"false";</script>
<<<
!!!!!Configuration
<<<
Normally, when a checkbox state is changed, the affected tiddlers are automatically re-rendered, so that any checkbox-dependent dynamic content can be updated.  There are three possible tiddlers to be re-rendered, depending upon where the checkbox is placed, and what kind of storage method it is using.
*''container'': the tiddler in which the checkbox is displayed. (e.g., this tiddler)
*''tagged'': the tiddler that is being tagged (e.g., "~MyTask" when tagging "~MyTask:done")
*''tagging'': the "tag tiddler" (e.g., "~done" when tagging "~MyTask:done")
You can set the default refresh handling for all checkboxes in your document by using the following javascript syntax either in a systemConfig plugin, or as an inline script.  (Substitute true/false values as desired):
{{{config.checkbox.refresh = { tagged:true, tagging:true, container:true };}}}

You can also override these defaults for any given checkbox by using an initialization function to set one or more of the refresh options.  For example:
{{{[_{place.refresh.container=false}]}}}
<<<
!!!!!Revisions
<<<
2008.01.08 [*.*.*] plugin size reduction: documentation moved to [[CheckboxPluginInfo]]
2008.01.05 2.4.0 set global "window.place" to current checkbox element when processing checkbox clicks.  This allows init/beforeClick/afterClick handlers to reference RELATIVE elements, including using "story.findContainingTiddler(place)".  Also, wrap handlers in "function()" so "return" can be used within handler code.
2008.01.02 2.3.0 split optional custom onClick handling into separate onClickBefore and onClickAfter handlers.  The onClickBefore handler permits interception of the click BEFORE the checkbox is set.  onClickAfter allows follow-on 'side-effect' processing to occur AFTER the checkbox is set.
2007.12.04 [*.*.*] update for TW2.3.0: replaced deprecated core functions, regexps, and macros
2007.08.06 2.2.5 supress automatic refresh of any tiddler that is currently being edited.  Ensures that current tiddler edit sessions are not prematurely discarded (losing any changes).  However, if checkbox changes a tag on a tiddler being edited, update the "tags" input field (if any) so that saving the edited tiddler correctly reflects any changes due to checkbox activity... see refreshEditorTagField().
2007.07.13 - 2.2.4 in handler(), fix srctid reference (was "w.tiddler", should have been "w.tiddler.title").  This fixes broken 'inline X' plus fatal macro error when using PartTiddlerPlugin.  Thanks to cmari for reporting the problem and UdoBorkowski for finding the code error.
2007.06.21 - 2.2.3 suppress automatic refresh of tiddler when using macro-syntax to prevent premature end of tiddler editing session.
2007.06.20 - 2.2.2 fixed handling for 'inline X' when checkboxes are contained in a 'trancluded' tiddler.  Now, regardless of where an inline X checkbox appears, the X will be placed in the originating source tiddler, rather than the tiddler in which the checkbox appears.
2007.06.17 - 2.2.1 Refactored code to add checkbox //macro// syntax for use in templates (e.g., {{{macro="checkbox ..."}}}. Also, code cleanup of existing tag handling.
2007.06.16 - 2.2.0 added support for tracking checkbox states using tiddler fields via "(fieldname@tiddlername)" syntax.
2006.05.04 - 2.1.3 fix use of findContainingTiddler() to check for a non-null return value, so that checkboxes won't crash when used outside of tiddler display context (such as in header, sidebar or mainmenu)
2006.03.11 - 2.1.2 added "|" as delimiter to tag-based storage syntax (e.g. "tiddler|tag") to avoid parsing ambiguity when tiddler titles or tag names contain ":".   Using ":" as a delimiter is still supported but is deprecated in favor of the new "|" usage.  Based on a problem reported by JeffMason.
2006.02.25 - 2.1.0 added configuration options to enable/disable forced refresh of tiddlers when toggling tags
2006.02.23 - 2.0.4 when toggling tags, force refresh of the tiddler containing the checkbox.
2006.02.23 - 2.0.3 when toggling tags, force refresh of the 'tagged tiddler' so that tag-related tiddler content (such as "to-do" lists) can be re-rendered.
2006.02.23 - 2.0.2 when using tag-based storage, allow use [[ and ]] to quote tiddler or tag names that contain spaces:
{{{[x([[Tiddler with spaces]]:[[tag with spaces]])]}}}
2006.01.10 - 2.0.1 when toggling tags, force refresh of the 'tagging tiddler'.  For example, if you toggle the "systemConfig" tag on a plugin, the corresponding "systemConfig" TIDDLER will be automatically refreshed (if currently displayed), so that the 'tagged' list in that tiddler will remain up-to-date.
2006.01.04 - 2.0.0 update for ~TW2.0
2005.12.27 - 1.1.2 Fix lookAhead regExp handling for {{{[x=id]}}}, which had been including the "]" in the extracted ID.  
Added check for "chk" prefix on ID before calling saveOptionCookie()
2005.12.26 - 1.1.2 Corrected use of toUpperCase() in tiddler re-write code when comparing {{{[X]}}} in tiddler content with checkbox state. Fixes a problem where simple checkboxes could be set, but never cleared.
2005.12.26 - 1.1.0 Revise syntax so all optional parameters are included INSIDE the [ and ] brackets.  Backward compatibility with older syntax is supported, so content changes are not required when upgrading to the current version of this plugin.   Based on a suggestion by GeoffSlocock
2005.12.25 - 1.0.0 added support for tracking checkbox state using tags ("TogglyTagging")
Revised version number for official post-beta release.
2005.12.08 - 0.9.3 support separate 'init' and 'onclick' function definitions.
2005.12.08 - 0.9.2 clean up lookahead pattern
2005.12.07 - 0.9.1 only update tiddler source content if checkbox state is actually different.  Eliminates unnecessary tiddler changes (and 'unsaved changes' warnings)
2005.12.07 - 0.9.0 initial BETA release
<<<
/%
!info
|Name|CheckboxToggleTag|
|Source|http://www.TiddlyTools.com/#CheckboxToggleTag|
|Version|1.3.6|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Description|toggle between two tag values using an HTML checkbox (no plugins)|
Usage:
<<<
{{{
in tiddler content:
   <<tiddler CheckboxToggleTag with: tag1 tag2 TiddlerName>> label
in ViewTemplate or EditTemplate:
   <span macro='CheckboxToggleTag with: tag1 tag2 TiddlerName'></span> label
}}}
where:
*''tag1'' is the tag to use when the checkbox is set
*''tag2'' //(optional)// is the tag to use when the checkbox is cleared (default=remove ''tag1'')
*''~TiddlerName'' //(optional)// is the tiddler to be tagged (default=current tiddler)
*''label'' //(optional)// is any text you want to display next to the checkbox
//note: to specify a ''~TiddlerName'' while omitting ''tag2'', use {{{""}}} (empty quotes) as a placeholder for ''tag2''//
<<<
Examples:
<<<
{{{
<<tiddler CheckboxToggleTag with: sometag>> set/clear 'sometag'
<<tiddler CheckboxToggleTag with: tagA tagB>> toggle tagA (checked) and tagB (unchecked)
}}}
<<tiddler CheckboxToggleTag with: sometag>> set/clear 'sometag'
<<tiddler CheckboxToggleTag with: tagA tagB>> toggle tagA (checked) and tagB (unchecked)
<<<
Notes:
<<<
*Clicking a checkbox immediately changes the corresponding tag value in the tiddler. This can, in some cases, trigger additional 'side-effect' processing, such as refreshing of page elements, or autosaving of the document (if that option is enabled).
*If you are currently editing the tiddler being tagged, any //unsaved// changes you have made to the contents of the ''tags'' input field will be discarded when the checkbox is clicked.
<<<
!end info
!show
<html><input type="checkbox" onclick="
	store.suspendNotifications();
	var tid=this.getAttribute('tid');
	var ontag=this.getAttribute('onTag');
	var offtag=this.getAttribute('offTag');
	if (ontag && ontag.length)  store.setTiddlerTag(tid,this.checked,ontag);
	if (offtag && offtag.length) store.setTiddlerTag(tid,!this.checked,offtag);
	store.resumeNotifications();
	store.notify(tid,true);
	var here=story.findContainingTiddler(this);
	if (here) { /* refresh current tiddler */
		var title=here.getAttribute('tiddler');
		var template=story.chooseTemplateForTiddler(title,story.isDirty(title)?2:1);
		story.refreshTiddler(title,template,true);
	}
	return false;
"><nowiki></html><<tiddler {{
	var tid="$3";
	if (tid=="$"+"3") {
		var here=story.findContainingTiddler(place);
		if (here) tid=here.getAttribute('tiddler');
	}
	if (store.tiddlerExists(tid)) {
		var c=place.lastChild.firstChild;
		c.setAttribute('onTag','$1');
		c.setAttribute('offTag','$2'!='$'+'2'&&'$2'!='undefined'?'$2':'');
		c.setAttribute('tid',tid);
		c.checked=store.getTiddler(tid).isTagged(c.getAttribute('onTag'));
	}
'';}}>>
!end show

%/<<tiddler {{'CheckboxToggleTag##'+('$1'=='$'+'1'?'info':'show')}} with: [[$1]] [[$2]] [[$3]]>>
/***
|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);
		}
	}
}
//}}}
/%
!info
|Name|CloseOtherTiddlers|
|Source|http://www.TiddlyTools.com/#CloseOtherTiddlers|
|Version|2.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Description|close all other tiddlers when a specific tiddler is viewed|
Usage:
<<<
{{{
<<tiddler CloseOtherTiddlers>>
}}}
<<<
!end
%/<<tiddler {{
	var out='CloseOtherTiddlers##info';
	if (!tiddler||tiddler.title!='CloseOtherTiddlers') {
		var here=story.findContainingTiddler(place);
		story.closeAllTiddlers(here?here.getAttribute("tiddler"):null);
		out='';
	}
out;}}>>
/***
|Name|CollapseTiddlersPlugin|
|Source|http://www.TiddlyTools.com/#CollapseTiddlersPlugin|
|Version|2.0.0|
|Author|Eric Shulman|
|OriginalAuthor|Bradley Meck - http://gensoft.revhost.net/Collapse.html|
|License|unknown|
|~CoreVersion|2.1|
|Type|plugin|
|Requires|CollapsedTemplate|
|Description|show/hide content of a tiddler while leaving tiddler title visible|
This plugin provides commands to quickly switch a rendered tiddler between its current ViewTemplate display and a minimal display (title and toolbar) defined by a separate CollapsedTemplate.
!!!Usage
<<<
In [[ToolbarCommands::ViewToolbar|ToolbarCommands]], add:
{{{
collapseTiddler collapseOthers
}}}
you can also embed the following macros in tiddler content:
*{{{<<collapseAll>>}}} - adds 'collapse all' command that applies CollapsedTemplate to each displayed tiddler
*{{{<<expandAll>>}}} - adds 'expand all' command that re-applies ViewTemplate (or equivalent custom template) to each displayed tiddler
*{{{<<foldFirst>>}}} - immediately apply CollapsedTemplate to a given tiddler, as soon as it is displayed.
<<<
!!!Revisions
<<<
2009.05.04 [2.0.0] standardized documentation and added version #
2008.10.05 collapseAll() and expandAll(): added "return false" to button handlers to prevent IE page transition
2008.03.06 refactored all code for size reduction, readability, and I18N/L10N-readiness.  Also added 'folded' flag to tiddler elements (for use by other plugins that need to know if tiddler is folded (e.g., [[SinglePageModePlugin]]
2007.10.11 moved [[FoldFirst]] inline script and converted to {{{<<foldFirst>>}}} macro
2007.12.09 suspend/resume SinglePageMode (SPM/TPM/BPM) when folding/unfolding tiddlers
2007.05.06 add "return false" at the end of each command handler to prevent IE 'page transition' problem.
2007.03.30 add a shadow definition for CollapsedTemplate.  Tweak ViewTemplate shadow so "fold/unfold" and "focus" toolbar items automatically appear when using default templates.  Remove error check for "CollapsedTemplate" existence, since shadow version will now always work as a fallback.
2006.02.24 added fallback to "CollapsedTemplate" if "WebCollapsedTemplate" is not found
2006.02.06 added check for 'readOnly' flag to use alternative "WebCollapsedTemplate"
<<<
!!!Code
***/
//{{{
version.extensions.CollapseTiddlersPlugin= {major: 2, minor: 0, revision: 0, date: new Date(2009,5,4)};

config.shadowTiddlers.CollapsedTemplate=
	"<!--{{{-->\
	<div class='toolbar' macro='toolbar expandTiddler collapseOthers closeTiddler closeOthers +editTiddler permalink references jump'></div>\
	<div class='title' macro='view title'></div>\
	<!--}}}-->";

// automatically tweak shadow ViewTemplate to add "collapseTiddler collapseOthers" commands
config.shadowTiddlers.ViewTemplate=config.shadowTiddlers.ViewTemplate.replace(/closeTiddler/,"collapseTiddler collapseOthers closeTiddler");

config.commands.collapseTiddler = {
	text: "fold",
	tooltip: "Collapse this tiddler",
	collapsedTemplate: "CollapsedTemplate",
	webCollapsedTemplate: "WebCollapsedTemplate",
	handler: function(event,src,title) {
		var e = story.findContainingTiddler(src); if (!e) return false;
		// don't fold tiddlers that are being edited!
		if(story.isDirty(e.getAttribute("tiddler"))) return false;
		var t=config.commands.collapseTiddler.getCollapsedTemplate();
		config.commands.collapseTiddler.saveTemplate(e);
		config.commands.collapseTiddler.display(title,t);
		e.setAttribute("folded","true");
		return false;
	},
	getCollapsedTemplate: function() {
		if (readOnly&&store.tiddlerExists(this.webCollapsedTemplate))
			return this.webCollapsedTemplate;
		else
			return this.collapsedTemplate
	},
	saveTemplate: function(e) {
		if (e.getAttribute("savedTemplate")==undefined)
			e.setAttribute("savedTemplate",e.getAttribute("template"));

	},
	// fold/unfold tiddler with suspend/resume of single/top/bottom-of-page mode
	display: function(title,t) {
		var opt=config.options;
		var saveSPM=opt.chkSinglePageMode; opt.chkSinglePageMode=false;
		var saveTPM=opt.chkTopOfPageMode; opt.chkTopOfPageMode=false;
		var saveBPM=opt.chkBottomOfPageMode; opt.chkBottomOfPageMode=false;
		story.displayTiddler(null,title,t);
		opt.chkBottomOfPageMode=saveBPM;
		opt.chkTopOfPageMode=saveTPM;
		opt.chkSinglePageMode=saveSPM;
	}
}

config.commands.expandTiddler = {
	text: "unfold",
	tooltip: "Expand this tiddler",
	handler: function(event,src,title) {
		var e = story.findContainingTiddler(src); if (!e) return false;
		var t = e.getAttribute("savedTemplate");
		config.commands.collapseTiddler.display(title,t);
		e.setAttribute("folded","false");
		return false;
	}
}

config.macros.collapseAll = {
	text: "collapse all",
	tooltip: "Collapse all tiddlers",
	handler: function(place,macroName,params,wikifier,paramString,tiddler){
		createTiddlyButton(place,this.text,this.tooltip,function(){
			story.forEachTiddler(function(title,tiddler){
				if(story.isDirty(title)) return;
				var t=config.commands.collapseTiddler.getCollapsedTemplate();


				config.commands.collapseTiddler.saveTemplate(tiddler);
				config.commands.collapseTiddler.display(title,t);
				tiddler.folded=true;
			});
			return false;
		})
	}
}

config.macros.expandAll = {
	text: "expand all",
	tooltip: "Expand all tiddlers",
	handler: function(place,macroName,params,wikifier,paramString,tiddler){
		createTiddlyButton(place,this.text,this.tooltip,function(){
			story.forEachTiddler(function(title,tiddler){
				var t=config.commands.collapseTiddler.getCollapsedTemplate();
				if(tiddler.getAttribute("template")!=t) return; // re-display only if collapsed
				var t=tiddler.getAttribute("savedTemplate");
				config.commands.collapseTiddler.display(title,t);
				tiddler.folded=false;
			});
			return false;
		})
	}
}

config.commands.collapseOthers = {
	text: "focus",
	tooltip: "Expand this tiddler and collapse all others",
	handler: function(event,src,title) {
		var e = story.findContainingTiddler(src); if (!e) return false;
		story.forEachTiddler(function(title,tiddler) {
			if(story.isDirty(title)) return;
			var t=config.commands.collapseTiddler.getCollapsedTemplate();
			if (e==tiddler) t=e.getAttribute("savedTemplate");
			config.commands.collapseTiddler.saveTemplate(tiddler);
			config.commands.collapseTiddler.display(title,t);
			tiddler.folded=(e!=tiddler);
		})
		return false;
	}
}

// {{{<<foldFirst>>}}} macro forces tiddler to be folded when *initially* displayed.
// Subsequent re-render does NOT re-fold tiddler, but closing/re-opening tiddler DOES cause it to fold first again.
config.macros.foldFirst = {
	handler: function(place,macroName,params,wikifier,paramString,tiddler){
		var e=story.findContainingTiddler(place);
		if (e.getAttribute("foldedFirst")=="true") return; // already been folded once
		var title=e.getAttribute("tiddler")
		var t=config.commands.collapseTiddler.getCollapsedTemplate();
		config.commands.collapseTiddler.saveTemplate(e);
		config.commands.collapseTiddler.display(title,t);
		e.setAttribute("folded","true");
		e.setAttribute("foldedFirst","true"); // only when tiddler is first rendered
		return false;
	}
}
//}}}
<!--{{{-->
<!--
|Name|CollapsedTemplate|
|Source|http://www.TiddlyTools.com/#CollapsedTemplate|
|Version||
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|template|
|Requires|ToolbarCommands|
|Description|alternative to ViewTemplate, used by CollapseTiddlersPlugin to display tiddler when 'folded'|
-->
<span class='toolbar' macro='toolbar [[ToolbarCommands::CollapsedToolbar]]'></span>
</span>
<span class='title'>
	<span class='floatleft' macro='tiddlerIcons' style='cursor:auto !important;'></span>
	<span macro='view title'></span>
</span>
<div class='tagClear'></div>
<!--}}}-->
{{floatleft small borderright{
Sunshine: #ff0
Grass: #360
Sky: LightBlue
Dirt: #633
Apple: #C00
Banana: #FF0
Lime: #3C6
Orange: #F93
Peach: #F99
Pear: #CF6
Raspberry: #606
Background: #fff
Foreground: #000
PrimaryPale: #9cf
PrimaryLight: #09f
PrimaryMid: #03c
PrimaryDark: #003
SecondaryPale: #ffc
SecondaryLight: #fc9
SecondaryMid: #cc6
SecondaryDark: #630
TertiaryPale: #eee
TertiaryLight: #ccc
TertiaryMid: #999
TertiaryDark: #666
Error: #C33
}}}PaletteMaker:<hr><<tiddler PaletteMaker>>{{clear block{}}}
/***
|Name|ColumnCalculatorPlugin|
|Source|http://www.TiddlyTools.com/#ColumnCalculatorPlugin|
|Version|0.6.2|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|calculate values from table cells in a column|
|Status| ALPHA - USE AT YOUR OWN RISK |
!!!Usage
<<<
{{{<<columncalc function startrow endrow>>}}}
where:
*''function'' is a keyword that specifies the type of calculation to perform:
** ''total'' or ''sum'' or //no param//<br>adds up values for cells above it in the column
** ''count''<br>number of non-empty cells in column
** ''average'' or ''avg''<br>average of cells in column (i.e., total/count)
* ''all'' (optional)<br>normally, only cells containing numbers or timestamps (hh:mm:ss) are included in the calculations.  The ''all'' keyword allows text or empty cells to be processed as if they contained a "0".
* ''startrow'',''endrow'' (optional)<br>specifies a ONE-based range of rows for limiting the calculation.  Use negative numbers to specify an offset from the current row (e.g., {{{<<calc sum 3 5>>}}} adds up rows 3, 4 and 5, while {{{<<calc sum 1 -1>>}}} adds up all numbers in the column excluding the current row (i.e., the same as the default if no startrow/endrow params are specified)
<<<
!!!Examples
<<<
''with numeric values...''
{{{
| foo| 3.2 |
| bar| 1.1 |
| baz| 2.9 |
| gronk| 4.3 |
| snork| non-number |
| count| <<columncalc count all 1 -1>> |
| total| <<columncalc sum all 1 -2>> |
| avg| <<columncalc average all 1 -3>> |
}}}
| foo| 3.2 |
| bar| 1.1 |
| baz| 2.9 |
| gronk| 4.3 |
| snork| non-number |
| count| <<columncalc count all 1 -1>> |
| total| <<columncalc sum all 1 -2>> |
| avg| <<columncalc average all 1 -3>> |

''with time-formatted values (hh:mm:ss)...''
{{{
| foo| 00:22:15 |
| bar| 00:03:30 |
| baz| 00:01:45 |
| count| <<columncalc count 1 -1>> |
| total| <<columncalc sum 1 -2>> |
| avg| <<columncalc average 1 -3>> |
}}}
| foo| 00:22:15 |
| bar| 00:03:30 |
| baz| 00:01:45 |
| count| <<columncalc count 1 -1>> |
| total| <<columncalc sum 1 -2>> |
| avg| <<columncalc average 1 -3>> |
<<<
!!!Revisions
<<<
2009.02.05 [0.6.2] added 'all' param to include empty/text rows in calculations.
2007.10.26 [0.6.1] in handler(), using '.textContent' instead of '.innerHTML' when reading values from table cells.  This allows use of values that are transcluded from slices in other tiddlers using the {{{<<tiddler 'TiddlerName::slicename'>>}}} syntax.
2007.06.29 [0.6.0] added support for handling values in hh:mm:ss format
2007.04.02 [0.5.0] started
<<<
!!!!!Code
***/
//{{{
version.extensions.ColumnCalculatorPlugin= {major: 0, minor: 6, revision: 1, date: new Date(2007,10,26)};
config.macros.columncalc= {
	handler:
	function(place,macroName,params,wikifier,paramString,tiddler) {

		if (place.parentNode.nodeName.toLowerCase()!='tr') return false; // not in a table
		var tbody=place.parentNode.parentNode;
		var row=tbody.childNodes.length-1; // current row #
		var col=place.parentNode.childNodes.length-1; // current column #

		var fn=params.shift();
		var allCells=(params[0]&&params[0].toLowerCase()=='all');
		if (allCells) params.shift();
		var startrow=0; var endrow=row-1;
		if (params[0]) var startrow=params.shift();
		if (startrow<0) startrow=1*startrow+row; else startrow=startrow-1;
		if (params[0]) var endrow=params.shift();
		if (endrow<0) endrow=1*endrow+row; else endrow=endrow-1;

		var count=total=0;
		for (r=startrow; r<=endrow; r++) {
			var cell=tbody.childNodes[r].childNodes[col].textContent;
			if (!cell) cell=tbody.childNodes[r].childNodes[col].innerHTML; // fallback for older browsers
			var val=cell; var hms=cell.split(':');
			if (hms.length==3) { // an hh:mm:ss time value
				var val=(hms[0]||0)*3600+(hms[1]||0)*60+(hms[2]||0)*1;
				var showTime=true; // use time formatting for results...
			}
			else if (cell.length && !isNaN(cell)) // a numeric value
				var val=eval(cell);
			else if (allCells) // an non-numeric cell (when 'all' is used)
				var val=0;
			if (!isNaN(val)) { total+=val; count++; }
		}
		switch (fn) {
			case 'count':
				var result=count;
				break;
			case 'average':
			case 'avg':
				var result=Math.floor(total/count*100)/100; // truncate to two decimal places
				break;
			case 'total':
			case 'sum':
			default:
				var result=total;
				break;
		}
		if (showTime && fn!='count') {
			var h=Math.floor(result/3600);
			var m=Math.floor((result-h*3600)/60);
			var s=Math.floor((result-h*3600-m*60)*100)/100; // truncate to two decimal places
			result=(h<10?'0':'')+h+':'+(m<10?'0':'')+m+':'+(s<10?'0':'')+s;
		}
		createTiddlyText(place,result);
	}
}
//}}}
/***
|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
<<<
/***
|Name|CompareTiddlersPlugin|
|Source|http://www.TiddlyTools.com/#CompareTiddlersPlugin|
|Version|1.1.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|show color-coded differences between two selected tiddlers|
!!!!!Usage
<<<
Display a form that lets you select and compare any two tiddlers:
{{{
<<compareTiddlers>>
}}}
To filter the lists of tiddlers by tags, include an optional tagvalue (or tag expression) parameter:
{{{
<<compareTiddlers "tagValue">>
   OR
<<compareTiddlers "boolean tag expression">> (requires MatchTagsPlugin)
}}}
<<<
!!!!!Example
<<<
{{{<<compareTiddlers>>}}}
{{smallform small{<<compareTiddlers>>}}}
<<<
!!!!!Revisions
<<<
2009.07.25 [1.1.0] added optional tag filter param
2007.10.15 [1.0.0] converted from inline script to true plugin
2006.12.27 [0.0.0] inline script.  {{{diff()}}} and {{{diffString()}}} functions written by Bradley Meck.
<<<
!!!!!Code
***/
//{{{
version.extensions.CompareTiddlersPlugin= {major: 1, minor: 1, revision: 0, date: new Date(2009,7,25)};
//}}}
//{{{
config.shadowTiddlers.CompareTiddlers='<<compareTiddlers>>';
//}}}
/***
//{{{
!html
<form><!--
--><input type=hidden name=filter value=''><!--
--><select name=list1 size=1 style='width:30%'
	onchange='config.macros.compareTiddlers.pick(this,this.form.view1,this.form.edit1,this.form.text1)'></select><!--
--><input type=button name=view1 style='width:10%' value='view' disabled
	onclick='if (this.form.list1.value.length)
		story.displayTiddler(story.findContainingTiddler(this),this.form.list1.value)'><!--
--><input type=button name=edit1 style='width:10%' value='edit' disabled
	onclick='if (this.form.list1.value.length)
		story.displayTiddler(story.findContainingTiddler(this),this.form.list1.value,DEFAULT_EDIT_TEMPLATE)'><!--
--><select name=list2 size=1 style='width:30%'
	onchange='config.macros.compareTiddlers.pick(this,this.form.view2,this.form.edit2,this.form.text2)'></select><!--
--><input type=button name=view2 style='width:10%' value='view' disabled
	onclick='if (this.form.list2.value.length)
		story.displayTiddler(story.findContainingTiddler(this),this.form.list2.value)'><!--
--><input type=button name=edit2 style='width:10%' value='edit' disabled
	onclick='if (this.form.list2.value.length)
		story.displayTiddler(story.findContainingTiddler(this),this.form.list2.value,DEFAULT_EDIT_TEMPLATE)'><br><!--
--><nobr><!--
--><textarea name=text1 style='width:49.5%;display:none' rows='10' readonly></textarea><!--
--><textarea name=text2 style='width:49.5%;display:none' rows='10' readonly></textarea><!--
--></nobr><!--
--><div style='float:left'><!--
-->Additions are shown in <span style='color:green'>GREEN</span>, <!--
-->deletions are shown in <span style='color:red'>RED</span><!--
--></div><!--
--><div style='text-align:right'><!--
--><input type=button name=compare style='width:10%' value='compare' disabled
	onclick='config.macros.compareTiddlers.compare(this.form,this.form.nextSibling)'><!--
--><input type=button name=done style='width:10%' value='done' disabled
	onclick='config.macros.compareTiddlers.reset(this.form,this.form.nextSibling)'><!--
--></div><!--
--></form><div class='compareTiddlersResults'>contents to be replaced by results of comparison</div>
!end
//}}}
***/
//{{{
config.macros.compareTiddlers= {
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		setStylesheet(this.css,'CompareTiddlersStyles');
		var out=createTiddlyElement(place,'span');
		out.innerHTML=store.getTiddlerText('CompareTiddlersPlugin##html');
		var form=out.getElementsByTagName('form')[0];
		var target=form.nextSibling;
		this.reset(form,target,params[0]);
	},
	css: '.compareTiddlersResults \
		{ display:none;clear:both;margin-top:1em;border:1px solid;-moz-border-radius:1em;-webkit-border-radius:1em;padding:1em;white-space:normal; }',
	reset: function(f,target,filter) {
		if (f.filter.value.length) var filter=f.filter.value;
		if (filter) var tids=store.filterTiddlers('[tag['+filter+']]')
		else var tids=store.getTiddlers('title','excludeLists');
		f.text1.style.display='none'; f.text1.value='';
		while (f.list1.options[0]) f.list1.options[0]=null; 
		f.list1.options[0]=new Option('select a tiddler...','',false,false);
		for (i=0; i<tids.length; i++)
			f.list1.options[f.list1.length]=new Option(tids[i].title,tids[i].title,false,false);
		f.text2.style.display='none'; f.text2.value='';
		while (f.list2.options[0]) f.list2.options[0]=null; 
		f.list2.options[0]=new Option('select a tiddler...','',false,false);
		for (i=0; i<tids.length; i++)
			f.list2.options[f.list2.length]=new Option(tids[i].title,tids[i].title,false,false);
		f.view1.disabled=f.view2.disabled=f.edit1.disabled=f.edit2.disabled=f.compare.disabled=f.done.disabled=true;
		f.filter.value=filter;
		target.style.display='none';
		removeChildren(target);
	},
	pick: function(list,view,edit,text) {
		var f=list.form;
		view.disabled=edit.disabled=f.done.disabled=!list.value.length;
		f.compare.disabled=!f.list1.value.length||!f.list2.value.length;
		if (!list.value.length) return;
		f.text1.style.display=f.text2.style.display='inline';
		text.value=store.getTiddlerText(list.value);
	},
	compare: function(f,target) {
		if (!f.list1.value.length) { f.list1.focus(); return alert('select a tiddler'); }
		var t1=store.getTiddlerText(f.list1.value); if (!t1) { displayMessage(f.list1.value+' not found');return false; }
		if (!f.list2.value.length) { f.list2.focus(); return alert('select a tiddler'); }
		var t2=store.getTiddlerText(f.list2.value); if (!t2) { displayMessage(f.list2.value+' not found');return false; }
		var out=this.diffString(t1,t2); if (!out || !out.length) out='no differences';
		removeChildren(target);
		target.innerHTML=out;
		target.style.display='block';
		f.done.disabled=false;
	},
//}}}
//{{{
	diffString: function( o, n ) {
		// This function was written by Bradley Meck
		// returns difference between old and new text, color-formatted additions and deletions
		if (o==n) return ""; // simple check, saves time if true
		var error = 5;
		var reg = new RegExp( "\\n|(?:.{0,"+error+"})", "g" );
		var oarr = o.match( reg ); // dices text into chunks
		var narr = n.match( reg );
		var out = this.diff(oarr,narr); // compare the word arrays
		var str = ""; // construct output
		for (i=0; i<out.length; i++) {
			switch (out[i].change) {
				case "ADDED":
					str+="<span style='color:green'>";
					str+=narr.slice(out[i].index,out[i].index+out[i].length).join("");
					str+="</span> ";
					break;
				case "DELETED":
					str+="<span style='color:red'>";
					str+=oarr.slice(out[i].index,out[i].index+out[i].length).join("");
					str+="</span> ";
					break;
				default:
					str+="<span>";
					str+=oarr.slice(out[i].index,out[i].index+out[i].length).join("");
					str+="</span> ";
					break;
			}	
		}
		return str;
	},
	diff: function( oldArray, newArray ) {
		// This function was written by Bradley Meck
		// finds the differences between one set of objects and another.
		// The objects do not need to be Strings.  It outputs an array of objects with the properties value and change.
		// This function is pretty hefty but appears to be rather light for a diff and tops out at O(N^2) for absolute worst cast scenario.
		var newElementHash = { };
		for( var i = 0; i < newArray.length; i++ ) {
			if( ! newElementHash [ newArray [ i ] ] ) {
				newElementHash [ newArray [ i ] ] = [ ];
			}
			newElementHash [ newArray [ i ] ].push( i );
		}
		var substringTable = [ ];
		for( var i = 0; i < oldArray.length; i++ ) {
			if(newElementHash [ oldArray [ i ] ] ) {
				var locations = newElementHash [ oldArray [ i ] ] ;
				for( var j = 0; j < locations.length; j++){
					var length = 1;
					while( i + length < oldArray.length && locations [ j ] + length < newArray.length
						&& oldArray [ i + length ] == newArray [ locations [ j ] + length ] ){
						length++;
					}
					substringTable.push( {
						oldArrayIndex : i,
						newArrayIndex : locations [ j ],
						matchLength : length
					} );
				}
			}
		}
		substringTable.sort( function( a, b ) {
			if ( a.matchLength > b.matchLength /* a is less than b by some ordering criterion */ ) {
				return -1;
			}
			if ( a.matchLength < b.matchLength /* a is greater than b by the ordering criterion */ ) {
				return 1;
			}
			// a must be equal to b
			return 0
		} );
		//displayMessage( substringTable.toSource( ) );
		for( var i = 0; i < substringTable.length; i++) {
			for( var j = 0; j < i; j++) {
				var oldDelta = substringTable [ i ].oldArrayIndex + substringTable [ i ].matchLength - 1 - substringTable [ j ].oldArrayIndex;
				var newDelta = substringTable [ i ].newArrayIndex + substringTable [ i ].matchLength - 1 - substringTable [ j ].newArrayIndex;
				//displayMessage( "oldDelta ::: " + oldDelta );
				//displayMessage( "newDelta ::: " + newDelta );
				//displayMessage( "matchLength ::: " + substringTable [ j ].matchLength );
				if( ( oldDelta >= 0 && oldDelta <= substringTable [ j ].matchLength )
				|| ( newDelta >= 0 && newDelta <= substringTable [ j ].matchLength )
				|| ( oldDelta < 0 && newDelta > 0 )
				|| ( oldDelta > 0 && newDelta < 0 ) ) {
					substringTable.splice( i, 1 );
					i--;
					break;
				}
			}
		}
		//displayMessage( substringTable.toSource(  ) );
		substringTable.sort( function( a, b ) {
			if ( a.oldArrayIndex < b.oldArrayIndex /* a is less than b by some ordering criterion */ ) {
				return -1;
			}
			if ( a.oldArrayIndex > b.oldArrayIndex /* a is greater than b by the ordering criterion */ ) {
				return 1;
			}
			// a must be equal to b
			return 0
		} );
		//displayMessage( substringTable.toSource( ) );
		var oldArrayIndex = 0;
		var newArrayIndex = 0;
		var results = [ ];
		for( var i = 0; i < substringTable.length; i++ ) {
			if( oldArrayIndex != substringTable [ i ].oldArrayIndex ) {
				results.push( {
					change : "DELETED",
					length : substringTable [ i ].oldArrayIndex - oldArrayIndex,
					index : oldArrayIndex
				} );
			}
			if( newArrayIndex != substringTable [ i ].newArrayIndex ) {
				results.push( {
					change : "ADDED",
					length : substringTable [ i ].newArrayIndex - newArrayIndex,
					index : newArrayIndex
				} );
			}
			results.push( {
				change : "STAYED",
				length : substringTable [ i ].matchLength,
				index : substringTable [ i ].oldArrayIndex
			} );
			oldArrayIndex = substringTable [ i ].oldArrayIndex + substringTable [ i ].matchLength;
			newArrayIndex = substringTable [ i ].newArrayIndex + substringTable [ i ].matchLength;
		}
		if( oldArrayIndex != oldArray.length ) {
			results.push( {
				change : "DELETED",
				length : oldArray.length - oldArrayIndex,
				index : oldArrayIndex
			} );
		}
		if( newArrayIndex != newArray.length ) {
			results.push( {
				change : "ADDED",
				length : newArray.length - newArrayIndex,
				index : newArrayIndex
			} );
		}
		return results;
	}
}
//}}}
//{{{
// re-label default text for some standard UI elements
config.commands.permalink.text="link";
config.commands.references.text="references";
merge(config.macros.toolbar,{ moreLabel: 'more\u25BC', lessLabel: '\u25C4less' });

// allows custom response when tiddler does not exist (e.g. redirection to alternative tiddler)
config.shadowTiddlers.MissingTiddler=config.views.wikified.defaultText.replace(/%0/,'$1'); // default to standard message
config.views.wikified.defaultText='<<tiddler MissingTiddler with: [[%0]]>>';

// wrap AdvancedOptions and PluginManager default content in a groupbox (and use a smaller font)
config.shadowTiddlers.AdvancedOptions=
	config.shadowTiddlers.AdvancedOptions.replace(
		/<<options>>/,
		"{{small groupbox{<<options>>}}}");

config.shadowTiddlers.PluginManager=
	config.shadowTiddlers.PluginManager.replace(
		/<<plugins>>/,
		"{{small groupbox{<<plugins>>}}}");

// message used by ConfirmExitPlugin when no changes have been made
config.messages.confirmExit_nochanges='\tTiddlyTools... Small Tools for Big Ideasâ„¢\n\t'
	+store.getTiddlerText("SiteUrl",document.location.protocol=="http"?document.location.href:"");
//}}}
/***
|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(); }
//}}}
/***
|Name|ConfirmSavePlugin|
|Source|http://www.TiddlyTools.com/#ConfirmSavePlugin|
|Documentation|http://www.TiddlyTools.com/#ConfirmSavePlugin|
|Version|1.1.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|if tiddlers are being edited, or there are no unsaved changes, ask before saving|
When <<saveChanges>> command link is clicked, if there are tiddlers still being edited or there are no changes unsaved changes, then ask for confirmation before saving the document to the file.
!!!!!Configuration
<<<
:
<<option chkConfirmSaveIfEditing>> confirm saving if tiddlers are still being edited
<<option chkConfirmSaveIfNoChanges>> confirm saving if there are no unsaved tiddler changes
<<<
!!!!!Revisions
<<<
2008.03.15 [1.1.0] added option settings and check for 'no unsaved changes'
2008.03.15 [1.0.0] Initial Release.
<<<
!!!!!Code
***/
//{{{
version.extensions.ConfirmSavePlugin= {major: 1, minor: 1, revision: 0, date: new Date(2008,3,15)};
//}}}
//{{{
if (config.options.chkConfirmSaveIfEditing==undefined) config.options.chkConfirmSaveIfEditing=true;
if (config.options.chkConfirmSaveIfNoChanges==undefined) config.options.chkConfirmSaveIfNoChanges=true;
//}}}
//{{{
if (config.macros.saveChanges.confirmSave_onClick==undefined) 
	config.macros.saveChanges.confirmSave_onClick=config.macros.saveChanges.onClick
config.macros.saveChanges.onClick=function(e) {
	var msg="";
	var editing=[];	// check for tiddlers being edited
	if (config.options.chkConfirmSaveIfEditing)
		story.forEachTiddler(function(tid,elem) { if (elem.getAttribute("dirty")=="true") editing.push(tid);});
	if (editing.length) {
		msg+="There "+(editing.length>1?"are ":"is ")+editing.length;
		msg+=" tiddler"+(editing.length>1?"s":"")+" currently being edited:\n\n";
		msg+=editing.join(", ")+"\n\n";
		msg+="Changes to "+(editing.length>1?"these tiddlers":"this tiddler");
		msg+=" will not be saved until editing is completed.";
	} else if (config.options.chkConfirmSaveIfNoChanges && !store.isDirty())
		msg+="There are no unsaved tiddler changes";
	if (msg.length) {
		msg+="\n\nPress OK to save the document anyway.";
		if (!confirm(msg)) return false;
	}
	return config.macros.saveChanges.confirmSave_onClick.apply(this,arguments); // let core save
}
//}}}
Submit your feedback and/or comments directly to ~TiddlyTools:
{{smallform{<html>
<form method=post target=responseframe action="http://www.tiddlytools.com/mailtext.php" style="display:inline">
	<input type=hidden name=to value="tiddlytools@tiddlytools.com">
	<input type=text name=name style="width:49%" value="your name" onfocus="this.select()">
	<input type=text name=from style="width:49%" value="your email address" onfocus="this.select()"><br>
	<input type=hidden name=subj value="TiddlyTools feedback">
	<font size=-2>Your message:</font><br>
	<textarea rows=7 cols=50 name=msg style="width:99%" onfocus="this.select()"></textarea><br>
	<div style="text-align:center">
	<font size=-2>Enter your information, then press</font> 
	<input type="submit" value="send"
		onclick="var f=this.form;
			if (f.name.value==f.name.defaultValue)
				{ alert('Please enter your name'); f.name.focus(); return false; }
			if (f.from.value==f.from.defaultValue)
				{ alert('Please enter your email address'); f.from.focus(); return false; }
			if (!f.msg.value.length)
				{ alert('Please enter a message'); f.msg.focus(); return false; }
			var target=this.form.nextSibling;
			target.style.display='block';
		">
	</div>
</form><div class="fine" style="text-align:center;display:none">
	server response:<br>
	<iframe src="" name="responseframe" id="responseframe"
		marginheight=0 style="display:block;border:0;padding:0;margin:0;width:100%;height:10em;">
	</iframe>
</div><hide linebreaks></html>}}}{{fine justify{
----
If you are reporting a problem with a TiddlyTools plugin, please provide a ''full, verifiable URL'' for your document, along with an accurate, helpful ''summary description'' of the problem.   ''Step-by-step procedures for reproducing the problem'' are essential to finding the cause and determining a fix (if any).  However, don't assume that your particular computing environment can be readily replicated... you may be asked to ''actively participate'' in the debugging process by providing detailed diagnostic information (error messages, screen snapshots, etc) as well ''testing any potential fixes prior to their release'' to the general public.
----
}}}{{fine justify{
''Important Note: this form cannot be used to send email to any destination other than ~TiddlyTools/ELS Design Studios.''  Please do not copy this form without modifying it to refer to your own server script and destination email address.}}}<<tiddler HideTiddlerTags>>
/***
<<tiddler CookieManager>>
***/
/***
!!![[Portable cookies:|CookieSaverPlugin]] {{fine{<<option chkPortableCookies>>enable <<option chkMonitorCookieJar>>monitor}}}
^^This section is ''//__automatically maintained__//'' by [[CookieSaverPlugin]].  To block specific cookies, see [[CookieSaverPluginConfig]].^^
***/
// // /% end portable cookies %/
/***
!!![[Baked cookies:|CookieManagerPlugin]]
^^Press {{smallform{<<cookieManager button>>}}} to save the current browser cookies... then hand-edit this section to customize the results.^^
***/

// 5 cookies saved on Tuesday, April 8th 2008 at 17:30:05 by ELSDesignStudios//
//^^(edit/remove username check and/or individual option settings as desired)^^//
//{{{
if (["ELSDesignStudios","ELS","Eric"].contains(config.options.txtUserName)) {
	config.options["chkInsertTabs"]=true;
	config.options["chkSearchByDate"]=true;
	config.options["chkTOCIncludeHidden"]=true;
	config.options["txtUploadUserName"]="ELSDesignStudios";
	config.options["txtUploadBackupDir"]="backup";
	config.options["txtUploadStoreUrl"]="http://www.tiddlytools.com/store.php";
	config.options["txtPrivWizardDefaultStep"]="2";
	config.options["txtSliderunsaved"]=true;
}
//}}}
// The following settings are applied as defaults for all users:           //
//{{{
	config.options["txtMaxEditRows"]=25;
	config.options["txtTiddlerLinkTootip"]="%0 - %2 (%3 bytes) - %4";

	if (!config.options.txtTheme.length) config.options.txtTheme='StyleSheet';

	// Make sure FAQ panels are *always* closed on startup (so load-on-demand can be used later on):
	config.options.chkSliderWelcomeShowFAQ=false;
	saveOptionCookie('chkSliderWelcomeShowFAQ');
	config.options.chkSliderMainMenu_faq=false;
	saveOptionCookie('chkSliderMainMenu_faq');
	config.options.chkSliderSiteMenu_faq=false;
	saveOptionCookie('chkSliderSiteMenu_faq');
//}}}
/***
|Name|CookieManagerPlugin|
|Source|http://www.TiddlyTools.com/#CookieManagerPlugin|
|Version|2.4.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|view/add/delete browser-based cookies and "bake" cookies to CookieJar tiddler for 'sticky' settings|
!!!!!Usage
<<<
This plugin provides an interactive control panel that lets you select, view, modify, or delete any of the current values for TiddlyWiki options that have been stored as local, private, //browser cookies//.  You can also use the control panel to "bake cookies", which generates a set of javascript statements that assign hard-coded option values to the TiddlyWiki internal variables that correspond to the current browser cookie settings.  These hard-coded values are then stored in the [[CookieJar]] tiddler, which is tagged with<<tag systemConfig>> so that each time the document is loaded, the baked cookie settings will be automatically applied.

When a set of baked cookies is added to the [[CookieJar]], it is automatically surrounded by a conditional test so that the hard-coded settings will only be applied for the username that was in effect when they were initially generated.  In this way, if you publish or share your document with others, //your// particular baked cookie settings are not automatically applied to others, so that their own browser-based cookie settings (if defined) will be applied as usual.

Whenever you "bake cookies", new hard-coded javascript assignment statements are *appended* to the end of the [[CookieJar]].  However, any baked cookies that were previously generated and stored in the [[CookieJar]] are not automatically removed from the tiddler.  As a result, because the most recently baked cookie settings in the [[CookieJar]] are always the last to be processed, the values assigned by older baked cookies are immediately overridden by the values from the newest baked cookies, so that the newest values will be in effect when the CookieJar startup processing is completed.

Each time you bake a new batch of cookies, it is recommended that you should review and hand-edit the [[CookieJar]] to remove any "stale cookies" or merge the old and new sets of baked cookies into a single block to simplify readability (as well as saving a little tiddler storage space).  Of course, you can also hand-edit the [[CookieJar]] tiddler at any time simply to remove a few individual //baked cookies// if they are no longer needed, and you can even delete the entire [[CookieJar]] tiddler and start fresh, if that is appropriate.  Please note that changing or deleting a baked cookie does not alter the current value of the corresponding option setting, and any changes you make to the [[CookieJar]] will only be applied after you have saved and reloaded the document in your browser.
<<<
!!!!!Examples
<<<
{{{<<cookieManager>>}}}
{{smallform small center{
@@display:block;width:35em;<<cookieManager>>@@}}}
<<<
!!!!!Configuration
<<<
<<option chkAllowBrowserCookies>> store ~TiddlyWiki option settings using private browser cookies
<<option chkMonitorBrowserCookies>> monitor browser cookie activity (show a message whenever a cookie is set or deleted)
<<option chkCookieManagerAddToAdvancedOptions>> display [[CookieManager]] in [[AdvancedOptions]]
//note: this setting does not take effect until you reload the document//
<<<
!!!!!Revisions
<<<
2011.01.16 2.4.1 in init(), corrected double addition of CookieManager to backstage
2009.08.05 2.4.0 changed CookieJar output format to support odd symbols in option names (e.g. '@')
2008.09.14 2.3.2 fixed handling for blocked cookies (was still allowing some blocked cookies to be set)
2008.09.12 2.3.1 added blocked[] array and allowBrowserCookie() test function for selective blocking of changes to browser cookies based on cookie name
2008.09.08 2.3.0 extensive code cleanup: defined removeCookie(), renamed cookies, added 'button' param for stand-alone "bake cookies" button, improved init of shadow [[CookieManager]] and [[CookieJar]] tiddlers for compatibility with new [[CookieSaverPlugin]]. 
2008.07.11 2.2.1 fixed recursion error in hijack for saveOptionCookie()
2008.06.26 2.2.0 added chkCookieManagerNoNewCookies option
2008.06.05 2.1.3 replaced hard-coded definition for "CookieJar" title with option variable
2008.05.12 2.1.2 add "cookies" task to backstage (moved from BackstageTasks)
2008.04.09 2.1.0 added options: chkCookieManagerAddToAdvancedOptions
2008.04.08 2.0.1 automatically include CookieManager control panel in AdvancedOptions shadow tiddler
2007.08.02 2.0.0 converted from inline script
2007.04.29 1.0.0 initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.CookieManagerPlugin= {major: 2, minor: 4, revision: 1, date: new Date(2011,1,16)};
//}}}
//{{{
config.macros.cookieManager = {
	target:
		config.options.txtCookieJar||"CookieJar",
	blockedCookies:
		[],
	allowBrowserCookie: function(name) {
		return true;
	},
	displayStatus: function(msg) {
		if (config.options.chkMonitorBrowserCookies && !startingUp)
			displayMessage("CookieManager: "+msg);
	},
	init: function() {
		if (config.options.txtCookieJar===undefined)
			config.options.txtCookieJar=this.target;
		if (config.options.chkAllowBrowserCookies===undefined)
			config.options.chkAllowBrowserCookies=true;
		if (config.options.chkMonitorBrowserCookies===undefined)
			config.options.chkMonitorBrowserCookies=false;

		config.shadowTiddlers.CookieManager=
			 "/***\n"
			+"!!![[Browser cookies:|CookieManagerPlugin]] "
			+"{{fine{<<option chkAllowBrowserCookies>>enable <<option chkMonitorBrowserCookies>>monitor}}}\n"
			+"^^Review, modify, or delete browser cookies..."
			+"To block specific cookies, see [[CookieManagerPluginConfig]].^^\n"
			+"@@display:block;width:30em;{{smallform small{\n<<cookieManager>>}}}@@\n"
			+"***/\n";

		// add CookieManager to shadow CookieJar
		var h="/***\n<<tiddler CookieManager>>\n***/\n";
		var t=(config.shadowTiddlers[this.target]||"").replace(new RegExp(h.replace(/\*/g,'\\*'),''),'')
		config.shadowTiddlers[this.target]=h+t;

		if (config.options.chkCookieManagerAddToAdvancedOptions===undefined)
			config.options.chkCookieManagerAddToAdvancedOptions=true;
		if (config.options.chkCookieManagerAddToAdvancedOptions)
			config.shadowTiddlers.AdvancedOptions+="\n!!CookieManager\n><<tiddler CookieManager>>";

		// add "cookies" backstage task
		if (config.tasks && !config.tasks.cookies) { // for TW2.2b3 or above
			config.tasks.cookies = {
				text: "cookies",
				tooltip: "manage cookie-based option settings",
				content: "{{groupbox{<<tiddler [["+this.target+"]]>>}}}"
			}
			config.backstageTasks.push("cookies");
		}
	},
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		var span=createTiddlyElement(place,"span");
		span.innerHTML=(params[0]&&params[0].toLowerCase()=="button")?this.button:this.panel;
		this.setList(span.firstChild.list);
	},
	panel: '<form style="display:inline;margin:0;padding:0" onsubmit="return false"><!--\
		--><select style="width:99%" name="list" \
			onchange="this.form.val.value=this.value.length?config.options[this.value]:\'\';"><!--\
		--></select><br>\
		<input type="text" style="width:98%;margin:0;" name="val" title="enter an option value"><br>\
		<input type="button" style="width:33%;margin:0;" value="get" title="refresh list" \
			onclick="config.macros.cookieManager.setList(this.form.list);"><!--\
		--><input type="button" style="width:33%;margin:0;" value="set" title="save cookie value" \
			onclick="var cmc=config.macros.cookieManager;\
				var opt=this.form.list.value; var v=this.form.val.value; \
				var msg=opt+\' is a blocked cookie.  OK to proceed?\';\
				if ((!cmc.blockedCookies.contains(opt) && cmc.allowBrowserCookie(opt))||confirm(msg)) {\
					config.options[opt]=opt.substr(0,3)==\'txt\'?v:(v.toLowerCase()==\'true\'); \
					saveOptionCookie(opt);config.macros.cookieManager.setList(this.form.list);\
				}"><!--\
		--><input type="button" style="width:33%;margin:0;" value="del" title="remove cookie" \
			onclick="var cmc=config.macros.cookieManager; var opt=this.form.list.value; \
				var msg=opt+\' is a blocked cookie.  OK to proceed?\';\
				if ((!cmc.blockedCookies.contains(opt) && cmc.allowBrowserCookie(opt))||confirm(msg)) {\
					removeCookie(this.form.list.value,true); \
					cmc.setList(this.form.list);\
				}"><br>\
		<input type="button" style="width:50%;margin:0;" value="bake cookies" \
			title="save current cookie-based option values into a tiddler" \
			onclick="return config.macros.cookieManager.bake(this,false)"><!--\
		--><input type="button" style="width:50%;margin:0;" value="bake all options" \
			title="save ALL option values (including NON-COOKIE values) into a tiddler" \
			onclick="return config.macros.cookieManager.bake(this,true)"><!--\
		--></form>\
	',
	button: '<form style="display:inline;margin:0;padding:0" onsubmit="return false"><!--\
		--><input type="button" style="margin:0;" value="bake cookies" \
			title="save current browser-based cookie values into a tiddler" \
			onclick="return config.macros.cookieManager.bake(this,false)"><!--\
		--></form>\
	',
	getCookieList: function() {
		var cookies = { };
		if (document.cookie != "") {
			var p = document.cookie.split("; ");
			for (var i=0; i < p.length; i++) {
				var pos=p[i].indexOf("=");
				if (pos==-1) cookies[p[i]]="";
				else cookies[p[i].substr(0,pos)]=unescape(p[i].slice(pos+1));
			}
		}
		var opt=new Array(); for (var i in config.options) if (cookies[i]) opt.push(i); opt.sort();
		return opt;
	},
	setList: function(list) {
		if (!list) return false;
		var opt=this.getCookieList();
		var sel=list.selectedIndex;
		while (list.options.length > 1) { list.options[1]=null; } // clear list (except for header item)
		list.options[0]=new Option("There are "+opt.length+" cookies...","",false,false);
		if (!opt.length) { list.form.val.value=""; return; } // no cookies
		var c=1;
		for(var i=0; i<opt.length; i++) {
			var txt="";
			if  (opt[i].substr(0,3)=="chk")
				txt+="["+(config.options[opt[i]]?"\u221A":"_")+"] ";
			txt+=opt[i];
			list.options[c++]=new Option(txt,opt[i],false,false);
		}
		list.selectedIndex=sel>0?sel:0;
		list.form.val.value=sel>0?config.options[list.options[sel].value]:"";
	},
	header:
		"/***\n"
		+"!!![[Baked cookies:|CookieManagerPlugin]]\n"
		+"^^Press {{smallform{<<cookieManager button>>}}} to save the current browser cookies... "
		+"then hand-edit this section to customize the results.^^\n"
		+"***/\n",
	format: function(name) {
		if (name.substr(0,3)=='chk')
			return '\tconfig.options["'+name+'"]='+(config.options[name]?'true;':'false;');
		return '\tconfig.options["'+name+'"]="'+config.options[name]+'";';
	},
	bake: function(here,all) {
		if (story.isDirty(this.target)) return false; // target is being hand-edited... do nothing
		var text=store.getTiddlerText(this.target);
		if (text.indexOf(this.header)==-1) {
			text+=this.header;
			displayMessage("CookieManager: added 'Baked Cookies' section to CookieJar");
		}
		var who=config.options.txtUserName;
		var when=new Date();
		var tags=['systemConfig'];
		var tid=store.getTiddler(this.target)||store.saveTiddler(this.target,this.target,text,who,when,tags,{});
		if (!tid) return false; // if no target... do nothing
		if (all) { 
			var opts=new Array();
			for (var i in config.options) if (i.substr(0,3)=='chk'||i.substr(0,3)=='txt') opts.push(i);
			opts.sort();
		}
		else var opts=this.getCookieList();
		var t=tid.text;
		if (t.indexOf(this.header)==-1) t+=this.header;
		t+='\n// '+opts.length+(all?' options':' cookies')+' saved ';
		t+=when.formatString('on DDD, MMM DDth YYYY at 0hh:0mm:0ss');
		t+=' by '+who+'//\n';
		t+='//^^(edit/remove username check and/or individual option settings as desired)^^//\n';
		t+='//{{{\n';
		t+='if (config.options.txtUserName=="'+who+'") {\n';
		for (i=0; i<opts.length; i++) t+=config.macros.cookieManager.format(opts[i])+"\n";
		t+='}\n//}}}\n';
		store.saveTiddler(this.target,this.target,t,who,when,tags,tid?tid.fields:{});
		story.displayTiddler(story.findContainingTiddler(this),this.target);
		story.refreshTiddler(this.target,null,true);
		var msg=opts.length+(all?' options':' cookies')+' have been saved in '+this.target+'.  ';
		msg+='Please review all stored settings.';
		displayMessage(msg);
		return false;
	}
}
//}}}
//{{{
// Hijack saveOptionCookie() to add cookie blocking and monitoring messages
config.macros.cookieManager.saveOptionCookie=saveOptionCookie;
window.saveOptionCookie=function(name,force)
{
	var cmc=config.macros.cookieManager; // abbrev
	if (force || ((config.options.chkAllowBrowserCookies || name=="chkAllowBrowserCookies")
		&& !cmc.blockedCookies.contains(name) && cmc.allowBrowserCookie(name))) {
		cmc.saveOptionCookie.apply(this,arguments);
		cmc.displayStatus(name+"="+config.options[name]);
	} else cmc.displayStatus("setting of '"+name+"' is blocked");
}

// 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=/;'; 
	}
}

// ... and then hijack it to add cookie blocking and monitoring messages
config.macros.cookieManager.removeCookie=removeCookie;
window.removeCookie=function(name,force)
{
	var cmc=config.macros.cookieManager; // abbrev
	if (!cmc.getCookieList().contains(name))
		return; // not a current cookie!
	if (force || ((config.options.chkAllowBrowserCookies || name=="chkAllowBrowserCookies")
		&& !cmc.blockedCookies.contains(name) && cmc.allowBrowserCookie(name))) {
		cmc.removeCookie.apply(this,arguments);
		cmc.displayStatus("deleted "+name);
	} else cmc.displayStatus("deletion of '"+name+"' is blocked");
}
//}}}
/***
|Name|CookieManagerPluginConfig|
|Source|http://www.TiddlyTools.com/#CookieManagerPluginConfig|
|Requires|CookieManagerPlugin|
|Description|custom settings for [[CookieManagerPlugin]]|
!!!!!Browser Cookie Configuration:
***/
// // <<option chkAllowBrowserCookies>> store ~TiddlyWiki option settings using private browser cookies
// // <<option chkMonitorBrowserCookies>> monitor browser cookie activity (shows a message whenever a cookie is updated)
//{{{
// default settings:
config.options.chkAllowBrowserCookies=true;	// if FALSE, this blocks *all* cookies
config.options.chkMonitorBrowserCookies=false;
//}}}

// // Individual cookie names can be prevented from being created, modified, or deleted in your browser's stored cookies by adding them to the {{{config.macros.cookieManager.blockedCookies}}} array: 
//{{{
var bc=config.macros.cookieManager.blockedCookies; // abbreviation
bc.push("txtMainTab");			// TiddlyWiki:  SideBarTabs
bc.push("txtTOCSortBy");		// TiddlyTools: TableOfContentsPlugin
bc.push("txtCatalogTab");		// TiddlyTools: CatalogTabs
//}}}
// // You can also define a javascript test function that determines whether or not any particular cookie name should be blocked or allowed.  The following function should return FALSE if the browser cookie should be blocked, or TRUE if changes to the cookie should be allowed:
//{{{
config.macros.cookieManager.allowBrowserCookie=function(name) {
	// add tests based on specific cookie names and runtime conditions
	return true;
}
//}}}
/***
|Name|CookieSaverPlugin|
|Source|http://www.TiddlyTools.com/#CookieSaverPlugin|
|Version|1.1.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|automatically save TiddlyWiki cookie options to [[CookieJar]] tiddler for portable settings|
!!!!!Usage
<<<
Whenever TiddlyWiki option settings are changed, a browser-based cookie value is added, removed, or changed.  Each time this occurs, the CookieSaverPlugin generates an equivalent ''portable cookie'': a single line of javascript code that assigns a stored value directly to the specific TiddlyWiki internal config.options.* variable corresponding to the browser cookie with the same name.

The portable cookies are automatically written into a tiddler named [[CookieJar]] that is tagged with<<tag systemConfig>>so that their values will be applied as soon as the document is saved and reloaded.  You can change or delete an individual portable cookie by editing the contents of the [[CookieJar]] and removing the appropriate line of javascript from the tiddler source code.  Note: editing the portable cookie definitions does not alter the values of any corresponding browser cookies, nor does it update the internal value that is in use within the current TiddlyWiki document session.  Changes made directly to the [[CookieJar]] are only applied after saving and reloading the document.  In any case, whenever a browser cookie value is updated, any modifications you made to the equivalent portable cookie are immediately rewritten to reflect the current browser cookie value.

Browser cookies are, obviously, stored with your browser... and are kept separate from the document itself.  In contrast, because your portable cookies are stored in a [[CookieJar]] within the document, they remain part of that document.

When the document is copied and shared with others, each copy includes the [[CookieJar]] containing //your// stored portable cookies.  Fortunately, CookieSaverPlugin can generate and maintain several separate sets of portable cookies in the same [[CookieJar]] tiddler, where each set is associated with a different TiddlyWiki username.  As long as other readers have not chosen the same username, your portable cookie values will not be automatically applied when they are reading the document.  Rather, as they interact with the document, a new set of portable cookies, associated with //their// username, will be automatically added to the [[CookieJar]].

In addition to tracking and applying separate portable cookies for each user, CookieSaverPlugin can also be configured so that sensitive data (such as internal URLs, email addresses, login IDs and passwords, etc.) will never be inadvertently stored in the [[CookieJar]].  To achieve this, you can selectively prevent specific cookienames from being used as portable cookies by placing a special javascript function definition in a tiddler named [[CookieSaverPluginConfig]], tagged with 'systemConfig':
{{{
config.macros.cookieSaver.allowPortableCookie=function(name){
	if ( ... some test using 'name' ...) return false;
	if ( ... another test with 'name' ...) return true;
	etc.
	return true;  // default=allow
}
}}}
The allowPortableCookie() function offers a flexible method for plugin developers and other technically skilled document authors to implement their own custom-defined, application-specific cookie data protection by applying sophisticated logic for deciding which cookies should be allowed or blocked based on variety of different conditions.  The basic operation of this function is to accept a cookie name as text input, apply some tests based on that cookie name (combined with any other useful criteria), and then return //true// if saving the portable cookie should be permitted, or //false// if the cookie should be excluded from the [[CookieJar]].

Unfortunately, although the technical expertise needed to write this test function is relatively minor, the level of programming ability that is needed can nonetheless be beyond the skills that many people possess.  To help address this, CookieSaverPlugin also supports an alternative syntax that allows you to define a simple array of cookie names that is used by the plugin to automatically block the indicated names from being included as portable cookies in the [[CookieJar]].  The array definition syntax looks like this:
{{{
// define a complete set of blocked cookie names
config.macros.cookieSaver.blockedCookies=['cookie','cookie','cookie',etc...];
}}}
or
{{{
// add individual cookies names to the current set of blocked cookies
config.macros.cookieSaver.blockedCookies.push('cookie');
config.macros.cookieSaver.blockedCookies.push('cookie');
etc...
}}}
Note: the allowPortableCookie() function and the blockedCookies[] array are only used to limit the creation of portable cookies within the [[CookieJar]], and are //not// applied when creating normal browser cookies.  Thus, regardless of whether or not a given portable cookie has been excluded or permitted, all the usual TiddlyWiki settings and internal state data can still be saved as secure, private, local browser cookies that are never made visible to others, even when the document is shared.
<<<
!!!!!Configuration
<<<
<<option chkPortableCookies>> allow ~CookieSaver to store //''portable cookies''// in [[CookieJar]] tiddler
<<option chkMonitorCookieJar>> monitor ~CookieSaver activity (show messages whenever [[CookieJar]] is updated)
<<option chkCookieJarAddToAdvancedOptions>> display [[CookieJar]] in [[AdvancedOptions]]
^^//note: changing this setting does not take effect until you reload the document//^^
<<<
!!!!!Revisions
<<<
2009.08.05 [1.1.0] changed CookieJar output format to support odd symbols in option names (e.g. '@')
2008.09.11 [1.0.2] automatically add portable cookies header to existing CookieJar (if any).  Also, added chkMonitorCookieJar option to display CookieJar activity messages
2008.09.10 [1.0.1] documentation, code cleanup, improvements in 'allowPortableCookie()' function handling
2008.09.09 [1.0.0] initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.CookieSaverPlugin= {major: 1, minor: 1, revision: 0, date: new Date(2009,8,5)};

config.macros.cookieSaver = {
	target:
		config.options.txtCookieJar||"CookieJar",
	init: function() {
		if (config.options.chkPortableCookies===undefined)
			config.options.chkPortableCookies=false;
		if (config.options.txtCookieJar===undefined)
			config.options.txtCookieJar=this.target;
		if (config.options.chkCookieJarAddToAdvancedOptions===undefined)
			config.options.chkCookieJarAddToAdvancedOptions=true;
		if (config.options.chkCookieJarAddToAdvancedOptions)
			config.shadowTiddlers.AdvancedOptions+="\n!!%0\n><<tiddler [[%0]]>>".format([this.target]);
		if (config.options.chkMonitorCookieJar===undefined)
			config.options.chkMonitorCookieJar=false;

		// add empty Portable Cookies section to shadow CookieJar
		var h="/***\n<<tiddler CookieManager>>\n***/\n";
		var t=(config.shadowTiddlers[this.target]||"").replace(new RegExp(h.replace(/\*/g,'\\*'),''),'')
		config.shadowTiddlers[this.target]=this.header+this.footer+t;

		// add empty Portable Cookies section to real CookieJar (if one exists)
		if (store.tiddlerExists(this.target) && !readOnly) {
			var tid=this.get(this.target);
			var t=tid.text;
			if (t.indexOf(this.header)==-1){
				t=this.header+this.footer+t.replace(new RegExp(h.replace(/\*/g,'\\*'),''),'');
				var who=config.options.chkForceMinorUpdate?tid.modifier:config.options.txtUserName;
				var when=config.options.chkForceMinorUpdate?tid.modified:new Date();
				store.saveTiddler(tid.title,tid.title,t,who,when,tid.tags,tid.fields);
				displayMessage("CookieSaver: added 'Portable Cookies' section to CookieJar");
			}
		}

		// add "cookies" backstage task
		if (config.tasks && !config.tasks.cookies) { // for TW2.2b3 or above
			config.tasks.cookies = {
				text: "cookies",
				tooltip: "manage cookie-based option settings",
				content: "{{groupbox{<<tiddler CookieManager>><<tiddler [[%0]]>>}}}".format([this.target])
			}
			config.backstageTasks.push("cookies");
		}
	},
	header:
		 "/***\n<<tiddler CookieManager>>\n***/\n"
		+"/***\n"
		+"!!![[Portable cookies:|CookieSaverPlugin]] "
		+"{{fine{<<option chkPortableCookies>>enable <<option chkMonitorCookieJar>>monitor}}}\n"
		+"^^This section is ''//__automatically maintained__//'' by [[CookieSaverPlugin]].  "
		+"To block specific cookies, see [[CookieSaverPluginConfig]].^^\n"
		+"***/\n",
	startUser:
		 "//{{{\n"
		+"if (config.options.txtUserName==\"%0\" && config.options.chkPortableCookies) {",
	endUser:
		"\n}\n//}}}\n",
	footer:
		"// // /% end portable cookies %/\n",
	get: function(tid) { // create or retrieve tiddler
		if (story.isDirty(tid)) return null; // tiddler is being hand-edited... leave it alone.
		var text=config.shadowTiddlers[this.target];
		var who=config.options.txtUserName;
		var when=new Date();
		var tags=['systemConfig'];
		return store.getTiddler(tid)||store.saveTiddler(tid,tid,text,who,when,tags,{});
	},
	format: function(name) {
		if (name.substr(0,3)=='chk')
			return '\tconfig.options["'+name+'"]='+(config.options[name]?'true;':'false;');
		return '\tconfig.options["'+name+'"]="'+config.options[name]+'";';
	},
	blockedCookies: [],
	allowPortableCookie: function(name) {
		return true;
	},
	set: function(name) {
		if (!name||!name.trim().length) return;
		if (name=='txtUserName' || this.blockedCookies.contains(name) || !this.allowPortableCookie(name)) {
			if (config.options.chkMonitorCookieJar && !startingUp)
				displayMessage("CookieJar: blocked '"+name+"'");
			return false; // don't save excluded cookies
		}
		var tid=this.get(this.target);
		if (!tid) return false; // if no tiddler... do nothing
		var t=tid.text;
		if (t.indexOf(this.header)==-1) {  // re-add Portable Cookies section if it was deleted by hand edit
			var h="/***\n<<tiddler CookieManager>>\n***/\n";
			t=this.header+this.footer+t.replace(new RegExp(h.replace(/\*/g,'\\*'),''),'');
		}
		var who=config.options.txtUserName;
		var when=new Date();
		var startmark=this.startUser.format([who]);
		var endmark=this.endUser;
		var startpos=t.indexOf(startmark);
		if (startpos==-1) { // insert new user (just before footer)
			if (config.options.chkMonitorCookieJar && !startingUp)
				displayMessage("CookieJar: added new user '"+who+"'");
			var addpos=t.indexOf(this.footer); if (addpos==-1) addpos=t.length;
			t=t.substr(0,addpos)+startmark+endmark+t.substr(addpos);
			startpos=addpos;
		}
		startpos+=startmark.length;
		var endpos=t.indexOf(endmark,startpos);
		var pre=t.substr(0,startpos);
		var lines=t.substring(startpos,endpos).split('\n');
		var post=t.substr(endpos);
		var code=this.format(name);
		var match='\tconfig.options["'+name+'"]=';
		var found=false; var changed=false;
		for (var i=0; i<lines.length; i++) { // find and replace existing setting
			if (lines[i].substr(0,match.length)==match) {
				found=true;
				if (changed=lines[i]!=code) lines[i]=code; // replace value
				if (config.options.chkMonitorCookieJar && !startingUp && changed)
					displayMessage("CookieJar: "+code);
			}
		}
		if (!found && code.length) { // OR, add new setting
			lines[lines.length]=code;
			if (config.options.chkMonitorCookieJar && !startingUp)
				displayMessage("CookieJar: "+code);
		}
		if (found && !changed) return; // don't alter tiddler unless necessary
		t=pre+lines.join('\n')+post;
		var who=config.options.chkForceMinorUpdate?tid.modifier:config.options.txtUserName;
		var when=config.options.chkForceMinorUpdate?tid.modified:new Date();
		store.saveTiddler(this.target,this.target,t,who,when,tid.tags,tid.fields);
		story.refreshTiddler(this.target,null,true);
	},
	remove: function(name) {
		if (!name||!name.trim().length) return;
		var who=config.options.txtUserName;
		var when=new Date();
		var tid=store.getTiddler(this.target);
		if (!tid) return false; // if no tiddler... do nothing
		var t=tid.text;
		var who=config.options.txtUserName
		var startmark=this.startUser.format([who]);
		var endmark=this.endUser;
		var startpos=t.indexOf(startmark);
		if (startpos==-1) return false; // no such user... do nothing
		startpos+=startmark.length;
		var endpos=t.indexOf(endmark,startpos);
		var pre=t.substr(0,startpos);
		var lines=t.substring(startpos,endpos).split('\n');
		var post=t.substr(endpos);
		var match='\tconfig.options["'+name+'"]';
		var found=false; var changed=false;
		for (var i=0; i<lines.length; i++) { // find and remove setting
			if (lines[i].substr(0,match.length)==match) {
				lines.splice(i,1);
				changed=true;
				if (config.options.chkMonitorCookieJar && !startingUp)
					displayMessage("CookieJar: deleted '"+name+"'");
				break;
			}
		}
		if (!changed) return; // not found... do nothing
		t=pre+lines.join('\n')+post;
		if (lines.length==1) { // no cookies left, remove user
			t=pre.substr(0,pre.length-startmark.length)+post.substr(endmark.length);
			if (config.options.chkMonitorCookieJar && !startingUp)
				displayMessage("CookieJar: removed user '"+who+"'");
		}
		var who=config.options.chkForceMinorUpdate?tid.modifier:config.options.txtUserName;
		var when=config.options.chkForceMinorUpdate?tid.modified:new Date();
		store.saveTiddler(this.target,this.target,t,who,when,tid.tags,tid.fields);
		story.refreshTiddler(this.target,null,true);
	}
}
//}}}
//{{{
// Hijack saveOptionCookie() to add CookieSaver processing
config.macros.cookieSaver.saveOptionCookie=saveOptionCookie;
window.saveOptionCookie=function(name)
{
	config.macros.cookieSaver.saveOptionCookie.apply(this,arguments);
	if (!readOnly && (config.options.chkPortableCookies || name=="chkPortableCookies"))
		config.macros.cookieSaver.set(name);
}
// 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=/;'; 
	}
}
// ... and then hijack it to also remove any corresponding PortableCookie
config.macros.cookieSaver.removeCookie=removeCookie;
window.removeCookie=function(name)
{
	if (config.options.chkPortableCookies && !readOnly)
		config.macros.cookieSaver.remove(name);
	config.macros.cookieSaver.removeCookie.apply(this,arguments);
}
//}}}
/***
|Name|CookieSaverPluginConfig|
|Source|http://www.TiddlyTools.com/#CookieSaverPluginConfig|
|Requires|CookieSaverPlugin|
|Description|custom settings for [[CookieSaverPlugin]]|
!!!!!Portable Cookie Configuration:
***/
// // <<option chkPortableCookies>> allow ~CookieSaver to store //''portable cookies''// in [[CookieJar]] tiddler
// // <<option chkMonitorCookieJar>> monitor ~CookieSaver activity (show messages whenever [[CookieJar]] is updated)
//{{{
// default to these settings:
// config.options.chkPortableCookies=false;	// when FALSE this blocks ALL portable cookies
// config.options.chkMonitorCookieJar=false;
//}}}

// // Individual cookie names can be added to the {{{config.macros.cookieSaver.blockedCookies}}} array to prevent them from being stored in the [[CookieJar]].
//{{{
var bc=config.macros.cookieSaver.blockedCookies;
bc.push("chkBackstage");		// core
bc.push("txtMainTab");			// TiddlyWiki: SideBarTabs
bc.push("txtTOCSortBy");		// TiddlyTools: TableOfContentsPlugin
bc.push("txtCatalogTab");		// TiddlyTools: CatalogTabs
bc.push("txtUploadFilename");		// BidiX: UploadPlugin
bc.push("txtUploadDir");		// BidiX: UploadPlugin
bc.push("pasPassword");			// BidiX: UploadPlugin
bc.push("pasUploadPassword");		// BidiX: UploadPlugin
//}}}
// // You can also define a javascript test function that determines whether or not any particular cookie name should be stored in the [[CookieJar]].  The following function should return FALSE if the portable cookie should be blocked, or TRUE if the cookie should be allowed:
//{{{
config.macros.cookieSaver.allowPortableCookie=function(name) {
	// add tests based on specific cookie names and runtime conditions
	if (name.substr(0,9)=="chkSlider") 	return false;	// NestedSlidersPlugin
	if (name.substr(0,13)=="txtFirstVisit")	return false;	// VisitCounter
	if (name.substr(0,12)=="txtLastVisit")	return false;	// VisitCounter
	if (name.substr(0,13)=="txtVisitCount")	return false;	// VisitCounter
	return true;
}
//}}}
/***
|Name|CopyTiddlerPlugin|
|Source|http://www.TiddlyTools.com/#CopyTiddlerPlugin|
|Version|3.2.6|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.3|
|Type|plugin|
|Description|Quickly create a copy of any existing tiddler|
!!!Usage
<<<
The plugin automatically updates the default (shadow) ToolbarCommands definitions to insert the ''copyTiddler'' command, which will appear as ''copy'' when a tiddler is rendered.  If you are already using customized toolbar definitions, you will need to manually add the ''copyTiddler'' toolbar command to your existing ToolbarCommands tiddler, e.g.:
{{{
|EditToolbar|... copyTiddler ... |
}}}
When the ''copy'' command is selected, a new tiddler is created containing an exact copy of the current text/tags/fields, using a title of "{{{TiddlerName (n)}}}", where ''(n)'' is the next available number (starting with 1, of course).  If you copy while //editing// a tiddler, the current values displayed in the editor are used (including any changes you may have already made to those values), and the new tiddler is immediately opened for editing.

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

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

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

config.commands.copyTiddler = {
	text: 'copy',
	hideReadOnly: true,
	tooltip: 'Make a copy of this tiddler',
	notitle: 'this tiddler',
	prefix: '',
	suffixText: ' (%0)',
	suffixPattern: / \(([0-9]+)\)$/,
	zeroPad: 0,
	sparse: false,
	handler: function(event,src,title)
		{ return config.commands.copyTiddler.click(src,event); },
	click: function(here,ev) {
		var tiddlerElem=story.findContainingTiddler(here);
		var template=tiddlerElem?tiddlerElem.getAttribute('template'):null;
		var title=here.getAttribute('from');
		if (!title || !title.length) {
			if (!tiddlerElem) return false;
			else title=tiddlerElem.getAttribute('tiddler');
		}
		var root=title.replace(this.suffixPattern,''); // title without suffix
		// find last matching title
		var last=title;
		if (this.sparse) { // don't fill-in holes... really find LAST matching title
			var tids=store.getTiddlers('title','excludeLists');
			for (var t=0; t<tids.length; t++) if (tids[t].title.startsWith(root)) last=tids[t].title;
		}
		// get next number (increment from last matching title)
		var n=1; var match=this.suffixPattern.exec(last); if (match) n=parseInt(match[1])+1;
		var newTitle=this.prefix+root+this.suffixText.format([String.zeroPad(n,this.zeroPad)]);
		// if not sparse mode, find the next hole to fill in...
		while (store.tiddlerExists(newTitle)||story.getTiddler(newTitle))
			{ n++; newTitle=this.prefix+root+this.suffixText.format([String.zeroPad(n,this.zeroPad)]); }
		if (!story.isDirty(title)) { // if tiddler is not being EDITED
			// duplicate stored tiddler (if any)
			var text=store.getTiddlerText(title,'');
			var who=config.options.txtUserName;
			var when=new Date();
			var newtags=[]; var newfields={};
			var tid=store.getTiddler(title); if (tid) {
				if (config.options.chkCopyTiddlerDate) var when=tid.modified;
				for (var t=0; t<tid.tags.length; t++) newtags.push(tid.tags[t]);
				store.forEachField(tid,function(t,f,v){newfields[f]=v;},true);
			}
	                store.saveTiddler(newTitle,newTitle,text,who,when,newtags,newfields,true);
			story.displayTiddler(tiddlerElem,newTitle,template);
		} else {
			story.displayTiddler(tiddlerElem,newTitle,template);
			var fields=config.commands.copyTiddler.gatherFields(tiddlerElem); // get current editor fields
			var newTiddlerElem=story.getTiddler(newTitle);
			for (var f=0; f<fields.length; f++) {  // set fields in new editor
				if (fields[f].name=='title') fields[f].value=newTitle; // rename title in new tiddler
				var fieldElem=config.commands.copyTiddler.findField(newTiddlerElem,fields[f].name);
				if (fieldElem) {
					if (fieldElem.getAttribute('type')=='checkbox')
						fieldElem.checked=fields[f].value;
					else 
						fieldElem.value=fields[f].value;
				}
			}
		}
		story.focusTiddler(newTitle,'title');
		return false;
	},
	findField: function(tiddlerElem,field) {
		var inputs=tiddlerElem.getElementsByTagName('input');
		for (var i=0; i<inputs.length; i++) {
			if (inputs[i].getAttribute('type')=='checkbox' && inputs[i].field == field) return inputs[i];
			if (inputs[i].getAttribute('type')=='text' && inputs[i].getAttribute('edit') == field) return inputs[i];
		}
		var tas=tiddlerElem.getElementsByTagName('textarea');
		for (var i=0; i<tas.length; i++) if (tas[i].getAttribute('edit') == field) return tas[i];
		var sels=tiddlerElem.getElementsByTagName('select');
		for (var i=0; i<sels.length; i++) if (sels[i].getAttribute('edit') == field) return sels[i];
		return null;
	},
	gatherFields: function(tiddlerElem) { // get field names and values from current tiddler editor
		var fields=[];
		// get checkboxes and edit fields
		var inputs=tiddlerElem.getElementsByTagName('input');
		for (var i=0; i<inputs.length; i++) {
			if (inputs[i].getAttribute('type')=='checkbox')
				if (inputs[i].field) fields.push({name:inputs[i].field,value:inputs[i].checked});
			if (inputs[i].getAttribute('type')=='text')
				if (inputs[i].getAttribute('edit')) fields.push({name:inputs[i].getAttribute('edit'),value:inputs[i].value});
		}
		// get textareas (multi-line edit fields)
		var tas=tiddlerElem.getElementsByTagName('textarea');
		for (var i=0; i<tas.length; i++)
			if (tas[i].getAttribute('edit')) fields.push({name:tas[i].getAttribute('edit'),value:tas[i].value});
		// get selection lists (droplist or listbox)
		var sels=tiddlerElem.getElementsByTagName('select');
		for (var i=0; i<sels.length; i++)
			if (sels[i].getAttribute('edit')) fields.push({name:sels[i].getAttribute('edit'),value:sels[i].value});
		return fields;
	}
};
//}}}
// // MACRO DEFINITION
//{{{
config.macros.copyTiddler = {
	label: 'copy',
	prompt: 'Make a copy of %0',
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		var title=params.shift();
		params=paramString.parseParams('anon',null,true,false,false);
		var label	=getParam(params,'label',this.label+(title?' '+title:''));
		var prompt	=getParam(params,'prompt',this.prompt).format([title||this.notitle]);
		var b=createTiddlyButton(place,label,prompt,
			function(ev){return config.commands.copyTiddler.click(this,ev)});
		b.setAttribute('from',title||'');
	}
};
//}}}
/***
|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 - %1, %2 (%3 bytes) - %4';
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>>
/%
|Name|CreateTiddlersFromCSV|
|Source|http://www.TiddlyTools.com/#CreateTiddlersFromCSV|
|Version|1.3.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|html|
|Description|create tiddlers from CSV data|

!FORMAT
<<<
~Comma-Separated Value (CSV) format:
{{{
title,created,modified,modifier,tags,text,customfield1,customfield2,...
MyTiddler,04/25/2009,04/25/2009,YourName,tag1 [[tag 2]] tag3,"This is ""quoted"" content, with a comma",value,value,...
}}}
{{wrap{
''The first line contains lower-case field names and must include a //"title"// field''.  Subsequent lines define //~CSV-encoded// data: any values that contain quotes or commas are surrounded by double-quotes, and quotes occuring //within// the values are doubled-up.  The ''tags'' field is entered as a //space-separated bracketed list//. Additional fieldnames ("fieldN") are added as custom tiddler fields.}}}
<<<
!end

REVISIONS:
[1.3.1] remove debugging message
[1.3.0] correct handling for embedded quotes and strip \r from input
[1.2.0] convert created/modified values from strings to date objects
[1.1.0] handle CSV-encoded embedded commas and quotes

%/<<tiddler HideTiddlerTags>>{{small smallform{
Enter/paste<<slider {{config.options['']=false;'';}}
	[[CreateTiddlersFromCSV##FORMAT]] 'CSV-formatted data...' 'view CSV format description'
>> or, read data from a tiddler: <html><nowiki>
	<form style='display:inline;margin:0;padding:0;white-space:normal;'>
	<select class='editor' name='tid' title='select a tiddler title'>
	<option>select a tiddler title...</option>
	</select>
	<input type='button' value='get data'
		onclick="this.form.src.value=store.getTiddlerText(this.form.tid.value,'')">
	<input type='button' value='create tiddlers' onclick="
		var CSV=this.form.src.value;
		// GET NAMES
		var lines=CSV.replace(/\r/g,'').split('\n');
		var names=lines.shift().replace(/\x22/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(/\x22([^\x22]*?)\x22/g, function(x){ return x.replace(/\,/g,comma).replace(/\n/g,newline); });
		var lines=CSV.split('\n'); var count=0;
		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 j=0; j<values.length; j++)
				values[j]=values[j].replace(commaRE,',').replace(newlineRE,'\n')
					.replace(/^\x22|\x22$/g,'').replace(/\x22\x22/g,'\x22');
			// 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;
				}
			}
			if (title.length) {
				store.saveTiddler(title,title,text,who,when,tags,fields,true,created||when);
				displayMessage('Created '+title);
				count++;
			}
			else if (!confirm('invalid data on line '+i+': missing/blank TiddlerName\n\n'
				+values.join('\n')+'\n\n\OK=skip, CANCEL=stop')) break;
		}
		displayMessage('Created '+count+' tiddlers');
	"><br><textarea class='editor' name='src' style='display:inline;width:100%;height:10em;'></textarea>
	</form>
</html><<tiddler {{
	var list=place.lastChild.getElementsByTagName('form')[0].tid;
	store.forEachTiddler(function(title,tiddler){
		list.options[list.length]=new Option(title,title);
	});
'';}}>>}}}
/%
*** DO NOT INSTALL THIS TIDDLER IN YOUR OWN DOCUMENTS ***

This tiddler has been customized for use on TiddlyTools.com:
* suppress tiddler background
* suppress tabContent border/padding (for "Page" tab only)

%/<<tiddler HideTiddlerBackground>><script>
	place.style.border="0";
	place.style.padding="0";
</script><<currentTiddler>>
/%
!info
|Name|CycleThemes|
|Source|http://www.TiddlyTools.com/#CycleThemes|
|Version|2.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Description|creates command link to cycle through systemThemes|
Usage
<<<
{{{
<<tiddler CycleThemes>>
<<tiddler CycleThemes with: label "theme theme theme">>
}}}
*''label'' (optional)<br>text of command link. default='next theme'
*''"theme theme theme"'' (optional)<br>list of theme tiddlers to cycle through.   default=[[StyleSheet]] plus all tiddlers tagged with<<tag systemTheme>>, except those tagged with<<tag excludeTheme>>or<<tag excludeLists>>
<<<
Examples
<<<
*Cycle through all themes:<br>{{{<<tiddler CycleThemes>>}}}<br><<tiddler CycleThemes##show with: 'next theme' >>
*Toggle between two themes:<br>{{{<<tiddler CycleThemes with: "toggle" "StyleSheet Plain">>}}}<br><<tiddler CycleThemes##show with: "toggle" "StyleSheet Plain">>
*Apply a theme:<br>{{{<<tiddler CycleThemes with: "default" StyleSheet>>}}}<br><<tiddler CycleThemes##show with: "use default StyleSheet" StyleSheet>>
<<<
!end
!show
<html><nowiki><a href="javascript:;"
onmouseover="
	this.title='current theme: '+config.options.txtTheme;
	this.href='javascript:void(eval(decodeURIComponent(%22(function(){try{('
	+encodeURIComponent(encodeURIComponent(this.onclick))
	+')()}catch(e){alert(e.description?e.description:e.toString())}})()%22)))';"
onclick="
	var titles='$2'.readBracketedList();
	if ('$2'=='$'+'2') {
		var tids=store.getTaggedTiddlers('systemTheme');
		titles=tids.map(function(t){return t.tags.contains('excludeTheme','excludeLists')?null:t.title;});
		titles.pushUnique('StyleSheet');
	}
	var curr=titles.indexOf(config.options.txtTheme);
	var next=curr+1>=titles.length?0:curr+1;
	while(!titles[next] && next!=curr) next=next+1>=titles.length?0:next+1;
	story.switchTheme(titles[next]);
	return false;"
>$1</a></html>
!end
%/<<tiddler {{var src='CycleThemes'; src+(tiddler&&tiddler.title==src?'##info':'##show')}}
	with: {{'$1'=='$'+'1'?'next theme':'$1'}} "$2">>
/***
|Name|DOMTweaksPlugin|
|Source|http://www.TiddlyTools.com/#DOMTweaksPlugin|
|Version|1.0.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|set DOM element IDs, add/remove classes and/or reposition rendered elements|
This plugin defines several useful macro-based functions for performing direct manipulation of DOM elements, including setting element ID's, moving elements, and adding/removing classnames from elements.
!!!!!Usage
<<<
{{{<<DOM setID id force>>}}}
>assign an ID to the DOM element in which this macro is being rendered.  If the current DOM element already has an ID, the new ID will //not// replace  the current ID, unless you include the additional "''force''" keyword parameter.  (note: requiring this extra parameter helps minimize any problems that may arise if an existing, system-assigned ID is unintentionally re-assigned due to mis-placement of the macro... e.g., renaming 'mainMenu' or 'header' is NOT a good idea, and is prevented unless "force" is used)
{{{<<DOM move id>>}}}
>Move any uniquely identified DOM element to the current rendering location.  Allows dynamic relocation of standard TW elements such as 'sidebar', 'mainMenu', as well as any other DOM elements that have an ID assigned to them (via the {{{<<DOM setID id>>}}} macro).  You can also use this macro to move [[NestedSlidersPlugin]]-generated slider/floating panels that have had an ID assigned to them (using either the {{{<<DOM setID id>>}}} macro or the NestedSlidersPlugin {{{#panelID:}}} syntax).
{{{<<DOM addclass classname>>}}}
>add a classname to the DOM element in which this macro is being rendered
{{{<<DOM removeClass classname>>}}}
>remove a classname from the DOM element in which this macro is being rendered
<<<
!!!!!Revisions
<<<
2007.07.20 [1.0.1] in setID handler, check for existing ID so multiple elements don't get the same ID.  Also added basic parameter checks.
2007.07.20 [1.0.0] initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.DOMTweaksPlugin= {major: 1, minor: 0, revision: 1, date: new Date(2007,7,20)};
config.macros.DOM= {
	handler: function(place,macroName,params) {
		if (!params.length) return;
		switch (params[0].toUpperCase()) {
			case "SETID":
				if (!params[1]) return;
				if (place.id==params[1]) break; // already has this ID... do nothing!
				if (document.getElementById(params[1])) // if ID is already used by something else
					displayMessage("DOMTweaks: ID already in use: '"+params[1]+"'");
				else if (!place.id.length || params[2]&&params[2].toUpperCase=="FORCE")
					place.id=params[1]; // set (or clear) the ID
				else
					displayMessage("DOMTweaks: to re-assign existing ID for '"+place.id+"', use the 'Force' option... Luke. :-)" );
				break;
			case "MOVE":
				if (!params[1]) return;
				var e=document.getElementById(params[1]); if (e) place.insertBefore(e,null);
				break;
			case "ADDCLASS":
				if (!params[1]) return;
				if (addClass instanceof Function) addClass(place,params[1]);
				break;
			case "REMOVECLASS":
				if (!params[1]) return;
				if (removeClass instanceof Function) removeClass(place,params[1]);
				break;
		}
	}
}
//}}}
/***
|Name|DOMViewerPlugin|
|Source|http://www.TiddlyTools.com/#DOMViewerPlugin|
|Version|1.8.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|display internal Document Object Model for wiki-formatted content|
Whenever TiddlyWiki renders a given tiddler, it creates a 'tree' of DOM (Document Object Model) elements that represent the information that is displayed by the browser.  You can use the ''DOMViewer'' macro to examine the internal DOM elements that are produced by TiddlyWiki's formatter (the 'wikifier'), or elements directly produced by embedded macros that create custom formatted output.  This can be particularly helpful when trying to fine tune the layout and appearance of your tiddler content.
!!!!! Usage/Example:
<<<
syntax: {{{<<DOMViewer rows:nn indent:xxxx inline path elementID|tiddlertitle>>}}}

DOMViewer creates a textarea control and reports the DOM tree for the current 'insertion point' where the DOMViewer macro is being placed.  ''inline'' flag uses TiddlyWiki rendering instead of textarea control. ''path'' shows the relative location of each child element in the DOM tree, using subscript notation, ''[elementID or tiddlertitle]'' displays DOM elements starting from the node with the specified ID.  If that ID is not found in the DOM tree, the macro attempts to open a tiddler with that title and then displays the DOM elements that were rendered for that tiddler.

<<DOMViewer tiddlerDOMViewerPlugin>>
<<<
!!!!!Revisions
<<<
2010.11.30 1.8.1 use story.getTiddler()
2007.09.27 1.8.0 split DOMViewer macro into separate plugin (see [[TidIDEPlugin]])
|please see [[TidIDEPluginInfo]] for additional revision details|
2006.04.15 0.5.0 Initial ALPHA release. Converted from inline script.
<<<
!!!!!Code
***/
//{{{
version.extensions.DOMViewerPlugin= {major: 1, minor: 8, revision: 1, date: new Date(2010,11,30)};
config.macros.DOMViewer = { 
	handler: function(place,macroName,params) {
		// set default params
		var inline=false;
		var theRows=15;
		var theIndent="|  ";
		var showPath=false;
		var theTarget=place;
		// unpack options parameters
		if (params[0]=='inline') { inline=true; theIndent=">"; params.shift(); } 
		if (params[0]&&(params[0].substr(0,7)=="indent:")) { theIndent=params[0].substr(7); params.shift(); } 
		if (params[0]&&(params[0].substr(0,5)=="rows:")) { theRows=params[0].substr(5); params.shift(); } 
		if (params[0]=='path') { showPath=true; params.shift(); } 
		if (params[0]) { var title=params[0]
			theTarget=document.getElementById(title);
			if (!theTarget)
				if (store.getTiddler(title)!=undefined) {
					theTarget=story.getTiddler(title);
					if (!theTarget && confirm("DOMViewer asks:\n\nIs it OK to open tiddler '"+title+"' now?")) { 
						story.displayTiddler(null,title,1,null,null,false);
						theTarget=story.getTiddler(title);
					}
				}
			params.shift();
		}
		// generate and display DOM tree
		if (inline) {
			var out=this.getNodeTree(theTarget,theIndent,showPath,inline);
			wikify(out,place);
		}
		else {
			var out=this.getNodeTree(theTarget,theIndent,showPath,inline);
			var css=".DOMViewer{width:100%;font-size:8pt;color:inherit;background:transparent;border:0px;}";
			setStylesheet(css,"DOMViewerStylesheet");
			var theTextArea=createTiddlyElement(place,"textarea",null,"DOMViewer",out);
			theTextArea.rows=theRows;
			theTextArea.cols=60;
			theTextArea.wrap="off";
			theTextArea.theTarget=theTarget;
			theTextArea.theIndent=theIndent;
			theTextArea.showPath=showPath;
		}
	},
	getNodeTree: function(theNode,theIndent,showPath,inline,thePrefix,thePath) {
		if (!theNode) return "";
		if (!thePrefix) thePrefix="";
		if (!thePath) thePath="";
		var mquote='"'+(inline?"{{{":"");
		var endmquote=(inline?"}}}":"")+'"';
		// generate output for this node
		var out = thePrefix;
		if (showPath && thePath.length)
			out += (inline?"//":"")+thePath.substr(1)+":"+(inline?"//":"")+"\r\n"+thePrefix;
		if (theNode.className=="DOMViewer")
			return out+'[DOMViewer]\r\n'; // avoid self-referential recursion
		out += (inline?"''":"")+theNode.nodeName.toUpperCase()+(inline?"''":"");
		if (theNode.nodeName=="#text")
			out += ' '+mquote+theNode.nodeValue.replace(/\n/g,'\\n')+endmquote;
		if (theNode.className)
			out += ' class='+mquote+theNode.className+endmquote;
		if (theNode.type)
			out += ' type='+mquote+theNode.type+endmquote;
		if (theNode.id)
			out += ' id='+mquote+theNode.id+endmquote;
		if (theNode.name)
			out += " "+theNode.name+(theNode.value?"="+mquote+theNode.value+endmquote:"");
		if (theNode.href)
			out += ' href='+mquote+theNode.href+endmquote;
		if (theNode.src)
			out += ' src='+mquote+theNode.src+endmquote;
		if (theNode.attributes && theNode.getAttribute("tiddlyLink")!=undefined)
			out += ' tiddler='+mquote+theNode.getAttribute("tiddlyLink")+endmquote;
		out += "\r\n";
		// recursively generate output for child nodes
		thePath=thePath+"."+theNode.nodeName.toLowerCase();
		thePrefix=theIndent+thePrefix;
		for (var i=0;i<theNode.childNodes.length;i++) {
			var thisChild=theNode.childNodes.item(i);
			var theNum=(inline?"~~":"(")+(i+1)+(inline?"~~":")");
			out += this.getNodeTree(thisChild,theIndent,showPath,inline,thePrefix,thePath+theNum);
		}
		return out;
	}
}
//}}}
/%
|Name|DailyChecklist|
|Source|http://www.TiddlyTools.com/#DailyChecklist|
|Version|2.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.4|
|Type|transclusion|
|Description|example of self-contained tag-based daily checklist|

----- EDIT THIS SECTION ONLY ----- %/
Five things to do every day:
<<<
<<tiddler DailyChecklist##toggletag with: questions>> Ask questions
<<tiddler DailyChecklist##toggletag with: answers>> Seek Answers
<<tiddler DailyChecklist##toggletag with: fun>> Have Fun
<<tiddler DailyChecklist##toggletag with: difference>> Make A Difference
<<tiddler DailyChecklist##toggletag with: smile>> Smile
----
<<tiddler DailyChecklist##toggleall with: "questions answers fun difference smile">> //toggle all checkboxes//
<<<
<<tiddler DailyChecklist##resetall with: "reset all items" "questions answers fun difference smile">>
/% ----- DO NOT EDIT BELOW THIS LINE -----

!toggletag
<html><nowiki><form style="display:inline">
	<input type="checkbox" name='c' onclick="
		var tid=story.findContainingTiddler(this).getAttribute('tiddler');
	 	store.setTiddlerTag(tid,this.checked,'$1');
	">
</form></html><<tiddler {{
	var t=store.getTiddler(story.findContainingTiddler(place).getAttribute('tiddler'));
	place.lastChild.getElementsByTagName('form')[0].c.checked=t.isTagged('$1');
'';}}>>
!end toggletag

!toggleall
<html><nowiki><form style="display:inline">
	<input type="checkbox" name="c" onclick="
		var tid=story.findContainingTiddler(this).getAttribute('tiddler');
		var tags='$1'.readBracketedList();
		store.suspendNotifications();
		for (var t=0; t<tags.length; t++)
			store.setTiddlerTag(tid,this.checked,tags[t]);
		store.resumeNotifications();
		story.refreshTiddler(tid,null,true);
	">
</form></html><<tiddler {{
	var t=store.getTiddler(story.findContainingTiddler(place).getAttribute('tiddler'));
	var tags='$1'.readBracketedList(); 
	place.lastChild.getElementsByTagName('form')[0].c.checked=t.tags.containsAll(tags);
'';}}>>
!end toggleall

!resetall
<html><nowiki><form style="display:inline">
	<input type="button" value="$1" onclick="
		var tid=story.findContainingTiddler(this).getAttribute('tiddler');
		var tags='$2'.readBracketedList();
		store.suspendNotifications();
		for (var t=0; t<tags.length; t++)
			store.setTiddlerTag(tid,false,tags[t]);
		store.resumeNotifications();
		story.refreshTiddler(tid,null,true);
"></form></html>
!end resetall
%/
/***
|Name|[[DatePlugin]]|
|Source|http://www.TiddlyTools.com/#DatePlugin|
|Documentation|http://www.TiddlyTools.com/#DatePluginInfo|
|Version|2.7.3|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|formatted dates plus popup menu with 'journal' link, changes and (optional) reminders|
This plugin provides a general approach to displaying formatted dates and/or links and popups that permit easy navigation and management of tiddlers based on their creation/modification dates.
!!!!!Documentation
>see [[DatePluginInfo]]
!!!!!Configuration
<<<
<<option chkDatePopupHideCreated>> omit 'created' section from date popups
<<option chkDatePopupHideChanged>> omit 'changed' section from date popups
<<option chkDatePopupHideTagged>> omit 'tagged' section from date popups
<<option chkDatePopupHideReminders>> omit 'reminders' section from date popups
<<option chkShowJulianDate>> display Julian day number (1-365) below current date

see [[DatePluginConfig]] for additional configuration settings, for use in calendar displays, including:
*date formats
*color-coded backgrounds
*annual fixed-date holidays
*weekends
<<<
!!!!!Revisions
<<<
2011.04.23 2.7.3 added config.macros.date.tipformat for custom mouseover tooltip and config.macros.date.leadtime for custom reminder leadtime (default=90 days)
2010.12.15 2.7.2 omit date highlighting when hiding popup items (created/changed/tagged/reminders)
|please see [[DatePluginInfo]] for additional revision details|
2005.10.30 0.9.0 pre-release
<<<
!!!!!Code
***/
//{{{
version.extensions.DatePlugin= {major: 2, minor: 7, revision: 3, date: new Date(2011,4,23)};

config.macros.date = {
	format: 'YYYY.0MM.0DD', // default date display format
	linkformat: 'YYYY.0MM.0DD', // 'dated tiddler' link format
	tipformat: 'YYYY.0MM.0DD', // 'dated tiddler' link tooltip format
	leadtime: 31, // find reminders up to 31 days from now
	linkedbg: '#babb1e',
	todaybg: '#ffab1e',
	weekendbg: '#c0c0c0',
	holidaybg: '#ffaace',
	createdbg: '#bbeeff',
	modifiedsbg: '#bbeeff',
	remindersbg: '#c0ffee',
	weekend: [ 1,0,0,0,0,0,1 ], // [ day index values: sun=0, mon=1, tue=2, wed=3, thu=4, fri=5, sat=6 ],
	holidays: [ '01/01', '07/04', '07/24', '11/24' ]
		// NewYearsDay, IndependenceDay(US), Eric's Birthday (hooray!), Thanksgiving(US)
};

config.macros.date.handler = function(place,macroName,params)
{
	// default: display current date
	var now =new Date();
	var date=now;
	var mode='display';
	if (params[0]&&['display','popup','link'].contains(params[0].toLowerCase()))
		{ mode=params[0]; params.shift(); }

	if (!params[0] || params[0]=='today')
		{ params.shift(); }
	else if (params[0]=='filedate')
		{ date=new Date(document.lastModified); params.shift(); }
	else if (params[0]=='tiddler')
		{ date=store.getTiddler(story.findContainingTiddler(place).id.substr(7)).modified; params.shift(); }
	else if (params[0].substr(0,8)=='tiddler:')
		{ var t; if ((t=store.getTiddler(params[0].substr(8)))) date=t.modified; params.shift(); }
	else {
		var y = eval(params.shift().replace(/Y/ig,(now.getYear()<1900)?now.getYear()+1900:now.getYear()));
		var m = eval(params.shift().replace(/M/ig,now.getMonth()+1));
		var d = eval(params.shift().replace(/D/ig,now.getDate()+0));
		date = new Date(y,m-1,d);
	}
	// date format with optional custom override
	var format=this.format; if (params[0]) format=params.shift();
	var linkformat=this.linkformat; if (params[0]) linkformat=params.shift();
	showDate(place,date,mode,format,linkformat);
}

window.showDate=showDate;
function showDate(place,date,mode,format,linkformat,autostyle,weekend)
{
	mode	  =mode||'display';
	format	  =format||config.macros.date.format;
	linkformat=linkformat||config.macros.date.linkformat;

	// format the date output
	var title=date.formatString(format);
	var linkto=date.formatString(linkformat);
	var tip=date.formatString(config.macros.date.tipformat);

	// just show the formatted output
	if (mode=='display') { place.appendChild(document.createTextNode(title)); return; }

	// link to a 'dated tiddler'
	var link = createTiddlyLink(place, linkto, false);
	link.appendChild(document.createTextNode(title));
	link.title = tip;
	link.date = date;
	link.format = format;
	link.linkformat = linkformat;

	// if using a popup menu, replace click handler for dated tiddler link
	// with handler for popup and make link text non-italic (i.e., an 'existing link' look)
	if (mode=='popup') {
		link.onclick = onClickDatePopup;
		link.style.fontStyle='normal';
	}
	// format the popup link to show what kind of info it contains (for use with calendar generators)
	if (autostyle) setDateStyle(place,link,weekend);
}
//}}}
//{{{
// NOTE: This function provides default logic for setting the date style when displayed in a calendar
// To customize the date style logic, please see[[DatePluginConfig]]
function setDateStyle(place,link,weekend) {
	// alias variable names for code readability
	var date=link.date;
	var fmt=link.linkformat;
	var linkto=date.formatString(fmt);
	var cmd=config.macros.date;

	var co=config.options; // abbrev

	if ((weekend!==undefined?weekend:isWeekend(date))&&(cmd.weekendbg!=''))
		{ place.style.background = cmd.weekendbg; }
	if (hasModifieds(date)||hasCreateds(date)||hasTagged(date,fmt))
		{ link.style.fontStyle='normal'; link.style.fontWeight='bold'; }
	if (hasReminders(date))
		{ link.style.textDecoration='underline'; }
	if (isToday(date))
		{ link.style.border='1px solid black'; }
	if (isHoliday(date)&&(cmd.holidaybg!=''))
		{ place.style.background = cmd.holidaybg; }
	if (hasCreateds(date)&&(cmd.createdbg!=''))
		{ place.style.background = cmd.createdbg; }
	if (hasModifieds(date)&&(cmd.modifiedsbg!=''))
		{ place.style.background = cmd.modifiedsbg; }
	if ((hasTagged(date,fmt)||store.tiddlerExists(linkto))&&(cmd.linkedbg!=''))
		{ place.style.background = cmd.linkedbg; }
	if (hasReminders(date)&&(cmd.remindersbg!=''))
		{ place.style.background = cmd.remindersbg; }
	if (isToday(date)&&(cmd.todaybg!=''))
		{ place.style.background = cmd.todaybg; }
	if (config.options.chkShowJulianDate) { // optional display of Julian date numbers
		var m=[0,31,59,90,120,151,181,212,243,273,304,334];
		var d=date.getDate()+m[date.getMonth()];
		var y=date.getFullYear();
		if (date.getMonth()>1 && (y%4==0 && y%100!=0) || y%400==0)
			d++; // after February in a leap year
		wikify('@@font-size:80%;<br>'+d+'@@',place);
	}

}
//}}}
//{{{
function isToday(date) // returns true if date is today
	{ var now=new Date(); return ((now-date>=0) && (now-date<86400000)); }
function isWeekend(date) // returns true if date is a weekend
	{ return (config.macros.date.weekend[date.getDay()]); }
function isHoliday(date) // returns true if date is a holiday
{
	var longHoliday = date.formatString('0MM/0DD/YYYY');
	var shortHoliday = date.formatString('0MM/0DD');
	for(var i = 0; i < config.macros.date.holidays.length; i++) {
		var holiday=config.macros.date.holidays[i];
		if (holiday==longHoliday||holiday==shortHoliday) return true;
	}
	return false;
}
//}}}
//{{{
// Event handler for clicking on a day popup
function onClickDatePopup(e) { e=e||window.event;
	var p=Popup.create(this); if (!p) return false;
	// always show dated tiddler link (or just date, if readOnly) at the top...
	if (!readOnly || store.tiddlerExists(this.date.formatString(this.linkformat)))
		createTiddlyLink(createTiddlyElement(p,'li'),this.date.formatString(this.linkformat),true);
	else
		createTiddlyText(createTiddlyElement(p,'li'),this.date.formatString(this.linkformat));
	addCreatedsToPopup(p,this.date,this.format);
	addModifiedsToPopup(p,this.date,this.format);
	addTaggedToPopup(p,this.date,this.linkformat);
	addRemindersToPopup(p,this.date,this.linkformat);
	Popup.show(); e.cancelBubble=true; if(e.stopPropagation)e.stopPropagation(); return false;
}
//}}}
//{{{
function indexCreateds() // build list of tiddlers, hash indexed by creation date
{
	var createds= { };
	var tiddlers = store.getTiddlers('title','excludeLists');
	for (var t = 0; t < tiddlers.length; t++) {
		var date = tiddlers[t].created.formatString('YYYY0MM0DD')
		if (!createds[date])
			createds[date]=new Array();
		createds[date].push(tiddlers[t].title);
	}
	return createds;
}
function hasCreateds(date) // returns true if date has created tiddlers
{
	if (config.options.chkDatePopupHideCreated) return false;
	if (!config.macros.date.createds) config.macros.date.createds=indexCreateds();
	return (config.macros.date.createds[date.formatString('YYYY0MM0DD')]!=undefined);
}

function addCreatedsToPopup(p,when,format)
{
	if (config.options.chkDatePopupHideCreated) return false;
	var force=(store.isDirty() && when.formatString('YYYY0MM0DD')==new Date().formatString('YYYY0MM0DD'));
	if (force || !config.macros.date.createds) config.macros.date.createds=indexCreateds();
	var indent=String.fromCharCode(160)+String.fromCharCode(160);
	var createds = config.macros.date.createds[when.formatString('YYYY0MM0DD')];
	if (createds) {
		createds.sort();
		var e=createTiddlyElement(p,'div',null,null,'created ('+createds.length+')');
		for(var t=0; t<createds.length; t++) {
			var link=createTiddlyLink(createTiddlyElement(p,'li'),createds[t],false);
			link.appendChild(document.createTextNode(indent+createds[t]));
		}
	}
}
//}}}
//{{{
function indexModifieds() // build list of tiddlers, hash indexed by modification date
{
	var modifieds= { };
	var tiddlers = store.getTiddlers('title','excludeLists');
	for (var t = 0; t < tiddlers.length; t++) {
		var date = tiddlers[t].modified.formatString('YYYY0MM0DD')
		if (!modifieds[date])
			modifieds[date]=new Array();
		modifieds[date].push(tiddlers[t].title);
	}
	return modifieds;
}
function hasModifieds(date) // returns true if date has modified tiddlers
{
	if (config.options.chkDatePopupHideChanged) return false;
	if (!config.macros.date.modifieds) config.macros.date.modifieds = indexModifieds();
	return (config.macros.date.modifieds[date.formatString('YYYY0MM0DD')]!=undefined);
}

function addModifiedsToPopup(p,when,format)
{
	if (config.options.chkDatePopupHideChanged) return false;
	var date=when.formatString('YYYY0MM0DD');
	var force=(store.isDirty() && date==new Date().formatString('YYYY0MM0DD'));
	if (force || !config.macros.date.modifieds) config.macros.date.modifieds=indexModifieds();
	var indent=String.fromCharCode(160)+String.fromCharCode(160);
	var mods = config.macros.date.modifieds[date];
	if (mods) {
		// if a tiddler was created on this date, don't list it in the 'changed' section
		if (config.macros.date.createds && config.macros.date.createds[date]) {
			var temp=[];
			for(var t=0; t<mods.length; t++)
				if (!config.macros.date.createds[date].contains(mods[t]))
					temp.push(mods[t]);
			mods=temp;
		}
		mods.sort();
		var e=createTiddlyElement(p,'div',null,null,'changed ('+mods.length+')');
		for(var t=0; t<mods.length; t++) {
			var link=createTiddlyLink(createTiddlyElement(p,'li'),mods[t],false);
			link.appendChild(document.createTextNode(indent+mods[t]));
		}
	}
}
//}}}
//{{{
function hasTagged(date,format) // returns true if date is tagging other tiddlers
{
	if (config.options.chkDatePopupHideTagged) return false;
	return store.getTaggedTiddlers(date.formatString(format)).length>0;
}

function addTaggedToPopup(p,when,format)
{
	if (config.options.chkDatePopupHideTagged) return false;
	var indent=String.fromCharCode(160)+String.fromCharCode(160);
	var tagged=store.getTaggedTiddlers(when.formatString(format));
	if (tagged.length) var e=createTiddlyElement(p,'div',null,null,'tagged ('+tagged.length+')');
	for(var t=0; t<tagged.length; t++) {
		var link=createTiddlyLink(createTiddlyElement(p,'li'),tagged[t].title,false);
		link.appendChild(document.createTextNode(indent+tagged[t].title));
	}
}
//}}}
//{{{
function indexReminders(date,leadtime) // build list of tiddlers with reminders, hash indexed by reminder date
{
	var reminders = { };
	if(window.findTiddlersWithReminders!=undefined) { // reminder plugin is installed
		var t = findTiddlersWithReminders(date, [0,leadtime], null, null, 1);
		for(var i=0; i<t.length; i++) reminders[t[i].matchedDate]=true;
	}
	return reminders;
}

function hasReminders(date) // returns true if date has reminders
{
	if (config.options.chkDatePopupHideReminders) return false;
	if (window.reminderCacheForCalendar)
		return window.reminderCacheForCalendar[date]; // use calendar cache
	if (!config.macros.date.reminders)
		config.macros.date.reminders = indexReminders(date,config.macros.date.leadtime); // create a reminder cache
	return (config.macros.date.reminders[date]);
}

function addRemindersToPopup(p,when,format)
{
	if (config.options.chkDatePopupHideReminders) return false;
	if(window.findTiddlersWithReminders==undefined) return; // reminder plugin not installed

	var indent = String.fromCharCode(160)+String.fromCharCode(160);
	var reminders=findTiddlersWithReminders(when, [0,config.macros.date.leadtime],null,null,1);
	createTiddlyElement(p,'div',null,null,'reminders ('+(reminders.length||'none')+')');
	for(var t=0; t<reminders.length; t++) {
		link = createTiddlyLink(createTiddlyElement(p,'li'),reminders[t].tiddler,false);
		var diff=reminders[t].diff;
		diff=(diff<1)?'Today':((diff==1)?'Tomorrow':diff+' days');
		var txt=(reminders[t].params['title'])?reminders[t].params['title']:reminders[t].tiddler;
		link.appendChild(document.createTextNode(indent+diff+' - '+txt));
	}
	if (readOnly) return;	// readonly... omit 'new reminder...' command
	var rem='\\<\\<reminder day:%0 month:%1 year:%2 title:"Enter a reminder title here"\\>\\>';
	rem=rem.format([when.getDate(),when.getMonth()+1,when.getYear()+1900]);
	var cmd="<<newTiddler label:[["+indent+"new reminder...]] prompt:[[add a reminder to '%0']]"
		+" title:[[%0]] text:{{var t=store.getTiddlerText('%0','');t+(t.length?'\\n':'')+'%1'}} tag:%2>>";
	wikify(cmd.format([when.formatString(format),rem,config.options.txtCalendarReminderTags||'']),
		createTiddlyElement(p,'li'));
}
//}}}
/***
|Name|DatePluginConfig|
|Source|http://www.TiddlyTools.com/#DatePluginConfig|
|Documentation|http://www.TiddlyTools.com/#DatePluginInfo|
|Version|2.7.3|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|formats, background colors and other optional settings for DatePlugin|
***/
// // Default popup content display options (can be overridden by cookies)
//{{{
if (config.options.chkDatePopupHideCreated===undefined)
	config.options.chkDatePopupHideCreated=false;
if (config.options.chkDatePopupHideChanged===undefined)
	config.options.chkDatePopupHideChanged=false;
if (config.options.chkDatePopupHideTagged===undefined)
	config.options.chkDatePopupHideTagged=false;
if (config.options.chkDatePopupHideReminders===undefined)
	config.options.chkDatePopupHideReminders=false;
//}}}

// // show Julian date number below regular date
//{{{
if (config.options.chkShowJulianDate===undefined)
	config.options.chkShowJulianDate=false;
//}}}

// // fixed-date annual holidays
//{{{
config.macros.date.holidays=[
	"01/01", // NewYearsDay, 
	"07/04", // US Independence Day
	"07/24"  // Eric's Birthday (hooray!)
];
//}}}

// // weekend map (1=weekend, 0=weekday)
//{{{
config.macros.date.weekend=[ 1,0,0,0,0,0,1 ]; // day index values: sun=0, mon=1, tue=2, wed=3, thu=4, fri=5, sat=6
//}}}

// // date display/link formats
//{{{
config.macros.date.format="YYYY.0MM.0DD"; // default date display format
config.macros.date.linkformat="YYYY.0MM.0DD"; // 'dated tiddler' link format
config.macros.date.tipformat="YYYY.0MM.0DD"; // 'dated tiddler' tooltip format
//}}}

// // reminder lead time
//{{{
config.macros.date.leadtime=31; // find reminders up to 31 days from now
//}}}

// // When displaying a calendar (see [[CalendarPlugin]]), you can customize the colors/styles that are applied to the calendar dates by modifying the values and/or functions below:
//{{{
// default calendar colors
config.macros.date.weekendbg="#c0c0c0";
config.macros.date.holidaybg="#ffaace";
config.macros.date.createdbg="#bbeeff";
config.macros.date.modifiedsbg="#bbeeff";
config.macros.date.linkedbg="#babb1e";
config.macros.date.remindersbg="#c0ffee";

// apply calendar styles
function setDateStyle(place,link,weekend) {
	// alias variable names for code readability
	var date=link.date;
	var fmt=link.linkformat;
	var linkto=date.formatString(fmt);
	var cmd=config.macros.date;

	if ((weekend!==undefined?weekend:isWeekend(date))&&(cmd.weekendbg!=""))
		{ place.style.background = cmd.weekendbg; }
	if (hasModifieds(date)||hasCreateds(date)||hasTagged(date,fmt))
		{ link.style.fontStyle="normal"; link.style.fontWeight="bold"; }
	if (hasReminders(date))
		{ link.style.textDecoration="underline"; }
	if (isToday(date))
		{ link.style.border="1px solid black"; }
	if (isHoliday(date)&&(cmd.holidaybg!=""))
		{ place.style.background = cmd.holidaybg; }
	if (hasCreateds(date)&&(cmd.createdbg!=""))
		{ place.style.background = cmd.createdbg; }
	if (hasModifieds(date)&&(cmd.modifiedsbg!=""))
		{ place.style.background = cmd.modifiedsbg; }
	if ((hasTagged(date,fmt)||store.tiddlerExists(linkto))&&(cmd.linkedbg!=""))
		{ place.style.background = cmd.linkedbg; }
	if (hasReminders(date)&&(cmd.remindersbg!=""))
		{ place.style.background = cmd.remindersbg; }
	if (isToday(date)&&(cmd.todaybg!=""))
		{ place.style.background = cmd.todaybg; }
	if (config.options.chkShowJulianDate) {
		var m=[0,31,59,90,120,151,181,212,243,273,304,334];
		var d=date.getDate()+m[date.getMonth()];
		var y=date.getFullYear();
		if (date.getMonth()>1 && (y%4==0 && y%100!=0) || y%400==0) d++; // after February in a leap year
		wikify("@@font-size:80%;<br>"+d+"@@",place);
	}
	var t=store.getTiddlerText(linkto,'')
	if (config.options.chkInlineCalendarJournals && t.length) wikify('<br>'+t,place);
}
//}}}
|Name|DatePluginInfo|
|Source|http://www.TiddlyTools.com/#DatePlugin|
|Documentation|http://www.TiddlyTools.com/#DatePluginInfo|
|Version|2.7.3|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|documentation|
|Description|documentation for DatePlugin|
This plugin provides a general approach to displaying formatted dates and/or links and popups that permit easy navigation and management of tiddlers based on their creation/modification dates.
!!!!!Usage
<<<
This plugin displays formatted dates, for the specified year, month, day using number values or mathematical expressions such as (Y+1) or (D+30).  Optionally, you can create a link to a 'dated tiddler' for quick blogging or create a popup menu that includes the dated tiddler link plus links to tiddlers that were created/changed on that date, or are tagged with that date and, if the [[ReminderMacros|http://remindermacros.tiddlyspot.com/]] plugin is installed, any pending reminders for next month.  There is also a public API, so other plugins can embed a variety of formatted date output, links, and/or popup menus.
{{{
<<date mode date format linkformat>>
}}}
//all parameters are optional//
*''mode''<br>is one of:
**''display'' (default)<br>shows a formatted date
**''link''<br>creates a link to a specific 'date titled' tiddler
**''popup''<br>creates a popup command containing a dated tiddler link, plus links to changes and reminders.
*''date'' (or ''tiddler'' or ''tiddler:title'' or ''today'' or ''filedate'')<br>enter ANY date (not just today) as space-separated year, month, and day parameters (e.g., 2011 4 23).  You can use pre-defined variables, Y, M, and D for the current year, month and day, repectively.  These variables can be combined with simple mathematical expressions to calculate ''relative dates'' (e.g., D+1 = tomorrow, M-1 = last month, Y+1= next year, etc.)  Alternatively, you can use special keywords in place of the year/month/day parameters to access tiddler and file dates:
**''tiddler'' displays the modification date of the current tiddler.
**''tiddler://name-of-tiddler//'' displays the modification date of a specific tiddler.
**''today'' shows the current date.
**''filedate'' shows the modification date of the entire document.  
*{{block{
''format'' (and ''linkformat'') (default: YYYY.0MM.0DD)<br>uses standard ~TiddlyWiki date formatting syntax to specify the title of the target tiddler.
>''DDD'' - day of week in full (eg, "Monday"), ''DD'' - day of month, ''0DD'' - adds leading zero
>''MMM'' - month in full (eg, "July"), ''MM'' - month number, ''0MM'' - adds leading zero
>''YYYY'' - full year, ''YY'' - two digit year, ''hh'' - hours, ''mm'' - minutes, ''ss'' - seconds
>//note: use of hh, mm or ss format codes is only supported with ''tiddler'', ''today'' or ''filedate'' values//
}}}
*{{block{
''linkformat''<br>specify an alternative date format so that the title of a 'dated tiddler' link can have a format that differs from the date's displayed format.  The default tooltip is same as the title of the linked tiddler.  You can customize the tooltip by modifying the definition in [[DatePluginConfig]]:
{{{
config.macros.date.tipformat="YYYY.0MM.0DD"; // 'dated tiddler' tooltip format
}}}
}}}
You can adjust the 'lead time' for display of [[reminders|http://remindermacros.tiddlyspot.com/]] by modifying the definition in [[DatePluginConfig]]:
{{{
config.macros.date.leadtime=30; // find reminders up to 30 days from now
}}}
In addition to the macro syntax, DatePlugin also provides a public javascript API so that other plugins that work with dates (such as calendar generators, etc.) can quickly incorporate date formatted links or popups into their output:
{{{
showDate(place, date, mode, format, linkformat, autostyle, weekend);
}}}
Note that the javascript API supports two //optional// true/false parameters, in addition those provided by the macro interface:
*''autostyle''<br>font/background styles of formatted dates are automatically adjusted to show the date's status:  'today' is boxed, 'changes' are bold, 'reminders' are underlined, weekends, holidays, changes, and reminders each have a different background color to make them more visibly distinct from one another.
*''weekend''<br>true=day is a weekend, false=day is a weekday, default=automatically determine if a given date falls on a weekend.
<<<
!!!!!Examples
<<<
{{{The current date: <<date>>}}}
>The current date: <<date>>
{{{The current time: <<date today "0hh:0mm:0ss">>}}}
>The current time: <<date today "0hh:0mm:0ss">>
{{{Today's blog: <<date link today "DDD, MMM DDth, YYYY">>}}}
>Today's blog: <<date link today "DDD, MMM DDth, YYYY">>
{{{Recent blogs/changes/reminders: <<date popup Y M D-1 "yesterday">> <<date popup today "today">> <<date popup Y M D+1 "tomorrow">>}}}
>Recent blogs/changes/reminders: <<date popup Y M D-1 "yesterday">> <<date popup today "today">> <<date popup Y M D+1 "tomorrow">>
{{{The first day of next month will be a <<date Y M+1 1 "DDD">>}}}
>The first day of next month will be a <<date Y M+1 1 "DDD">>
{{{This tiddler (DatePlugin) was last updated on: <<date tiddler "DDD, MMM DDth, YYYY">>}}}
>This tiddler (DatePlugin) was last updated on: <<date tiddler "DDD, MMM DDth, YYYY">>
{{{The SiteUrl was last updated on: <<date tiddler:SiteUrl "DDD, MMM DDth, YYYY">>}}}
>The SiteUrl was last updated on: <<date tiddler:SiteUrl "DDD, MMM DDth, YYYY">>
{{{This document was last saved on <<date filedate "DDD, MMM DDth, YYYY at 0hh:0mm:0ss">>}}}
>This document was last saved on <<date filedate "DDD, MMM DDth, YYYY at 0hh:0mm:0ss">>
{{{<<date Y 07 24 "MMM DDth, YYYY">> will be a <<date Y 07 24 "DDD">>}}}
><<date Y 07 24 "MMM DDth, YYYY">> will be a <<date Y 07 24 "DDD">>
<<<
!!!!!Revisions
<<<
2011.04.23 2.7.3 added config.macros.date.tipformat for custom mouseover tooltip
2010.12.15 2.7.2 omit date highlighting when hiding popup items (created/changed/tagged/reminders)
2009.05.31 2.7.1 in addRemindersToPopup(), 'new reminder....' command now uses {{{<<newTiddler>>}}} macro.  Also, general code reduction/cleanup.
2008.03.08 2.7.0 in addModifiedsToPopup(), if a tiddler was created on the specified date, don't list it in the 'changed' section of the popup.  Based on a request from Kashgarinn
2008.01.31 2.6.0 refactored date style logic into separate setDateStyle() function so it can be overridden by a custom definition.  See [[DatePluginConfig]].
2008.01.11 2.5.0 added options to selectively suppress created/changes/tagged/reminders popup content 
2008.01.08 [*.*.*] plugin size reduction: documentation moved to DatePluginInfo
2007.11.21 2.4.0 added hasTagged() and addTaggedToPopup() to list any tiddlers that has been tagged using the title of the dated journal tiddler asa tag value (i.e., the tiddlers that will be listed in the standard "tagging" display when viewing the journal tiddler itself).  Based on a request from Coby.
2007.06.20 2.3.1 in onClickDatePopup(), use Popup.show() instead of deprecated ScrollToTiddlerPopup().  Fixes fatal error that prevents popups from being properly displayed
2007.05.31 2.3.0 list "created" tiddlers in date popup.  Also, force re-cache of created/modified indices when displaying current date and store.isDirty(), so that popup is kept in sync with tiddler changes.
2006.05.09 2.2.1 added "todaybg" handling to set background color of current date.  Also, honor excludeLists tag when getting lists of tiddlers.  Based on suggestions by Mark Hulme.
2006.05.05 2.2.0 added "linkedbg" handling to set background color when a 'dated tiddler' exists.  Based on a suggestion by Mark Hulme.
2006.03.08 2.1.2 add 'override leadtime' flag param in call to findTiddlersWithReminders(), and add "Enter a title" default text to new reminder handler.  Thanks to Jeremy Sheeley for these additional tweaks.
2006.03.06 2.1.0 hasReminders() nows uses window.reminderCacheForCalendar[] when present.  If calendar cache is not present, indexReminders() now uses findTiddlersWithReminders() with a 90-day look ahead to check for reminders.  Also, switched default background colors for autostyled dates: reminders are now greenish ("c0ffee") and holidays are now reddish ("ffaace").
2006.02.14 2.0.5 when readOnly is set (by TW core), omit "new reminders..." popup menu item and, if a "dated tiddler" does not already exist, display the date as simple text instead of a link.
2006.02.05 2.0.4 added var to variables that were unintentionally global.  Avoids FireFox 1.5.0.1 crash bug when referencing global variables
2006.01.18 2.0.3 In 1.2.x the tiddler editor's text area control was given an element ID=("tiddlerBody"+title), so that it was easy to locate this field and programmatically modify its content.  With the addition of configuration templates in 2.x, the textarea no longer has an ID assigned.  To find this control we now look through all the child nodes of the tiddler editor to locate a "textarea" control where attribute("edit") equals "text", and then append the new reminder to the contents of that control.
2006.01.11 2.0.2 correct 'weekend' override detection logic in showDate()
2006.01.10 2.0.1 allow custom-defined weekend days (default defined in config.macros.date.weekend[] array)
added flag param to showDate() API to override internal weekend[] array
2005.12.27 2.0.0 Update for TW2.0
Added parameter handling for 'linkformat'
2005.12.21 1.2.2 FF's date.getYear() function returns 105 (for the current year, 2005).  When calculating a date value from Y M and D expressions, the plugin adds 1900 to the returned year value get the current year number.  But IE's date.getYear() already returns 2005.  As a result, plugin calculated date values on IE were incorrect (e.g., 3905 instead of 2005).  Adding +1900 is now conditional so the values will be correct on both browsers.
2005.11.07 1.2.1 added support for "tiddler" dynamic date parameter
2005.11.06 1.2.0 added support for "tiddler:title" dynamic date parameter
2005.11.03 1.1.2 when a reminder doesn't have a specified title parameter, use the title of the tiddler that contains the reminder as "fallback" text in the popup menu.  Based on a suggestion from BenjaminKudria.
2005.11.03 1.1.1 Temporarily bypass hasReminders() logic to avoid excessive overhead from generating the indexReminders() cache.  While reminders can still appear in the popup menu, they just won't be indicated by auto-styling the date number that is displayed.  This single change saves approx. 60% overhead (5 second delay reduced to under 2 seconds).
2005.11.01 1.1.0 corrected logic in hasModifieds() and hasReminders() so caching of indexed modifieds and reminders is done just once, as intended.  This should hopefully speed up calendar generators and other plugins that render multiple dates...
2005.10.31 1.0.1 documentation and code cleanup
2005.10.31 1.0.0 initial public release
2005.10.30 0.9.0 pre-release
<<<
/***
|Name|DefaultTheme|
|Source|http://www.TiddlyTools.com/#DefaultTheme|
|Version|1.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|Description|Default systemTheme definition|

|StyleSheet|##StyleSheet|
|PageTemplate|##PageTemplate|
|ViewTemplate|##ViewTemplate|
|EditTemplate|##EditTemplate|
|PageTemplateReadOnly|##PageTemplateReadOnly|
|ViewTemplateReadOnly|##ViewTemplateReadOnly|
|EditTemplateReadOnly|##EditTemplateReadOnly|

!StyleSheet
/*{{{*/
[[StyleSheet]]
/*}}}*/
!PageTemplate
<!--{{{-->
[[PageTemplate]]
<!--}}}-->
!ViewTemplate
<!--{{{-->
[[ViewTemplate]]
<!--}}}-->
!EditTemplate
<!--{{{-->
[[EditTemplate]]
<!--}}}-->
!PageTemplateReadOnly
<!--{{{-->
[[PageTemplateReadOnly]]
<!--}}}-->
!ViewTemplateReadOnly
<!--{{{-->
[[ViewTemplate]]
<!--}}}-->
!EditTemplateReadOnly
<!--{{{-->
[[EditTemplateReadOnly]]
<!--}}}-->
***/
[[Welcome]]
/%
!info
|Name|DigitalClock|
|Source|http://www.TiddlyTools.com/#DigitalClock|
|Version|2.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Description|display current time with automatic update|
Usage
<<<
{{{
<<tiddler DigitalClock with: format tick>>
}}}
*''format'' is any TiddlyWiki date/time formatting string
*''tick'' is the time in seconds between display updates (default=1sec)
<<<
Example
<<<
show hours, minutes and seconds, updated once per second:
{{{<<tiddler DigitalClock with: "hh:0mm:0ss" 1>>}}}
<<tiddler DigitalClock##show with: "hh:0mm:0ss" 1>>
<<<
!end
!show
<html><a href='javascript:;'></a></html><<tiddler {{
	window.DigitalClock_tick=function(id){
		var e=document.getElementById(id); if (!e) return;
		e.title='click to '+(e.paused?'RESUME':'PAUSE')+' clock display';
		if (e.paused) return;
		e.innerHTML=new Date().formatString(e.fmt);
		e.timer=setTimeout('window.DigitalClock_tick('+id+')',e.tick*1000);
	}
	var e=place.lastChild.firstChild;
	e.id=new Date().getTime()+Math.random();
	e.onclick=function(){this.paused=!this.paused;window.DigitalClock_tick(this.id);}
	e.style.cursor='pointer';
	e.fmt=('$1'=='$'+'1')?'hh12:0mm:0ss am':'$1';
	e.tick=('$2'=='$'+'2')?'1':'$2';
	if (e.timer===undefined) window.DigitalClock_tick(e.id);
'';}}>>
!end
%/<<tiddler {{'DigitalClock##'+(tiddler&&tiddler.title=='DigitalClock'?'info':'show');}}
	with: [[$1]] [[$2]]>>
TiddlyWiki FireFox TiddlyTools TiddlyTech HowTo $1
/***
|Name|DisableWikiLinksPlugin|
|Source|http://www.TiddlyTools.com/#DisableWikiLinksPlugin|
|Version|1.6.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|selectively disable TiddlyWiki's automatic ~WikiWord linking behavior|
This plugin allows you to disable TiddlyWiki's automatic ~WikiWord linking behavior, so that WikiWords embedded in tiddler content will be rendered as regular text, instead of being automatically converted to tiddler links.  To create a tiddler link when automatic linking is disabled, you must enclose the link text within {{{[[...]]}}}.
!!!!!Usage
<<<
You can block automatic WikiWord linking behavior for any specific tiddler by ''tagging it with<<tag excludeWikiWords>>'' (see configuration below) or, check a plugin option to disable automatic WikiWord links to non-existing tiddler titles, while still linking WikiWords that correspond to existing tiddlers titles or shadow tiddler titles.  You can also block specific selected WikiWords from being automatically linked by listing them in [[DisableWikiLinksList]] (see configuration below), separated by whitespace.  This tiddler is optional and, when present, causes the listed words to always be excluded, even if automatic linking of other WikiWords is being permitted.  

Note: WikiWords contained in default ''shadow'' tiddlers will be automatically linked unless you select an additional checkbox option lets you disable these automatic links as well, though this is not recommended, since it can make it more difficult to access some TiddlyWiki standard default content (such as AdvancedOptions or SideBarTabs)
<<<
!!!!!Configuration
<<<
<<option chkDisableWikiLinks>> Disable ALL automatic WikiWord tiddler links
<<option chkAllowLinksFromShadowTiddlers>> ... except for WikiWords //contained in// shadow tiddlers
<<option chkDisableNonExistingWikiLinks>> Disable automatic WikiWord links for non-existing tiddlers
Disable automatic WikiWord links for words listed in: <<option txtDisableWikiLinksList>>
Disable automatic WikiWord links for tiddlers tagged with: <<option txtDisableWikiLinksTag>>
<<<
!!!!!Revisions
<<<
2008.07.22 [1.6.0] hijack tiddler changed() method to filter disabled wiki words from internal links[] array (so they won't appear in the missing tiddlers list)
2007.06.09 [1.5.0] added configurable txtDisableWikiLinksTag (default value: "excludeWikiWords") to allows selective disabling of automatic WikiWord links for any tiddler tagged with that value.
2006.12.31 [1.4.0] in formatter, test for chkDisableNonExistingWikiLinks
2006.12.09 [1.3.0] in formatter, test for excluded wiki words specified in DisableWikiLinksList
2006.12.09 [1.2.2] fix logic in autoLinkWikiWords() (was allowing links TO shadow tiddlers, even when chkDisableWikiLinks is TRUE).  
2006.12.09 [1.2.1] revised logic for handling links in shadow content
2006.12.08 [1.2.0] added hijack of Tiddler.prototype.autoLinkWikiWords so regular (non-bracketed) WikiWords won't be added to the missing list
2006.05.24 [1.1.0] added option to NOT bypass automatic wikiword links when displaying default shadow content (default is to auto-link shadow content)
2006.02.05 [1.0.1] wrapped wikifier hijack in init function to eliminate globals and avoid FireFox 1.5.0.1 crash bug when referencing globals
2005.12.09 [1.0.0] initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.DisableWikiLinksPlugin= {major: 1, minor: 6, revision: 0, date: new Date(2008,7,22)};

if (config.options.chkDisableNonExistingWikiLinks==undefined) config.options.chkDisableNonExistingWikiLinks= false;
if (config.options.chkDisableWikiLinks==undefined) config.options.chkDisableWikiLinks=false;
if (config.options.txtDisableWikiLinksList==undefined) config.options.txtDisableWikiLinksList="DisableWikiLinksList";
if (config.options.chkAllowLinksFromShadowTiddlers==undefined) config.options.chkAllowLinksFromShadowTiddlers=true;
if (config.options.txtDisableWikiLinksTag==undefined) config.options.txtDisableWikiLinksTag="excludeWikiWords";

// find the formatter for wikiLink and replace handler with 'pass-thru' rendering
initDisableWikiLinksFormatter();
function initDisableWikiLinksFormatter() {
	for (var i=0; i<config.formatters.length && config.formatters[i].name!="wikiLink"; i++);
	config.formatters[i].coreHandler=config.formatters[i].handler;
	config.formatters[i].handler=function(w) {
		// supress any leading "~" (if present)
		var skip=(w.matchText.substr(0,1)==config.textPrimitives.unWikiLink)?1:0;
		var title=w.matchText.substr(skip);
		var exists=store.tiddlerExists(title);
		var inShadow=w.tiddler && store.isShadowTiddler(w.tiddler.title);
		// check for excluded Tiddler
		if (w.tiddler && w.tiddler.isTagged(config.options.txtDisableWikiLinksTag))
			{ w.outputText(w.output,w.matchStart+skip,w.nextMatch); return; }
		// check for specific excluded wiki words
		var t=store.getTiddlerText(config.options.txtDisableWikiLinksList);
		if (t && t.length && t.indexOf(w.matchText)!=-1)
			{ w.outputText(w.output,w.matchStart+skip,w.nextMatch); return; }
		// if not disabling links from shadows (default setting)
		if (config.options.chkAllowLinksFromShadowTiddlers && inShadow)
			return this.coreHandler(w);
		// check for non-existing non-shadow tiddler
		if (config.options.chkDisableNonExistingWikiLinks && !exists)
			{ w.outputText(w.output,w.matchStart+skip,w.nextMatch); return; }
		// if not enabled, just do standard WikiWord link formatting
		if (!config.options.chkDisableWikiLinks)
			return this.coreHandler(w);
		// just return text without linking
		w.outputText(w.output,w.matchStart+skip,w.nextMatch)
	}
}

Tiddler.prototype.coreAutoLinkWikiWords = Tiddler.prototype.autoLinkWikiWords;
Tiddler.prototype.autoLinkWikiWords = function()
{
	// if all automatic links are not disabled, just return results from core function
	if (!config.options.chkDisableWikiLinks)
		return this.coreAutoLinkWikiWords.apply(this,arguments);
	return false;
}

Tiddler.prototype.disableWikiLinks_changed = Tiddler.prototype.changed;
Tiddler.prototype.changed = function()
{
	this.disableWikiLinks_changed.apply(this,arguments);
	// remove excluded wiki words from links array
	var t=store.getTiddlerText(config.options.txtDisableWikiLinksList,"").readBracketedList();
	if (t.length) for (var i=0; i<t.length; i++)
		if (this.links.contains(t[i]))
			this.links.splice(this.links.indexOf(t[i]),1);
};
//}}}
This package helps you to //''discover''// the connections and interrelationships between the tiddlers contained in a TiddlyWiki document.  This is particularly useful where the contents of a document are not already known, such as when a document has been edited by several people, or has gradually changed over an extended period of time.
/***
|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
<<<
/%
*** DO NOT INSTALL THIS TIDDLER IN YOUR OWN DOCUMENTS ***

This tiddler has been customized for use on TiddlyTools.com:
* suppress tiddler background
* suppress tabContent border/padding (for "Page" tab only)

%/<<tiddler HideTiddlerBackground>><script>
	place.style.border="0";
	place.style.padding="0";
</script>{{viewer{
<<discussion>>}}}
{{justify{''//TiddlyTools plugins, scripts, templates, styles, etc, are [[licensed|LegalStatements]] for use by the general public without any charges or fees.//''  Even so, a considerable amount of effort and creativity has been applied to developing and maintaining these add-on components as well as the FAQ articles, examples, and other content presented in this document.  In addition, much time has been dedicated to providing support to the TiddlyWiki user community by responding to questions and requests for help posted online or sent by private email.

//If TiddlyTools' add-ons, articles, examples, or help responses have been of use to you, and you'd like to show your appreciation in a tangible way, you can make a financial donation via [[PayPal|http://www.PayPal.com/]].//

{{smallform fine{<html><hide linebreaks><div style='float:right;margin-left:1em;'>
<form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_blank" style="padding:0;margin:0;">
<input type="hidden" name="cmd" value="_xclick">
<input type="hidden" name="business" value="elsdesign@gmail.com">
<input type="hidden" name="item_name" value="TiddlyTools Donation">
<input type="hidden" name="no_shipping" value="0">
<input type="hidden" name="cn" value="Your feedback is appreciated!">
<input type="hidden" name="tax" value="0">
<input type="hidden" name="lc" value="US">
<input type="hidden" name="bn" value="PP-DonationsBF">
<table class="borderless"><tr valign="bottom"><td>
	<i>make a single contribution:</i><br>
	<input type="text" value="$20.00" name="amount" maxlength="16" size="24" id="amount"/>
	<input type="hidden" name="currency_code" value="USD">
	<input type="submit" name="submit" value="  donate   ">
</td></tr></table>
</form><form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_blank" style="padding:0;margin:0;">
<input type="hidden" name="cmd" value="_s-xclick">
<input type="hidden" name="hosted_button_id" value="E26HYJJQTW87E">
<table class="borderless"><tr valign="bottom"><td>
	<input type="hidden" name="on0" value="Contribution Level">
	<i>or an annual pledge (12 monthly payments):</i><br>
	<select name="os0">
		<option value="bronze">$10.00/month (bronze)</option>
		<option selected="selected" value="silver">$20.00/month (silver)</option>
		<option value="gold">$30.00/month (gold)</option>
		<option value="platinum">$50.00/month (platinum)</option>
		<option value="diamond">$100.00/month (diamond)</option>
	</select>
	<input type="hidden" name="currency_code" value="USD">
	<input type="submit" name="submit" value="subscribe">
</td></tr></table>
</form></div></html>}}}
{{center{''//You decide how much TiddlyTools has been worth to you.//... simply give what you feel is fair reward for the value you have received.''}}}
{{clear small{

//Please note: In addition to saying "thank you", your donations will enable me to devote more time to maintaining and enhancing the components offered on TiddlyTools as well as continue to provide ongoing help and support activities for the general TiddlyWiki community at large... so ''please donate generously and often!''//}}}}}}
/***
|Name|[[DragScrollPlugin]]|
|Source|http://www.TiddlyTools.com/#DragScrollPlugin|
|Documentation|http://www.TiddlyTools.com/#DragScrollPlugin|
|Version|1.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|use SHIFT-DRAG to scroll the browser window|
DragScrollPlugin allows you to use your mouse to scroll the browser window by grabbing anywhere on the background of the document while holding the SHIFT key.
!!!!!Documentation
<<<
Whenever your page contains extra-wide content that does not 'wrap' onto extra lines, in can result in both horizontal and vertical scrollbars.  Unfortunately, using each scrollbar separately to navigate across the page can become very tedious and makes it more difficult to interact with your content in a flexible and effective manner.

''Drag-scrolling allows you to move in both the horizontal and vertical direction at the same time, simply by holding SHIFT while clicking and dragging the mouse across the page.''
<<<
!!!!!Configuration
<<<
<<option chkDragScroll>> enable //drag-scrolling//
<<<
!!!!!Revisions
<<<
2008.12.01 [1.0.0] Initial public release
<<<
!!!!!Code
***/
//{{{
version.extensions.DragScrollPlugin= {major: 1, minor: 0, revision: 0, date: new Date(2008,12,01)};

if (!config.dragscroll) { // only once
	config.dragscroll={
		// use to end event handling for processed events
		processed: function(ev) {
			var ev=ev||window.event;
			if (ev) { ev.cancelBubble=true; if (ev.stopPropagation) ev.stopPropagation(); }
			return false;
		},
		// MOUSE DOWN - SET CURSOR, SAVE SCROLL DATA
		savedMouseDown: document.onmousedown,
		mousedown: function(ev) {
			var ev=ev||window.event; var target=resolveTarget(ev); var d=config.dragscroll;
			var scroll=ev.shiftKey&&config.options.chkDragScroll;
			var skip=['input','option','textarea'].contains(target.nodeName.toLowerCase());
			if (!scroll||skip) { // handle event normally
				if (d.savedMouseDown!=undefined) return d.savedMouseDown.apply(target,arguments);
				else return;
			}
			d.mX=!config.browser.isIE?ev.pageX:ev.clientX; d.sX=findScrollX();
			d.mY=!config.browser.isIE?ev.pageY:ev.clientY; d.sY=findScrollY();
			d.scrolling=true; document.body.style.cursor='move';
			return config.dragscroll.processed(ev);
		},
		// MOUSE MOVE - UPDATE SCROLL DATA AND SCROLL THE WINDOW 
		savedMouseMove: document.onmousemove,
		mousemove: function(ev) {
			var ev=ev||window.event; var target=resolveTarget(ev); var d=config.dragscroll;
			if (!d.scrolling || !ev.shiftKey) { // NOT SCROLLING
				if (d.savedMouseMove!=undefined) return d.savedMouseMove.apply(target,arguments);
				else return;
			}
			// set scroll pos based on diff between new and old (x,y)
			var mx=!config.browser.isIE?ev.pageX:ev.clientX;
			var my=!config.browser.isIE?ev.pageY:ev.clientY;
			var sx=!config.browser.isIE?findScrollX():d.sX;
			var sy=!config.browser.isIE?findScrollY():d.sY;
			window.scrollTo(sx-mx+d.mX,sy-my+d.mY);
			return config.dragscroll.processed(ev);
		},
		// MOUSEUP - CLEAR THE DRAG DATA, RESET THE CURSOR
		savedMouseUp: document.onmouseup,
		mouseup: function(ev) {
			var ev=ev||window.event; var target=resolveTarget(ev); var d=config.dragscroll;
			var wasScrolling=d.scrolling; d.scrolling=false; document.body.style.cursor='auto';
			if (d.savedMouseUp!=undefined) return d.savedMouseUp.apply(target,arguments);
			if (wasScrolling) return config.dragscroll.processed(ev);
			return;
		}
	}
	// DEFAULT SETTING (ENABLED)
	if (config.options.chkDragScroll===undefined) config.options.chkDragScroll=true;
	// HIJACK MOUSE HANDLERS
	document.onmousedown=config.dragscroll.mousedown;
	document.onmousemove=config.dragscroll.mousemove;
	document.onmouseup  =config.dragscroll.mouseup;
}
//}}}
''ELS Design Studios'' was established in 1995, and specializes in ''interaction design'', ''visual design'', and ''information architecture''.  Through a combination of user-centric design, handcrafted production, and personalized service, our approach emphasizes the total ''visitor experience'' to produce highly effective feature-rich interactive applications, documents and on-line presentations for businesses, organizations, and individuals.  

@@display:block;text-align:center;font-size:18pt;color:#0c0;font-family:"trebuchet ms";//Your web site/application can be more
intuitive, expressive, functional... effective!//@@

Throughout the various stages of design and implementation, we draw upon many years of experience in commercial software and web development processes to deliver ''well-planned, robust, functionality''.  We work closely with you to help focus your imagination and refine your message in order to identify clearly defined, practical project goals that match your creative sensibilities and/or business needs.  We provide guidance and recommendations for your decision-making processes, while insulating you from technological details that can divert attention from achieving your project goals, so you can make informed decisions to ensure that the the final result expresses your unique ''style, strategy, message and vision''.

----
@@font-size:12pt;Whether your site is presenting your personal creativity or furthering your business objectives, ''our role is to help you to realize YOUR vision'' for YOUR web application.@@
----

@@display:block;font-size:8pt;line-height:110%;The founder and principal designer, Eric L. Shulman, brings a wealth of direct, intensive experience in developing complex interactive systems.  His designs emphasize both ease-of-use and rich functionality to deliver 'best-of-breed' user experiences.  His professional and academic qualifications include an interdisciplinary degree in "Interactive Systems Design" from [[Carnegie-Mellon University|http://www.cmu.edu]] (1985), as well as many years of user interface and software design work on significant commercial products.

At [[Lotus Development Corporation|http://www.lotus.com]], he was directly involved in the innovation of new graphical interface techniques for "1-2-3", their flagship spreadsheet product.  He has also been a Senior Research Engineer with [[OpenData, Inc.|http://www.opendata.com]], and as well as a key contributor in the Product Design Group at [[Clarify, Inc.|http://www.clarify.com]], where he developed comprehensive interface design standards for their suite of Customer Relationship Management (CRM) applications, and provided cross-team guidance and consultation for their marketing, engineering, quality assurance, and documentation organizations.@@
/***
|Name|Edge of Night|
|Source|http://www.TiddlyTools.com/#Edge of Night|
|Version||
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|CSS|
|Description|theme: dark blue sunset photo background|
|StyleSheet|Edge of Night|
|PageTemplateReadOnly|PageTemplateReadOnly|
|EditTemplateReadOnly|EditTemplateReadOnly|
***/

[[StyleSheetAdjustments]]
[[BrightText]]
/* ==== Edge of Night ==== */
/*{{{*/
body
	{ background-image: url('[[EdgeOfNightBackground]]'); background-color:#113; }
.groupbox
	{ background-image: url('[[TexturesParchmentGray]]');}
.menubox
	{ background-color: #002; border:1px solid; }
.annotation
	{ background-color: #002; }
.viewer
	{ background-image: url('[[TexturesMarbleBlack]]'); background-color:#111; border: 1px solid #999; -moz-border-radius:1em;-webkit-border-radius:1em; padding:1em; }
.header
	{ background-image: none; background-color:transparent; color:#ccf; border-bottom:0px solid #036; }
.siteSubtitle
	{ color:#0c0; }
.floatingPanel, .attachPanel, #importPanel, #exportPanel
	{ background: #eee; background-image: url('[[TexturesParchmentGray]]');}
.floatingPanel a, .attachPanel a, #importPanel a, #exportPanel a, 
.floatingPanel .button, .attachPanel .button, #importPanel .button, #exportPanel .button,
.floatingPanel .tiddlyLinkExisting, .attachPanel .tiddlyLinkExisting, #importPanel .tiddlyLinkExisting, #exportPanel .tiddlyLinkExisting,
	{ color:#009; }
#messageArea 
	{ background: #ddf; }
.siteMenu .floatingPanel
	{ background-image: url('[[TexturesParchmentGray]]'); }
.viewer h1,.viewer h2,.viewer h3,.viewer h4,.viewer h5 { background: #666; color:#fff; }

.tabContents
	{ background-color:#ddf; color:#000; background-image: url('[[TexturesParchmentGray]]'); }
.viewer .tabContents, #sidebarTabs .tabContents
	{ background-image:none; background-color:#002; color:#fff; }

.tabContents a, .tabContents .button, .tabContents .tiddlyLinkExisting
	{ color:#99f; }
/*********
#tiddlerWelcome .viewer .tabContents
	{ background-image: url('[[TexturesMarbleBlack]]'); }
#mainMenu .menubox
	{ background-image: url('[[TexturesMarbleBlack]]'); }
**********/
/*}}}*/
!usage
{{{[img[EdgeOfNightBackground]]}}}
[img[EdgeOfNightBackground]]
!notes
&copy; 1999 ELS Design Studios - do not copy without prior explicit permission
!type
image/jpg
!file
./images/sunset.jpg
!url
/images/sunset.jpg
!data
/***
|Name|[[EditFieldPlugin]]|
|Source|http://www.TiddlyTools.com/#EditFieldPlugin|
|Version|1.6.2|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|extend core edit macro for use in ViewTemplates or direct embedding in tiddler content|
!!!!!Documentation
>see [[EditFieldPluginInfo]]
!!!!!Revisions
<<<
2011.04.10 1.6.2 fixed 'null' fieldname handling in Chrome
| Please see [[EditFieldPluginInfo]] for previous revision details |
2007.08.22 1.0.0 initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.EditFieldPlugin= {major: 1, minor: 6, revision: 2, date: new Date(2011,4,10)};

config.macros.edit.editFieldPlugin_savedHandler=config.macros.edit.handler;
config.macros.edit.cancelMsg = "Abandon changes to %0@%1?";
config.macros.edit.saveMsg = "Save changes to %0@%1?";
config.macros.edit.handler = function(place,macroName,params,wikifier,paramString,tiddler) {

	// let core render input/textarea, then get resulting element
	config.macros.edit.editFieldPlugin_savedHandler.apply(this,arguments);
	var fieldType=params[0]=="text"||params[1]?'textarea':'input';
	var elems=place.getElementsByTagName(fieldType); var e=elems[elems.length-1];

	// extended fieldname@tiddlername handling
	var parts=e.getAttribute("edit").split('@');
	var field=parts[0];
	var title=parts[1]||tiddler.title;
	if (title=='here') title=tiddler.title;
	// stop field from being saved with 'done' button
	if (parts[1]) { e.removeAttribute("edit"); e.setAttribute("field",field); }

	// save starting value and target tiddler
	e.value=store.getValue(title,field)||e.value; // get field value
	e.setAttribute("currval",e.value); // save starting value
	e.setAttribute("tiddler",title);

	// force height for textarea field
	if (fieldType=="textarea" && params[1]) e.style.height=params[1]+"em";

	// if viewing tiddler, add autosave handlers
	var here=story.findContainingTiddler(place);
	var isViewed=here&&here.getAttribute("template").indexOf("ViewTemplate")!=-1;
	if (parts[1]||isViewed) { // remote reference or view mode editing...
		story.setDirty(tiddler.title,false); // clear tiddler ("dirty") flag (set by core)
		e.onkeydown=function(ev) { // ENTER key=save (for single-line input)
			var event=ev?ev:window.event;
			this.setAttribute("keyCode",event.keyCode); // save last keyCode (for blur)
			if (event.keyCode==13 && this.nodeName.toUpperCase()!="TEXTAREA")
				this.saveField(); // save input to tiddler field
		}
		e.onblur=function(ev) { // confirm input when focus moves away
			var event=ev?ev:window.event;
			var tid=this.getAttribute("tiddler"); if (!tid || !tid.length) return;
			var field=this.getAttribute("edit")||this.getAttribute("field");
			if (this.value==this.getAttribute("currval")) return; // no change
			if (this.getAttribute("keyCode")=="27") { // if user pressed ESC
				var msg=config.macros.edit.cancelMsg.format([field,tid]);
				if (!msg.length || confirm(msg))
					this.value=this.getAttribute("currval"); // reset value
				this.id=new Date().getTime(); // unique ID for re-focus after blur
				setTimeout("document.getElementById('"+this.id+"').focus()",1);
			} else { // other focus change events
				var msg=config.macros.edit.saveMsg.format([field,tid]);
				if (!msg.length || confirm(msg)) this.saveField(); // save value
				else this.value=this.getAttribute("currval");
			}
		};
		e.saveField=function() { // unpack/validate attribs and then save the field
			var tid=this.getAttribute("tiddler"); if (!tid || !tid.length) return;
			var field=this.getAttribute("edit")||this.getAttribute("field");
			var title=(field=="title")?this.value:tid;
			if (!title.length) { // error: blank tiddler title
				this.value=this.getAttribute("currval"); // reset value
				this.id=new Date().getTime(); // unique ID for delayed messages/refocus
				setTimeout("displayMessage('Please enter a non-blank value')",1);
				setTimeout("document.getElementById('"+this.id+"').focus()",2);
				return;
			}
			config.macros.edit.saveField(tid,title,field,this.value);
			this.setAttribute("currval",this.value); // remember new starting value
		};
	}
}
//}}}
//{{{
// save input value to tiddler field (create/touch/rename tiddler as needed)
config.macros.edit.saveField = function(tid,title,field,val) {
	var t=store.getTiddler(tid);
	store.suspendNotifications();
	var anim=config.options.chkAnimate; config.options.chkAnimate=false; // suspend animation
	var who=t&&config.options.chkForceMinorUpdate?t.modifier:config.options.txtUserName;
	var when=t&&config.options.chkForceMinorUpdate?t.modified:new Date();
	store.saveTiddler(t?tid:title,title,t?t.text:"",who,when,t?t.tags:[],t?t.fields:null);
	store.setValue(title,field,val); // save field
	if (tid!=title) // new title... show renamed tiddler in place of current one
		{ story.displayTiddler(story.getTiddler(tid),title); story.closeTiddler(tid); }
	if (field=="text") // content changed, refresh tiddler display
		{ story.refreshTiddler(title,null,true); }
	config.options.chkAnimate=anim; // resume animation
	store.resumeNotifications();
	store.notify(title,true);
}
//}}}
/***
|Name|EditFieldPluginInfo|
|Source|http://www.TiddlyTools.com/#EditFieldPlugin|
|Documentation|http://www.TiddlyTools.com/#EditFieldPluginInfo|
|Version|1.6.2|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|documentation|
|Description|documentation for EditFieldPlugin|
!!!!!Usage
<<<
When a tiddler is edited, input fields -- defined in the [[EditTemplate]] -- are displayed.  The ''TiddlyWiki //template// syntax'' for the {{{<<edit>>}}} macro is:
{{{
<span class="editor" macro="edit fieldname numberOfLines defaultValue"></span>
}}}
*''fieldname''<br>refers to a tiddler field, either standard or custom, within the current tiddler.
*''numberOfLines'' //(optional, default=1)//<br>if omitted (or equal to 1), a standard one-line text input field is created.  If >1, a multi-line //textarea// field is created.  Note: the standard tiddler 'text' field has special core handling applied so that it is always rendered using a textarea field, whose size is based on the length of the tiddler content, limted by the {{{<<option txtMaxEditRows>>}}} setting.
*''defaultValue'' //(optional, default=blank)//<br>a fallback value to display if the field is not yet defined in the tiddler.
The TiddlyWiki core only supports use of the edit macro within an [[EditTemplate]] definition.  Changes to values displayed in the tiddler editor are only saved (or discarded) if you press the "done" (or "cancel") command in the tiddler editor's toolbar.  However, these commands are not available when //viewing// a tiddler, so there is no way to trigger the saving of any changes you have entered.

EditFieldPlugin adds handling that allows you to embed the edit macro in the [[ViewTemplate]] (using the standard ''TiddlyWiki //template// syntax'') or directly in tiddler content using ''TiddlyWiki //wiki// syntax'' (e.g, {{{<<edit fieldname@TiddlerName numberOfLines defaultValue>>}}}).

When you make changes to a tiddler input field displayed in //viewed// content, your changes are saved (or discarded) as soon as you press ENTER (or ESC).  If you move away from that input field ('onBlur' handling), a message is displayed asking you to confirm saving/discarding any field changes.  To suppress either (or both) of these confirmation messages, you can add the following configuration settings to [[EditFieldPluginConfig]] (tagged with <<tag systemConfig>>):
{{{
config.macros.edit.cancelMsg = "";
config.macros.edit.saveMsg = "";
}}}
The plugin also enhances the fieldname syntax to allow reference to fields in other tiddlers using: "{{{fieldname@TiddlerName}}}", so you can 'remotely' display and edit fields stored those tiddlers.  This allows you to create, for example, a summary tiddler for reviewing/editing field values from several tiddlers at the same time.
<<<
!!!!!Examples
<<<
*"""<<edit foobar>>"""<br><<edit foobar>>
*"""<<edit foobar@SomeTiddler>>"""<br><<edit foobar@SomeTiddler>>
*"""<<edit tags>>"""<br><<edit tags>>
*"""<<edit text 15>>"""<br>{{editor{<<edit text 15>>}}}
<<<
!!!!!Revisions
<<<
2011.04.10 1.6.2 fixed 'null' fieldname handling in Chrome
2010.11.15 1.6.1 fixed display of field values for 'non-stored' tiddler content (e.g., shadows, tags, default new tiddler)
2010.10.31 1.6.0 fixed display of remote field values.  In onblur(), refactored save/cancel message text for easier customization and bypass confirmation if text is blank.  
2009.09.16 1.5.1 fixed 'onblur' handling for local fields (fieldname@here).  Added support for  '@here' syntax
2009.09.05 1.5.0 code refactored.  added handling for fieldname@tiddlername
2007.08.22 1.0.0 initial release
<<<
/***
|Name|[[EditSectionPlugin]]|
|Source|http://www.TiddlyTools.com/#EditSectionPlugin|
|Documentation|http://www.TiddlyTools.com/#EditSectionPlugin|
|Version|1.8.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|invoke popup 'section editor' for specified section of a tiddler|
!!!!!Usage
<<<
{{{
<<editSection TiddlerName##sectionname label tooltip>>
}}}
This macro adds a command link that invokes a popup editor for a specific section, where:
*''~TiddlerName##sectionname'' specifies the tiddler and section you want to edit.
**If you omit the "##sectionname" portion (i.e., only enter "~TiddlerName"), the entire content of the indicated tiddler is edited.
**If you omit the "~TiddlerName" portion (i.e., only enter "##sectionname"), the current containing tiddler (if any) is assumed.
**Changing the section name in the popup editor //renames// that section within the tiddler.
**Changing the tiddler title in the popup editor //copies// that section to another tiddler.
**If the indicated tiddler and/or section does not yet exist, it will be created when you press 'save'.
*''label'' and ''tooltip'' (both //optional//) specify the link label and mouseover help text for the 'edit section' command link.
You can also add the following macro, //at the end of a tiddler//, to automatically add an 'edit section' command link for each section shown in the tiddler.
{{{
<<editSections label tooltip>>
}}}
*''label'' and ''tooltip'' (both //optional//) specify the link label and mouseover help text for the 'edit section' command link.
>//Note: when a document is viewed in 'readOnly' mode, both of these macros are bypassed and no output is produced.//
<<<
!!!!!Sample
<<<
This is an example section for you to try
<<<
!!!!!Example
<<<
{{{
<<editSection ##Sample>>
}}}
<<editSection ##Sample>>
<<<
!!!!!Configuration
<<<
To customize and/or translate the HTML form layout used to render the section editor, edit the [[EditSectionTemplate]] shadow tiddler.
<<<
!!!!!Revisions
<<<
2012.01.29 1.8.1 invoke autoSaveChanges() when tiddlers are modified.
2011.12.22 1.8.0 added {{{<<editSections>>}}} macro for automatic adding of 'edit section...' links to headings
2011.12.20 1.7.0 added drag handling for editor panels
2011.10.28 1.6.8 fixed getMX()/getMY() for Chrome scroll offset handling
2011.09.02 1.6.7 more refactoring and cleanup of default form init/save handlers
2011.08.02 1.6.6 major code refactor to allow customization of form handling for type-specific [[PasteUpHelperPlugin]] extensions
2011.07.30 1.6.5 in removePanel(), call Popup.remove() so 'child' popups are closed when panel is closed
2011.07.24 1.6.4 refactored save() to provide updateTiddler() entry point for use with PasteUpHelperPlugin 'quickmenu' commands. Added getMX() and getMY() for cross-browser mouse coordinates
2011.06.05 1.6.3 added TiddlySpace cloneFields() to delete and save handlers so editing sections automatically copies/owns an included tiddler
2011.05.05 1.6.2 renamed delete() to deleteSection() to avoid javascript keyword errors
2011.05.04 1.6.1 in delete(), use removeTiddler() for proper notification handling
2011.05.01 1.6.0 added delete() functionality
2011.01.09 1.5.1 in handler(), don't render command link if document is readOnly
2010.12.24 1.5.0 replace use of core Popups with custom panel handling (bypass core interactions and errors)
2010.11.07 1.4.0 in popup(), render HTML form from EditSectionTemplate, and then applyHtmlMacros() to render wiki-syntax macro-generated form elements (e.g., {{{<<option>>, <<select>>}}}, etc.).  Also, refactored form init/save handling to add customization 'hooks'
2010.10.25 1.3.0 added support for editing complete tiddlers using "~TiddlerName" syntax (omit "##sectionname")
2010.07.15 1.2.0 added confirmation when section rename will overwrite other section
2010.07.13 1.1.1 added 'dirty flag' confirmation to popup handling to avoid discarding unsaved changes
2010.07.11 1.1.0 fixed handling for creating new sections in existing tiddlers. Copied StickyPopupPlugin to eliminate dependency. Added Popup.showHere()
2010.05.24 1.0.2 in save(), escape regexp chars in section titles (e.g. "!SectionNameWith?InIt")
2009.09.07 1.0.1 documentation/code cleanup
2009.09.01 1.0.0 initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.EditSectionPlugin= {major: 1, minor: 8, revision: 1, date: new Date(2012,1,29)};

config.macros.editSection = {
	label: 'edit section...',
	tip: 'edit %0',
	sectionfmt: '{{hidden{\n!%0\n%1\n!end\n}}}',
	sectionerr: 'Invalid tiddler/section name: %0',
	newtiddlertxt: '',
	discardmsg: 'Discard unsaved changes for %0?',
	deletemsg: 'Are you sure you want to delete %0?',
	overwritemsg: '%0##%2 already exists. Choose OK to overwrite it',
	template: 'EditSectionTemplate', // DEFAULT FORM TEMPLATE
//}}}
// // PLUGIN INITIALIZATION
//{{{
	init: function() {
		// SHADOW PAYLOAD FOR DEFAULT EditSectionTemplate FORM DEFINITION
		config.shadowTiddlers[this.template]
			=store.getTiddlerText('EditSectionPlugin##HTML','');

		// CLOSE PANELS IF CLICK on other than POPUP OR EDITOR PANEL
		addEvent(document,'click',function(ev) {
			var p=resolveTarget(ev||window.event);
			while (p) {
				if (hasClass(p,'editSectionPanel')) break;
				if (hasClass(p,'popup')) break;
				p=p.parentNode;
			}
			if (!p) config.macros.editSection.removeAllPanels();
			return true;
		});

		// HIJACK QuickEditPlugin's getField() to support use with editSectionPanel
		if (config.quickEdit) {
			config.quickEdit.getTiddlerField=config.quickEdit.getField;
			config.quickEdit.getField=function(where) {
				var e=where; while(e) {	if (hasClass(e,'editSectionPanel')) break; e=e.parentNode; }
				return e?e.getElementsByTagName('textarea')[0]:this.getTiddlerField(where);
			}

		}
	},
//}}}
// // GENERAL UTILITIES
//{{{
	ok: function(ev) { var ev=ev||window.event;
		ev.cancelBubble=true;
		if(ev.stopPropagation)ev.stopPropagation();
		return false;
	},
	getMX: function(ev) { var ev=ev||window.event; // GET MOUSE X
		if (config.browser.isIE)	return ev.clientX+findScrollX();// IE
		if (config.userAgent.indexOf('chrome')!=-1) return ev.pageX;	// Chrome
		if (config.browser.isSafari) 	return ev.pageX+findScrollX(); 	// Webkit
		else				return ev.pageX;		// Firefox/other
	},
	getMY: function(ev) { var ev=ev||window.event; // GET MOUSE Y
		if (config.browser.isIE)	return ev.clientY+findScrollY();// IE
		if (config.userAgent.indexOf('chrome')!=-1) return ev.pageY;	// Chrome
		if (config.browser.isSafari) 	return ev.pageY+findScrollY();	// Webkit
		else				return ev.pageY;		// Firefox/other
	},
	cloneFields: function(fields) { // for TIDDLYSPACE compatibility
		var f=merge({},fields); // copy object
		if (f["server.workspace"]!=config.defaultCustomFields["server.workspace"]) {
			f=merge(f,config.defaultCustomFields); // overwrite with defaults
			f["server.permissions"] = "read, write, create, delete";
			delete f["server.page.revision"];
			delete f["server.title"];
			delete f["server.etag"];
		}
		return f;
	},
//}}}
// // MACRO/CLICK HANDLER
//{{{
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		if (readOnly) return;
		var here=story.findContainingTiddler(place);
		var tid=params[0];
		var label=params[1]||this.label.format([tid]);
		var tip=params[2]||this.tip.format([tid]);
		var btn=createTiddlyButton(place,label,tip,this.click);
		btn.setAttribute('tid',tid);
	},
	click: function(ev,type) { // note: optional 'type' is passed in from PasteUpPluginHelper
		var parts=this.getAttribute('tid').split('##');
		var title=parts[0]; var section=parts[1];
		var here=story.findContainingTiddler(this);
		if (!title&&here) title=here.getAttribute('tiddler');
		if (!title) return false;
		var tid=title; if (section&&section.length) tid=[title,section].join('##');
		return config.macros.editSection.createPanel(this,ev,tid,title,section,type);
	},
//}}}
// // EDITOR PANEL HANDLER
//{{{
	createPanel: function(here,ev,tid,title,section,type) {
		if (!this.removeAllPanels()) return this.ok(ev);
		var p=createTiddlyElement(document.body,"ol",
			"editSectionPanel","popup smallform editSectionPanel");
		p.root=here; 
		p.setAttribute('dirty',null);
		p.setAttribute('message',this.discardmsg.format([tid]));
		p.onmousedown=this.mousedown; p.style.cursor='move'; // for panel dragging
		p.innerHTML=store.getRecursiveTiddlerText(this.getForm(tid,type),'',10);
		applyHtmlMacros(p,store.getTiddler(title));
		var f=p.getElementsByTagName('form')[0];
		f.panel=p;
		f.title.value=title;
		f.section.value=section||'';
		f.init=this.getInitForm(tid,type);
		f.save=this.getSaveForm(tid,type);
		f.init(here,f,title,section,type);
		this.showPanel(p,here,ev);
		return this.ok(ev);
	},
	showPanel: function(p,here,ev) {
		var x=this.getMX(ev); var y=this.getMY(ev);
		var winw=findWindowWidth();
		var scrollw=winw-document.body.offsetWidth;
		if(p.offsetWidth>winw*0.75) p.style.width=winw*0.75 + "px";
		if(x+p.offsetWidth>winw-scrollw-1) x=winw-p.offsetWidth-scrollw-1;
		var s=p.style; s.left=x+'px'; s.top=y+'px'; s.display='block';
		if(config.options.chkAnimate && anim)	anim.startAnimating(new Scroller(p));
		else					window.scrollTo(0,ensureVisible(p));
	},
	removePanel: function(p) {
		Popup.remove(); // child popup (if any) is closed when panel is closed
		if (!p || p.getAttribute('dirty')!='true' || confirm(p.getAttribute('message')))
			{ if (p) removeNode(p); return true; }
		return false;
	},
	removeAllPanels: function() {
		var ok=true;
		jQuery('.editSectionPanel').each(function(index){
			var f=this.getElementsByTagName('form')[0];
			if (f.content) f.content.blur(); // force onchange (sets 'dirty' flag as needed)
			ok=config.macros.editSection.removePanel(this);
			return true;
		});
		return ok; // FALSE if panels remain
	},
//}}}
// // PANEL DRAG HANDLER
//{{{
	mousedown: function(ev) { ev=ev||window.event; // MOVE PANEL
		var cme=config.macros.editSection; // abbrev

		// ignore clickthrough from form fields, links, and images
		var target=resolveTarget(ev);
		if (['TEXTAREA','SELECT','INPUT','A','IMG'].contains(target.nodeName.toUpperCase()))
			return true;

		// GET TRACKING ELEMENT
		var track=this; // if 'capture' not supported, track in element only
		if (document.body.setCapture) var track=document.body; // IE
		if (window.captureEvents) var track=window; // moz
		if (!track.save_onmousemove) track.save_onmousemove=track.onmousemove;
		if (!track.save_onmouseup)   track.save_onmouseup  =track.onmouseup;
		if (!track.save_onkeyup)     track.save_onkeyup    =track.onkeyup;
		track.onmousemove=cme.dragmove;
		track.onmouseup	 =cme.dragup;
		track.onkeyup	 =cme.dragkeyup;
		// SAVE INITIAL POSITION
		track.elem=this;		// panel element
		track.start={
			X: cme.getMX(ev),  Y: cme.getMY(ev),	// mouse position
			T: this.offsetTop, L: this.offsetLeft,	// panel position
		}
		return cme.ok(ev);
	},
	dragmove: function(ev) { ev=ev||window.event; // MOVE PANEL
		var cme=config.macros.editSection; // abbrev
		// CAPTURE MOUSE EVENTS DURING DRAG
		if (document.body.setCapture) document.body.setCapture(); // IE
		if (window.captureEvents) window.captureEvents(Event.MouseMove|Event.MouseUp,true); // moz
		var e=this.elem; var s=e.style;
		var dX=cme.getMX(ev)-this.start.X;
		var dY=cme.getMY(ev)-this.start.Y;
		e.changed=e.changed||(Math.abs(dX)>1)||(Math.abs(dY)>1); // MINIMUM 2px MOVEMENT
		if (!e.changed) return cme.ok(ev);
		s.top =this.start.T+dY+'px';
		s.left=this.start.L+dX+'px';
		return cme.ok(ev);
	},
	dragkeyup: function(ev) { ev=ev||window.event; // STOP DRAG (ESC key)
		if (ev.keyCode==27) {
			var s=this.elem.style;
			s.top=this.start.T+'px';
			s.left=this.start.L+'px';
			return this.onmouseup(ev);
		}
	},
	dragup: function(ev) { ev=ev||window.event; // RELEASE MOUSE
		var cme=config.macros.editSection; // abbrev
		if (document.body.releaseCapture) document.body.releaseCapture(); // IE
		if (window.releaseEvents) window.releaseEvents(Event.MouseMove|Event.MouseUp); // moz
		this.onmousemove=this.save_onmousemove;
		this.onmouseup  =this.save_onmouseup;
		this.onkeyup    =this.save_onkeyup;
		return cme.ok(ev);
	},
//}}}
// // EDITOR FORM HANDLER
//{{{
	getForm:	function(tid,type) { return this.template; }, // see PasteUpHelperPlugin
	getInitForm:	function(tid,type) { return this.initForm; }, // see PasteUpHelperPlugin
	getSaveForm:	function(tid,type) { return this.saveForm; }, // see PasteUpHelperPlugin
	initForm: function(here,form,title,section,type) { // SET FORM CONTENT FROM TIDDLER SECTION
		var tid=title; if (section) tid=[title,section].join('##');
		form.newsection.value=tid; // target for output
		form.content.value=store.getTiddlerText(tid,'');
		if (version.extensions.TextAreaPlugin) new window.TextAreaResizer(form.content);
	},
	saveForm: function(here,ev) { // GET SECTION CONTENT FROM FORM (DEFAULT=TEXT CONTENT ONLY)
		var f=here.form;

		// GET TARGET TITLE/SECTION
		var tid=f.newsection.value;
		var parts=tid.split('##');
		var title=parts[0];
		var section=parts[1];
		var oldsection=f.section.value;
		var where=f.panel.root;
		if (!title) title=story.findContainingTiddler(where).getAttribute('tiddler');
		if (!title) {
			displayMessage(this.sectionerr.format([f.newsection.value]));
			f.newsection.focus(); f.newsection.select(); return false;
		}
		// CHECK FOR TIDDLER OVERWRITE
		if (!section && title!=f.title.value && store.tiddlerExists(title)) {
			if (!confirm(config.messages.overwriteWarning.format([title])))
				{ f.newsection.focus(); f.newsection.select(); return this.ok(ev); }

		}
		// WRITE TIDDLER CONTENT and CLOSE PANEL
		this.updateTiddler(f.content.value,title,section,oldsection);
		f.panel.setAttribute('dirty',null); this.removePanel(f.panel);
		return this.ok(ev);
	},
	changed: function(here,ev) {
		here.form.panel.setAttribute('dirty','true');
		return this.ok(ev);
	},
	cancel: function(here,ev) {
		this.removePanel(here.form.panel);
		return this.ok(ev);
	},
	remove: function(here,ev) {
		var f=here.form;
		var title=f.title.value;
		var section=f.section.value;
		var tid=title; if (section.length) tid=[title,section].join('##');
		var msg=this.deletemsg.format([tid]);
		if (!confirm(msg)) return this.ok(ev);
		this.deleteSection(title,section);
		f.panel.setAttribute('dirty',null);
		this.removePanel(f.panel);
		return this.ok(ev);
	},
//}}}
// // TIDDLER I/O
//{{{
	updateTiddler: function(txt,title,section,oldsection) {
		// GET (or CREATE) TIDDLER
		var t=store.getTiddler(title);
		var who =t&&config.options.chkForceMinorUpdate?t.modifier:config.options.txtUserName;
		var when=t&&config.options.chkForceMinorUpdate?t.modified:new Date();
		if (!t) {
			t=new Tiddler(); t.text=store.getTiddlerText(title,'');
			if (section&&!t.text.length) t.text=this.newtiddlertxt.format([title,section]);
		}
		// ADD/REVISE/RENAME SECTION CONTENT (if any)
		if (section) {
			// GET SECTION VALUES
			if (!oldsection) var oldsection=section;
			var oldval=store.getTiddlerText(title+'##'+oldsection); // previous section value
			var newval=txt; // revised section value
			var existingval=store.getTiddlerText(title+'##'+section); // existing section value
			// REVISE TIDDLER TEXT
			var txt=t.text; // default tiddler text = unchanged
			var pattern=new RegExp('(.*!{1,6})'+oldsection.escapeRegExp()+'\\n'
				+(oldval||'').escapeRegExp()+'((?:\\n!{1,6}|$).*)');
			var altpattern=this.sectionfmt.format([oldsection,oldval||'']);
			if (section!=oldsection && existingval) { // rename overwrites another section...
				if (!confirm(this.overwritemsg.format([title,section])))
					return this.ok(ev);
				txt=txt.replace(altpattern,''); // REMOVE old section (auto-generated)
				txt=txt.replace(pattern,'$2');  // REMOVE old section (generic format)
				// TARGET new section name and value
				pattern=new RegExp('(.*!{1,6})'+section.escapeRegExp()+'\\n'
					+existingval.escapeRegExp()+'((?:\\n!{1,6}|$).*)');
				oldval=existingval;
			}
			if (typeof oldval=="string") // section exists... update/rename it
				txt=txt.replace(pattern,'$1'+section+'\n'+newval+'$2');
			else // otherwise, append a new section to end of tiddler
				txt=txt+this.sectionfmt.format([section,newval]);
		}
		// SAVE TIDDLER
		var fields=this.cloneFields(t.fields);
		store.saveTiddler(title,title,txt,who,when,t.tags,fields);
		story.refreshTiddler(title,null,true);
		autoSaveChanges();
	},
	deleteSection: function(title,section) {
		// GET TIDDLER
		var t=store.getTiddler(title); if (!t) return;
		var who =t&&config.options.chkForceMinorUpdate?t.modifier:config.options.txtUserName;
		var when=t&&config.options.chkForceMinorUpdate?t.modified:new Date();
		if (!section) { // REMOVE TIDDLER
			store.removeTiddler(title);
		} else { // REMOVE SECTION FROM TIDDLER
			var val=store.getTiddlerText(title+'##'+section); // CURRENT SECTION VALUE
			if (typeof val=="string") { // section exists
				var txt=t.text; // default tiddler text = unchanged
				var pattern=new RegExp('(.*!{1,6})'+section.escapeRegExp()+'\\n'
					+(val||'').escapeRegExp()+'((?:\\n!{1,6}|$).*)');
				var altpattern=this.sectionfmt.format([section,val||'']);
				txt=txt.replace(altpattern,''); // REMOVE old section (auto-generated)
				txt=txt.replace(pattern,'$2');  // REMOVE old section (generic format)
				var fields=this.cloneFields(t.fields);
				store.saveTiddler(title,title,txt,who,when,t.tags,fields);
				story.refreshTiddler(title,null,true);
				autoSaveChanges();
			}
		}
	}
}
//}}}
// // EDIT SECTIONS MACRO
//{{{
config.macros.editSections = {
	label: 'edit...',
	tip: 'edit this section',
	command: '~~<<editSection [[##%0]] "%1" "%2">>~~',
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		if (readOnly) return;
		var elems=place.parentNode.getElementsByTagName("*");
		for (var i=0; i<elems.length; i++) { var e=elems[i]; // for each heading element
			if (!['H1','H2','H3','H4','H5'].contains(e.nodeName)) continue;
			var section=e.textContent;
			var label=(params[0]||this.label).format([section]);
			var tip  =(params[1]||this.tip  ).format([section]);
			wikify(this.command.format([section,label,tip]),e);
		}		
	}
}
//}}}
/***
//{{{
!HTML
<!--{{{-->
<!--
|Name|EditSectionTemplate|
|Source||
|Version||
|Author||
|License|http://www.TiddlyTools.com/#LegalStatements|
|Type|template|
|Requires|EditSectionPlugin|
|Description|popup editor form template used by EditSectionPlugin|
-->
<form action='javascript:;' style="white-space:nowrap">
<input type="hidden" name="title" value="">
<input type="hidden" name="section" value="">
<input type="text" name="newsection" value="" autocomplete="off" style="width:61%"
	onchange="return config.macros.editSection.changed(this,event);">
<input type=button value="save" style="width:12%"
	onclick="return config.macros.editSection.saveForm(this,event)">
<input type=button value="cancel" style="width:12%"
	onclick="return config.macros.editSection.cancel(this,event)">
<input type=button value="delete" style="width:12%"
	onclick="return config.macros.editSection.remove(this,event)">
<div macro="tiddler QuickEditToolbar"></div>
<textarea name="content" rows="15" cols="80" autocomplete="off"
	onchange="return config.macros.editSection.changed(this,event)"></textarea>
</form>
<!--}}}-->
!end
//}}}
***/
// //<<editSections "edit">> 
<!--{{{-->
<!--
|Name|EditTemplate|
|Source|http://www.TiddlyTools.com/#EditTemplate|
|Version||
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|template|
|Requires|ToolbarCommands|
|Description|custom version of shadow template used to display tiddler for normal editing|
-->
<span title=' '> <!-- prevent background tooltip from appearing (if any) -->
<span class='toolbar' macro='toolbar [[ToolbarCommands::EditToolbar]]'></span>
<div class='title' macro='view title'></div>
<div style='clear:both'></div>
<div class='editor' macro='edit title'></div>
<div macro='annotations'></div>
<div macro='tiddler QuickEditToolbar'></div>
<div class='editor' macro='edit text'></div>
<span macro='resizeEditor'></span><span macro='setUserName'></span>
<div class='editor' macro='preview hide text'></div>
<div class='editor' macro='edit tags'></div>
<div class='toolbar editorFooter' style='text-align:left !important;float:left !important'>
	<span macro='message views.editor.tagPrompt'></span>
	<span macro='tagChooser'></span>
</div>
<div style='clear:both'></div>
</span>
<!--}}}-->
<!--{{{-->
<!--
|Name|EditTemplate|
|Source|http://www.TiddlyTools.com/#EditTemplate|
|Version||
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|template|
|Requires|ToolbarCommands|
|Description|custom version of shadow template used to display tiddler for normal editing|
-->
<span class='toolbar' macro='toolbar [[ToolbarCommands::EditToolbarReadOnly]]'></span>
<div class='title' macro='view title'></div>
<div style='clear:both'></div>
<div class='editor' macro='edit title'></div>
<div macro='annotations'></div>
<div class='editor' macro='edit text'></div>
<span macro='resizeEditor'></span>
<div class='editor' macro='preview hide text'></div>
<div class='editor' macro='edit tags'></div>
<div class='toolbar editorFooter' style='text-align:left !important;float:left !important'>
	<span macro='message views.editor.tagPrompt'></span>
	<span macro='tagChooser'></span>
</div>
<div style='clear:both'></div>
<!--}}}-->
/***
|Name|EditTiddlerPlugin|
|Source|http://www.TiddlyTools.com/#EditTiddlerPlugin|
|Version|1.3.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|embed an 'edit' link in tiddler content to invoke edit on any specified tiddler title|
!!!!!Usage
<<<
{{{
<<editTiddler TiddlerName label>>
}}}
*''~TiddlerName''<br>the title of the tiddler to edit (omit or use the keyword 'here' for current //containing// tiddler)
*''label''<br>command link text (default="edit")
The plugin also adds ''ctrl-enter'' as a ''keyboard shortcut to start editing'' the current //selected// tiddler (the one with an active toolbar menu)
<<<
!!!!!Revisions
<<<
2009.08.15 1.3.1 in shortcut, invoke editTiddler command handler (sets focus and custom fields)
2009.08.14 1.3.0 added CTRL-ENTER keyboard shortcut to invoke edit for 'selected' tiddlers
2007.03.22 1.2.0 added 'here' keyword and optional 2nd param to specify label text
2007.03.15 1.1.1 fixed 'get tiddler ID' logic so it actually works! D'oh! 
2007.03.11 1.1.0 changed 'get tiddler ID' logic so that macro can be used outside a tiddler (i.e., in mainMenu) by specifying the ID
2006.10.04 1.0.1 invoke findContainingTiddler() as fallback when 'tiddler' param is null
2006.04.28 1.0.0 Initial release
<<<
!!!Code
***/
//{{{
version.extensions.EditTiddlerPlugin={major:1, minor:3, revision:1, date: new Date(2009,8,15)};

config.macros.editTiddler={
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		var tid=params.shift(); // use specified tiddler ID (or "here")
		if (!tid || tid=="here") {
			var here=story.findContainingTiddler(place);
			if (!here) return; // not in a tiddler, do nothing
			tid=here.getAttribute('tiddler'); // get ID from tiddler element
		}
		var label="edit"; if (params[0]) label=params.shift();
		createTiddlyButton(place,label,'edit tiddler: '+tid,this.onclick).setAttribute('which',tid);
	},
	onclick: function(e) {
		story.displayTiddler(null,this.getAttribute('which'),DEFAULT_EDIT_TEMPLATE);
	}
}
//}}}
//{{{
	addEvent(document,'keypress', function(ev) { var ev=ev||window.event;
		if (!ev.ctrlKey || ev.keyCode!=13) return; // CTRL-ENTER = edit tiddler
		story.forEachTiddler(function(title,tiddler){
			if (hasClass(tiddler,'selected') && !story.isDirty(title))
				config.commands.editTiddler.handler(ev,null,title);
		});
		return false;
	});
//}}}
/%
!info
|Name|EmbedTiddlers|
|Source|http://www.TiddlyTools.com/#EmbedTiddlers|
|Version|2.0.2|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|Type|transclusion|
|Description|transclude a list of tiddlers in a specific order|
Usage
<<<
{{{
<<tiddler EmbedTiddlers with: "TiddlerName [[TiddlerName with spaces]] TiddlerName ...">>
<<tiddler EmbedTiddlers with: @TiddlerName>>
<<tiddler EmbedTiddlers with: =tagValue sortby>>
}}}
*''"~TiddlerName """[[TiddlerName with spaces]] TiddlerName ...""""''<br>specifies a list of tiddlers to embed
*''@~TiddlerName''<br>specifies a //separate// tiddler containing the space-separated, bracketed list of tiddlers to embed (e.g., like [[DefaultTiddlers]])
*''=tagValue''<br>embeds all tiddlers that are tagged with the indicated value
*''sortby'' (optional)<br> specifies a tiddler field for sorting the results (default="title").  Use "+" or "-" prefix to indicate the sort direction (ascending/descending), e.g., "-modified" sorts by tiddler modification date, most recent first.
Note: if MatchTagsPlugin is installed, you can use //compound Boolean logic expressions// in place of the "tagValue" (following the leading "=").  However, because a boolean expression will always contain spaces, it MUST be enclosed in quotes (or doubled square brackets {{{[[...]]}}}), like this:
{{{
<<tiddler EmbedTiddlers with: "=settings AND NOT systemConfig">>
}}}
<<<
!end
!out
$1
!end
!show
<<tiddler EmbedTiddlers##out with: {{
	var list='$1';
	var sortby='title'; if ('$2'!='$'+'2') sortby='$2';
	var tids=[];
	if (list.substr(0,1)=='=') {
		var fn=store.getMatchingTiddlers||store.getTaggedTiddlers;
		var tagged=store.sortTiddlers(fn.apply(store,[list.substr(1)]),sortby);
		for (var t=0; t<tagged.length; t++) tids.push(tagged[t].title);
	} else {
		if (list.substr(0,1)=='@') list=store.getTiddlerText(list.substr(1),'');
		var tids=list.readBracketedList();
	}
	var out='';
	for (var i=0; i<tids.length; i++) out+='<<tiddler [['+tids[i]+']]>\>';
	out;
}}>>
!end
%/<<tiddler {{var src='EmbedTiddlers'; src+(tiddler&&tiddler.title==src?'##info':'##show');}}
	with: "$1" "$2">>
/***
|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|ExternalTiddlersPlugin|
|Source|http://www.TiddlyTools.com/#ExternalTiddlersPlugin|
|Documentation|http://www.TiddlyTools.com/#ExternalTiddlersPluginInfo|
|Version|1.3.3|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Requires|TemporaryTiddlersPlugin, SectionLinksPlugin (optional, recommended)|
|Description|retrieve and wikify content from external files or remote URLs|
This plugin extends the {{{<<tiddler>>}}} macro syntax so you can retrieve and wikify content directly from external files or remote URLs.  You can also define alternative "fallback" sources to provide basic "import on demand" handling by automatically creating/importing tiddler content from external sources when the specified ~TiddlerName does not already exist in your document.
!!!!!Documentation
>see [[ExternalTiddlersPluginInfo]]
!!!!!Configuration
<<<
<<option chkExternalTiddlersImport>> automatically create/import tiddlers when using external fallback references
{{{usage: <<option chkExternalTiddlersImport>>}}}
<<option chkExternalTiddlersQuiet>> don't display messages when adding tiddlers ("quiet mode")
{{{usage: <<option chkExternalTiddlersQuiet>>}}}
<<option chkExternalTiddlersTemporary>> tag retrieved tiddlers as 'temporary'(requires [[TemporaryTiddlersPlugin]])
{{{usage: <<option chkExternalTiddlersTemporary>>}}}
tag retrieved tiddlers with: <<option txtExternalTiddlersTags>>
{{{usage: <<option txtExternalTiddlersTags>>}}}

__password-protected server settings //(optional, if needed)//:__
>username: <<option txtRemoteUsername>> password: <<option txtRemotePassword>>
>{{{usage: <<option txtRemoteUsername>> <<option txtRemotePassword>>}}}
>''note: these settings are also used by [[LoadTiddlersPlugin]] and [[ImportTiddlersPlugin]]''
<<<
!!!!!Revisions
<<<
2011.04.27 1.3.3 merge/clone defaultCustomFields for saving in TiddlySpace
|please see [[ExternalTiddlersPluginInfo]] for additional revision details|
2007.11.25 1.0.0 initial release - moved from CoreTweaks
<<<
!!!!!Code
***/
//{{{
version.extensions.ExternalTiddlersPlugin= {major: 1, minor: 3, revision: 3, date: new Date(2011,4,26)};

// optional automatic import/create for missing tiddlers
if (config.options.chkExternalTiddlersImport==undefined) config.options.chkExternalTiddlersImport=true;
if (config.options.chkExternalTiddlersTemporary==undefined) config.options.chkExternalTiddlersTemporary=true;
if (config.options.chkExternalTiddlersQuiet==undefined) config.options.chkExternalTiddlersQuiet=false;
if (config.options.txtExternalTiddlersTags==undefined) config.options.txtExternalTiddlersTags="external";
if (config.options.txtRemoteUsername==undefined) config.options.txtRemoteUsername="";
if (config.options.txtRemotePassword==undefined) config.options.txtRemotePassword="";

config.macros.tiddler.externalTiddlers_handler = config.macros.tiddler.handler;
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 list = names[0];
	var items = list.split("|"); 
	var className = names[1] ? names[1] : null;
	var args = params[0]["with"];

	// UTILITY FUNCTIONS
	function extract(text,tids) { // get tiddler source content from plain text or TW doc
		if (!text || !tids || !tids.length) return text; // no text or no tiddler list... return text as-is
		var remoteStore=new TiddlyWiki();
		if (!remoteStore.importTiddlyWiki(text)) return text; // not a TW document... return text as-is
		var out=[]; for (var t=0;t<tids.length;t++)
			{ var txt=remoteStore.getTiddlerText(tids[t]); if (txt) out.push(txt); }
		return out.join("\n");
	}
	function substitute(text,args) { // replace "substitution markers" ($1-$9) with macro param values (if any)
		if (!text || !args || !args.length) return text;
		var n=args.length; if (n>9) n=9;
		for(var i=0; i<n; i++) { var re=new RegExp("\\$" + (i + 1),"mg"); text=text.replace(re,args[i]); }
		return text;
	}
	function addTiddler(src,text,tids) { // extract tiddler(s) from text and create local copy
		if (!config.options.chkExternalTiddlersImport) return; // not enabled... do nothing
		if (!text || !tids || !tids.length) return; // no text or no tiddler list... do nothing
		var remoteStore=new TiddlyWiki();
		if (!remoteStore.importTiddlyWiki(text)) // not a TW document... create a single tiddler from text
			makeTiddler(src,text,tids[0]);
		else // TW document with "permaview-like" suffix... copy tiddler(s) from remote store
			for (var t=0;t<tids.length;t++)
				insertTiddler(src,remoteStore.getTiddler(tids[t]));
		return;
	}
	function makeTiddler(src,text,title) { // create a new tiddler object from text
		var who=config.options.txtUserName; var when=new Date();
		var msg="/%\n\nThis tiddler was automatically created using ExternalTiddlersPlugin\n";
		msg+="by %0 on %1\nsource: %2\n\n%/";
		var tags=config.options.txtExternalTiddlersTags.readBracketedList();
		if (config.options.chkExternalTiddlersTemporary) tags.pushUnique(config.options.txtTemporaryTag);
		var fields=merge({},config.defaultCustomFields,true)
		store.saveTiddler(null,title,msg.format([who,when,src])+text,who,when,tags,fields);
		if (!config.options.chkExternalTiddlersQuiet) displayMessage("Created new tiddler '"+title+"' from text file "+src);
	}
	function insertTiddler(src,t) { // import a single tiddler object into the current document store
		if (!t) return;
		var who=config.options.txtUserName; var when=new Date();
		var msg="/%\n\nThis tiddler was automatically imported using ExternalTiddlersPlugin\n";
		msg+="by %0 on %1\nsource: %2\n\n%/";
		var newtags=new Array().concat(t.tags,config.options.txtExternalTiddlersTags.readBracketedList());
		if (config.options.chkExternalTiddlersTemporary) newtags.push(config.options.txtTemporaryTag);
		var fields=merge(t.fields,config.defaultCustomFields,true)
		store.saveTiddler(null,t.title,msg.format([who,when,src])+t.text,t.modifier,t.modified,newtags,fields);
		if (!config.options.chkExternalTiddlersQuiet) displayMessage("Imported tiddler '"+t.title+"' from "+src);
	}
	function getGUID()  // create a Globally Unique ID (for async reference to DOM elements)
		 { return new Date().getTime()+Math.random().toString(); }

	// loop through "|"-separated list of alternative tiddler/file/URL references until successful
	var fallback="";
	for (var i=0; i<items.length; i++) { var src=items[i];
		// if tiddler (or shadow) exists, replace reference list with current source name and apply core handler
		if (store.getTiddlerText(src)) {
			arguments[2][0]=src; // params[] array
			var p=arguments[4].split(list); arguments[4]=p[0]+src+p[1]; // paramString
			this.externalTiddlers_handler.apply(this,arguments);
			break; // stop processing alternatives
		}

		// tiddler doesn't exist, and not an external file/URL reference... skip it
		if (!config.formatterHelpers.isExternalLink(src)) {
			if (!fallback.length) fallback=src; // title to use when importing external tiddler
			continue;
		}
		// separate 'permaview' list of tiddlers (if any) from file/URL (i.e., '#name name name..." suffix)
		var p=src.split("#"); src=p.shift(); var tids=p.join('#').readBracketedList(false);
		// if reference is to a remotely hosted document or the current document is remotely hosted...
		if (src.substr(0,4)=="http" || document.location.protocol.substr(0,4)=="http") {
			if (src.substr(0,4)!="http") // fixup URL for relative remote references
				{ var h=document.location.href; src=h.substr(0,h.lastIndexOf("/")+1)+src; }
			var wrapper = createTiddlyElement(place,"span",getGUID(),className); // create placeholder for async rendering
			var callback=function(success,params,text,src,xhr) { // ASYNC CALLBACK
				if (!success) { displayMessage(xhr.status); return; } // couldn't read remote file... report the error 
				if (params.fallback.length)
					addTiddler(params.url,text,params.tids.length?params.tids:[params.fallback]); // import tiddler
				var wrapper=document.getElementById(params.id); if (!wrapper) return; 
				wikify(substitute(extract(text,params.tids),params.args),wrapper); // ASYNC RENDER
			};
			var callbackparams={ url:src, id:wrapper.id, args:args, tids:tids, fallback:fallback }  // ASYNC PARAMS
			var name=config.options.txtRemoteUsername; // optional value
			var pass=config.options.txtRemotePassword; // optional value
			var x=doHttp("GET",src,null,null,name,pass,callback,callbackparams,null)
			if (typeof(x)=="string") // couldn't start XMLHttpRequest... report error
				{ displayMessage("error: cannot access "+src); displayMessage(x); }
			break; // can't tell if async read will succeed.... stop processing alternatives anyway.
		}
		else { // read file from local filesystem
			var text=loadFile(getLocalPath(src));
			if (!text) { // couldn't load file... fixup path for relative reference and retry...
				var h=document.location.href;
				var text=loadFile(getLocalPath(decodeURIComponent(h.substr(0,h.lastIndexOf("/")+1)))+src);
			}
			if (text) { // test it again... if file was loaded OK, render it in a class wrapper
				if (fallback.length) // create new tiddler using primary source name (if any)
					addTiddler(src,text,tids.length?tids:[fallback]);
				var wrapper=createTiddlyElement(place,"span",null,className);
				wikify(substitute(extract(text,tids),args),wrapper); // render
				break; // stop processing alternatives
			}
		}
	}
};
//}}}
|Name|ExternalTiddlersPluginInfo|
|Source|http://www.TiddlyTools.com/#ExternalTiddlersPlugin|
|Documentation|http://www.TiddlyTools.com/#ExternalTiddlersPluginInfo|
|Version|1.3.3|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|documentation|
|Description|documentation for ExternalTiddlersPlugin|
This plugin extends the {{{<<tiddler>>}}} macro syntax so you can retrieve and wikify content directly from external files or remote URLs.  You can also define alternative "fallback" sources to provide basic "import on demand" handling by automatically creating/importing tiddler content from external sources when the specified ~TiddlerName does not already exist in your document.
!!!!!Configuration
>see ExternalTiddlersPlugin
!!!!!Usage
<<<
The standard TiddlyWiki core syntax for the {{{<<tiddler>>}}} macro is:
>{{{<<tiddler TiddlerName with: param param param ...>>}}}
where the optional {{{with: param param param...}}} values are used to replace any corresponding "substitution markers" ($1 to $9) that may be embedded in the referenced tiddler content.

This plugin allows the {{{<<tiddler>>}}} macro to ''use external file/URL references in place of the usual ~TiddlerName parameter'', so that you can render wiki-formatted source content retrieved from an external file/URL reference (as determined by the core's isExternalLink() test function), ''//as if// it had come from a tiddler in the current document''.  The external file/URL can be either ''a relative or absolute reference'' and can contain ''"plain text" or a full TiddlyWiki document''.  When using a TiddlyWiki document, you must specify which tiddlers should be included in the output by appending a permaview-like suffix to the file or URL reference, e.g.:
>{{{<<tiddler "myfile.txt" with: param param param...>>}}}
>or
>{{{<<tiddler "myfile.html#TiddlerName TiddlerName..." with: param param param...>>}}}
>or
>{{{<<tiddler "http://www.TiddlyWiki.com/index.html#HelloThere" with: param param param...>>}}}
If the plugin-enhanced {{{<<tiddler>>}}} macro is unable to retrieve the external content --  perhaps because the file doesn't exist or doesn't contain the requested tiddler(s), or cross-domain security blocked file access, or the network/server "timed out", etc., -- then it produces no output (i.e., just as when the standard {{{<<tiddler>>}}} macro is given a ~TiddlerName does not exist in the current document.)
<<<
!!!!!Using alternative "fallback" references
<<<
In addition to using external file/URL references in place of the usual ~TiddlerName, the plugin also allows you to use a ''fallback list'' consisting of a combination of alternative sources: tiddlers, local files, and/or URL references, each separated by "|".  The first reference in a fallback list is the "primary source"; the remaining references are "fallback sources".  The plugin will attempt to retrieve content from each fallback source until one is successfully retrieved or all alternatives have been tried.

For example, if you create a tiddler called [[HelloThere]], as well as a remotely-hosted TW document containing a published tiddler, also called [[HelloThere]], then you can write:
>{{{<<tiddler [[HelloThere|http://www.TiddlyWiki.com/#HelloThere]]>>}}}
When [[HelloThere]] is present in the local document, it is processed in the normal manner.  However, if you delete the  local [[HelloThere]] tiddler, the plugin will attempt to retrieve the [[HelloThere]] tiddler from the indicated remote URL.

Please note: although you can list any number of alternative sources, in whatever order you prefer, retrieval from a remote URL occurs asynchronously via XMLHttpRequest() processing.  As a consequence, there can be ''no more than one remote URL reference in the fallback list'', and any alternatives that follow a remote URL reference will not be processed.
<<<
!!!!!Automatically import/create missing tiddlers
<<<
When content is retrieved from an external fallback source, the plugin can automatically import/create tiddler(s) containing that content into your document, allowing you to display, modify, save and/or search for text in that tiddler from within your own document, without needing to retrieve it again from the external source.

If no local ~TiddlerName(s) are specified in the fallback list (i.e., only direct file/URL references are present), then a tiddler will NOT be created, so that each time you render the tiddler display the external source will be re-read in order to render the most recently saved external file content.  To illustrate using the example from above:
>&nbsp;&nbsp;&nbsp;{{{<<tiddler [[HelloThere|http://www.TiddlyWiki.com/#HelloThere]]>>}}}
will automatically create a locally-stored [[HelloThere]] tiddler, so that the external source is only accessed the first time the content is rendered, while:
>&nbsp;&nbsp;&nbsp;{{{<<tiddler [[http://www.TiddlyWiki.com/#HelloThere]]>>}}}
will re-load the content from the external source each time the display is rendered.

For easy identification, any tiddlers that are automatically created/imported are tagged with <<tag external>> (or other custom-defined tag values).  These tiddlers can also be automatically tagged with <<tag temporary>> for use with [[TemporaryTiddlersPlugin]], which will skip over those tiddlers when saving changes to your document so that when you reload the document, the temporary tiddlers will no longer be present and will be retrieved anew from the external source, on demand, when (or if) they are needed.  Important reminder: ''If you modify a temporary tiddler and want to retain it in your local document, be sure to remove the <<tag temporary>> tag from the tiddler before saving.''
<<<
!!!!!~XMLHttpRequest: performance and security issues
<<<
This plugin uses asynchronous XMLHttpRequest() processing to access external content directly from URLs hosted on remote web servers.  However, ''cross-domain access from one remote domain to another using XMLHttpRequest() processing is generally restricted for security reasons''.  As a result, URL references between server-hosted documents will not work unless those documents are located within the same domain.  In order to ensure that external content included in server-hosted documents will be displayed as intended, you should ''always use either a relative path/file reference or an http: reference located on the same domain as the published document.'' for any document you intend to publish.

Note: Some hosting providers, such as http://www.TiddlySpot.com/ offer ''"proxy" services that may allow you to bypass the security restrictions'' for certain designated remote web sites.  Consult your hosting service for information regarding their proxy arrangments (if any).
<<<
!!!!!Revisions
<<<
2011.04.27 1.3.3 merge/clone defaultCustomFields for saving in TiddlySpace
2011.02.08 1.3.2 fixed parsing of external links to allow retrieval of tiddler sections from remote files.  NOTE: //requires SectionLinksPlugin v1.4.1 or above//).  Also, calls to saveTiddler() use config.defaultCustomFields for TiddlySpace compatibility.
2008.10.27 1.3.1 in insertTiddler(), fixed Safari bug by replacing static Array.concat(...) with new Array().concat(...)
2008.01.08 [*.*.*] plugin size reduction: documentation moved to ExternalTiddlersPluginInfo
2008.01.03 1.3.0 use lower-level doHttp() instead loadRemoteFile() so that optional username/password values can be used in XMLHttpRequest
2007.12.22 1.2.2 in handler(), when reading from local file with relative path fixup, use decodeURIComponent() instead of decodeURI 
2007.11.30 1.2.1 lots of code/documentation cleanup.  renamed option cookies.  changed auto tag value to "external".
2007.11.27 1.2.0 added support for automatically importing external tiddlers
2007.11.26 1.1.1 improved XMLHttpRequest() error reporting for cross-domain security issues
2007.11.26 1.1.0 added support for multiple alternative fallback references
2007.11.25 1.0.0 initial release - moved from CoreTweaks
<<<
{{smallform{
<<tiddler HideTiddlerTags>><<tiddler GetTheFAQs>>}}}
/***
|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|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>
<!--}}}-->
systemConfig script settings CSS attachment template sample

AttachFilePackage
ImportExportPackage
MediaPackage
NavigationPackage
ThemePackage
TidIDEPackage
QuickEditPackage
DiscoveryPackage
IconPackage
TaskPackage
WoodshopPackage
ScrollbarPackage
BookmarkPackage
<script label="last change..." title="goto the most recently modified tiddler">
	var title=store.getTiddlers("modified","excludeLists").reverse()[0].title;
	story.displayTiddler(null,title); story.refreshTiddler(title,null,true);
	return false;
</script>
----
<script label="open...">
	var tid=prompt("enter a tiddler title"); if (!tid || !tid.length) return;
	story.displayTiddler(story.findContainingTiddler(place),tid);
	return false;
</script>
----
[[Welcome]]
[[About]]
[[Contact]]
----
SiteMenu
StoryMenu
MainMenu
MainMenuExtras
SideBarOptions
SideBarTabs
SiteTitle
----
<<editTiddler FavoriteTiddlers "edit favorites...">>
<script>
	window.sec=1000; // global abbreviation - default multiplier for speed control
	window.step=10;  // global abbreviation - time between items
	var here=story.findContainingTiddler(place); if (!here) return;
	var tid=here.getAttribute("tiddler");
	setTimeout("story.closeAllTiddlers('"+tid+"')",1);
</script>/%

%/{{hidden{

!!!Show
/%

Usage: <<tiddler FeaturedTiddlers##Show with: TiddlerName Description Delay Duration Direction>>

%/{{span{[[$1]]:
{{smaller{$2}}}/%
%/<<animate = "$5" %0% 100 0 {{"$3"*1000}} 1500 2 {{"$4"*1000-3000}}>>/%
%/<<animate = +fontSize %0% 0 100 {{"$3"*1000}} 500 2 {{"$4"*1000-1000}}>>/%
%/}}}/%
%/{{hidden{<<tiddler SlideshowTimer with: [[$1]] {{"$3"*1+1}}>>}}}
!!!end Show

}}}/%
<<tiddler MoveTiddlerToTop>>/%
%/<<tiddler HideTiddlerTags>>/%
%/<<tiddler HideTiddlerBackground>>/%
%/<<tiddler HideTiddlerSubtitle>>/%
%/{{selected{{{toolbar fine{
	{{fine{<<tiddler SlideshowTimer with: Welcome {{6+step*13}}>>&nbsp;}}}/%
	%/<<tiddler ToggleFullScreen with: fullscreen restore>>/%
	%/<<tiddler RefreshTiddler with: replay>>/%
	%/<script label="stop">
		var here=story.findContainingTiddler(place); if (!here) return;
		story.closeTiddler(here.getAttribute("tiddler"));
		story.displayTiddler(null,"Welcome"); story.refreshTiddler("Welcome",null,true);
		return false;
	</script>/%
%/}}}}}}/%
%/<html><hide linebreaks><embed src='midi/marslove.mid'
	width=100 height=16 autostart='true' autoplay='true'>
</embed></html>/%

BANNER MESSAGE [0:00-0:10]
%/{{big center italic{
{{gray{<<animate div "TiddlyTools presents...<br><br>" fontSize %0% 0 70 0 {{.1*step*sec}} 2 {{.7*step*sec}}>>}}}/%
%/{{blue{<<animate div "Small Tools" fontSize %0% 0 100 {{.1*step*sec}} {{.1*step*sec}} 2 {{.8*step*sec}}>>}}}/%
%/{{gray{<<animate div "for" fontSize %0% 0 50 {{.2*step*sec}} {{.05*step*sec}} 2 {{.6*step*sec}}>>}}}/%
%/{{green{<<animate div "''BIG Ideas!''" fontSize %0% 0 300 {{.3*step*sec}} {{.1*step*sec}} 2 {{.7*step*sec}}>>}}}/%

%/{{span italic normal bold{

//You can install these tools -- and many other TiddlyTools plugins,
scripts, packages, template, themes, etc. -- to customize //YOUR// TiddlyWiki documents!!///%
%/<<animate = fontSize %0% 0 100 {{.5*step*sec}} {{.15*step*sec}} 2 {{.4*step*sec}}>>/%
%/}}}/%

%/<<tiddler FeaturedTiddlers##Show Tiddler with: MiniBrowser
	"Browser-in-browser with favorites list<br>transparently supports embedded media players<br>for Windows, Real, Quicktime and Flash"
	{{2+step*1}} {{step}} left>>/%

%/<<tiddler FeaturedTiddlers##Show with: FAQViewer
	"Helpful articles with TiddlyWiki tips, tricks, tech notes, etc.<br>select by tag keyword or full text search..."
	{{2+step*2}} {{step}} right>>/%

%/<<tiddler FeaturedTiddlers##Show with: RecentChanges
	"View a droplist of recently changed tiddlers,<br>select a tiddler to goto, edit, or preview it's content"
	{{2+step*3}} {{step}} left>>/%

%/<<tiddler FeaturedTiddlers##Show with: TicketTracker
	"Check trac.tiddlywiki.org for the latest TiddlyWiki development status<br>Submit bug reports and feature requests.<br>Review the 'roadmap' for future releases."
	{{2+step*4}} {{step}} right>>/%

%/<<tiddler FeaturedTiddlers##Show with: MatchTags
	"Use Boolean tag expressions<br>(AND, OR, NOT, with parentheses)<br>to find tiddlers with specific tag combinations"
	{{2+step*5}} {{step}} left>>/%

%/<<tiddler FeaturedTiddlers##Show with: CompareTiddlers
	"word-by-word comparison of any two tiddlers<br>with side-by-side, color-coded display of differences"
	{{2+step*6}} {{step}} right>>/%

%/<<tiddler FeaturedTiddlers##Show with: SplitTiddler
	"Separate large blocks of text into separate tiddlers"
	{{2+step*7}} {{step}} left>>/%

%/<<tiddler FeaturedTiddlers##Show with: CookieManager
	"View and modify your TiddlyWiki personal settings<br>Update or reset checkbox and text options<br>'bake' cookies for 'sticky' settings"
	{{2+step*8}} {{step}} right>>/%

%/<<tiddler FeaturedTiddlers##Show with: QuickEditToolbar
	"Quickly insert links, files, etc.<br>Add common TiddlyWiki formatting syntax with one click<br>Interactive controls for incremental FIND/REPLACE<br>"
	{{2+step*9}} {{step}} left>>/%

%/<<tiddler FeaturedTiddlers##Show with: TiddlerTweaker
	"Select/modify internal tiddler values for multiple tiddlers at one time!<br>Change tiddler title, author, dates, etc.<br>Add, remove, replace tags on selected tiddlers with just one click!"
	{{2+step*10}} {{step}} right>>/%

%/<<tiddler FeaturedTiddlers##Show with: SystemInfo
	"Examine TiddlyWiki system internals<br>View shadows, stylesheets, toolbars, macros, formatters, and more!"
	{{2+step*11}} {{step}} left>>/%

%/<<tiddler FeaturedTiddlers##Show with: RollText
	"Display horizontally scrolling messages<br>using 'zoom in/zoom out' text animation effects"
	{{2+step*12}} {{step}} right>>/%

%/}}}
/***
|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;
})
//}}}
/***
|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>>
/%
!info
|Name|FoldOtherTiddlers|
|Source|http://www.TiddlyTools.com/#FoldOtherTiddlers|
|Version|2.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Description|fold all other tiddlers when a tiddler is viewed|
Usage:
<<<
{{{
<<tiddler FoldOtherTiddlers>>
}}}
<<<
!end
%/<<tiddler {{
	var out='FoldOtherTiddlers##info';
	if (config.commands.collapseTiddler && (!tiddler||tiddler.title!='FoldOtherTiddlers')) {
		var here=story.findContainingTiddler(place);
		if (here) config.commands.collapseOthers.handler(null,here,here.getAttribute('tiddler'));
		out='';
	}
out;}}>>
/***
|Name|FramedLinksPlugin|
|Source|http://www.TiddlyTools.com/#FramedLinksPlugin|
|Version|1.1.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|clicking an external link opens an IFRAME following the link instead of opening a new tab/window|
This plugin causes clicks on external links to be rendered as inline frames (~IFRAMEs) instead of opening new browser tabs/windows.
!!!!!Usage
<<<
Use standard TiddlyWiki external link syntax into your tiddler content. If {{{chkFramedLinks}}} is enabled or the tiddler is tagged with 'framedLinks' (see Configuration), then whenever you click the external link an IFRAME will be dynamically added to the content.  Clicking on the link again removes the IFRAME.  Hold down any modifier (shift, control, or alt) while clicking a link ''temporarily'' bypasses the IFRAME handling and use the standard link handling behavior.
<<<
!!!!!Configuration
<<<
<<option chkFramedLinks>> display inline frames for all external links
&nbsp; &nbsp; {{{<<option chkFramedLinks>>}}}
<<option chkFramedLinksTag>> display inline frames for external links in tiddlers tagged with: <<option txtFramedLinksTag>> 
&nbsp; &nbsp; {{{<<option chkFramedLinksTag>> <<option txtFramedLinksTag>>}}}
IFRAME size (CSS units: %, em, px, cm, in) - width: <<option txtFrameWidth>> height: <<option txtFrameHeight>>
&nbsp; &nbsp; {{{<<option txtFrameWidth>> <<option txtFrameHeight>>}}}
<<<
!!!!!Examples
<<<
Try these links:
*http://www.TiddlyWiki.com
*http://www.TiddlyTools.com
*http://groups.google.com/group/TiddlyWiki/topics
<<<
!!!!!Revisions
<<<
2008.11.14 [1.1.1] fixed handling for external links embedded in //shadow// tiddlers
2008.09.13 [1.1.0] added support to selectively enable embedded IFRAMEs if the containing tiddler is tagged with 'framedLinks'
2007.11.29 [1.0.5] added slider animation and improved CSS handling for IFRAME height/width to maximize display area
2007.11.29 [1.0.0] initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.FramedLinksPlugin= {major: 1, minor: 1, revision: 1, date: new Date(2008,11,14)};

var co=config.options; // abbreviation
if (co.chkFramedLinks==undefined) co.chkFramedLinks=false;
if (co.chkFramedLinksTag==undefined) co.chkFramedLinksTag=true;
if (co.txtFramedLinksTag==undefined) co.txtFramedLinksTag="framedLinks";
if (co.txtFrameWidth==undefined) co.txtFrameWidth="100%";
if (co.txtFrameHeight==undefined) co.txtFrameHeight="80%";

window.framedLinks_createExternalLink=createExternalLink;
window.createExternalLink=function(place,url)
{
	var link=this.framedLinks_createExternalLink.apply(this,arguments);
	link.onclick=function(ev) { var e=ev?ev:window.event;
		var co=config.options; // abbreviation
		var here=story.findContainingTiddler(this);
		if (here) var tid=store.getTiddler(here.getAttribute("tiddler"));
		var enabled=co.chkFramedLinks || co.chkFramedLinksTag && tid && tid.isTagged(co.txtFramedLinksTag);
		if (!enabled || e.ctrlKey || e.shiftKey || e.altKey) return; // BYPASS
		var p=this.parentNode; 
		var f=this.nextSibling?this.nextSibling.firstChild:null; // get the IFRAME... maybe...
		var w=co.txtFrameWidth; if (!w || !w.length) w="100%";
		var h=co.txtFrameHeight; if (!h || !h.length) h="80%";
		if (h.indexOf("%")) h=(findWindowHeight()*h.replace(/%/,"")/100)+"px"; // calc height as % of window
		var showing=f && f.nodeName.toUpperCase()=="IFRAME"; // does IFRAME really exist?
		var stretchCell=p.nodeName.toUpperCase()=="TD" && w.indexOf("%")!=-1 && w.replace(/%/,"")>=100;
		if (!showing) { // create an iframe
			link.style.display="block"; // force IFRAME onto line following link
			if (stretchCell) { p.setAttribute("savedWidth",p.style.width); p.style.width="100%"; } // adjust TD so IFRAME stretches
			var wrapper=createTiddlyElement(null,"span"); // wrapper for slider animation
			wrapper.setAttribute("url",this.href); // for async loading of frame after animation completes
			var f=createTiddlyElement(wrapper,"iframe"); // create IFRAME
			f.style.backgroundColor="#fff"; f.style.width=w; f.style.height=h;
			p.insertBefore(wrapper,this.nextSibling);
			function loadURL(wrapper) { var f=wrapper.firstChild; var url=wrapper.getAttribute("url");
				var d=f.contentDocument?f.contentDocument:(f.contentWindow?f.contentWindow.document:f.document);
				d.open(); d.writeln("<html>connecting to "+url+"</html>"); d.close();
				try { f.src=url; } // if the iframe can't handle the href
				catch(e) { alert(e.description?e.description:e.toString()); } // ... then report the error
				window.scrollTo(0,ensureVisible(wrapper));
			}
			if (!co.chkAnimate) loadURL(wrapper);
			else {
				var morph=new Slider(wrapper,true);
				morph.callback=loadURL;
				morph.properties.push({style: 'width', start: 0, end: 100, template: '%0%'});
				anim.startAnimating(morph);
			}
		} else { // remove iframe
			link.style.display="inline"; // restore link style
			if (stretchCell) p.style.width=p.getAttribute("savedWidth"); // restore previous width of TD
			if (!co.chkAnimate) p.removeChild(f.parentNode);
			else {
				var morph=new Slider(f.parentNode,false,false,"all");
				morph.properties.push({style: 'width', start: 100, end: 0, template: '%0%'});
				anim.startAnimating(morph);
			}
		}
		e.cancelBubble=true; if (e.stopPropagation) e.stopPropagation(); return false;
	}
	return link;
}
//}}}
/%
!info
|Name|GetTheFAQs|
|Source|http://www.TiddlyTools.com/#GetTheFAQs|
|Version|2.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion |
|Requires|LoadTiddlersPlugin, FAQViewerPlugin|
|Description|autoload FAQ articles from external document|
Usage
<<<
{{{
<<tiddler GetTheFAQs>>
<<tiddler GetTheFAQs with: location tag tiddlername>>
}}}
*''location'' (optional)<br>is a URL, a relative path/file, or a TiddlerName that refers to a TiddlyWiki document. If omitted (use {{{[[]]}}} as a placeholder), the contents of [[SiteFAQ]] (if any) will be used.  If [[SiteFAQ]] doesnt exist, a default of 'faq.html' will be used.
*''tag'' (optional)<br>indicates the tag to match when retrieving tiddlers (default="faq").
*''tiddlername'' (optional)<br>specifies a desired 'target' tiddler title (default=none).
Tiddlers are loaded only if the specified target tiddler or tag value is not present in the current document.  If suitable tiddlers are already present, the [[FAQViewer]] is automatically displayed.
<<<
Example
<<<
{{{<<tiddler GetTheFAQs>>}}}
{{smallform{<<tiddler GetTheFAQs##show>>}}}
<<<
!end

!notloaded
//There are no ''%0'' tiddlers currently loaded.//
''Please <html><nowiki><a href="javascript:;" onclick="
	var here=story.findContainingTiddler(this);
	if (here) story.refreshTiddler(here.getAttribute('tiddler'),null,true);
	return false;
">refresh this tiddler</a></html> to import the %0 archive...''
//To view the archive directly, please visit://
{{indent{[[%1|%1]]}}}
!end

!show
<<tiddler {{
	var out='';
	var src='$1'!='$'+'1'?'$1':'';
	var tag='$2'!='$'+'2'?'$2':'faq';
	var target='$3'!='$'+'3'?'$3':'';
	var defaultsrc	='faq.html';
	var askmsg	="Enter the location of a TiddlyWiki document containing '%0' tiddlers";
	var confirmmsg	="Press OK to import '%0' tiddlers from:";
	var loadingmsg	="'%0' tiddlers are being imported... please wait...";

	// if target or tagged tiddlers already exists, just show the viewer
	if (store.tiddlerExists(target)||store.getTaggedTiddlers(tag,'excludeLists').length)
		out='<<faqViewer %0 %2 outline -modified [[YYYY.0MM.0DD - ]]>\>';
	else {
		src=store.getTiddlerText(src,src); // get src from tiddler (if any)
		if (!src.length) // fallback: use [[SiteFAQ]] or default (faq.html)
			src=store.getTiddlerText('SiteFAQ',defaultsrc);
		var s=prompt(confirmmsg.format([tag]),src); // ask for permission (or change src)
		if (!s||!s.length) // cancelled
			out=store.getTiddlerText('GetTheFAQs##notloaded');
		else {
			src=store.getTiddlerText(s,s); // get src from tiddler (if any)
			// show 'please wait' message if remote async load
			var async=document.location.protocol!='file:'||src.substr(0,4)=='http'; 
			if (async) setTimeout('displayMessage("'+loadingmsg.format([tag])+'")',1);
			out='<<loadTiddlers [[tag:%0]] [[%1]] quiet nodirty noreport temporary>\>';
		}
	}
	wikify(out.format([tag,src,target.length?'startwith:'+target:'']),place);
'';}}>>
!end
%/<<tiddler {{var src='GetTheFAQs'; src+(tiddler&&tiddler.title==src?'##info':'##show')}}
	with: [[$1]] [[$2]] [[$3]]>>
/%
|''URL:''|http://gimcrackd.com/etc/src/|
|''Description:''|Gimcrack'd: Code and Other Oddments|
|''Author:''|ChrisKlimas|
%/
{{{
-------------------OO---------
--------------------OO--------
-------------------O----------
------------------------------
--------------------------O---
--------------------------O-O-
--------------------------OO--
------------------------------
------OO----------------------
-----OO-----------------------
-------O----------------------
------------------------------
-------------------------O----
--------------------------OO--
-------------------------OO---
----OOO-----------------------
------O-----------------------
-----O------------------------
------------------------------
-----------O-O----------------
-----------OO-----------------
------------O-----------------
------------------------------
--------------------OOO-------
--------------------O---------
---------------------O--------
------------------------------
-----------O------------------
------------O-----------------
----------OOO-----------------
}}}
{{{
--------------------------------------
------------------------O-------------
----------------------O-O-------------
------------OO------OO------------OO--
-----------O---O----OO------------OO--
OO--------O-----O---OO----------------
OO--------O---O-OO----O-O-------------
----------O-----O-------O-------------
-----------O---O----------------------
------------OO------------------------
--------------------------------------
--------------------------------------
--------------------------------------
--------------------------------------
--------------------------------------
--------------------------------------
--------------------------------------
--------------------------------------
--------------------------------------
--------------------------------------
--------------------------------------
--------------------------------------
-------------------------------------#
-------------------------------------#
-----------------------------------###
}}}
/%
|''URL:''|http://groups.google.com/group/TiddlyWiki/topics|
|''Description:''|TiddlyWiki discussions, help, announcments, etc.|
|''Author:''|[[everyone!|http://groups.google.com/group/TiddlyWiki/topics]]|
%/
This is a good place to ask questions... people are friendly and helpful!
/***
|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
<<<
Welcome
----
Hola
----
Hala
----
Shalom
----
Ni hao
----
Kumusta
----
'Allo
----
G'day
----
Bon giorno
----
Hi
----
Hej
----
Ol&aacute;
----
Salut
----
Hello
----
Oi
----
Hoi
----
Aloha
----
Bonjour
----
Guten Tag
----
Namaste
----
Ciao
/***
|Name|GridPlugin|
|Source|http://www.TiddlyTools.com/#GridPlugin|
|Documentation|http://www.TiddlyTools.com/#GridPluginInfo|
|Version|2.0.7|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1.3|
|Type|plugin|
|Description|Display/edit slices, sections and fields in a grid (table) for a 'birds-eye' view of your document|
!!!!!Documentation
>see [[GridPluginInfo]]
!!!!!Revisions
<<<
2010.03.06 2.0.7 fixed setSection()
2009.09.26 2.0.6 fixed setSlice() for existing slices with empty values
|please see [[GridPluginInfo]] for additional revision details|
2007.01.30 0.0.1 started
<<<
!!!!!Code
***/
//{{{
version.extensions.GridPlugin= {major: 2, minor: 0, revision: 7, date: new Date(2010,3,6)};

config.macros.grid= {
	sizeSliceName: 'TiddlerSize', // fake slice to show # of bytes in tiddler 
	noColsMsg: '@@display:block;border:1px solid;there are no columns to display@@',
	showHeaders:'&#x25BA;&#x25BA;&#x25BA;',
	showHeadersTip:'show column headings',
	hideHeaders:'&#x25C4;&#x25C4;&#x25C4;',
	hideHeadersTip:'hide column headings',
	slicesRE: /(?:^\|\s*[\'\/]*~?(\w+)\:?[\'\/]*\s*\|\s*(.*?)\s*\|$)/gm,
	gridStyles: '.viewer .grid thead td, .grid thead td { background:transparent; }',
	init: function() { setStylesheet(this.gridStyles,'gridStyles'); },
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		var edit=params.contains('edit') && !readOnly; // no editing if readOnly
		var wiki=params.contains('wikify');
		var inline=params.contains('inline');
		if (inline) var heads=true;
		var all=params.contains('all');
		params=paramString.parseParams('name',null,true,false,true); // for NAMED VALUES
		var filter=getParam(params,'filter',''); // core or MatchTagsPlugin tag filter syntax
		if (filter.length && !filter.startsWith('[tag[')) filter='[tag['+filter+']]';
		var tags=this.getList(getParam(params,'tags'),true); // older "match at least one tag" syntax
		if (tags.length) filter='[tag['+tags.join(']][tag[')+']]'+filter;
		var names=this.getList(getParam(params,'columns')); // slices/sections/fields to use as columns
		var clip=getParam(params,'clip',0); // 0=no clipping
		var width=getParam(params,'width','auto');
		var rc=this.getRowsAndCols(filter,names,all);
		if (!rc.cols.length) wikify(this.noColsMsg,place);
		else this.renderTable(place,rc.rows,rc.cols,inline,heads,wiki,edit,clip,width);
	},
	getList: function(t,gettags) {
		var items=(t||'').readBracketedList();
		for (var i=0;i<items.length;i++) { var item=items[i];
			// replace item with list based on item prefix:
			// +name  contents of tiddler (space-separated list)
			// @name  slices/tags,
			// @!name sections
			// @=name fields
			if ('@+'.indexOf(item.substr(0,1))!=-1) {
				var title=item.substr(1); var type=title.substr(0,1);
				if ('=!'.indexOf(type)!=-1) title=title.substr(1);
				if (title=='here')
					title=story.findContainingTiddler(place).getAttribute('tiddler');
				var tid=store.getTiddler(title); if (tid) {
					var list=[];
					if (item.substr(0,1)=='+') list=tid.text.readBracketedList();  // contents
					else if (gettags) list=tid.tags; // tags
					else if (type=='!') list=this.getSections(tid.title);  // sections
					else if (type=='=') list=this.getFields(tid.title); // fields
					else for (var s in this.getSlices(tid.title)) list.push(s);  // slices
					items.splice(i,1); // remove item
					for (var j=0;j<list.length;j++,i++) items.splice(i,0,list[j]); // add list
				}
			}
		}
		return items;
	},
	getRowsAndCols: function(filter,names,all) {
		var rows=[]; var cols=[]; // get rows (tiddlers) and columns (slices)
		var tiddlers=filter&&filter.length?store.filterTiddlers(filter):store.getTiddlers();
		for (i=0; i<tiddlers.length; i++) {
			var slices=this.getSlices(tiddlers[i].title);
			var include=false; for (var s in slices) { cols.pushUnique(s); include=true; }
			if (include||all) rows.push(tiddlers[i].title);
		}
		rows=rows.sort();
		// use specified list instead of collected slice names
		if (names.length) var cols=names;
		return {rows:rows,cols:cols};
	},
	renderTable: function(place,rows,cols,inline,heads,wiki,edit,clip,width) {
		var span=createTiddlyElement(place,'span')
		span.innerHTML=this.generateTable(rows,cols,inline,heads,wiki,edit,clip,width)
		// replace TD content with wikified elements
		var tds=span.getElementsByTagName('td');
		for (var t=0; t<tds.length; t++) {
			if (hasClass(tds[t],'wiki')) {
				var txt=getPlainText(tds[t]);
				if (hasClass(tds[t],'grid_heading')) txt='[['+txt+']]';
				removeChildren(tds[t]);
				wikify(txt,tds[t]);
			}
		}
	},
	generateTable: function(rows,cols,inline,heads,wiki,edit,clip,width) {
		var out= "<html><table class='sortable grid' style='border:0;padding:0;spacing:0;"
			+"border-collapse:collapse;width:"+width+"'>";

		// column headings
		out+=	 "<thead><tr style='border:0;vertical-align:bottom'>"
			+"<td style='text-align:right;border:0'>"
			+"<a href='javascript:;' style='font-size:80%;'"
			+"	title='"+(heads?this.hideHeadersTip:this.showHeadersTip)+"'"
			+"	onclick='return config.macros.grid.toggleHeaders("
			+"		this,event,"+(heads?"true":"false")+")'>"
			+(heads?this.hideHeaders:this.showHeaders)
			+"</a>"
			+"</td>";
		for (var i=0;i<cols.length;i++) {
			out+=	 "<td style='text-align:center;cursor:pointer;"
				+"	border:0;padding-left:2px;padding-right:2px;' "
				+"<span style='display:"+(heads?"block":"none")+"'>"
				+cols[i].replace(/^[=!]/,'')
				+"</span></td>";
		}
		out+="</tr></thead>";

		// row heading format ('fake' tiddler link)
		// %0=cell width, %1=tiddler name, %2='wiki' classname (optional), %3='inline' classname (optional)
		var head="<td style='text-align:right;border:0;padding-right:2px;white-space:nowrap;%0;'>"
			+"<a href='javascript:;' tid=\"%1\" class='grid_heading %2 %3' "
			+"onclick='story.displayTiddler("
			+"	this,this.getAttribute(\"tid\"));return false'>%1</a></td>";

		// row value format
		// %0=bgcolor, %1=cellwidth, %2=cell alignment, %3=tiddler name
		// %4=slice/section/field name, %5=tooltip, %6='wiki' classname (optional),
		// %7='inline' classname (optional), %8=cell content value
		var cell="<td style='background-color:%0;border:1px solid;%1;%2;' tid=\"%3\" ";
		if (edit) cell+="onclick='return config.macros.grid.editInPlace("
			+"this,event,this.getAttribute(\"tid\"),\"%4\");' ";
		cell+="title=\"%5\" class='grid_content %6 %7'>%8</td>";

		// generate rows
		for (var i=0;i<rows.length;i++) {
			var tiddlersrc=rows[i].replace(/"/g,"&#x22;");
			out+="<tr style='border:0;vertical-align:top'>";
			out+=head.format([inline?'width:1%':'',tiddlersrc,wiki?'wiki':'',inline?'inline':'']);
			for (var j=0;j<cols.length;j++) { var c=cols[j];
				var val=this.get(rows[i],c);
				var content="&nbsp;";
				if (val.length && inline) {
					content=val.htmlEncode();
					if (c=='=text'||clip) // truncate
						content=val.substr(0,clip||500)
							+(val.length>(clip||500)?"...":"");
					if (c=='=text') // format tiddler source
						content='<html><code style="line-height:100%">'
							+content.replace(/\n/g,'<br>')
							+'</code></html>';
				}
				var title=this.showName(tiddlersrc,c)+(!inline?'='+val:'');
				out+=cell.format([
					val.length&&!inline?'#999':'transparent', !inline?'width:1em;':'',
					inline&&!isNaN(parseFloat(val))?'text-align:right !important;':'',
					tiddlersrc, c, title, wiki?'wiki':'', inline?'inline':'', content]);
			}
			out+='</tr>';
		}
		out+="</table></html>";
		return out;
	},
	showName: function(tid,name) {
		if (name==this.sizeSliceName) var fmt='%0 - size (in bytes)'; // fake slice
		var fmt=(name.substr(0,1)=='=')?'%1@%0':(name.substr(0,1)=='!')?'%1##%0':'%0::%1';
		return fmt.format([tid,name.replace(/^[=!]/,'')]);
	},
	toggleHeaders: function(here,event,defOpen) {
		if (here.expanded==undefined) here.expanded=defOpen;
		var ex=here.expanded=!here.expanded; 
		here.innerHTML=ex?this.hideHeaders:this.showHeaders;
		here.title=ex?this.hideHeadersTip:this.showHeadersTip;
		var cells=here.parentNode.parentNode.getElementsByTagName('td');
		for (i=1; i<cells.length; i++) cells[i].firstChild.style.display=ex?'inline':'none';
		event.cancelBubble=true;if(event.stopPropagation)event.stopPropagation();return false;
	},
	editInPlace: function(here,event,tid,name) {
		if (here.editing) return false; // already editing, don't re-init
		if (name==this.sizeSliceName) return false; // read-only fake slice
		var v=this.get(tid,name); // current value
		var lines=v.split('\n').length;
		var title=this.showName(tid,name);
		var style=lines>1?'font-size:90%;width:99%;':'font-size:100%;width:95%;line-height:100%;'
		var maxlines=Math.min(lines,config.options['txtMaxEditRows']); // for textarea
		var html=lines>1?'<textarea rows='+maxlines:'<input type="text"';
		html   +=' tid="'+tid.replace(/"/g,'&#x22;')+'"'
			+' name="'+name.replace(/"/g,'&#x22;')+'"'
			+' style="margin:0px;padding:1px 0px 1px 3px;border:0;'+style+'"'
			+' title="'+title+' (ENTER=submit, ESC=cancel)"'
			+' onblur="config.macros.grid.blur(this,event)"'
			+' onkeydown="config.macros.grid.keydown(this,event)"';
		html+=lines>1?'></textarea>':'>';
		here.editing=true;
		here.setAttribute('savedWidth',here.style.width);
		here.setAttribute('savedPadding',here.style.padding);
		here.setAttribute('savedColor',here.style.backgroundColor);
		if (!hasClass(here,'inline')) here.style.width='99%';
		here.style.padding='0px'; 
		here.style.backgroundColor='#fff';
		here.innerHTML=html;
		var ta=here.firstChild; ta.value=v; ta.focus(); ta.select();
		event.cancelBubble=true;if(event.stopPropagation)event.stopPropagation();return false;
	},
	keydown: function(here,ev) { ev=ev||window.event;
		var tid=here.getAttribute('tid');
		var name=here.getAttribute('name');
		if (ev.keyCode==27) {
			var currval=this.get(tid,name);
			if (here.value==currval) { here.blur(); return false; }
			here.asking=true; // prevents blur handling during confirm()
			var discard=confirm('OK to discard changes to '+this.showName(tid,name)+'?');
			here.asking=false;
			if (discard) { here.value=currval; here.blur(); }
			return false;
		}
		else if (ev.keyCode==13 && !ev.ctrlKey) {
			this.set(tid,name,here.value);
			here.blur();
			return false;
		}
	},
	blur: function(here,ev) { ev=ev||window.event;
		if (here.asking) return false;
		var tid=here.getAttribute('tid');
		var name=here.getAttribute('name');
		var currval=this.get(tid,name);
		var msg=this.showName(tid,name)+' has changed... OK to save changes?';
		if (here.value!=currval && confirm(msg))
			{ this.set(tid,name,here.value); currval=this.get(tid,name); }
		var target=here.parentNode;
		target.editing=false;
		target.style.backgroundColor=target.getAttribute('savedColor');
		target.style.padding=target.getAttribute('savedPadding');
		target.style.width=target.getAttribute('savedWidth');
		if (name=='=text') currval='<html><code>'+currval.substr(0,500).replace(/\\n/g,'<br>')+'</code></html>';
		if (hasClass(target,'wiki')) { removeChildren(target); wikify(currval,target); }
		else target.innerHTML=hasClass(target,'inline')?currval:'&nbsp;';
	},
	get: function(tid,name) {
		if (name.substr(0,1)=='=') var v=store.getValue(tid,name.substr(1)); // field
		else if (name.substr(0,1)=='!') var v=store.getTiddlerText(tid+'##'+name.substr(1));  // section
		else if (name==this.sizeSliceName) var v=store.getTiddlerText(tid,'').length.toString();  // fake slice
		else var v=store.getTiddlerSlice(tid,name); // real slice
		return v||'';
	},
	set: function(tid,name,val) {
		if (val==this.get(tid,name)) return false; // unchanged... do nothing
		if (name.substr(0,1)=='=') // field
			{  name=name.substr(1); store.setValue(tid,name,val); }
		else if (name.substr(0,1)=='!') // section
			{  name=name.substr(1); this.setSection(tid,name,val); }
		else // slice
			{ this.setSlice(tid,name,val); }
		displayMessage(this.showName(tid,name)+' has been updated');
		return false;
	},
	setSection: function(tid,name,newval) {
		var t=store.getTiddler(tid); if (!t) { var t=new Tiddler(); t.text=''; }
		var oldval=this.get(tid,'!'+name).escapeRegExp();
		var pattern=new RegExp('(.*!{1,6}'+name+'\\n)'+oldval+'((?:\\n!{1,6}|$).*)');
		var newText=t.text.replace(pattern,'$1'+newval+'$2');
		var who=config.options.txtUserName; var when=new Date();
		if (config.options.chkForceMinorUpdate) { var who=t.modifier; var when=t.modified; }
		store.saveTiddler(tid,tid,newText,who,when,t.tags,t.fields);
		story.refreshTiddler(tid,null,true);
	},
	setSlice: function(tid,name,newval) {
		var t=store.getTiddler(tid); if (!t) { var t=new Tiddler(); t.text=''; }
		var oldval=this.get(tid,name)||'';
		var pattern="((?:^|\\n)\\|\\s*[\\'\\/]*~?(?:"
			+name.escapeRegExp()
			+")\\:?[\\'\\/]*\\s*\\|\\s*)(?:"
			+oldval.escapeRegExp()
			+")(\\s*\\|(?:\\n|$))";
		var match=t.text.match(new RegExp(pattern));
		if (match) {
			var pos=t.text.indexOf(match[0]);
			var newText=t.text.substr(0,pos)
				+match[1]+newval+match[2]
				+t.text.substr(pos+match[0].length);
		} else { // create new slice at start of tiddler or after last existing slice (if any)
			var match=t.text.match(this.slicesRE); if (match) var last=match[match.length-1];
			var pos=last?t.text.indexOf(last)+last.length+1:0; 
			var newText=t.text.substr(0,pos)+'|'+name+'|'+newval+'|\n'+t.text.substr(pos);
		}
		var who=config.options.txtUserName; var when=new Date();
		if (config.options.chkForceMinorUpdate) { var who=t.modifier; var when=t.modified; }
		store.saveTiddler(tid,tid,newText,who,when,t.tags,t.fields);
		story.refreshTiddler(tid,null,true);
	},
	getSlices: function(tid) {
		var slices = {};
		var text = store.getTiddlerText(tid,'');
		slices[this.sizeSliceName]=text.length.toString();  // fake slice
		this.slicesRE.lastIndex = 0;
		do {
			var m = this.slicesRE.exec(text);
			if (m) { if (m[1]) slices[m[1]] = m[2]; else slices[m[3]] = m[4]; }
		} while(m);
		return slices;
	},
	getSections: function(tid) {
		var s=[];
		var t=store.getTiddlerText(tid,'');
		var p=/(?:^|\n)!{1,6}([^\n]*)\n/gm;
		do { var m=p.exec(t); if (m) { s.push(m[1]); } } while(m);
		return s;
	},
	getFields: function(tid) {
		var t=store.getTiddler(tid); if (!t) return [];
		var fields=['=created','=modified','=modifier','=text','=tags'];
		for (var f in t.fields) fields.push('='+f);
		return fields;
	}
};
//}}}
/***
|Name|GridPluginInfo|
|Source|http://www.TiddlyTools.com/#GridPlugin|
|Documentation|http://www.TiddlyTools.com/#GridPluginInfo|
|Version|2.0.7|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1.3|
|Type|documentation|
|Description|documentation for GridPlugin|
!!!!!Usage
<<<
The {{{<<grid>>}}} macro generates a table, where ''rows are tiddlers, columns are any combination of slices, sections or field names'', and grid cells display individual values (or colored boxes with mouseover 'tooltips' to view values).
*Use tag filtering to select and display specific subsets of tiddlers.
*Grid column headings can be shown/hidden by clicking the {{{>>>}}} symbol in the upper-left corner
*Optionally, clicking on a cell allows you to edit the value in that cell.  Pressing enter (or moving away from the input field) saves the changed value.  Pressing escape cancels the changes (after confirming)
{{{
<<grid	columns:[[name name name...]]
	tags:[[tag tag...]]
	filter:...
	clip:...
	inline wikify edit all>>
}}}
//all parameters are optional//
*''columns:...'' (list) default=use all slices defined in the document<br>display columns using the specified names, which refer to any combination of slices, sections and fields.
**If a column name begins with '=' (equal sign), then it is a tiddler field reference.
**If a column name begins with '!' (exclamation), then it is a tiddler section reference.
**Column names without either prefix are tiddler slice references.
**''{{{+TiddlerName}}}'' uses a space-separated list of column names stored in another tiddler.
**''{{{@TiddlerName}}}'' uses the slices from a given tiddler as column names.
**''{{{@!TiddlerName}}}'' uses the sections from a given tiddler.
**''{{{@=TiddlerName}}}'' uses the fields from a given tiddler.
**A special read-only 'fake' slice name, ''~TiddlerSize'', can be used to automatically compute and show the tiddler's size in bytes.
*''tags:...'' (list) default=show all tiddlers<br>display tiddlers that match at least ONE of the specified tags.
**''{{{+TiddlerName}}}'' uses a space-separated list of tags stored in another tiddler.
**''{{{@TiddlerName}}}'' uses the tags assigned to the indicated tiddler.
*''filter:...'' (filter syntax) default=none<br>enhanced tiddler selection by tags, using core filter syntax (e.g., {{{"[tag[tag1]][tag[tag2]]"}}}) or MatchTagsPlugin's compound //Boolean tag expressions// (e.g., {{{"tag1 or (tag2 and tag3) and not tag4)"}}})
*''clip:...'' (number) default=no clip length limit<br>maximum # of characters to show in a grid cell when using 'inline' keyword.  Text values are truncated with '...'
*''inline'' (keyword)<br>displays column values directly in grid cells.  Default=use a colored block if a value is defined, with mouseover 'tooltip' to show the actual value
*''wikify'' (keyword)<br>parses and formats wiki-syntax contained in values.  Default=show values ''as-is'', without wiki formatting
*''edit'' (keyword)<br>enables click-to-edit to change values.  Default=read-only display of values.
*''all'' (keyword)<br>displays a row for each tiddler, even tiddlers that have NO non-blank values. Default=show only tiddlers that have at least one defined value.
Note: this plugin uses a modified version of slices pattern:
{{{
slicesRE = /(?:^\|[\'\/]*~?(\w+)\:?[\'\/]*\|\s*(.*?)\s*\|$)/gm;
}}}
* eliminates TONS of spurious slices caused by over-eager 'description' format pattern matches
* enforces beginning-of-line and end-of-line sequences.  (Allows slice values to contain |, such as in pretty links)
<<<
!!!!!Examples
<<<
*{{block{
View 'mouseover' summary of slices
for tiddlers matching at least one tag from a list of tags
using slices from this tiddler as columns
<<<
{{{
<<grid tags:[[systemConfig pluginInfo script]] columns:@GridPluginInfo>>
}}}
+++[show results...]...
<<grid tags:[[systemConfig pluginInfo script]] columns:@GridPluginInfo>>
===
<<<
}}}
*{{block{
Edit slices (Description, Version), fields (changecount) and sections (Revisions)
for tiddlers using TW core filter syntax:
<<<
{{{
<<grid filter:[tag[systemConfig]][tag[pluginInfo]][tag[script]]
	columns:[[Description Version =changecount !Revisions]] inline wikify edit>>
}}}
+++[show results...]...
<<grid filter:[tag[systemConfig]][tag[pluginInfo]][tag[script]]
	columns:[[Description Version =changecount !Revisions]] inline wikify edit>>
===
<<<
}}}
*{{block{
Edit slices (Description, Version), fields (changecount) and sections (Revisions)
for tiddlers using enhanced boolean filter syntax (requires [[MatchTagsPlugin]])
<<<
{{{
<<grid filter:[[systemConfig or pluginInfo or script]]
	columns:[[Description Version =changecount !Revisions]] inline wikify edit>>
}}}
+++[show results...]...
<<grid filter:[[systemConfig or pluginInfo or script]]
	columns:[[Description Version =changecount !Revisions]] inline wikify edit>>
===
<<<
}}}
<<<
!!!!!Revisions
<<<
2010.03.06 2.0.7 fixed setSection()
2009.09.26 2.0.6 fixed setSlice() for existing slices with empty values
2009.09.25 2.0.5 fixed cell redraw after edit-in-place
2009.09.25 2.0.4 fixed ({{{@!name}}} ) and {{{@=name}}} handling
2009.09.24 2.0.3 added handling for getting columns from tiddler sections ({{{@!name}}} ) or fields {{{@=name}}}
2009.09.23 2.0.2 fixed handling for {{{@TiddlerName/+TiddlerName}}}
2009.09.21 2.0.1 split keydown() and blur() functions from editInPlace() and added confirmation for escape key (discard changes)
2009.09.20 2.0.0 Complete re-write.  Renamed [[GridPlugin]].  View and/or edit any tiddler section, slice or field.  Renamed 'slices:...' param to 'columns:...'
2009.09.17 1.1.1 added textarea handling for multi-line fields (e.g., 'text')
2009.09.17 1.1.0 added '=fieldname' syntax for 'field grid'
2008.08.15 1.0.3 add brackets around row headings when wikifying so that non-wikiword tiddler titles are linked
2008.08.13 1.0.2 wikify row headings (in addition to slice value cells) whenever 'wikify' param is used
2008.05.01 1.0.1 in editSlice(), corrected fixup for titles containing double-quotes
2007.09.18 1.0.0 added 'wikify' param and handling to format wiki-syntax contained in slice values
2008.05.01 1.0.1 in editSlice(), corrected fixup for titles containing double-quotes
2007.09.18 1.0.0 added 'wikify' param and handling to format wiki-syntax contained in slice values
2007.08.02 0.9.8 when generating HTML, replace double-quotes in tiddler titles with {{{&#x22;}}} to avoid ambiguity with quotes used as HTML attribute syntax delimiters.
2007.07.22 0.9.7 removed hard-coded 99% 'width bias' and wordwrap from Description cells, default to autosize (equal size for all columns).  Added width:xxxx param to easily stretch table to fit containing space
2007.06.08 0.9.6 fixed generated code for row headings and edit_slice() handlers, so titles with single-quotes will work
2007.04.24 0.9.5 added 'fake' slicename: 'TiddlerSize', to display # of bytes in tiddler as a grid column.
2007.04.13 0.9.4 honor 'excludeLists' tag so that 'hidden' tiddlers aren't displayed in the grid
2007.04.08 0.9.3 fixed cell bgcolor (non-inline grid 'blocks') after edit-in-place adds/clears a slice value
2007.04.07 0.9.2 support edit in place for non-inline grids (color 'blocks').  Also create new slices in tiddlers if slice not already present
2007.04.07 0.9.1 use locally-defined slicesRE (and getSlice() method) instead of re-defining core slicesRE.  Avoids breaking use of shadow ColorPalette slices.  
2007.04.05 0.9.0 Added functioning 'set slice' handler and 'edit-in-place' feature.  Eliminated mouseover popups (use tooltips instead).  Added ''tags:'', ''slices:'' and ''edit'' params.  Lots of code cleanup.
2007.04.04 0.8.1 in info() and popup() functions, instead of creating popup display, use element tooltip to show mouseover details.
2007.03.25 0.8.0 change to BETA status and added support for 'tags:tag tag tag tag' filtering param
2007.02.03 0.0.2 change display of slices from 'tiddler[slidename]' to 'tiddler:slicename' to match TW slice syntax
2007.01.30 0.0.1 started (adapted from TagGridPlugin)
<<<
/***
|Name|HTMLFormattingPlugin|
|Source|http://www.TiddlyTools.com/#HTMLFormattingPlugin|
|Documentation|http://www.TiddlyTools.com/#HTMLFormattingPluginInfo|
|Version|2.4.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|embed wiki syntax formatting inside of HTML content|
The ~HTMLFormatting plugin allows you to ''mix wiki-style formatting syntax within HTML formatted content'' by extending the action of the standard TiddlyWiki formatting handler.
!!!!!Documentation
>see [[HTMLFormattingPluginInfo]]
!!!!!Configuration
<<<
Use {{{<hide linebreaks>}}} within HTML content to wiki-style rendering of line breaks.  To //always// omit all line breaks from the rendered output, you can set this option:
><<option chkHTMLHideLinebreaks>> ignore all line breaks
which can also be 'hard coded' into your document by adding the following to a tiddler, tagged with <<tag systemConfig>>
>{{{config.options.chkHTMLHideLinebreaks=true;}}}
<<<
!!!!!Revisions
<<<
2010.05.07 2.4.1 added chkHTMLHideLinebreaks option
| see [[HTMLFormattingPluginInfo]] for additional revision details |
2005.06.26 1.0.0 Initial Release (as code adaptation - pre-dates TiddlyWiki plugin architecture!!)
<<<
!!!!!Code
***/
//{{{
version.extensions.HTMLFormattingPlugin= {major: 2, minor: 4, revision: 1, date: new Date(2010,5,7)};

// find the formatter for HTML and replace the handler
initHTMLFormatter();
function initHTMLFormatter()
{
	for (var i=0; i<config.formatters.length && config.formatters[i].name!="html"; i++);
	if (i<config.formatters.length)	config.formatters[i].handler=function(w) {
		if (!this.lookaheadRegExp)  // fixup for TW2.0.x
			this.lookaheadRegExp = new RegExp(this.lookahead,"mg");
		this.lookaheadRegExp.lastIndex = w.matchStart;
		var lookaheadMatch = this.lookaheadRegExp.exec(w.source)
		if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
			var html=lookaheadMatch[1];
			// if <nowiki> is present, just let browser handle it!
			if (html.indexOf('<nowiki>')!=-1)
				createTiddlyElement(w.output,"span").innerHTML=html;
			else {
				// if <hide linebreaks> is present, or chkHTMLHideLinebreaks is set
				// suppress wiki-style literal handling of newlines
				if (config.options.chkHTMLHideLinebreaks||(html.indexOf('<hide linebreaks>')!=-1))
					html=html.replace(/\n/g,' ');
				// remove all \r's added by IE textarea and mask newlines and macro brackets
				html=html.replace(/\r/g,'').replace(/\n/g,'\\n').replace(/<</g,'%%(').replace(/>>/g,')%%');
				// create span, let browser parse HTML
				var e=createTiddlyElement(w.output,"span"); e.innerHTML=html;
				// then re-render text nodes as wiki-formatted content
				wikifyTextNodes(e,w);
			}
			w.nextMatch = this.lookaheadRegExp.lastIndex; // continue parsing
		}
	}
}

// wikify #text nodes that remain after HTML content is processed (pre-order recursion)
function wikifyTextNodes(theNode,w)
{
	function unmask(s) { return s.replace(/\%%\(/g,'<<').replace(/\)\%%/g,'>>').replace(/\\n/g,'\n'); }
	switch (theNode.nodeName.toLowerCase()) {
		case 'style': case 'option': case 'select':
			theNode.innerHTML=unmask(theNode.innerHTML);
			break;
		case 'textarea':
			theNode.value=unmask(theNode.value);
			break;
		case '#text':
			var txt=unmask(theNode.nodeValue);
			var newNode=createTiddlyElement(null,"span");
			theNode.parentNode.replaceChild(newNode,theNode);
			wikify(txt,newNode,highlightHack,w.tiddler);
			break;
		default:
			for (var i=0;i<theNode.childNodes.length;i++)
				wikifyTextNodes(theNode.childNodes.item(i),w); // recursion
			break;
	}
}
//}}}
|Name|HTMLFormattingPluginInfo|
|Source|http://www.TiddlyTools.com/#HTMLFormattingPlugin|
|Documentation|http://www.TiddlyTools.com/#HTMLFormattingPluginInfo|
|Version|2.4.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|documentation|
|Description|documentation for HTMLFormattingPlugin|
The ~HTMLFormatting plugin allows you to freely ''mix wiki-style formatting syntax within HTML formatted content'' by extending the action of the standard TiddlyWiki formatting handler.
!!!!!Usage
<<<
The shorthand Wiki-style formatting syntax of ~TiddlyWiki is very convenient and enables most content to be reasonably well presented. However, there are times when tried-and-true HTML formatting syntax allows more more precise control of the content display.

When a tiddler is about to be displayed, ~TiddlyWiki looks for tiddler content contained within {{{<html>}}} and {{{</html>}}} markers.  When present, the TiddlyWiki core simply passes this content directly to the browser's internal "rendering engine" to process as ~HTML-formatted content.  However, TiddlyWiki does not also process the HTML source content for any embedded wiki-formatting syntax it may contain.  This means that while you can use HTML formatted content, you cannot mix wiki-formatted content within the HTML formatting.

This plugin extends the TiddlyWiki core processing so that, after the HTML formatting has been processed, all the pieces of text occuring within the HTML block are then processed one piece at a time, so that normal wiki-style formatting can be applied to the individual text pieces.

Note: To bypass this extended processing for a specific section of HTML content, embed ''{{{<nowiki>}}}'' //anywhere// inside the {{{<html>...</html>}}} delimiters, and wiki formatting will not be applied to that content.
<<<
!!!!!Line breaks
<<<
One major difference between Wiki formatting and HTML formatting is how "line breaks" are processed. Wiki formatting treats all line breaks as literal content to be displayed //as-is//. However, because HTML normally ignores line breaks and actually processes them as simple "word separators" instead, many people who write HTML include extra line breaks in their documents, just to make the "source code" easier to read.

Even though you can use HTML tags within your tiddler content, the default treatment for line breaks still follows the Wiki-style rule (i.e., all new lines are displayed as-is). When adding HTML content to a tiddler (especially if you cut-and-paste it from another web page), you should take care to avoid adding extra line breaks to the text.

If removing all the extra line breaks from your HTML content would be a big hassle, you can quickly //override the default Wiki-style line break rule// so that the line breaks use the standard HTML rules, by placing ''{{{<hide linebreaks>}}}'' //anywhere// within the HTML content.  This automatically converts all line breaks to spaces before rendering the content, so that the literal line breaks will be processed as simple word-breaks instead.

Alternatively, if you //always// want to omit all line breaks from the rendered output, you can set this option:
><<option chkHTMLHideLinebreaks>> ignore all line breaks
which can also be 'hard coded' into your document by adding the following to a tiddler, tagged with <<tag systemConfig>>
>{{{config.options.chkHTMLHideLinebreaks=true;}}}

Note: this does //not// alter the actual tiddler content that is stored in the document, just the manner in which it is displayed. Any line breaks contained in the tiddler will still be there when you edit its content. Also, to include a literal line break when the ''<{{{hide linebreaks}}}>'' tag is present, you will need to use a ''<{{{br}}}>'' or ''<{{{p}}}>'' HTML tag instead of simply typing a line break.
<<<
!!!!!How it works
<<<
The TW core support for HTML does not let you put ANY wiki-style syntax (including TW macros) *inside* the {{{<html>...</html>}}} block.  Everything between {{{<html>}}} and {{{</html>}}} is handed to the browser for processing and that is it.

However, not all wiki syntax can be safely passed through the browser's parser. Specifically, any TW macros inside the HTML will get 'eaten' by the browser since the macro brackets, {{{<<...>>}}} use the "<" and ">" that normally delimit the HTML/XML syntax recognized by the browser's parser.

Similarly, you can't use InlineJavascript within the HTML because the {{{<script>...</script>}}} syntax will also be consumed by the browser and there will be nothing left to process afterward.  Note: unfortunately, even though the browser removes the {{{<script>...</script>}}} sequence, it doesn't actually execute the embedded javascript code that it removes, so any scripts contained inside of <html> blocks in TW are currently being ignored. :-(

As a work-around to allow TW *macros* (but not inline scripts) to exist inside of <html> formatted blocks of content, the plugin first converts the {{{<<}}} and {{{>>}}} into "%%(" and ")%%", making them "indigestible" so they can pass unchanged through the belly of the beast (the browser's HTML parser).

After the browser has done its job, the wiki syntax sequences (including the "undigested" macros) are contained in #text nodes in the browser-generated DOM elements.  The plugin then recursively locates and processes each #text node, converts the %%( and )%% back into {{{<<}}} and {{{>>}}}, passes the result to wikify() for further rendering of the wiki-formatted syntax into a containing SPAN that replaces the previous #text node.  At the end of this process, none of the encoded %%( and )%% sequences remain in the rendered tiddler output.
<<<
!!!!!Revisions
<<<
2010.05.07 2.4.1 added chkHTMLHideLinebreaks option
2009.01.05 2.4.0 in wikifyTextNodes(), pass w.highlightRegExp and w.tiddler to wikify() so that search term highlighting and tiddler-relative macro processing will work
2008.10.02 2.3.0 added use of {{{<nowiki>}}} marker to bypass all wikification inside a specific HTML block
2008.09.19 2.2.0 in wikifyTextNodes(), don't wikify the contents of STYLE nodes (thanks to MorrisGray for bug report)
2008.04.26 [*.*.*] plugin size reduction: more documentation moved to HTMLFormattingInfo
2008.01.08 [*.*.*] plugin size reduction: documentation moved to HTMLFormattingInfo
2007.12.04 [*.*.*] update for TW2.3.0: replaced deprecated core functions, regexps, and macros
2007.06.14 2.1.5 in formatter, removed call to e.normalize().  Creates an INFINITE RECURSION error in Safari!!!!
2006.09.10 2.1.4 update formatter for 2.1 compatibility (use this.lookaheadRegExp instead of temp variable)
2006.05.28 2.1.3 in wikifyTextNodes(), decode the *value* of TEXTAREA nodes, but don't wikify() its children.  (thanks to "ayj" for bug report)
2006.02.19 2.1.2 in wikifyTextNodes(), put SPAN element into tiddler DOM (replacing text node), BEFORE wikifying the text content.  This ensures that the 'place' pasced to any macros is correctly defined when the macro is evaluated, so that calls to story.findContainingTiddler(place) will work as expected. (Thanks for bug report from GeoffSlocock)
2006.02.05 2.1.1 wrapped wikifier hijack in init function to eliminate globals and avoid FireFox 1.5.0.1 crash bug when referencing globals
2005.12.01 2.1.0 don't wikify #TEXT nodes inside SELECT and TEXTAREA elements
2005.11.06 2.0.1 code cleanup
2005.10.31 2.0.  replaced hijack wikify() with hijack config.formatters["html"] and simplified recursive WikifyTextNodes() code
2005.10.09 1.0.2 combined documentation and code into a single tiddleb
2005.08.05 1.0.1 moved HTML and CSS definitions into plugin code instead of using separate tiddlers
2005.07.26 1.0.1 Re-released as a plugin. Added <{{{html}}}>...</{{{nohtml}}}> and <{{{hide newlines}}}> handling
2005.06.26 1.0.0 Initial Release (as code adaptation - pre-dates TiddlyWiki plugin architecture!!)
<<<
/%
!info
|Name|HideTiddlerBackground|
|Source|http://www.TiddlyTools.com/#HideTiddlerBackground|
|Version|2.0.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Description|hide a tiddler's background and border (if any)|
Usage:
<<<
{{{
<<tiddler HideTiddlerBackground>>
<<tiddler HideTiddlerBackground with: TiddlerTitle>>
}}}
<<<
!end
!show
<<tiddler {{
	var title="$1";
	if (title=='$'+'1')
		title=(story.findContainingTiddler(place)||place).getAttribute('tiddler')||'';
	var t=story.getTiddler(title); if (t) {
		var e=t.getElementsByTagName('*');
		for (var i=0; i<e.length; i++) if (hasClass(e[i],'viewer')) {
			var s=e[i].style;
			s.backgroundImage='none';
			s.backgroundColor='transparent';
			s.border=s.margin=s.padding='0px';
			break;
		}
	}
'';}}>>
!end
%/<<tiddler {{
	var src='HideTiddlerBackground';
	src+(tiddler&&tiddler.title==src?'##info':'##show');}}
with: [[$1]]>>
/%
!info
|Name|HideTiddlerSubtitle|
|Source|http://www.TiddlyTools.com/#HideTiddlerSubtitle|
|Version|2.0.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Description|hide a tiddler's subtitle (date and author)|
Usage:
<<<
{{{
<<tiddler HideTiddlerSubtitle>>
<<tiddler HideTiddlerSubtitle with: TiddlerTitle>>
}}}
<<<
!end
!show
<<tiddler {{
	var title="$1";
	if (title=='$'+'1')
		title=(story.findContainingTiddler(place)||place).getAttribute('tiddler')||'';
	var t=story.getTiddler(title); if (t) {
		var e=t.getElementsByTagName('*');
		for (var i=0; i<e.length; i++)
			if (hasClass(e[i],'subtitle')) e[i].style.display='none';
	}
'';}}>>
!end
%/<<tiddler {{
	var src='HideTiddlerSubtitle';
	src+(tiddler&&tiddler.title==src?'##info':'##show');}}
with: [[$1]]>>
/%
!info
|Name|HideTiddlerTags|
|Source|http://www.TiddlyTools.com/#HideTiddlerTags|
|Version|2.0.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Description|hide a tiddler's 'tagged' and 'tagging' displays (if any)|
Usage:
<<<
{{{
<<tiddler HideTiddlerTags>>
<<tiddler HideTiddlerTags with: TiddlerTitle>>
}}}
<<<
!end
!show
<<tiddler {{
	var title="$1";
	if (title=='$'+'1') {
		var here=story.findContainingTiddler(place);
		if (here) title=here.getAttribute('tiddler');
	}
	var t=story.getTiddler(title); if (t) {
		var e=t.getElementsByTagName('*');
		for (var i=0; i<e.length; i++)
			if (hasClass(e[i],'tagging')||hasClass(e[i],'tagged'))
				e[i].style.display='none';
	}
'';}}>>
!end
%/<<tiddler {{
	var src='HideTiddlerTags';
	src+(tiddler&&tiddler.title==src?'##info':'##show');}}
with: [[$1]]>>
/%
!info
|Name|HideTiddlerTitle|
|Source|http://www.TiddlyTools.com/#HideTiddlerTitle|
|Version|2.0.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Description|hide a tiddler's title and subtitle (date and author)|
Usage:
<<<
{{{
<<tiddler HideTiddlerTitle>>
<<tiddler HideTiddlerTitle with: TiddlerTitle>>
}}}
<<<
!end
!show
<<tiddler {{
	var title="$1";
	if (title=='$'+'1')
		title=(story.findContainingTiddler(place)||place).getAttribute('tiddler')||'';
	var t=story.getTiddler(title); if (t) {
		var e=t.getElementsByTagName('*');
		for (var i=0; i<e.length; i++)
			if (hasClass(e[i],'title')||hasClass(e[i],'subtitle')) e[i].style.display='none';
	}
'';}}>>
!end
%/<<tiddler {{
	var src='HideTiddlerTitle';
	src+(tiddler&&tiddler.title==src?'##info':'##show');}}
with: [[$1]]>>
/%
!info
|Name|HideTiddlerToolbar|
|Source|http://www.TiddlyTools.com/#HideTiddlerToolbar|
|Version|2.0.2|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Description|hide a tiddler's toolbar (menu commands)|
Usage:
<<<
{{{
<<tiddler HideTiddlerToolbar>>
<<tiddler HideTiddlerToolbar with: TiddlerTitle>>
}}}
<<<
!end

!show
<<tiddler {{
	var title="$1";
	if (title=='$'+'1')
		title=(story.findContainingTiddler(place)||place).getAttribute('tiddler')||'';
	var t=story.getTiddler(title); if (t) {
		var e=t.getElementsByTagName('*');
		for (var i=0; i<e.length; i++)
			if (hasClass(e[i],'toolbar')) e[i].style.display='none';
	}
'';}}>>
!end
%/<<tiddler {{
	var src='HideTiddlerToolbar';
	src+(tiddler&&tiddler.title==src?'##info':'##show');
}} with [[$1]]>>
/***
|Name|HideTiddlersPlugin|
|Source|http://www.TiddlyTools.com/#HideTiddlersPlugin|
|Documentation|http://www.TiddlyTools.com/#HideTiddlersPlugin|
|Version|1.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|hide/show tiddlers instead of closing/re-opening them|
|Status|ALPHA EXPERIMENTAL - use with caution|
!!!!!Documentation
<<<
This plugin hijacks the core's displayTiddler() and closeTiddler() functions so that closing a tiddler //hides// it rather than removing it from the story column.  When the tiddler is re-opened, it is made visible again without needing to be re-rendered, which can significantly reduce the processing required by tiddlers that generate their content through use of complex macros or scripts.

Notes:
*hidden tiddlers are still re-rendered as needed when underlying information is changed or other page-wide refresh events occur, so that they will still be up-to-date if re-displayed.  This can, in some cases, trigger side-effect actions associated with those tiddlers that would normally not occur had they actually been closed, rather than merely hidden from view
*Using <<closeAll>> (or invoking the core {{{restart()}}} function) will always //close// the tiddlers rather than hiding them, regardless of the current plugin settings or tiddler tags
<<<
!!!!!Configuration
<<<
hide tiddlers instead of closing them:
<<option chkNoClose>>tiddlers tagged with <<option txtNoCloseTag>>
<<option chkNoCloseAll>>all tiddlers, regardless of tags
<<<
!!!!!Revisions
<<<
2009.10.04 [1.0.0] initial release.  Much thanks to Shviller for original concept.
<<<
!!!!!Code
***/
//{{{
version.extensions.HideTiddlersPlugin= {major: 1, minor: 0, revision: 0, date: new Date(2009,10,4)};

var co=config.options; //abbrev
if (co.chkNoClose===undefined)	  co.chkNoClose=true;
if (co.txtNoCloseTag===undefined) co.txtNoCloseTag='noClose';

if (Story.prototype.displayTiddler_save===undefined)
	Story.prototype.displayTiddler_save=Story.prototype.displayTiddler;
Story.prototype.displayTiddler=function(place,title) {
	var here=story.getTiddler(title);
	if (here) here.style.display='block';
	this.displayTiddler_save.apply(this,arguments);
}

if (Story.prototype.closeTiddler_save===undefined)
	Story.prototype.closeTiddler_save=Story.prototype.closeTiddler;
Story.prototype.closeTiddler=function(title) {
	var co=config.options; //abbrev
	var t=store.getTiddler(title);
	if (co.chkNoCloseAll || co.chkNoClose&&t&&t.isTagged(co.txtNoCloseTag)) {
		var here=story.getTiddler(title);
		if (here) here.style.display='none';
		forceReflow();
	} else this.closeTiddler_save.apply(this,arguments);
}

if (Story.prototype.closeAllTiddlers_save===undefined)
	Story.prototype.closeAllTiddlers_save=Story.prototype.closeAllTiddlers;
Story.prototype.closeAllTiddlers=function(title) {
	var co=config.options; //abbrev
	var t=co.chkNoClose;
	co.chkNoClose=false;
	this.closeAllTiddlers_save.apply(this,arguments);
	co.chkNoClose=t;
}
//}}}
<script>setTimeout("story.closeAllTiddlers('HolidayGreetings')",1);</script>/%
%/<<tiddler MoveTiddlerToTop>>/%
%/<<tiddler HideTiddlerTags>>/%
%/<<tiddler HideTiddlerBackground>>/%
%/<<tiddler HideTiddlerSubtitle>>/%
%/{{selected{{{toolbar{
	{{fine{<<tiddler SlideshowTimer with: Welcome 70>>&nbsp;}}}/%
	%/<<tiddler RefreshTiddler with: "replay">>/%
	%/<script label="stop">
		story.closeTiddler("HolidayGreetings");
		story.displayTiddler(null,"Welcome"); story.refreshTiddler("Welcome",null,true);
		return false;
	</script>/%
%/}}}}}}/%
%/<html><hide linebreaks><embed src='midi/jingle_bells_jazz.mid'
	width=100 height=16 autostart='true' autoplay='true'>
</embed></html>
@@position:absolute;width:50%;margin-left:20%;margin-top:-50px;white-space:nowrap;opacity:0.7;filter:'alpha(opacity:70)';///%

MULTI-HOLIDAY GREETINGS [0:02-0:35.5]
%/<<animate div "{{left   red{Merry Christmas}}}"	fontSize %0% 0 300 2000  1500 16 1500>>/%
%/<<animate div "{{right  blue{Happy Hanukkah}}}"	fontSize %0% 0 300 4000  1500 16 1500>>/%
%/<<animate div "{{center green{Eid Mubarak}}}"		fontSize %0% 0 300 6000  1500 16 1500>>/%
%/<<animate div "{{right  red{Happy Kwanzaa}}}"		fontSize %0% 0 300 8000  1500 16 1500>>/%
%/<<animate div "{{center blue{Ponggalo Ponggal!}}}"	fontSize %0% 0 300 10000 1500 16 1500>>/%
%/<<animate div "{{left   green{Happy Solstice}}}"	fontSize %0% 0 300 12000 1500 16 1500>>/%
%/<<animate div "{{center red{Happy Lohri}}}"		fontSize %0% 0 300 14000 1500 16 1500>>/%
%/<<animate div "{{right  blue{Festivus for the Rest Of Us!}}}" fontSize %0% 0 200 16000 1500 16 1500>>/%
%/<<animate div "{{left   green{Happy Bodhi Day}}}"	fontSize %0% 0 300 18000 1500 16 1500>>/%
%/<<animate div "{{right  red{Merry Xmas}}}"		fontSize %0% 0 300 20000 1500 16 1500>>/%
%/<<animate div "{{center blue{and a Happy New Year!}}}" fontSize %0% 0 200 22000 1500 16 1500>>/%
%/<<animate = left %0% 20 -20 0 2000 35>><<animate = +top %0px 0 100 0 1000 40>>/%
%///@@/%

BANNER MESSAGE "ROLLTEXT" [0:05-0:40], SCROLL OUT/HIDE [0:45-0:60]
%/{{block{
----
{{medium center{@@font-family:Trebuchet MS;//[>img[images/eric3.gif]]<script>
	// see [[RollText]] script for general purpose utility...
	var txt="Whatever you may be celebrating this time of year, be it the birth of a savior, or the strength of your forebears, the turning of the seasons, or nothing in particular... May the closing of your year be filled with the warmth of those around you and the joy of the season; may the year ahead be full of good fortune, hope, and wonder. May we all come together in the true spirit of the season to forget our differences and be grateful for everyone around us, give to those less fortunate, and celebrate the many things that all of us have worth celebrating in our lives.<br><br> {{floatleft{&nbsp;{{fine{@@color:#999;//text&nbsp;by&nbsp;Alex&nbsp;Stewart//@@}}}}}} {{floatright{Love!&nbsp;}}} {{floatright{Laugh,&nbsp;}}} {{floatright{Live,&nbsp;}}} //{{right{<br>{{normal{...be&nbsp;well,&nbsp;be&nbsp;happy...}}}<br>-e}}}//";
	var out='';
	var words=txt.split(' ');
	var when=5000;
	for (var w=0; w<words.length; w++, when+=300)
		out+='<<animate "'+words[w]+' " fontSize %0% 0 100 '+when+' 600>>';
	return out;
</script>//@@}}}/%
%//% OFF <<animate = marginTop %0% 0 -250 45000 15000>> %//%
%//% OFF <<animate = +right %0% 0 -250 45000 15000>> %//%
%//% OFF <<animate = set display none 59500>> %//%
%/}}}
This package defines a set of small icons appear adjacent to the title of each tiddler and indicate various information about the tiddler, such as whether it has unsaved changes, or has been changed recently, or has been tagged as<<tag Trash>>.  Additional icons indicate important categories of tiddlers (based on tags), such as plugins, scripts, templates, attachments, bookmarks, tasks, etc.

----
<<tiddler ShowAllIcons>>
----

{{fine italic{
Note: this package includes icons that are part of the "Silk" icon set: http://www.famfamfam.com/lab/icons/silk/ containing 1000 16-by-16 pixel icons in PNG format, created by Mark James, a part-time web developer, part-time student currently living in Birmingham, UK, and is licensed under a Creative Commons Attribution 2.5 License. Please visit http://www.famfamfam.com/ for further information and licensing details.}}}
/***
|Name|ImageMapPlugin|
|Source|http://www.TiddlyTools.com/#ImageMapPlugin|
|Documentation|http://www.TiddlyTools.com/#ImageMapPluginInfo|
|Version|1.2.2|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|apply image maps ('hotspots') with links to tiddlers|
!!!!!Documentation
>see [[ImageMapPluginInfo]]
!!!!!Revisions
<<<
2009.05.27 [1.2.2] improved autoscroll for {{{<<mapMaker>>}}} textarea
2009.05.14 [1.2.1] added cursor changes
see [[ImageMapPluginInfo]] for additional revision details
2009.05.09 [1.0.0] initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.ImageMapPlugin= {major: 1, minor: 2, revision: 2, date: new Date(2009,5,27)};
//}}}
//{{{
config.macros.imageMap = {
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		// image element must immediately precede macro
		var img=place.lastChild; if (!img||img.nodeName!='IMG') return;
		var map=params[0]; var items=store.getTiddlerText(map,'').split('\n----\n'); if (!items) return;
		var out=['<MAP NAME="'+map+'">'];
		var fmt='<AREA SHAPE="POLY" TIDDLER="%0" COORDS="%1" TITLE="%2" ALT="%2" ONCLICK="%3" STYLE="%4">';
		var click="story.displayTiddler(story.findContainingTiddler(this),this.getAttribute('tiddler'));";
		var style='cursor:pointer';
		for (var i=0; i<items.length; i++) {
			var lines=items[i].split('\n'); var tid=lines.shift(); var coords=lines.join('');
			var tip=store.tiddlerExists(tid)?store.getTiddler(tid).getSubtitle():tid;
			out.push(fmt.format([tid,coords,tip,click,style]));
		}
		out.push('</MAP>');
		createTiddlyElement(place,'span').innerHTML=out.join('');
		img.setAttribute('isMap',true);
		img.setAttribute('useMap','#'+map);
		img.style.border=0;
	}
}
//}}}
//{{{
config.macros.mapMaker= {
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		var img=place.lastChild; // image element must immediately precede macro
		if (!img||img.nodeName!='IMG') return;
		img.onmousemove=function(ev){ ev=ev||window.event;
			var mX=!config.browser.isIE?ev.pageX:(ev.clientX+findScrollX());
			var mY=!config.browser.isIE?ev.pageY:(ev.clientY+findScrollY());
			var ta=this.nextSibling.getElementsByTagName('textarea')[0];
			var lines=ta.value.split('\n'); var last=lines.length?lines.length-1:0;
			var vals=lines[last].split(','); vals.pop(); vals.pop(); lines[last]=vals.join(',');
			lines[last]+=(lines[last].length?',':'')+(mX-findPosX(this))+','+(mY-findPosY(this));
			ta.value=lines.join('\n');
			ta.scrollTop=ta.scrollHeight-ta.offsetHeight+this.emH*2;
			ta.scrollLeft=lines[last].length*this.emW-ta.offsetWidth;
			ta.focus();
		};
		img.onmouseout=function(ev){ ev=ev||window.event;
			var ta=this.nextSibling.getElementsByTagName('textarea')[0];
			var lines=ta.value.split('\n'); var last=lines.length?lines.length-1:0;
			var vals=lines[last].split(','); vals.pop(); vals.pop(); lines[last]=vals.join(',');
			ta.value=lines.join('\n');
			ta.scrollTop=ta.scrollHeight-ta.offsetHeight+this.emH*2;
			ta.scrollLeft=lines[last].length*this.emW-ta.offsetWidth;
		};
		img.onmouseover=img.onclick=function(ev) { ev=ev||window.event;
			var mX=!config.browser.isIE?ev.pageX:(ev.clientX+findScrollX());
			var mY=!config.browser.isIE?ev.pageY:(ev.clientY+findScrollY());
			var ta=this.nextSibling.getElementsByTagName('textarea')[0];
			ta.value+=(ta.value.length?',':'')+(mX-findPosX(this))+','+(mY-findPosY(this));
			var lines=ta.value.split('\n'); var last=lines.length?lines.length-1:0;
			ta.scrollTop=ta.scrollHeight-ta.offsetHeight+this.emH*2;
			ta.scrollLeft=lines[last].length*this.emW-ta.offsetWidth;
			ta.focus();
		}
		img.style.border='1px solid #999';
		img.style.cursor='crosshair';
		var map=params[0]||'';
		var s=createTiddlyElement(place,'div');
		s.style.height=s.style.width='1em';
		img.emW=s.offsetWidth; img.emH=s.offsetHeight; // get font metrics (for auto scrolling)
		s.style.height=s.style.width='';
		s.innerHTML+='<div class="toolbar">'
			+'<a href="javascript:;" '
			+'onclick="config.macros.mapMaker.load(this.parentNode.nextSibling)">load map</a>'
			+'<a href="javascript:;" '
			+'onclick="config.macros.mapMaker.save(this.parentNode.nextSibling)">save map</a>'
			+'</div>'
			+'<textarea rows="8" style="display:block;clear:both;width:100%;" tiddler="'+map+'">'
			+store.getTiddlerText(map,'')
			+'</textarea>';
	},
	load: function(ta) {
		var tid=prompt('Enter a tiddler title:',ta.getAttribute('tiddler')||'');
		if (!tid||!tid.length) return; // cancelled by user
		ta.value=store.getTiddlerText(tid,''); ta.setAttribute('tiddler',tid);
		return false;
	},
	save: function(ta) {
		var tid=prompt('Enter a tiddler title:',ta.getAttribute('tiddler')||'NewImageMap');
		while (tid && tid.length && store.tiddlerExists(tid)) {
			if(confirm(config.messages.overwriteWarning.format([tid]))) break;
			var tid=prompt('Enter a different tiddler title:',tid);
		}
		if (!tid||!tid.length) return; // cancelled by user
		store.saveTiddler(tid,tid,ta.value,config.options.txtUserName,new Date(),['imageMap'],{});
		story.displayTiddler(null,tid);
		displayMessage('image map saved to: '+tid);
		ta.setAttribute('tiddler',tid);
		return false;
	}
}
//}}}
/***
|Name|ImageMapPluginInfo|
|Source|http://www.TiddlyTools.com/#ImageMapPlugin|
|Documentation|http://www.TiddlyTools.com/#ImageMapPluginInfo|
|Version|1.2.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|documentation|
|Description|documentation for ImageMapPlugin|
!!!Usage
<<<
{{{
[img[...]]<<imageMap MapName>>
}}}
applies an image map to the embedded image immediately preceding the macro.   ''~MapName'' is the title of a tiddler (or a tiddler section) that contains an ''~HR-separated list'' of items, where the first line of each item is the ''tiddler to link to'' and the second line is a ''list of polygon coordinates'' using standard HTML <AREA COORDS="..."> syntax (e.g., a ''comma-separated series of X,Y pairs'': "x1,y1,x2,y2,x3,y3,...", that trace out the desired shape).
{{{
[img[...]]<<mapMaker MapName>>
}}}
adds interactive point-and-click calculation of X,Y map coordinates that are automatically entered into a text input field that you can then edit and save to a tiddler to create an ~HR-separated map definition.
<<<
!!!imageMap Example
<<<
{{{
[img[images/california.gif]]<<imageMap ImageMapPluginInfo##county_map>>
}}}
~~//(click a county to open a tiddler)//~~
[img[images/california.gif]]<<imageMap ImageMapPluginInfo##county_map>>
<<<
!!!mapMaker example
<<<
{{{
[img[images/california.gif]]<<mapMaker ImageMapPluginInfo##county_map>>
}}}
~~//(click anywhere inside image to record x,y coordinates)//~~
[img[images/california.gif]]<<mapMaker ImageMapPluginInfo##county_map>>
<<<
!!!Revisions
<<<
2009.05.14 1.2.1 added cursor changes
2009.05.13 1.2.0 add MAP/AREA elements using innerHTML
2009.05.12 1.1.1 fixed mapMaker event handling for IE
2009.05.10 1.1.0 added {{{<<mapMaker>>}}}
2009.05.10 1.0.1 open tiddlers following current tiddler instead of at top of story column
2009.05.09 1.0.0 initial release
<<<
!!!Sample Map
<<<
{{{
!county_map
San Francisco
50,231,51,225,54,222,55,226,55,231,50,231,50,231
----
San Mateo
59,252,60,242,58,239,55,238,54,232,49,233,50,240,50,244,50,249,54,253,59,252,59,252
----
Santa Clara
94,242,90,244,80,243,75,242,66,243,60,243,58,251,63,255,70,258,75,270,79,268,95,268,97,260,97,254,94,254,93,252,97,250,94,248,95,246,94,242,94,242
----
Alameda
94,223,95,242,90,243,80,242,75,241,65,242,66,235,63,225,70,224,80,226,94,221,94,224,95,225,95,231,94,223,94,223
----
Contra Costa
97,213,97,221,83,226,69,224,63,224,62,220,67,214,73,217,79,214,98,214,96,214,97,213,97,213
----
Santa Cruz
53,254,59,251,63,255,70,258,75,268,73,273,68,273,67,266,53,254,53,254
----
San Benito
117,292,116,302,114,304,110,302,111,307,104,304,101,306,91,292,91,288,87,288,87,285,73,273,75,271,78,269,96,270,116,292,117,292,117,292
----
Monterey
128,325,86,325,83,319,83,313,78,309,78,305,64,286,64,283,67,282,67,273,73,273,87,284,86,288,90,287,91,292,101,305,104,303,110,306,113,303,126,318,128,325,128,325
----
Fresno
123,266,133,278,149,271,164,269,170,261,176,261,176,257,181,258,182,254,190,252,194,245,203,237,211,243,213,248,211,253,218,267,221,276,215,276,214,278,195,278,195,282,179,282,177,285,166,285,162,289,154,291,152,294,146,294,146,302,126,318,116,304,118,302,116,299,117,290,106,278,123,265,123,266,123,266
----
Merced
114,249,117,245,142,238,145,245,148,249,153,251,152,256,143,256,136,258,130,262,125,263,106,278,96,269,97,261,99,255,113,250,114,249,114,249
----
Madera
167,243,173,243,174,239,178,238,179,234,192,227,194,228,193,235,198,232,203,236,192,245,188,252,180,254,180,258,172,257,175,261,168,260,163,269,146,270,132,278,122,266,124,263,130,262,135,258,142,256,151,256,152,252,167,243,167,243
----
Kings
162,324,161,303,164,302,164,295,162,294,162,289,153,291,151,295,146,295,146,303,128,318,128,325,161,324,162,324,162,324
----
Tulare
232,324,233,316,234,314,229,310,229,303,228,299,230,296,219,276,213,276,212,279,193,278,193,282,177,282,176,286,164,285,161,289,163,295,164,303,160,304,161,325,232,324,232,324
----
Mono
183,182,183,188,185,194,181,200,181,209,185,211,185,213,191,218,191,224,196,227,194,235,198,233,203,236,211,243,243,243,183,182,183,182
----
Inyo
241,243,320,324,233,324,233,317,235,314,229,310,229,303,228,299,231,295,220,276,217,267,211,253,213,247,211,242,242,244,241,243,241,243
----
San Luis Obispo
111,348,97,340,86,325,127,325,129,332,139,341,144,343,145,346,150,348,156,354,156,358,159,360,161,368,157,371,153,364,136,358,133,354,131,360,126,362,126,366,120,363,112,364,111,356,106,353,112,348,111,348,111,348
----
Santa Barbara
121,387,117,383,111,381,111,365,121,362,127,367,125,362,132,360,135,353,137,359,154,365,157,372,161,368,164,372,163,394,143,390,126,384,121,387,121,387
----
Ventura
186,402,175,401,163,395,163,372,166,369,172,371,177,376,186,376,193,397,186,402,186,402
----
Los Angeles
205,409,184,402,193,397,186,376,234,376,236,388,238,408,232,416,222,420,217,424,211,420,205,409,205,409
----
Kern
240,325,128,325,130,334,139,342,150,348,159,359,162,370,167,368,176,377,235,375,237,374,239,343,241,341,241,325,240,325,240,325
----
San Bernardino
392,401,320,324,240,325,241,342,238,345,236,374,234,377,237,407,256,422,264,413,290,414,303,417,386,414,390,409,392,401,392,401
----
Riverside
379,441,388,429,387,412,303,417,289,414,263,413,255,421,260,424,260,428,265,428,265,436,271,438,275,443,352,444,379,442,379,441,379,441
----
Orange
258,441,221,421,232,415,237,407,255,421,259,424,260,428,266,428,265,438,258,443,258,441,258,441
----
San Diego
322,482,284,484,280,475,276,464,270,451,258,440,264,437,272,438,275,443,283,445,321,444,321,483,322,482,322,482
----
Imperial
378,480,321,482,322,445,378,443,382,451,378,461,383,468,382,475,378,480,378,480
----
Stanislaus
113,229,95,240,98,257,113,249,118,244,141,237,132,228,127,214,124,230,112,229,113,229,113,229
----
Mariposa
168,228,154,225,151,228,148,227,147,231,144,231,145,236,141,237,143,245,151,254,165,242,172,243,172,238,177,238,177,234,191,227,194,226,189,224,184,221,181,223,178,220,169,229,157,226,153,226,151,229,152,229,168,228,168,228
----
Alpine
173,172,172,176,164,180,164,192,179,201,185,194,183,181,173,173,173,172,173,172
----
Calaveras
125,203,127,214,132,223,144,220,165,195,163,191,158,194,150,194,135,203,125,203,125,203
----
San Joaquin
108,205,97,213,97,222,94,225,95,240,113,229,124,229,127,215,125,203,120,206,107,206,108,205,108,205
----
Amador
125,189,126,194,125,203,135,203,150,194,158,194,163,191,164,179,154,186,142,189,124,189,125,189,125,189
----
Sacramento
83,212,96,213,107,205,118,205,124,203,125,195,123,188,120,180,104,180,106,189,103,197,102,203,94,206,93,210,79,212,83,212,83,212
----
Yolo
102,174,98,174,97,170,92,165,68,164,74,178,79,181,81,189,91,190,93,187,97,187,99,197,104,197,106,189,104,180,102,174,102,174
----
Solano
79,197,72,204,73,209,82,211,94,210,95,205,103,203,104,196,98,196,97,186,91,187,90,190,80,189,78,193,79,197,79,197
----
Napa
58,177,59,183,65,192,65,205,71,204,79,197,77,192,80,188,78,181,73,178,67,164,64,166,64,173,58,177,58,177
----
Sonoma
24,168,48,165,56,175,57,182,64,192,64,203,45,198,43,191,32,180,31,176,23,168,24,168,24,168
----
Marin
44,210,50,212,52,216,57,218,60,217,59,212,62,210,64,203,46,199,43,209,44,210,44,210
----
Tuolumne
165,195,144,219,131,223,132,227,142,237,146,236,145,230,149,230,149,226,154,228,155,225,169,228,178,220,182,222,185,221,190,225,190,218,185,213,185,210,180,209,180,200,165,193,164,196,165,195,165,195
----
Mendocino
10,107,16,116,16,126,15,132,20,151,21,161,24,169,50,165,43,158,46,155,46,150,43,145,45,137,53,132,53,114,56,109,11,108,10,107,10,107
----
Humboldt
21,38,17,50,19,59,12,70,9,70,1,85,2,92,10,107,31,108,33,73,32,65,39,65,39,59,45,53,43,51,44,42,33,43,30,37,21,37,21,38,21,38
----
Del Norte
24,14,19,24,20,37,29,37,32,43,37,42,38,37,35,34,42,31,43,21,50,15,24,14,24,14
----
Siskiyou
130,19,51,15,44,21,43,31,36,33,39,37,38,43,43,42,42,50,45,53,54,57,55,61,59,61,59,65,64,61,69,63,67,54,71,52,76,54,80,48,90,46,90,55,131,57,132,31,129,30,130,19,130,19
----
Modoc
183,22,130,19,131,57,179,60,182,22,183,22,183,22
----
Trinity
56,98,57,102,55,105,55,109,31,108,33,72,31,65,39,65,40,58,44,52,54,57,55,61,58,61,58,65,65,61,69,63,67,53,71,52,76,55,79,47,90,46,90,55,90,59,75,70,70,84,56,98,56,98
----
Shasta
124,95,120,96,115,94,111,96,94,96,83,97,78,95,71,98,67,96,57,98,69,84,74,70,90,59,89,54,131,57,132,93,124,95,124,95
----
Tehama
130,105,125,110,109,116,104,122,93,122,93,124,53,122,53,114,57,108,55,106,56,101,56,97,65,96,71,98,77,95,84,98,94,97,112,96,116,94,120,96,123,95,126,98,126,101,130,105,130,105
----
Lake
64,150,67,162,64,167,64,173,58,178,50,164,42,159,46,154,46,149,43,145,45,137,52,133,55,131,61,132,61,141,55,141,54,143,57,149,63,151,64,151,64,150,64,150
----
Colusa
95,143,92,149,92,156,94,164,67,163,64,151,57,149,53,143,56,141,83,142,84,140,87,141,89,143,95,143,95,143
----
Glenn
99,131,97,133,97,137,101,139,96,143,89,143,86,141,82,140,82,142,60,142,61,132,55,131,53,123,92,123,99,131,99,131
----
Sutter
113,166,111,170,111,179,103,180,102,174,97,173,97,169,93,164,92,156,91,149,108,151,108,157,113,166,113,166
----
Butte
120,143,115,144,115,146,107,151,91,149,95,143,101,139,96,137,96,132,99,131,92,123,102,122,109,116,125,109,128,117,126,124,130,128,132,135,126,140,121,138,120,143,120,143
----
El Dorado
170,160,163,160,157,164,149,164,148,167,131,166,122,177,126,188,143,188,155,185,162,180,172,176,173,172,170,169,170,160,170,160
----
Placer
171,152,146,151,138,158,135,158,129,163,121,161,113,165,111,170,111,179,120,179,122,177,131,166,146,168,150,164,157,164,163,161,171,160,171,153,171,152,171,152
----
Yuba
135,145,131,145,129,148,124,150,122,159,113,166,108,157,108,151,115,146,115,143,122,143,120,139,127,140,133,135,135,134,135,145,135,145
----
Nevada
172,143,150,142,146,139,136,144,131,144,129,148,124,150,122,161,130,164,136,157,138,158,146,151,170,152,171,143,171,144,172,143,172,143
----
Sierra
172,131,145,130,139,126,134,134,134,145,145,139,150,143,172,144,173,131,172,131,172,131
----
Plumas
141,94,124,94,126,102,130,105,125,110,128,117,126,124,130,129,132,134,140,126,145,130,168,131,171,124,169,117,154,102,149,103,148,106,141,102,141,93,141,94,141,94
----
Lassen
177,93,174,130,167,131,170,124,169,115,153,101,148,104,148,106,141,103,141,93,132,93,131,59,179,60,176,94,177,93,177,93
!end county_map
}}}
<<<
***/
 

/***
|Name|ImagePathPlugin|
|Source|http://www.TiddlyTools.com/#ImagePathPlugin|
|Version|0.7.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin
|Description|Tell TiddlyWiki where to look for image files.  Permits multiple 'fallback' locations|
|Status|ALPHA - initial development/testing only - may be unstable - do not distribute|

!!!!!Usage
<<<
This plugin adds "resolvePath()" fallback processing to the {{{[img[...]]}}} formatter's handler, so that local image file references can be successfully resolved, even if the files cannot be located on the local filesystem.

The plugin tries alternative file "paths" that are listed, one per line, in an optional tiddler, [[ImagePathList]].  Each path in the list is combined with the image filename, which is then checked for existence, until the file is located.  If no alternative is found, or [[ImagePathList]] is not present, then a 'last-ditch' fallback is attempted using the remote system and path specified in [[SiteUrl]] (if present).

If no fallback attempt is successful (i.e., because no [[ImagePathList]] OR [[SiteUrl]] tiddlers have been defined), the plugin simply passes the original image file value along for default handling by the browser without any "path resolution" being applied.(i.e, the current TW core behavior occurs).

| ''Important note: This plugin may cause one or more security alert messages to appear, because it uses browser-specific functions that can require security permission in order to access the local filesystem to check for the existence of a given image file.  If you block local access, the 'last-ditch' fallback using the remote [[SiteUrl]] (if present) will be attempted.'' |

Note: the image formatter code contained here also includes support for AttachFilePlugin extensions (if installed).  AttachFilePlugin includes its own fallback mechanism for handling embedded vs. local file vs. remote URL references to the attached binary file.  Both methods may be used: ImagePathPlugin provides fallback for images contained in tiddler content, while AttachFilePlugin works well for access to non-image binary files (or images used in CSS as backgrounds, textures, etc.)
<<<
!!!!!Examples
<<<
coming soon...
<<<
!!!!!Revisions
<<<
''2007.04.13 [0.7.1]'' in testFile(), convert any file:// references to local native format before checking for existence.
''2007.03.26 [0.7.0]'' for IE, use onError handling to trigger call to resolvePath() so it will only be invoked if the original path/file is not found by the browser-native lookup.  This avoids an unneeded call to fileExists() and the accompanying ActiveX security alert message box (as well as being slightly more efficient...)
''2007.03.25 [0.6.0]'' code cleanup (moved global functions into config.formatterHelpers) plus documentation re-write
''2007.03.24 [0.5.0]'' initial implementation - ALPHA - do not distribute
<<<
!!!!!Code
***/
//{{{
version.extensions.ImagePathPlugin= {major: 0, minor: 7, revision: 1, date: new Date(2007,4,13)};
//}}}
//{{{
// name of path definition tiddler
if (config.options.txtPathTiddler==undefined) config.options.txtPathTiddler="ImagePathList";
//}}}
//{{{
// low-level wrapper for platform-specific tests for local file existence
// returns true/false without visible error display
// Uses Components for FF and ActiveX FSO object for MSIE
// NOTE: this can cause a security warning on some browsers
config.formatterHelpers.fileExists=function(theFile) {
	var found=false;
	// DEBUG: alert('testing fileExists('+theFile+')...');
	if(window.Components) {
		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(theFile); }
		catch(e) { return false; } // invalid directory
		found = file.exists();
	}
	else { // use ActiveX FSO object for MSIE 
		var fso = new ActiveXObject("Scripting.FileSystemObject");
		found = fso.FileExists(theFile)
	}
	// DEBUG: alert(theFile+" "+(found?"exists":"not found"));
	return found;
}
//}}}
//{{{
// higher-level logic for checking local file existence.
// with secondary check for finding relative file references
// and automatic OK of http-based references without checking local filesystem
config.formatterHelpers.testFile=function(theFile) {
	if (document.location.protocol!="file:") return true; // viewing remote document, can't test local filesystem... assume OK
	if (theFile.substr(0,5)=="http:") return true; // remote HTTP reference... assume OK
	if (theFile.substr(0,5)=="file:") theFile=getLocalPath(theFile); // convert local FILE reference to native format
	if (this.fileExists(theFile)) return true; // file exists locally... OK to use!
	// file might have been relative, add path from current document and try again
	var docPath=document.location.href;
	var slashpos=docPath.lastIndexOf("/"); if (slashpos==-1) slashpos=docPath.lastIndexOf("\\"); 
	if (slashpos!=-1 && slashpos!=docPath.length-1) docPath=docPath.substr(0,slashpos+1); // trim off filename
	if (this.fileExists(getLocalPath(docPath+theFile)))
		return true; // ah ha!... file exists relative to current document... OK to use!
	return false; // file not found on local system
}
//}}}
//{{{
// given a path/file string, check for existence and
// try alternatives (if any) defined in a tiddler
// with last-ditch using system/path from SiteUrl (if any)
config.formatterHelpers.resolvePath=function(theFile,testoriginal) {
	if (testoriginal && this.testFile(theFile)) return theFile; // FOUND FILE - use specified path/file without modification
	// get the filename portion only
	var slashpos=theFile.lastIndexOf("/"); if (slashpos==-1) slashpos=theFile.lastIndexOf("\\"); 
	var theName=(slashpos==-1)?theFile:theFile.substr(slashpos+1);
	// get list of fallbacks (if any)
	var pathText=store.getTiddlerText(config.options.txtPathTiddler);
	if (pathText && pathText.length) {
		var paths=pathText.split("\n");
		for (p=0; p<paths.length; p++) // combine path+filename until one works...
			if (this.testFile(paths[p]+theName))
				return paths[p]+theName; // FOUND FILE - use alternative path+filename
	}
	// try "last ditch" fallback using SiteURL - assumes that original path/file was relative to document location
	var siteURL=store.getTiddlerText("SiteUrl");
	if (!siteURL||!siteURL.length) return theFile; // NO FALLBACK - use original path/file and hope for the best
	// trim filename (if any) from site URL
	var slashpos=siteURL.lastIndexOf("/"); if (slashpos==-1) slashpos=siteURL.lastIndexOf("\\"); 
	if (slashpos!=-1 && slashpos!=siteURL.length-1) siteURL=siteURL.substr(0,slashpos+1);
	return siteURL+theFile; // LAST DITCH: use system/path from SiteUrl combined with original file/path
}
//}}}
//{{{
// replace standard handler for image formatter
// adds call to resolvePath() to handle fallback processing
// includes support for AttachFilePlugin as well
config.formatters[config.formatters.findByField("name","image")].handler=function(w) {
	if (!this.lookaheadRegExp)  // fixup for TW2.0.x
		this.lookaheadRegExp = new RegExp(this.lookahead,"mg");
	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];
			if (!config.formatterHelpers.isExternalLink) // fixup for TW2.0.x
				var external=!store.tiddlerExists(link)&&!store.isShadowTiddler(link);
			else
				var external=config.formatterHelpers.isExternalLink(link);
			if (external) {
				if (config.macros.attach && config.macros.attach.isAttachment(link)) { // ELS - attachments
					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);
			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];
		if (config.macros.attach!=undefined && config.macros.attach.isAttachment(lookaheadMatch[4])) // ELS - attachments
			img.src=config.macros.attach.getAttachment(lookaheadMatch[4]);
		else {
			if (config.browser.isIE || config.browser.isSafari) { // ELS - path processing
				// IE and Safari use browser's onError handling to check the original file...
				// avoids extra security alert messages due to use of Components/ActiveX for filesystem access
				img.onerror=(function(){this.src=config.formatterHelpers.resolvePath(this.src,false);return false;});
				img.src=lookaheadMatch[4]; // ELS - path processing
			} else {
				// if NOT IE or Safari, always check the original path/file before rendering
				img.src=config.formatterHelpers.resolvePath(lookaheadMatch[4],true);
			}
		}
		w.nextMatch = this.lookaheadRegExp.lastIndex;
	}
}
//}}}
/***
|Name|ImageSizePlugin|
|Source|http://www.TiddlyTools.com/#ImageSizePlugin|
|Version|1.2.3|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|adds support for resizing images|
This plugin adds optional syntax to scale an image to a specified width and height and/or interactively resize the image with the mouse.
!!!!!Usage
<<<
The extended image syntax is:
{{{
[img(w+,h+)[...][...]]
}}}
where ''(w,h)'' indicates the desired width and height (in CSS units, e.g., px, em, cm, in, or %). Use ''auto'' (or a blank value) for either dimension to scale that dimension proportionally (i.e., maintain the aspect ratio). You can also calculate a CSS value 'on-the-fly' by using a //javascript expression// enclosed between """{{""" and """}}""". Appending a plus sign (+) to a dimension enables interactive resizing in that dimension (by dragging the mouse inside the image). Use ~SHIFT-click to show the full-sized (un-scaled) image. Use ~CTRL-click to restore the starting size (either scaled or full-sized).
<<<
!!!!!Examples
<<<
{{{
[img(100px+,75px+)[images/meow2.jpg]]
}}}
[img(100px+,75px+)[images/meow2.jpg]]
{{{
[<img(34%+,+)[images/meow.gif]]
[<img(21% ,+)[images/meow.gif]]
[<img(13%+, )[images/meow.gif]]
[<img( 8%+, )[images/meow.gif]]
[<img( 5% , )[images/meow.gif]]
[<img( 3% , )[images/meow.gif]]
[<img( 2% , )[images/meow.gif]]
[img(  1%+,+)[images/meow.gif]]
}}}
[<img(34%+,+)[images/meow.gif]]
[<img(21% ,+)[images/meow.gif]]
[<img(13%+, )[images/meow.gif]]
[<img( 8%+, )[images/meow.gif]]
[<img( 5% , )[images/meow.gif]]
[<img( 3% , )[images/meow.gif]]
[<img( 2% , )[images/meow.gif]]
[img(  1%+,+)[images/meow.gif]]
{{tagClear{
}}}
<<<
!!!!!Revisions
<<<
2011.09.03 [1.2.3] bypass addStretchHandlers() if no '+' suffix is used (i.e., not resizable)
2010.07.24 [1.2.2] moved tip/dragtip text to config.formatterHelpers.imageSize object to enable customization
2009.02.24 [1.2.1] cleanup width/height regexp, use '+' suffix for resizing
2009.02.22 [1.2.0] added stretchable images
2008.01.19 [1.1.0] added evaluated width/height values
2008.01.18 [1.0.1] regexp for "(width,height)" now passes all CSS values to browser for validation
2008.01.17 [1.0.0] initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.ImageSizePlugin= {major: 1, minor: 2, revision: 3, date: new Date(2011,9,3)};
//}}}
//{{{
var f=config.formatters[config.formatters.findByField("name","image")];
f.match="\\[[<>]?[Ii][Mm][Gg](?:\\([^,]*,[^\\)]*\\))?\\[";
f.lookaheadRegExp=/\[([<]?)(>?)[Ii][Mm][Gg](?:\(([^,]*),([^\)]*)\))?\[(?:([^\|\]]+)\|)?([^\[\]\|]+)\](?:\[([^\]]*)\])?\]/mg;
f.handler=function(w) {
	this.lookaheadRegExp.lastIndex = w.matchStart;
	var lookaheadMatch = this.lookaheadRegExp.exec(w.source)
	if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
		var floatLeft=lookaheadMatch[1];
		var floatRight=lookaheadMatch[2];
		var width=lookaheadMatch[3];
		var height=lookaheadMatch[4];
		var tooltip=lookaheadMatch[5];
		var src=lookaheadMatch[6];
		var link=lookaheadMatch[7];

		// Simple bracketted link
		var e = w.output;
		if(link) { // LINKED IMAGE
			if (config.formatterHelpers.isExternalLink(link)) {
				if (config.macros.attach && config.macros.attach.isAttachment(link)) {
					// see [[AttachFilePluginFormatters]]
					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);
			addClass(e,"imageLink");
		}

		var img = createTiddlyElement(e,"img");
		if(floatLeft) img.align="left"; else if(floatRight) img.align="right";
		if(width||height) {
			var x=width.trim(); var y=height.trim();
			var stretchW=(x.substr(x.length-1,1)=='+'); if (stretchW) x=x.substr(0,x.length-1);
			var stretchH=(y.substr(y.length-1,1)=='+'); if (stretchH) y=y.substr(0,y.length-1);
			if (x.substr(0,2)=="{{")
				{ try{x=eval(x.substr(2,x.length-4))} catch(e){displayMessage(e.description||e.toString())} }
			if (y.substr(0,2)=="{{")
				{ try{y=eval(y.substr(2,y.length-4))} catch(e){displayMessage(e.description||e.toString())} }
			img.style.width=x.trim(); img.style.height=y.trim();
			if (stretchW||stretchH) config.formatterHelpers.addStretchHandlers(img,stretchW,stretchH);
		}
		if(tooltip) img.title = tooltip;

		// GET IMAGE SOURCE
		if (config.macros.attach && config.macros.attach.isAttachment(src))
			src=config.macros.attach.getAttachment(src); // see [[AttachFilePluginFormatters]]
		else if (config.formatterHelpers.resolvePath) { // see [[ImagePathPlugin]]
			if (config.browser.isIE || config.browser.isSafari) {
				img.onerror=(function(){
					this.src=config.formatterHelpers.resolvePath(this.src,false);
					return false;
				});
			} else
				src=config.formatterHelpers.resolvePath(src,true);
		}
		img.src=src;
		w.nextMatch = this.lookaheadRegExp.lastIndex;
	}
}

config.formatterHelpers.imageSize={
	tip: 'SHIFT-CLICK=show full size, CTRL-CLICK=restore initial size',
	dragtip: 'DRAG=stretch/shrink, '
}

config.formatterHelpers.addStretchHandlers=function(e,stretchW,stretchH) {
	e.title=((stretchW||stretchH)?this.imageSize.dragtip:'')+this.imageSize.tip;
	e.statusMsg='width=%0, height=%1';
	e.style.cursor='move';
	e.originalW=e.style.width;
	e.originalH=e.style.height;
	e.minW=Math.max(e.offsetWidth/20,10);
	e.minH=Math.max(e.offsetHeight/20,10);
	e.stretchW=stretchW;
	e.stretchH=stretchH;
	e.onmousedown=function(ev) { var ev=ev||window.event;
		this.sizing=true;
		this.startX=!config.browser.isIE?ev.pageX:(ev.clientX+findScrollX());
		this.startY=!config.browser.isIE?ev.pageY:(ev.clientY+findScrollY());
		this.startW=this.offsetWidth;
		this.startH=this.offsetHeight;
		return false;
	};
	e.onmousemove=function(ev) { var ev=ev||window.event;
		if (this.sizing) {
			var s=this.style;
			var currX=!config.browser.isIE?ev.pageX:(ev.clientX+findScrollX());
			var currY=!config.browser.isIE?ev.pageY:(ev.clientY+findScrollY());
			var newW=(currX-this.offsetLeft)/(this.startX-this.offsetLeft)*this.startW;
			var newH=(currY-this.offsetTop )/(this.startY-this.offsetTop )*this.startH;
			if (this.stretchW) s.width =Math.floor(Math.max(newW,this.minW))+'px';
			if (this.stretchH) s.height=Math.floor(Math.max(newH,this.minH))+'px';
			clearMessage(); displayMessage(this.statusMsg.format([s.width,s.height]));
		}
		return false;
	};
	e.onmouseup=function(ev) { var ev=ev||window.event;
		if (ev.shiftKey) { this.style.width=this.style.height=''; }
		if (ev.ctrlKey)  { this.style.width=this.originalW; this.style.height=this.originalH; }
		this.sizing=false;
		clearMessage();
		return false;
	};
	e.onmouseout=function(ev) { var ev=ev||window.event;
		this.sizing=false;
		clearMessage();
		return false;
	};
}
//}}}
The plugins in this package provide interactive functionality for importing/exporting tiddlers to/from other TiddlyWiki documents.  Additional plugins provide enhanced local/remote file I/O features, including "save as", "save from web" and "upload" functionality.
/***
|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|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Requires|ImportTiddlersPlugin|
|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
//}}}
/***
|Name|InlineJavascriptPlugin|
|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|plugin|
|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]]
!!!!!Revisions
<<<
2010.12.15 1.9.6 allow (but ignore) type="..." syntax
|please see [[InlineJavascriptPluginInfo]] for additional revision details|
2005.11.08 1.0.0 initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.InlineJavascriptPlugin= {major: 1, minor: 9, revision: 6, date: new Date(2010,12,15)};

config.formatters.push( {
	name: "inlineJavascript",
	match: "\\<script",
	lookahead: "\\<script(?: type=\\\"[^\\\"]*\\\")?(?: src=\\\"([^\\\"]*)\\\")?(?: label=\\\"([^\\\"]*)\\\")?(?: title=\\\"([^\\\"]*)\\\")?(?: key=\\\"([^\\\"]*)\\\")?( 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) { // external script library
				var script = document.createElement("script"); script.src = src;
				document.body.appendChild(script); document.body.removeChild(script);
			}
			if (code) { // inline code
				if (show) // display source in tiddler
					wikify("{{{\n"+lookaheadMatch[0]+"\n}}}\n",w.output);
				if (label) { // create 'onclick' command link
					var link=createTiddlyElement(w.output,"a",null,"tiddlyLinkExisting",wikifyPlainText(label));
					var fixup=code.replace(/document.write\s*\(/gi,'place.bufferedHTML+=(');
					link.code="function _out(place,tiddler){"+fixup+"\n};_out(this,this.tiddler);"
					link.tiddler=w.tiddler;
					link.onclick=function(){
						this.bufferedHTML="";
						try{ var r=eval(this.code);
							if(this.bufferedHTML.length || (typeof(r)==="string")&&r.length)
								var s=this.parentNode.insertBefore(document.createElement("span"),this.nextSibling);
							if(this.bufferedHTML.length)
								s.innerHTML=this.bufferedHTML;
							if((typeof(r)==="string")&&r.length) {
								wikify(r,s,null,this.tiddler);
								return false;
							} else return r!==undefined?r:false;
						} catch(e){alert(e.description||e.toString());return false;}
					};
					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 script immediately
					var fixup=code.replace(/document.write\s*\(/gi,'place.innerHTML+=(');
					var c="function _out(place,tiddler){"+fixup+"\n};_out(w.output,w.tiddler);";
					try	 { var out=eval(c); }
					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") window.wikifyPlainText=function(text,limit,tiddler) {
	if(limit > 0) text = text.substr(0,limit);
	var wikifier = new Wikifier(text,formatter,null,tiddler);
	return wikifier.wikifyPlain();
}
//}}}

// // GLOBAL FUNCTION: $(...) -- 'shorthand' convenience syntax for document.getElementById()
//{{{
if (typeof($)=='undefined') { function $(id) { return document.getElementById(id.replace(/^#/,'')); } }
//}}}
/***
|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
<<<
This package provides a set of TW-compatible "form input fields" for accessing and modifying custom tiddler fields, tags, options, etc.  These input fields make it easier to build application-specific View/Edit templates as well as end-user-oriented "control panels" and "fill in forms".
/%
|Name|InstantBookmarklets|
|Source|http://www.TiddlyTools.com/#InstantBookmarklets|
|Version|2.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion bookmarklet|
|Description|instantly create bookmarklets by dragging onclick links to the browser toolbar|

!help
To create a bookmarklet, simply drag-and-drop any command link below directly onto your browser's toolbar or right-click and use 'bookmark this link' (or 'add to favorites') to add the bookmarklet to your browser's bookmarks menu.

Once installed, you can use the bookmarklet with ANY TiddlyWiki document, even if the command script (and InlineJavascriptPlugin) has not been installed in that document!
!end

%/{{nowrap{
__[[InstantBookmarklets:|InstantBookmarklets]]__{{fine{
&nbsp; //drag these links to your browser toolbar!// <html><nowiki><a href='javascript:;' onclick="alert(store.getTiddlerText('InstantBookmarklets##help')); return false;">(help...)</a></html>}}}
//~TiddlyWiklets: {{fine{(TiddlyWiki "tear-off" utilities)}}}///%

========================== TOGGLE SITE TITLES %/
*<html><nowiki><a href="javascript:;"  title="show/hide SiteTitle and SiteSubtitle (header) content"
onmouseover="
	this.href='javascript:void(eval(decodeURIComponent(%22(function(){try{('
	+encodeURIComponent(encodeURIComponent(this.onclick))
	+')()}catch(e){alert(e.description?e.description:e.toString())}})()%22)))';"
onclick="
	var c=document.getElementById('contentWrapper');  if (!c) return;
	for (var i=0; i<c.childNodes.length; i++)
		if (hasClass(c.childNodes[i],'header')) { var h=c.childNodes[i]; break; }
	if (!h) return;
	config.options.chkHideSiteTitles=h.style.display!='none';
	h.style.display=config.options.chkHideSiteTitles?'none':'block';
	saveOptionCookie('chkHideSiteTitles');
	return false;
">&#x25b2; - Toggle site titles</a></html>/%

========================== TOGGLE LEFT SIDEBAR %/
*<<tiddler ToggleLeftSidebar with: "&#x25c4; - Toggle left sidebar">>/%

========================== TOGGLE RIGHT SIDEBAR %/
*<<tiddler ToggleRightSidebar with: "&#x25ba; - Toggle right sidebar">>/%

========================== TOGGLE ANIMATION EFFECTS %/
*<<tiddler ToggleAnimations with: "&infin; - Toggle animation effects">>/%

========================== TOGGLE "FULLSCREEN" (SIDEBARS AND TITLES) %/
*<<tiddler ToggleFullScreen with: "&loz; - Toggle fullscreen ON" "&loz; - Toggle fullscreen OFF">>/%

========================== TOGGLE TIDDLER TITLES (and SUBTITLES) %/
*<<tiddler ToggleTiddlerTitles with: "T - Toggle tiddler titles">>/%

========================== TOGGLE TIDDLER TAGS %/
*<<tiddler ToggleTiddlerTags with: "# - Toggle tiddler tags">>/%

========================== RESTART WITHOUT RELOADING %/
*<html><nowiki><a href="javascript:;"  title="Restart initial page content WITHOUT RELOADING!"
onmouseover="
	this.href='javascript:void(eval(decodeURIComponent(%22(function(){try{('
	+encodeURIComponent(encodeURIComponent(this.onclick))
	+')()}catch(e){alert(e.description?e.description:e.toString())}})()%22)))';"
onclick="
	story.closeAllTiddlers(); restart(); refreshPageTemplate(); 
 	return false;
">&#x2302; - Home</a></html>/%

========================== REFRESH WITHOUT RESTARTING %/
*<<tiddler RefreshPageDisplay with: "&asymp; - Refresh current display">>/%

========================== SHOW CURRENT VERSION, TIMESTAMP, and TIDDLER INFO %/
*<<tiddler ShowDocumentInfo>>/%

========================== RESET TIDDLYWIKI OPTION COOKIES (WITH CONFIRM) %/
*<<tiddler ResetOptionCookies>>/%

========================== CLEAR CHANGE COUNTERS %/
*<<tiddler ResetChangeCounters>>/%

========================== SAVE FROM CLIPBOARD ("rescue storeArea") %/
*<<tiddler SaveToClipboard with: "&sum; - Save current storeArea contents to clipboard">>/%

========================== LOAD REMOTE PLUGINS...%/
[[Load remote plugins|LoadRemotePlugin]]: {{fine{(//load on demand//)}}}
<<tiddler LoadRemotePlugin##Examples>>/%

}}}/%  END NOWRAP %/
[img[banner.gif]] {{big{&rarr;}}} [img[i4logo.gif]]

{{left{
__''@@font-size:18pt;font-family:times;color:#0c0;I@@ntuitive'' \In*tu"i*tive\ (//adj.//)__
{{small{
1. Seeing clearly; as, an intuitive view; intuitive vision.
2. Knowing, or perceiving, by intuition;
3. Capable of knowing without deduction or reasoning.
}}}
__''@@font-size:18pt;font-family:times;color:#0c0;I@@nterfaces'' \In`ter"faces\ (//noun//)__
{{small{
1. Devices and/or processes for controlling and monitoring inter-operability between complex physical systems and mechanisms
2. Visual, syntactic and semantic conventions and procedures for the representation and exchange of information and/or commands for controlling software applications and digital presentations.
}}}
__''@@font-size:18pt;font-family:times;color:#0c0;I@@ntelligent'' \In*tel"li*gent\ (//adj.//)__
{{small{
1. Possessing sound knowledge
2. Exercising or showing good judgment
3. Endowed with the capacity to reason
}}}
__''@@font-size:18pt;font-family:times;color:#0c0;I@@nteractions'' \In`ter*ac"tions\ (//noun//)__
{{small{
1. Mutual or reciprocal actions or influence
2. Sequences of events, actions, and conditional responses, combined to achieve specific goals or purposes
}}}}}}
!!!Design Principles
<<<
The most important function of an interface is to communicate information in ways that can be easily understood. To achieve this, a "user-centric" design approach is needed, in which the focus is on the intent, knowledge, expectations, and abilities of a range of typical viewers as they might be expected to interact with a proposed interface. 
| ''Knowledge and ability vary greatly from person-to-person, and task-to-task. Interfaces should be flexible and adaptable to best fit these individual differences.'' |
The most effective interfaces help the viewer to ''focus'' on their ''goals'' and ''objectives'' to obtain relevant, meaningful and ''useful results'' with less of ''time'' and ''effort''.  To evaluate the potential of alternative interface designs, techniques such as scenarios, storyboarding, and use-case analysis can be used to illustrate how even minor variations in the presentation style and organization of an interface can enhance or detract from the overall effectiveness of the viewing experience. 
| ''A good interface is like a good hairpiece - you won't notice it.  A bad interface is like a bad hairpiece - all you can do is stare at it.'' |
When an interface is well designed, it doesn't really get much notice. Most functions perform just as the viewer expects them to, and the interaction flows smoothly from activity to activity. In contrast, when an interface is poorly designed, very little works as the viewer expects. As a result, the viewer's mental focus is diverted away from the real task and they expend considerable effort simply to decipher an arbitrary, non-intuitive method of interaction, in hopes of finding a means to achieve the results they desire. 
| ''More often than not, you get what you //expect// to get.  Effective interfaces focus on helping the user form expectations that work.'' |
Informative messages, tooltips, help text, as well as suitably-worded labels on form controls and linked text, all contribute to an interactive process of "managing expectations", so that the user is able to quickly understand and form accurate expectations of the behavior of the interface and the desired results can be reliably predicted and more easily achieved.
<<<
@@font-size:6pt;&copy;1995-2006 Eric L. Shulman.  All rights retained.@@
/%
|''URL:''|http://jackparke.googlepages.com/jtw.html|
|''Description:''|Plugins, Macros and Hacks|
|''Author:''|JackParker|
%/
/*{{{*/
/**
* $Id: Jash.css,v 1.3 2007/11/16 03:06:33 billyreisinger Exp $
*
* Jash - JavaScript Shell
* Copyright: 2007, Billy Reisinger
* Documentation: http://www.billyreisinger.com/jash/
* License: GNU General Public License - http://www.gnu.org/licenses/gpl.html
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* 
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
* 
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
**/
#JashParent {
	width: 581px;
	height: 450px;
	border: 1px solid gray;
	-moz-border-radius: 10px; /* ELS */
	-webkit-border-radius: 10px; /* ELS */
	color: black;
	z-index: 10000;
	overflow: hidden;
	background: #ccc;
	opacity: 0.90;
	filter: alpha(opacity=90);
	position: absolute;
	left: 25%;
	color: black;
	font-family: monospace;
	margin: 0;
}
#JashParent div {
	margin: 0;
}
#JashParent a, #JashParent a:visited, #JashParent a:active, #JashParent a:hover {
	text-decoration: none;
	color: black;
}
.transparentMode {
	opacity: 0.20 !important;
	filter: alpha(opacity=20) !important;
}
#JashDragBar {
	BACKGROUND: gray;
	CURSOR: move;
	COLOR: white;
	font-family: arial,helvetica,sans-serif; /* ELS - changed from monospace to arial,helvetica,sans-serif */
	font-weight: bold;
	text-indent: 4px;
	font-size: 14pt; /* ELS - changed from 14px to 14pt */
	HEIGHT: 25px;
	TEXT-ALIGN: left;
	overflow: hidden;
	border: 1px outset white;
	-moz-border-radius-topleft: 10px; /* ELS */
	-moz-border-radius-topright: 10px; /* ELS */
	-webkit-border-top-left-radius: 10px; /* ELS */
	-webkit-border-top-right-radius: 10px; /* ELS */
}
.JashXButton {
    border: 1px solid white;
    -moz-border-radius: 5px; /* ELS */
    -webkit-border-radius: 5px; /* ELS */
    color: white !important;
    position: absolute;
    background: #bbb;
    width: 20px; 
    text-align: center;
    display: block;
    right: 3px; _right: 1px;
    top: 4px; _top: 1px;
    font-family: arial,helvetica,sans-serif; /* ELS - changed to arial,helvetica,sans-serif */
    font-size: 8pt; /* ELS - changed from 18px to 8pt */
    cursor: pointer;
}
a.JashXButton:hover {
	background: #ddd; 
}
#JashTextareaWrap {
	width: 100%;
	_height: 420px;
}
html>body #JashTextareaWrap {
	height: 100%;
}
#JashOutput {
	border: 2px inset white;
	FONT-SIZE: 10px;
	font-family: "Lucida Console", monaco, monospace;
	BACKGROUND: black;
	width: 99%;
	COLOR: lightgreen;
	PADDING: 2px;
	height: 60%;
	height: expression(parseInt(this.parentNode.parentNode.offsetHeight * (3/5)) + 'px');
	
}
#JashInput {
	padding: 2px;
	WIDTH: 99%;
	border: 2px inset white;
	-moz-border-radius-bottomleft: 10px; /* ELS */
	-moz-border-radius-bottomright: 10px; /* ELS */
	-webkit-border-bottom-left-radius: 10px; /* ELS */
	-webkit-border-bottom-right-radius: 10px; /* ELS */
	HEIGHT: 25%;
	font-family: monospace;
	font-size: 11px;
	height: expression(parseInt(this.parentNode.parentNode.offsetHeight * (3/13)) + 'px');
}
#JashParent .cssEntry {
	background: lightgreen;
	font-size: 11px;
	font-family: monospace;
}
#JashBottomBar {
	BACKGROUND: #ccc;
	POSITION: relative;
	HEIGHT: 20px;
	overflow: hidden;
	margin-top: 2px;
}
#JashBottomBar a {
	HEIGHT: 14px;
	font-size: 9px;
	font-weight: normal;
	font-family: arial;
	float: left;
	padding: 4px;
	background: #eee;
	cursor: pointer;
	border: 1px outset white;
	margin-right: 1px;
}
#JashBottomBar a:hover {
	padding-top: 3px;
	padding-bottom: 5px;
	background-color: white;
}
#JashBottomBar a:active, #JashBottomBar a:focus {
	padding-top: 5px;
	padding-bottom: 3px;
	background-color: #ddd;
}
#JashResizeButton {
	BORDER: 1px solid gray;
	-moz-border-radius-bottomright: 10px; /* ELS */
	-webkit-border-bottom-right-radius: 10px; /* ELS */
	BACKGROUND: #eee;
	WIDTH: 17px;
	height: 17px;
	line-height: 0;
	CURSOR: move;
	position: absolute;
	bottom: -1px;
	right: -1px;
	z-index: 2000;
}
/*}}}*/
//{{{
// Jash - JavaScript Shell
// Copyright: 2007, Billy Reisinger
// Documentation: http://www.billyreisinger.com/jash/
// License: GNU General Public License - http://www.gnu.org/licenses/gpl.html

// MODIFIED BY ELS (www.TiddlyTools.com) on 12/11/2007 for embedded use within TiddlyWiki documents
// * disabled setting of stylesheet from remote URL - use internal CSS definitions instead (see [[jash.css]] tiddler)
// * disabled automatic display on startup (but initialize jash panel so ESC key will work)

window.Jash=function(){this.jashRoot="http://www.billyreisinger.com/jash/source/latest/";this.domGetElFunctions={id:new Array("document.getElementById","$"),className:new Array("getElementsByClassName","$C")};var line="-------------------------------------------------";var _null="nooutput";this.revision="$Revision: 1.14 $".replace(/(\$|[A-Za-z]|\s|:)/g,'');this.version="$Name: REL_1_35_7 $".replace(/\$|Name:|\s|REL_/g,'').replace(/_/g,'.');this.versionDate="$Date: 2007/11/16 03:24:54 $";this.main=function(){this.browser=this.returnBrowserType();this.lineNumber=0;this.mainBlock;this.output=document.getElementById("JashOutput");this.input;this.outputHistory=new Array();this.cssEvalFlag=false;this.innerHtmlInspection=false;this.accessKeyText=this.getAccessKeyText();this.defaultText="Jash, v"+this.version+"\nEnter \"jash.help()\" for a list of commands.\n";this.cls=this.clear;this.tabIndexIndex=0;this.currentNode={};this.tips=["Did you know?\nThe DOM Inspector will automatically put\n an element with an ID in the input field for you.","Did you know?\nYou can tie this script into your own to jash scripts. Use 'jash.methodName' anywhere\n in your scripts, and pull\n up this window before executing to see\n the results.","Did you know?\nUse jash.stopWatch.start() and jash.stopWatch.stop() to\n time execution speeds! Handy for optimization.","Did you know?\nPress TAB to complete a function, method, or property name.\n If more than one match is found, a list of possible\n matches will appear.","Did you know?\nYou can use jash.show() to show a list of the names\nand types of an object's members.\nOn the other hand, jash.dump will show names and\n_values_ of an object's members.","Whoa ---- you can now tab-complete HTML element ids after typing document.getElementsById(' (or the '$' shorthand if using Prototype).  This also works with class names (i.e. document.getElementsByClassName)"]
this.defaultText+=line+"\n"+this.tips[(parseInt((Math.random()*10)%this.tips.length))]+"\n"+line+"\n";

/* 
ELS: disable loading of remote stylesheet!  (use styles from [[jash.css]] tiddler intead)
if(this.returnBrowserType()!="sa"){this.stylesheet=document.body.appendChild(document.createElement('link'));}else{this.stylesheet=document.getElementsByTagName("head")[0].appendChild(document.createElement("link"));}
this.stylesheet.type='text/css';this.stylesheet.rel='stylesheet';this.stylesheet.href=this.jashRoot+'Jash.css';
*/

this.create();Jash.TabComplete.prototype=this;this.tabComplete=new Jash.TabComplete();Jash.Evaluator.prototype=this;this.evaluation=new Jash.Evaluator();this.history=new Jash.History();var _self=this;window.setTimeout(function(){_self.input.focus();},500);if(typeof event!="undefined")delete event;}
this.returnBrowserType=function(){if(window.navigator.userAgent.toLowerCase().indexOf("opera")!=-1){return"op";}
if(window.navigator.userAgent.toLowerCase().indexOf("msie")!=-1){return"ie";}
if(window.navigator.userAgent.toLowerCase().indexOf("firefox")!=-1){return"ff";}
if(window.navigator.userAgent.toLowerCase().indexOf("safari")!=-1){return"sa";}}
this.returnOsType=function(){var ua=window.navigator.userAgent.toLowerCase();if(ua.indexOf("macintosh")!=-1){return"mac";}else if(ua.indexOf("windows")!=-1){return"win";}else if(ua.indexOf("linux i686")!=-1){return"linux";}}
this.getAccessKeyText=function(){var txt;var agt=this.returnOsType();switch(this.browser){case"ie":txt="Alt";break;case"ff":if(agt=="mac"){txt="Ctrl";}else if(agt=="linux"){txt="Alt";}else{txt="Alt-Shift";}
break;case"op":txt="Shift-Esc";break;case"sa":if(agt=="mac"){txt="Ctrl";}else{txt="Alt";}
break;default:txt="Alt";break;}
return txt;}
this.print=function(text,clear,suppressLineNumbers,autoscroll){clear=(typeof clear!="undefined")?clear:false;autoscroll=(typeof autoscroll!="undefined")?autoscroll:true;if(this.output==null||document.getElementById("JashParent")==null){this.create();this.output=document.getElementById("JashOutput");this.mainBlock=document.getElementById("JashParent");}
if(clear){this.clear();}
if(text!=""){if(typeof suppressLineNumbers!="undefined"&&!suppressLineNumbers){this.output.value+=this.lineNumber+". ";}
this.output.value+=text+"\n";if(autoscroll){this.output.scrollTop=this.output.scrollHeight;}
this.lineNumber++;}
return _null;}
this.show=function(obj){this.print(line,false,true);var out="";this.lineNumber=0;for(var p in obj){if(typeof obj[p]=="function"){var t=obj[p].toString();t=t.replace(/[\x0A\x0D]/g,"").replace(/\s+/g,"").replace(/\{.+\}/g,"{ ... }");t=t.replace(p,"");t=p+": "+t;}else{t=p+": "+typeof obj[p];}
out+=++this.lineNumber+". "+t+"\n";}
this.print(out,false,true);this.print(line,false,true);this.output.scrollTop=this.output.scrollHeight;return _null;}
this.dump=function(obj){if(typeof obj=="string"){this.print(obj);}else{this.print(line,false,true);var out=new Array();if(typeof obj.push=="undefined"){for(var th in obj){out.push(++this.lineNumber+". "+th+" = "+obj[th]);}}else{for(var i=0;i<obj.length;i++){out.push(++this.lineNumber+". "+obj[i]);}}
this.print(out.join("\n"),false,true);this.print(line,false,true);this.output.scrollTop=this.output.scrollHeight;}
return _null;}
this.clear=function(){this.outputHistory.push(this.output.value);this.output.value="";this.input.focus();return _null;}
this.showOutputHistory=function(){this.outputHistory.push(this.output.value);this.dump(this.outputHistory);}
this.assignInputKeyEvent=function(keyCode){if(keyCode==13){this.evaluation.evaluate(this.input.value);this.input.value="";return false;}else if(keyCode==38){if(this.browser!="op"){this.input.value=this.history.getPreviousInput();}
return false;}else if(keyCode==40){if(this.browser!="op"){this.input.value=this.history.getNextInput();}
return false;}else if(keyCode==9){this.tabComplete.tabComplete();return false;}}
this.getXBrowserYOffset=function(){var y;if(self.pageYOffset){y=self.pageYOffset;}else if(document.documentElement&&document.documentElement.scrollTop){y=document.documentElement.scrollTop;}else if(document.body){y=document.body.scrollTop;}
return y;}
this.getMouseXY=function(e){var tempX=0
var tempY=0
if(window.event){if(document.documentElement&&document.documentElement.scrollTop){tempX=window.event.clientX+document.documentElement.scrollLeft;tempY=window.event.clientY+document.documentElement.scrollTop;}else{tempX=window.event.clientX+document.body.scrollLeft;tempY=window.event.clientY+document.body.scrollTop;}}else{tempX=e.pageX;tempY=e.pageY;}
return{x:tempX,y:tempY};}
this.getDimensions=function(el){var dims={}
if(document.all){dims.x=el.offsetWidth;dims.y=el.offsetHeight;}else{dims.x=parseInt(document.defaultView.getComputedStyle(el,"").getPropertyValue("width"));dims.y=parseInt(document.defaultView.getComputedStyle(el,"").getPropertyValue("height"));}
return dims;}
this.addEvent=function(obj,eventName,func){if(obj.addEventListener)
return obj.addEventListener(eventName,func,true);else if(obj.attachEvent){obj.attachEvent("on"+eventName,func);return true;}
return false;}
this.findElementPosition=function(obj){var curleft=0;var curtop=0;if(obj.offsetParent){curleft=obj.offsetLeft
curtop=obj.offsetTop
while(obj=obj.offsetParent){curleft+=obj.offsetLeft
curtop+=obj.offsetTop}}
return[curleft,curtop];}
this.create=function(){if(document.getElementsByTagName("frameset").length>0){alert("Jash currently does not support pages with frames.");return;}
var self=this;var debugParent=document.createElement("div");var windowScrollY=0;if(document.documentElement&&document.documentElement.scrollTop){windowScrollY=document.documentElement.scrollTop;}else if(document.body){windowScrollY=document.body.scrollTop}else{windowScrollY=window.scrollY;}





debugParent.style.top=windowScrollY+50+"px";debugParent.id="JashParent";

/*
ELS: 12/12/2007 - REMOVED ESC HANDLER SO OTHER PAGE ELEMENTS GET THEM!... SEE BELOW FOR ALTERNATIVE SHIFT-ESC HANDLER
this.addEvent(document,"keydown",function(e){e=(typeof window.event!="undefined")?window.event:e;if(e.keyCode=="27"){if(typeof e.shiftKey=="undefined"||!e.shiftKey && (this.mainBlock.style.display!="none")){self.close();}}});
*/

var textareaWrap=document.createElement("div");textareaWrap.id="JashTextareaWrap";var debugOutput=document.createElement("textarea");debugOutput.id="JashOutput";debugOutput.wrap="off";debugOutput.readOnly="true";debugOutput.value=this.defaultText;var inp=document.createElement("textarea");inp.id="JashInput";var last="";inp.onkeydown=function(e){e=(typeof window.event!="undefined")?window.event:e;return self.assignInputKeyEvent(e.keyCode);}
inp.onkeypress=function(e){e=(typeof window.event!="undefined")?window.event:e;var k=e.keyCode;if(!self.evaluation.cssEvalFlag){if(k==9||k==13||k==38||k==40){if(k!=40&&this.browser!="ie"){return false;}}}else if(k==9){return false;}}
var dragBut=document.createElement("div");dragBut.innerHTML="Jash";dragBut.id="JashDragBar";dragBut.onmousedown=function(e){e=(typeof window.event!="undefined")?window.event:e;var xplus=(typeof e.layerX=="undefined")?e.offsetX:e.layerX;var yplus=(typeof e.layerY=="undefined")?e.offsetY:e.layerY;document.onmousemove=function(e){var coords=self.getMouseXY(e);document.getElementById("JashParent").style.top=coords.y-yplus+"px";document.getElementById("JashParent").style.left=coords.x-xplus+"px";}
return false;}
document.onmouseup=function(){document.onmousemove=null;};dragBut.onclick=function(){return false;}
var xBut=document.createElement("a");xBut.className="JashXButton";xBut.innerHTML="X";xBut.href="#";xBut.onclick=function(){self.close();return false;}
var clearBut=document.createElement("a");clearBut.innerHTML="Clear ("+this.accessKeyText+"-C)";clearBut.accessKey="C";clearBut.className="JashButton";clearBut.onclick=function(){self.clear();return false;}
this.setCrossBrowserAccessKeyFunctionForAnchor(clearBut);var evalBut=document.createElement("a");evalBut.value="Evaluate ("+this.accessKeyText+"-Z)";evalBut.innerHTML="Evaluate ("+this.accessKeyText+"-Z)";evalBut.accessKey="Z";evalBut.className="JashButton";evalBut.title="Evaluate current input ("+this.accessKeyText+"-Z)";evalBut.onclick=function(){self.evaluation.evaluate(inp.value);if(!self.evaluation.cssEvalFlag){inp.value="";}
inp.focus();return false;}
this.setCrossBrowserAccessKeyFunctionForAnchor(evalBut);var helpBut=document.createElement("a");helpBut.innerHTML="Help";helpBut.className="JashButton";helpBut.title="Help: show list of commands (or type jash.help(); )";helpBut.onclick=function(){self.help();}
var domBut=document.createElement("a");domBut.innerHTML="Mouseover DOM ("+this.accessKeyText+"-X)";domBut.title="Mouseover DOM: toggle to turn on/off inspection of document nodes ("+this.accessKeyText+"-X)";domBut.className="JashButton";domBut.accessKey="X";domBut.tabIndex="4";this.domActive=false;domBut.onclick=function(){if(!self.domActive){document.body.onmouseover=function(e){if(typeof e=="undefined"){e=window.event;}
self.showNodes(e);}
self.setButtonVisualActiveState(domBut,"on");self.domActive=true;}else{document.body.onmouseover=function(){}
self.domActive=false;self.setButtonVisualActiveState(domBut,"off");}
return _null;}
this.setCrossBrowserAccessKeyFunctionForAnchor(domBut);var innerHtmlInspectBut=document.createElement("a");innerHtmlInspectBut.innerHTML="innerHTML Dump ("+this.accessKeyText+"-A)";innerHtmlInspectBut.title="innerHTML Inspect: toggle to turn on/off innerHTML inspection of document nodes ("+this.accessKeyText+"-A)";innerHtmlInspectBut.className="JashButton";innerHtmlInspectBut.accessKey="A";innerHtmlInspectBut.tabIndex="5";this.innerHtmlInspection=false;innerHtmlInspectBut.onclick=function(){self.innerHtmlInspection=!self.innerHtmlInspection;self.setButtonVisualActiveState(innerHtmlInspectBut,self.innerHtmlInspection?"on":"off");return _null;}
this.setCrossBrowserAccessKeyFunctionForAnchor(innerHtmlInspectBut);var cssBut=document.createElement("a");cssBut.innerHTML="CSS Input ("+this.accessKeyText+"-S)";cssBut.title="CSS Input: turn on CSS input to enter arbitrary CSS ("+this.accessKeyText+"-S)";cssBut.className="JashButton";cssBut.accessKey="S";cssBut.onclick=function(){if(!self.evaluation.cssEvalFlag){self.setButtonVisualActiveState(cssBut,"on");self.evaluation.cssEvalFlag=true;inp.className="cssEntry";if(document.getElementById("JashStyleInput")!=null){self.evaluation.styleInputTag.disabled=false;}
inp.value="";}else{self.setButtonVisualActiveState(cssBut,"off");inp.className="";self.evaluation.cssEvalFlag=false;if(document.getElementById("JashStyleInput")!=null){self.evaluation.styleInputTag.disabled=true;}
inp.value="";}
inp.focus();return _null;}
this.setCrossBrowserAccessKeyFunctionForAnchor(cssBut);var resizeBut=document.createElement("div");resizeBut.id="JashResizeButton";this.minDims={x:100,y:100};resizeBut.onmousedown=function(e){e=(typeof window.event!="undefined")?window.event:e;var originalDims=self.getDimensions(textareaWrap);var originMouseDims=self.getMouseXY(e);document.onmousemove=function(e){var newMouseDims=self.getMouseXY(e);var newWidth=originalDims.x+(newMouseDims.x-originMouseDims.x);if(newWidth<self.minDims.x){newWidth=self.minDims.x;}
textareaWrap.style.width=newWidth+"px";debugParent.style.width=newWidth+"px";var newHeight=originalDims.y+(newMouseDims.y-originMouseDims.y);if(newHeight<self.minDims.y){newHeight=self.minDims.y;}
textareaWrap.style.height=newHeight+"px";debugParent.style.height=newHeight+"px";}
document.onmouseup=function(){document.onmousemove="";}}
var bottomBar=document.createElement("div");bottomBar.id="JashBottomBar";debugParent.appendChild(dragBut);debugParent.appendChild(xBut);bottomBar.appendChild(evalBut);bottomBar.appendChild(cssBut);bottomBar.appendChild(domBut);bottomBar.appendChild(innerHtmlInspectBut);bottomBar.appendChild(clearBut);bottomBar.appendChild(helpBut);debugParent.appendChild(bottomBar);debugParent.appendChild(resizeBut);document.body.appendChild(debugParent);textareaWrap.appendChild(debugOutput);textareaWrap.appendChild(inp);debugParent.appendChild(textareaWrap);this.bottomBar=document.getElementById("JashBottomBar");this.dragBar=document.getElementById("JashDragBar")
this.output=document.getElementById("JashOutput");this.input=document.getElementById("JashInput");this.mainBlock=debugParent;this.addEvent(window,'scroll',function(){debugParent.style.top=50+self.getXBrowserYOffset()+'px';});}
this.setButtonVisualActiveState=function(button,state){if(state=="on"){button.style.backgroundColor="lightgreen";}else{button.style.backgroundColor="";}}
this.help=function(){var out=new Array();out.push(line);out.push("Jash v"+this.version+" "+this.versionDate.replace(/\$/g,''),true);out.push("http://www.billyreisinger.com/jash/documentation.html");out.push(line);out.push("METHODS");out.push(line);out.push("this.cls() - clear console and terminal");out.push("jash.print(str,clear) - output str to console ~~ str = string ~~ clear = true|false: clear console before output");out.push("this.close() - close this console");out.push("this.dump(obj) - output object and members to console");out.push("this.show(obj) - print out the names and types (only) of all members of obj");out.push("this.stopWatch.start() - start timer");out.push("this.stopWatch.stop() - end timer and return result in ms");out.push("this.kill(HTML Element) - remove an element from the page.");out.push("this.getDimensions(HTML Element) - get width, height dimensions of an html element. Returns an object [x,y]");out.push(line);out.push("KEYSTROKES");out.push(line);out.push("press up arrow in input field to retrieve last input");out.push("press ESC to show/hide console");out.push("press "+this.accessKeyText+"-Q to turn on/off Transparent mode, so you can see through the Jash.");out.push("press ENTER in input field to enter a command");out.push("press TAB to auto-complete input");out.push("press "+this.accessKeyText+"-Z to evaluate input");out.push("press "+this.accessKeyText+"-X to activate/deactivate DOM inspector");out.push("press "+this.accessKeyText+"-A to activate/deactivate innerHTML dump (only works w/ DOM inspector)");out.push("press "+this.accessKeyText+"-C to clear output and input");out.push("press "+this.accessKeyText+"-S to turn on/off CSS input mode. In CSS input mode, you can enter arbitrary CSS selectors and rules, as you would normally do in a CSS stylesheet.");this.print(out.join("\n"));return _null;}
this.close=function(){if(this.mainBlock.style.display=="none"){this.mainBlock.style.display="block";this.input.focus();}else{this.mainBlock.style.display="none";}}
this.setCrossBrowserAccessKeyFunctionForAnchor=function(el){var self=this;el.tabIndex=++this.tabIndexIndex;if(this.browser=="ie"){el.onfocus=function(){if(window.event.altKey){el.onclick();}
self.input.focus();}}}
this.stopWatch={t_start:0,t_end:0,t_total:0,start:function(){t_start=new Date().getTime();return t_start;},stop:function(){t_end=new Date().getTime();t_total=t_end-t_start;return(t_total);}}
this.showNodes=function(e){if(typeof e=="undefined")e=window.event;var el=typeof e.target=="undefined"?e.srcElement:e.target;this.currentNode=el;var childMost=this.identifyNode(el,false);var out="";var childmostTxt="childmost..... "+childMost.txt+"\n";while(el=el.parentNode){if(el.nodeName.toLowerCase()=="html"){out="parentmost.... <html>\n"+out;break;}
out=this.identifyNode(el).txt+"\n"+out;}
out="**** PRESS "+this.accessKeyText+"-X TO PAUSE / UNPAUSE ****\n"+out;out+=childmostTxt;this.print(out,true,true,false);if(this.innerHtmlInspection){this.print("INNER HTML");if(this.currentNode.innerHTML.indexOf("<")!=-1){this.print(Jash.Indenter.indent(this.currentNode.innerHTML),false,true,false);}else{this.print(this.currentNode.innerHTML,false,true,false);}}
if(!this.evaluation.cssEvalFlag){if(childMost.id!=""){if(typeof $!="undefined"){this.input.value='$("'+childMost.id+'")';}else{this.input.value='document.getElementById("'+childMost.id+'")';}}else{this.input.value="this.currentNode";}}}
this.identifyNode=function(el,showDots){showDots=typeof showDots=="boolean"?showDots:true;var out={txt:"",id:""};if(showDots)out.txt+=".............. ";out.txt+="<"+el.nodeName.toLowerCase();for(var i=0;i<el.attributes.length;i++){if((this.browser=="ie"&&el.attributes[i].specified===true)||this.browser!="ie"){out.txt+=" "+el.attributes[i].name;out.txt+="=\""+el.attributes[i].value+"\"";}}
out.txt+=">";return out;}
this.kill=function(){this.currentNode.parentNode.removeChild(this.currentNode);}}
Jash.Evaluator=function(){this.cssEvalFlag=false;var _null="nooutput";this.evaluate=function(input){if(input=="")return false;this.history.add(input);if(this.cssEvalFlag){this.evalCss(input);this.print(input);}else{var output=this.evalJs(input);if(typeof output!="undefined"){this.print(">> "+input);this.print(output);}}}
this.evalJs=function(input){try{var result;if(this.browser=="ie"){result=eval(input);}else{result=window.eval(input);}
if(result!=null&&result.toString()!=_null){return(result.toString());}else{return"null"}}catch(e){return(e.message);}}
this.evalCss=function(input){try{this.insertStyleRule(input);}catch(e){}
return input;}
this.insertStyleRule=function(rule){var lastStyleSheetIndex=document.styleSheets.length-1;if(document.getElementById("JashStyleInput")==null){this.styleInputTag=document.createElement("style");this.styleInputTag.id="JashStyleInput";this.styleInputTag.type="text/css";document.body.appendChild(this.styleInputTag);}
if(this.browser=="ff"||this.browser=="op"){this.styleInputTag.innerHTML+=rule+"\n";}else if(this.browser=="ie"||this.browser=="sa"){if(this.browser=="ie"){var i=0;}else if(this.browser="sa"){var i=document.styleSheets.length-1;}
var rulesArray=rule.split("}");for(var t=0;t<rulesArray.length;t++){var ruleSplit=rulesArray[t].split("{");var selectors=ruleSplit[0].split(",");for(var k=0;k<selectors.length;k++){document.styleSheets[i].addRule(selectors[k],ruleSplit[1]);}}}
return"";}
return this;}
Jash.History=function(){this.entries=new Array('');this.position=0;}
Jash.History.prototype={add:function(input){this.entries.push(input);this.position=this.entries.length-1;},getPreviousInput:function(){if(this.position<0){return'';}
var entry=typeof this.entries[this.position]!="undefined"?this.entries[this.position]:'';if(this.position>0){this.position--;}
return entry;},getNextInput:function(){if(this.position+1<this.entries.length){return this.entries[++this.position];}else{return'';}}}
Jash.Indenter={indentChar:"\t",nodesCommonlyUnclosed:new Array("link ","img ","meta ","!DOCTYPE ","input ","param","hr","br"),stringRepeat:function(stringToRepeat,times){var string=new Array();for(var i=0;i<times;i++){string.push(stringToRepeat);}
return string.join('');},closeUnclosedNode:function(str){for(var k=0;k<this.nodesCommonlyUnclosed.length;k++){var reg=new RegExp("^"+this.nodesCommonlyUnclosed[k].toLowerCase());if(str.toLowerCase().match(reg)){return str.replace(">","/>");}}
return str;},indentAndAdd:function(level,string,arr){var indents=this.stringRepeat(this.indentChar,level);arr.push(indents+string);return arr;},indent:function(source){var source=source;var arr=new Array();source=source.replace(/[\n\r\t]/g,'');source=source.replace(/>\s+/g,">");source=source.replace(/\s+</g,"<");var splitsrc=source.split("<");for(i=0;i<splitsrc.length;i++){splitsrc[i]=this.closeUnclosedNode(splitsrc[i]);}
source=splitsrc.join("<");var level=0;var sourceLength=source.length;var position=0;while(position<sourceLength){if(source.charAt(position)=='<'){var startedAt=position;var tagLevel=1;if(source.charAt(position+1)=='/'){tagLevel=-1;}
if(source.charAt(position+1)=='!'){tagLevel=0;}
while(source.charAt(position)!='>'){position++;}
if(source.charAt(position-1)=='/'){tagLevel=0;}
var tagLength=position+1-startedAt;if(tagLevel===-1){level--;}
arr=this.indentAndAdd(level,source.substr(startedAt,tagLength),arr);if(tagLevel===1){level++;}}
if((position+1)<sourceLength){if(source.charAt(position+1)!=='<'){startedAt=position+1;while(source.charAt(position)!=='<'&&position<sourceLength){position++;}
if(source.charAt(position)==='<'){tagLength=position-startedAt;arr=this.indentAndAdd(level,source.substr(startedAt,tagLength),arr);}}else{position++;}}else{break;}}
return arr.join("\n");}}
Jash.Profiler=function(func,onFinish){this.func=func;this.time=0;this.defaultOnFinish=function(){};this.results=new Array();this.onFinish=typeof onFinish!="function"?this.defaultOnFinish:onFinish;var self=this;this.reverseWhile=function(reps){this.stopWatch.start();while(reps>0){this.func();reps--;}
return this.stopWatch.stop();}
this.forLoop=function(reps){this.stopWatch.start();for(i=0;i<reps;i++){this.func();}
return this.stopWatch.stop();}
this.loop=function(kind,reps){if(!this.results[kind]){this.results[kind]=new Array();}
var repsMemberName="r_"+reps;if(!this.results[kind][repsMemberName]){this.results[kind][repsMemberName]=new Array();}
var time=this[kind](reps);this.results[kind][repsMemberName].push(time);}
this.runOnce=function(){if(!this.results.runOnce){this.results.runOnce=new Array();}
this.stopWatch.start();func();this.results.runOnce.push(this.stopWatch.stop());}
this.stopWatch={t_start:0,t_end:0,t_total:0,start:function(){t_start=new Date().getTime();return t_start;},stop:function(){t_end=new Date().getTime();t_total=t_end-t_start;self.time=t_total;return t_total;}}
this.average=function(arr){var sum=0;for(i=0;i<arr.length;i++){sum+=arr[i];}
return sum/arr.length}
this.multiPass=function(passes,type,reps){if(typeof type=="undefined"){type="runOnce";}else if(typeof this[type]=="undefined"){jash.print("Error: the loop type '"+type+"' does not exist");return false;}
var self=this;if(type=="runOnce"){if(passes<1){self.reportProfile(Math.round(this.average(this.results.runOnce)),type,reps);}else{window.setTimeout(function(){self.runOnce();self.multiPass(--passes,type);},50);}}else{if(passes<1){var repsMemberName="r_"+reps;self.reportProfile(Math.round(this.average(this.results[type][repsMemberName])),type,reps);}else{window.setTimeout(function(){self.loop(type,reps);self.multiPass(--passes,type,reps);},50);}}}
this.reportProfile=function(avgMs,type,reps){var line="-------PROFILER----------------------------------------------";var str=line+"\n"+this.func+"\n"+line+"\n";str+="Type of profile: "+type+"\n";if(typeof reps!="undefined"){str+="Loop iterations: "+reps+"\n";}
str+="Average execution time: "+avgMs+"ms"+"\n";if(type=="runOnce"){howManyTimes=this.results.runOnce.length;}else{repsMemberName="r_"+reps;howManyTimes=this.results[type][repsMemberName].length;}
str+="Average calculated from "+howManyTimes+" pass(es)\n";str+=line+"\n";jash.print(str);}}
Jash.TabComplete=function(){this.tabComplete=function(e){e=(typeof window.event!="undefined")?window.event:e;var inputText=this.input.value;var match=null;if(match=this.searchInputForDomGetElFunctions(inputText)){this.tabCompleteIdOrClassInJavascript(match.match[0],match.type);this.focusCaretAtEndOfInput();return false;}else if(this.evaluation.cssEvalFlag){this.tabCompleteIdOrClassInCss(inputText);this.focusCaretAtEndOfInput();return false;}else{this.tabCompleteJavascript(e,inputText);this.focusCaretAtEndOfInput();}}
this.focusCaretAtEndOfInput=function(){this.input.selectionEnd=this.input.selectionStart=this.input.value.length;}
this.tabCompleteJavascript=function(e,inputText){var words=inputText.split(/\s+/);var lastWord=words[(words.length-1)];var numOpeningParens=lastWord.split("(").length-1;var numClosingParens=lastWord.split(")").length-1;var scope;var sentinel=0;var diff=numOpeningParens-numClosingParens;if(diff>0){numClosingParens=lastWord.split("(")[numOpeningParens].split(")").length-1;var numRealDanglers=numOpeningParens-numClosingParens;scope=lastWord.split("(").slice(numRealDanglers).join("(");}else if(diff<0){this.print("error: too many closing parentheses");return false;}else{scope=lastWord;}
scope=scope.split(".");var fragment=scope.pop();scope=scope.join(".");if(scope=="")scope="window";var members=this.getMembers(scope);var results=this.findTextMatchesInArray(members,fragment);if(results==false){}else if(typeof results!="string"){this.dump(results);var bestMatch=this.findBestStringMatch(fragment,results);if(fragment!=''){fragReg=new RegExp(fragment+"$");this.input.value=this.input.value.replace(fragReg,bestMatch);}else{this.input.value+=bestMatch;}}else{var reggie=new RegExp(fragment+"$");this.input.value=this.input.value.replace(reggie,results);}
return false;}
this.doAllStringsInArrayHaveSameCharacterAtIndex=function(index,arr){var matched=0;if(!arr[0].charAt(index))return false;var character=arr[0].charAt(index);for(var i=1;i<arr.length;i++){if(!arr[i].charAt(index)||arr[i].charAt(index)!=character){return false;}}
return true;}
this.findBestStringMatch=function(str,arr){var fragLength=str.length;var matches=this.doAllStringsInArrayHaveSameCharacterAtIndex(fragLength,arr);while(matches){fragLength++;matches=this.doAllStringsInArrayHaveSameCharacterAtIndex(fragLength,arr);}
return arr[0].substr(0,fragLength);}
this.tabCompleteIdOrClassInJavascript=function(inputText,type){var query=inputText.split("(");query=query[query.length-1].replace(/\W/g,'');var matches=new Array();var els=document.getElementsByTagName("*");if(type=="id"){for(var i=0;i<els.length;i++){if(els[i].id&&els[i].id.indexOf(query)==0){matches.push(els[i].id);}}}else if(type=="class"){for(var i=0;i<els.length;i++){if(els[i].className&&els[i].className!=''){var classes=els[i].className.split(/\s/);for(var ii=0;ii<classes.length;ii++){if(classes[ii].indexOf(query)==0||query==''){if(matches.join("***").indexOf(classes[ii])==-1){matches.push(classes[ii]);}}}}}}
if(matches.length==1){this.input.value+=matches[0].split(query)[1];}else if(matches.length==0){this.print("no match");}else{this.dump(matches.sort());var bestMatch=this.findBestStringMatch(query,matches);if(query!=''){var replacement=inputText.split("(");replacement[replacement.length-1]=replacement[replacement.length-1].replace(query,bestMatch);this.input.value=this.input.value.replace(inputText,replacement.join("("));}else{this.input.value+=bestMatch;}}}
this.tabCompleteIdOrClassInCss=function(inputText){var selectors=inputText.replace(/(\.|#)/g,' $1').split(/\s+/);var lastSelector=selectors[selectors.length-1];var els=document.getElementsByTagName("*");var matches=new Array();if(lastSelector.match(/^\./)){for(var i=0;i<els.length;i++){if(els[i].className&&els[i].className!=''){var classes=els[i].className.split(/\s/);for(var ii=0;ii<classes.length;ii++){if(classes[ii].indexOf(lastSelector.substr(1))==0||lastSelector=="."){if(matches.join("***").indexOf(classes[ii])==-1){matches.push("."+classes[ii]);}}}}}}else if(lastSelector.match(/^#/)){for(var i=0;i<els.length;i++){if(els[i].id&&els[i].id.indexOf(lastSelector.substr(1))==0){matches.push("#"+els[i].id);}}}
if(matches.length==1){this.input.value+=matches[0].split(lastSelector)[1];}else if(matches.length==0){this.print("no match");}else{this.dump(matches.sort());var bestMatch=this.findBestStringMatch(lastSelector,matches);if(lastSelector!=''){this.input.value=this.input.value.replace(lastSelector,bestMatch);}else{this.input.value+=bestMatch;}}}
this.searchInputForDomGetElFunctions=function(inputText){for(var i=0;i<this.domGetElFunctions.id.length;i++){var selfct=new RegExp(this.domGetElFunctions.id[i].replace("\$","\\\$")+"\\\(['\"]\\w*$");if(inputText.match(selfct)){return{match:inputText.match(selfct),type:"id"};}}
for(var i=0;i<this.domGetElFunctions.className.length;i++){var selfct=new RegExp(this.domGetElFunctions.className[i].replace("\$","\\\$")+"\\\(['\"]\\w*$");if(inputText.match(selfct)){return{match:inputText.match(selfct),type:"class"};}}}
this.findTextMatchesInArray=function(arrayToTest,findMe){var resultsArray=new Array();var tester=new RegExp("^"+findMe);for(var i=0;i<arrayToTest.length;i++){if(tester.test(arrayToTest[i])){resultsArray.push(arrayToTest[i]);}}
if(resultsArray.length>1){resultsArray.sort();return resultsArray;}else if(resultsArray.length==1){return resultsArray[0];}else{return false;}}
this.getMembers=function(context){var members=new Array();for(memberName in eval(context)){members.push(memberName);}
return members;}
return this;}

// ELS 12/12/2007: init is deferred until first time panel is shown
window.toggleJash=function() // show/hide panel...
	{ if("jash" in window)window.jash.close();else{window.jash=new Jash();window.jash.main();} }
window.isJashVisible=function() // so scripts can find out the current display state
	{ return window.jash?window.jash.mainBlock.style.display!="none":false; }
addEvent(document,"keydown",function(ev){ // SHIFT-ESC shows/hides panel, ESC hides panel
	var e=(typeof window.event!="undefined")?window.event:ev;
	if(e.keyCode=="27"&&(e.shiftKey||window.isJashVisible())) window.toggleJash(); });
//}}}
<html><hide linebreaks><a href="javascript:;" class="button"
	title='JASH: Javascript Shell - view/modify internal run time variables and functions!'
	onclick="if (window.toggleJash) toggleJash(); return false;"
	onmouseover="this.href='javascript:void(eval(decodeURIComponent(%22(function(){try{('
		+encodeURIComponent(encodeURIComponent(this.onclick))
		+')()}catch(e){alert(e.description?e.description:e.toString())}})()%22)))';">
	$1
</a></html>
~JaSH is a Javascript Shell written by Billy Reisinger, and provides a cross-browser compatible interactive javascript development and debugging tool.

This package includes a whitespace-compressed version of the Jash source code ([[Jash.js]]), accompanied by the appropriate stylesheet definitions necessary to render the Jash interface ([[Jash.css]]).  Additionally, [[JashCommand]] provides a simple ~HTML-based command link that toggles the display of the Jash interface with a single click.
[>img[Creative Commons Attribution-ShareAlike 3.0 License|images/somerights20.png][http://creativecommons.org/licenses/by-sa/3.0/]]''Copyrights:''
<<<
This work is based upon TiddlyWiki <<version>>, created by Jeremy Ruston, &copy; 2004-2009 [[UnaMesa Association|http://www.unamesa.org/]].  Modifications and additions to this work, including (but not limited to) original programmatic components ("plugins", "macros", "scripts", "stylesheets") have been created by Eric L. Shulman and/or ELS Design Studios.

These components are distributed using an ''open source'' model; however, they are ''not in the public domain, and the author retains all applicable rights''.  You //are// permitted to ''use, copy, and/or modify'' individual components of this work, subject to the licensing terms and conditions specifically included within or referenced by those individual components, as well as other terms, conditions, instructions, and guidelines included herein, as well as all terms and conditions defined by the [[Creative Commons Attribution-ShareAlike 3.0 License|http://creativecommons.org/licenses/by-sa/3.0/]].

This work may contain portions of copyrighted materials from other sources.  In accordance with "fair use" principles (see [[United States Copyright Law, Title 17, Section 107|http://www.copyright.gov/title17/92chap1.html#107]]), such materials have been reproduced without profit for purposes of criticism, comment, news reporting, instruction, scholarship, and/or research.  ''All other original content, including (but not limited to) writings, images, and audio/video recordings, are the property of Eric L. Shulman and/or ELS Design Studios, or are used under license or agreement with third parties'' and, except as required for normal viewing of this work, may not be stored, displayed or re-transmitted in any form, nor used for any commercial purposes, without prior permission from the respective rights holders.

This work includes or refers to icons that from the [[Silk icon set|http://www.famfamfam.com/lab/icons/silk/ ]] of 16-by-16 pixel icons in PNG format, created by Mark James, and is licensed under a Creative Commons Attribution 2.5 License. Please visit http://www.famfamfam.com/ for further information and licensing details.
<<<
''Terms of use:''
<<<
This work contains ''individual components that are intended to be selectively copied and installed'' into your own TiddlyWiki files in order to enhance and customize those documents.  You may ''download and save this work for use only as a //local// resource'' to assist you in developing your //own// TiddlyWiki document designs.  However, you may not re-distribute this document in it's entirety, nor re-use it's overall design without prior written permission.

Tiddlers can be imported from any TiddlyWiki document.  As a consequence, if you share your document with even just ONE other person, you become a "re-distributor" of the tiddlers contained in that document.  As such, ''you should avoid modifying any TiddlyTools components you have installed in your own documents'' unless there is a compelling, //functional// reason to do so and, even then, ''the best approach is often to simply submit a feature request'' to the original author/publisher and leave it up to them to determine the best way to modify and re-publish those components.

Nonetheless, if you //do// modify and/or share components of this work, you should ''always retain the original published content within those components'', including all documentation, credits, licensing information, and URL references to the official distribution source for the unaltered versions of those components.  In addition, ''all modified components must be clearly identifiable as derivative works'' that have been differentiated from the original versions by renaming those components, as well as adding inline comments and a "revision history" to document specific changes.

If you share a modified TiddlyTools component, you must be prepared to support it.  All ''problems that occur within a modified component should be reported first directly to the provider of that modified component'', and then only reported to TiddlyTools if it can be shown that the problem also occurs in TiddlyTools' officially-published version of the component.  Any ''problems that are reported for //undifferentiated// modifications won't receive help from TiddlyTools'' (once they are determined to be modified, of course!), other than to direct the inquiry to wherever they got the modified components from in the first place.

Except for officially-published links to specific components of this work, ''you must not create or share deep links'' to online components of this work (e.g., images, audio, video, etc.).  Instead, you should copy the desired components (subject to applicable licenses and copyrights) to your own system or online hosting service, and ensure that your document contains references to //those// copies.
<<<
''Trademarks/servicemarks:''
<<<
"ELS Design Studios", "~TiddlyTools", "~TiddlyStudios", "~TiddlyTech", "~TiddlyLabs", "Small Tools for Big Ideas!", "Intuitive Interfaces for Intelligent Interactions" and the "i4" logo (in graphical //and// text forms) are trademarks or servicemarks of ELS Design Studios and may not be used without permission.  Limited use of "ELS Design Studios" and "~TiddlyTools" marks in other works is granted for attribution purposes only.  Such use does not create or imply any endorsement, agency or partner relationship with Eric L. Shulman and/or ELS Design Studios, nor with any designated representatives, agents, or heirs thereof.
<<<
''Limits on Liability:''
<<<
All materials are presented on an "as-is" basis and are subject to change without notice.  The author of this document makes no claims regarding the suitability or reliability of the information presented, and assumes no liability for any damages that may occur as a result of its use.
<<<
''Privacy Notice: ''
<<<
This site limits the collection and use of non-public, personal customer information to that which is needed to offer products and services, and to file reports or financial statements as required by law. This site has physical, electronic and procedural safeguards to maintain the protections of private information, and does not provide, sell or otherwise disclose such information to non-affiliated third parties.
<<<
@@display:block;text-align:center;^^//please review these statements periodically, as they are subject to change without notice//^^@@
/***
|Name|Let's Get Tanked!|
|Source|http://www.TiddlyTools.com/#Let's Get Tanked!|
|Version||
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|CSS|
|Description|theme: dark blue fishtank photo background|
|StyleSheet|Let's Get Tanked!|
|PageTemplateReadOnly|PageTemplateReadOnly|
|EditTemplateReadOnly|EditTemplateReadOnly|
***/

[[StyleSheetAdjustments]]
[[BrightText]]
/* ==== Let's Get Tanked! ==== */
/*{{{*/
body
	{ background-image: url('[[LetsGetTankedBackground]]'); background-attachment: fixed; background-color:#113; }
.menubox
	{ background: #003; border:1px solid; -moz-border-radius:1em;-webkit-border-radius:1em; padding:1em }
.annotation
	{ background-color: #003; }
.viewer
	{ background: #003; border:1px solid; -moz-border-radius:1em;-webkit-border-radius:1em; padding:1em; opacity:0.8; filter:'alpha(opacity:80)'; }
#tiddlerWelcome .tabContents
	{ opacity:0.9; filter:'alpha(opacity:90)'; }
.header
	{ background-image: none; background-color:transparent; color:#ccf; border:0; }
.floatingPanel, .attachPanel, #importPanel, #exportPanel,
	{ background: #eef; }
.floatingPanel a, .attachPanel a, #importPanel a, #exportPanel a, #sidebarTabs .tabContents a,
.floatingPanel .button, .attachPanel .button, #importPanel .button, #exportPanel .button, #sidebarTabs .tabContents .button,
.floatingPanel .tiddlyLinkExisting, .attachPanel .tiddlyLinkExisting, #importPanel .tiddlyLinkExisting, #exportPanel .tiddlyLinkExisting, #sidebarTabs .tabContents .tiddlyLinkExisting
	{ color:#009; }
.siteMenu .floatingPanel, #messageArea 
	{ background: #eef; }
.tiddlyCard { background:#ffd; }
.viewer h1,.viewer h2,.viewer h3,.viewer h4,.viewer h5 { background: #666; color:#fff; }
.viewer .tabContents, #sidebarTabs .tabContents
	{ background-color:#002; }
.tabContents a, .tabContents .button, .tabContents .tiddlyLinkExisting
	{ color:#99f; }
/*}}}*/
!usage
{{{[img[Let's Get Tanked! Background]]}}}
[img[Let's Get Tanked! Background]]
!notes
&copy; 2002 ELS Design Studios - do not copy without prior explicit permission
!type
image/jpg
!file
./images/fish.jpg
!url
http://www.TiddlyTools.com/images/fish.jpg
!data
/%
|''URL:''|http://tiddlywiki.squize.org/|
|''Description:''|a repository of my extensions for TW|
|''Author:''|SaqImtiaz|
%/
/***
|Name|ListboxPlugin|
|Source|http://www.TiddlyTools.com/#ListboxPlugin|
|Documentation|http://www.TiddlyTools.com/#ListboxPluginInfo|
|Version|1.4.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|set custom field or tiddler tags by selecting from listbox/droplist|
The {{{<<select>>}}} macro allows you to set tiddler field values by selecting pre-configured values from a listbox/droplist control.  
!!!!!Documentation
>see [[ListboxPluginInfo]]
!!!!!Revisions
<<<
2010.03.14 1.4.1 use filterTiddlers() instead of getTaggedTiddlers() - use MatchTagsPlugin for tag expressions
|please see [[ListboxPluginInfo]] for additional revision details|
2007.05.12 0.5.0 started
<<<
!!!!!Code
***/
//{{{
version.extensions.ListboxPlugin= {major: 1, minor: 4, revision: 1, date: new Date(2010,3,14)};

config.macros.select = {
	tooltip: "select a value for %0@%1",
	blankTooltip: "set %0@%1=[no value]",
	valueTooltip: "set %0@%1=%2",
	otherLabel: "other",
	otherTooltip: "set %0@%1=[enter a value...]",
	otherPrompt: "enter a value for '%0'",
	editLabel: "edit list...",
	editTooltip: "edit '%0' list definition (%1)",
	changeMsg: "setting %0@%1=%2",
	verbose: false,
	hereKeyword: "here",
	defaultTarget: "SiteFields",
	handler:
	function(place,macroName,params,wikifier,paramString,tiddler) {

		// default to containing tiddler or "SiteFields" catch-all
		var here=story.findContainingTiddler(place);
		var targetID=here?here.getAttribute("tiddler"):this.defaultTarget;

		// get field name and non-default target (if any)
		var field=params.shift();
		var pos=field.indexOf("@"); // if non-default target ("field@tiddler" syntax)
		if(pos!=-1) { // split field into field and tiddlername.
			if (field.substr(pos+1)!=this.hereKeyword) // "here" == use default target
				targetID=field.substr(pos+1); // use different target tiddler
			field=field.substr(0,pos);
		}
		if(!field || !field.length) return; // no field name... do nothing
		if (field.substr(0,1)=="=") targetID="(system)"; // internal option value

		var items=[]; var listsrc='';
		var autosave=false; var allowBlank=false; var allowOther=false; var allowEdit=false;
		var allowMultiple=false; var wikifyData=false; var rows=0; var width='';
		var p=params.shift();
		while (p) {
			if (p.toLowerCase()=='autosave')	// autosave on change
				autosave=true;
			else if (p.toLowerCase()=='allowblank')	// add empty item
				var allowBlank=true;
			else if (p.toLowerCase()=='allowother')	// add "other: ____" item
				var allowOther=true;
			else if (p.toLowerCase()=='allowedit')	// add "edit list..." item
				var allowEdit=true;
			else if (p.toLowerCase()=='allowmultiple') // multi-select
				var allowMultiple=true;
			else if (p.startsWith('rows:')) // 0=autosize listbox, 1=droplist, n=listbox
				var rows=p.substr(5);
			else if (p.startsWith('width:')) // CSS width of list
				var width=p.substr(6);
			else if (p.startsWith('prompt:')) // prompt text (1st item in list)
				var ptext=p.substr(7);
			else if (p.substr(0,1)=="+"||p.substr(0,1)=="*") { // read HR-separated tiddler
				var listsrc=p.substr(1);
				var listtxt=store.getTiddlerText(listsrc,'');
				var wikifyData=p.substr(0,1)=="*";
				if (listtxt.length && wikifyData) // wikify source to handle macros/scripts
					listtxt=this.getWikifiedData(listtxt);
				if (listtxt.length)
					items=items.concat(listtxt.split(listtxt.indexOf('\n----\n')!=-1?'\n----\n':'\n'));
			}
			else if (p.startsWith("=")) { // get items from tagged tiddlers
				var filter=p.substr(1);
				if (!filter.startsWith('[')) filter='[tag['+filter+']]';
				var tids=store.filterTiddlers(filter);
				for (var t=0; t<tids.length; t++) items.push(tids[t].title);
			}
			else { // param is item value or 'label=value'
				var parts=p.split("=");
				var label=parts[0]; var v=parts[1]?parts[1]:parts[0];
				items.push(label+"="+v);
			}
			p=params.shift();
		}
		if (rows==1) allowMultiple=false; // droplist cannot do multi-select
		if (tiddler && !story.isDirty(tiddler.title)) autosave=true; // tiddler is in VIEW mode, force autosave

		this.render(createTiddlyElement(place,"span"), null,
			targetID, field, ptext, items, listsrc, wikifyData,
			rows, width, autosave, allowBlank, allowOther, allowEdit, allowMultiple);

		store.addNotification(null,this.refresh); // syncs lists when tiddlers are changed
	},
	getWikifiedData: // wikify tiddler content, then extract text WITH newlines and HRs included
	function(txt) {
		var e=createTiddlyElement(document.body,"div"); wikify(txt,e);
		var breaks=e.getElementsByTagName("br");
		for (var b=0; b<breaks.length; b++) breaks[b].parentNode.insertBefore(document.createTextNode("\n"),breaks[b]);
		var lines=e.getElementsByTagName("hr");
		for (var l=0; l<lines.length; l++) lines[l].parentNode.insertBefore(document.createTextNode("----\n"),lines[l]);
		var items=e.getElementsByTagName("li");
		for (var i=0; i<items.length; i++) items[i].parentNode.insertBefore(document.createTextNode("\n"),items[i]);
		var txt=getPlainText(e); removeNode(e); return txt;
	},
	refresh:
	function (title) { // re-render dependent lists
		var lists=document.getElementsByTagName('select');
		for (var i=0; i<lists.length; i++) { var list=lists[i];
			if (list.getAttribute('listsrc')!=title) continue; // no sync needed
			var listtxt=store.getTiddlerText(list.getAttribute('listsrc')||'','');
			if (listtxt.length && list.getAttribute("wikifyData")=="true")
				listtxt=this.getWikifiedData(listtxt);
			if (listtxt.length)
				var items=listtxt.split(listtxt.indexOf('\n----\n')!=-1?'\n----\n':'\n');
			config.macros.select.render(list.parentNode, list,
				list.getAttribute('tiddler'),
				list.getAttribute('edit'),
				list.getAttribute('ptext'),
				items||[],
				list.getAttribute('listsrc'),
				list.getAttribute("wikifyData")=="true",
				list.getAttribute("rows"),
				list.getAttribute("width"),
				list.getAttribute("autosave")=="true",
				list.getAttribute("allowBlank")=="true",
				list.getAttribute("allowOther")=="true",
				list.getAttribute("allowEdit")=="true",
				list.getAttribute("allowMultiple")=="true");
		}
	},
	render:
	function (place, here, targetID, field, ptext, items, listsrc, wikifyData,
		rows, width, autosave, allowBlank, allowOther, allowEdit, allowMultiple) {

		var values=[]; var opts=[];

		// use current selection(s) (if any) (except for "edit list..." item)
		if (here) for (var i=0; i<here.options.length; i++) {
			var opt=here.options[i];
			if (opt.selected && opt.text!=config.macros.select.editLabel) values.push(opt.value);
		}
		// no listbox or no selections... get value(s) from field (if any)
		if (!values.length) {
			var v=(field.substr(0,1)=='=')?config.options[field.substr(1)]:store.getValue(targetID,field);
			if (v) values=(field=='tags'||allowMultiple)?v.readBracketedList():[v];
		}
		// add prompt item
		if (ptext&&ptext.length)
			opts.push('<option value="_ptext" title="">'+ptext+'</option>');
		// add 'no value' item
		if ((!allowMultiple && !values.length) || allowBlank)
			opts.push('<option value="" title="'+this.blankTooltip.format([field,targetID])+'"></option>');
		// add enumerated items
		var isOther=values.length; // assume no matching value
		for (var opt=0; opt<items.length; opt++) {
			var lines=items[opt].split("\n"); var parts=lines[0].split("=");
			var label=parts[0];
			var v=parts[1]?parts[1]:parts[0];
			var title=lines[1]?lines[1]:this.valueTooltip.format([field,targetID,v]);
			var sel=values.contains(v); if (sel) isOther=false; // found matching value
			opts.push('<option value="'+v+'" '+(sel?'selected':'')+' title="'+title+'">'+label+'</option>');
		}
		// add 'other...'
		if (field=='tags') isOther=false;
		if (isOther||allowOther) {
			var label="other"+(isOther?(": "+values[0]):"...");
			var v=isOther?values[0]:'';
			var t=this.otherTooltip.format([field,targetID]);
			opts.push('<option value="'+v+'" '+(isOther?'selected':'')+' title="'+t+'">'+label+'</option>');
		}
		// add 'edit list...'
		if (listsrc && (!store.getTiddlerText(listsrc) || allowEdit)) {
			var title=this.editTooltip.format([field,listsrc]);
			opts.push('<option value="'+listsrc+'" title="'+title+'">'+this.editLabel+'</option>');
		}
		// render listbox
		var html='<select '+(values[0]?'value="'+values[0]+'" ':' ')
			+' title="'+this.tooltip.format([field,targetID])+'"'
			+' rows="'+rows+'"'+' size="'+(rows!=0?rows:opts.length)+'"'+' style="width:'+width+'"'
			+' tiddler="'+targetID+'"'+' edit="'+field+'"'+' ptext="'+ptext+'"'
			+' listsrc="'+listsrc+'"'+' wikifyData="'+wikifyData+'"'
			+' autosave="'+autosave+'"'+' allowBlank="'+allowBlank+'"'+' allowOther="'+allowOther+'"'
			+' allowEdit="'+allowEdit+'"'+' allowMultiple="'+allowMultiple+'"'+(allowMultiple?' multiple':'')
			+' onclick="return config.macros.select.onClick(this,event)"'
			+' onchange="return config.macros.select.onChange(this,event)"'
			+' ondblclick="return false">'+opts.join('')+'</select>';
		place.innerHTML=html;
	},
	onClick:
	function(here,event) {
		var sel=here.selectedIndex;
		if (sel!=-1 && here.options[sel].text.startsWith(config.macros.select.otherLabel))
			here.onchange.apply(here,arguments);
	},
	onChange:
	function(here,event) {
		var cms=config.macros.select; // abbrev
		var sel=here.selectedIndex;
		if (sel!=-1) {
			if (here.options[sel].text==cms.editLabel) {
				story.displayTiddler(story.findContainingTiddler(here),here.value,DEFAULT_EDIT_TEMPLATE);
				return false;
			}
			if (here.options[sel].text.startsWith(cms.otherLabel)) {
				var newval=prompt(cms.otherPrompt.format([here.getAttribute("edit")]),here.value);
				if (!newval) {// user cancelled
					var v=store.getValue(here.getAttribute("tiddler"),here.getAttribute("edit"));
					{ here.value=v; if (v==undefined) here.selectedIndex=0; return false; }
				};
				here.options[sel].value=newval;
				here.options[sel].text=cms.otherLabel+": "+newval;
				here.value=newval;
			}
			if (here.options[sel].value=='_ptext')
				for (var i=0; i<here.options.length; i++)
					here.options[i].selected=false;
		}
		if (here.getAttribute("autosave")=="true") config.macros.select.setFieldValue(here);
		return false;
	},
	setFieldValue: function(here) {
		var tid=here.getAttribute("tiddler"); if (!tid || !tid.length) return; // no target, do nothing
		var field=here.getAttribute("edit");
		if (field.substr(0,1)=='=') { // option cookie instead of tiddler field
			config.macros.option.propagateOption(field.substr(1),"value",here.value,"input");
			return;
		}
		// ensure tiddler exists
		if (!store.tiddlerExists(tid)) store.saveTiddler(tid,tid,"",config.options.txtUserName,new Date(),[]);
		if (field=='tags') {
			store.suspendNotifications();
			for (var i=0; i<here.options.length; i++) {
				var opt=here.options[i];
				if (opt.text==config.macros.select.editLabel) continue;
				store.setTiddlerTag(tid,opt.selected,opt.value);
			}
			store.resumeNotifications();
		} else {
			// get multi-select items
			var values=[];
			for (var i=0; i<here.options.length; i++) {
				var opt=here.options[i];
				if (opt.text==config.macros.select.editLabel) continue;
				if (opt.selected) values.pushUnique(String.encodeTiddlyLink(opt.value));
			}
			if (values.length==1) values=[here.value]; // remove unneeded brackets around single value
			store.setValue(tid,field,values.length?values.join(' '):null); // if no selections, delete field
		}
		// 'touch' tiddler and report to user
		var t=store.getTiddler(tid);
		var who=config.options.chkForceMinorUpdate?t.modifier:config.options.txtUserName;
		var when=config.options.chkForceMinorUpdate?t.modified:new Date();
		store.saveTiddler(tid,tid,t.body,who,when,t.tags,t.fields);
		if (config.macros.select.verbose)
			{ clearMessage(); displayMessage(config.macros.select.changeMsg.format([field,tid,here.value])); }
	}
}
//}}}
|Name|ListboxPlugin|
|Source|http://www.TiddlyTools.com/#ListboxPlugin|
|Documentation|http://www.TiddlyTools.com/#ListboxPluginInfo|
|Version|1.4.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|documentation|
|Description|documentation for ListboxPlugin|
The {{{<<select>>}}} macro allows you to set tiddler field values by selecting pre-configured enumerated values from a listbox/droplist control.  
!!!!!Usage
<<<
in tiddler content:
{{{
<<select fieldname@tiddlername value value value ...
	rows:nn width:xxx "prompt:..." autoSave allowBlank allowOther allowMultiple>>
<<select fieldname@tiddlername label=value label=value label=value ...
	rows:nn width:xxx "prompt:..." autoSave allowBlank allowOther allowMultiple>>
<<select fieldname@tiddlername =tagvalue allowEdit
	rows:nn width:xxx "prompt:..." autoSave allowBlank allowOther allowMultiple>>
<<select fieldname@tiddlername "=tag expression" allowEdit
	rows:nn width:xxx "prompt:..." autoSave allowBlank allowOther allowMultiple>>
<<select fieldname@tiddlername +TiddlerName allowEdit
	rows:nn width:xxx "prompt:..." autoSave allowBlank allowOther allowMultiple>>
<<select fieldname@tiddlername *TiddlerName allowEdit
	rows:nn width:xxx "prompt:..." autoSave allowBlank allowOther allowMultiple>>
}}}
in a custom [[EditTemplate]] or [[ViewTemplate]]:
{{{
<div class="editor" macro="select ..."></div>
}}}
//where://
*''fieldname@tiddlername'' (or ''=cookiename''){{block{
<<<
Specifies the tiddler field associated with the list display.  The "@tiddlername" portion is optional and, when omitted (or the special keyword, "@here" is used), the current tiddler is assumed.  Alternatively, if the fieldname begins with an equal sign (=), then it will be used as a TiddlyWiki option cookie reference and the selected value will be ''assigned to that cookiename //instead// of being stored in a tiddler field''.  Note: when a cookie reference is used, any "@tiddlername" portion that may be present in the syntax will be //ignored//.
<<<
}}}
*{{block{
''value value value ...'' //or// ''label=value label=value label=value ...'' //(inline list definition)//
''+~TiddlerName'' //or// ''*~TiddlerName'' //(tiddler-based list definition)//
''=tagvalue'' //or// ''"=tag expression"'' //(tag-based list definition)//
<<<
Specifies list items as simple values or label/value pairs.  

You can use the ''+~TiddlerName'' or ''*~TiddlerName'' syntax to define the values or label/value pairs using a tiddler containing an "HR-separated" list, where each list item is one or two lines of text, separated from the next item by a horizontal rule: """----""".  The first line of each item contains the value or label=value that will appear in the list.  The second, optional line allows you to specify custom tooltip help text for that list item.

The default tooltip for a list item is: "{{{set fieldname@tiddlername=itemvalue}}}".  Note: if all list entries are single-line (i.e., you are not defining ANY custom tooltips), you can omit the horizontal rule between entries... each line of text will be treated as a separate list entry.

If you use "*" preceding the ~TiddlerName, the contents of the tiddler will first be processed by the TiddlyWiki parser and that output will then be used as the list definition.  This allows you to apply macros and scripts to //dynamically generate list definitions// based on the current document contents (such as available tag names).

You can also use the ''=tagvalue'' syntax to generate a list whose items are the names of tiddlers tagged with that value (e.g., "=systemConfig" to list all plugins, or "=friends" to list all tiddlers tagged as "friends").  If you have MatchTagsPlugin installed, you can use Boolean tag //expressions// (e.g., "=friends or (lovers and not crazy)", to list only tiddlers that have a suitable combination of tags.
<<<
}}}
*''allowEdit'' //(for use with +~TiddlerName or *~TiddlerName param only)//{{block{
<<<
adds optional "edit list..." item to the end of the list, to enable quick editing of a tiddler-based list definition.  Note: if the ''+~TiddlerName'' parameter refers to a tiddler that does not yet exist, the "edit list..." item is automatically added to the list, even if ''allowEdit'' was not specified.  This allows you to place an 'empty' tiddler-based list into your content (e.g., """<<select fieldname =NewTiddlerName>>"""), and then create and define the tiddler-based list later on.
<<<
}}}
*''rows:nn''{{block{
<<<
specifies the number of lines to display in the list.  If rows=1, a 'droplist' is displayed. If rows>1 a fixed-height listbox is used.  By default (or if rows=0 is used), the listbox is displayed with enough lines to show all items without scrolling (i.e., "fit to contents - vertically")
<<<
}}}
*''width:xxx''{{block{
<<<
specifies the width of the list, using a CSS dimension value (px, em, in, cm, or %).  The default is auto (i.e., "fit to contents - horizontally").
<<<
}}}
*''"prompt:..."''{{block{
<<<
specifies 'guide text' to display as the first item in the list.  Selecting this item does not change the value stored in the field.
<<<
}}}
*''autoSave''{{block{
<<<
when used in EditTemplate, this keyword forces selection changes to be applied immediately rather than waiting for the "done" command to be invoked.  Note: because the standard ViewTemplate toolbar does not have a "done" command to signal the end of the editing activity, ''autoSave'' is always enabled when working with a selection list that is being displayed in 'view mode'.
<<<
}}}
*''allowBlank''{{block{
<<<
when the value of a tiddler field is "undefined", a 'blank' item is added at the beginning of the list to represent the undefined field value.  When a field value is subsequently selected, the blank item is removed from the list.   Use the ''allowBlank'' keyword to always include the blank item in the list.  Selecting the blank item sets the field value back to "undefined" (i.e., deletes the field).
<<<
}}}
*''allowOther''{{block{
<<<
when the value of a tiddler field does not match any of the values in the list, a special 'other' item is added at the end of the list so that the unrecognized field value can be shown.  If another field value is subsequently selected, the 'other' item is removed from the list.  Use the ''allowOther'' keyword to always include the 'other item in the list.  When this item is selected, you will be prompted to enter a custom value to assign to the field.
<<<
}}}
*''allowMultiple''{{block{
<<<
when used with a listbox (e.g, rows>1), permits selection of multiple items using ctrl-click and shift-click.  Selected values are stored in the tiddler field as a space-separated list, with brackets ({{{[[...]]}}}}) used as needed around values containing spaces.  //note: multiple selection is not supported by droplists (rows=1)//
<<<
}}}
<<<
!!!!!Examples
<<<
''inline list definition:''
{{{<<select thing rows:1 eenie meenie miney moe>>}}}
<<select thing rows:1 eenie meenie miney moe>>
{{{<<select size rows:1 "prompt:select a show size..." xsmall=30 small=32 medium=34 large=36 xlarge=38>>}}}
<<select size rows:1 "prompt:select a show size..." xsmall=30 small=32 medium=34 large=36 xlarge=38>>
{{{<<select size allowOther "prompt:select a shoe size..." xsmall=30 small=32 medium=34 large=36 xlarge=38>>}}}
<<select size allowOther "prompt:select a shoe size..." xsmall=30 small=32 medium=34 large=36 xlarge=38>>

{{{<<select gender Male Female>>}}}
<<select gender Male Female>>

''tiddler-based list definition:''
{{{<<select color rows:1 +ListboxSample>>}}}
<<select color rows:1 +ListboxSample>>
{{{<<select color allowBlank allowOther allowMultiple +ListboxSample allowEdit>>}}}
<<select color allowBlank allowOther allowMultiple +ListboxSample allowEdit>>
{{{<<select demo@ListboxDemoTarget +ListboxNewSample>>}}}
<<select demo@ListboxDemoTarget +ListboxNewSample>>

''tag-based list definition:''
{{{<<select plugins rows:1 =systemConfig>>}}}
<<select plugins rows:1 allowBlank =systemConfig>>
{{{<<select samples rows:1 allowBlank =sample>>}}}
<<select samples rows:1 =sample>>
<<<
!!!!!Revisions
<<<
2010.03.14 1.4.1 use filterTiddlers() instead of getTaggedTiddlers() - use MatchTagsPlugin for tag expressions
2009.09.02 1.4.0 added 'prompt:...' param
2009.09.02 1.3.0 added special handling for tags field
2009.06.15 1.2.3 in setFieldValue(), eliminate extra brackets around single value selections
2009.06.15 1.2.2 fixed infinite loop problem in refresh()
2009.06.15 1.2.1 if not allowMultiple, handle field values containing space-separated lists as single values
2009.05.31 1.2.0 added allowMultiple flag.  Rewrote handler to allow option params in any order.  Corrected handling of blank/other values.
2008.07.22 1.1.0 added "=cookiename" syntax for storing selected value in cookie instead of a tiddler field
2008.04.28 1.0.1 added "=tagvalue" syntax for generating lists of tiddlers tagged with a given value
2007.08.31 0.8.2 corrected handling for "@tiddlername" syntax for non-default 'target' tiddler.
2007.08.06 0.8.1 added support for "@here" keyword syntax and cleaned up handling for identifying 'target' tiddler.  Also added 'onclick' handler for "other:" item, so that prompt dialog is presented even if "other" was already selected (and hence, no "onchange" event)
2007.07.29 0.8.0 added getWikifiedData() and use of "*" prefix on TiddlerName so macros or inline scripts embedded in listbox definitions can generate dynamic lists based on current document content.
2007.07.26 0.7.3 fixed call to config.macros.select.setFieldValue()
2007.07.24 0.7.2 in setFieldValue(), 'touch' target tiddler AFTER setting value to avoid early refresh event that steps on listbox attributes, causing a fatal error (in IE only).
2007.06.28 0.7.1 in render(), retrieve current val from tiddler editor control (when editing) or use stored field (when viewing).
2007.05.29 0.7.0 split render() logic from handler(), added refresh() notification to auto sync lists that use +TiddlerName definition
2007.05.15 0.6.1 code/documentation cleanup
2007.05.14 0.6.0 lots more options
2007.05.12 0.5.0 started
<<<
Red=#FF0000
----
Orange=#FF9900
----
Yellow=#FFFF00
----
Green=#00FF00
----
Blue=#0000FF
----
Indigo=#000099
----
Violet=#9900FF
----
Black=#000000
----
White=#FFFFFF
/%
!info
|Name|LoadRemotePlugin|
|Source|http://www.TiddlyTools.com/#LoadRemotePlugin|
|Version|2.0.2|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Description|Load a plugin from a remote .js URL|
Usage
<<<
{{{
<<tiddler LoadRemotePlugin with: "label" "tip" "URL"
	"onloadfunction" "preloadedtest" "onrunfunction" "configoverlay">>
}}}
*''label'' and ''tip''<br>command link text and tooltip
*''URL''<br>location of .js (i.e., the remotely stored plugin file)
*''onloadfunction''<br>js code invoked after loading remote plugin (can be used to init values, display tiddlers, etc)
*''preloadedtest''<br>js expression evaluated to test if plugin has already been loaded
*''onrunfunction''<br>js code invoked //instead of onloadfunction// when plugin is already loaded
*''configoverlay''<br>name of tiddler containing js code with additional custom settings, tweaks, etc.
<<<
Examples
<<<
{{{
<<tiddler LoadRemotePlugin##show with:
	[[ImportTiddlersPlugin]]
	[[Load ImportTiddlersPlugin from svn.TiddlyWiki.org repository]]
	[[http://svn.tiddlywiki.org/Trunk/contributors/EricShulman/plugins/ImportTiddlersPlugin.js]]
	[[window.story.displayTiddler(null,'ImportTiddlers')]]
	[[version.extensions.ImportTiddlersPlugin!=undefined]]
	[[window.story.displayTiddler(null,'ImportTiddlers')]]
	[[ImportTiddlersPluginConfig]]
>>
}}}
<<tiddler LoadRemotePlugin##Examples>>
<<<
!end

!Examples
*[[TiddlyTools|http://www.TiddlyTools.com/]]
**{{block{<<tiddler LoadRemotePlugin##show with:
	[[ImportTiddlersPlugin]]
	[[Load ImportTiddlersPlugin from svn.TiddlyWiki.org repository]]
	[[http://svn.tiddlywiki.org/Trunk/contributors/EricShulman/plugins/ImportTiddlersPlugin.js]]
	[[window.story.displayTiddler(null,'ImportTiddlers')]]
	[[version.extensions.ImportTiddlersPlugin!=undefined]]
	[[window.story.displayTiddler(null,'ImportTiddlers')]]
	[[ImportTiddlersPluginConfig]]
>>}}}
**{{block{<<tiddler LoadRemotePlugin##show with:
	[[TiddlerTweakerPlugin]]
	[[Load TiddlerTweakerPlugin from svn.TiddlyWiki.org repository]]
	[[http://svn.tiddlywiki.org/Trunk/contributors/EricShulman/plugins/TiddlerTweakerPlugin.js]]
	[[window.story.displayTiddler(null,'TiddlerTweaker')]]
	[[version.extensions.TiddlerTweakerPlugin!=undefined]]
>>}}}
**{{block{<<tiddler LoadRemotePlugin##show with:
	[[RearrangeTiddlersPlugin]]
	[[Load RearrangeTiddlersPlugin from www.TiddlyTools.com]]
	[[http://www.TiddlyTools.com/plugins/RearrangeTiddlersPlugin.js]]
	[[window.story.forEachTiddler(function(t,e){window.story.refreshTiddler(t,null,true)}); window.refreshDisplay()]]
	[[Story.prototype.rearrangeTiddlersHijack_refreshTiddler!=undefined]]
>>}}}
*[[Abego Software|http://tiddlywiki.abego-software.de/]]
**{{block{<<tiddler LoadRemotePlugin##show with:
	[[YourSearchPlugin]]
	[[Load YourSearchPlugin from tiddlywiki.abego-software.de]]
	[[http://tiddlywiki.abego-software.de/archive/YourSearchPlugin/Plugin-YourSearch-src.2.1.1.js]]
	[[window.refreshPageTemplate()]]
	[[version.extensions.YourSearchPlugin!=undefined]]
>>}}}
*[[FirefoxPrivileges.TiddlySpot.com|http://firefoxprivileges.tiddlyspot.com/]]
**{{block{<<tiddler LoadRemotePlugin##show with:
	[[Firefox Privilege Manager]]
	[[Load Firefox Privilege Manager from svn.TiddlyWiki.org repository]]
	[[http://svn.tiddlywiki.org/Trunk/contributors/XavierVerges/plugins/FirefoxPrivilegesPlugin.js]]
	[[config.macros.firefoxPrivileges.onload()]]
	[[config.macros.firefoxPrivileges!=undefined]]
	[[backstage.switchTab('firefoxPrivileges')]]
>>}}}
*[[BillyReisinger.com:|http://www.billyreisinger.com/jash/]]
**{{block{<<tiddler LoadRemotePlugin##show with:
	[[Jash (JAvascript SHell)]]
	[[Load Jash (JAvascript SHell) from www.billyreisinger.com/jash]]
	[[http://www.billyreisinger.com/jash/source/latest/Jash.js]]
	[[window.jash.close()]]
	[[window.jash!=undefined]]
>>}}}
!end

!show
<html><nowiki><a href="javascript:;" title="$2"
onmouseover="
	this.href='javascript:void(eval(decodeURIComponent(%22(function(){try{('
	+encodeURIComponent(encodeURIComponent(this.onclick))
	+')()}catch(e){alert(e.description?e.description:e.toString())}})()%22)))';"
onclick="
	try { if ($5) {
		clearMessage();
		try {$6;} catch(e) {$4;}
		displayMessage('$1 is already installed.');
		return false;
	} } catch(e){;}
	var s=document.createElement('script');
	s.src='$3';
	s.onerror=function() {
		clearMessage();
		displayMessage('Could not load $1 from');
		displayMessage(this.src,this.src);
	};
	s.onload=function() { 
		clearMessage();
		{$4;}
		try { eval(store.getTiddlerText('$7','')); }
		catch(e) { displayMessage(e.description||e.toString()); }
		displayMessage('$1 has been loaded from');
		displayMessage(this.src,this.src);
	};
	s.onreadystatechange=function()  /* for IE */
		{ if(this.readyState=='complete') this.onload(); };
	document.getElementsByTagName('head')[0].appendChild(s);
	return false;
">$1</a></html>
!end
%/<<tiddler {{var src='LoadRemotePlugin';src+(tiddler&&tiddler.title==src?'##info':'##show');}}
	with: [[$1]] [[$2]] [[$3]] [[$4]] [[$5]] [[$6]] [[$7]]>>
/***
|Name|LoadTiddlersPlugin|
|Source|http://www.TiddlyTools.com/#LoadTiddlersPlugin|
|Documentation|http://www.TiddlyTools.com/#LoadTiddlersPluginInfo|
|Version|3.9.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|macro for automated updates or one-click installations of tiddlers from remote sources|
!!!!!Documentation
>see [[LoadTiddlersPluginInfo]]
!!!!!Configuration
<<<
<<option chkLoadTiddlersShowReport>>after loading tiddlers, automatically display [[ImportedTiddlers]] (if created)
__password-protected server settings //(optional, if needed)//:__
>username: <<option txtRemoteUsername>> password: <<option txtRemotePassword>>
>{{{usage: <<option txtRemoteUsername>> <<option txtRemotePassword>>}}}
>''note: these settings are also used by [[ExternalTiddlersPlugin]] and [[ImportTiddlersPlugin]]''
<<<
!!!!!Revisions
<<<
2010.08.11 3.9.0 added 'autosave' optional param
|please see [[LoadTiddlersPluginInfo]] for additional revision details|
2005.07.20 1.0.0 Initial Release
<<<
!!!!!Code
***/
//{{{
version.extensions.LoadTiddlersPlugin= {major: 3, minor: 9, revision: 0, date: new Date(2010,8,11)};

if (config.options.chkLoadTiddlersShowReport===undefined)
	config.options.chkLoadTiddlersShowReport=true;

config.macros.loadTiddlers = {
	label: '',
	tip: "add/update tiddlers from '%0'",
	lockedTag: 'noReload',	// if existing tiddler has this tag value, don't overwrite it, even if inbound tiddler is newer
	askMsg: 'Please enter a local path/filename or a remote URL',
	openMsg: 'Opening %0',
	openErrMsg: 'Could not open %0 - error=%1',
	readMsg: 'Read %0 bytes from %1',
	foundMsg: 'Found %0 tiddlers in %1',
	nochangeMsg: "'%0' is up-to-date... skipped.",
	lockedMsg: "'%0' is tagged '%1'... skipped.",
	skippedMsg: 'skipped (cancelled by user)',
	loadedMsg: 'Loaded %0 of %1 tiddlers from %2',
	reportTitle: 'ImportedTiddlers',
	warning: "Warning!!  Processing '%0' as a systemConfig (plugin) tiddler may produce unexpected results! Press OK to proceed.",
	autosaveMsg: 'Save current document?  Press OK to proceed.',
	handler: function(place,macroName,params) {
		var label=(params[0] && params[0].substr(0,6)=='label:')?params.shift().substr(6):this.label;
		var tip=(params[0] && params[0].substr(0,7)=='prompt:')?params.shift().substr(7):this.tip;
		var filter='updates';
		if (params[0] && (params[0]=='all' || params[0]=='new' || params[0]=='changes' || params[0]=='updates'
			|| params[0].substr(0,8)=='tiddler:' || params[0].substr(0,4)=='tag:'))
			filter=params.shift();
		var src=params.shift(); if (!src || !src.length) return; // filename is required
		var quiet=(params[0]=='quiet'); if (quiet) params.shift();
		var ask=(params[0]=='confirm'); if (ask) params.shift();
		var force=(params[0]=='force'); if (force) params.shift();
		var init=(params[0]=='init'); if (init) params.shift();
		var nodirty=(params[0]=='nodirty'); if (nodirty) params.shift();
		var norefresh=(params[0]=='norefresh'); if (norefresh) params.shift();
		var noreport=(params[0]=='noreport'); if (noreport) params.shift();
		var autosave=(params[0]=='autosave'); if (autosave) params.shift();
		this.newTags=[]; if (params[0]) this.newTags=params; // any remaining params are used as 'autotags'
		var flags={quiet:quiet, ask:ask, filter:filter, force:force, init:init,
			nodirty:nodirty, norefresh:norefresh, noreport:noreport, autosave:autosave};
		if (label.trim().length) { // CLICKABLE LINK
			createTiddlyButton(place,
				label.format([src.replace(/%20/g,' ')]),
				tip.format([src.replace(/%20/g,' ')]),
				function() {
					var cml=config.macros.loadTiddlers;
					cml.loadFile(src,cml.doImport,flags);
					return false;
				})
		}
		else // IMMEDIATE IMPORT
			this.loadFile(src,this.doImport,flags);
	},
	loadFile: function(src,callback,params) {
		var quiet=params.quiet;
		if (src=='ask') src=prompt(this.askMsg);
		if (src==undefined || !src.length) return null; // filename is required
		if (!quiet) clearMessage();
		if (!quiet) displayMessage(this.openMsg.format([src.replace(/%20/g,' ')]));
		// if working locally and src is not a URL, read from local filesystem
		if (document.location.protocol=='file:' && src.substr(0,5)!='http:' && src.substr(0,5)!='file:') {
			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(this.openErrMsg.format([src.replace(/%20/g,' '),'(unknown)']));
			} else {
				if (!quiet) displayMessage(this.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,params,txt,src,null);
			}
		} else { // use XMLHttpRequest
			doHttp('GET',src,null,null,config.options.txtRemoteUsername,config.options.txtRemotePassword,callback,params,null);
		}
	},
	readTiddlersFromHTML: function(html) {
		// for TW2.2+
		if (TiddlyWiki.prototype.importTiddlyWiki!=undefined) {
			var remoteStore=new TiddlyWiki();
			remoteStore.importTiddlyWiki(html);
			return remoteStore.getTiddlers('title');	
		}
	},
	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');	
	},
	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];
	},
	doImport: function(status,params,html,src,xhr) {
		var cml=config.macros.loadTiddlers; // abbrev
		src=src.split('?')[0]; // strip off "?nocache=..."
		if (!status) {
			displayMessage(cml.openErrMsg.format([src.replace(/%20/g,' '),xhr.status]));
			return false;
		}
		var quiet=params.quiet;
		var ask=params.ask;
		var filter=params.filter;
		var force=params.force;
		var init=params.init;
		var nodirty=params.nodirty;
		var norefresh=params.norefresh;
		var noreport=params.noreport;
		var autosave=params.autosave;
		var tiddlers = cml.readTiddlersFromHTML(html);
		if (!tiddlers||!tiddlers.length) tiddlers=cml.readTiddlersFromCSV(html);
		if (!tiddlers||!tiddlers.length) tiddlers=cml.createTiddlerFromFile(src,html);
		var count=tiddlers?tiddlers.length:0;
		if (!quiet) displayMessage(cml.foundMsg.format([count,src.replace(/%20/g,' ')]));
		var wasDirty=store.isDirty();
		store.suspendNotifications();
		var count=0;
		if (tiddlers) for (var t=0;t<tiddlers.length;t++) {
			var inbound = tiddlers[t];
			var theExisting = store.getTiddler(inbound.title);
			if (inbound.title==cml.reportTitle)
				continue; // skip 'ImportedTiddlers' history from the other document...
			if (theExisting && theExisting.tags.contains(cml.lockedTag)) {
				if (!quiet) displayMessage(cml.lockedMsg.format([theExisting.title,cml.lockedTag]));
				continue; // skip existing tiddler if tagged with 'noReload'
			}
			// apply the all/new/changes/updates filter (if any)
			if (filter && filter!='all') {
				if ((filter=='new') && theExisting) // skip existing tiddlers
					continue;
				if ((filter=='changes') && !theExisting) // skip new tiddlers
					continue;
				if ((filter.substr(0,4)=='tag:') && inbound.tags.indexOf(filter.substr(4))==-1) // must match specific tag value
					continue;
				if ((filter.substr(0,8)=='tiddler:') && inbound.title!=filter.substr(8)) // must match specific tiddler name
					continue;
				if (!force && store.tiddlerExists(inbound.title) && ((theExisting.modified.getTime()-inbound.modified.getTime())>=0)) {
					var msg=cml.nochangeMsg;
					if (!quiet&&msg.length) displayMessage(msg.format([inbound.title]));
					continue;
				}
			}
			// get confirmation if required
			var msg=(theExisting?'Update':'Add')+" tiddler '"+inbound.title+"'\n"
				+'from '+src.replace(/%20/g,' ')+'\n\nOK to proceed?';
			if (ask && !confirm(msg))
				{ tiddlers[t].status=cml.skippedMsg; continue; }
			// DO IT!
			var tags=new Array().concat(inbound.tags,cml.newTags);
	                store.saveTiddler(inbound.title, inbound.title, inbound.text, inbound.modifier,
				inbound.modified, tags, inbound.fields, true, inbound.created);
			// force creation date to imported value - needed for TW2.1.3 or earlier
	                store.fetchTiddler(inbound.title).created = inbound.created;
			tiddlers[t].status=theExisting?'updated':'added'
			if (init && tags.contains('systemConfig') && !tags.contains('systemConfigDisable')) {
				var ok=true;
				if (ask||!quiet) ok=confirm(cml.warning.format([inbound.title]))
				if (ok) { // run the plugin
					try { window.eval(inbound.text); tiddlers[t].status+=' (plugin initialized)'; }
					catch(ex) { displayMessage(config.messages.pluginError.format([exceptionText(ex)])); }
				}
			}
			count++;
		}
		store.resumeNotifications();
		if (count) {
			// set/clear 'unsaved changes' flag, refresh page display, and generate a report
			store.setDirty(wasDirty||!nodirty);
			if (!norefresh) {
				story.forEachTiddler(function(t,e){
					if(!story.isDirty(t))story.refreshTiddler(t,null,true)
				});
				store.notifyAll();
			}
			if (!noreport) cml.report(src,tiddlers,count,quiet);
		}
		if (!quiet||count) // force msg if tiddlers were loaded
			displayMessage(cml.loadedMsg.format([count,tiddlers.length,src.replace(/%20/g,' ')]));
		if (count && autosave && (!ask||confirm(cml.autosaveMsg))) saveChanges();
	},
	showReport: true,
	report: function(src,tiddlers,count,quiet) {
		var cml=config.macros.loadTiddlers; // abbrev
		// format the new report content
		var newText = 'On '+(new Date()).toLocaleString()+', ';
		newText += config.options.txtUserName+' loaded '+count+' tiddlers ';
		newText += 'from\n[['+src+'|'+src+']]:\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';
		var title=cml.reportTitle;
		var currText='';
		var t=store.getTiddler(title);
		if (t) currText=(t.text.length?'\n----\n':'')+t.text;
		store.saveTiddler(title, title, newText+currText,
			config.options.txtUserName, new Date(),	t?t.tags:null, t?t.fields:null);
		if (!quiet) {
			if (config.options.chkLoadTiddlersShowReport)
				story.displayTiddler(null,title);
			story.refreshTiddler(title,null,true);
		}
	}
}
//}}}
/***
|Name|LoadTiddlersPluginInfo|
|Source|http://www.TiddlyTools.com/#LoadTiddlersPlugin|
|Documentation|http://www.TiddlyTools.com/#LoadTiddlersPluginInfo|
|Version|3.9.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|documentation|
|Description|documentation for LoadTiddlersPlugin|
!!!!!Usage
<<<
{{{
<<loadTiddlers label:... prompt:... filter source
	quiet confirm force init nodirty norefresh noreport autosave
	tag tag tag...>>
}}}
*''label:...'' and ''prompt:...''<br>link and tooltip text to trigger the load tiddler processing.  If a label is NOT provided, then no link is created and the loadTiddlers function is performed whenever the containing tiddler is rendered.
*''filter'' (optional keyword)<br>determines which tiddlers will be automatically selected for importing.  Use one of the following:
**''all''<br>ALL tiddlers from the import source document, even if they have not been changed.
**''new''<br>only tiddlers that are found in the import source document, but do not yet exist in the destination document
**''changes''<br>only tiddlers that exist in both documents for which the import source tiddler is newer than the existing tiddler
**''updates''<br>both ''new'' and ''changes'' (this is the default action when none is specified)
**''tiddler:TiddlerName''<br>only the specified tiddler is retrieved
**''tag:value''<br>only the tiddlers tagged with the indicated value.
*''source'' (required)<br>is the location of the imported document.  It can be either a local document path/filename in whatever format your system requires, or a remote web location (starting with "http://" or "https://").  Use the special keyword, ''ask'', to prompt for a source location whenever the macro is invoked
*''quiet'' (optional)<br>supresses all status message during the import processing.  Note: if any tiddlers are actually imported, a final message will still be displayed, even when 'quiet' is specified.  This ensures that changes to your document cannot occur without any visible indication at all.
*''confirm'' (optional)<br>adds interactive confirmation for each inbound tiddler, so that you can manually bypass any tiddlers that you do not want to import.  Note: this flag also adds confirmation when using the ''autosave'' option (see below).
*''init'' (optional)<br>invokes tiddlers tagged with <<tag systemConfig>> as plugins as soon as they are imported, without requiring a save-and-reload action first.  For safety, you will be asked to confirm each imported plugin, so that you can manually bypass any that you do not want to invoke.  Note, however, that those tiddlers are still //imported// and saved with your document and will still take effect the next time you save-and-reload the document.
*''force'' (optional)<br>imports all matching tiddlers, even if unchanged
*''noreport'' (optional)<br>suppress generation of [[ImportedTiddlers]] report
*''nodirty'' (optional)<br>loads tiddlers without marking the document as 'dirty' (i.e., needing to be saved)
*''norefresh'' (optional)<br>prevents automatic re-rendering of the page after tiddlers are loaded
*''autosave'' (optional)<br>automatically saves the document if tiddlers have been loaded
*''tag tag tag...'' (optional)<br>any remaining parameters are used as tag values to be added to each imported tiddler (i.e., "tag-on-import")
Note: if a tiddler in the current document is tagged with<<tag noReload>> then it ''will not be overwritten, even if the inbound tiddler has been selected'' by the filtering process.  This allows you to make local changes to imported tiddlers while ensuring that those changes won't be lost due to automatic tiddler updates retrieved from the import source document.
<<<
!!!!!Examples
<<<
{{{<<loadTiddlers "label:load tiddlers from %0" example.html confirm temporary>>}}}
<<loadTiddlers "label:load tiddlers from %0" example.html confirm temporary>>
{{{<<loadTiddlers "label:load tiddlers from %0 plus AUTOSAVE" example.html confirm norefresh autosave>>}}}
<<loadTiddlers "label:load tiddlers from %0" example.html confirm norefresh autosave>>
<<<
!!!!!Configuration
<<<
<<option chkLoadTiddlersShowReport>>after loading tiddlers, automatically display [[ImportedTiddlers]] (if created)
__password-protected server settings //(optional, if needed)//:__
>username: <<option txtRemoteUsername>> password: <<option txtRemotePassword>>
>{{{usage: <<option txtRemoteUsername>> <<option txtRemotePassword>>}}}
>''note: these settings are also used by [[ExternalTiddlersPlugin]] and [[ImportTiddlersPlugin]]''
<<<
!!!!!Revisions
<<<
2010.08.11 3.9.0 added 'autosave' optional param
2009.10.08 3.8.1 removed switchTheme() from doImport()... causes an INFINITE cycle of imports!
2009.10.06 3.8.0 added createTiddlerFromFile (import text files)
2009.10.04 3.7.8 in doImport(), call switchTheme() after loading tiddlers
2009.09.27 3.7.7 in readTiddlersFromCSV(), strip \r from input and fixed handling for quoted values
2009.09.01 3.7.6 added config.options.chkLoadTiddlersShowReport (default=true)
2009.09.01 3.7.6 added config.options.chkLoadTiddlersShowReport (default=true)
2009.08.30 3.7.5 in doImport(), check status and report error, if any
2009.08.29 3.7.4 in handler(), added 'return false' in button function (fixes IE page transition)
2009.08.19 3.7.3 in doImport(), fixed 'init' handling
2009.08.16 3.7.2 in doImport(), corrected check for tiddlers returned by readTiddlersFromHTML();
2009.07.03 3.7.1 fixups for TW252: doHttp() doesn't return XHR and convertUTF8ToUnicode() not needed for local I/O
2009.05.04 3.7.0 read CSV file format
2008.11.14 3.6.4 in loadFile(), force use of XMLHttpRequest if not viewing a local document (supports use of relative file references when online)
2008.10.27 3.6.3 in doImport(), fixed Safari bug by replacing static Array.concat(...) with new Array().concat(...)
2008.08.05 3.6.2 rewrote loadFile() to eliminate use of platform-specific fileExists() test
2008.08.03 3.6.1 in handler(), changed variable 'prompt' to 'tip' to avoid conflict with prompt() function
2008.01.07 3.6.0 added 'init' option to automatically invoke plugin tiddlers as soon as they are loaded (without needing save/reload)
2008.01.03 3.5.0 in loadFile(), use lower-level doHttp() instead of loadRemoteFile() in order to support username/password access to remote server
2007.12.04 *.*.* update for TW2.3.0: replaced deprecated core functions, regexps, and macros
2007.06.27 3.4.8 added missing 'fields' params to saveTiddler() call. Fixes problem where importing tiddlers would lose the custom fields.
2007.06.25 3.4.7 add calls to store.suspendNotifications() and store.resumeNotifications() to eliminate redisplay overhead DURING import activities.
2007.05.27 3.4.6 in handler(), loadRemoteFile() and doImport(), added 'noreport' flag to suppress generation of ImportedTiddlers
2007.05.27 3.4.5 in handler(), initialize 'newTags' to [] (empty array) instead of null... fixes fatal error when loading tiddler without autotagging.
2007.04.22 3.4.4 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.04.05 3.4.3 in doImport(), changed this.readTiddlersFromHTML(html) to config.macros.loadTiddlers.readTiddlersFromHTML(html).
2007.03.26 3.4.2 renamed import() to doImport() to fix IE load-time error ("identifier expected").  "import" is a reserved word in some browsers...
2007.03.22 3.4.1 code cleanup: moved all functions inside object def'n, re-wrote report function
2007.03.21 3.4.0 split ImportTiddlersPlugin and LoadTiddlersPlugin into separate plugins
|please see [[ImportTiddlersPluginInfo]] for additional revision details|
2005.07.20 1.0.0 Initial Release
<<<
/***
|Name|LoadTiddlersPluginPatch|
|Source|http://www.TiddlyTools.com/#LoadTiddlersPluginPatch|
|Version|3.6.2|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Requires|LoadTiddlersPlugin|
|Description|backward-compatible function patches for use with LoadTiddlersPlugin and TW2.1.x or earlier|

!!!!!Usage
<<<
The current version LoadTiddlersPlugin is compatible with the TW2.2.x core functions.
This "patch" plugin provides additional functions needed to enable the current version of LoadTiddlersPlugin 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.08.05 [3.6.2] rewrote loadFile to eliminate use of platform-specific fileExists() function
2008.01.03 [3.5.0] added support for passing txtRemoteUsername and txtRemotePassword for accessing password-protected remote servers
2007.06.27 [3.4.8] compatibility functions split from LoadTiddlersPlugin
|please see [[LoadTiddlersPlugin]] 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.LoadTiddlersPluginPatch= {major: 3, minor: 6, revision: 2, date: new Date(2008,8,5)};

config.macros.loadTiddlers.loadFile = function(src,callback,params) {
	var quiet=params.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(this.openErrMsg.format([src.replace(/%20/g," "),"(filesystem error)"]));
		} else {
			if (!quiet) displayMessage(this.readMsg.format([txt.length,src.replace(/%20/g," ")]));
			if (callback) callback(true,params,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.loadTiddlers.readMsg.format([x.responseText.length,src]));
					if (callback) callback(true,params,x.responseText,src,x);
				}
				else {
					if (!quiet) displayMessage(config.macros.loadTiddlers.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(this.openErrMsg.format([src,"(unknown)"]));
				displayMessage(e.description?e.description:e.toString());
			}
		}
	}
}

config.macros.loadTiddlers.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("tiddler");
		if(!title && nodes[t].id && (nodes[t].id.substr(0,5) == "store"))
			title = nodes[t].id.substr(5);
		if(title && title != "")
			tiddlers.push((new Tiddler()).loadFromDiv(nodes[t],title));
	}
	return tiddlers;
}

// // COPIED FROM TW2.2beta5
// // enables reading tiddler definitions using TW2.2 storeArea format, even when plugin is running under TW2.1.x
// // storeArea format changes include:
// // <pre> nodes
// // attribute(tiddler) renamed to attribute(title)
// // attribute(modified) is omitted if created==modified
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;
};

} // END OF TW2.1.x backward-compatibility functions
//}}}
<!--{{{-->
<!--
|Name|LockedEditTemplate|
|Source|http://www.TiddlyTools.com/#LockedEditTemplate|
|Version||
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|template|
|Requires|TiddlerPasswordPlugin,TiddlerPasswordPluginConfig,TaggedTemplateTweak|
|Description|prompt for admin password to allow editing of tiddlers tagged with "locked"|
-->
<span macro='getTiddlerPassword - "A password is required to edit this tiddler:"'></span>
[[EditTemplate]]
<!--}}}-->
/***
|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
//}}}
{{center{
<script>
	place.onmouseover=function(e){ addClass(this,"selected"); }
	place.onmouseout =function(e){ removeClass(this,"selected"); }
</script>/%

WELCOME:
%/{{big mouseover{[[welcome|Welcome]]<<tiddler {{
	place.lastChild.onclick=function() {
		story.closeTiddler('Welcome'); story.displayTiddler(null,'Welcome');
		refreshElements(document.getElementById('mainMenu').parentNode,'MainMenu');
		return false;
	};
'';}}>>}}}/%

BEGIN BOX
%/{{menubox small mouseover{<<moveablePanel name:mainmenu>>{{medium{
/% ABOUT	%/[[about|About]]
/% CATALOG	%/[[catalog|CatalogTabs]]
/% FAQ		%/[[FAQ|FAQViewer]]
/% CONTACT	%/[[contact|Contact]]
/% DONATE	%/[[donate|Donations]]
/% QUICKSTART	%/[[quickstart|QuickStart]]
}}}}}}/%
END BOX

%/}}}/% (end small center) 
%/<<animate =mainMenu marginTop %0px {{-findWindowHeight()}} 0 0 1500>>/%
%/
/%
TiddlyTools-specific custom menu - DO NOT COPY
%/{{small center{<script>
	place.onmouseover=function(e){ addClass(this,"selected"); }
	place.onmouseout =function(e){ removeClass(this,"selected"); }
</script>++++(chkShowAccessories){{mouseover{[accessories][&radic;accessories]}}}...
	<<tiddler MainMenuExtras##accessories>>
===}}}{{small center{<script>
	place.onmouseover=function(e){ addClass(this,"selected"); }
	place.onmouseout =function(e){ removeClass(this,"selected"); }
</script>++++(chkShowPowerTools){{mouseover{[powertools][&radic;powertools]}}}...
	<<tiddler MainMenuExtras##powertools>>
===}}}@@display:block;height:.5em;@@/%

!accessories
{{center menubox smallform fine mouseover{
<<moveablePanel name:accessories fold hover>>{{normal{@@line-height:1.2em;{{span{
@@position:relative;+++^800px^[browser|open web sites/media streams from inside TiddlyWiki]...
	{{fine block{<<moveablePanel name:minibrowser_mainmenu>>MiniBrowser
----
	<<miniBrowser>>}}}===@@
@@position:relative;+++^20em^[calculator]...
	<<moveablePanel name:microcalc_mainmenu>>MicroCalc<br><<tiddler MicroCalc>>===@@
@@position:relative;+++^[clock]...
	<<moveablePanel name:clock_mainmenu>><script>
		place.menu.style.top="-1.5em";
	</script>{{center menubox{<script>
		place.style.margin="-1.5em";
	</script>{{big{<<tiddler DigitalClock>>}}}}}}===@@
@@position:relative;+++^15em^[timer|track elapsed time for any task or activity]...
	<<moveablePanel name:timer_mainmenu>>~TaskTimer
	{{center smallform{<<taskTimer ask>><script>place.lastChild.firstChild.style.width="100%";</script>}}}===@@
@@position:relative;+++^18em^[calendar]...
	<<moveablePanel name:calendar_mainmenu>>calendar<html><hr></html>{{small{
		<<calendar thismonth>><script>place.lastChild.style.width="100%";</script>}}}===@@
@@position:relative;+++(MainMenuExtras_tiddlypod)^[tiddlypod|playlist for audio streams]...
	<<moveablePanel name:tiddlypod_mainmenu>><script>
		place.menu.style.top="0em";
	</script>{{center fine{<script>
		place.style.margin="-.5em 0";
	</script>//<<tiddlyPod listlength:15em width:200>>//}}}===@@
@@position:relative;+++^[tiddlylife|Cellular Automata: Conway's "Game of Life"]...
	<<moveablePanel name:tiddlylife_mainmenu>>[[TiddlyLife|TiddlyLifePlugin]]: Conway's "Game of Life"
----
	{{center small nowrap{
	<<life cellsize:.8em tid:GliderDance>>}}}===@@
@@position:relative;+++^[twittertabs|search and display *current* tweets]...
	<<moveablePanel name:twitter_mainmenu>><<tiddler TwitterTabs>>===@@
@@position:relative;+++^[tinychat|video conferencing from TinyChat.com]...
	<<moveablePanel name:tinychat_mainmenu>><<tiddler TinyChat>>===@@
}}}@@}}}}}}
!end

!powertools
{{center menubox smallform fine mouseover{
<<moveablePanel name:powertools fold hover>>{{normal{@@line-height:1.2em;{{span{
@@position:relative;+++^25em^[panels|Panel Manager Map Viewer]...
	[[PanelManager Map Viewer|PanelManagerPlugin]]
----
	{{center{<<moveablePanel commands>><<moveablePanel viewer>><<moveablePanel name:panelmanager_mainmenu fold hover manager height:auto>>}}}===@@
@@position:relative;+++^65em^[cookies|Manage TiddlyWiki persistent cookie settings]...
	<<moveablePanel name:cookies_mainmenu>>CookieManager / CookieJar
----
	@@line-height:120%;<<tiddler ScrollBox with: CookieJar 30em>>@@===@@
@@position:relative;+++^65em^[tweaker]...
	<<moveablePanel name:tweaker_mainmenu>>TiddlerTweaker<html><hr></html>{{small smallform{<<tiddler TiddlerTweaker>>}}}===@@
@@position:relative;+++^65em^[tidIDE|TiddlyWiki Integrated Development Environment]...
	{{fine block smallform left{
		<<moveablePanel name:tidIDE_mainmenu>>TiddlyWiki Integrated Development Environment
	<<tidIDE id:mainmenu +SystemInfo CompareTiddlers edit>>}}}===@@
@@position:relative;+++^[files|view local files and folders (offline use only)]...
	<<moveablePanel name:files_mainmenu>>ShowLocalDirectory //(offline use only)//
----
	<<tiddler ScrollBox with: ShowLocalDirectory 40em>>===@@
<script label="jash" title="JASH: Javascript Shell">
	clearMessage(); toggleJash();
</script><script>
	place.lastChild.className="button";
</script>
@@position:relative;+++^25em^*[bookmarklets]...
	<<moveablePanel name:bookmarklets_mainmenu>>{{fine block{
	<<tiddler InstantBookmarklets>>}}}===@@
@@position:relative;+++^450px^[palettemaker|view/update ColorPalette definitions]...
	<<moveablePanel name:palette_mainmenu>>PaletteMaker
----
	<<tiddler PaletteMaker>>===@@
}}}@@}}}}}}
!end
%/
<script>
	place.onmouseover = function(e){ addClass(this,"selected"); }
	place.onmouseout = function(e){ removeClass(this,"selected"); }
</script>{{small center{
{{fine mouseover{[[legal statements|LegalStatements]]}}}{{tiny mouseover{
<br>//<html><a href="http://www.TiddlyWiki.com" target="_blank"
	title="Visit www.TiddlyWiki.com">TiddlyWiki v<<version>></a></html>//
}}}}}}
<!--{{{-->
<script> // See StorySaverPlugin for more info
if (window.coreTweaks_getParameters==undefined) {
	window.coreTweaks_getParameters=window.getParameters;
	window.getParameters=function() {
		var p=window.coreTweaks_getParameters.apply(this,arguments);
		if (!p) {
			var cookies = document.cookie.split("; ");
			for (var c=0; c<cookies.length; c++) {
				var name=cookies[c].split("=")[0]; var value=cookies[c].split("=")[1];
				if (name=="txtSavedStory" && value.length) p=unescape(value);
			}
		}
		return p;
	}
}
</script>
<!--}}}-->
<!--{{{-->
<meta name="viewport" content="width=device-width" /> <!-- for webkit canvas -->
<script>
// tell InternetExplorer to use cached CSS background images (reduces server load)
// based on a suggestion by Bob Denny posted to the TiddlyWikiDev GoogleGroups discussion:
// http://groups.google.com/group/TiddlyWikiDev/msg/81797af532ed770f
try { document.execCommand("BackgroundImageCache", false, true); } catch(err) {;}
</script>
<style type="text/css">
#contentWrapper {display:none;}
body { background: url("images/sunset.jpg"); }
</style>
<div id="SplashScreen" style="border: 1px solid #ccc; -moz-border-radius:1em;-webkit-border-radius:1em; display:block; text-align:center; width:360px; margin:100px auto; padding:.25em 1em; color:#fff; font-size:24pt; font-family:verdana,arial,helvetica,sans; font-style:italic; background-color:#006; white-space:nowrap"><img src="images/eric3.gif" title="Hi there! I'm Eric Shulman, creator of TiddlyTools... enjoy!" style="float:right;">TiddlyTools<div style="font-size:12pt;font-style:italic; font-family:Trebuchet MS;">Small Tools for Big Ideas!</div><div style="font-size:8pt; color:#fff; padding-top:.5em">please wait...</div></div>
<!--}}}-->
/%
|''URL:''|http://www.martinswiki.com/ |
|''Description:''|Martin Buddens's Plugins |
|''Author:''|MartinBudden |
%/
/***
|Name|MatchTagsPlugin|
|Source|http://www.TiddlyTools.com/#MatchTagsPlugin|
|Documentation|http://www.TiddlyTools.com/#MatchTagsPluginInfo|
|Version|2.0.6|
|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
<<<
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];
			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);
	}
};
//}}}
/***
|Name|MatchTagsPluginInfo|
|Source|http://www.TiddlyTools.com/#MatchTagsPlugin|
|Documentation|http://www.TiddlyTools.com/#MatchTagsPluginInfo|
|Version|2.0.6|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|documentation|
|Description|documentation for MatchTagsPlugin|
!!!!!Usage
<<<
This plugin extends the {{{[tag[tagname]]}}} macro parameter syntax used by the TiddlyWiki core {{{<<list>>}}} macro so that, instead of a simple tagname value, you can specify a complex combination of tagname values using a //boolean expression// containing AND, OR, and NOT operators, enclosed in nested parentheses if needed.
{{{
<<list filter "[tag[expression]]">>
}}}
In addition, the plugin defines a new macro, {{{<<matchTags ...>>}}} that can be used instead of the core {{{<<list>>}}} macro to output a list of matching tiddlers //using a custom 'item format' and 'separator'//.  You can also use this macro to create a command link that displays the matching tiddlers within a popup list, similar to the standard {{{<<tag tagName>>}}} macro, but matching a combination of tag values rather than a single tag value.
{{{
<<matchTags inline "format" "separator" sort:fieldname tag expression>>
<<matchTags popup "label:..." "prompt:..." sort:fieldname tag expression>>
<<matchTags report TiddlerName "format" "separator" sort:fieldname tag expression>>
<<matchTags panel  Tiddlername "format" "separator" sort:fieldname tag expression>>
}}}
where:
* ''inline'', ''report'', ''panel'', and ''popup''<br>are keywords that indicate the type of output that the macro should produce:
** ''inline'' //(default)// - displays a list of matching tiddlers embedded directly in tiddler content
** ''popup'' - embeds a command button that, when clicked, lists matching tiddlers in a ~TiddlyWiki popup display
** ''report'' - generates a list of matching tiddler in a separate [[MatchingTiddlers]] report tiddler
** ''panel'' - displays an interactive form for generating a [[MatchingTiddlers]] report
* ''format''<br>defines the wiki-syntax for rendering list items.  The following //substitution markers// can be used to insert tiddler-specific information for each matched tiddler:
** {{{%0}}} - title
** {{{%1}}} - modifier (author)
** {{{%2}}} - modified (date of last change)
** {{{%3}}} - text (all tiddler content)
** {{{%4}}} - firstline (tiddler content up to the first newline)
** {{{%5}}} - description (tiddler slice or section content named "description" or "Description")
** {{{%6}}} - tags (space-separated, bracketed list)
* ''separator''<br>defines the wiki-syntax to use //between// each matching title (e.g., ", " creates a comma-separated list, while "\n" displays one tiddler per line).
* ''sort:fieldname'' (optional)<br>specifies the sort order for the resulting list of tiddlers.  You can specify any tiddler field name (standard or custom-defined).  Standard tiddler fieldnames include: //title, created, modified, modifier//.  If not specified, tiddlers are sorted by title.  You can prefix the fieldname with "+" or "-" to indicate ascending or descending order, respectively.
* ''tag expression''<br>the remaining parameter(s) are joined together to define the boolean expression to be matched.
When using the ''popup'' option, there are two additional (and optional) parameters you can specify:
* ''"label:..."''(optional)<br> indicates the text for the popup command link.  The default is to display the specified tag expression itself.
* ''"prompt:..."'' (optional)<br>indicates the mouseover 'tooltip' for the popup command link.
* note: you can apply custom CSS styles (e.g., font size) to the popup by adding a rule for ".matchTags .popup" to your [[StyleSheet]].
When using the ''report'' or ''panel'' option, an additional parameter may be provided:
* ''~TiddlerName''<br>specifies the target tiddler into which the output will be generated (default: [[MatchingTiddlers]])
Notes:
*A tag expression can use any combination of text operators: ''AND'', ''OR'', ''NOT'' (or their equivalent javascript operators: ''&&'', ''||'', ''!''), contained in nested parentheses as needed.
*Operators should be delimited by spaces or parentheses.
*Before matching, leading/trailing spaces are automatically trimmed and multiple spaces are reduced to single spaces.
*Tag values containing embedded spaces do //not// have to be enclosed in {{{[[...]]}}}.
*Tag values that contain boolean operators as ''literal text'' (e.g., {{{"foo and bar"}}} or {{{"foo && bar"}}} cannot be used within a compound boolean expression, but //can// be matched if specified by themselves, without any other tag values or operators.
*To match tiddlers that are untagged, use "-" as a special tag value within the expression.
*You can match "wildcard" tags  by using //regular expression// (i.e., "text pattern") syntax within a tag value, e.g. {{{[Tt]agvalue.*}}}
<<<
!!!!!Examples:
<<<
display a popup list:
{{{
<<matchTags popup sample OR (settings AND systemConfig)>>
}}}
><<matchTags popup sample OR (settings AND systemConfig)>>
display a popup list with custom label:
{{{
<<matchTags popup "label:samples and settings" sample OR (settings AND systemConfig)>>
}}}
><<matchTags popup "label:samples and settings" sample OR (settings AND systemConfig)>>
display a popup list of untagged tiddlers:
{{{
<<matchTags popup ->>
}}}
><<matchTags popup ->>
generate a report using interactive form control panel
{{{
<<matchTags panel "MatchingTiddlers" "[[%0]]" "\n" sample OR (settings AND systemConfig)>>
}}}
>{{smallform{<<matchTags panel "MatchingTiddlers" "[[%0]]" "\n" sample OR (settings AND systemConfig)>>}}}
comma-separated list:
{{{
<<matchTags "[[%0]]" ", " sample OR (settings AND systemConfig)>>
}}}
><<matchTags "[[%0]]" ", " sample OR (settings AND systemConfig)>>
numbered list (sorted by modification date, most recent first):
{{{
<<matchTags "#[[%0]] (%2)<br>^^%5^^" "\n" sort:-modified sample OR (settings AND systemConfig)>>
}}}
><<matchTags "#[[%0]] (%2)<br>^^%5^^" "\n" sort:-modified sample OR (settings AND systemConfig)>>
bullet-item list (using the TiddlyWiki core {{{<<list filter ...>>}}} macro):
//(Note: when using the core {{{<<list>>}}} macro, you should always enclose the entire tag filter parameter within quotes)//
{{{
<<list filter "[tag[sample OR (settings AND systemConfig)]]">>
}}}
><<list filter "[tag[sample OR (settings AND systemConfig)]]">>
<<<
!!!!!Revisions
<<<
2011.10.28 2.0.6 added .matchTags CSS class to popups to enable custom styling via StyleSheet
2011.01.22 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")
2010.03.02 2.0.3 added %6 format (tags)
2010.03.01 2.0.2 in formatList(), don't automatically put '[[' and ']]' around title (%0) in formatted output
2009.08.29 2.0.1 added support for {{{config.macros.matchTags.defTags}}} to auto-tag [[MatchingTiddlers]] output
2008.09.04 2.0.0 added "report" and "panel" options to generate formatted results and store in a tiddler.  Also, added config.macros.matchTags.formatList(place,fmt,sep) API to return formatted output for use with other plugins/scripts
2008.09.01 1.9.2 fixed return value from popup button handler so IE doesn't attempt to leave the page
2008.08.31 1.9.1 improved expression conversion handling to permit use of regular expressions for "wildcard" matching within tag values
2008.06.12 1.9.0 added support for formatted output of: title, who, when, text, firstline, description (slice or section)
2008.06.05 1.8.0 in getMatchingTiddlers(), added optional sortfield and tiddlers params to support use of alternative set of tiddlers instead of using current store content (provides filtering support for ImportTiddlersPlugin)
2008.06.04 1.7.1 in getMatchingTiddlers(), reworked conversion of expression for more robust parsing of whitespace, parentheses and javascript operators and allow use of "-" (untagged) //within// expressions
2008.05.19 1.7.0 in getMatchingTiddlers(), use reverseLookup() instead of forEachTiddler() to permit access to tiddlers included via [[IncludePlugin|http://tiddlywiki.abego-software.de/#IncludePlugin]]
2008.05.17 1.6.0 in getMatchingTiddlers(), rewrote expression conversion to handle tags with spaces tag values that are substrings of other tag values.
2008.05.16 1.5.0 added special case using "-" to find UNTAGGED tiddlers
2008.05.15 1.4.0 added "popup" output option
2008.05.14 1.3.4 instead of hijacking getTaggedTiddlers(), added tweak of filterTiddlers() prototype to replace getTaggedTiddlers() with getMatchingTiddler() so that core use of getTaggedTiddlers() does not perform boolean processing of tiddler titles such as [[To Be or not To Be]].  Also, improved "filter error" messages in getMatchingTiddlers() to report tag expression in addition to actual eval error.
2008.04.25 1.3.3 in getTaggedTiddlers(), fixed handling for "not" embedded within a tag
2008.04.21 1.3.2 in getTaggedTiddlers(), fixed handling for initial "NOT" and "NOT(expr)" syntax
2008.04.20 1.3.1 in getTaggedTiddlers(), corrected check for boolean expression to avoid excess processing of tags containing spaces.  Also, improved handling for non-existing tags that contain text of existing tags
2008.04.19 1.3.0 in filterTiddlers(), use getTaggedTiddlers() instead of matchTags(), and then hijack getTaggedTiddlers() to add matchTags() handling
2008.04.19 [*.*.*] plugin size reduction: moved documentation to [[MatchTagsPluginInfo]]
2008.03.25 1.2.0 added optional "sort:fieldname" parameter
2008.03.20 1.1.2 in handler(), replace 'encodeTiddlyLink' with explicit [[...]] brackets to ensure that one-word tiddler titles are properly rendered as TiddlyLinks
2008.02.29 1.1.1 in matchTags(), added handling to skip remaining tiddlers if expression has an error
2008.02.29 1.1.0 refactored to define store.matchTags() and extend store.filterTiddlers()
2008.02.28 1.0.0 initial release
<<<
<!--{{{-->
<!--
|Name|MediaEditTemplate|
|Source|http://www.TiddlyTools.com/#MediaEditTemplate|
|Version|1.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|template|
|Requires|ListboxPlugin, CheckboxPlugin|
|Description|custom version of edit template used when tiddler is tagged with "media"|
-->
<span class='toolbar' macro='toolbar +saveTiddler -cancelTiddler ! copyTiddler deleteTiddler ! fields '></span>
<div class='title' macro='view title'></div>
<div style='clear:both'></div>
<div class='viewer'>
<table class='borderless' style='width:100%'><tr valign='bottom'>
<td style='width:40%'>
	<div class='small'>this item (tiddler name):</div>
	<div class='editor' macro='edit title'></div>
</td><td style='width:30%'>
	<div class='small'>previous (tiddler name):</div>
	<div class='editor' macro='edit previous'></div>
</td><td style='width:30%'>
	<div class='small'>next (tiddler name):</div>
	<div class='editor' macro='edit next'></div>
</td></tr></table>
<table class='borderless' style='width:100%'><tr valign='bottom'>
<td style='width:70%'>
	<div class='small'>caption (text):</div>
	<div class='editor' macro='edit mediatitle'></div>
</td><td style='width:15%'>
	<div class='small'>item ID (text):</div>
	<div class='editor' macro='edit itemid'></div>
</td><td style='width:15%'>
	<div class='small'>group ID (text):</div>
	<div class='editor' macro='edit groupid'></div>
</td></tr></table>
<table class='borderless' style='width:100%'><tr valign='bottom'>
<td style='width:40%'>
	<div class='small left'>media&nbsp;URL (Windows/Real/Quicktime/Flash/JPG/GIF/HTML):</div>
	<div class='editor' macro='edit mediaurl'></div>
</td><td style='width:15%'>
	<div class='small left'>media&nbsp;type:</div>
	<div class='editor smallform' macro='select mediatype rows:1 width:100% "auto-detect=auto" "Windows Media=windows" "Real One=realone" "QuickTime=quicktime" "Flash=flash" "still image (JPG/GIF)=image" "web page (HTML)=iframe"'></div>
</td><td style='width:15%'>
	<span class='small'>width&nbsp;(px):</span>
	<span class='editor' macro='edit width'></span>
</td><td style='width:15%'>
	<span class='small'>height&nbsp;(px):</span>
	<span class='editor' macro='edit height'></span>
</td><td style='width:15%;white-space:nowrap'>
	<span class='smallform' macro='checkbox autoplay@'></span><!--
	--><span class='small'>autoplay</span><br>
	<span class='smallform' macro='checkbox showcontrols@ checked'></span><!--
	--><span class='small'>show controls</span>
</td></tr></table>
<div class='small'>Notes (text):</span></div>
<div class='editor' macro='edit text 5'></div>
<table class='borderless' style='width:100%'><tr valign='bottom'>
<td style='width:33%'>
	<div class='small'>Submit comments to (URL):</div>
	<div class='editor' macro='edit rpgaction'></div>
</td><td style='width:33%'>
	<div class='small'>OK 'landing' page (URL):</div>
	<div class='editor' macro='edit rpgok'></div>
</td><td style='width:33%'>
	<div class='small'>Retry 'landing' page (URL):</div>
	<div class='editor' macro='edit rpgretry'></div>
</td></tr></table>
<div class='small'>Tags (keywords):</span></div>
<div class='editor' macro='edit tags'></div>
<div class='small editorFooter' style='text-align:left !important;'>
	<span macro='message views.editor.tagPrompt'></span>
	<span macro='tagChooser'></span>
</div>
<div style='clear:both'></div>
</div>
<!--}}}-->
These plugins enable you to easily add various types of media (audio, video, flash, etc.) to your tiddler content.  The package includes several different kinds of embedded media players and a number of examples that define and present media content using custom templates, along with supporting plugins to provide additional rendering/formatting for the content surrounding the embedded player.
Jeremy Ruston (TiddlyWiki) and Eric Shulman (TiddlyTools)
Yerba Buena Gardens, The Metreon, San Francisco, CA
1/28/06 3:45pm
[[AmericaFree.TV|http://www.AmericaFree.tv]] offers FREE ~QuickTime video streams of classic comedy films such as //"Arsenic and Old Lace"//, as well as movies/TV shows from Abbott & Costello, The Three Stooges, Laurel & Hardy, and others.

Other streams from ~AmericaFree.TV include "Classic Movies" and "~B-Movies" from the 1950's and 1960's.  Visit [[AmericaFree.TV|http://www.AmericaFree.tv]] for details and links.
Live webcam views of Times Square, New York, complete with audio.  Automatically switches between several cameras from various vantage points.
<!--{{{-->
<!--
|Name|MediaViewTemplate|
|Source|http://www.TiddlyTools.com/#MediaViewTemplate|
|Version|1.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|template|
|Requires|ToolbarCommands, StoryViewerPlugin, WikifyPlugin, PlayerPlugin|
|Description|custom version of view template used when tiddler is tagged with "media"|
-->
<span class='toolbar' macro='toolbar [[ToolbarCommands::ViewToolbar]]'></span>
<span class='title'>
	<span class='floatleft' macro='tiddlerIcons' style='cursor:auto !important;'></span>
	<span macro='view title'></span>
</span>
<span class='subtitle'>
	<span style='white-space:nowrap' macro='view modified date [[DDD, MMM DDth YYYY]]'></span>
</span>
<div class='tagClear'></div>
<div class='viewer'>
<div class='floatright smallform' macro='storyViewer media list allbuttons'></div>
<div class='big' macro='view mediatitle wikified'></div>
<hr>
<table class='borderless' style='width:100%'><tr valign='top'>
<td style='width:50%' rowspan='2'>
	<div macro='wikify "{{stretch{<<player [[id=%0]] [[%1]] [[%2]] [[%3]] [[%4]] [[%5]] [[%6]]>>}}}"
		title mediatype mediaurl width height autoplay showcontrols'></div>
	<div style='text-align:center'>
		<span class='smallform' macro='checkbox autoplay@'></span>
		<span class='small'>autoplay</span>
		<span class='smallform' macro='checkbox showcontrols@ checked'></span>
		<span class='small'>show controls</span>
	</div>
</td>
<td style='width:50%' valign=top>
	<div class='fine floatright'>group:<span macro='wikify %0 groupid'></span></div>
	<div class='fine'>notes:</div>
	<div class='small groupbox' macro='view text wikified'></div>
</td></tr><tr><td valign=bottom>
	<form target="responseframe" method="post" enctype="multipart/form-data" action="">
		<div class='fine bold italic'>If you would like to ask a question or make a comment:</div>
		<div class='small groupbox'>
			<div style='display:block';>
				<textarea name="answer" style='width:100%;height:6em' rows="6"></textarea>
				<div class='center'>
					<span class='fine bold italic'>Enter your message, then press </span>
					<!-- hidden values set by onclick handler below -->
					<input type="hidden" name="username" value="txtUserName">
					<input type="hidden" name=itemid value="code#"> 
					<input type="hidden" name=okPage value="URL">
					<input type="hidden" name=retryPage value="URL">
					<input type="submit" value="send"
						onclick="var tid=story.findContainingTiddler(this).getAttribute('tiddler');
							var action=store.getValue(tid,'act');
							var ok=store.getValue(tid,'ok');
							var retry=store.getValue(tid,'retry');
							var defaults=store.getTiddlerText('DefaultResponder','').split('\n');
							this.form.action=action?action:defaults[0];
							this.form.okPage.value=ok?ok:defaults[1];
							this.form.retryPage.value=retry?retry:defaults[2];
							this.form.itemid.value=store.getValue(tid,'itemid');
							if (config.macros.setUserName.handler) config.macros.setUserName.handler();
							this.form.username.value=config.options.txtUserName;
							this.parentNode.parentNode.style.display='none';
							this.parentNode.parentNode.nextSibling.style.display='block';
							if (!this.form.action.length) { 
								var f=this.parentNode.parentNode.nextSibling.firstChild;
								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('<font size=-1><i>A responder URL has not been defined.<br>');
								d.writeln('Your response was not sent.</i></font>');
								d.close();
								return false;
							}
					">
				</div>
			</div><div style='display:none'><iframe
					src="" name="responseframe" id="responseframe"
					style="height:7em;width:100%;">
				</iframe>
				<div class='center medium'>
					<input type='button' value='try again...'
						title='edit and resend your response'
						onclick='var here=this.parentNode.parentNode;
							here.style.display="none"; here.previousSibling.style.display="block";'>
					&nbsp;&nbsp;&nbsp;&nbsp;
					<input type='button' value='next item...'
						onmouseover='var tid=story.findContainingTiddler(this).getAttribute("tiddler");
							this.title="proceed to "+store.getValue(tid,"next");'
						onclick='var tid=story.findContainingTiddler(this).getAttribute("tiddler");
							var next=store.getValue(tid,"next");
							if (next&&next.length) story.displayTiddler(null,next);
							else displayMessage("There is no next item...");'>
				</div>
			</div>
		</div>
	</form>
</td>
</tr></table>
<div class='tagClear'></div>
</div>
<!--}}}-->
MainMenu SideBarOptions SideBarTabs StoryMenu SiteMenu SiteMenuGoto SiteMenuSearch SiteMenuFile SiteMenuEdit SiteMenuView SiteMenuOptions SiteMenuOptionsUpload SiteMenuExtras
/***
|Name|MessageLogPlugin|
|Source|http://www.TiddlyTools.com/#MessageLogPlugin|
|Documentation|http://www.TiddlyTools.com/#MessageLogPlugin|
|Version|1.1.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.4|
|Type|plugin|
|Description|automatically log TW messages to a [[MessageLog]] tiddler|
This plugin uses a tiddler to store the text/link for each message that is displayed during a TiddlyWiki session.
!!!!!Documentation
<<<
This plugin automatically appends TiddlyWiki messages to a //shadow// tiddler, [[MessageLog]], to provide a short-term, per-session record of messages without altering any 'real' tiddlers in your document.  You can also suppress the //display// of messages that are recorded to the [[MessageLog]].  You can view the shadow [[MessageLog]] tiddler at any time to review the previous messages.  If you edit the MessageLog (making it a 'real' tiddler') it will then be saved with the rest of your TW document when you save the file, allowing you to keep a persistent, inter-session log rather than a short-term, per-session log.
<<<
!!!!!Configuration
<<<
<<option chkMessageLog>> log messages to <<option txtMessageLogName>>
<<option chkMessageLogFade>> fade message display after {{threechar{<<option txtMessageLogFade>>}}} seconds
<<option chkMessageLogQuiet>> hide all messages (when logging is enabled)
Date format (for log entries): <<option txtMessageLogDateFormat>>
<<<
!!!!!Revisions
<<<
2012.05.22 1.2.0 added chkMessageLogFade/txtMessageLogFade for timed hiding of messages
2012.01.29 1.1.1 in displayMessage(), added noLog param (bypass logging while still showing message)
2012.01.22 1.1.0 added chkMessageLogQuiet option.  Misc code cleanup
2008.12.24 1.0.2 hijack getMessageDiv() to add 'view log' command to message box
2008.12.23 1.0.1 defined ResetMessageLogCommand section and embedded command in default shadow message log.  Also, prevent refresh of log display if tiddler is currently being edited.
2008.12.23 1.0.0 initial release
<<<
!!!!!MessageLogControls
<<option chkMessageLog>> enable logging | <<option chkMessageLogFade>> fade message display after {{threechar{<<option txtMessageLogFade>>}}} seconds | <<option chkMessageLogQuiet>> hide all messages while logging | <html><a href='javascript:;' title='clear stored message log' onclick='var log=config.options.txtMessageLogName; if (!confirm(this.title+"?")) return false; config.shadowTiddlers[log]="\<\<tiddler [[MessageLogPlugin##MessageLogControls]]\>\>\n"; store.removeTiddler(log); story.refreshTiddler(log,null,true);'>clear message log</a></html>
!!!!!Code
***/
//{{{
version.extensions.MessageLogPlugin= {major: 1, minor: 2, revision: 0, date: new Date(2012,5,22)};

// SETTINGS
var defaults={
	chkMessageLog:		true,
	chkMessageLogQuiet:	false,
	chkMessageLogFade:	false,
	txtMessageLogFade:	'3',
	txtMessageLogName:	'MessageLog',
	txtMessageLogDateFormat:'YYYY.0MM.0DD 0hh:0mm:0ss'
}; for (var opt in defaults) config.options[opt]=defaults[opt];

// SHADOW LOG
config.shadowTiddlers[config.options.txtMessageLogName]=
	'<<tiddler [[MessageLogPlugin##MessageLogControls]]>>\n'

if (window.displayMessage_MessageLogHijack===undefined) { // only once
	window.displayMessage_MessageLogHijack=window.displayMessage;
	window.displayMessage=function(text,linkText,noLog) {
		var co=config.options; // abbrev
		this.displayMessage_MessageLogHijack.apply(this,arguments);
		if (noLog || !co.chkMessageLog) return;
		var log=co.txtMessageLogName;
		var fmt='>%0 '+(linkText?'[[%1|%2]]':'%1');
		var now=new Date().formatString(co.txtMessageLogDateFormat);
		var cmd='<<tiddler [[MessageLogPlugin##MessageLogControls]]>>\n';
		var out=store.getTiddlerText(log,cmd)+fmt.format([now,text,linkText])+'\n';
		config.shadowTiddlers[log]=out; // update shadow log
		var tid=store.getTiddler(log); if (tid) { // update real tiddler log, if present
			var who=co.chkForceMinorUpdate?tid.modifier:co.txtUserName;
			var when=co.chkForceMinorUpdate?tid.modified:new Date();
			store.saveTiddler(log,log,out,who,when,tid.tags,tid.fields);
		}
		if (!story.isDirty(log)) story.refreshTiddler(log,null,true); // only if log is not being edited
		if (co.chkMessageLogFade && co.txtMessageLogFade>0)
			setTimeout("jQuery('#messageArea').fadeOut('slow',clearMessage)",co.txtMessageLogFade*1000); 
	}
}

if (window.getMessageDiv_MessageLogHijack===undefined) { // only once
	window.getMessageDiv_MessageLogHijack=window.getMessageDiv;
	window.getMessageDiv=function() { // add 'view log' command to message box
		var co=config.options; // abbrev
		var msgArea=document.getElementById("messageArea"); if(!msgArea) return null;
		var addLogBtn=!msgArea.hasChildNodes();
		var r=this.getMessageDiv_MessageLogHijack.apply(this,arguments);
		if (co.chkMessageLog && co.chkMessageLogQuiet) msgArea.style.display="none";
		if(addLogBtn) {
			createTiddlyText(msgArea.firstChild,'|');
			createTiddlyButton(msgArea.firstChild,'log','view '+co.txtMessageLogName,
				function(ev) { story.displayTiddler(null,config.options.txtMessageLogName); });
		}
		return r;
	}
}
//}}}
/%
!info
|Name|MicroBrowser|
|Source|http://www.TiddlyTools.com/#MicroBrowser|
|Version|2.0.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|Type|transclusion|
|Description|simplified browser-in-browser with bookmarks|
Usage
<<<
{{{
<<tiddler MicroBrowser>>
<<tiddler MicroBrowser with: TiddlerName>>
}}}
*''TiddlerName'' (optional, default='MiniBrowserList') contains an ~HR-separated list of bookmarks (1st line=list text, 2nd line=URL).  
* For additional features, including support for embedded video and flash players, please see [[MiniBrowserPlugin]].
<<<
Example
<<<
{{{<<tiddler MicroBrowser>>}}}
<<tiddler MicroBrowser##show>>
<<<
!end
!show
{{smallform{<html><nowiki><style>
	#tiddlerMicroBrowser .tagged {display:none;}
</style>
<form style='display:inline;margin:0;padding:0;white-space:nowrap;' onsubmit='return false;'><!--
	--><input type='button' value='<' title='back' style='width:3%'
		onclick='try{this.form.nextSibling.history.go(-1)}catch(e){window.history.go(-1)}'><!--
	--><input type='button' value='>' title='forward' style='width:3%'
		onclick='try{this.form.nextSibling.history.go(+1)}catch(e){window.history.go(+1)}'><!--
	--><input type='button' value='+' title='refresh'style='width:3%'
		onclick='try{this.form.nextSibling.location.reload()}catch(e){;}'><!--
	--><input type='button' value='x' title='stop'style='width:3%'
		onclick='window.stop()'><!--
	--><select name='bookmarks' size='1' style='width:25%'
		onchange='this.form.url.value=this.value; this.form.go.click();'><!--
	--><option value=''>bookmarks...</option><!--
	--></select><!--
	--><input type='button' value='edit' title='edit the bookmarks list' style='width:6%'
		onclick='story.displayTiddler(null,this.form.bookmarks.getAttribute("tiddler"),2)'><!--
	--><input type='text' name='url' size='60' value='' style='width:39%'
		onfocus='this.select()'><!--
	--><input type='button' value='go' name='go' title='view URL' style='width:6%'
		onclick="var f=this.form; var i=this.form.nextSibling;
			var u=f.url.value.replace(/^\s*|\s*$/g,'');
			if (!u.length) u=f.url.value=f.bookmarks.value.replace(/^\s*|\s*$/g,'');
			if (u.length) { f.done.disabled=false; i.style.display='block'; i.src=u; }
			else { f.done.disabled=true; i.style.display='none'; i.src=''; }
		"><!--
	--><input type='button' value='open' title='open a separate tab/window' style='width:6%'
		onclick='if (this.form.url.value.length) window.open(this.form.url.value)'><!--
	--><input type='button' value='done' name='done' disabled title='disconnect from URL' style='width:6%'
		onclick="this.form.done.disabled=true; var i=this.form.nextSibling; i.style.display='none'; i.src='';"><!--
	--></form><iframe src='' width='100%' height='480' 
		style='display:none;background:#fff;border:1px solid;'></iframe>
</html><<tiddler {{
	var list=place.lastChild.getElementsByTagName('form')[0].bookmarks;
	while (list.options[1]) list.options[1]=null;
	var tid='$1'; if(tid=='$'+'1') tid='MiniBrowserList';
	list.setAttribute('tiddler',tid);
	var parts=store.getTiddlerText(tid,'').split('\n----\n');
	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
		var indent=value&&value.length?'\xa0\xa0':'';
		list.options[list.length]=new Option(indent+label,value);
	}
''}}>>}}}
!end
%/<<tiddler {{var src='MicroBrowser'; src+(tiddler&&tiddler.title==src?'##info':'##show');}}
	with: [[$1]]>>
/%
!info
|Name|MicroCalc|
|Source|http://www.TiddlyTools.com/#MicroCalc|
|Version|2.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Description|simple calculator using javascript eval() function|
Usage
<<<
{{{
<<tiddler MicroCalc>>
<<tiddler MicroCalc with: width>>
*''width'' (optional) is a CSS measurement (default=auto)
}}}
<<<
Example
>{{{<<tiddler MicroCalc with: 300px>>}}}
><<tiddler MicroCalc##show with: 300px>>
!end
!show
<html><nowiki>
<form action="javascript:;" style="width:$1;display:block;white-space:nowrap;margin:0;padding:0;"><!--
--><input name="input" value="0" style="width:70%;text-align:right;"
	title="INPUT: enter a JavaScript expression, function, or object/variable name"
	onfocus="this.select()"
	onkeyup="if (event.keyCode==13) {this.form.go.click(); return false;}"><!--
--><input name="go" type="button" value="=" style="width:10%"
	title="CALCULATE: evaluate input and display results"
	onclick="var i=this.form.input; var o=this.form.output; var val=i.value; var res='';
		try{res=eval(val);i.value=res}catch(e){res=e.description||e.toString()};
		o.value+=(o.value.length?'\n':'')+val+'\n='+res;
		o.style.display='block'; o.scrollTop=o.scrollHeight;
		i.select();i.focus();"><!--
--><input name="memstore" type="button" value="m" style="width:10%"
	title="MEMORY STORE: save input to temporary memory"
	onclick="var f=this.form; f.memory.value=f.input.value;
		f.memory.parentNode.style.display='block'"><!--
--><input name="clear" type="button" value="c" style="width:10%" 
	title="CLEAR: erase history and reset input"
	onclick="var i=this.form.input; var o=this.form.output;
		o.value='';o.style.display='none';
		i.value='0';i.select();i.focus();"><!--
--><div style="display:none"><!--
--><input name="memory" value="0" style="width:70%;text-align:right;"
	title="MEMORY: temporarily store input during calculations"><!--
--><input name="meminsert" type="button" value="mi" style="width:10%"
	title="MEMORY INSERT: append memory value to current input"
	onclick="var i=this.form.input;
		i.value+=this.form.memory.value; i.select();i.focus();"><!--
--><input name="memrecall" type="button" value="mr" style="width:10%"
	title="MEMORY RECALL: replace current input with memory value "
	onclick="var i=this.form.input;
		i.value=this.form.memory.value; i.select();i.focus();"><!--
--><input name="memclear" type="button" value="mc" style="width:10%"
	title="MEMORY CLEAR: clear temporary memory"
	onclick="var f=this.form; f.memory.value='0';
		f.memory.parentNode.style.display='none';
		f.input.select();f.input.focus();"><!--
--></div><!--
--><textarea name="output" rows=5 style="width:99%;display:none;text-align:right;"
	title="HISTORY: previous inputs and calculated results"></textarea><!--
--></form></html>
!end
%/<<tiddler {{tiddler&&tiddler.title=='MicroCalc'?'MicroCalc##info':'MicroCalc##show'}}
	with: {{'$1'!='$'+'1'?'$1':'auto'}}>>
TiddlyWiki.com - official release
http://www.TiddlyWiki.com
----
TiddlyWiki.org - wiki, tickets, source control
http://www.TiddlyWiki.org
----
GoogleGroup: TiddlyWiki - user/author discussion
http://groups.google.com/group/TiddlyWiki/
----
GoogleGroup: TiddlyWikiDev - core/plugin discussion
http://groups.google.com/group/TiddlyWikiDev/
----
TiddlyVault - index of add-ons from many sources
http://TiddlyVault.TiddlySpot.com
----
TiddlySpot - instant TiddlyWiki hosting!!
http://www.TiddlySpot.com
----
TiddlyTools - plugins, scripts, templates, etc.
http://www.TiddlyTools.com
----
del.icio.us - find popular TiddlyWiki sites
http://del.icio.us/tag/tiddlywiki
----
<<tiddler BookmarkList>>
----
<<tiddler MiniBrowserList_osmosoft>>
----
<<tiddler MiniBrowserList_tech>>
----
<<tiddler MiniBrowserList_news>>
----
<<tiddler MiniBrowserList_media>>
----
<<tiddler MiniBrowserList_flash>>
flash games...

----
Rag Doll
http://www.planetdan.net/pics/misc/georgerag.swf
----
Asteroids
http://www.80smusiclyrics.com/games/asteroids.swf
----
PacMan
http://www.80smusiclyrics.com/games/pacman.swf
----
Tetris
http://www.80smusiclyrics.com/games/tetris2.swf
----
Simon
http://www.80smusiclyrics.com/games/simon.swf
flickr photos...

----
HDR Pool (public collection)
http://www.flickr.com/groups/hdr/pool/show/
----
favorite videos...

----
"PovertyUSA" - WATCH THIS!
http://www.nccbuscc.org/cchd/povertyusa/tour.swf
----
Jack W counts (1yr old)
http://wolfram.org/media/jack_20050310_cleaned.mov
----
webcams...

----
Times Square
http://www.earthcam.com/usa/newyork/timessquare/asx/tsq_stream.asx
----
Monterey Bay
http://www.mbayaq.org/media/STRM/mba_mbay.asx
----
Wrightsville Beach, North Carolina
http://www.aroundtownnc.com/wvx/beachcam.wvx
----
Koningsplein, Amsterdam
"""mms://rembrandt.terena.nl/stream2"""
----
Corsica
http://195.6.173.164/liensmedias/webcam.asx
----
Kulak's Woodshed: Live/Recorded acoustic music
http://www.kulakswoodshed.com/high.asx
----
news...

----
BBC News24 - Live
http://www.bbc.co.uk/newsa/n5ctrl/live/nb/rm/video/now2_nb.ram
----
BBC News - London Summary
http://www.bbc.co.uk/london/realmedia/news/tvnews.ram
----
BBC Entertainment News
http://www.bbc.co.uk/newsa/n5ctrl/summaries/entertain/bb_liquid_news.ram
----
Bloomberg Business News
http://www.bloomberg.com/streams/video/LiveBTV200.ram
----
movies (AmericaFree.TV)...

----
Classic Comedy
http://www.americafree.tv/unicast_mov/AmericaFreeTVComedy.mov
----
Classic Movies
http://www.americafree.tv/unicast_mov/AmericaFreeTVClassics.mov
----
"B" Movies
http://www.americafree.tv/unicast_mov/AmericaFreeTVDimensionB.mov
----
science/education/govt...

----
PBS: Annenberg/CPB
http://www.scctv.net/annenberg_broadband.asx
----
NASA TV
http://science.ksc.nasa.gov/video/nasatv/nasatv.asx
----
C-SPAN 1
http://play.rbn.com/play.asx?url=cspan/cspan/wmlive/cspan1v.asf&proto=mms?mswmext=.asx
----
C-SPAN 2
http://play.rbn.com/play.asx?url=cspan/cspan/wmlive/cspan2v.asf&proto=mms?mswmext=.asx
----
C-SPAN 3
http://play.rbn.com/play.asx?url=cspan/cspan/wmlive/cspan3v.asf&proto=mms?mswmext=.asx
news and events...

----
News - CNN
http://www.cnn.com
----
News - BBC
http://news.bbc.co.uk
----
Comics
http://www.unitedmedia.com/comics/
----
Television
http://www.tvguide.com/listings/default.aspx
----
Weather
http://www.wunderground.com/US/CA/Sunnyvale.html
----
Earthquakes
http://quake.wr.usgs.gov/recenteqs/latest.htm
----
Maps
http://maps.google.com
BT/Osmosoft...

----
Jeremy Ruston
http://jermolene.wordpress.com/
----
Andrew Back
http://carrierdetect.com/
----
Fred Dohr
http://fnd.lewcid.org/blog/
----
James Shi
http://curiousjames.wordpress.com/
----
Jon Lister
http://jaybyjayfresh.com/
----
Nick Webb
http://www.erraticmusings.com/
----
Paul Downey
http://blog.whatfettle.com/
----
Phil Hawksworth
http://www.hawksworx.com/journal/
----
Phil Whitehouse
http://philwhitehouse.blogspot.com/
----
Simon McManus
http://simonmcmanus.com/
technical references...

----
Javascript QuickRef (DevGuru)
http://www.devguru.com/technologies/javascript/
----
CSS QuickRef (DevGuru)
http://www.devguru.com/technologies/css2/
----
CSS compatibility chart
http://www.webdevout.net/browser-support-css
----
Unicode Character Charts
http://www.alanwood.net/unicode/
----
UTF-8 Encoding (Wikipedia)
http://en.wikipedia.org/wiki/UTF-8
----
HTML Character entities (W3)
http://www.w3.org/TR/REC-html40/sgml/entities.html
----
Mozilla Developer Center
http://developer.mozilla.org/
----
Gecko DOM Reference
http://developer.mozilla.org/en/docs/Gecko_DOM_Reference
----
IP Lookup...

----
ARIN - North America
http://www.arin.net
----
RIPE - Europe
http://www.ripe.net
----
APNIC - Asia/Pacific
http://www.apnic.net
----
LACNIC - Latin America/Caribbean
http://www.lacnic.net
----
AFRINIC - Africa
http://www.afrinic.net
/***
|Name|MiniBrowserPlugin|
|Source|http://www.TiddlyTools.com/#MiniBrowserPlugin|
|Documentation|http://www.TiddlyTools.com/#MiniBrowserPluginInfo|
|Version|1.5.3|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.2|
|Type|plugin|
|Requires|PlayerPlugin (optional, recommended)|
|Description|embedded browser-in-browser with favorites lists and media support|
!!!!!Documentation
>see [[MiniBrowserPluginInfo]]
!!!!!Configuration
>Default mini browser size:
>width: <<option txtMiniBrowserWidth>> height: <<option txtMiniBrowserHeight>>
!!!!!Revisions
<<<
2011.02.08 1.5.3 added 'nocontrols' macro keyword parameter
2009.08.29 1.5.2 in load(), fixed 'noplayer' IFRAME output
2009.07.03 1.5.1 added onclick handling to 'n of m' button.  also, if noedit mode, add line numbers to bookmarks droplist items
2009.06.08 1.5.0 added optional 'noedit' mode: replaces add/del/edit buttons with next/previous navigation.
|see [[MiniBrowserPluginInfo]] for additional revision details|
2007.10.15 1.0.0 combined MiniBrowser and MediaCenter inline scripts and converted to true plugin
2006.03.01 0.0.0 inline script
<<<
!!!!!Code
***/
//{{{
version.extensions.MiniBrowserPlugin={major: 1, minor: 5, revision: 3, date: new Date(2011,2,8)};

config.shadowTiddlers.MiniBrowser='<<miniBrowser>>';
config.options.txtMiniBrowserWidth=config.options.txtMiniBrowserWidth||'100%';
config.options.txtMiniBrowserHeight=config.options.txtMiniBrowserHeight||'480';
config.macros.miniBrowser= {
	favoritesList: 'MiniBrowserList',
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		var noPlayer=params[0]&&params[0].toLowerCase()=='noplayer'; if (noPlayer) params.shift();
		var noEdit  =params[0]&&params[0].toLowerCase()=='noedit';   if (noEdit)   params.shift();
		var expand  =params[0]&&params[0].toLowerCase()=='expand';   if (expand)   params.shift();
		var hideControls=params[0]&&params[0].toLowerCase()=='hidecontrols'; if (hideControls) params.shift();
		var noControls  =params[0]&&params[0].toLowerCase()=='nocontrols';   if (noControls)   params.shift();
		hideControls	=noControls||hideControls;	// no controls implies hide controls
		var url		=(params[0]&&!store.tiddlerExists(params[0]))?params.shift():'';
		if (!url.length) noControls=hideControls=false; // if no initial URL, force controls to show
		if (!config.macros.player) noPlayer=true; // PlayerPlugin not installed
		var w=config.options.txtMiniBrowserWidth;
		var h=config.options.txtMiniBrowserHeight;

		// create form
		var guid=new Date().getTime()+Math.random().toString(); // globally unique ID
		var html=store.getTiddlerText('MiniBrowserPlugin##html');
		html=html.replace(/%id%/g,guid)
			.replace(/%noplayer%/g,noPlayer?'true':'')
			.replace(/%noedit%/g,noEdit||readOnly?'none':'inline')
			.replace(/%shownav%/g,noEdit||readOnly?'inline':'none')
			.replace(/%hidecontrols%/g,hideControls?'none':'block')
			.replace(/%bookmarksize%/g,(expand?70:20)+'%')
			.replace(/%urlsize%/g,(expand?69.5:20)+'%')
			.replace(/%linebreak%/g,expand?'<br>':'')
			.replace(/%favorites%/g,params[0]||config.macros.miniBrowser.favoritesList);
		createTiddlyElement(place,'span').innerHTML=html;

		// init form
		function $(i){return document.getElementById(i)}; // abbrev
		$('minibrowser_controls_'+guid).style.display=hideControls?'none':'block';
		$('minibrowser_resize_'+guid).style.display=hideControls?'none':'block';
		$('minibrowser_nocontrols_'+guid).style.display=noControls?'none':'inline';
		$('minibrowser_togglecontrols_'+guid).checked=!hideControls;
		$('minibrowser_form_'+guid).url.value=url;
		$('minibrowser_form_'+guid).w.value=w;
		$('minibrowser_form_'+guid).h.value=h;
		if (noPlayer) { // hide type list no PlayerPlugin
			$('minibrowser_type_'+guid).style.display='none';
			$('minibrowser_url_'+guid).style.width=(expand?81.5:32)+'%';
		}

		// load bookmarks droplist from HR-separated tiddler contents
		var b=$('minibrowser_bookmarks_'+guid);
		while (b.options[1]) b.options[1]=null; // clear list but leave 'prompt' item
		var p; while (p=params.shift()) this.getFavorites(b,p,noEdit); // load custom bookmarks
		if (b.length<2) this.getFavorites(b,config.macros.miniBrowser.favoritesList,noEdit); // default list
		$('minibrowser_nav_'+guid).value='1 out of '+b.length;

		// load initial URL (if any)
		var place=$('minibrowser_player_'+guid);
		this.load(place,guid,'','',w,h,true,noPlayer);
		this.go($('minibrowser_form_'+guid));
	},
	getFavorites: function(list,tid,noEdit) {
		var txt=store.getTiddlerText(tid); if (!txt||!txt.trim().length) return;
		txt=this.getWikifiedData(txt);
		var parts=txt.split('\n----\n');
		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
			var indent=value&&value.length?'\xa0\xa0':'';
			var prefix=value.length&&noEdit?list.length+1+': ':'';
			list.options[list.length]=new Option(prefix+indent+label,value,false,false);
		}
	},
	getWikifiedData: // wikify content, then extract text WITH newlines and HRs included
	function(txt) {
		var e=createTiddlyElement(document.body,'div'); wikify(txt,e);
		var breaks=e.getElementsByTagName('br');
		for (var b=0; b<breaks.length; b++)
			breaks[b].parentNode.insertBefore(document.createTextNode('\n'),breaks[b]);
		var lines=e.getElementsByTagName('hr');
		for (var l=0; l<lines.length; l++)
			lines[l].parentNode.insertBefore(document.createTextNode('----\n'),lines[l]);
		var items=e.getElementsByTagName('li');
		for (var i=0; i<items.length; i++)
			items[i].parentNode.insertBefore(document.createTextNode('\n'),items[i]);
		var txt=getPlainText(e);
		removeNode(e);
		return txt.replace(/\r*/g,'').replace(/\n\n/g,'\n');
	},
	load: function(place,id,type,url,w,h,showcontrols,noPlayer) {
		if (!noPlayer)
			config.macros.player.loadURL(place,id,type,url,w,h,showcontrols);
		else { // force IFRAME-only display
			if (!place) place=document.getElementById(id).parentNode;
			var fmt="<iframe name='%0' id='%0' src='%1' width='%2' height='%3' \
				style='background:#fff;border:1px solid'></iframe>";
			place.innerHTML=fmt.format([id,url,w,h]);
		}
	},
	go: function(f) {
		var url=f.url.value.trim();
		if (!url.length) url=f.url.value=f.bookmarks.value.trim();
		if (!url.length) { this.done(f); return false; }
		var id=f.playerID.value;
		document.getElementById('minibrowser_player_'+id).style.display='block';
		document.getElementById('minibrowser_controls2_'+id).style.display='block';
		this.load(null,id,f.type.value,f.url.value,f.w.value,f.h.value,f.ctrls.checked,f.noPlayer.value=='true');
		var matched=false; for (var i=0; i<f.bookmarks.options.length; i++) // select matching bookmark
			if (f.bookmarks.options[i].value==url) { f.bookmarks.selectedIndex=i; matched=true; break; }
		if (!matched) f.bookmarks.selectedIndex=0;
		f.done.disabled=false;
		return false;
	},
	done: function(f) {
		var id=f.playerID.value;
		this.load(null,id,null,null,f.w.value,0,f.ctrls.checked,f.noPlayer.value=='true');
		document.getElementById('minibrowser_player_'+id).style.display='none';
		document.getElementById('minibrowser_controls2_'+id).style.display='none';
		f.done.disabled=true; 
		return false;
	},
	fit: function(place) {
		// fudge factor to account for the other controls + padding + borders.  ADJUST THIS VALUE TO FIT LAYOUT
		var trim=89;
		var t=story.findContainingTiddler(place);
		if (!t) { t=place; while (t && t.className!='floatingPanel') t=t.parentNode; } if (!t) return;
		var w='100%'; // horizontal stretching via CSS works, but vertical stretching doesn't... so:
		var h=t.offsetHeight-trim; // workaround: get containing panel/tiddler height and subtract trim height
		var f=place.form;
		this.load(null,f.playerID.value,f.type.value,f.url.value,w,h,f.ctrls.checked,f.noPlayer.value=='true');
		place.form.w.value=w; place.form.h.value=h; // update width/height input fields
	},
	add: function(place,title) {
		var v=place.value; if (!v.length) return;
		var d=prompt('Please enter a description for\n'+place.value); if (!d || !d.length) return;
		var who=config.options.txtUserName;
		var when=new Date();
		var tid=store.getTiddler(title);
		var txt='%0\n%1\n----\n%2'.format([d,v,tid?tid.text:'']);
		store.saveTiddler(title,title,txt,who,when,tid?tid.tags:[],tid?tid.fields:{});
		if (!tid) story.displayTiddler(story.findContainingTiddler(place),title);
		else story.refreshTiddler(title,1,true);
		var here=story.findContainingTiddler(place);
		if (here) story.refreshTiddler(here.getAttribute('tiddler'),1,true);
	},
	del: function(place,title) {
		var v=place.value; if (!v.length) return;
		var d=place.options[place.selectedIndex].text; if (!d.length) return;
		if (!confirm('Are you sure you want to remove this favorite?\n\n'+d+'\n'+v)) return;
		var tid=store.getTiddler(title); if (!tid) return;
		var who=config.options.txtUserName;
		var when=new Date();
		var pat='%0\n%1\n----\n'.format([d.replace(/\xa0/g,''),v]); var re=new RegExp(pat,'i');
		var txt=tid.text.replace(re,'');
		store.saveTiddler(title,title,txt,who,when,tid?tid.tags:[],tid?tid.fields:{});
		story.refreshTiddler(title,1,true);
		var here=story.findContainingTiddler(place);
		if (here) story.refreshTiddler(here.getAttribute('tiddler'),1,true);
	}
}
//}}}
/***
//{{{
!html
<form id='minibrowser_form_%id%' style='display:block;margin:0;padding:0' onsubmit='return config.macros.miniBrowser.go(this);'><!--
--><nobr><input type='hidden' name='playerID' value='%id%'><input type='hidden' name='noPlayer' value='%noplayer%'><!--
--><div id='minibrowser_controls_%id%' style='display:%hidecontrols%'><!--
--><input type='button' value='<' title='back' style='width:3%'
	onclick='try{window.frames["player_%id%"].history.go(-1)}catch(e){window.history.go(-1)}' ><!--
--><input type='button' value='>' title='forward' style='width:3%'
	onclick='try{window.frames["player_%id%"].history.go(+1)}catch(e){window.history.go(+1)}'><!--
--><input type='button' value='+' title='refresh'style='width:3%'
	onclick='try{window.frames["player_%id%"].location.reload()}catch(e){;}'><!--
--><input type='button' value='x' title='stop'style='width:3%'
	onclick='window.stop()'><!--
--><select name='bookmarks' id='minibrowser_bookmarks_%id%' size='1' style='width:%bookmarksize%'
	onchange='this.form.url.value=this.value;
		this.form.nav.value="%0 out of %1".format([this.selectedIndex+1,this.length]);
		this.form.nav.title="reload %0".format([this.options[this.selectedIndex].text]);
		return config.macros.miniBrowser.go(this.form);'><!--
--><option value=''>bookmarks...</option><!--
--></select><!--
--><span style='display:%noedit%'><!--
--><input type='button' value='add' title='add URL to the bookmarks' style='width:6%'
	favorites="%favorites%"
	onclick='config.macros.miniBrowser.add(this.form.url,this.getAttribute("favorites"));'><!--
--><input type='button' value='del' title='remove URL from the bookmarks' style='width:6%'
	favorites="%favorites%"
	onclick='config.macros.miniBrowser.del(this.form.bookmarks,this.getAttribute("favorites"));'><!--
--><input type='button' value='edit' title='edit the bookmarks list' style='width:6%'
	favorites="%favorites%"
	onclick='story.displayTiddler(null,this.getAttribute("favorites"),2)'><!--
--></span><!--
--><span style='display:%shownav%'><!--
--><input name=prev type='button' value='&#x25C4;' title='view previous bookmark' style='width:3%'
	onclick='var b=document.getElementById("minibrowser_bookmarks_%id%");
		b.selectedIndex=Math.max(b.selectedIndex-1,0); b.onchange();'><!--
--><input name='nav' id='minibrowser_nav_%id%'
	type='button' value='N out of MM' title='enter a bookmark number' style='width:12%'
	onclick='return this.form.next.click();
		var b=this.form.bookmarks;
		var i=prompt("Enter a bookmark number (1-"+b.length+")",b.selectedIndex+1);
		if (i && i<b.length) { b.selectedIndex=i-1; b.onchange(); }'><!--
--><input name=next type='button' value='&#x25BA;' title='view next bookmark' style='width:3%'
	onclick='var b=document.getElementById("minibrowser_bookmarks_%id%");
		b.selectedIndex=Math.min(b.selectedIndex+1,b.length); b.onchange();'><!--
--></span><!--
-->%linebreak%<!--
--><select name='type' id='minibrowser_type_%id%' size='1' style='width:12%'
	onchange='var opt=this.options; for (var i=0; i<opt.length; i++)
		if (i==this.selectedIndex) opt[i].text=opt[i].text.replace(/\xa0\xa0/,"&radic;");
		else opt[i].text=opt[i].text.replace(/&radic;/,"\xa0\xa0");
		if (this.selectedIndex==0) opt[1].text=opt[1].text.replace(/\xa0\xa0/,"&radic;");'><!--
--><option value=''>type...</option><!--
--><option value=''>&radic; auto-detect</option><!--
--><option value='iframe'>&nbsp;&nbsp; web page</option><!--
--><option value='windows'>&nbsp;&nbsp; windows media</option><!--
--><option value='realone'>&nbsp;&nbsp; real one</option><!--
--><option value='quicktime'>&nbsp;&nbsp; quicktime</option><!--
--><option value='flash'>&nbsp;&nbsp; flash</option><!--
--><option value='image'>&nbsp;&nbsp; jpg/gif/png</option><!--
--></select><!--
--><input type='text' name='url' id='minibrowser_url_%id%' size='60' value='' style='width:%urlsize%'
	onfocus='this.select()'><!--
--><input type='submit' value='go' title='view URL' style='width:6%'><!--
--><input type='button' value='open' title='open a separate tab/window' style='width:6%'
	onclick='if (this.form.url.value.length) window.open(this.form.url.value)'><!--
--><input type='button' value='done' name='done' disabled title='disconnect from URL' style='width:6%'
	onclick='return config.macros.miniBrowser.done(this.form);'><!--
--></div><!--
--><div id='minibrowser_player_%id%' style='display:none;text-align:center'></div><!--
--><span id='minibrowser_controls2_%id%' style='margin-top:2px;display:none;'><!--
--><div id='minibrowser_resize_%id%' style='display:%hidecontrols%;float:right'><!--
--> size: <input type='text' name='w' size='3' value='' style=''
	onfocus='this.select()'><!--
-->x<input type='text' name='h' size='3' value='' style=''
	onfocus='this.select()'><!--
--> <input type='submit' value='set' style='width:5em'
	onclick='var f=this.form;
		if(!f.w.value.trim().length) f.w.value=config.options.txtMiniBrowserWidth;
		if(!f.h.value.trim().length) f.h.value=config.options.txtMiniBrowserHeight;
		config.options.txtMiniBrowserWidth=f.w.value; config.options.txtMiniBrowserHeight=f.h.value;
		saveOptionCookie("txtMiniBrowserWidth"); saveOptionCookie("txtMiniBrowserHeight");'><!--
--><input type='submit' value='reset' style='width:5em'
	onclick='var f=this.form; f.ctrls.checked=true; f.w.value="100%"; f.h.value="480";
		config.options.txtMiniBrowserWidth=f.w.value; config.options.txtMiniBrowserHeight=f.h.value;
		saveOptionCookie("txtMiniBrowserWidth"); saveOptionCookie("txtMiniBrowserHeight");'><!--
--><input type='button' value='fit' title='resize player to fit containing window' style='width:5em'
	onclick='config.macros.miniBrowser.fit(this)'><!--
--></div><!--
 style='display:%hidecontrols%'
--><span id='minibrowser_nocontrols_%id%'><!--
--> <input type='checkbox' name='ctrls' id='minibrowser_togglecontrols_%id%' title='toggle minibrowser controls' CHECKED 
	onclick='document.getElementById("minibrowser_controls_%id%").style.display=this.checked?"block":"none";
		document.getElementById("minibrowser_resize_%id%").style.display=this.checked?"block":"none";'
><a href='' title='toggle minibrowser controls'
	onclick='this.previousSibling.click();return false;'>show controls</a><!--
--></span><!--
--></span><!--
--></nobr></form>
!end
//}}}
***/
 
/***
|Name|MiniBrowserPlugin|
|Source|http://www.TiddlyTools.com/#MiniBrowserPlugin|
|Documentation|http://www.TiddlyTools.com/#MiniBrowserPluginInfo|
|Version|1.5.3|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.2|
|Type|plugin|
|Requires|PlayerPlugin (optional, recommended)|
|Description|embedded browser-in-browser with favorites lists and media support|
!!!!!Usage
<<<
{{{<<miniBrowser noplayer noedit expand hidecontrols nocontrols URL TiddlerName TiddlerName TiddlerName...>>}}}
* ''noplayer'' (optional)<br>disables support for embedded media player (using [[PlayerPlugin]], if installed)
* ''noedit'' (optional)<br>hides bookmark //add//, //del//, and //edit// buttons
* ''expand'' (optional)<br>displays minibrowser controls on two lines instead of one for increased readability, especially when long titles or URLs are displayed.
* ''hidecontrols'' (optional)<br>hides initial display of minibrowser controls (except for 'show controls' checkbox)<br>//note: if no initial URL is specified, controls will be shown anyway//
* ''nocontrols'' (optional)<br>hides all minibrowser controls including 'show controls' checkbox<br>//note: if no initial URL is specified, controls will be shown anyway//
* ''URL'' (optional)<br>specifies an initial URL to open when the mini browser is rendered
* ''TiddlerName'', ''TiddlerName''... (optional)<br>indicates one or more tiddlers containing 'HR-separated' lists of favorites.<br>//notes: if no tiddler is specified, [[MiniBrowserList]] is used by default.  In addition, when adding/deleting favorites, the plugin automatically updates [[MiniBrowserList]], regardless of any alternative lists of favorites stored in separate tiddlers.  After changes to [[MiniBrowserList]] are made, you can then use cut/paste to manually move entries from that tiddler into other tiddlers.//
<<<
!!!!!Configuration
>Default mini browser size:
>width: <<option txtMiniBrowserWidth>> height: <<option txtMiniBrowserHeight>>
!!!!!Examples
>{{{<<miniBrowser>>}}}<br>{{smallform small{<<miniBrowser>>}}}
>{{{<<miniBrowser noedit>>}}}<br>{{smallform small{<<miniBrowser noedit>>}}}
>{{{<<miniBrowser expand>>}}}<br>{{smallform small{<<miniBrowser expand>>}}}
>{{{<<miniBrowser noedit expand>>}}}<br>{{smallform small{<<miniBrowser noedit expand>>}}}
>{{{<<miniBrowser hidecontrols http://www.TiddlyWiki.com>>}}}<br>{{smallform small{<<miniBrowser hidecontrols http://www.TiddlyWiki.com>>}}}
!!!!!Revisions
<<<
2011.02.08 1.5.3 added 'nocontrols' macro keyword parameter
2009.08.29 1.5.2 in load(), fixed 'noplayer' IFRAME output
2009.07.03 1.5.1 added onclick handling to 'n of m' button.  also, if noedit mode, add line numbers to bookmarks droplist items
2009.06.08 1.5.0 added optional 'noedit' mode to hide bookmark add/del/edit buttons.  Also, moved html def'n to section (saves space)
2008.09.30 1.4.0 removed hard-coded fontsize.  Added 'expand' option (wider controls, displayed on two lines)
2008.09.16 1.3.1 fixed getWikifiedData() when using IE (remove \r and multiple \n)
2008.08.12 1.3.0 added support for wikifying content from favorites lists to enable use of forEachTiddler or inline script output to generate lists on the fly.
2008.08.06 1.2.2 corrected size control buttons to use fixed width
2008.04.07 1.2.1 added txtMiniBrowserWidth and txtMiniBrowserHeight.  cleanup init handling (somewhat)
2008.04.06 1.2.0 added support for specifying initial URL to view (suggested by Richard Berg).  When opening a URL, select matching entry (if any) in bookmarks droplist.  Added support for hiding minibrowser controls.
2008.01.19 1.1.0 added support for optional extra favorites lists stored in separate tiddlers
2007.10.15 1.0.0 combined MiniBrowser and MediaCenter inline scripts and converted to true plugin
2006.03.01 0.0.0 inline script
<<<
!NewDocumentPlugin
{{{
__2008.04.22 IMPORTANT NOTICE:__
>The features previously provided by this plugin have been replaced by [[SaveAsPlugin]] and [[SnapshotPlugin]].
}}}
!CommentScript
{{{
__2008.04.12 IMPORTANT NOTICE:__
>This inline script has been replaced by [[CommentPlugin]].
}}}
!SelectStylesheetPlugin
{{{
__2008.01.22 IMPORTANT NOTICE:__
>As of TiddlyWiki version 2.3.0, this plugin has been replaced by [[SwitchThemePlugin]].
}}}
!SliceGridPlugin(Info)?
{{{
__2009.09.20 IMPORTANT NOTICE:__
>This plugin has been replaced by [[GridPlugin]], which displays/edits tiddler sections and fields as well as slices.
}}}
!RescueStoreArea
{{{
__2010.03.01 IMPORTANT NOTICE:__
>This tiddler has been replaced by [[SaveToClipboard]], which supports direct clipboard access, and outputs complete TiddlyWiki documents, including core source code.
}}}
!ExpandSlidersScript
{{{
__2010.12.28 IMPORTANT NOTICE:__
>This inline script has been replaced by the [[ToggleSliders]] transclusion.
}}}
!.+PluginInfo
{{{
>Sorry, no additional documentation is available for this plugin.
}}}
!FAQ_.*
{{{
This TiddlyTools FAQ article has been archived in:
>{{medium{http://www.TiddlyTools.com/faq.html#$1}}}
<<tiddler GetTheFAQs with: [[http://www.TiddlyTools.com/faq.html]] [[faq]] [[$1]]>>
}}}
!http://.*
{{{
$1
<html><iframe src="$1" style="width:100%;height:480px"></iframe></html>
}}}
/***
|Name|MissingTiddlersPlugin|
|Source|http://www.TiddlyTools.com/#MissingTiddlersPlugin|
|Documentation|http://www.TiddlyTools.com/#MissingTiddlersPluginInfo|
|Version|1.2.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|define fallback content for missing tiddlers|
!!!Documentation
>see [[MissingTiddlersPluginInfo]]
!!!Revisions
<<<
2009.10.11 1.2.0 strip leading/trailing 'pre' formatting from fallback content
| Please see [[MissingTiddlersPluginInfo]] for previous revision details |
2009.01.20 1.0.0 initial release
<<<
!!!Code
***/
//{{{
version.extensions.MissingTiddlersPlugin={major: 1, minor: 2, revision: 0, date: new Date(2009,10,11)};

config.views.wikified.defaultText
	='<<missingTiddler [[%0]] MissingTiddlersList MissingTiddler>>';

config.shadowTiddlers.MissingTiddler
	="The tiddler '$1' does not exist. Double-click to create it.";

config.macros.missingTiddler = { 
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		var title=params[0]||'';
		var tid=params[1]||'MissingTiddlersList';
		var t=store.getTiddlerText(tid,'');
		var out=store.getTiddlerText(params[2]||'MissingTiddler','');
		var list=[]; var p=/(?:^|\n)!{1,6}([^\n]*)\n/gm;
		do { var m=p.exec(t); if (m) { if (m[1]!='end') list.push(m[1]); } } while(m);
		for (var i=0; i<list.length; i++) if (title.match(new RegExp(list[i])))
			{ out=store.getTiddlerText(tid+'##'+list[i]).trim(); break; }
		out=out.replace(/^\{\{\{\n/,'').replace(/\n\}\}\}$/,'').replace(/\$1/g,title);
		wikify(out,place);
	}
}
//}}}
|Name|MissingTiddlersPluginInfo|
|Source|http://www.TiddlyTools.com/#MissingTiddlersPlugin|
|Documentation|http://www.TiddlyTools.com/#MissingTiddlersPluginInfo|
|Version|1.2.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|documentation|
|Description|documentation for MissingTiddlersPlugin|
By default, TiddlyWiki defines "catch-all" fallback content that is displayed if a tiddler doesn't exist:
>{{{The tiddler '$1' doesn't yet exist. Double-click to create it}}}
Rather than simply displaying a standard fallback message, the MissingTiddlersPlugin first attempts to match the missing tiddler title using a custom-defined list of title patterns and fallback content.  If a match is found, the corresponding alternative fallback content is rendered.  If no match is found, the plugin then displays the standard catch-all content as usual.  The plugin also creates a shadow tiddler, [[MissingTiddler]], so that you can easily customize the catch-all content to suit your needs.
!!!Usage
<<<
The TW core value for {{{config.views.wikified.defaultText}}} is automatically modified, like this:
{{{
<<missingTiddler [[%0]] ListName CatchAllName>>
}}}
*''"""[[%0]]"""''<br>inserts the title of the missing tiddler (this must be entered exactly as it appears, including the brackets)
*{{block{
''~ListName'' (default=[[MissingTiddlersList]])<br>specifies the tiddler containing the list of regexp-based title patterns and associated fallback content, where ''each section heading is a title pattern'', and ''the body of the section is the fallback content''
}}}
*''~CatchAllName'' (default=[[MissingTiddler]])<br>contains fallback content for any missing titles that are ''not matched'' in [[MissingTiddlersList]] (or if [[MissingTiddlersList]] does not exist at all).
For most purposes, you will not need to adjust this macro, and can simply edit [[MissingTiddlersList]] and/or [[MissingTiddler]] to define your desired alternative fallback content.  For example:

[[MissingTiddlersList]]:
{{{
!SomeRenamedTitle
$1 has been replaced by SomeOtherTitle
!SomeRedirectedTitle
<<tiddler SomeNewTitle>>
!SomeDeletedTitle
$1 has been removed and is no longer available.
!FAQ_.*
All FAQ articles have been moved to [[the FAQ archive|faq.html]]
}}}
[[MissingTiddler]]
{{{
Missing or Unknown tiddler: $1
Double-click to create it, or:
<<search>>
}}}
*You can embed the requested tiddler title into any fallback content by using {{{$1}}} as a //substitution marker//.  When rendered, the title of the missing tiddler is automatically inserted in place of the marker.
*{{block{
Fallback content can include embedded macros that provide additional interaction (e.g., {{{<<search>>}}}) or perform side-effect processing for specific missing tiddlers.  For example, you can use {{{<<loadTiddlers>>}}} (see [[LoadTiddlersPlugin]]) to automatically attempt to retrieve a missing tiddler "on-demand" from another 'archival' TiddlyWiki document, like this:
{{{
<<loadTiddlers [[tiddler:$1]] [[archive.html]] quiet nodirty noreport temporary>>
}}}
}}}
*To prevent side-effect macros from being processed when directly viewing the [[MissingTiddlerList]], you can enclose the fallback content within """{{{...}}}""".  When that fallback content is actually used, the plugin will automatically remove this surrounding syntax so that the content, including any side-effect macros, will be rendered normally at that time.
*The plugin uses the //first successful match// in the list.  Be sure to define more specific patterns (e.g., exact tiddler titles) before any patterns that contain matching wildcard sequences (e.g., ".*"), so that the more general pattern will not be applied instead of the exact match.
*The fallback content is only used when attempting to //display// a missing tiddler and will //not// be applied when transcluding a missing tiddler (e.g., {{{<<tiddler SomeMissingTitle>>}}}), nor will it change the use of TiddlyWiki core functions: {{{ store.tiddlerExists(), store.getTiddler(),}}} or {{{store.getTiddlerText().}}}
<<<
!!!Revisions
<<<
2009.10.11 1.2.0 strip leading/trailing 'pre' formatting from fallback content
2009.10.11 1.1.0 use section formatting in MissingTiddlersList
2009.01.20 1.0.0 initial release
<<<
/%
|''URL:''|http://mptw.tiddlyspot.com/|
|''Description:''|a tiddlywiki distribution and plugins document|
|''Author:''|SimonBaird|
%/
/%
!info
|Name|MoveTiddlerToTop|
|Source|http://www.TiddlyTools.com/#MoveTiddlerToTop|
|Version|2.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Description|reposition the current tiddler to top of the story column|
Usage:
<<<
{{{
<<tiddler MoveTiddlerToTop>>
}}}
<<<
!end
%/<<tiddler {{
	var out='MoveTiddlerToTop##info';
	if (!tiddler||tiddler.title!='MoveTiddlerToTop') {
		var here=story.findContainingTiddler(place);
		if (here) here.parentNode.insertBefore(here,here.parentNode.firstChild);
		out='';
	}
out;}}>>
<!--{{{-->
<!--
|Name|MoveableEditTemplate|
|Source|http://www.TiddlyTools.com/#MoveableEditTemplate|
|Version||
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|template|
|Requires|MoveablePanelPlugin, EditTemplate, TaggedTemplateTweak|
|Description|add moveablePanel macro to tiddlers tagged with 'moveable'|
-->
<div class='moveablePanel'>
	[[EditTemplate]]
	<div macro='moveablePanel name:{{tiddler?tiddler.title:""}} height:auto'></div>
</div>
<!--}}}-->
<html><style>
#tiddlerMoveablePanelPackage .tagged { display:none; }
#tiddlerMoveablePanelPackage .viewer .content { max-height:999999em; height:auto; overflow:visible; }
</style></html>@@font-size:150%;''"free-range" tiddlers with room to roam...''@@
<<<
@@font-size:90%;line-height:120%;text-align:justify;display:block;<<tiddler QuickStart##badge with: moveable.html>>[[MoveablePanelPlugin]] turns tiddlers and other document content into  '''moveable panels' that can be dragged with the mouse to  //undock// them from their default //anchor points// and reposition them to almost any location on the page -- even far off screen!''  Using moveable panels, your document content can now be spread out over a wide (actually, //infinite//) area, both horizontally and vertically, allowing you to ''quickly create a complete 'web desktop' with different groupings of moveable tiddlers and menus''... all within a single TiddlyWiki document!

No matter where you place the panels, the document extents will ''automatically grow (or shrink) as needed to contain all moveable panels''.  Unfortunately, ''you can only scroll in one direction at a time when using the browser window's separate horizontal and vertical scrollbars'', making navigation between far-flung panels extremely tedious and awkward.  To address this, [[DragScrollPlugin]] allows you to ''scroll the browser window in both the horizontal and vertical directions at the same time, simply by holding down the SHIFT key while dragging the mouse across the page'' until the desired content is scrolled into view.

Of course, once you can move things around, you will want them to //stay there//.  By itself, [[MoveablePanelPlugin]] has no memory and all panels are rendered at their original, docked anchor points each time the document is loaded into the browser.  [[PanelManagerPlugin]] adds the ability to automatically ''track and record each panel's current position and size in a //panel map//, using simple wiki-formatted tables stored in tiddlers''.  The current panel map is also automatically stored as a browser-cookie, so that ''wherever you place a panel, it stays there until you move it again'', even in between document sessions.

[[PanelManagerPlugin]] also adds a popup menu with lots of functions for managing individual moveable panels (e.g., 'bring to front', 'jump to panel', 'dock/undock', etc.) plus a ''powerful, graphical panel map viewer and interactive page navigator'' that allows you to load, save, edit and view //named// panel maps stored in your document.  You can also scroll directly to any panel or other selected page location, anywhere on the page, by using the 'jump to panel' command or ''//compass navigation tool//'' from the Panel Manager popup menu.

You can access the Panel Manager popup map viewer at any time from the <<moveablePanel menu label:[[Panel Manager button (&#x2261;)]]>> that is added to the upper right corner of each undocked panel.  You can also ''open the popup menu from //anywhere// on the page simply by using ALT+CLICK on the //background// of the page'' (i.e., not on a link or other //active// element that could respond to the click!).  This permits access to the Panel Manager commands, even when there are no moveable panels visible on the screen.
@@
<<<
/***
|Name|[[MoveablePanelPlugin]]|
|Source|http://www.TiddlyTools.com/#MoveablePanelPlugin|
|Documentation|http://www.TiddlyTools.com/#MoveablePanelPluginInfo|
|Version|3.0.4|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|move/size any tiddler or page element|
Use the mouse to move/resize any specific tiddler content, page element, or [[floating slider panel|NestedSlidersPlugin]].
!!!!!Documentation
>see [[MoveablePanelPluginInfo]]
!!!!!Configuration
<<<
<<option chkMoveablePanelShowStatus>> show position/size while moving/resizing a panel
<<option chkMoveablePanelShowManager>> automatically add Panel Manager button to undocked panels (see [[PanelManagerPlugin]])
<<<
!!!!!Revisions
<<<
2010.12.24 3.0.4 fixed findMouseX/findMouseY for webkit browsers
|please see [[MoveablePanelPluginInfo]] for additional revision details|
2006.03.04 1.0.0 Initial public release
<<<
!!!!!Code
***/
//{{{
version.extensions.MoveablePanelPlugin= {major: 3, minor: 0, revision: 4, date: new Date(2010,12,24)};
if (config.macros.moveablePanel===undefined) config.macros.moveablePanel={};
//}}}
// // translate
//{{{
// TRANSLATORS: copy this section to MoveablePanelPluginLingoXX (where 'XX' is a language/country code)
if (config.macros.moveablePanel===undefined) config.macros.moveablePanel={};
merge(config.macros.moveablePanel,{

	foldLabel:	'\u2212', // minus
	foldTip:	'FOLD=reduce panel size',
	unfoldLabel:	'+',
	unfoldTip:	'UNFOLD=restore panel size',
	hoverLabel:	'^',
	hoverTip:	'HOVER=keep panel in view when scrolling',
	scrollLabel:	'\u2248', // asymp
	scrollTip:	'SCROLL=allow panel to move with page',
	closeLabel:	'X',
	closeTip:	'CLOSE=hide this panel',
	dockLabel:	'\u221A', // radic
	dockTip:	'DOCK=reset size/position',

	noPid:		'unnamed panel',

	statusMsg:	'%0: pos=(%1,%2)%3 size=(%4,%5) z=%6',
	hoveredMsg:	'[hovering]',
	dockedTip:	'%0: docked',
	scrollMsg:	'%0: pos=(%1,%2)',
	msgDuration:	3000,

	moveTip:	'%0DRAG EDGE=move',
	sizeTip:	'(SHIFT=resize)',
	sizeWidthTip:	'(SHIFT=resize width)',
	sizeHeightTip:	'(SHIFT=resize height)',
	clickTip:	  'CLICK=bring to front, SHIFT-CLICK=send to back',
	dblclickdockTip:  'DOUBLE-CLICK=dock',
	dblclickunfoldTip:'DOUBLE-CLICK=unfold',

	foldParam:	'fold',
	hoverParam:	'hover',
	nocloseParam:	'noclose',
	nodockParam:	'nodock',
	undockedParam:	'undocked',

	jumpParam:	'jump',
	dockParam:	'dock',
	moveParam:	'move',
	labelParam:	'label',
	promptParam:	'prompt',

	allParam:	'all',
	nameParam:	'name',
	topParam:	'top',
	leftParam:	'left',
	widthParam:	'width',
	heightParam:	'height',

	managerParam:	'manager'
});
//}}}
// // global functions (general utilities)
//{{{
// if removeCookie() function is not defined by TW core, define it here (for <TW2.5)
if (window.removeCookie===undefined) {
	window.removeCookie=function(name) {
		document.cookie = name+'=; expires=Thu, 01-Jan-1970 00:00:01 UTC; path=/;'; 
	}
}
if (window.copyObject===undefined) {
	window.copyObject=function(src)	{
		for (var i in src) this[i]=typeof src[i]!='object'?src[i]:new copyObject(src[i]);
	}
}
if (window.compareObjects===undefined) {
	window.compareObjects=function(a,b) {
		if (a===b) return true;
		if (a==undefined||b==undefined) return false;
		for (var i in a) if (typeof a[i]!='object'?a[i]!==b[i]:!compareObjects(a[i],b[i])) return false;
		return true;
	}
}
if (window.isEmptyObject===undefined) {
	window.isEmptyObject=function(src) { for (var i in src) return false; return true; }
}

// cross-browser metrics
window.findMouseX=function(ev) { if (!ev) return 0; var x=0;
	if (config.browser.isIE)	return ev.clientX+findScrollX();// IE
	if (config.browser.isSafari) 	return ev.pageX+findScrollX(); 	// Webkit
	else				return ev.pageX;		// Firefox/other
}
window.findMouseY=function(ev){ if (!ev) return 0; var y=0;
	if (config.browser.isIE)	return ev.clientY+findScrollY();// IE
	if (config.browser.isSafari) 	return ev.pageY+findScrollY();	// Webkit
	else				return ev.pageY;		// Firefox/other
}
//}}}
// // macro
//{{{
merge(config.macros.moveablePanel,{
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {

		// ALTERNATIVE OUTPUT: Panel Manager macro extensions...
		if (this.manager && this.manager.handler(place,macroName,params,wikifier,paramString,tiddler))
			return; // processed by PanelManager

		// UNPACK KEYWORD PARAMS
		var showfold	 =params.contains(this.foldParam);
		var showhover	 =params.contains(this.hoverParam);
		var showclose	 =!params.contains(this.nocloseParam);
		var showdock	 =!params.contains(this.nodockParam);
		var showmanager  =params.contains(this.managerParam);
		var startundocked=params.contains(this.undockedParam);
		var jump	 =params.contains(this.jumpParam);
		var dock	 =params.contains(this.dockParam);
		var move	 =params.contains(this.moveParam);
		var all		 =params.contains(this.allParam);

		// UNPACK VALUE PARAMS
		params=paramString.parseParams('anon',null,true,false,false);
		var label =getParam(params,this.labelParam,null);
		var prompt=getParam(params,this.promptParam,null);
		var name  =getParam(params,this.nameParam,null);
		var top   =getParam(params,this.topParam,null);
		var left  =getParam(params,this.leftParam,null);
		var width =getParam(params,this.widthParam,null);
		var height=getParam(params,this.heightParam,null);

		// COMMANDS: JUMP, MOVE, DOCK
		if (jump||move||dock) {
			if (!label||!label.length) {
				var p=this.findPanel(name);
				if (jump) { if (p) this.scrollToPanel(p,true); else window.scrollTo(left,top); }
				if (move) { this.movePanel(p,left,top,true,true); }
				if (dock) { if (all) this.forAllPanels(this.dockPanel); else if (p) this.dockPanel(p); }
				return;
			}
			var tip=(jump?this.jumpParam:move?this.moveParam:dock?this.dockParam:'')+': '+name;
			var b=createTiddlyButton(place,label,prompt||tip, function(ev) {
				var cmm=config.macros.moveablePanel; var p=cmm.findPanel(this.name);
				if (this.jump) { if (p) cmm.scrollToPanel(p,true); else window.scrollTo(this.left,this.top); }
				if (this.move) { if (p) cmm.movePanel(p,this.left,this.top,true,true); }
				if (this.dock) { if (p) cmm.dockPanel(p); else if (this.all) cmm.forAllPanels(cmm.dockPanel); }
				return cmm.processed(ev)
			},'button');
			b.jump=jump; b.move=move; b.dock=dock;
			b.name=name; b.all=all;   b.left=left; b.top=top;
			return;
		}

		// PANEL SETUP
		var p=this.getPanel(place);
		this.cachePanel(p);
		addClass(p,'moveablePanel');
		p.pid=name;
		p.showmanager=showmanager;
		p.fixedheight=height||undefined;
		p.fixedwidth=width||undefined;
		this.addPanelButtons(p,showfold,showhover,showclose,showdock,showmanager);
		this.addMouseHandlers(p);
		if (startundocked) {
			this.undockPanel(p);
			if (!startingUp) { this.bringPanelToFront(p); this.scrollToPanel(p); }
		}
		if (this.manager) { this.manager.applyMap(p); this.manager.trackMap(p); }
		this.notify(p);
	},
//}}}
// // notifications
//{{{
	quiet: 0, // flag to suspend/resume notifications
	notify: function(p) { // notify others of panel changes
		if (this.quiet) return;
		if (this.manager) this.manager.notify(p); // pass notices to manager (updates viewers)
	},
//}}}
// // general panel utilities
//{{{
	getPanel: function(place) { // find containing panel or floating slider (use current element as fallback)
		var p=place;
		while (p && !(hasClass(p,'moveablePanel')||hasClass(p,'floatingPanel'))) p=p.parentNode;
		return p||place;
	},
	getAllPanels: function(zSort) { // find 'moveablePanel' elements (optionally sort by zIndex)
		var panels=[];
		var sortByZindex=function(a,b){
			var v1=parseInt(a.style.zIndex); if (isNaN(v1)) v1=0;
			var v2=parseInt(b.style.zIndex); if (isNaN(v2)) v2=0;
			return(v1==v2)?0:(v1>v2?1:-1);
		}
		// if native browser fn is defined, use it (*much* more efficient!)
		if (document.getElementsByClassName) { 
			var elems=document.getElementsByClassName('moveablePanel');
			for (var i=0; i<elems.length; i++) panels.push(elems[i]);
			return zSort?panels.sort(sortByZindex):panels;
		}
		// otherwise, find all DIVs and SPANs with the right class
		// NOTE: IE requires use of Enumerator() to iterate over elements, or it FREEZES UP COMPLETELY!!
		var isIE=config.browser.isIE;
		var elems=document.getElementsByTagName('DIV');
		for (var i=isIE?new Enumerator(elems):0; isIE?!i.atEnd():(i<elems.length); isIE?i.moveNext():i++) {
			var panel=isIE?i.item():elems[i];
			if (hasClass(panel,'moveablePanel')) panels.push(panel);
		}
		var elems=document.getElementsByTagName('SPAN');
		for (var i=isIE?new Enumerator(elems):0; isIE?!i.atEnd():(i<elems.length); isIE?i.moveNext():i++) {
			var panel=isIE?i.item():elems[i];
			if (hasClass(panel,'moveablePanel')) panels.push(panel);
		}
		return zSort?panels.sort(sortByZindex):panels;
	},
	findPanel: function(pid) { // find a named panel
		var p=this.getAllPanels();
		for (var i=0; i<p.length; i++) { if (pid && p[i].pid==pid) return p[i]; }
		return undefined;
	},
	forAllPanels: function(callback) { // invoke a function on each panel
		var panels=this.getAllPanels();
		this.quiet++;
		for (var i=0; i<panels.length; i++) callback.apply(this,[panels[i]]);
		this.quiet--;
		this.notify('all');
	},
	cachePanel: function(p) { // save original styles and handlers
		if (!p.saved) p.saved={ 
			x:p.style.left||'', y:p.style.top||'', w:p.style.width||'', h:p.style.height||'',
			z:p.style.zIndex||'', pos:p.style.position||'', title: p.title,
			mouseover:p.onmouseover, mouseout:p.onmouseout,
			mousedown:p.onmousedown, mousemove:p.onmousemove, dblclick:p.ondblclick
		};
	},
	restorePanel: function(p) { // restore original styles
		if (!p.saved) return;
		p.style.left=p.saved.x; p.style.top=p.saved.y; p.style.width=p.saved.w; p.style.height=p.saved.h;
		p.style.zIndex=p.saved.z; p.style.position=p.saved.pos; p.title=p.saved.title;
		removeClass(p,'folded'); removeClass(p,'hover'); removeClass(p,'undocked');
	},
//}}}
// // panel metrics
//{{{
	getPanelOffset: function(p) { // adjustment for child elements inside relative/floatingPanel containers
		var r=new Object(); r.x=0; r.y=0; if (!p) return r;
		var pp=p.parentNode; while (pp && !(pp.style&&pp.style.position=='relative')) pp=pp.parentNode;
		if (pp) { r.x+=findPosX(pp); r.y+=findPosY(pp); }
		var pp=p.parentNode; while (pp && !hasClass(pp,'floatingPanel')) pp=pp.parentNode;
		if (pp) { r.x+=findPosX(pp); r.y+=findPosY(pp); }
		return r;
	},
	// PROBLEM: the offsetWidth/offsetHeight do not seem to account for padding or borders
	// WORKAROUND: subtract padding and border (in px) from width and height
	// ISSUE: I still don't understand why this is needed...
	// TBD: get padding/border values from p.style and convert to px
	// NOTE: 10.6667 seems to be about 1em...
	getPanelEdgeWidth:
	  	function(p) { return 10.6667; },
	getPanelEdgeHeight:
		function(p) { return 10.6667; },
	getPanelHeight:
		function(p) { var pad=10.6667; var border=1; return p.offsetHeight-(pad*2+border*2); },
	getPanelWidth:
		function(p) { var pad=10.6667; var border=1; return p.offsetWidth -(pad*2+border*2); },
//}}}
// // panel stacking (zIndex)
//{{{
	isStackable: function(p) { // zIndex is only effective with absolute or fixed elements
		return (['absolute','fixed'].contains(p.style.position)&&!hasClass(p,'popup'));
	},
	normalizeStack: function(panels) { // set zIndex to correspond to stack order
		for (var i=0; i<panels.length; i++) {var z=panels[i].style.zIndex;
			if (z==0||z=='auto') continue; // if not stacking (e.g., 'auto', '', or null)
			if (z<10000 || z>10000) continue; // use large values for "always in front/back"
			if (z!=i+2) panels[i].style.zIndex=i+2;
			if (this.manager) this.manager.trackMap(panels[i]);
		}
		return panels;
	},
	bringPanelToFront: function(p) { if (!p) return;
		if (!this.isStackable(p)) return; // can't be stacked
		var panels=this.getAllPanels(true);
// WFFL - normalizing every time works, but takes too long
//		if (p.style.zIndex>panels.length+2) return; // stay in front
//		this.normalizeStack(panels);
//		p.style.zIndex=panels.length+2;
// WFFL - for now, just bump up the max (ignore z>10000) and normalize much less often
		if (p.style.zIndex>1000) this.normalizeStack(panels);
		var zMax=0; if (panels.length) {
			var i=panels.length-1; zMax=parseInt(panels[i].style.zIndex);
			while (zMax>10000 && i>0) zMax=parseInt(panels[--i].style.zIndex);
			if (p==panels[i]) return; // already in front
			if (isNaN(zMax)) zMax=0;
		}
		p.style.zIndex=zMax+1;
		this.notify(p);
	},
	sendPanelToBack: function(p) { if (!p) return;
		if (!this.isStackable(p)) return; // can't be stacked
		var panels=this.getAllPanels(true);
// WFFL - normalizing every time works, but takes too long
//		if (p.style.zIndex<2) return; // stay in back
//		this.normalizeStack(panels);
//		p.style.zIndex=1;
// WFFL - for now, just bump down the min (ignore z<10000) and normalize much less often
		if (p.style.zIndex<1000) this.normalizeStack(panels);
		var zMin=0; if (panels.length) {
			var i=0; zMin=parseInt(panels[i].style.zIndex);
			while (zMin<10000 && i<panels.length-1) zMin=parseInt(panels[++i].style.zIndex);
			if (p==panels[i]) return; // already in back
			if (isNaN(zMin)) zMin=0;
		}
		p.style.zIndex=zMin-1;
		this.notify(p);
	},
	returnPanelToStack: function(p) { if (!p) return;
		p.style.zIndex=p.saved?p.saved.zIndex:'';
		this.notify(p);
	},
//}}}
// // panel scrolling 
//{{{
	noScrollX: 0, // flags to disable TW built-in scrolling behavior
	noScrollY: 0, // set by hijacks, cleared by ensurePanelVisible(), below
	// scroll view to show panel along nearest edge of window or centered (optional)
	scrollToPanel: function(p,center) { if (!p) return;
		if (hasClass(p,'popup')) return; // popup=let core scrolling handle it
		if (hasClass(p,'hover')) return; // hover=always in view=don't scroll
		var scrollSize=findWindowWidth()-document.body.offsetWidth; // width of scrollbar
		var sx=findScrollX();	var ww=findWindowWidth()-scrollSize;
		var sy=findScrollY();	var wh=findWindowHeight()-scrollSize;
		var px=findPosX(p);	var pw=p.offsetWidth;
		var py=findPosY(p);	var ph=p.offsetHeight;
		var nx=sx; var ny=sy; // assume no scrolling is needed
		// if BR is not in view, scroll to show BR
		if (px+pw>sx+ww) nx=px+pw-ww;
		if (py+ph>sy+wh) ny=py+ph-wh;
		// if TL not in view or too big... scroll to show TL
		if (px<nx || px>nx+ww || px+pw>nx+ww) nx=px;
		if (py<ny || py>ny+wh || py+ph>ny+wh) ny=py;
		// optionally, center in view (if panel fits)
		if (center && pw<ww) nx-=(ww-pw)/2;
		if (center && ph<wh) ny-=(wh-ph)/2;
		if (nx!=sx||ny!=sy) { // if we need to scroll...
			window.scrollTo(nx,ny);
			if (config.options.chkMoveablePanelShowStatus && !startingUp) {
				var id=hasClass(p,'tiddler')?p.getAttribute('tiddler'):p.pid;
				this.timedMessage(this.scrollMsg.format([id||this.noPid,px,py]),this.msgDuration);
			}
			this.notify(p);
		}
	},
	// bring to front and scroll into view (with optional ASYNC)
	ensurePanelVisible: function(p,delay) { if (!p) return;
		if (delay && !startingUp) { // wait for core animation to complete...
			if (hasClass(p,'tiddler'))
				p=config.macros.moveablePanel.findPanel(p.getAttribute('tiddler'))||p;
			if (!p.id) p.id=new Date().getTime()+Math.random(); // unique ID
			var code='config.macros.moveablePanel.ensurePanelVisible(document.getElementById("%0"));';
			setTimeout(code.format([p.id]),delay);
			return;
		}
		// unblock scrolling and bring the panel into view
		if (this.noScrollX>0) this.noScrollX--; if (this.noScrollY>0) this.noScrollY--;
		if (hasClass(p,'popup')) return; // leave popups alone!
		this.bringPanelToFront(p);
		if (this.noScrollX+this.noScrollY==0 && !startingUp) // no scroll during document startup
			this.scrollToPanel(p);
	},
//}}}
// // panel status
//{{{
	formatPanelStatus: function(p) {
		var s=p.style; var msg=this.statusMsg.format([p.pid||this.noPid,
			s.left,s.top,hasClass(p,'hover')?this.hoveredMsg:'',s.width,s.height,s.zIndex]);
		return msg.replace(/(\.[0-9]+)|px/g,''); // remove decimals and 'px'
	},
	showPanelStatus: function(p,show) { // display panel info in titlebar while moving/sizing
		if (!config.options.chkMoveablePanelShowStatus) return;
		if (show) document.title=this.formatPanelStatus(p)
		else refreshPageTitle();
	},
	timedMessage: function(msg,duration) {
		document.title=msg; setTimeout('refreshPageTitle()',duration);
	},
	getPanelTooltip: function(p) {
		return hasClass(p,'undocked')?this.formatPanelStatus(p):this.dockedTip.format([p.pid||this.noPid]);
	},
//}}}
// // panel actions
//{{{
	undockPanel: function(p,front) { // undocked with default pos/size
		if (hasClass(p,'undocked')) return; // already undocked
		// get size BEFORE undocking
		p.style.width=p.fixedwidth  ||(this.getPanelWidth(p)+'px');
		p.style.height=p.fixedheight||(this.getPanelHeight(p)+'px');
		addClass(p,'undocked');	if (!this.isStackable(p)) p.style.position='absolute'; // UNDOCK it
		// set position AFTER undocking
		var offset=this.getPanelOffset(p);
		p.style.left=findPosX(p)-offset.x+'px'; p.style.top=findPosY(p)-offset.y+'px';
		if (front) this.bringPanelToFront(p);
		this.notify(p);
	},
	dockPanel: function(p) { // reset to docked pos/size
		if (!hasClass(p,'undocked')) return; // already docked
		this.restorePanel(p); // reset panel
		// FOR FLOATING SLIDERS: trigger slider adjustment handler (if any)
		if (hasClass(p,'floatingPanel') && window.adjustSliderPos)
			window.adjustSliderPos(p.parentNode,p.button,p);
		this.quiet++; if (this.manager) this.manager.trackMap(p); this.quiet--;
		this.notify(p)
	},
	closePanel: function(p) { // dock panel, then close (for tiddlers and floating sliders)
		var t=story.findContainingTiddler(p);
		var isTiddler=t&&this.findPanel(t.getAttribute('tiddler'));
		var isFloating=hasClass(p,'floatingPanel');
		if (!isTiddler) // when closing TIDDLERS, leave them undocked (keeps size/pos)
			this.dockPanel(p);
		// FOR FLOATING SLIDERS: set focus and do a fake click on slider button
		if (isFloating) { p.button.focus(); onClickNestedSlider({target:p.button}); }
		// FOR TIDDLERS: call story.closeTiddler()
		if (isTiddler) { story.closeTiddler(t.getAttribute('tiddler')); }
	},
	movePanel: function(p,x,y,show,centered) { if (!p) return;
		this.quiet++;
		this.undockPanel(p);
		// adjust for child elements inside relative/floatingPanel containers
		var offset=this.getPanelOffset(p);
		p.style.left=x-offset.x+'px'; p.style.top=y-offset.y+'px';
		if (show) { this.bringPanelToFront(p); this.scrollToPanel(p,centered); }
		this.quiet--;
		this.showPanelStatus(p,true);
		if (this.manager) this.manager.trackMap(p);
	},
	foldPanel: function(p) { // toggle panel height
		if (hasClass(p,'folded')) removeClass(p,'folded'); else addClass(p,'folded');
		if (this.manager) this.manager.trackMap(p);
		this.notify(p);
	},
	hoverPanel: function(p) { // toggle fixed position
		if (hasClass(p,'hover')) {
			removeClass(p,'hover');
			var offset=this.getPanelOffset(p);
			p.style.left=p.offsetLeft+findScrollX()-offset.x+'px';
			p.style.top=p.offsetTop+findScrollY()-offset.y+'px';
		} else {
			var offset=this.getPanelOffset(p);
			var ww=findWindowWidth(); var wh=findWindowHeight();
			p.style.left=(p.offsetLeft-findScrollX()+offset.x)%ww+'px';
			p.style.top =(p.offsetTop -findScrollY()+offset.y)%wh+'px';
			addClass(p,'hover'); 
		}
		if (this.manager) this.manager.trackMap(p);
		this.notify(p);
	},
	resetPanel: function(p) { // reset to session starting pos/size
		if (this.manager) this.manager.resetPanel(p); else this.dockPanel(p);
	},
//}}}
// // menu buttons
//{{{
	processed: function(ev) { var ev=ev||window.event; // use to end event handling for menus and mouse actions
		if (ev) { ev.cancelBubble=true; if (ev.stopPropagation) ev.stopPropagation(); } return false;
	},
	addPanelButtons: function(p,showfold,showhover,showclose,showdock,showmanager) {
		if (p.menu) return; // only once per panel
		function cmd(menu,label,tip,callback,show,arg) {
			var fn=function(ev){return this.callback.apply(config.macros.moveablePanel,[this,ev,this.arg]);}
			var b=createTiddlyButton(menu,label,tip,fn,'moveablePanelButton');
			b.style.display=show?'inline':'none'; b.callback=callback; b.arg=arg;
			return b;
		}
		var m=createTiddlyElement(p,'div',null,'moveablePanelMenu');
		p.showfold=showfold;
		p.foldbutton= cmd(m,this.foldLabel,this.foldTip,this.foldHandler,showfold);
		p.unfoldbutton= cmd(m,this.unfoldLabel,this.unfoldTip,this.foldHandler,false);
		p.showhover=showhover;
		p.hoverbutton=cmd(m,this.hoverLabel,this.hoverTip,this.hoverHandler,showhover);
		p.scrollbutton=cmd(m,this.scrollLabel,this.scrollTip,this.hoverHandler,false);
		p.showdock=showdock;
		p.dockbutton= cmd(m,this.dockLabel,this.dockTip,this.dockHandler,showdock);
		p.showclose=showclose;
		p.closebutton=cmd(m,this.closeLabel,this.closeTip,this.closeHandler,showclose);
		p.showmanager=showmanager;
		if (this.manager) p.managerbutton=cmd(m,this.manager.buttonLabel,this.manager.buttonTip,
			this.manager.popup,showmanager,p.pid);
		p.menu=m;
	},
	togglePanelButtons: function(p,show) { if (!p||!p.menu) return;
		var undocked=hasClass(p,'undocked');
		var floating=hasClass(p,'floatingPanel');
		var hover=hasClass(p,'hover');
		var folded=hasClass(p,'folded');
		var t=story.findContainingTiddler(p);
		var tiddler=t&&this.findPanel(t.getAttribute('tiddler'));
		var show=show&&(undocked||floating);
		p.menu.style.display=show?'inline':'none';
		if (p.showfold)  p.foldbutton.style.display  =!folded?'inline':'none';
		if (p.showfold)  p.unfoldbutton.style.display= folded?'inline':'none';
		if (p.showhover) p.hoverbutton.style.display =!hover?'inline':'none';
		if (p.showhover) p.scrollbutton.style.display= hover?'inline':'none';
		if (p.showdock)  p.dockbutton.style.display =undocked?'inline':'none';
		if (p.showclose) p.closebutton.style.display=floating||(tiddler&&undocked)?'inline':'none';
		if (p.managerbutton) { // see [[PanelManagerPlugin]]
			var show=p.showmanager||config.options.chkMoveablePanelShowManager;
			p.managerbutton.style.display=show?'inline':'none';
		}
	},
	foldHandler: function(place,ev){ var p=this.getPanel(place);
		this.foldPanel(p); this.togglePanelButtons(p,true); return this.processed(ev); },
	hoverHandler: function(place,ev){ var p=this.getPanel(place);
		this.hoverPanel(p); this.togglePanelButtons(p,true); return this.processed(ev); },
	dockHandler: function(place,ev){ var p=this.getPanel(place);
		this.dockPanel(p); this.togglePanelButtons(p,true); return this.processed(ev); },
	closeHandler: function(place,ev){ var p=this.getPanel(place);
		this.closePanel(p); this.togglePanelButtons(p,true); return this.processed(ev); },
//}}}
// // mouse handlers
//{{{
	addMouseHandlers: function(p) {
		if (p.handlers) return true; // only add handlers ONCE
		p.onmouseover=function(ev) { var ev=ev||window.event;
			var r=config.macros.moveablePanel.mouseover(this,ev);
			return r&&this.saved.mouseover?this.saved.mouseover.apply(this,arguments):true;
		};
		p.onmouseout=function(ev) { var ev=ev||window.event;
			var r=config.macros.moveablePanel.mouseout(this,ev);
			return r&&this.saved.mouseout?this.saved.mouseout.apply(this,arguments):true;
		};
		p.onmousemove=function(ev) { var ev=ev||window.event;
			var r=config.macros.moveablePanel.mousemove(this,ev);
			return r&&this.saved.mousemove?this.saved.mousemove.apply(this,arguments):true;
		};
		p.ondblclick=function(ev) { var ev=ev||window.event;
			var r=config.macros.moveablePanel.dblclick(this,ev);
			return r&&this.saved.dblclick?this.saved.dblclick.apply(this,arguments):r;
		};
		p.onmousedown=function(ev) { var ev=ev||window.event;
			var r=config.macros.moveablePanel.mousedown(this,ev);
			return r&&this.saved.mousedown?this.saved.mousedown.apply(this,arguments):r;
		};
		p.handlers=true;
	},
	isEdge: function(p,ev) { // near 'edge' of panel (or child element)?
		var ev=ev||window.event; var target=resolveTarget(ev);
		if (!p) return false;
		// ignore form input fields
		if (['input','select','option','textarea'].contains(target.nodeName.toLowerCase())) return false;
		var left=findPosX(p); var top=findPosY(p);
		var width=p.offsetWidth; var height=p.offsetHeight;
		var x=findMouseX(ev); var y=findMouseY(ev);
		if (hasClass(p,'hover')) { x-=findScrollX(); y-=findScrollY(); } // window-relative panel
		if (x<left||y<top||x>=left+width||y>=top+height) { // outside of panel
			if (p==target || p!=this.getPanel(target)) return false;
			return this.isEdge(target,ev); // check target child element
		}
		var edgeW=this.getPanelEdgeWidth(p); var edgeH=this.getPanelEdgeHeight(p);
		var isT=(y-top<edgeH); var isL=(x-left<edgeW);
		var isB=(top+height-y<edgeH); var isR=(left+width-x<edgeW);
		return isT||isL||isB||isR;
	},
	// temporary element during move/size keeps document from shrinking 
	addGhost: function(p) {
		var g=document.getElementById('moveablePanelGhost');
		if (!g) g=createTiddlyElement(document.body,'div','moveablePanelGhost','moveablePanelGhost');
		var border=1; // note: must match CSS for 'moveablePanelGhost' WFFL-HACK
		g.style.left=findPosX(p)+'px';
		g.style.top=findPosY(p)+'px';
		g.style.width=((p.offsetWidth-border*2)||0)+'px';
		g.style.height=((p.offsetHeight-border*2)||0)+'px';
	},
	clearGhost: function() {
		var e=document.getElementById('moveablePanelGhost');
		if (e) e.parentNode.removeChild(e);
	},
	// MOUSEOVER=SHOW MENU
	mouseover: function(place,ev) { var ev=ev||window.event;
		var p=this.getPanel(place);
		addClass(p,'selected'); // shows toolbar-classed items
		this.togglePanelButtons(p,true);
		return true;
	},
	// MOUSEOUT=HIDE MENU
	mouseout: function(place,ev) { var ev=ev||window.event;
		var p=this.getPanel(place);
		removeClass(p,'selected'); // hides toolbar-classed items
		this.togglePanelButtons(p,false);
		return true;
	},
	// MOUSEMOVE=SHOW MENU AND SET CURSOR/TIP
	mousemove: function(place,ev) { var ev=ev||window.event;
		var p=this.getPanel(place);
		p.style.cursor='auto'; p.title=p.saved?p.saved.title:'';
		if (!this.isEdge(p,ev)) return true;
		var fw=p.fixedwidth;  if (fw==null) fw=undefined;
		var fh=p.fixedheight; if (fh==null) fh=undefined;

		p.title=this.moveTip.format([p.pid?p.pid+': ':'']);
		if (fw===undefined&&fh===undefined) p.title+=' '+this.sizeTip;
		else if  (fw===undefined) p.title+=' '+this.sizeWidthTip;
		else if  (fh===undefined) p.title+=' '+this.sizeHeightTip;
		if (hasClass(p,'undocked')) {
			p.title+=', '+this.clickTip+', ';
			p.title+=hasClass(p,'folded')?this.dblclickunfoldTip:this.dblclickdockTip;
		}
		p.style.cursor='move';
		if (ev.shiftKey&&!(fw&&fh)) { // set resizing cursor (if not fixed width/height)
			var left=findPosX(p); var top=findPosY(p);
			var width=p.offsetWidth; var height=p.offsetHeight;
			var x=findMouseX(ev); var y=findMouseY(ev);
			if (hasClass(p,'hover')) { x-=findScrollX(); y-=findScrollY(); } // window-relative panel
			var edgeW=this.getPanelEdgeWidth(p); var edgeH=this.getPanelEdgeHeight(p);
			var isT=(y-top<edgeH); var isL=(x-left<edgeW);
			var isB=(top+height-y<edgeH); var isR=(left+width-x<edgeW);
			p.style.cursor=(fh===undefined?(isT?'n':(isB?'s':'')):'')
				+(fw===undefined?(isL?'w':(isR?'e':'')):'')+'-resize';
		}
		return true;
	},
	// DOUBLE-CLICK=DOCK OR UNFOLD
	dblclick: function(place,ev) { var ev=ev||window.event;
		var p=this.getPanel(place);
		if (!this.isEdge(p,ev)) return true;
		// if folded... unfold, otherwise... undock
		if (hasClass(p,'folded')) this.foldPanel(p); else this.dockPanel(p);
		this.togglePanelButtons(p,false);
		return this.processed(ev);
	},
	// MOUSEDOWN=START MOVE/SIZE, CLICK=BRING TO FRONT, SHIFT-CLICK=SEND TO BACK
	mousedown: function(place,ev) { var ev=ev||window.event;
		var p=this.getPanel(place);

		// CLICK ALWAYS BRINGS TO FRONT
		this.quiet++;
		this.bringPanelToFront(p);
		if (this.manager) this.manager.trackMap(p);
		this.quiet--;
		if (!this.isEdge(p,ev)) return true;

		// start capturing mouse events and set mouse/key handlers
		var target=p; // if 'capture' not supported, track in panel only
		if (document.body.setCapture) // IE
			{ document.body.setCapture(); var target=document.body; }
		if (window.captureEvents) // moz
			{ window.captureEvents(Event.MouseMove|Event.MouseUp,true); var target=window; }
 		if (target.onmousemove!=undefined) target.saved_mousemove=target.onmousemove;
		target.onmousemove=this.dragmove;
		if (target.onmouseup!=undefined) target.saved_mouseup=target.onmouseup;
		target.onmouseup=this.dragstop;
 		if (target.onkeydown!=undefined) target.saved_keydown=target.onkeydown;
		target.onkeydown=this.dragkey;

		// calculate and save drag data in target element
		var x=findMouseX(ev); var left=findPosX(p); var width =p.offsetWidth;
		var y=findMouseY(ev); var top =findPosY(p); var height=p.offsetHeight;
		var sizing=ev.shiftKey;
		var edgeW=this.getPanelEdgeWidth(p); var edgeH=this.getPanelEdgeHeight(p);
		var isT=(y-top<edgeH); var isL=(x-left<edgeW);
		var isB=(top+height-y<edgeH); var isR=(left+width-x<edgeW);
		var d=new Object();
		d.panel=p; d.left=left; d.top=top;
		d.width=this.getPanelWidth(p); d.height=this.getPanelHeight(p);
		d.sizing=sizing; d.edgeW=edgeW; d.edgeH=edgeH;
		d.isT=isT; d.isL=isL; d.isB=isB; d.isR=isR; d.offset=this.getPanelOffset(p);
		d.saved={ x:p.style.left, y:p.style.top, w:p.style.width, h:p.style.height,
			z:p.style.zIndex, pos:p.style.position, classname:p.className };
		target.data=d;
		this.addGhost(p); // keep document from shrinking during move/size
		return this.processed(ev);
	},
	// MOUSEMOVE (during drag)=move/size panel
	dragmove: function(ev){ var ev=ev||window.event; var cmm=config.macros.moveablePanel;
		var d=this.data; var p=d.panel;
		if (!p) { this.onmousemove=this.saved_mousemove?this.saved_mousemove:null; return; }

		cmm.quiet++; // save all notifications until the end...

		// ensure panel is undocked and scrolled into view, THEN get starting mouse and scroll positions
		if (!hasClass(p,'undocked'))
			{ cmm.undockPanel(p,true); if (this.manager) this.manager.trackMap(p); }
		if (d.x===undefined) // first move event only
			{ cmm.scrollToPanel(p); d.x=findMouseX(ev); d.y=findMouseY(ev); }

		// get current mouse pos
		var newX=findMouseX(ev); var newY=findMouseY(ev);

		// calculate new TLWH (start with current panel pos/size)
		var startX=d.x; var startY=d.y; var offsetX=d.offset.x; var offsetY=d.offset.y;
		var L=d.left; var T=d.top; var W=d.width; var H=d.height;
		var newL=L; var newT=T; var newW=p.fixedwidth||W; var newH=p.fixedheight||H;
		if (d.sizing) { // resize panel
			var minW=d.edgeW*2; var minH=d.edgeH*2; // stay bigger than edge areas
			if (hasClass(p,'folded')) this.fold(p.foldButton,ev); // un-fold first!
			if (d.isT) newH=H-newY+startY+1;
			if (d.isB) newH=H+newY-startY+1;
			if (d.isL) newW=W-newX+startX+1;
			if (d.isR) newW=W+newX-startX+1;
			if (d.isT) newT=T-offsetY+newY-startY+1; else newT=T-offsetY; 
			if (d.isL) newL=L-offsetX+newX-startX+1; else newL=L-offsetX; 
			if ((d.isL||d.isR)&&!p.fixedwidth)  newW=(newW>minW?newW:minW);
			if ((d.isT||d.isB)&&!p.fixedheight) newH=(newH>minH?newH:minH);
		} else { // move panel
			newL=L-offsetX+newX-startX+1;
			newT=T-offsetY+newY-startY+1;
		}
		if (hasClass(p,'hover')) { // hover=stay on first screen
			var ww=findWindowWidth(); var wh=findWindowHeight();
			newL+=offsetX; newT+=offsetY; // hover=no relative offset (window-relative)
			// WFFL lower right is off... a bit too far (perhaps scrollwidth?)
			if (newL+newW>ww) newL=ww-newW; if (newT+newH>wh) newT=wh-newH; // limit lower right
			if (newL<0) newL=0; if (newT<0) newT=0; // limit upper left
		} else { // normal floating panel=limit upper left (stay on page)
			if (newL+offsetX<0) newL=0-offsetX; if (newT+offsetY<0) newT=0-offsetY;
		}

		// move the panel and scroll into view as needed
		p.style.left=newL.toString()+'px';
		p.style.top=newT.toString()+'px';
		if (d.sizing) p.style.width=newW.toString()+'px';
		if (d.sizing) p.style.height=newH.toString()+'px';
		cmm.scrollToPanel(p);

		// report new position and notify panel manager... done!
		cmm.quiet--; cmm.showPanelStatus(p,true); cmm.notify(p);
		return cmm.processed(ev);
	},
	dragkey: function(ev){ var ev=ev||window.event;
		var d=this.data; var p=d.panel;
		if (ev.keyCode==27) { // ESC=CANCEL... restore panel to previous pos/size
			p.style.left =d.saved.x; p.style.top   =d.saved.y;
			p.style.width=d.saved.w; p.style.height=d.saved.h;
			p.style.zIndex=d.saved.z;
			p.style.position=d.saved.pos;
			p.className=d.saved.classname;
			return this.onmouseup(ev);
		}
		if (this.saved_keydown) return this.saved_keydown(ev);
	},
	// MOUSEUP: END MOVE/SIZE, SHIFT-CLICK=SEND TO BACK
	dragstop: function(ev){ var ev=ev||window.event; var cmm=config.macros.moveablePanel;
		var newX=findMouseX(ev); var newY=findMouseY(ev);
		if (this.releaseCapture) this.releaseCapture(); // IE
		if (this.releaseEvents) this.releaseEvents(Event.MouseMove|Event.MouseUp); // moz
		this.onmousemove=this.saved_mousemove?this.saved_mousemove:null;
		this.onmouseup=this.saved_mouseup?this.saved_mouseup:null;
		this.onkeydown=this.saved_keydown?this.saved_keydown:null;
		var d=this.data; var p=d.panel;
		if (ev.shiftKey && d.x==newX && d.y==newY && cmm.isEdge(p,ev))
			cmm.sendPanelToBack(p); // SHIFT-CLICK *EDGE*
		cmm.togglePanelButtons(p,true);
		cmm.quiet++; if (cmm.manager) cmm.manager.trackMap(p); cmm.quiet--;
		cmm.clearGhost(); // allow document to adjust extents (if needed)
		cmm.showPanelStatus(p,false); cmm.timedMessage(cmm.formatPanelStatus(p),cmm.msgDuration);
		return cmm.processed(ev);
	},
//}}}
// // CSS definitions
//{{{
	css: '/*{{{*/\n'
		+'.moveablePanelMenu\n'
			+'\t{ display:none; position:absolute; right:.5em; top:-1em; }\n'
		+'.undocked .selected.moveablePanelMenu\n'
			+'\t{ display:inline; }\n'
		+'.floatingPanel .selected .moveablePanelMenu\n'
			+'\t{ display:inline; }\n'
		+'.hover\n'
			+'\t{ position:fixed !important; }\n'
		+'.folded\n'
			+'\t{ height:1.5em !important; overflow:hidden !important; }\n'
		+'.tiddler .folded\n'
			+'\t{ height:2em !important; }\n'
		+'.folded  .moveablePanelMenu\n'
			+'\t{ top:.5em; }	/* buttons fit in folded panel */\n'
		+'.tiddler .moveablePanelMenu\n'
			+'\t{ top:.2em; }	/* buttons fit in tiddler title */\n'
		+'.undocked .toolbar\n'
			+'\t{ padding-right:7.5em; }	/* make room for buttons next to toolbar */\n'
		+'.floatingPanel .moveablePanelMenu\n'
			+'\t{ right:1em;top:1em; } /* buttons fit in floating panel */\n'
		+'.moveablePanelButton\n {'
			+'\tbackground:#ccc !important; color:#000 !important;\n'
			+'\tborder:1px solid #666; padding:0 .25em; margin:0px 1px;\n'
			+'}\n'
		+'.moveablePanelButton:hover\n'
			+'\t{ background:#fff !important; color:#000 !important; }\n'
		+'.popup\n'
			+'\t{ z-index:9999999 !important; } /* popups MUST always be on top!  */\n'
		+'.moveablePanelGhost\n'
			+'\t{ position:absolute; border:1px dotted #999; }\n'
		+'/*}}}*/'
});
//}}}
// // load time initialization
//{{{
// defaults for options
if (config.options.txtMoveablePanelMapName===undefined)
	config.options.txtMoveablePanelMapName='DefaultMap';
if (config.options.chkMoveablePanelShowStatus===undefined)
	config.options.chkMoveablePanelShowStatus=true;
if (config.options.chkMoveablePanelShowManager===undefined)
	config.options.chkMoveablePanelShowManager=true;

// set up shadow stylesheet, then load styles (might be customized)
config.shadowTiddlers.MoveablePanelStyles=config.macros.moveablePanel.css;
var css=store.getRecursiveTiddlerText('MoveablePanelStyles',config.macros.moveablePanel.css,10);
setStylesheet(css,'moveablePanelStyles');
//}}}
// // hijacks
//{{{
// adjust popup placement to account for the current horizontal scrollbar
// offset (if any), so that popups will appear in the correct location, even
// when their 'root' element is scrolled far from the page origin.
var fn=Popup.place; fn=fn.toString(); if (fn.indexOf('findScrollX')==-1) { // only once
	fn=fn.replace(/winWidth\s*-\s*scrollWidth\s*-\s*1/,
		'findScrollX() + winWidth - scrollWidth - 1');
	fn=fn.replace(/winWidth\s*-\s*popupWidth\s*-\s*scrollWidth\s*-\s*1/,
		'findScrollX() + winWidth - popupWidth - scrollWidth - 1');
	eval('Popup.place='+fn);
}
//}}}
//{{{
// window.scrollTo() is used throughout the core (and plugins) to scroll to a *vertical*
// position as computed by ensureVisible(), in order to bring a tiddler into view.
// Unfortunately, the *horizontal* scroll position is almost always hard-coded to 0
// (i.e. a return to the left edge of the page).  Normally, this is not a problem,
// since a page is rarely scrolled horizontally.  However, when there are moveable
// panels, they can appear far from the left edge, so always scrolling to the left
// edge is very disruptive.  In addition, unwanted scrolling can occur as a side
// effect when displaying or refreshing a tiddler (e.g., switching between
// view/edit templates).  These hijacks adds control flags ('noScrollX' and 'noscrollY')
// that can be used to temporarily disable scrolling within the document.
if (window.scrollTo_moveablePanel==undefined) { // only once
window.scrollTo_moveablePanel=window.scrollTo;
	window.scrollTo=function(x,y) {
		var cmm=config.macros.moveablePanel;
		if (cmm.noScrollX&&cmm.noScrollY) return;
		x=cmm.noScrollX?findScrollX():x;
		y=cmm.noScrollY?findScrollY():y;
		window.scrollTo_moveablePanel(x,y);
	}
}
// ensureVisible() is used to calculate the y-offset of a tiddler, just before scrolling
// This tweak sets up an ASYNC timer to invoke the 'bring to front/scroll into view'
// function for 'tiddler' and 'popup' classes.  This allows the function
// to be triggered *after* core scrolling occurs, so the fixups are not
// stomped on by the core's normal scroll handling
if (window.ensureVisible_moveablePanel==undefined) { // only once
	window.ensureVisible_moveablePanel=window.ensureVisible;
	window.ensureVisible=function(e) {
		var ny=ensureVisible_moveablePanel.apply(this,arguments); // get core value

		// fixup height to account for horizontal scrollbar (if present)
		var atBottom=findPosY(e)+e.offsetHeight>=findScrollY()+findWindowHeight();
		var hasHScroll=document.documentElement.scrollWidth>findWindowWidth();
		var hScrollSize=findWindowWidth()-document.body.offsetWidth;
		if (atBottom && hasHScroll) ny+=hScrollSize;

		// defer scrolling for tiddlers and popups (except during startup)
		if (!startingUp && (hasClass(e,'tiddler')||hasClass(e,'popup'))) {
			var cmm=config.macros.moveablePanel;
			cmm.noScrollX++; if (hasClass(e,'tiddler')) cmm.noScrollY++;
			var delay=config.options.chkAnimate?config.animDuration+50:50;
			cmm.ensurePanelVisible(e,delay); // ASYNC SCROLL
		}
		return ny;
	}
}

// story.refreshTiddler()
if (Story.prototype.refreshTiddler_moveablePanel==undefined) { // only once
	Story.prototype.refreshTiddler_moveablePanel=Story.prototype.refreshTiddler;
	Story.prototype.refreshTiddler=function() {
		var cmm=config.macros.moveablePanel;
		cmm.noScrollX++; cmm.noScrollY++; // DON'T SCROLL AT ALL
		var r=this.refreshTiddler_moveablePanel.apply(this,arguments);
		cmm.noScrollX--; cmm.noScrollY--;
		return r;

	}
}
// story.displayTiddler()
if (Story.prototype.displayTiddler_moveablePanel==undefined) { // only once
	Story.prototype.displayTiddler_moveablePanel=Story.prototype.displayTiddler;
	Story.prototype.displayTiddler=function(srcElement,tiddler) {
		var cmm=config.macros.moveablePanel;
//WFFL		cmm.noScrollX++; cmm.noScrollY++;
		var r=this.displayTiddler_moveablePanel.apply(this,arguments);
		var title=(tiddler instanceof Tiddler)?tiddler.title:tiddler;
		var panel=cmm.findPanel(title); // if moveable... unfold panel (but not during startup)
		if (panel&&hasClass(panel,'folded')&&!startingUp) cmm.foldPanel(panel);
		var delay=config.options.chkAnimate?config.animDuration+50:50;
		cmm.ensurePanelVisible(this.getTiddler(title),delay); // ASYNC SCROLL
		return r;

	}
}
//}}}
//{{{
// Zoomer() displays an animated bounding box when showing a tiddler.  But this box 'zooms' to the tiddler's 'anchor point', not the current panel position, which can cause a 'scroll blink'.  This hijack redirects the zoomer's target directly to the undocked panel (if any)
if (window.Zoomer_moveablePanel==undefined) { // only once
	window.Zoomer_moveablePanel=window.Zoomer;
	window.Zoomer=function(text,startElement,targetElement,unused) {
		if (hasClass(targetElement,'tiddler')) {
			var tid=targetElement.getAttribute('tiddler');
			arguments[2]=config.macros.moveablePanel.findPanel(tid)||targetElement;			
		}
		return window.Zoomer_moveablePanel.apply(this,arguments);
	}
}
//}}}
/***
|Name|MoveablePanelPluginInfo|
|Source|http://www.TiddlyTools.com/#MoveablePanelPlugin|
|Documentation|http://www.TiddlyTools.com/#MoveablePanelPluginInfo|
|Version|3.0.3|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|documentation for MoveablePanelPlugin|
Adds move/resize mouse handling plus fold/unfold, hover/scroll, and close/dock buttons to any rendered tiddler content, page element, or [[floating slider panel|NestedSlidersPlugin]].
!!!!!Usage
<<<
Please see [[MoveablePanelPackage]] for a general overview of features as well as information about other plugins and tiddlers associated with installation and use of moveable panels.
{{{
<<moveablePanel>>
<<moveablePanel undocked fold hover noclose nodock manager name:... width:... height:...>>

<<moveablePanel move label:... prompt:... name:... top:... left:...>>

<<moveablePanel jump label:... prompt:... name:... >>
<<moveablePanel jump label:... prompt:... top:... left:... >>

<<moveablePanel dock label:... prompt:... name:... >>
<<moveablePanel dock label:... prompt:... all>>
}}}
Without any parameters, the {{{<<moveablePanel>>}}} simply adds the 'moveable panel' mouse handling and button commands to a containing element that has been marked with a CSS class of 'moveablePanel' (e.g., """{{moveablePanel{...}}}""") or 'floatingPanel' (created by [[NestedSlidersPlugin]]) .  If no containing 'moveablePanel' or 'floatingPanel' element is located, the panel handlers are added directly to the element in which the macro is contained.

__Optional macro parameters are:__
*''undocked''<br>by default, a moveable panel is rendered inline ('docked'), and only floats in front of other content ('undocked') after the user has moved it from it's 'anchor point'.  The ''undocked'' keyword indicates that the panel should be be immediately 'undocked' and brought to the front of the 'stack' of undocked panels as soon as it is rendered.
*''fold''<br>adds the fold/unfold (-/+) button
*''hover''<br>adds the hover/scroll (^/=) button
*''noclose''<br>supresses the close (X) button
*''nodock''<br>supresses the dock (&radic;) button
*''manager''<br>forces the Panel Manger button to always appear in the panel, regardless of the option setting (see below)
*''name:...''<br>specifies a unique identifier for the panel, to be used by the ''menu'', ''move'', ''jump'', or ''dock'' functions described below, as well as by the (optional) [[PanelManagerPlugin]] to create //panel maps// that track and record the size and position of named panels, so that they can remain where you put them, even in between browser sessions.
*''width:...''<br>specifies a fixed-width for the panel (using CSS dimensions).  This prevents horizontal resizing.
*''height:...''<br>specifies a fixed-height for the panel (using CSS dimensions).  This prevents vertical resizing.

In addition to adding panel handlers to a containing element, the macro can also be used to invoke several panel-specific actions, either immediately, or by clicking on an embedded command link:
*''dock''<br>returns a named panel to it's original anchor point.
*''jump''<br>scrolls the window to view a named panel or go to the specified (top,left) location on the page.  To dock all panels at once, the ''all'' keyword can be used instead of specifying a ''name:...'' parameter.
*''move''<br>moves the named panel to the specified (top,left) location on the page.
Note: when using ''dock'', ''jump'', or ''move'', if the ''label:...'' parameter is omitted, the action is performed immediately upon rendering the macro.  Otherwise, a command link is created using the specified ''label:...'' and (optional) ''prompt:...'' values.

__Mouse handling:__
When the mouse is just inside the edges of a moveable panel, the cursor will change to 'crossed-arrows'.  Grab (click-hold) the panel anywhere in the edge area and then drag the mouse to reposition it.  To resize the panel, hold the ''shift'' key before grabbing the panel: the cursor will change to a 'double-arrow' resizing symbol.  Drag a side edge of the panel to stretch horizontally or vertically, or drag a corner of the panel to stretch in both dimensions at once.  Double-clicking the edge of a panel resets it to its original 'docked' size and location.  Clicking (anywhere) in a moveable panel brings it to the top of the 'zIndex' stack (if overlapping with other panels).  Shift-click (along an edge) sends the panel to the back.

__Panel buttons:__
When the mouse is anywhere over a panel (not just near the edge), a special 'panel menu' appears in the ''upper right corner'' of the panel, with the following command buttons:
* &minus;/+ (fold/unfold): ''fold'' temporarily reduces the panel height to just one line.  ''unfold'' restores the panel height.
*^/= (hover/scroll): ''hover'' causes the panel to remain in view (i.e., 'fixed position') even when scrolling the rest of the page content.  ''scroll'' allows the panel to revert to scrolling with the page content (the usual behavior)
*X (close): ''close'' hides a panel from the page display.  If you have moved/resized a panel, closing it restores its default position and size.
*&radic; (dock): When a moveable panel has actually been moved from its default position, the ''close'' command is replaced with ''dock'', which restores the tiddler to its default //non-floating// location on the page.
*&#x2261; (manager): If [[PanelManagerPlugin]] is installed, this button provides instant access to the entire Panel Manager popup menu and interactive, graphical panel map viewer.

__Adding panel handlers to all tiddlers__
You can apply {{{<<moveablePanel ...>>}}} to //all// tiddlers by customizing the [[ViewTemplate]] definition to wrap the entire tiddler layout within a span that invokes the macro.  To uniquely name each moveable tiddler panel (i.e., so its position/size will be remembered by the Panel Manager), you can use a 'computed parameter' to dynamically assign the tiddler's title as the value of the 'name:...' parameter, like this:
{{{
<div class='moveablePanel'>
	... rest of tiddler layout template (i.e., everything from the normal ViewTemplate)
	<div macro='moveablePanel name:{{tiddler?tiddler.title:""}} height:auto'></div>
</div>
}}}
//Note: reference to 'tiddler.title' in this way requires installation of TiddlyTools'// [[CoreTweaks##444]] or use of TW2.5 (not yet available)
<<<
!!!!!Configuration
<<<
<<option chkMoveablePanelShowManager>> automatically add<<moveablePanel menu label:[[Panel Manager Popup Menu]]>>in undocked panels
{{{<<option chkMoveablePanelShowManager>>}}}
<<option chkMoveablePanelShowStatus>> show position/size while moving/resizing a panel
{{{<<option chkMoveablePanelShowStatus>>}}}
<<<
!!!!!Revisions
<<<
2010.12.24 3.0.4 fixed findMouseX/findMouseY for webkit browsers
2008.12.24 3.0.3 added ESC key handling to cancel panel move/size (restores previous panel state)
2008.12.20 3.0.2 addGhost()/clearGhost(): shows panel outline during move/size (prevents document from shrinking until move/size is done)
2008.12.15 3.0.1 handling for 'hovered' elements: adjust for fixed vs. absolute (no relative offsets, no scroll offsets), translate movement to top-left screen, restrict movement within screen bounds
2008.12.10 3.0.0 total rewrite: extensive code refactoring and improved event handling for cross-browser compatibility, manage zIndex 'stacking' of panels, added shadow tiddler for customizable CSS, named panels, macro commands for embedding jump, dock, or move command links, complete I18N/L10N-readiness, {{{ensureVisible()}}} 'fixups' for horizontal scrolling, and hooks for optional [[PanelManagerPlugin]] (panel map 'memory' and interactive graphical viewers)
2008.11.17 2.6.0 added optional 'height:...' and 'width:...' macro params for fixed size dimensions (use 'height:auto' for moveable tiddlers).  Added CSS for moveablePanelMenu and moveablePanelButton styles (for easier customization)
2008.11.16 2.5.2 small fixes to mouseover/isEdge() handling.  some code cleanup as well
2008.11.15 2.5.1 changed stored panel data format to be compatible with Project Cecily map format (space-separated, strip decimals and 'px').  Also, moved slider-specific adjustPanel() logic into [[NestedSlidersPlugin]].
2008.11.12 2.5.0 more major code changes (lots of event handling fixes and code refactoring)
2008.11.09 2.4.0 major re-write to fix mouse event handling issues and isEdge() logic for nested moveable panels
2008.11.06 2.3.0 added CLICK/SHIFT-CLICK for 'move to top / return to stack' panel zIndex handling
2008.11.03 2.2.0 automatically store/recall position/size of named panels using a cookie and/or tiddler
2008.09.11 2.1.2 corrected caching of transient attribute (use =='true' to convert string to boolean)
2008.01.08 [*.*.*] plugin size reduction: documentation moved to ...Info tiddler
2007.12.30 2.1.0 added 'noedges' option for alternative 'grab handles' (top=move, bottom-right=resize)
2007.12.17 2.0.0 code reduction and feature cleanup: when the macro is not in a floating panel, it will make it's containing element moveable.  Removed 'maximize' functionality (which was badly broken), and replaced it with 'double-click=DOCK' (resets size/position without hiding panel). Use hasClass() test function to allow additional classes to be used with moveable floating panels (to apply extra custom CSS styles).
2007.06.10 1.3.7 in handler(), mouse event handlers now use apply() to correctly invoke any previous mouse handler functions.  Also, clear the existing 'snap panel back to button location' mouseover/out event handlers for floating panels (defined by NestedSlidersPlugin).  Extends fix from v1.3.5. 
2007.06.08 1.3.6 in getPanel(), remove unneeded check for 'moveable' tag.  Also, added support for 'noclose' macro param, and updated documentation accordingly.
2007.06.02 1.3.5 in handler(), remove onmouseover handler from NestedSlider button elements, to prevent automatic 'snap to original location' behavior.  This allows *moveable* floating panels to maintain their placement when they have been manually re-positioned.  This change is made for compatibility with [[NestedSlidersPlugin]] use of onmouseover (see entry for version 2.0.4)
2006.10.17 1.3.4 when moving panel, adjust position for relative containing DIV
2006.05.25 1.3.3 in closePanel(), use p.button.onclick() so that normal processing (updating slider button tooltip, access key, etc.) is performed
2006.05.11 1.3.2 doc update
2006.05.11 1.3.1 re-define all functions within moveablePanel object (eliminate global window.* function definitions (and some 'leaky closures' in IE)
2006.05.11 1.3.0 converted from inline javascript to true plugin
2006.05.09 1.2.3 in closePanel(), set focus to sliderpanel button (if any)
2006.05.02 1.2.2 in MoveOrSizePanel(), calculate adjustments for top and left when inside nested floating panels
2006.04.06 1.2.1 in getPanel(), allow redefinition or bypass of 'moveable' tag (changed from hard-coded 'tearoff')
2006.03.29 1.2.0 in getPanel(), require 'tearoff' tag to enable floating tiddlers
2006.03.13 1.1.0 added handling for floating tiddlers and conditional menu display
2006.03.06 1.0.2 set move or resize cursor during mousetracking
2006.03.05 1.0.1 use 'window' vs 'document.body' so mousetracking in FF doesn't drop the panel when moving too quickly
2006.03.04 1.0.0 Initial public release
<<<
/***
This stylesheet contains CSS definitions for extra styling of tiddlers (and other standard page content) for use with MoveablePanelPlugin
***/
/*{{{*/
/* UNDOCKED STYLES */
.tiddler
	{ margin:0 !important; padding:0 !important; overflow:visible !important;
}
.undocked .header {
	border:1px solid; -moz-border-radius:.5em; -webkit-border-radius:.5em;
}
.undocked #sidebarOptions { 
	width:auto; border:1px solid; padding:1em; margin:0; background:#fff;
	-moz-border-radius:1em; -webkit-border-radius:1em;
}
.undocked #sidebarTabs { 
	width:auto; border:1px solid; padding:1.0em; background:#fff;
	-moz-border-radius:1em; -webkit-border-radius:1em;
}
.undocked #sidebarTabs .tabContents
	{ width:17em; max-height:30em; overflow:auto; }
.undocked #sidebarTabs .tabContents .tabContents
	{ width:16em; max-height:24em; overflow:auto; }

/* TIDDLER 'TITLEBAR' */
.title {
	font-size:120%;
	line-height:150%;
	background-color:#ace;
	color:[[ColorPalette::Background]];
	border:1px solid [[ColorPalette::Foreground]]; border-bottom:0;
	-moz-border-radius:1em 1em 0 0;
	-webkit-border-bottom-left-radius:0;
	-webkit-border-bottom-right-radius:0;
	-webkit-border-top-left-radius: .7em;
	-webkit-border-top-right-radius: .7em;
	padding-left:.5em;
}
.selected .title {
	background-color:#def;
	color:[[ColorPalette::Foreground]];
}
.subtitle { display:none; }

/* TIDDLER TOOLBAR */
.tiddler .folded
	{ height:2em !important; }
.tiddler .folded .title
	{ -moz-border-radius:1em; -webkit-border-radius:1em; border:1px solid #000; }
.tiddler .moveablePanelMenu
	{ top:.4em !important }	/* shift buttons to fit in titlebar */
.undocked .toolbar
	{ padding-right:8em !important; } /* make room for buttons next to toolbar */
.toolbar
	{ float:right; visibility:hidden; margin-top:.5em; margin-right:.5em; }
.toolbar .button
	{ padding:0px .5em; }
.selected .toolbar 
	{ visibility:visible; }
.selected .toolbar .button {
	background:#fff; color:black; border:1px solid black; margin:0 1px;
	-moz-border-radius:.5em; -webkit-border-radius:.5em; }
.selected .toolbar .button:hover
	{ background:#ace; }

/* TIDDLER BODY */
.viewer {
	border:1px solid; padding:1em; background:#fff;
	-moz-border-radius:0 0 1em 1em;
	-webkit-border-bottom-left-radius:1em;
	-webkit-border-bottom-right-radius:1em;
	-webkit-border-top-left-radius:0;
	-webkit-border-top-right-radius:0;
}
.viewer .content
	{ max-height:35em; overflow:auto; } /* limit tiddler height */

/* ADJUST 'TAGGED' DISPLAY FOR UNDOCKED TIDDLERS */
.undocked .tagged
	{ position:absolute; right:2.5em; }
.selected .undocked .tagged
	{ opacity:0.1 !important; filter:'alpha(opacity:10)' !important; }
.selected .undocked .tagged:hover
	{ opacity:1 !important; filter:'alpha(opacity:100)' !important; }

/* DOTTED FOCUS AROUND CURRENT TIDDLER */
.moveablePanel
	{ margin:1px; }
.selected .moveablePanel
	{ margin:0px; border:1px dotted;
	-moz-border-radius:1.1em; -webkit-border-radius:1.1em; }

/* ELIMINATE SCROLLBARS (and TAGS) IN PanelViewer */
#tiddlerPanelViewer .viewer .content
	{ max-height:999999em; }
#tiddlerPanelViewer .panelManagerMapViewer
	{ margin-right:1em; }
#tiddlerPanelViewer .tagged
	{ display:none; }

/*}}}*/
<!--{{{-->
<!--
|Name|MoveableViewTemplate|
|Source|http://www.TiddlyTools.com/#MoveableViewTemplate|
|Version||
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|template|
|Requires|MoveablePanelPlugin, ViewTemplate, TaggedTemplateTweak|
|Description|add moveablePanel macro to tiddlers tagged with 'moveable'|
-->
<div class='moveablePanel'>
	[[ViewTemplate]]
	<div macro='moveablePanel name:{{tiddler?tiddler.title:""}} height:auto'></div>
</div>
<!--}}}-->
/%
|Name|MultiSelectSampleScript|
|Source|http://www.TiddlyTools.com/#MultiSelectSampleScript|
|Version|0.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|script|
|Description|demonstrates handling for multi-select listboxes|

This sample script demonstrates how to display and populate a multi-select listbox of tiddler titles, and then act on the selection programmatically (via onclick handler for "go" button).  This is only an example.  Adapt it for your own use.  Good Luck!

%/<html><form action="javascript:;" style="display:inline"><!--
	--><select multiple name=list size=6 style="width:100%"></select><br><!--
	--><div style="text-align:center"><!--
	--> list size:<input type=text size=1 value=6 
		onchange="this.form.list.size=this.value; this.form.list.multiple=(this.value>1);"><!--
	--> <input type=button name=refresh value='refresh' 
		onclick="var list=this.form.list; while (list.options[0]) list.options[0]=null; var tids=store.getTiddlers('title','excludeLists'); for (i=0; i<tids.length; i++) list.options[list.length]=new Option(tids[i].title,tids[i].title,false,false);"><!--
	--> <input type=button name=go value='go' 
		onclick="var list=this.form.list;
			var tids=[]; for (i=0;i<list.length;i++)
				if (list.options[i].selected)
					tids.push(list.options[i].value);
			for (t=0;t<tids.length;t++) {
				var title=tids[t];
				displayMessage(title); /* ACT ON TIDDLER */
			}
		"><!--
	--></div><!--
--></form><hide linebreaks></html><script>
	var form=place.lastChild.firstChild;
	var tids=store.getTiddlers('title','excludeLists');
	while (form.list.options[0]) form.list.options[0]=null; 
	for (i=0; i<tids.length; i++)
		form.list.options[form.list.length]=new Option(tids[i].title,tids[i].title,false,false);
</script><<tiddler HideTiddlerTags>>
These plugins help make it easier to navigate within a TiddlyWiki document.  They provide several different ways to interact with your document to search, explore, and display specific tiddlers of interest and then rearrange/fold those tiddlers, save/restore 'stories' (lists of displayed tiddlers), or quickly back-track to previously viewed tiddlers, even after closing them!
/***
|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
<<<
{{borderleft{
{{fine{__//select a document type://__}}}
<<saveAs [[label:Empty TiddlyWiki]] [[filename:new.html]] open none>>
{{block{
<script>
	var out="";
	var tags=store.getTags();
	for (i=0; i<tags.length; i++) if (tags[i][0].indexOf("Package")!=-1)
		out+=(out.length?"\n":"")
			+"&nbsp; <<saveAs [[label:"+tags[i][0]+"]] [[filename:new.html]] open [["+tags[i][0]+"]]>>";
	if (out.length) return '+++{{nowrap{[TiddlyTools "Pick-a-Package"...]}}}\n '+out+"===";
</script>}}}{{bordertop{
@@display:block;<<saveAs "label:custom..." [[filename:new.html]] open ask>> {{fine{//(match tags)//}}}@@}}}}}}
/%
!info
|Name|NextTiddler|
|Source|http://www.TiddlyTools.com/#NextTiddler|
|Version|2.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Description|create a link to close the current tiddler and open another in its place|
Usage:
<<<
{{{
<<tiddler NextTiddler with: NextTiddlerTitle linktext>>
}}}
<<<
Example
<<<
{{{<<tiddler NextTiddler with: About "About TiddlyTools">>}}}
<<tiddler NextTiddler with: About "About TiddlyTools">>
<<<
!end
!show
[[$2|$1]]<<tiddler {{
	place.lastChild.onclick=function() {
		var here=story.findContainingTiddler(this);
		story.displayTiddler(here,"$1"); // open next
		story.closeTiddler(here.getAttribute('tiddler')); // close self
	}
'';}}>>
!end
%/<<tiddler {{'NextTiddler##'+('$1'=='$'+'1'?'info':'show')}} with: [[$1]] [[$2]]>>
/%
!info
|Name|OpenAllTiddlers|
|Source|http://www.TiddlyTools.com/#OpenAllTiddlers|
|Version|2.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Description|create a link to open ALL tiddlers in the document|
Usage:
<<<
{{{
<<tiddler OpenAllTiddlers>>
<<tiddler OpenAllTiddlers with: label>>
}}}
<<<
Example
<<<
{{{<<tiddler OpenAllTiddlers with: "click me">>}}}
<<tiddler OpenAllTiddlers##show with: "click me">>
<<<
!end
!show
<html><nowiki><a href='javascript:;' onclick="
	var tids=store.getTiddlers();
	if (confirm('Show all %0 tiddlers?'.format([tids.length]))) {
		var titles=[];
		for (var t=0;t<tid.length; t++)
			titles.push(tiddlers[t].title);
		story.closeAllTiddlers();
		story.displayTiddlers(null,titles);
	}
	return false;
">open all...</a></html>
!end
%/<<tiddler {{var src='OpenAllTiddlers'; src+(tiddler&&tiddler.title==src?'##info':'##show')}}
	with: [[$1]]>>
/%
!info
|Name|OpenTaggedTiddlers|
|Source|http://www.TiddlyTools.com/#OpenTaggedTiddlers|
|Version|2.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Description|create a link to open a set of tagged tiddlers with a single click|
Usage:
<<<
{{{
<<tiddler OpenTaggedTiddlers with: label tagToMatch sortBy reverse close limit>>
}}}
*''label''<br>is the text of the link
*''tagToMatch''<br>is a single tag value to be matched.  Note: when MatchTagsPlugin is installed, you can also use a boolean tag expression, enclosed in "..."
*''sortBy'' (optional)<br>a tiddler fieldname, (default="title", use "modified" or "created" for tiddler dates)
*''reverse'' (optional)<br>display order for the tiddlers (i.e., descending vs. ascending)
*''close'' (optional)<br>closes all open tiddlers before opening the tagged tiddlers
*''limit'' (optional)<br>maximum number of tiddlers to be opened
Note: use "" as placeholders when omitting optional parameters
<<<
Example
<<<
{{{<<tiddler OpenTaggedTiddlers##show with: "click me..." sample title reverse "" 3>>}}}
<<tiddler OpenTaggedTiddlers##show with: "click me..." sample title reverse "" 3>>
<<<
!end
!show
<html><nowiki><a href='javascript:;' onclick="
	var list=[];
	var match='$2';
	var sortBy='$3'; if ((sortBy=='$'+'3')||(sortBy=='')) sortBy='title';
	var filter='[tag[%0]][sort[%1]]'.format([match,sortBy]);
	var tids=store.filterTiddlers(filter);
	if ('$4'=='reverse') tids=tids.reverse();
	if ('$5'=='close') story.closeAllTiddlers();
	var limit=('$6'!='$'+'6')?parseInt('$6'):tids.length;
	for (var t=0;t<tids.length && t<limit;t++) list.push(tids[t].title);
	if (confirm('Show %0 tiddlers tagged with \x27%1\x27?'.format([tids.length,match]))) {
		var here=story.findContainingTiddler(place);
		story.displayTiddlers(here,list);
		if (here && list.length) { // scroll to top of newly displayed tiddlers
			var cmd='window.scrollTo(0,'+(here.offsetTop+here.offsetHeight)+')';
			var delay=config.options.chkAnimate?config.animDuration+100:0;
			setTimeout(cmd,delay);
		}
	}
	return false;
">$1</a></html>
!end
%/<<tiddler {{var src='OpenTaggedTiddlers'; src+(tiddler&&tiddler.title==src?'##info':'##show')}}
	with: [[$1]] [[$2]] [[$3]] [[$4]] [[$5]] [[$6]]>>
/%
!info
|Name|OpenTiddlers|
|Source|http://www.TiddlyTools.com/#OpenTiddlers|
|Version|2.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Description|command link to open multiple tiddlers with a single click|
Usage:
<<<
in tiddler content:
{{{
<<tiddler OpenTiddlers with: label
	"tiddler tiddler [[tiddler with spaces]] tiddler..." template>>
}}}
note: ''template'' is optional and defaults to ViewTemplate
<<<
!end

!show
<html><nowiki><a href='javascript:;' onclick='
	var tidlist="$2";
	if ("$3"!="$"+"3") var template="$3";
	story.displayTiddlers(story.findContainingTiddler(place),tidlist.readBracketedList(),template);
	return false;
'>$1</a></html>
!end
%/<<tiddler {{'OpenTiddlers##'+("$1"=='$'+'1'?'info':'show')}}
	with: [[$1]] {{"$2"}} [[$3]]>>
<!--{{{-->
<!--
|Name|PageTemplate|
|Source|http://www.TiddlyTools.com/#PageTemplate|
|Version||
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|template|
|Description|custom version of shadow template for controlling page layout|
-->
<div id='siteHeader' class='header'>
	<span id='siteTitle' class='siteTitle' refresh='content' tiddler='SiteTitle'></span>
	<span id='siteSubtitle' class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
</div>
<div id='siteMenu' class='siteMenu' refresh='content' tiddler='SiteMenu' style='clear:both'></div>
<div id='breadCrumbs' class='breadCrumbs'></div>
<div id='mainMenu'>
	<div id='mainMenuStandard' refresh='content' tiddler='MainMenu'></div>
	<div id='mainMenuExtras' macro='tiddler MainMenuExtras'></div>
	<div id='mainMenuFooter' macro='tiddler MainMenuFooter'></div>
</div>
<div id='sidebar'>
	<div id='sidebarOptions' refresh='content' tiddler='SideBarOptions'></div>
	<div id='sidebarTabs' refresh='content' force='true' tiddler='SideBarTabs'></div>
</div>
<div id='displayArea'>
	<div id='messageArea' ondblclick='clearMessage();return false;'></div>
	<div id='storyMenu' class='storyMenu' refresh='content' force='false' tiddler='StoryMenu'></div>
	<div id='searchPanel' class='searchPanel smallform' style='display:none;margin:1em;clear:both;z-index:10001'
		macro='moveablePanel name:searchresults undocked manager hover width:auto height:auto'></div>
	<div id='tiddlerDisplay' style="clear:both"></div>
</div>
<div style="position:fixed;z-index:1001;bottom:.3em;right:.3em;cursor:pointer;font-size:9pt;">
	<a href="javascript:window.scrollTo(0,0)" title="scroll to top of page">&#x25b2;</a>
</div>
<span style='display:none' macro='tiddler SiteStartup'></span>
<!--}}}-->
<!--{{{-->
<!--
|Name|PageTemplateReadOnly|
|Source|http://www.TiddlyTools.com/#PageTemplateReadOnly|
|Version||
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|template|
|Description|custom version of shadow template for controlling page layout|
-->
<div id='siteHeader' class='header'>
	<span id='siteTitle' class='siteTitle' refresh='content' tiddler='SiteTitle'></span>
	<span id='siteSubtitle' class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
</div>
<div id='siteMenu' class='siteMenu' refresh='content' tiddler='SiteMenu' style='clear:both'></div>
<div id='breadCrumbs' class='breadCrumbs'></div>
<div id='mainMenu'>
	<div>
		<div id='mainMenuStandard' refresh='content' tiddler='MainMenu'></div>
		<div class='center fine' style='padding-bottom:1em;' refresh='content' tiddler='ToggleReadOnly'></div>
	</div>
	<div id='mainMenuExtras' refresh='content' tiddler='MainMenuExtras'></div>
</div>
<div id='sidebar'>
	<div id='sidebarOptions' refresh='content' tiddler='SideBarOptions'></div>
	<div id='sidebarTabs' refresh='content' force='true' tiddler='SideBarTabs'></div>
</div>
<div id='displayArea'>
	<div id='messageArea'></div>
	<div id='storyMenu' class='storyMenu' refresh='content' force='false' tiddler='StoryMenu'></div>
	<div id='searchPanel' class='searchPanel smallform' style='display:none;margin:1em;clear:both' macro='moveablePanel name:searchresults undocked width:auto height:auto'></div>
	<div id='tiddlerDisplay' style="clear:both"></div>
</div>
<span style='display:none' macro='tiddler SiteStartup'></span>
<!--}}}-->
/%
!info
|Name|PaletteMaker|
|Source|http://www.TiddlyTools.com/#PaletteMaker|
|Version|1.2.2|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|Type|transclusion|
|Description|edit/create ColorPalette using interactive grid/list|
Usage
<<<
{{{
<<tiddler PaletteMaker with: PaletteName GridName noList noGrid allowOther>>
}}}
*''~PaletteName'' (default=ColorPalette)<br>specifies a tiddler containing {{{name:value}}} slices that assign names to color values
*''~GridName'' (default=[[216-color 'web safe' grid|http://en.wikipedia.org/wiki/Web_colors#Web-safe_colors]])<br>specifies a tiddler (or section) that defines a table, where each table cell contains one of:
**a 3-digit #RGB or 6-digit #RRGGBB color value
**an [[X11 Color Name|http://en.wikipedia.org/wiki/X11_color_names]]
**another valid CSS attribute value (see ''allowOther'', below)
*''noList'' //or// ''noGrid''<br>omits the palette listbox or color grid to provide a more compact layout
*''allowOther''<br>permit non-color CSS attribute values to be entered/selected, e.g., {{{url('images/somefile.jpg')}}}
<<<
Notes:
<<<
*{{block{
You can use "-" as placeholders for the default values of ''~PaletteName'' and/or ''~GridName'':
{{{
<<tiddler PaletteMaker with: - - nogrid>>
}}}
}}}
*{{block{
The grid/list are rendered with 'float:left' styles so content that follows will be rendered next to them.  To show your content below the grid/list display, embed an //empty// 'tagClear' CSS wrapper after the PaletteMaker:
{{{
<<tiddler PaletteMaker ...>>{{tagClear{
}}} 
}}}
You can also customize the default styles contained in [[PaletteMakerStyles]]:
<<tiddler PaletteMaker##showcode with: styles>>
}}}
*The default color grid definition is:<br><<tiddler PaletteMaker##showcode with: colorgrid>>
<<<
Examples
<<<
Edit ColorPalette (allow non-color values to be entered):
{{{<<tiddler PaletteMaker with: - - allowOther>>}}}
<<tiddler PaletteMaker##show with: - - allowOther>>{{tagClear{
}}}
Create/edit NewPalette using a 16-color 'rainbow' and/or shades of gray (no list):
{{{<<tiddler PaletteMaker with: NewPalette PaletteMaker##grayscale noList>>}}}
<<tiddler PaletteMaker##show with: NewPalette PaletteMaker##grayscale noList>>
{{{<<tiddler PaletteMaker with: NewPalette PaletteMaker##rainbow noList>>}}}
<<tiddler PaletteMaker##show with: NewPalette PaletteMaker##rainbow noList>>
<<<
!showcode
<<tiddler PaletteMaker##out with: {{store.getTiddlerText('PaletteMaker##$1')}}>>
!out
{{{
$1
}}}
!end

!colorgrid
|white		||   |   |   |   |   |   |FC0|F90|F60|F30|   |   |   |   |   |   ||FFF|
|black		||9C0|   |   |   |   |C90|FC3|FC6|F96|F63|C30|   |   |   |   |C03||EEE|
|red		||CF0|CF3|330|660|990|CC0|FF0|C93|C63|300|600|900|C00|F00|F36|F03||DDD|
|orange		||9F0|CF6|9C3|663|993|CC3|FF3|960|930|633|933|C33|F33|C36|F69|F06||CCC|
|yellow		||6F0|9F6|6C3|690|996|CC6|FF6|963|630|966|C66|F66|903|C39|F6C|F09||BBB|
|green		||3F0|6F3|390|6C0|9F3|CC9|FF9|C96|C60|C99|F99|F39|C06|906|F3C|F0C||AAA|
|blue		||0C0|3C0|360|693|9C6|CF9|FFC|FC9|F93|FCC|F9C|C69|936|603|C09|303||999|
|darkmagenta	||3C3|6C6|0F0|3F3|6F6|9F9|CFC|   |   |   |C9C|969|939|909|636|606||888|
|violet		||060|363|090|393|696|9C9|   |   |   |FCF|F9F|F6F|F3F|F0F|C6C|C3C||777|
|darkred	||030|0C3|063|396|6C9|9FC|CFF|39F|9CF|CCF|C9F|96C|639|306|90C|C0C||666|
|darkorange	||0F3|3F6|093|0C6|3F9|9FF|9CC|06C|69C|99F|99C|93F|60C|609|C3F|C0F||555|
|gold		||0F6|6F9|3C6|096|6FF|6CC|699|036|369|66F|66C|669|309|93C|C6F|90F||444|
|darkgreen	||0F9|6FC|3C9|3FF|3CC|399|366|069|039|33F|33C|339|336|63C|96F|60F||333|
|darkblue	||0FC|3FC|0FF|0CC|099|066|033|39C|36C|00F|00C|009|006|003|63F|30F||222|
|indigo		||0C9|   |   |   |   |09C|3CF|6CF|69F|36F|03C|   |   |   |   |30C||111|
|darkviolet	||   |   |   |   |   |   |0CF|09F|06F|03F|   |   |   |   |   |   ||000|
!grayscale
|FFF|EEE|DDD|CCC|BBB|AAA|999|888|777|666|555|444|333|222|111|000|
!rainbow
|black|white|red|orange|yellow|green|blue|darkmagenta|violet|darkred|darkorange|gold|darkgreen|darkblue|indigo|darkviolet|
!end

!styles
/*{{{*/
.colorgrid table
	{ float:left; margin:0 !important; border:0 !important; }
.colorgrid table, .colorgrid tr, .colorgrid th, .colorgrid tbody
	{ color:black; border:0 !important; }
.colorgrid td
	{ height:16px; width:16px; text-align:center; padding:0; line-height:100%; }
.colorgrid select
	{ float:left; margin-left:16px; font-size:80%; height:255px; }
/*}}}*/
!end

!code
<<tiddler {{
config.shadowTiddlers.PaletteMakerStyles=store.getTiddlerText('PaletteMaker##styles');
setStylesheet(store.getTiddlerText('PaletteMakerStyles'),'paletteMakerStyles');
window.paletteMaker = {
	getColor: function(t){ if (!t||!t.length) return null;
		var s=document.createElement('span').style;
		try { s.color='#'+t; if (s.color.length) return '#'+t; }
		catch(e) { try{ s.color=t; } catch(e){ return null; } return t; } // IE 
		s.color=t; return s.color.length?t:null; // FF
	},
	getTextColor: function(t){ 
		t=this.getColor(t);
		if (!t||!t.length||!t.startsWith('#')) return 'black'; // BAD COLOR or X11 COLOR NAME
		var rgb=t.substr(1).split(''); var long=t.length>=6;
		function h2d(h){return '0123456789ABCDEF'.indexOf(h?h.toUpperCase():'');};
		var r=h2d(rgb[0]); var g=h2d(rgb[long?2:1]); var b=h2d(rgb[long?4:2]);
		if (r<0||g<0||b<0||r+g+b>=15) return 'black'; // BAD RGB or BRIGHT COLOR
		return 'white'; // DARK COLOR
	},
	getPalette: function(palette) {
		var pal={};
		var slices=store.calcAllSlices(palette);
		for (var s in slices) {
			var color=slices[s].toUpperCase().replace(/#/,'');
			if (!pal[color]) pal[color]=new Array();
			pal[color].push(s);
		}
		return pal;
	},
	drawGrid: function(place,grid,palette,opts) {
		var pm=window.paletteMaker; // abbrev
		removeChildren(place);
		if (!opts.contains('NOGRID')) wikify(store.getTiddlerText(grid,''),place);
		if (!opts.contains('NOLIST')) var s=pm.drawList(place,
			{ palette:palette,min:0,max:0,edit:true,callback:pm.callback,place:place,opts:opts });
		var pal=pm.getPalette(palette);
		var cells=place.getElementsByTagName('td');
		for (var i=0; i<cells.length; i++) { var td=cells[i];
			td.style.border=0;
			var txt=getPlainText(td).trim(); if (!txt.length) continue;
			var c=pm.getColor(txt); if (!c && !opts.contains('ALLOWOTHER')) continue;
			if (c) { td.style.backgroundColor=c; td.innerHTML=''; td.style.fontSize='70%'; }
			td.title=c||txt;
			td.style.cursor=c?'crosshair':'pointer';
			td.params={ palette:palette, min:0, max:15, edit:true, callback:pm.callback,
				place:place, grid:grid,	opts:opts, pick:c||txt };
			if (pal[txt.toUpperCase()]) {
				td.params.names=pal[txt.toUpperCase()];
				td.title+='='+td.params.names.join(', ');
				if (c) { td.style.color=pm.getTextColor(c); td.innerHTML='&radic;'; }
			}
			td.onclick=function(ev) { ev=ev||window.event;
				var p=Popup.create(this); if(!p)return false;
				p.className+=' sticky smallform';
				var s=window.paletteMaker.drawList(p,this.params);
				s.style.fontSize='80%'; Popup.show(); s.focus();
				ev.cancelBubble=true; if(ev.stopPropagation)ev.stopPropagation();
				return false;
			};
		}
	},
	drawList: function(here,p) {
		var pm=window.paletteMaker; // abbrev
		var s=createTiddlyElement(here,'select');
		s.params=p;
		s.options[s.length]=new Option(p.palette+':','_view');
		s.options[s.length-1].title='open '+p.palette;
		if (p.edit && p.pick!==undefined) {
			var c=pm.getColor(p.pick);
			s.options[s.length]=new Option('+Add this color...','_add');
			if (c) s.options[s.length-1].style.backgroundColor=c;
			if (c) s.options[s.length-1].style.color=pm.getTextColor(c);
			s.options[s.length-1].title=p.pick;
		}
		var colors=store.calcAllSlices(p.palette);
		for (var x in colors) {
			var c=pm.getColor(colors[x]);
			var prefix=p.names&&p.names.contains(x)?'=':'\xA0\xA0';
			s.options[s.length]=new Option(prefix+x,colors[x]);
			if (c) s.options[s.length-1].style.backgroundColor=c;
			if (c) s.options[s.length-1].style.color=pm.getTextColor(c)
			s.options[s.length-1].title=(!c?'other: "':'')+colors[x]+(!c?'"':'');
		}
		s.size=p.min&&s.length<p.min?p.min:p.max&&s.length>p.max?p.max:s.length;
		s.onclick=function(ev){ ev=ev||window.event;
			var name=this.options[this.selectedIndex].text.replace(/[\xA0=]+/,'').trim();
			if (this.params.callback) this.params.callback(this,name,this.value,this.params);
			return false;
		};
		s.onkeyup=function(ev){ ev=ev||window.event;
			if (ev.keyCode==13) { this.onclick(); Popup.remove(); }
			if (ev.keyCode==27) Popup.remove();
			return false;
		};
		return s;
	},
	callback: function(here,name,val,p){
		var pm=window.paletteMaker; // abbrev
		if (!val.length) return;
		var pick=p.pick!==undefined?p.pick:val;
		if (val=='_view') {
			story.displayTiddler(story.findContainingTiddler(this.place),p.palette);
			Popup.remove();
			return false;
		} else if (val=='_add') {
			var msg='Enter a new name for "'+pick+'"';
			name=prompt(msg,'');
			var slices=store.calcAllSlices(p.palette);
			while (name && slices[name])
				name=prompt('"'+name+'" is already in use\n'+msg,name);
		} else if (p.edit) {
			var allow=p.opts.contains('ALLOWOTHER');
			var msg='Change "'+name+'" from "'+val+'" to:';
			pick=prompt(msg,pick);
			while (pick && !pm.getColor(pick)) {
				var err='"'+pick+'" is not a recognized color\n\xa0';
				if (!allow) err+='Please try again\n\n';
				else err+='Press OK to use this value anyway\n\n';
				var pre=pick; pick=prompt(err+msg,pick);
				if (pre==pick && allow) break;
			}
		} else {
			// TBD: callback without editing
			Popup.remove();	return false;
		}
		here.selectedIndex=0;
		if (!name||!pick) return false;
		pm.set(p.palette,name.replace(/ /g,''),pick);
		pm.drawGrid(p.place,p.grid,p.palette,p.opts);
		Popup.remove();
		return false;
	},
	set: function(palette,name,newval) {
		var tid=store.getTiddler(palette);
		if (!tid) { var tid=new Tiddler(); tid.text=store.getTiddlerText(palette,''); }
		var oldval=store.getTiddlerSlice(palette,name)||'';
		var pattern="((?:^|\\n)(?:[\\'\\/]{0,2})~?(?:"
			+name.escapeRegExp()
			+")\\1\\:[\\t\\x20]*)(?:"
			+oldval.escapeRegExp()
			+")([\\t\\x20]*(?:\\n|$))";
		var t=tid.text; var match=t.match(new RegExp(pattern));
		if (match) {
			var pos=t.indexOf(match[0]);
			var newText=t.substr(0,pos)+
				match[1]+newval+match[2]+
				t.substr(pos+match[0].length);
		} else { // place new slice at top of list or start of tiddler
			var match=t.match(store.slicesRE);
			var pos=t.indexOf(match?match[0]:'');
			var newText=t.substr(0,pos)
				+name+': '+newval+(t.length?'\n':'')
				+t.substr(pos);
		}
		var who=config.options.txtUserName; var when=new Date();
		if (config.options.chkForceMinorUpdate)
			{ var who=tid.modifier; var when=tid.modified; }
		displayMessage('setting "'+palette+'::'+name+'" to "'+newval+'"');
		store.saveTiddler(palette,palette,newText,who,when,tid.tags,tid.fields);
		story.refreshTiddler(palette,null,true);
	}
};
'';}}>>
!end

!show
<<tiddler {{
	var opts=[]
	var palette=('$1'!='$'+'1' && '$1'!='-')?'$1':'ColorPalette';
	var grid   =('$2'!='$'+'2' && '$2'!='-')?'$2':'PaletteMaker##colorgrid';
	opts.push('$3'.toUpperCase());
	opts.push('$4'.toUpperCase());
	opts.push('$5'.toUpperCase());
	if (!place.lastChild||!hasClass(place.lastChild,'colorgrid')) {
		var wrapper=createTiddlyElement(place,'span',null,'colorgrid');
		window.paletteMaker.drawGrid(wrapper,grid,palette,opts);
	}
'';}}>>
!end

%/<<tiddler PaletteMaker##code>>/%
%/<<tiddler {{var src='PaletteMaker'; src+(tiddler&&tiddler.title==src?'##info':'##show');}}
	with: [[$1]] [[$2]] [[$3]] [[$4]] [[$5]]>>
/***
|Name|[[PanelManagerPlugin]]|
|Source|http://www.TiddlyTools.com/#PanelManagerPlugin|
|Documentation|http://www.TiddlyTools.com/#PanelManagerPlugin|
|Version|1.0.2|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Requires|MoveablePanelPlugin|
|Description|Add-on for [[MoveablePanelPlugin]]: Panel Manager Menu, Control Panel, and Map Viewer |
Track position/size of moveable panels using named //panel maps//.  Interactive graphical map viewer provides "bird's eye" view of entire document for quick navigation between panels and management of panel layouts.
!!!!!Documentation
<<<
see [[PanelManagerPluginInfo]] (pending)
{{{
<<moveablePanel menu label:... prompt:...>>
<<moveablePanel menu label:... prompt:... name:...>>
<<moveablePanel maps label:... prompt:...>>
<<moveablePanel load label:... prompt:... name:...>>
<<moveablePanel viewer size:... >>
<<moveablePanel table>>
<<moveablePanel commands>>
}}}
*''menu''<br>instead of adding the mouse handling to the containing panel, the macro will render just the Panel Manager menu button.  This allows you to embed the button anywhere in your document (e.g., in the main menu or sidebar) to provide a fixed location for always accessing the current panel layout.  When ''menu'' is specified, you can use ''label:...'' and ''prompt:...'' to override the default button text (&#x2261;) and tooltip to suit your purposes.  If you provide a ''name:...'' parameter along with ''menu'', then only the section of the Panel Manager menu that applies to that named panel will be included in the resulting menu (to control a single, specific panel).
*''maps''<br>embeds a popup list of all panel maps stored in the document, permitting you to quickly switch between panel maps just by selecting a map from the popup list.
*''load''<br>embeds a command link that loads the panel map specified by the ''name:...'' parameter.
*''viewer''<br>embeds a graphical, interactive panel map viewer and page navigator in your tiddler content.  You can specify the maximum width and height of the embedded viewer using the ''size:...'' parameter with CSS units of measure (e.g., px, em, cm, in, %).  If the size is not specified, the default is for the viewer to fit the element in which it rendered (i.e., using the 'auto' or '100%' CSS value).  The ''viewer'' display is updated //live// as panels are docked/undocked, moved, size, folded, etc.
*''table''<br>embeds a panel map data table viewer in your tiddler content.  This table shows the x, y, w, h, and z, values associated with each panel stored in the current map.  As with the ''viewer'', the ''table'' data is automatically updated when panels are changed.
*''commands''<br>embeds the panel map management commands (i.e., ''new'', ''load'', ''edit'', ''save'', and ''view table...'').

// more documentation pending... //
<<<
!!!!!Open issues
<<<
Known problems:
* IE: Popups appear as a vertical line when X > window width (i.e., the core assumes left side of page)... maybe a CSS clipping issue?
* IE: 'zoomed in' mapsize calculation is way off.  These equations need to be re-examined for all browsers.
Additional features (for later):
* Track hover/docked states (in addition to x,y,w,h,z,folded)
* Drag outline in map to scroll page
* Option to normalize z-range when saving maps
<<<
!!!!!Configuration
<<<
<<option chkPanelManagerUseCookies>> remember panel maps between sessions (enables cookies)
<<option chkMoveablePanelShowStatus>> show position/size while moving/resizing a panel
<<option chkMoveablePanelShowManager>> add Panel Manager button to all undocked panels
<<option chkPanelManagerAutoMap>> automatically show map viewer as soon as popup menu is opened
<<option chkPanelManagerMapFullPage>> show full page (zoom out) in map viewer (no scrollbars)
Popup map viewer display size (maximum width and height): {{fourchar{<<option txtPanelManagerPopupMapSize>>}}}
^^//(use CSS dimensions, leave blank or use 'auto' to fit to container)//^^
<<<
!!!!!Examples
<<<
popup menu:
>{{{<<moveablePanel menu label:panels>>}}}
><<moveablePanel menu label:panels>>
map viewer control panel
>{{{<<moveablePanel commands>>}}}
><<moveablePanel commands>>
map viewer display
>{{{<<moveablePanel viewer size:400px>>}}}
>{{groupbox floatleft center{<<moveablePanel viewer size:400px>>}}}{{clear block{}}}
<<<
!!!!!Revisions
<<<
2010.12.24 1.0.2 fixed findMouseX/findMouseY for webkit browsers
2008.12.15 1.0.1 handling for 'hovered' elements: adjust for fixed vs. absolute (no relative offsets, no scroll offsets), translate movements to top-left screen, restrict movements within screen bounds
2008.11.26 1.0.0 initial release - use with [[MoveablePanelPlugin]] v3.0.0 or above
|please see [[MoveablePanelPluginInfo]] for additional information|
<<<
!!!!!Code
***/
//{{{
version.extensions.PanelManagerPlugin= {major: 1, minor: 0, revision: 2, date: new Date(2010,12,24)};
//}}}
// // defaults for options
//{{{
if (config.options.txtMoveablePanelMapName===undefined)
	config.options.txtMoveablePanelMapName='DefaultMap';
if (config.options.chkMoveablePanelShowStatus===undefined)
	config.options.chkMoveablePanelShowStatus=true;
if (config.options.chkMoveablePanelShowManager===undefined)
	config.options.chkMoveablePanelShowManager=true;
if (config.options.chkPanelManagerAutoMap===undefined)
	config.options.chkPanelManagerAutoMap=true;
if (config.options.chkPanelManagerMapFullPage===undefined)
	config.options.chkPanelManagerMapFullPage=true;
if (config.options.txtPanelManagerPopupMapSize===undefined)
	config.options.txtPanelManagerPopupMapSize='auto';
if (config.options.chkPanelManagerUseCookies===undefined)
	config.options.chkPanelManagerUseCookies=true;
//}}}
// // shadow tiddlers (for displaying interfaces inside sliders, tabs, etc)
//{{{
config.shadowTiddlers.PanelViewer='<<moveablePanel viewer>>';
config.shadowTiddlers.PanelTable='<<moveablePanel table>>';
config.shadowTiddlers.PanelCommands='<<moveablePanel commands>>';
//}}}
// // translate
//{{{
// TRANSLATORS: copy this section to PanelManagerPluginLingoXX
if (config.macros.moveablePanel===undefined) config.macros.moveablePanel={};
if (config.macros.moveablePanel.manager===undefined) config.macros.moveablePanel.manager={};
merge(config.macros.moveablePanel.manager,{

	buttonLabel:	'\u2261', // equiv
	buttonTip:	'Panel Manager',

	panelCmd:	"panel: '%0'\xa0",
	jumpToPanelCmd:	'jump to panel',
	jumpToPanelTip:	"bring '%0' into view",
	frontCmd:	'bring to front',
	frontTip:	"bring '%0' to front of stack",
	backCmd:	'send to back',
	backTip:	"send '%0' to back of stack",
	stackCmd:	'return to stack',
	stackTip:	"return '%0' to it's default stack order (zIndex)",
	moveCmd:	'move panel',
	moveTip:	"move '%0' to another location on the page",
	foldCmd:	'fold panel',
	foldTip:	"reduce the height of '%0'",
	unfoldCmd:	'unfold panel',
	unfoldTip:	"restore the height of '%0'",
	hoverCmd:	'hover panel',
	hoverTip:	"keep '%0' in view when scrolling",
	scrollCmd:	'scroll panel',
	scrollTip:	"allow '%0' to move with page",
	dockCmd:	'dock panel',
	dockTip:	"attach '%0' to it's default anchor point",
	undockCmd:	'undock panel',
	undockTip:	"detach '%0' from it's default anchor point",
	closeCmd:	'close panel',
	closeTip:	"hide/close '%0'",
	openCmd:	'open panel',
	openTip:	"show/open '%0'",
	resetCmd:	'reset panel',
	resetTip:	"return '%0' to it's starting size/position for this session",

	tiddlerCmd:	"tiddler: '%0'",
	tiddlerDirtyMsg:"'%0' is currently being edited. Unsaved changes will be discarded.",

	selectPanelCmd:	'panels...',
	selectPanelTip:	'select and navigate to other panels',
	selectPanelMsg:	'select a panel:',

	selectMapCmd:	'maps...',
	selectMapTip:	'Select a stored panel layout',
	selectMapMsg:	'select a map:',

	viewMapCmd:	"map: '%0'\xa0",
	viewMapTip:	'view, load, edit and save panel layouts',
	viewMapHeader:	"__//current map:// %0 %1__\n",
	viewMapEmpty:	'| there are currently no //undocked// panels |>|>|>|>|>|',
	viewMapUnsaved:	'(unsaved)',
	newMapCmd:	'new',
	newMapTip:	"Dock all panels and start a new map",
	newMapPrompt:	'Create a new panel map:',
	newMapName:	'NewMap',
	newMapErr:	"A panel map named '%0' already exists.  Unsaved changes in '%0' will be discarded.",
	loadMapCmd:	'load',
	loadThisMapTip:	"Apply the panel layout from '%0'",
	switchMapMsg:	"Now using panel map: '%0'",
	editMapCmd:	"edit",
	editMapTip:	'Edit the stored panel layout',
	saveMapCmd:	'save',
	saveMapTip:	'Save the current panel layout',
	saveMapPrompt:	'Save the current panel map to a tiddler:',
	saveMapMsg:	"Panel layout saved to '%0'",
	unsavedMapErr:	"Unsaved changes to the current panel map, '%0', will be discarded.",

	optionsCmd:	'options...',
	optionsTip:	'set MoveablePanel options',
	useCookiesCmd:	'remember panel maps between sessions\xa0',
	useCookiesTip:	'remember panel maps between sessions (uses cookies)',
	showManagerCmd:	'add PanelManager button to all panels\xa0',
	showManagerTip:	'add PanelManager button to all panels',
	autoMapCmd:	'show map viewer when popup menu is opened\xa0',
	autoMapTip:	'show map viewer when popup menu is opened',
	showStatusCmd:	'show panel info while moving/sizing\xa0',
	showStatusTip:	'show panel info while moving/sizing',
	mapFullPageCmd:	'zoom out (fullpage)',
	mapFullPageTip:	'view the entire panel map scaled to fit\xa0',
	mapScrollPageCmd:'zoom in (scroll)',
	mapScrollPageTip:'view a portion of the panel map with scrolling',
	mapSizeCmd:	'viewer size:\xa0',
	mapSizeTip:	'set the map viewer display (use CSS measurements: px, em, in, cm, %)',

	dockAllCmd:	'dock all panels',
	dockAllTip:	'Return all panels to their default anchor points',
	resetAllCmd:	'reset all panels',
	resetAllTip:	'Reset all panels to their starting size/position for this session',

	noPid:		'unnamed panel',
	noPanels:	'\xa0no active panels\xa0',
	notAPanel:	"\xa0has not been displayed yet\xa0",
	noMaps:		'\xa0no saved maps\xa0',
	thisPanel:	'this panel',
	notMoveableMsg:	"'%0' is not a moveable panel",
	viewerMapStatsMsg:
		 "| document size:&nbsp;|''%0 x %1'' |\n"
		+"| window size:&nbsp;|''%2 x %3'' |\n"
		+"| window view:&nbsp;|''(%4-%5) x (%6-%7)'' |\n",
	viewerTableCmd:	'show table...',
	viewerTableTip:	'show/hide current map data table',
	viewerBackgroundTip:'click for display options...',
	refreshMapCmd:	'refresh viewer',
	refreshMapTip:	'redraw map viewer display image',

	viewerMapTip:	'click to scroll...',
	XYJumpCmd:	'scroll window to:',
	XYJumpTip:	'scroll to %0(%1,%2)',
	XYMoveCmd:	"move '%0' to:",
	XYMoveTip:	'move panel to %0(%1,%2)',
	jumpHereCmd:	'scroll here (%0,%1)\xa0',
	moveHereCmd:	'move here (%0,%1)\xa0',
	compassJumpCmd:	'or, scroll to:',
	compassMoveCmd:	'or, move to:',
	centerJumpCmd:	'center on panel',
	centerJumpTip:	'view panel in center of window ',
	centerMoveCmd:	'center in view',
	centerMoveTip:	'center of current window view ',
	compassTL:	'\u25E4', compassT: '\u25B2', compassTR: '\u25E5',
	compassL:	'\u25C4', compassC: '\u25CA', compassR:  '\u25BA',
	compassBL:	'\u25E3', compassB: '\u25BC', compassBR: '\u25E2',
	compassTLTip:	'top left corner of page ',
   	compassTTip:	'top edge of page ',
	compassTRTip:	'top right corner of page ',
	compassLTip:	'left edge of page ',
	compassCTip:	'center of page ',
	compassRTip:	'right edge of page ',
	compassBLTip:	'bottom left corner of page ',
	compassBTip:	'bottom edge of page ',
	compassBRTip:	'bottom right corner of page ',

	mapTags:	['panelmap'], // default tags - 1st tag used to find panelmaps - can be customized
	mapTag:		'panelmap', // fallback default - DO NOT CHANGE
	mapHeader:	'| %0!panelname|   !x |   !y |   !w |   !h |   !z | !fold | !hover |h', // CHANGE HEADINGS ONLY
	mapFormat:	'| %0| %1| %2| %3| %4| %5|   %6   |    %7   |', // DO NOT CHANGE
	checkmark:	'\u221A', // DO NOT CHANGE

	// DO NOT TRANSLATE PARAMETERS (BREAKS PORTABILITY OF CONTENT ACROSS DOCUMENTS)
	nameParam:	'name',
	menuParam:	'menu',
	mapsParam:	'maps',
	labelParam:	'label',
	promptParam:	'prompt',
	commandsParam:	'commands',
	viewerParam:	'viewer',
	tableParam:	'table',
	sizeParam:	'size',
	loadParam:	'load'
});
//}}}
// // general utilities (global)
//{{{
// if removeCookie() function is not defined by TW core, define it here (for <TW2.5)
if (window.removeCookie===undefined) {
	window.removeCookie=function(name) {
		document.cookie = name+'=; expires=Thu, 01-Jan-1970 00:00:01 UTC; path=/;'; 
	}
}
if (window.copyObject===undefined) {
	window.copyObject=function(src)	{
		for (var i in src) this[i]=typeof src[i]!='object'?src[i]:new copyObject(src[i]);
	}
}
if (window.compareObjects===undefined) {
	window.compareObjects=function(a,b) {
		if (a===b) return true;
		if (a==undefined||b==undefined) return false;
		for (var i in a) if (typeof a[i]!='object'?a[i]!==b[i]:!compareObjects(a[i],b[i])) return false;
		return true;
	}
}
if (window.isEmptyObject===undefined) {
	window.isEmptyObject=function(src) { for (var i in src) return false; return true; }
}

// cross-browser metrics
window.findMouseX=function(ev) { if (!ev) return 0; var x=0;
	if (config.browser.isIE)	return ev.clientX+findScrollX();// IE
	if (config.browser.isSafari) 	return ev.pageX+findScrollX(); 	// Webkit
	else				return ev.pageX;		// Firefox/other
}
window.findMouseY=function(ev){ if (!ev) return 0; var y=0;
	if (config.browser.isIE)	return ev.clientY+findScrollY();// IE
	if (config.browser.isSafari) 	return ev.pageY+findScrollY();	// Webkit
	else				return ev.pageY;		// Firefox/other
}
// NOTE: WEBKIT uses document.width/height, MOZ uses the 'documentElement.scrollWidth/Height'
window.findDocumentWidth=function()
	{ var dw=document.documentElement.scrollWidth; if (document.width>dw) dw=document.width; return dw; }
window.findDocumentHeight=function()
	{ var dh=document.documentElement.scrollHeight; if (document.height>dh) dh=document.height; return dh; }

// abbreviations for adding menu elements
window.addLI=function(place)
	{return createTiddlyElement(place,'li');};
window.addBR=function(place)
	{return createTiddlyElement(place,'br');};
window.addHR=function(place)
	{return createTiddlyElement(createTiddlyElement(place,'li',null,'listBreak'),'div');};
window.addSEP=function(place)
	{return createTiddlyText(place,'\xa0|\xa0');};
window.addTXT=function(place,txt)
	{return createTiddlyText(addLI(place),txt)};
window.addBTN=function(place,label,tip,fn)
	{return createTiddlyButton(place,label,tip,fn,'button')};
window.addCMD=function(place,label,tip,fn)
	{return createTiddlyButton(addLI(place),label,tip,fn,'button')};
window.addPOP=function(place,className)
	{return Popup.create(place,null,'popup '+className)};
window.addCHK=function(place,label,tip,opt,hidechk) { // option checkbox AND text toggle config.options[chk...]
	if (!hidechk) config.macros.option.genericCreate(place,'chk',opt,null,'no');
	var b=addBTN(place,label,tip,function(ev){
		var ev=ev||window.event; var cmm=config.macros.moveablePanel;
		config.options[this.opt]=!config.options[this.opt];
		config.macros.option.propagateOption(this.opt,'checked',config.options[this.opt],'input');
		saveOptionCookie(this.opt); cmm.manager.notify('option:'+this.opt);
		Popup.remove(Popup.find(this)); return cmm.processed(ev);
	}); b.opt=opt; b.innerHTML=label;
};

// open popup at current mouse position
Popup.showHere=function(place,ev) {
	var x=findMouseX(ev)-findPosX(place);
	var y=findMouseY(ev)-findPosY(place);
	Popup.show('top','left',{x:x,y:y});
}
//}}}
// // macro
//{{{
if (config.macros.moveablePanel===undefined) config.macros.moveablePanel={};
if (config.macros.moveablePanel.manager===undefined) config.macros.moveablePanel.manager={};
merge(config.macros.moveablePanel.manager,{
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {

		var showmenu	=params.contains(this.menuParam);
		var showcommands=params.contains(this.commandsParam);
		var showtable	=params.contains(this.tableParam);
		var showviewer	=params.contains(this.viewerParam);
		var showmaps	=params.contains(this.mapsParam);

		params=paramString.parseParams('anon',null,true,false,false);
		var load	=getParam(params,this.loadParam,null);
		var name	=getParam(params,this.nameParam,null);
		var label	=getParam(params,this.labelParam,null);
		var prompt	=getParam(params,this.promptParam,null);
		var size	=getParam(params,this.sizeParam,null);

		if (load) addBTN(place,label||load,prompt||this.loadThisMapTip.format([load]),function(ev){
			config.macros.moveablePanel.manager.loadMap(this.map,ev)}).map=load;
		if (showmenu) 	  this.menu(place,name,label||this.buttonLabel,prompt||this.buttonTip);
		if (showcommands) this.viewer_commands(createTiddlyElement(place,'div'));
		if (showtable)	  this.viewer_table(createTiddlyElement(place,'div'));
		if (showviewer)	  this.viewer_map(createTiddlyElement(place,'div'),false,size);
		if (showmaps)	  this.menu_loadMap(place,label||this.selectMapCmd,prompt||this.selectMapTip,'bottom','left');

		return load||showmenu||showcommands||showtable||showviewer||showmaps; // handled==TRUE
	},
//}}}
// // notifications
//{{{
	notify: function(p) { // p=panel that was changed (or a text message if refresh/reload event)
		if (config.macros.moveablePanel.quiet) return;
		// for now, just a general refresh of all currently display viewers
		this.refreshAllViewers(p);
	},
//}}}
// // panel maps
//{{{
	map: undefined,
	startingMap: undefined,
	trackMap: function(p) {
		if (!p||!p.pid||!p.pid.length) return;
		this.readMap(config.options.txtMoveablePanelMapName);
		var re=/(\.[0-9]*px)|px/g; // removes decimals and 'px' from CSS
		if (!hasClass(p,'undocked'))
			delete this.map[p.pid];
		else this.map[p.pid]={ pid:p.pid, 
			x:p.style.left.replace(re,''),  y:p.style.top.replace(re,''),
			w:p.style.width.replace(re,''),	h:p.style.height.replace(re,''),
			z:p.style.zIndex, folded:hasClass(p,'folded'), hover:hasClass(p,'hover')  };
		this.setMapCookie(config.options.txtMoveablePanelMapName);
		this.notify(p);
	},
	applyMap: function(p) {
		var cmm=config.macros.moveablePanel;
		if (!p||!p.pid||!p.pid.length) return;
		this.readMap(config.options.txtMoveablePanelMapName);
		var d=this.map[p.pid]; if (!d) return; // panel is not mapped... do nothing
		if (!cmm.isStackable(p)) p.style.position='absolute';
		addClass(p,'undocked');
		if (d.folded) addClass(p,'folded'); else removeClass(p,'folded');
		if (d.hover)  addClass(p,'hover');  else removeClass(p,'hover');
		function addPX(v) { return v&&v.length?v+(!isNaN(v)?'px':''):''; }
		p.style.left  =addPX(d.x); p.style.top   =addPX(d.y);
		p.style.width =addPX(d.w); p.style.height=addPX(d.h);
		p.style.zIndex=d.z&&d.z.length?d.z:'';
		this.notify(p);
	},
	formatMap: function(includeHeading) {
		var cmm=config.macros.moveablePanel;
		function pad(t,maxlen) {
			var spaces='                                                  '; // 50 spaces
			return t.toString().length>=maxlen?'':spaces.substr(0,maxlen-t.toString().length);
		}
		var panels=cmm.getAllPanels(true); // sorted by zIndex
		var maxlen=0; for (var i=0; i<panels.length; i++)
			if (panels[i].pid && panels[i].pid.length>maxlen) maxlen=panels[i].pid.length;
		var panelHeader=this.mapHeader.split('|')[1].trim().format(['']);
		if (maxlen<panelHeader.length) maxlen=panelHeader.length;
		var out=[]; 
		if (includeHeading) out.push(this.mapHeader.format([pad(panelHeader,maxlen)]));
		for (var i=0; i<panels.length; i++) {
			var pid=panels[i].pid; var d=this.map[pid]; if (!d) continue;
			out.push(this.mapFormat.format([pad(pid,maxlen)+pid,
				pad(d.x,5)+d.x, pad(d.y,5)+d.y,	pad(d.w,5)+d.w, pad(d.h,5)+d.h,
				pad(d.z,5)+d.z, d.folded?this.checkmark:' ', d.hover?this.checkmark:' ' ]));
		}
		return out.join('\n');
	},
	setMapCookie: function(map) {
		if (!config.options.chkPanelManagerUseCookies) return;
		var opt='txt'+map;
		config.options[opt]=this.formatMap();
		if (config.options[opt].length) saveOptionCookie(opt); else removeCookie(opt);
	},
	readMap: function(map,force) { // get map from tiddler+cookie (cookie takes precedence)
		if (this.map && !force) return; // CACHED or LOAD ON DEMAND
		delete this.map; this.map=new Object();
		var t=store.getTiddlerText(map);
		if (config.options.chkPanelManagerUseCookies) var c=config.options['txt'+map];
		var m=(t||'')+(t&&c?'\n':'')+(c||'');
		if (!m||!m.length) return false; // NO MAP
		var items=m.split('\n');
		for (var i=0; i<items.length; i++) {
			// skip non-data table rows (|h, |c, or |k syntax)
			if (items[i].substr(items[i].length-1,1)!='|') continue;
			var d=items[i].split('|');
			for (var j=0;j<d.length;j++) d[j]=d[j]?d[j].trim():'';
			if (d[1]&&d[1].length) { 
				var m=this.map[d[1]]=new Object();
				m.pid=d[1]; m.x=d[2]; m.y=d[3]; m.w=d[4]; m.h=d[5]; m.z=d[6];
				m.folded=(d[7]&&d[7].length>0); m.hover=(d[8]&&d[8].length>0);
			}
		}
		if (!force) this.startingMap=new copyObject(this.map); // DEEP COPY TO CACHE
	},
	writeMap: function(map) {
		this.readMap(map);
		var t=store.getTiddler(map);
		var who=t&&config.options.chkForceMinorUpdate?t.modifier:config.options.txtUserName;
		var when=t&&config.options.chkForceMinorUpdate?t.modified:new Date();
		var tags=t?t.tags:this.mapTags; tags.pushUnique(this.mapTags[0]||this.mapTag);
		var fields=t?t.fields:{};
		store.saveTiddler(map,map,this.formatMap(true),who,when,tags,fields);
		story.refreshTiddler(map,null,true);
	},
	newMap: function(ev) { // clear map and docked all panels
		var cmm=config.macros.moveablePanel;
		var map=config.options.txtMoveablePanelMapName;
		var newname=prompt(this.newMapPrompt,this.newMapName);
		while (newname && newname.trim().length && newname!=map && newname!=this.newMapName
			&& (config.options['txt'+newname]||store.tiddlerExists(newname)) ) {
			if (confirm(this.newMapErr.format([newname]))) break;  // CANCELLED
			newname=prompt(this.newMapPrompt,newname);
		}
		if (!newname || !newname.trim().length) return true; // CANCELLED
		if (this.isMapChanged(map)&&!confirm(this.unsavedMapErr.format([map]))) return true;
		delete this.map; this.map=new Object();
		config.options['txt'+newname]=''; removeCookie('txt'+newname); // flush new map cookie (if any)
		var panels=cmm.getAllPanels();
		cmm.quiet++; for (var i=0; i<panels.length; i++) cmm.restorePanel(panels[i]); cmm.quiet--;
		config.options.txtMoveablePanelMapName=newname;
		saveOptionCookie('txtMoveablePanelMapName');
		this.notify('new map');
		return cmm.processed(ev);
	},
	loadMap: function(map,ev) { // *adds* entries to existing map data
		var cmm=config.macros.moveablePanel;
		var currmap=config.options.txtMoveablePanelMapName;
		if (this.isMapChanged(currmap)&&!confirm(this.unsavedMapErr.format([currmap]))) return true;
		config.options['txt'+map]=''; removeCookie('txt'+map);
		this.readMap(map,true);	// FORCE RELOAD
		cmm.quiet++;
		var panels=cmm.getAllPanels();
		for (var i=0; i<panels.length; i++) {
			if (hasClass(panels[i],'undocked')) cmm.restorePanel(panels[i]);
			this.applyMap(panels[i]);
		}
		cmm.quiet--;
		config.options.txtMoveablePanelMapName=map;
		saveOptionCookie('txtMoveablePanelMapName')
		this.setMapCookie(map);
		this.notify('load map');
		return cmm.processed(ev);
	},
	saveMap: function(map,ev) {
		var cmm=config.macros.moveablePanel;
		var map=prompt(this.saveMapPrompt,map);
		while (map && map.trim().length && store.tiddlerExists(map)) {
			var msg=story.isDirty(map)?this.tiddlerDirtyMsg:config.messages.overwriteWarning;
			if (confirm(msg.format([map]))) break;  // CANCELLED
			map=prompt(this.saveMapPrompt,map);
		}
		if (!map || !map.trim().length) return true; // CANCELLED
		if (story.isDirty(map)) { story.closeTiddler(map); story.displayTiddler(null,map); }
		this.writeMap(map);
		displayMessage(this.saveMapMsg.format([map]));
		config.options.txtMoveablePanelMapName=map; saveOptionCookie('txtMoveablePanelMapName');
		return cmm.processed(ev);
	},
	isPanelMapped: function(pid) { // is panel ID in the map?
		return this.map && this.map[pid];
	},
	isPanelChanged: function(p) { // compare current and starting map values
		var now=this.map?this.map[p.pid]:undefined;
		var then=this.startingMap?this.startingMap[p.pid]:undefined;
		if (!now&&!then) return false;
		if (!now&&then || now&&!then) return true;
		return (now.x!=then.x || now.y!=then.y || now.w!=then.w || now.h!=then.h || now.z!=then.z);
	},
	resetPanel: function(p) { // restore panel from starting map (if any)
		var cmm=config.macros.moveablePanel;
		if (!this.startingMap || !this.startingMap[p.pid]) { cmm.dockPanel(p); return; }
		cmm.quiet++;
		if (hasClass(p,'folded')) cmm.foldPanel(p);  // un-fold
		if (hasClass(p,'hover')) cmm.hoverPanel(p);  // un-hover
		this.map[p.pid]=new copyObject(this.startingMap[p.pid]);
		this.setMapCookie(config.options.txtMoveablePanelMapName);
		cmm.quiet--;
		this.applyMap(p);
	},
	isMapChanged: function(map) { // compare with saved map or starting map
		var currMap=this.formatMap(true);
		var savedMap=store.getTiddlerText(map);
		if (isEmptyObject(this.map)&&(!savedMap||(map==this.newMapName))) return false;
		return savedMap?currMap!=savedMap:!compareObjects(this.map,this.startingMap);
	},
//}}}
// // menu button and popup
//{{{
	menu: function(place,name,label,prompt) {
		if (name) { // show only the submenu for the named panel
			var b=addBTN(place,label,prompt,function(ev){
				var ev=ev||window.event; var cmm=config.macros.moveablePanel;
				var popup=addPOP(this,'panelManagerPopup'); if (!popup) return false;
				var docX=findMouseX(ev)+findScrollX(); var docY=findMouseY(ev)+findScrollY();
				cmm.manager.menu_panel(popup,cmm.findPanel(this.pid),this.pid,Popup.find(this)+1,docX,docY);
				Popup.show(); return cmm.processed(ev);
			}); b.innerHTML=label; b.pid=name;
		} else { // show entire manager menu
			var b=addBTN(place,label,prompt,function(ev){
				return config.macros.moveablePanel.manager.popup(this,ev,null,true);
			}); b.innerHTML=label;
		}
	},
	popup: function(place,ev,pid,nopanel) {
		var ev=ev||window.event; var cmm=config.macros.moveablePanel; var mgr=cmm.manager;
		var popup=addPOP(place,'sticky panelManagerPopup'); if (!popup) return cmm.processed(ev);
		popup.onclick=function(ev) { var ev=ev||window.event; var cmm=config.macros.moveablePanel;
			var lvl=Popup.find(this); if (lvl<Popup.stack.length-1) // toggle child popups
				{ Popup.remove(lvl+1); return cmm.processed(ev); }
		}
		var panel=cmm.findPanel(pid)||cmm.getPanel(place);
		var showPanelMenu=hasClass(panel,'moveablePanel')&&!nopanel;
		mgr.menu_map(popup,config.options.chkPanelManagerAutoMap);
		if (showPanelMenu) { // FOR THIS PANEL
			var b=addCMD(popup,mgr.panelCmd.format([pid]),cmm.getPanelTooltip(panel),function(ev){
				var ev=ev||window.event; var cmm=config.macros.moveablePanel;
				var popup=addPOP(this,'panelManagerPopup'); if (!popup) return false;
				var docX=findMouseX(ev)+findScrollX(); var docY=findMouseY(ev)+findScrollY();
				cmm.manager.menu_panel(popup,panel,this.panel.pid,Popup.find(this)+1,docX,docY);
				Popup.show('top','right'); return cmm.processed(ev);
			}); b.panel=panel;
		}
		addHR(popup);
		mgr.menu_forAll(popup);
		addHR(popup);
		mgr.menu_selectMap(popup);
		mgr.menu_selectPanel(popup);
		mgr.menu_options(popup);
		addHR(popup);
		addTXT(popup,mgr.XYJumpCmd);
		mgr.menu_compass(popup,showPanelMenu?panel:null,findMouseX(ev),findMouseY(ev)); // scroll
		Popup.showHere(place,ev)
		return cmm.processed(ev);
	},
//}}}
// // manager menu
//{{{
	menu_panel: function(place,p,pid,remove,x,y) {
		var cmm=config.macros.moveablePanel;
		// commands FOR ONE PANEL
		// p=panel, pid=requested panel ID, remove=popup level to close afterwards
		if (!p){addTXT(place,this.panelCmd.format([pid]));addTXT(place,this.notAPanel.format([pid]));return;}
		function cmd(place,label,tip,callback,p,arg) { // buttons invoke 'callback(p,arg)'
			var b=addCMD(place,label,tip,function(ev){
				var ev=ev||window.event; var cmm=config.macros.moveablePanel;
				this.callback.apply(cmm,[this.panel,this.arg]);
				cmm.manager.trackMap(this.panel);
				cmm.manager.refreshAllViewers();
				Popup.remove(this.remove);
				return cmm.processed(ev);
			}); b.panel=p; b.callback=callback; b.arg=arg; b.remove=remove;
		}
		var pid=p.pid||this.thisPanel;
		var u=hasClass(p,'undocked');
		var f=hasClass(p,'floatingPanel');
		var folded=hasClass(p,'folded');
		var hover=hasClass(p,'hover');
		var v=p.style.display!='none'; 
		var here=story.findContainingTiddler(p);
		var t=here&&cmm.findPanel(here.getAttribute('tiddler'));
		cmd(place,this.jumpToPanelCmd,this.jumpToPanelTip.format([pid]),cmm.ensurePanelVisible, p);
		if (u) cmd(place,this.frontCmd,this.frontTip.format([pid]),cmm.bringPanelToFront, p);
		if (u) cmd(place,this.backCmd, this.backTip.format( [pid]),cmm.sendPanelToBack,   p);
		if (u) cmd(place,this.stackCmd,this.stackTip.format([pid]),cmm.returnPanelToStack,p);
		if (p.showfold && (u||f)) {
			if (!folded) cmd(place,this.foldCmd,  this.foldTip.format(  [pid]),cmm.foldPanel, p);
			if ( folded) cmd(place,this.unfoldCmd,this.unfoldTip.format([pid]),cmm.foldPanel, p);
		}
		if (p.showhover && (u||f)) {
			if (!hover) cmd(place,this.hoverCmd, this.hoverTip.format( [pid]),cmm.hoverPanel,p);
			if ( hover) cmd(place,this.scrollCmd,this.scrollTip.format([pid]),cmm.hoverPanel,p);
		}
		if (cmm.manager.isPanelChanged(p))
			cmd(place,this.resetCmd,this.resetTip.format([pid]),cmm.resetPanel,p);
		if (t)		cmd(place,this.closeCmd,this.closeTip.format([pid]),cmm.closePanel,p);
		if (f&&v)	cmd(place,this.closeCmd,this.closeTip.format([pid]),cmm.closePanel,p);
		if (f&&!v)	cmd(place,this.openCmd, this.openTip.format( [pid]),cmm.closePanel,p);
		if (u)  cmd(place,this.dockCmd,  this.dockTip.format(  [pid]),cmm.dockPanel,  p);
		if (!u) cmd(place,this.undockCmd,this.undockTip.format([pid]),cmm.undockPanel,p,true);
		if (u||f) { // move panel
			addHR(place); addTXT(place,this.XYMoveCmd.format([pid]));
			this.menu_compass(place,p,x,y,true); // move
		}
	},
	menu_compass: function(place,p,x,y,move) { // scroll page or move panel using 'compass' buttons
		function cmd(place,label,tip,isTD,p,x,y,move) {
			var b=createTiddlyButton(isTD?createTiddlyElement(place,'TD'):addLI(place),label,tip,function(ev){
				var ev=ev||window.event; var cmm=config.macros.moveablePanel;
				if (this.move && this.p) cmm.movePanel(this.p,this.x,this.y,true,true);
				else window.scrollTo(this.x,this.y);
				cmm.manager.refreshAllViewers(); Popup.remove(Popup.find(this)); return cmm.processed(ev);
			},isTD?'panelManagerPopupCompassButton':'button'); b.p=p; b.x=x; b.y=y; b.move=move;
		}
		var ww=findWindowWidth();  var dw=findDocumentWidth();  var sx=findScrollX();
		var wh=findWindowHeight(); var dh=findDocumentHeight(); var sy=findScrollY();
		var cx=Math.floor(dw/2); var cy=Math.floor(dh/2);
		var nx=sx; var ny=sy; // assume scrolling
		move=move&&p; // only if a valid panel
		var tip=move?this.XYMoveTip:this.XYJumpTip;
		if (p) { // if panel, calc window center position for center on panel / center in view
			var px=p.offsetLeft; var py=p.offsetTop; var pw=p.offsetWidth; var ph=p.offsetHeight;
			if (move) { // adjust document width/centering to account for panel width/height
				dw-=pw+2; cx-=pw/2; var nx=px;
				dh-=ph+2; cy-=ph/2; var ny=py;
				var wcx=Math.floor(sx+ww/2-pw/2);
				var wcy=Math.floor(sy+wh/2-ph/2);
			} else {
				var offset=config.macros.moveablePanel.getPanelOffset(p); // adjust for relative elements
				var wcx=Math.max(Math.floor(px+offset.x-ww/2+pw/2),0);
				var wcy=Math.max(Math.floor(py+offset.y-wh/2+ph/2),0);
			}
		}
		var indent='\xa0\xa0';
		// PANEL
		if (p) {
			var label=move?this.centerMoveCmd:this.centerJumpCmd;
			var prompt=tip.format([move?this.centerMoveTip:this.centerJumpTip,wcx,wcy]);
			cmd(place,indent+label,prompt,false,p,wcx,wcy,move);
		}
		// HERE
		var label=move?this.moveHereCmd:this.jumpHereCmd;
		cmd(place,indent+label.format([x,y]),tip.format(['',x,y]),false,p,x,y,move);
		addTXT(place,indent+(move?this.compassMoveCmd:this.compassJumpCmd));
		// COMPASS
		var tbl=createTiddlyElement(place,'table',null,'panelManagerPopupCompass');
		var tbody=createTiddlyElement(tbl,'tbody');
		var tr=createTiddlyElement(tbody,'tr');
		cmd(tr,this.compassTL,tip.format([this.compassTLTip, 0,0]),true,p, 0,0,move);
		cmd(tr,this.compassT, tip.format([this.compassTTip ,nx,0]),true,p,nx,0,move);
		cmd(tr,this.compassTR,tip.format([this.compassTRTip,dw,0]),true,p,dw,0,move);
		var tr=createTiddlyElement(tbody,'tr');
		cmd(tr,this.compassL, tip.format([this.compassLTip, 0,ny]),true,p, 0,ny,move);
		cmd(tr,this.compassC, tip.format([this.compassCTip,cx,cy]),true,p,cx,cy,move);
		cmd(tr,this.compassR, tip.format([this.compassRTip,dw,ny]),true,p,dw,ny,move);
		var tr=createTiddlyElement(tbody,'tr');
		cmd(tr,this.compassBL,tip.format([this.compassBLTip, 0,dh]),true,p, 0,dh,move);
		cmd(tr,this.compassB, tip.format([this.compassBTip ,nx,dh]),true,p,nx,dh,move);
		cmd(tr,this.compassBR,tip.format([this.compassBRTip,dw,dh]),true,p,dw,dh,move);
	},
	menu_map: function(place,autoclick) {
		var map=config.options.txtMoveablePanelMapName;
		var b=addCMD(place,this.viewMapCmd.format([map]),this.viewMapTip,function(ev){
			var ev=ev||window.event; var cmm=config.macros.moveablePanel;
			var popup=addPOP(this,'sticky panelManagerMapPopup'); if (!popup) return false;
			cmm.manager.viewer_commands(popup);
			addHR(popup);
			cmm.manager.viewer_map(popup);
			popup.onclick=function(ev) {
				var ev=ev||window.event; var cmm=config.macros.moveablePanel;
				var lvl=Popup.find(this); if (lvl<Popup.stack.length-1) // toggle child popup
					{ Popup.remove(lvl+1); return cmm.processed(ev); }
				var popup=addPOP(this,'sticky panelManagerPopup'); if(!popup)return false;
				cmm.manager.menu_mapBackground(popup);
				Popup.showHere(this,ev); return cmm.processed(ev);
			}
			popup.title=cmm.manager.viewerBackgroundTip;
			Popup.show('top','right');
			return cmm.processed(ev);
		});
		// autoclick on initial mouseover
		if (autoclick) b.onmouseover=function(ev) { this.onmouseover=null; return this.onclick.apply(this,arguments); };
	},
	menu_forAll: function(place) {
		var cmm=config.macros.moveablePanel;
		// commands FOR ALL PANELS
		function cmd(label,tip,callback) {
			var b=addCMD(place,label,tip,function(ev){
				var ev=ev||window.event; var cmm=config.macros.moveablePanel;
				if (!confirm(this.title+'?')) return false;
				var panels=cmm.forAllPanels(this.callback);
				cmm.manager.refreshAllViewers();
				Popup.remove(Popup.find(this)); return cmm.processed(ev);
			}); b.callback=callback;
		};
		cmd(this.resetAllCmd,this.resetAllTip,cmm.resetPanel);
		cmd(this.dockAllCmd,this.dockAllTip,cmm.dockPanel);
	},
	menu_selectPanel: function(place){
		// LIST OF PANELS with PANEL SUBMENUS
		addCMD(place,this.selectPanelCmd,this.selectPanelTip,function(ev){
			var ev=ev||window.event; var cmm=config.macros.moveablePanel;
			var popup=addPOP(this,'panelManagerPopup'); if (!popup) return false;
			var panels=cmm.getAllPanels();
			addTXT(popup,panels.length?cmm.manager.selectPanelMsg:cmm.manager.noPanels);
			for (var i=0; i<panels.length; i++) { var p=panels[i];
				var b=addCMD(popup,p.pid||cmm.manager.noPid,cmm.getPanelTooltip(p),function(ev){
					var ev=ev||window.event; var cmm=config.macros.moveablePanel;
					var popup=addPOP(this,'panelManagerPopup');
					if(!popup)return false;
					var docX=findMouseX(ev)+findScrollX(); var docY=findMouseY(ev)+findScrollY();
					cmm.manager.menu_panel(popup,this.p,
						this.p.pid||cmm.manager.thisPanel,Popup.find(this)+1,docX,docY);
					Popup.show('top','right'); return cmm.processed(ev);
				}); b.p=p; b.onmouseover=b.onclick; // ALWAYS autoclick on mouseover
			}
			Popup.show('top','right'); return cmm.processed(ev);
		});
	},
	menu_selectMap: function(place){
		// same as LOAD COMMAND IN VIEWER (with different label/tip and popup alignment)
		this.menu_loadMap(addLI(place),this.selectMapCmd,this.selectMapTip,'top','right');
	},
	menu_options: function(place) {
		var on='<input type="checkbox" checked>'; var off='<input type="checkbox">';
		addCMD(place,this.optionsCmd,this.optionsTip,function(ev){
			var ev=ev||window.event; var cmm=config.macros.moveablePanel; var mgr=cmm.manager;
			var popup=addPOP(this,'sticky panelManagerPopup'); if (!popup) return false;
			addCHK(popup,mgr.useCookiesCmd,mgr.useCookiesTip,'chkPanelManagerUseCookies');
			addBR(popup);
			addCHK(popup,mgr.showManagerCmd,mgr.showManagerTip,'chkMoveablePanelShowManager');
			addBR(popup);
			addCHK(popup,mgr.autoMapCmd,mgr.autoMapTip,'chkPanelManagerAutoMap');
			addBR(popup);
			addCHK(popup,mgr.showStatusCmd,mgr.showStatusTip,'chkMoveablePanelShowStatus');
			Popup.show('top','right'); return cmm.processed(ev);
		});
	},
//}}}
// // panel map viewers
//{{{
	// MAP MANAGEMENT COMMANDS
	viewer_commands: function(place,refresh) {
		if (refresh) removeChildren(place);
		else place=createTiddlyElement(place,'div',null,'panelManagerMapCommands');
		var map=config.options.txtMoveablePanelMapName;
		var unsaved=this.isMapChanged(map)?this.viewMapUnsaved:'';
		wikify(this.viewMapHeader.format([map,unsaved]),place);
				this.command_newMap(place);
		addSEP(place); 	this.menu_loadMap(place,this.loadMapCmd,this.selectMapTip);
		addSEP(place); 	this.command_editMap(place);
		addSEP(place); 	this.command_saveMap(place);
		addSEP(place); 	this.command_viewerTable(place);
	},
//}}}
//{{{
	// TABLE VIEW - ALL MAP ENTRIES
	viewer_table: function(place,refresh) {
		var cmm=config.macros.moveablePanel;
		if (refresh) removeChildren(place);
		else place=createTiddlyElement(place,"div",null,"panelManagerMapTable");
		place.onclick=function(ev){ var cmm=config.macros.moveablePanel;
			var lvl=Popup.find(this); if (lvl!=-1) Popup.remove(lvl+1);
			cmm.manager.refreshAllViewers(); return cmm.processed(ev); }
		var link='[[%0]]'; var cmd='<<moveablePanel %2 %3:[[%0]] %4:[[%0]] %5:[[%1]]>>';
		cmd=cmd.format(['%0','%1',this.menuParam,this.nameParam,this.labelParam,this.promptParam]);
		var sortByZ=function(a,b){ var v1=parseInt(a.z); var v2=parseInt(b.z); return(v1==v2)?0:(v1>v2?1:-1); }
		var map=[]; for (var pid in this.map) map.push(this.map[pid]); map=map.sort(sortByZ);
		var rows=[]; for (var i=0; i<map.length; i++) { var m=map[i];
			var isPanel=cmm.findPanel(m.pid);
			var isTiddler=store.tiddlerExists(m.pid)||store.isShadowTiddler(m.pid);
			var fmt=isPanel?cmd:(isTiddler?link:cmd);
			var lbl=fmt.format([m.pid,this.panelCmd.format([m.pid])]);
			rows.push(this.mapFormat.format([lbl,m.x,m.y,m.w,m.h,m.z,
				m.folded?this.checkmark:' ', m.hover?this.checkmark:' ']));
		}
		var table=this.mapHeader.format([''])+'\n'+rows.join('\n')+(!rows.length?this.viewMapEmpty:'');
		wikify(table,place);
	},
//}}}
//{{{
	// GRAPHICAL VIEWER - ACTIVE PANELS AND TIDDLERS
	mapXtoDocX: function(e,ev,scale,scroller) { // convert mouse click in map panel to equivalent document location
		var mouseX=findMouseX(ev);
		var mapX=findPosX(e.parentNode)-scroller.scrollLeft;
		var docX=Math.floor((mouseX-mapX)/scale)-Math.floor((mouseX-mapX)*scale);
		return docX;
	},
	mapYtoDocY: function(e,ev,scale,scroller) { // convert mouse click in map panel to equivalent document location
		var mouseY=findMouseY(ev);
		var mapY=findPosY(e.parentNode)-scroller.scrollTop;
		var docY=Math.floor((mouseY-mapY)/scale)-Math.floor((mouseY-mapY)*scale);
		return docY;
	},
	viewer_map: function(place,refresh,mapSize){
		var cmm=config.macros.moveablePanel;
		if (!refresh) {
			place=createTiddlyElement(place,'div',null,'panelManagerMapViewer');
			place.mapSize=mapSize; // save for use with refresh
		} else {
			var mapSize=place.mapSize; // refresh... use saved map size
			removeChildren(place); // NOTE: ASSUMES CONTAINER HAS NO OTHER CONTENT
		}

		// METRICS
		var dw=findDocumentWidth();  var ww=findWindowWidth();  if (dw<ww) dw=ww; var sx=findScrollX();
		var dh=findDocumentHeight(); var wh=findWindowHeight(); if (dh<wh) dh=wh; var sy=findScrollY();

		// SET MAP MAXSIZE
		var wrapper=createTiddlyElement(place,'div');
		if (Popup.find(place)!=-1) mapSize=config.options.txtPanelManagerPopupMapSize; // IF POPUP
		wrapper.style.width=mapSize||''; mapSize=wrapper.offsetWidth; // APPLY CSS THEN GET PIXELS

		// SET SCROLLING/SCALING
		var scroll=!config.options.chkPanelManagerMapFullPage;
		// default to fit entire page in viewer
		if (dw>dh) { var w=mapSize; var h=dh/dw*mapSize; var scale=w/dw; }
		else 	   { var h=mapSize; var w=dw/dh*mapSize; var scale=h/dh; }
		if (scroll) { // set smaller dimension to fixed value, scroll the other
			wrapper.style.width=mapSize+'px'; wrapper.style.height=wh/ww*mapSize+'px';  
			wrapper.style.overflow='auto'; // make it's contents scrollable
			var scrollsize=findWindowWidth()-document.body.offsetWidth+2;
			if (dw<=ww&&dh<=wh) { // smaller than window... enlarge to fit width
				w=mapSize; h=dh/dw*w; scale=w/dw;
				wrapper.style.overflow='visible'; // no scrollbars
			} else if (dw>dh) { // wide... add hScroll
				h=wh/ww*mapSize; w=dw/dh*h; scale=h/dh;
				wrapper.style.height=h+scrollsize+'px';  
			} else { // tall... add vScroll
				w=mapSize-scrollsize; h=dh/dw*w; scale=w/dw;
			}
		}

		// CREATE DOCUMENT BACKGROUND
		var doc=createTiddlyElement(wrapper,'div',null,'map');
		doc.style.width=w+'px'; doc.style.height=h+'px';
		doc.onclick=function(ev){ // BACKGROUND POPUP: SCROLL+OPTIONS
			var ev=ev||window.event; var cmm=config.macros.moveablePanel;
			var lvl=Popup.find(this); if (lvl<Popup.stack.length-1) // toggle child popup
				{ Popup.remove(lvl+1); return cmm.processed(ev); }
			var popup=addPOP(this,'sticky panelManagerPopup'); if(!popup)return false;
			var dx=cmm.manager.mapXtoDocX(this,ev,scale,this.parentNode);
			var dy=cmm.manager.mapYtoDocY(this,ev,scale,this.parentNode);
			addTXT(popup,cmm.manager.XYJumpCmd); cmm.manager.menu_compass(popup,null,dx,dy);
			addHR(popup); cmm.manager.menu_mapBackground(popup);
			Popup.showHere(this,ev); return cmm.processed(ev);
		};
		doc.scale=scale; doc.title=this.viewerMapTip; doc.style.cursor='crosshair';

		// SHOW VIEWPORT (CURRENT WINDOW POS)
		var currview=createTiddlyElement(doc,'div');
		var s=currview.style; s.border='1px dotted'; s.position='absolute';
		s.left=sx*scale+'px'; s.top=sy*scale+'px'; s.width=(ww-2)*scale+'px'; s.height=(wh-2)*scale+'px';

		// GET ALL PANELS AND FIND BASELINE Z FOR RENDERING MAP ON TOP OF POPUPS/PANELS
		var panels=cmm.getAllPanels(); var allPids=[]; var minZ=0; var viewerZ=0;
		for (var i=0; i<panels.length; i++) { var p=panels[i]; allPids.push(p.pid); 
			if (p.style.zIndex<minZ) minZ=p.style.zIndex;
		}
		if (Popup.find(place)!=-1) viewerZ=Popup.stack[Popup.find(place)].popup.style.zIndex;
		else if (cmm.getPanel(place)) viewerZ=cmm.getPanel(place).style.zIndex;
		var baseZ=viewerZ-minZ+1;

		// DRAW PANEL BOXES
		for (var i=0; i<panels.length; i++) {
			var p=panels[i];
			var d=cmm.manager.viewer_mapbox_draw(doc,p,scale,baseZ);
			d.title=cmm.getPanelTooltip(p);
		}

		// DRAW TIDDLER BOXES
		story.forEachTiddler(function(t,e){
			if (allPids.contains(t)) return; // TIDDLER IS ALSO MOVEABLE PANEL... SKIP IT
			var d=cmm.manager.viewer_mapbox_draw(doc,e,scale,baseZ);
			d.tid=t; var tiddler=store.getTiddler(t);
 			d.title=tiddler?tiddler.getSubtitle():config.macros.moveablePanel.manager.tiddlerCmd.format([t]);
		});

		// SHOW DOC/WINDOW SIZE/VIEWPORT
		var span=createTiddlyElement(place,'span',null,'panelManagerMapStats');
		var msg=this.viewerMapStatsMsg.format([dw,dh,ww,wh,sx,sx+ww,sy,sy+wh]);
		wikify(msg,span);

		// SET MAP SCROLLPOS TO MATCH PAGE SCROLLPOS
		// NOTE: must be done *after* all content has been rendered or scrollbar will jump to zero
		if (scroll) { wrapper.scrollTop=sy*scale; wrapper.scrollLeft=sx*scale; }

	},
	// draw one map box with borders, mouseover shading and drag handling for moving
	viewer_mapbox_draw: function(doc,p,scale,baseZ) {
		var x=findPosX(p); var w=p.offsetWidth; var y=findPosY(p); var h=p.offsetHeight;
		if (hasClass(p,'hover')) { x+=findScrollX(); y+=findScrollY(); } // hover=always in view
		var db=createTiddlyElement(doc,'div',null,'panelManagerViewerMapBox');
		db.panel=p; 		db.scale=scale; 	var s=db.style;
		s.border="1px solid";	s.position='absolute';	s.cursor='crosshair';	s.zIndex=baseZ+p.style.zIndex;
		s.top=y*scale+'px';	s.left=x*scale+'px'; 	s.width=w*scale+'px';	s.height=h*scale+'px';
		s.background='#eee';	s.opacity='0.6';	s.filter='alpha(opacity:60)';
		db.onmouseover=function(ev)
			{ var s=this.style; s.background='#999';s.opacity='1';s.filter='alpha(opacity:100)'; }
		db.onmouseout=function(ev)
			{ var s=this.style; s.background='#eee';s.opacity='0.5';s.filter='alpha(opacity:50)'; }
		db.onmousedown=this.viewer_mapbox_dragstart;
		db.onclick=this.viewer_mapbox_popup;
		return db;
	},
	viewer_mapbox_dragstart: function(ev) { var ev=ev||window.event; var cmm=config.macros.moveablePanel;
		// capture mouse events and set drag handlers on target (body, window, or this panel)
		var target=this; // fallback to this panel if 'capture' not supported
		if (document.body.setCapture) // IE
			{ document.body.setCapture(); var target=document.body; }
		if (window.captureEvents) // moz
			{ window.captureEvents(Event.MouseMove|Event.MouseUp,true); var target=window; }
		// save drag data in target element
		if (!target.dragData) target.dragData=new Object();
		var d=target.dragData;
		d.box=this; d.scale=this.scale;	d.map=this.parentNode; d.scroller=this.parentNode.parentNode;
		d.startX=findMouseX(ev); d.startScrollX=d.scroller.scrollLeft; d.grabX=findMouseX(ev)-findPosX(this);
		d.startY=findMouseY(ev); d.startScrollY=d.scroller.scrollTop;  d.grabY=findMouseY(ev)-findPosY(this);
		d.offset=cmm.getPanelOffset(d.box.panel);
		d.dragging=true; this.style.cursor='move';
		d.savedonmousemove=target.onmousemove;
		target.onmousemove=cmm.manager.viewer_mapbox_dragmove;
		d.savedonmouseup=target.onmouseup;
		target.onmouseup=cmm.manager.viewer_mapbox_dragstop;
		cmm.addGhost(d.box.panel); // keep document from shrinking during move/size
		cmm.noScrollX++; cmm.noScrollY++; // prevent document from scrolling during move/size
		return cmm.processed(ev);
	},
	viewer_mapbox_dragmove: function(ev) { var ev=ev||window.event; var cmm=config.macros.moveablePanel;
		var d=this.dragData; if (!d || !d.dragging) return; // NOT DRAGGING
		if (!hasClass(d.box.panel,'moveablePanel')) { // NOT MOVEABLE
			clearMessage();
			displayMessage(cmm.manager.notMoveableMsg.format([d.box.panel.pid||d.box.tid]));
			return this.onmouseup(ev);
		}
		cmm.quiet++; cmm.undockPanel(d.box.panel,true); cmm.quiet--; // GET READY TO MOVE
		var mouseX=!config.browser.isIE?ev.pageX:ev.clientX;
		var mouseY=!config.browser.isIE?ev.pageY:ev.clientY;
		var mapX=findPosX(d.map)+d.startScrollX; var mapW=d.map.offsetWidth;
		var mapY=findPosY(d.map)+d.startScrollY; var mapH=d.map.offsetHeight;
		var scrollX=d.scroller.scrollLeft;	 var scrollW=d.scroller.offsetWidth;
		var scrollY=d.scroller.scrollTop;	 var scrollH=d.scroller.offsetHeight;
		var boxW=d.box.offsetWidth;		 var boxH=d.box.offsetHeight;
		var boxX=findMouseX(ev)-mapX-d.grabX+scrollX;
		var boxY=findMouseY(ev)-mapY-d.grabY+scrollY;
		if (boxX<0) boxX=0; if (boxY<0) boxY=0; // limit upper left=stay on page
		if (hasClass(d.box.panel,'hover')) { // hover=limit bottom right (stay in screen)
			if (boxX+boxW>scrollW) boxX=scrollW-boxW; if (boxY+boxH>scrollH) boxY=scrollH-boxH;
			if (boxX<scrollX) boxX=scrollX; if (boxY<scrollY) boxY=scrollY;
		}
		var docX=Math.floor(boxX/d.scale)-d.offset.x;
		var docY=Math.floor(boxY/d.scale)-d.offset.y;
		if (hasClass(d.box.panel,'hover')) { // window-relative placement
			var ww=findWindowWidth();  var sx=findScrollX();
			var wh=findWindowHeight(); var sy=findScrollY();
			docX-=sx-d.offset.x; docY-=sy-d.offset.y;
			if (docX+d.box.panel.offsetWidth >ww) docX=ww-d.box.panel.offsetWidth;
			if (docY+d.box.panel.offsetHeight>wh) docY=wh-d.box.panel.offsetHeight;
			if (docX<0) docX=0; if (docY<0) docY=0;
		}
		// update box AND panel positions
		d.box.style.left=boxX+'px';	d.box.panel.style.left=docX+'px';
		d.box.style.top =boxY+'px';	d.box.panel.style.top =docY+'px';
		// resize map/scroll viewer as needed
		if (boxX<scrollX) d.scroller.scrollLeft=boxX;
		if (boxX+boxW>scrollX+scrollW || boxX+boxW>d.map.offsetWidth) {
			d.map.style.width=Math.max(boxX+boxW,mapW)+'px';
			d.scroller.scrollLeft=boxX+boxW-scrollW;
		}
		if (boxY<scrollY) d.scroller.scrollTop=boxY;
		if (boxY+boxH>scrollY+scrollH || boxY+boxH>d.map.offsetHeight) {
			d.map.style.height=Math.max(boxY+boxH,mapH)+'px';
			d.scroller.scrollTop=boxY+boxH-scrollH;
		}
		cmm.showPanelStatus(d.box.panel,true);
		return cmm.processed(ev);
	},
	viewer_mapbox_dragstop: function(ev) { var ev=ev||window.event; var cmm=config.macros.moveablePanel;
		var d=this.dragData; if (!d || !d.dragging) return; // NOT DRAGGING
		if (this.releaseCapture) this.releaseCapture(); // IE
		if (this.releaseEvents) this.releaseEvents(Event.MouseMove|Event.MouseUp); // moz
		this.onmousemove=d.savedonmousemove; this.onmouseup=d.savedonmouseup;
		cmm.noScrollX--; cmm.noScrollY--; // allow document to scroll
		cmm.clearGhost(); // allow document to adjust extents (if needed)
		var moved=findMouseX(ev)!=d.startX || findMouseY(ev)!=d.startY;
		if (moved) { cmm.manager.trackMap(d.box.panel); cmm.manager.refreshAllViewers(); }
		d.dragging=false; d.box.style.cursor='pointer';
		cmm.showPanelStatus(d.box.panel,false);
		cmm.timedMessage(cmm.formatPanelStatus(d.box.panel),cmm.msgDuration);
		// HACK: ignore next click to prevent webkit from closing popup after dragging
		d.box.ignoreClick=moved&&config.browser.isSafari;
		return cmm.processed(ev);
	},
	viewer_mapbox_popup: function(ev) {
		var ev=ev||window.event; var cmm=config.macros.moveablePanel; var mgr=cmm.manager;
		if (this.ignoreClick) { this.ignoreClick=false; return cmm.processed(ev); } // HACK
		var lvl=Popup.find(this); if (lvl<Popup.stack.length-1) // toggle child popup
			{ Popup.remove(lvl+1); return cmm.processed(ev); }
		var popup=addPOP(this,'sticky panelManagerPopup'); if (!popup) return false;
		var dx=cmm.manager.mapXtoDocX(this,ev,this.scale,this.parentNode.parentNode);
		var dy=cmm.manager.mapYtoDocY(this,ev,this.scale,this.parentNode.parentNode);
		if (this.tid)	cmm.manager.menu_mapTiddler(popup,this.tid,this.panel,dx,dy);
		else		cmm.manager.menu_mapPanel(popup,this.panel,dx,dy);
		Popup.showHere(this,ev); return cmm.processed(ev);
	},

//}}}
//{{{
	refreshAllViewers: function(){
		var elems=document.getElementsByTagName("DIV");
		for (var i=0; i<elems.length; i++) {
			if (hasClass(elems[i],'panelManagerMapViewer'))   this.viewer_map(elems[i],true);
			if (hasClass(elems[i],'panelManagerMapTable'))	  this.viewer_table(elems[i],true);
			if (hasClass(elems[i],'panelManagerMapCommands')) this.viewer_commands(elems[i],true);
		}
	},
//}}}
// // map viewer commands
//{{{
	menu_mapBackground: function(place) {
		var centered=createTiddlyElement(place,'div'); centered.style.textAlign='center';
		if (Popup.find(place)>0) { // POPUP VIEWER PERMITS RESIZING
			addBTN(centered,'\xa0'+this.mapSizeCmd,this.refreshMapTip,function(ev){
				var ev=ev||window.event; var cmm=config.macros.moveablePanel;
				cmm.manager.refreshAllViewers();
				Popup.remove(Popup.find(this));	return cmm.processed(ev);
			});
			wikify('{{panelManagerMapPopupEdit{<<option txtPanelManagerPopupMapSize>>}}}\xa0',centered);
		}
		var opt='chkPanelManagerMapFullPage'; // toggle label...
		var label=config.options[opt]?this.mapScrollPageCmd:this.mapFullPageCmd;
		var tip=config.options[opt]?this.mapScrollPageTip:this.mapFullPageTip;
		addCHK(addLI(centered),label,tip,opt,true);
		addHR(centered); addCMD(centered,this.refreshMapCmd,this.refreshMapTip,function(ev){
			var ev=ev||window.event; var cmm=config.macros.moveablePanel;
			cmm.manager.refreshAllViewers();
			Popup.remove(Popup.find(this));	return cmm.processed(ev);
		});
	},
	menu_mapPanel: function(place,panel,docX,docY) {
		var cmm=config.macros.moveablePanel;
		var b=addCMD(place,this.panelCmd.format([panel.pid]),cmm.getPanelTooltip(panel),function(ev){
			var ev=ev||window.event; var cmm=config.macros.moveablePanel;
			var popup=addPOP(this,'panelManagerPopup'); if (!popup) return false;
			cmm.manager.menu_panel(popup,panel,this.panel.pid||this.thisPanel,Popup.find(this)+1,docX,docY);
			Popup.show('top','right'); return cmm.processed(ev);
		}); b.panel=panel;
		// autoclick on initial mouseover
		b.onmouseover=function(ev) { this.onmouseover=null; return this.onclick.apply(this,arguments); };
		addHR(place); addTXT(place,this.XYJumpCmd); this.menu_compass(place,panel,docX,docY);
		addHR(place); this.menu_mapBackground(place);
	},
	menu_mapTiddler: function(place,tid,tiddlerElem,docX,docY) {
		var cmm=config.macros.moveablePanel;
		var b=addCMD(place,this.tiddlerCmd.format([tid]),'',function(ev){
			var ev=ev||window.event; var cmm=config.macros.moveablePanel; var mgr=cmm.manager;
			var popup=addPOP(this,'panelManagerPopup'); if (!popup) return false;
			var b=addCMD(popup,mgr.jumpToPanelCmd,mgr.jumpToPanelTip.format([tid]),function(ev){
				var ev=ev||window.event; var cmm=config.macros.moveablePanel;
				cmm.scrollToPanel(this.tiddlerElem,true); cmm.manager.refreshAllViewers();
				Popup.remove(Popup.find(this)); return cmm.processed(ev);
			}); b.tid=this.tid; b.tiddlerElem=this.tiddlerElem;
			var b=addCMD(popup,mgr.closeCmd,mgr.closeTip.format([tid]),function(ev){
				var ev=ev||window.event; var cmm=config.macros.moveablePanel;
				var OK=!story.isDirty(this.tid)||confirm(cmm.manager.tiddlerDirtyMsg.format([this.tid]));
				if (OK) { story.closeTiddler(this.tid); cmm.manager.refreshAllViewers(); }
				Popup.remove(Popup.find(this)); return cmm.processed(ev);
			}); b.tid=this.tid;
			Popup.show('top','right'); return cmm.processed(ev);
		}); b.tid=tid; b.tiddlerElem=tiddlerElem;
		// autoclick on initial mouseover
		b.onmouseover=function(ev) { this.onmouseover=null; return this.onclick.apply(this,arguments); };
		addHR(place); addTXT(place,this.XYJumpCmd); this.menu_compass(place,tiddlerElem,docX,docY);
		addHR(place); this.menu_mapBackground(place);
	},
	command_newMap: function(place){
		addBTN(place,this.newMapCmd,this.newMapTip,function(ev){
			var ev=ev||window.event; var cmm=config.macros.moveablePanel;
			if (!cmm.manager.newMap(ev)) cmm.manager.refreshAllViewers();
			return cmm.processed(ev);
		});
	},
	menu_loadMap: function(place,label,tip,valign,halign){
		addBTN(place,label,tip,function(ev){
			var ev=ev||window.event; var cmm=config.macros.moveablePanel;
			var popup=addPOP(this,'panelManagerPopup'); if (!popup) return false;
			var tids=store.getTaggedTiddlers(cmm.manager.mapTags[0]||cmm.manager.mapTag);
			addTXT(popup,tids.length?cmm.manager.selectMapMsg:cmm.manager.noMaps);
			for (var t=0;t<tids.length;t++) { var title=tids[t].title;
				var b=addCMD(popup,title,cmm.manager.loadThisMapTip.format([title]),function(ev){
					var ev=ev||window.event; var cmm=config.macros.moveablePanel;
					if (!cmm.manager.loadMap(this.map,ev)) { 
						cmm.manager.refreshAllViewers();
						displayMessage(cmm.manager.switchMapMsg.format([this.map]));
					}
					Popup.remove(Popup.find(this)); return cmm.processed(ev);
				}); b.map=title;
			}
			if (valign||halign) Popup.show(valign,halign); else Popup.showHere(this,ev);
			return cmm.processed(ev);
		});
	},
	command_editMap: function(place){
		var map=config.options.txtMoveablePanelMapName;
		addBTN(place,this.editMapCmd.format([map]),this.editMapTip,function(ev){
			var ev=ev||window.event; var cmm=config.macros.moveablePanel;
			if (!store.tiddlerExists(this.map)&&cmm.manager.saveMap(this.map,ev)) return cmm.processed(ev);
			cmm.manager.refreshAllViewers();
			story.displayTiddler(null,this.map,DEFAULT_EDIT_TEMPLATE);
			return cmm.processed(ev);
		}).map=map;
	},
	command_saveMap: function(place){
		addBTN(place,this.saveMapCmd,this.saveMapTip,function(ev){
			var ev=ev||window.event; var cmm=config.macros.moveablePanel;
			if (!cmm.manager.saveMap(this.map,ev)) cmm.manager.refreshAllViewers();
			return cmm.processed(ev);
		}).map=config.options.txtMoveablePanelMapName;
	},
	command_viewerTable: function(place){
		addBTN(place,this.viewerTableCmd,this.viewerTableTip,function(ev){
			var ev=ev||window.event; var cmm=config.macros.moveablePanel;
			var popup=addPOP(this.parentNode,'panelManagerPopup'); if (!popup) return false;
			cmm.manager.viewer_table(popup);
			Popup.showHere(place,ev); return cmm.processed(ev);
		});
	},
//}}}
// // CSS definitions
//{{{
	css: '/*{{{*/\n'
		+'.panelManagerPopup\n'
			+'\t{ white-space:nowrap; }\n'
		+'.panelManagerPopup input\n'
			+'\t{ text-align:center; font-size:90%; }\n'
		+'.panelManagerPopupCompass {\n'
			+'\tbackground:#999; margin:1em;\n'
			+'\t-moz-border-radius:.5em; -webkit-border-radius:.5em;\n'
			+'}\n'
		+'.panelManagerPopupCompass td {\n'
			+'\tfont-size:2em; width:1.5em; height:1.5em; text-align:center; vertical-align;center;\n'
			+'\tbackground:#eee !important; color:#000 !important;\n'
			+'\tborder:1px solid #666; padding:0; margin:0;\n'
			+'\t-moz-border-radius:2px; -webkit-border-radius:2px;\n'
			+'}\n'
		+'.panelManagerPopupCompass td:hover\n'
			+'\t{ background:#fff !important; color:#000 !important; }\n'
		+'.panelManagerPopupCompassButton:hover\n'
			+'\t{ background:transparent !important; color:#000; }\n'
		+'.panelManagerMapPopup\n'
			+'\t{ text-align:center; white-space:nowrap; }\n'
		+'.panelManagerMapPopupEdit input\n'
			+'\t{ width:5em; margin-top:.2em; }\n'
		+'.panelManagerMapViewer .map {\n'
			+'\tposition:relative; overflow:hidden;\n'
			+'\tcolor:#000; background-color:#fff;\n'
			+'\tmargin:0; border:1px solid;\n'
			+'\t-moz-border-radius:3px; -webkit-border-radius:3px;\n'
			+'}\n'
		+'.panelManagerViewerMapBox\n'
			+'\t{ border:1px solid; -moz-border-radius:2px; -webkit-border-radius:2px; }\n'
		+'.panelManagerMapStats\n'
			+'\t{ font-size:80%; }\n'
		+'.panelManagerMapStats .twtable, .panelManagerMapStats .twtable tr, .panelManagerMapStats .twtable td\n'
			+'\t{ padding:0; margin:0; border:0; }\n'
		+'.panelManagerMapStats .twtable\n'
			+'\t{ width:100%; }\n'
		+'.panelManagerMapStats .twtable td\n'
			+'\t{ width:50%; }\n'
		+'/*}}}*/'
});
//}}}
// // CSS initialization (during startup)
//{{{
// set up shadow stylesheet, then load styles so customized CSS (if any) will be applied
config.shadowTiddlers.PanelManagerStyles=config.macros.moveablePanel.manager.css;
var css=store.getRecursiveTiddlerText('PanelManagerStyles',config.macros.moveablePanel.manager.css,10);
setStylesheet(css,'panelManagerStyles');
//}}}
// // hijack: sticky popups (allows interaction inside popup)
// // COPIED FROM [[StickyPopupPlugin]] TO ELIMINATE PLUGIN DEPENDENCY
//{{{
if (config.options.chkStickyPopups==undefined) config.options.chkStickyPopups=false;
try{removeEvent(document,"click",Popup.onDocumentClick);}catch(e){};
try{removeEvent(document,"click",Popup.stickyPopup_onDocumentClick);}catch(e){};
Popup.stickyPopup_onDocumentClick = function(ev)
{
	// if click is in a sticky popup, ignore it so popup will remain visible
	var e = ev ? ev : window.event; var target = resolveTarget(e);
	var p=target; while (p) {
		if (hasClass(p,"popup") && (hasClass(p,"sticky")||config.options.chkStickyPopups)) break;
		else p=p.parentNode;
	}
	// if not a sticky popup... use normal handling
	if (!p) {
		// HACK: if flag is set, ignore this click (and clear the flag)
		if (Popup.ignoreClick) Popup.ignoreClick=false; 
		else Popup.onDocumentClick(ev);
	}
	return true;
};
try{addEvent(document,"click",Popup.stickyPopup_onDocumentClick);}catch(e){};
//}}}
// // hijack: page background popup menu (ALT-CLICK)
//{{{
if (!document.getElementById('panelManagerPopupRoot')) { // only once
	var root=createTiddlyElement(document.body,'span','panelManagerPopupRoot');
	var s=root.style; s.width=0; s.height=0; s.top=0; s.left=0;
	s.display='inline'; s.overflow='visible'; s.position='absolute'; 
	document.onmousedown_panelmanager=document.onmousedown;
	document.onmousedown=function(ev) {
		var ev=ev||window.event; var target=resolveTarget(ev); var cmm=config.macros.moveablePanel;
		if (!ev||!ev.altKey) { // if not ALT-CLICK... handle event normally
			if (document.onmousedown_panelmanager==undefined) return;
			return document.onmousedown_panelmanager.apply(target,arguments);
		}
		var root=document.getElementById('panelManagerPopupRoot');
		var mX=findMouseX(ev); var mY=findMouseY(ev);
		root.style.left=mX+'px'; root.style.top =mY+'px';
		var p=cmm.getPanel(target); var t=story.findContainingTiddler(target);
		var id=p?p.pid:(t?t.getAttribute('tiddler'):'')
		// HACK: ignore next click on doc background (prevents IE from closing popup)
		Popup.ignoreClick=config.browser.isIE;
		cmm.manager.popup(root,ev,id);
		return cmm.processed(ev);
	}
}
//}}}
// // hijack: refresh map viewers when window is scrolled
//{{{
if (window.onscroll_panelManager_init===undefined) { // only once
	window.onscroll_panelManager_init=true;
	window.onscroll_panelManager=window.onscroll;
	window.onscroll=function() {
		config.macros.moveablePanel.manager.notify('refresh');
		if (window.onscroll_panelManager)
			return window.onscroll_panelManager.apply(this,arguments);
	}
}
//}}}
// // hijacks: refresh map viewers when tiddlers or nested sliders are opened/closed
//{{{
if (Story.prototype.displayTiddler_panelManager===undefined) { // only once
	Story.prototype.displayTiddler_panelManager=Story.prototype.displayTiddler;
	Story.prototype.displayTiddler=function() {
		var r=this.displayTiddler_panelManager.apply(this,arguments);
		config.macros.moveablePanel.manager.notify('refresh');
		return r;
	}
	Story.prototype.closeTiddler_panelManager=Story.prototype.closeTiddler;
	Story.prototype.closeTiddler=function() {
		var r=this.closeTiddler_panelManager.apply(this,arguments);
		// NOTE: ASYNC wait for core animation to finish, then update viewers
		var delay=config.options.chkAnimate?config.animDuration+100:0;
		setTimeout("config.macros.moveablePanel.manager.notify('refresh')",delay);
		return r;
	}
}
if (window.onClickNestedSlider && (window.onClickNestedSlider_panelManager===undefined)) { // only once
	window.onClickNestedSlider_panelManager=window.onClickNestedSlider;
	window.onClickNestedSlider=function() {
		var r=window.onClickNestedSlider_panelManager.apply(window,arguments);
		// NOTE: ASYNC wait for core animation to finish, then update viewers
		var delay=config.options.chkAnimate?config.animDuration+100:0;
		setTimeout("config.macros.moveablePanel.manager.notify('refresh')",delay);
		return r;
	}
}
//}}}
<!--{{{-->
<div class='moveablePanel'>
<div class='toolbar'>
	<span macro='moveablePanel load:{{tiddler?tiddler.title:""}} label:"load this map"'></span>
	<span macro='toolbar [[ToolbarCommands::ViewToolbar]]'></span>
</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='tagged' macro='tags'></div>
<div class='tagging' macro='tagging'></div>
<div class='viewer'>
	<div class='content' macro='view text wikified'></div>
</div>
<div class='tagClear'></div>
<div macro='moveablePanel name:{{story.findContainingTiddler(place).getAttribute("tiddler")}} undocked fold hover height:auto'></div>
</div>
<!--}}}-->
|Name|[[PasteUpCommands]]|
|Source|http://www.TiddlyTools.com/#PasteUpCommands|
|Version|2.1.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.5|
|Type|plugin|
|Requires|PasteUpPlugin PasteUpHelperPlugin EditSectionPlugin|
|Description|commands for use with PasteUp documents|
|See also|PasteUpToolbar StoryMenu|
!Navigation, Help and Printing (StoryMenu):
<<<
!!!contents
<<tiddler ToggleLeftSidebar with: "&#x25C4;contents" "show/hide main menu" "button nowrap">>
!!!toggleSidebar
<<tiddler ToggleRightSidebar with: "sidebar&#x25BA;" "show/hide sidebar functions" "button nowrap">>
!!!home
<html><nowiki><a href='javascript:;' class='button nowrap' title='redisplay starting page(s)'
onclick='story.closeAllTiddlers(); restart(); return false;'>&#x25C4;home</a></html>
!!!pages
<<tag pasteup "pages" "view pasteup pages">>
!!!help
<html><nowiki><a class='button nowrap' title="Instructions for using this document" onclick="
	story.displayTiddler(null,'Instructions');
	return false;
">help</a></html>
!!!printall
<html><nowiki><a class='button nowrap' title="print all pages" onclick="
	var storyname=store.getTiddlerText('PasteUpConfig::SlideshowList');
	var list=config.macros.storyViewer.getStory(storyname);
	if (!list.length) list.push('DefaultPage');
	story.closeAllTiddlers();
	story.displayTiddlers(null,list);
	window.print();
	return false;
">print</a></html>
!!!!!end
<<<
!!!Slideshow mode (StoryMenu):
<<<
!!!slideshow
<html><nowiki><a class='button nowrap' title="start/stop automatic slideshow" onclick="
	if (config.macros.storyViewer.started || this.savedHTML) {
		this.innerHTML=this.savedHTML; this.savedHTML=null;
		config.macros.option.propagateOption('chkSlideshow','checked',false,'input');
		config.macros.storyViewer.started=false;
		story.refreshAllTiddlers(true);
	} else {
		var chk='<input type=\x22checkbox\x22 checked style=\x22margin:0;padding:0;\x22>';
		this.savedHTML=this.innerHTML; this.innerHTML=chk+this.innerHTML;
		var storyname=store.getTiddlerText('PasteUpConfig::SlideshowList');
		var list=config.macros.storyViewer.getStory(storyname);
		if (!list.length) list.push('DefaultPage');
		window.readOnly=true;
		config.macros.option.propagateOption('chkHttpReadOnly','checked',true,'input');
		config.macros.option.propagateOption('chkSinglePageMode','checked',true,'input');
		config.macros.option.propagateOption('chkSlideshow','checked',true,'input');
		config.macros.storyViewer.started=true;
		story.closeAllTiddlers();
		story.switchTheme(config.options.txtTheme);
		store.notifyAll();
		story.displayTiddler(null,list[0]);
	}
	return false;
">slides</a></html><<tiddler {{
	var e=place.lastChild.getElementsByTagName('a')[0];
	if (config.macros.storyViewer.started && e.innerHTML.indexOf('checkbox')==-1) {
		var chk='<input type=\x22checkbox\x22 checked style=\x22margin:0;padding:0;\x22>';
		e.savedHTML=e.innerHTML;
		e.innerHTML=chk+e.innerHTML;
	}
'';}}>>
!!!slideshow_toolbar
<<storyViewer
	{{store.getTiddlerText('PasteUpConfig::SlideshowList')}}
	list allbuttons
	prompt:{{store.getTiddlerText('PasteUpConfig::SlideshowPrompt')}}>>/%
%/<<storyViewer
	{{store.getTiddlerText('PasteUpConfig::SlideshowList')}}
	timer:{{store.getTiddlerText('PasteUpConfig::SlideshowTimer')}}>>
!!!!!end
<<<
!Editing (StoryMenu):
<<<
!!!toggleEdit
<html><nowiki><span class="button nowrap" style="cursor:pointer"
	title="enable/disable editing of this document"
	onclick="this.getElementsByTagName('input')[0].click();">
<input type='checkbox' style="margin:0;padding:0;cursor:pointer" onclick="
	window.readOnly=!this.checked;
	config.macros.option.propagateOption('chkHttpReadOnly','checked',window.readOnly,'input');
	config.macros.option.propagateOption('chkSinglePageMode','checked',window.readOnly,'input');
	config.macros.option.propagateOption('chkSlideshow','checked',false,'input');
	config.macros.storyViewer.started=false;
	if (!config.extensions.tiddlyspace) { // DON'T HIDE BACKSTAGE FOR TIDDLYSPACE
		window.showBackstage=!window.readOnly;
		if(showBackstage && !backstage.area) backstage.init();
		backstage.button.style.display=showBackstage?'block':'none';
		backstage.hide();
	}
	story.switchTheme(config.options.txtTheme); store.notifyAll(); story.refreshAllTiddlers(true);
	return false;
">edit</span></html><<tiddler {{
	var e=place.lastChild.getElementsByTagName('input')[0];
	e.checked=!window.readOnly;
'';}}>>
!!!unsavedChanges
{{nowrap{<<unsavedChanges command "%0 unsaved change%2">>}}}
!!!undo
{{nowrap{<<undo label:"undo">>}}}
!!!save
{{nowrap{<<saveChanges "save" "save changes to this document">>}}}
!!!autosave
{{nowrap button{<<option chkAutoSave>>autosave}}}
!!!saveAs
{{nowrap{<<saveAs "label:save as">>}}}
!!!download
<html><nowiki><a class="button nowrap" href="" title="download a local copy of this document" onmouseover="
	if (config.extensions.tiddlyspace)
		this.href='/?download='+config.extensions.tiddlyspace.currentSpace.name+'.html';
	else
		this.href=document.location.href.replace(/^https?/,'ftp');
">download</a></html>
!!!setup
<<slider closed PasteUpConfig##setupmenu
	"setup" "configure PasteUp settings for this document">>
!!!!!end
<<<
!Editing (MainMenu and PasteUpToolbar)
<<<
!!!defaultpage
<html><nowiki><a class='button nowrap' title="edit default page layout" onclick="
	story.displayTiddler(null,'DefaultPage');
	return false;
">edit default page...</a></html>
!!!addpart
<html><nowiki><a class='button nowrap' title="add a part to this page" onclick="
	var here=story.findContainingTiddler(this);
	var tid=here?here.getAttribute('tiddler'):'';
	return config.macros.pasteUpHelper.popupPicker(this,event,tid,'part',
		'create a new part...', 'DefaultPart',
		'Please enter a part name:', 'or, add an existing part:');
">add a part...</a></html>
!!!addpage
<html><nowiki><a class='button nowrap' title="create a new pasteup page" onclick="
	return config.macros.pasteUpHelper.popupPicker(this,event,null,'pasteup',
		'create a new page...',	'DefaultPage',
		'Please enter a page name:', 'or, copy an existing page:');
">add a page...</a></html>
!!!deletepage
<html><nowiki><a class='button nowrap' title="delete this pasteup page" onclick="
	var tid=story.findContainingTiddler(this).getAttribute('tiddler');
	config.commands.deleteTiddler.handler(event,this,tid);
	return false;
">delete this page...</a></html>
!!!!!end
<<<
|Name|[[PasteUpConfig]]|
|Source|http://www.TiddlyTools.com/#PasteUpConfig|
|Version|1.1.3|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.5|
|Requires|PasteUpPlugin PasteUpHelperPlugin EditSectionPlugin|
|Type|data|
|Description|configuration options and data for PasteUpPlugin and PasteUpHelperPlugin|
!!!Usage
<<<
This tiddler contains sections with configuration data for use by PasteUpPlugin and PasteUpHelperPlugin.  Although you may directly edit the content of this tiddler to add/remove/modify the data, this is ''not recommended'', as you must be very careful to ''avoid changing any of the //required// syntax'' that surrounds the actual data values.  To ensure that only the desired tiddler data content is changed, you can use the following menu of commands to easily view/modify the separate configuration sections without needing to edit the tiddler as a whole:
| ''<<tiddler PasteUpConfig##setupmenu>>'' |
where:
* ''CSS'' - custom-defined CSS class definitions used to format pasteup part content
* ''fonts, styles, images'' - ~PasteUpHelper droplist definitions, one item per line:
** Each item is a name/value pair, separated by "=" (e.g, name=value)
** The name is displayed in the droplist, and the value is assigned when the item is selected.
** If the "=value" portion of an item is omitted, the item text is display and also used as the assigned value.
** An item with a trailing "=", //with no value specified//, clears the droplist selection.
** The values for font/style droplist items are CSS classnames.  The values for image droplist items are the path and filename of the respective image files.
** If a value currently assigned to a pasteup element does not match any values in the corresponding droplist, an "other: ...." item is automatically added to the list.
** Blank lines within a list definition are ignored.
* ''pagesize'' - the width and height of pasteup layout pages (use CSS units)
* ''partsize'',''imagesize'' - the default position/size for adding new parts/images (use CSS units)
* ''title, subtitle, menu'' - document title, subtitle, and main (home) menu
* ''startup'' - a space-separated list of tiddlers to display at startup (i.e., DefaultTiddlers)
* ''default page, default part'' - content for creating new pasteup pages and parts
* ''advanced'' - systemConfig-based advanced settings and tweaks to plugin internal values
Note: you can embed this menu in another tiddler by writing:
{{{
<<tiddler PasteUpConfig##setupmenu>>
}}}
<<<
{{hidden{
!!!setupmenu
{{small{
	  [[title|SiteTitle]]/%
%/ &nbsp; [[subtitle|SiteSubtitle]]/%
%/ &nbsp; [[menu|MainMenu]]/%
%/ &nbsp; [[startup|DefaultTiddlers]]/%
%/ &nbsp; [[default page|DefaultPage]]/%
%/ &nbsp; [[default part|DefaultPart]]/%
%/ &nbsp; [[advanced|StartupSettings]]
<<editSection PasteUpStyleSheet		 CSS		"custom CSS style definitions">>/%
%/<<editSection PasteUpFontList	 	 fonts		"font sizes">>/%
%/<<editSection PasteUpStyleList 	 styles		"text formatting styles">>/%
%/<<editSection PasteUpImageList 	 images		"embeddable images">>/%
%/<<editSection PasteUpConfig##pagesize	 pagesize	"pasteup layout height/width">>/%
%/<<editSection PasteUpConfig##partsize	 partsize	"default position/size for adding new parts">>/%
%/<<editSection PasteUpConfig##imagesize imagesize	"default position/size for adding new images">>/%
%/<<editSection PasteUpConfig##slideshow slideshow	"slideshow list source and timer duration">>/%
%/}}}
!end
}}}
!!!pagesize
<<<
Total page size, top margin size, pasteup layout size:
----
~PageWidth: 8.5in
~PageHeight: 11in
~MarginTop: .5in
Width: 8in
Height: 10in
----
notes:
* ~PageWidth/~PageHeight //includes// the space used for margins.
* Width/Height is the size of the //printed// area of each actual page of content, //excluding// the margins.
<<<
!!!partsize
<<<
Initial position/size for //creating new parts// with the ''add part'' toolbar command:
----
~PartLeft: 100px
~PartTop: 100px
~PartWidth: 200px
~PartHeight: 100px
----
notes:
*new parts should be placed near the top-left corner of the current pasteup page and given a default size so they are easy to locate and adjust after being added.
<<<
!!!imagesize
<<<
Initial position/size/adjustability for //adding an image within a part//:
----
~ImageLeft: 0px
~ImageTop: 0px
~ImageWidth: 100%
~ImageHeight: auto
~ImageAdjust: false
----
notes:
* position is specified as an x-offset and y-offset, relative to the upper-left corner of the containing part.
* width/height can be fixed values (e.g., px, in) and/or percentages, relative to the width/height of the containing part.  If both values are "100%", images are stretched to fit the containing part dimensions.  If either the width or height is set to "auto", images are scaled ''proportionally'' in that dimension.  When both values are set to "auto", images are rendered full-sized, without scaling.
* if set to 'false', the relative position/size of a newly added image is 'frozen' within the containing part.  To allow changes to the position/size for a specific image, you can select the 'adjust' checkbox in the PasteUpHelper image editor popup.  Setting ~ImageAdjust to "true" automatically enables 'adjustabilty' for all new images by default.
<<<
!!!slideshow
<<<
Source list and timer setting for automatic slideshows:
----
~SlideshowList: pasteup
~SlideshowTimer: 20
~SlideshowPrompt: pasteup pages...
----
notes:
* ~SlideshowList can be either a tag value to match (e.g. "pasteup") or the name of a tiddler containing links to the desired slides (e.g, "MainMenu", "DefaultTiddlers", etc.).
* ~SlideshowTimer specifies the number of seconds to display each slide before advancing to the next.
* ~SlideshowPrompt is the text label that appears as the first item in the slideshow droplist.
<<<
(default)=
tiny
fine
small
normal
medium
big
bigger
biggest
/***
|Name|[[PasteUpHelperPlugin]]|
|Source|http://www.TiddlyTools.com/#PasteUpHelperPlugin|
|Version|1.7.5|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.5|
|Type|plugin|
|Requires|[[PasteUpPlugin]] [[EditSectionPlugin]]|
|Description|extends [[PasteUpPlugin]] popup editor with enhanced form controls|
!!!Documentation
> see [[PasteUpPluginInfo]]
!!!Example
<<<
<<tiddler PasteUpHelperPlugin##test style:"border:1px solid blue;color:black;background:white;" edit adjust x:1.2in y:-18px w:318px h:74px>>/%
!test
test ~PasteUpHelper test
line 2
line 3
line 4
!end
%/
<<<
!!!Configuration
<<<
<<option chkPasteUpHelper>>enable PasteUpHelper menu (use SHIFT-click to bypass)
{{{<<option chkPasteUpHelper>>}}}
<<option chkPasteUpNoMenuLink>>disable menu heading link to part tiddler
{{{<<option chkPasteUpNoMenuLink>>}}}
<<option chkPasteUpHelperAutoName>>automatically name/number new pages/parts (e.g, Page01, Part01, etc.)
{{{<<option chkPasteUpHelperAutoName>>}}}
Also see [[PasteUpPlugin]], [[PasteUpConfig]] and related shadow tiddlers: [[DefaultPage]], [[DefaultPart]], [[PasteUpStyleSheet]], [[PasteUpHelperTemplate]], [[PasteUpCommands]]
<<<
!!!Revisions
<<<
2012.01.29 1.7.5 invoke autoSaveChanges when tiddlers are modified
2011.12.27 1.7.4 in "add image" dialog, added hidden "filename" field with 'character fixup' for server-side filename to replace all but alphanum, dot, dash, and underscore with underscores (e.g., no spaces or special characters allowed)
2011.11.25 1.7.3 remove extra trailing "," after last function declaration (fixes IE7 error).  Also, revised "add image" dialog layout and input validation handling
2011.09.15 1.7.2 in renderMenu(), cleanup LI creation when menu items are suppressed
2011.09.13 1.7.1 in renderMenu(), suppress menu items if corresponding label is null (or blank)
2011.09.12 1.7.0 added csrf_token to "add image" form (for TiddlySpace binary file upload)
2011.09.09 1.6.0 added support for autonaming: pagenamePattern, partnamePattern and getNextName()
2011.09.08 1.5.0 added popupPicker() to support 'add part' and 'add page' list interface
2011.09.04 1.4.0 replaced 'behind text' image option with 'layer' placement (z-index) control for all elements.  Added "add image" interface: addImagePanel()+HTML Template (shadow)
2011.09.02 1.3.0 major interface changes: replaced big 'helper' form with type-specific forms and handlers.  Rewrote modifyPart() to handle *all* part changes.  SHIFT-CLICK now bypasses helper and shows RAW part definition (all syntax visible)
2011.08.02 1.2.3 added support for multiple listbox definition tiddlers (e.g,. multiple image lists)
2011.08.02 1.2.2 moved renderMenu() from PasteUpPlugin.  Changed menu text and added type-specific commands
2011.07.31 1.2.1 refactored form template and init/save handlers to use getForm(), getInitForm(), and getSaveForm() access functions to support type-specific forms (see also: [[EditSectionPlugin]])
2011.07.24 1.2.0 Added handling for '[edit this list...]'.  Hijack renderMenu() and added popupList() and modifyPart() for fontsize/style 'quick menu' handling.  Added confirmation (optional) to removePart() handling.
2011.06.19 1.1.3 moved default/example user-defined pasteup styles from PageUpConfig##css to [[PasteUpStyleSheet]] shadow and add notification trigger for style changes.  Also, minor wording changes in PasteUpHelperTemplate.
2011.06.18 1.1.2 in initForm(), added "\\r?" to all regexp for IE7 newline handling
2011.06.08 1.1.1 in HTML template, changed "delete" to "remove" and use removePart() (see PasteUpPlugin) instead of editSection() (see EditSectionPlugin)
2011.05.15 1.1.0 added imagePopup() image thumbnail display and selection handling
2011.05.06 1.0.8 fixed default tiddler names sizeList, styleList, and fontList
2011.05.05 1.0.7 in HTML template, use deleteSection() (see EditSectionPlugin)
2011.05.03 1.0.6 HTML template layout changes for 'advanced' checkbox.  Also, moved default config for fonts, styles, and images to separate tiddlers for easier 'overlay' customizations.
2010.12.30 1.0.5 added 'image lock' feature
2010.12.25 1.0.4 removed use of IDs in HTML template and related code (for finding helper elements).  Added transclusion of QuickEditToolbar (optional)
2010.12.18 1.0.3 added 'image behind text' feature
2010.12.12 1.0.2 added "show/hide dimensions" to helper form
2010.11.27 1.0.1 added PasteUpConfig defaults for position/size of new parts and images
2010.11.21 1.0.0 initial release
2010.11.01 0.9.5 helper form and handlers split from PasteUpPlugin
| Please see [[PasteUpPluginInfo]] for previous revision details |
2010.07.21 0.7.5 alpha prototype (for review - do not distribute)
<<<
!!!Code
***/
// // PLUGIN VERSION
//{{{
version.extensions.PasteUpHelperPlugin= {major: 1, minor: 7, revision: 5, date: new Date(2012,1,29)};
//}}}
// // OPTIONS (COOKIES)
//{{{
if (config.options.chkPasteUpHelper===undefined)	config.options.chkPasteUpHelper=true;
if (config.options.chkPasteUpNoMenuLink===undefined)	config.options.chkPasteUpNoMenuLink=false;
if (config.options.chkPasteUpHelperAutoName===undefined)config.options.chkPasteUpHelperAutoName=false;
//}}}
// // HARD-CODED DEFAULTS
//{{{
config.macros.pasteUpHelper = {
	sizeList:	'PasteUpFontList',
	styleList:	'PasteUpStyleList',
	imageList:	'PasteUpImageList',
	styleSheet:	'PasteUpStyleSheet',
	uploadScript:	'http://www.tiddlytools.com/showargs.php',
	uploadPath:	'http://www.servername.com/images/',
	thumbsize:	'100px',
	templates: {	// HTML template SHADOW tiddlers (forms for popup editor)
		text:	  'PasteUpHelperTemplate_Text',		// edit text
		image:	  'PasteUpHelperTemplate_Image',	// select image, x,y,w,h,adjust
		addimage: 'PasteUpHelperTemplate_AddImage',	// add image to list (w/upload)
		place:	  'PasteUpHelperTemplate_Placement'	// x,y,w,h
	},
	MWtag: 'mediawiki',
	MWmsg: 'This part uses MediaWiki-formatted content.  To add an image, please edit the part text and use MediaWiki\'s standard image-embedding syntax.',
//}}}
// // TRANSLATE
//{{{
	sizeListAnnotation:	'List paste up font sizes, one per line (use CSS classnames defined in PasteUpStyleSheet)',
	styleListAnnotation:	'List paste up styles, one per line (use CSS classnames defined in PasteUpStyleSheet)',
	imageListAnnotation:	'List image URLs, one per line (use "name=URL..." to create short names for long URLs)',
	styleSheetAnnotation:	'Add/edit custom styles (CSS) here, then add list entries in PasteUpFontList and/or PasteUpStyleList',
	editTextMenuTxt:	'text...',
	editTextMenuTip:	'Enter TEXT content for this part',
	selectImageMenuTxt:	'image...',
	selectImageMenuTip:	'Choose an IMAGE for this part',
	selectStyleMenuTxt:	'style...',
	selectStyleMenuTip:	'Change the STYLE of this part',
	selectFontMenuTxt:	'font...',
	selectFontMenuTip:	'Change the FONT of this part',
	adjustMenuTxt:		'placement...',
	adjustMenuTip:		'Change the POSITION and/or SIZE of this part',
	removeMenuTxt:		'remove part...',
	removeMenuTip:		'Remove this part from the current page',
	deleteMenuTxt:		'delete part...',
	deleteMenuTip:		'Delete this part definition from the document',
//}}}
// // PLUGIN INIT
//{{{
	init: function() {
		if (!config.macros.pasteUp) return;
		if (!config.macros.editSection) return;

		// override PasteUpPlugin click action to add popup menu
		config.macros.pasteUp.clickAction=this.clickAction;

		// override default EditSectionPlugin forms and handlers
		var cme=config.macros.editSection; // ABBREV
		cme.getForm=this.getForm;
		cme.getInitForm=this.getInitForm;
		cme.getSaveForm=this.getSaveForm;

		// deliver SHADOW HTML form definitions (PasteUpHelper...Template)
		for (var i in this.templates) {
			var tid=this.templates[i];
			config.shadowTiddlers[tid]=store.getTiddlerText('PasteUpHelperPlugin##'+tid,'');
		}

		// deliver SHADOW example/default user-defined pasteup styles (PasteUpStyleSheet)
		var tid=this.styleSheet;
		config.shadowTiddlers[tid]=
			'/*{{{*/\n'
			+store.getTiddlerText('PasteUpHelperPlugin##css','')
			+'\n/*}}}*/';;
		config.annotations[tid]=this.styleSheetAnnotation;
		store.addNotification(tid,refreshStyles);

		// set annotation 'help text' for configuration tiddlers (NOTE: *NO* SHADOWS)
		function annotate(t,a) {
			var tids=t.readBracketedList();
			for (var i=0;i<tids.length;i++) config.annotations[tids[i]]=a;
		}
		annotate(this.styleList,this.styleListAnnotation);
		annotate(this.imageList,this.imageListAnnotation);
		annotate(this.sizeList, this.sizeListAnnotation);
	},
//}}}
// // POPUP MENU (extends PasteUpPlugin default popup menu)
//{{{
	clickAction: function(here,ev) {
		if (config.options.chkPasteUpHelper&&!ev.shiftKey) {
			var cmp=config.macros.pasteUp; // abbrev
			config.macros.pasteUpHelper.renderMenu(Popup.create(here),here);
			var x=cmp.getMX(ev)-findPosX(here);
			var y=cmp.getMY(ev)-findPosY(here);
			Popup.show('top','left',{x:x,y:y});
			return cmp.ok(ev);
		}
		else return config.macros.editSection.click.call(here,ev,'raw');
	},
	renderMenu: function(p,target) {
		var cmp=config.macros.pasteUpHelper; // ABBREV
		var tid=target.getAttribute('tid');
		var txt =store.getTiddlerText(tid);
		cmp.currentTarget=target; // NOTE: GLOBAL STATE VARIABLE!

		// HEADING
		var tip='';
		var s=target.style; var a='auto'; // abbreviations
		var t=target.getAttribute('tiddler'); // source title
		var c=target.className.replace(/ ?pasteUpBorder/,'').replace(/ ?pasteUp/,''); // classname
		if (c.length) tip+=' class="'+c+'", ';
		tip+='x='+(s.left||a)+', y='+(s.top||a);
		tip+=((s.zIndex!=0&&s.zIndex!=1)?', z='+s.zIndex:'')
		tip+=', w='+(s.width||a)+', h='+(s.height||a);
		var li=createTiddlyElement(p,'li'); li.title=tip;
		if (config.options.chkPasteUpNoMenuLink) var head=createTiddlyText(li,t);
		else { var head=createTiddlyLink(li,t); head.innerHTML=t; head.title=tip; }
		createTiddlyElement(p,'hr');

		// GET CURRENT FONTSIZE/STYLE from "class:..." macro param
		var size=''; var classname=''; // FIRST CLASSNAME IS FONTSIZE, REST IS STYLENAME
		var pat='<<(?:pasteUp|tiddler)\\s+\\[\\[.+##content\\]\\]\\s+class:"([^"]*)".*?>>';
		var re=new RegExp(pat);	var m=re.exec(txt);
		if (m) { var t=m[1].split(' '); size=t.shift(); classname=t.join(' '); }
		else { // FALLBACK: GET FONTSIZE/STYLE from CSS class wrapper
			var pat="\\{\\{([^\\{]+)\\{\\r?\\n((?:.|\\n)*)\\r?\\n\\}\\}\\}$";
			var re=new RegExp(pat); var m=re.exec(txt);
			if (m) { var t=m[1].split(' '); size=t.shift(); classname=t.join(' '); }
			else { // FALLBACK: GET FONTSIZE/STYLE from HTML div
				var pat='<html><div class="([^"]+)">\\r?\\n((?:.|\\n)*)\\r?\\n</div></html>$';
				var re=new RegExp(pat); var m=re.exec(txt);
				if (m) { var t=m[1].split(' '); size=t.shift(); classname=t.join(' '); }
			}
		}

		// EDIT TEXT...
		var label=this.editTextMenuTxt; var tip=this.editTextMenuTip;
		if (label&&label.length) createTiddlyButton(
			createTiddlyElement(p,'li'),label,tip,function(ev){
			Popup.remove();
			config.macros.editSection.click.call(
				config.macros.pasteUpHelper.currentTarget,ev,'text');
			return config.macros.pasteUp.ok(ev);
		});

		// SELECT IMAGE...
		var label=this.selectImageMenuTxt; var tip=this.selectImageMenuTip;
		if (label&&label.length) createTiddlyButton(
			createTiddlyElement(p,'li'),label,tip,function(ev){
			var cmp=config.macros.pasteUpHelper; // ABBREV
			Popup.remove();
			var t=store.getTiddler(this.getAttribute('tid'));
			if (t&&t.isTagged(cmp.MWtag)) alert(cmp.MWmsg);
			else config.macros.editSection.click.call(cmp.currentTarget,ev,'image');
			return config.macros.pasteUp.ok(ev);
		},null,null,null,{tid:tid});

		// SET STYLE...
		var label=this.selectStyleMenuTxt; var tip=this.selectStyleMenuTip;
		if (label&&label.length) createTiddlyButton(
			createTiddlyElement(p,'li'),label,tip,cmp.popupList,
			null,null,null,{mode:'style',tid:tid,val:classname});

		// SET FONTSIZE...
		var label=this.selectFontMenuTxt; var tip=this.selectFontMenuTip;
		if (label&&label.length) createTiddlyButton(
			createTiddlyElement(p,'li'),label,tip,cmp.popupList,
			null,null,null,{mode:'size',tid:tid,val:size});

		// ADJUST PART...
		if (target.adjustable) {
			var label=this.adjustMenuTxt; var tip=this.adjustMenuTip;
			if (label&&label.length) createTiddlyButton(
				createTiddlyElement(p,'li'),label,tip,function(ev){
				Popup.remove();
				config.macros.editSection.click.call(
					config.macros.pasteUpHelper.currentTarget,ev,'place');
				return config.macros.pasteUp.ok(ev);
			});
		}

		// SEPARATOR
		if (this.removeMenuTxt || this.deleteMenuTxt)
			createTiddlyElement(p,'hr');

		// REMOVE PART...
		var label=this.removeMenuTxt; var tip=this.removeMenuTip;
		if (label&&label.length) createTiddlyButton(
			createTiddlyElement(p,'li'),label,tip,function(ev){
			var cmp=config.macros.pasteUp; // abbrev
			Popup.remove();
			cmp.removePart(config.macros.pasteUpHelper.currentTarget);
			return cmp.ok(ev);
		});

		// DELETE PART...
		var label=this.deleteMenuTxt; var tip=this.deleteMenuTip;
		if (label&&label.length) createTiddlyButton(
			createTiddlyElement(p,'li'),label,tip,function(ev){
			var cmp=config.macros.pasteUp; // abbrev
			var cmh=config.macros.pasteUpHelper; // abbrev
			var cme=config.macros.editSection; // abbrev
			Popup.remove();
			var tid=cmh.currentTarget.getAttribute('tid');
			var title=tid.split('##')[0]; var section=tid.split('##')[1];
			if (confirm(cme.deletemsg.format([tid]))) {
				cmp.removePart(cmh.currentTarget,true); // NO EXTRA WARNING
				cme.deleteSection(title,section);
				displayMessage(tid+' deleted');
			}
			return cme.ok(ev);
		});
	},
//}}}
// // LISTBOXES
//{{{
	popupList: function(ev) { ev=ev||window.event;
		var cmp=config.macros.pasteUpHelper; // ABBREV
		var mode=this.getAttribute('mode');
		var tid =this.getAttribute('tid');
		var val =this.getAttribute('val');

		// RENDER POPUP LIST
		var p=Popup.create(this,null,'popup smallform'); p.style.padding='0';
		Popup.show('top','right'); 
		var s=createTiddlyElement(p,'select');
		if (mode=='style') cmp.setList(s,cmp.styleList,val,'select a style...');
		if (mode=='size')  cmp.setList(s,cmp.sizeList, val,'select a font...');
		s.size=s.length; s.style.width='100%';
		s.setAttribute('tid',tid); s.setAttribute('mode',mode); s.setAttribute('val',val);
		s.onkeyup=function(ev) {
			var k=(ev||window.event).keyCode;
			if (k==13) this.onclick();
			if (k==27) Popup.remove();
		};
		s.onclick=function(){
			if (!this.selectedIndex) return; // ignore click on prompt
			var cmp =config.macros.pasteUpHelper; // ABBREV
			var mode=this.getAttribute('mode');
			var tid =this.getAttribute('tid');
			var val =this.getAttribute('val');
			if (this.value=='_edit')
				story.displayTiddler(null,this.getAttribute('src'),DEFAULT_EDIT_TEMPLATE);
			else if (this.value!=val) {
				var txt=store.getTiddlerText(tid); // CURRENT CONTENT
				txt=cmp.modifyPart(tid,txt,mode,this.value); // REVISED CONTENT
				var title=tid.split('##')[0]; var section=tid.split('##')[1];
				config.macros.editSection.updateTiddler(txt,title,section);
			}
			Popup.remove();
			return config.macros.pasteUp.ok(ev);
		};
		s.focus();
		return config.macros.pasteUp.ok(ev);
	},
	setList: function(list,src,val,prompt) { // SET SIZE, STYLE, and IMAGE LISTS
		if (prompt) list.options[0]=new Option(prompt,''); // OVERRIDE DEFAULT PROMPT
		while (list.length>1) list.options[list.length-1]=null; // empty list (leave prompt)
		var tids=src.readBracketedList(); var txt=[];
		for (var i=0;i<tids.length;i++) txt.push(store.getTiddlerText(tids[i],''));
		var items=txt.join('\n').split('\n');
		var found=false;
		for (var i=0; i<items.length; i++) { // fmt: "value" or "name=value"
			var t=items[i]; var v=t; if (!t.length) continue;
			if (items[i].indexOf('=')!=-1) 
				{ var t=items[i].split('=')[0]; var v=items[i].split('=')[1]||''; }
			var sel=val.length&&(v==val); found=found||sel;
			list.options[list.length]=new Option(t,v,sel,sel);
		}
		if (!found && val.length)
			list.options[list.length]=new Option('other: '+val,val,true,true);
		list.options[list.length]=new Option('[edit this list...]','_edit');
		list.setAttribute('src',tids[0]); list.setAttribute('val',val);
		if (!list.onchange_saved) list.onchange_saved=list.onchange
		list.onchange=function() {
			if (this.value=='_edit') {
				config.macros.editSection.removeAllPanels();
				if (!jQuery('.editSectionPanel').length) // CLOSE PANEL STOPPED BY USER
					story.displayTiddler(null,this.getAttribute('src'),DEFAULT_EDIT_TEMPLATE);
			} else if (list.onchange_saved) list.onchange_saved.apply(this,arguments);
		}
	},
	popupPicker: function(root,ev,tid,tag,createlabel,createval,createmsg,selectmsg) {
		var p=Popup.create(root,null,'popup smallform'); p.style.padding='0';
		var tids=store.getTaggedTiddlers(tag,'excludeLists');
		var s=createTiddlyElement(p,'select');
		s.setAttribute('tid',tid); // TARGET TIDDLER
		s.setAttribute('msg',createmsg); // POPUP MSG (ASK FOR NAME)
		var indent='';
		if (createlabel&&createlabel.length) {
			s.options[s.length]=new Option(createlabel,createval);
			var indent='\xa0\xa0';
		}
		if (tids.length)
			s.options[s.length]=new Option(selectmsg,'');
		for (var t=0; t<tids.length; t++) { if (tids[t].title==createval) continue;
			s.options[s.length]=new Option(indent+tids[t].title,tids[t].title);
			s.options[s.length-1].title=tids[t].getSubtitle();
		}
		s.size=Math.min(s.length,10);
		s.onkeyup=function(ev){ var k=(ev||window.event).keyCode;
			if (k==13) this.onclick();
			if (k==27) Popup.remove();
			return config.macros.pasteUp.ok(ev);
		}
		if (tag=='part') {
			s.onclick=function(ev) {
				if (!this.value.length) return false;
				var tid=this.getAttribute('tid');
				var msg=this.getAttribute('msg');
				var p=this.value;
				var cmh=config.macros.pasteUpHelper; // abbrev
				if (p=='DefaultPart') {
					p=config.macros.pasteUpHelper.getNextName(tid,'part');
					if (!config.options.chkPasteUpHelperAutoName) p=prompt(msg,p);
				}
				if (p && p.length) config.macros.pasteUp.addPart(tid,p);
				Popup.remove(); return config.macros.pasteUp.ok(ev);
			}
		} else {
			s.onclick=function(ev){
				if (!this.value.length) return false;
				var tid=config.macros.pasteUpHelper.getNextName('','pasteup');
				var msg=this.getAttribute('msg');
				if (!config.options.chkPasteUpHelperAutoName) tid=prompt(msg,tid);
				var msg=config.messages.overwriteWarning.format([tid||'']);
				if (tid && (!store.tiddlerExists(tid)||confirm(msg))) {
					// CREATE NEW PAGE
					var src=this.value;
					var who=config.options.txtUserName;
					var when=new Date();
					var text=store.getTiddlerText(src,'');
					var tags=['pasteup'];
					var fields=config.defaultCustomFields
					store.saveTiddler(tid,tid,text,who,when,tags,fields);
					story.displayTiddler(null,tid);
					displayMessage('Created '+tid+' from '+src);
					// ADD TO DEFAULT TIDDLERS
					if (confirm('Automatically display \x22'+tid+'\x22 at startup?')) {
						var tid2='DefaultTiddlers'; var t=store.getTiddler(tid2);
						var text=store.getTiddlerText(tid2)+'\n[['+tid+']]';
						store.saveTiddler(tid2,tid2,text,who,when,t?t.tags:[],
							config.macros.pasteUp.cloneFields(t?t.fields:{}));
						displayMessage('Added '+tid+' to '+tid2);
					}
					autoSaveChanges();
				}
				Popup.remove(); return config.macros.pasteUp.ok(ev);
			}
		}
		if (tids.length) { Popup.show(); s.focus(); }
		else { p.style.display='none'; s.onclick.call(s,ev); }
		return config.macros.pasteUp.ok(ev);
	},
	pagenamePattern: 'Page%1',	// %0=next number
	partnamePattern: '%0_Part%1',	// %1=current page name
	getNextName: function(tid,tag) {
		var pat=tag=='part'?this.partnamePattern:this.pagenamePattern;
		var prefix=pat.format([tid,'']);
		var tids=store.getTaggedTiddlers(tag,'excludeLists');
		for (var t=tids.length-1; t>=0; t--)	// find last matching title
			if (tids[t].title.startsWith(prefix)) { var found=tids[t].title; break }
		var next=1;
		if (found) var match=/([0-9]+)$/.exec(found);
		if (match) next=parseInt(match[1])+1;
		return pat.format([tid,next]);
	},
//}}}
// // THUMBNAIL BROWSER
//{{{
	imagePopup: function(event,list) {
		var p=Popup.create(list); if (!p) return false;
		config.macros.pasteUpHelper.renderThumbs(p,list);
		Popup.show('top','left');
		event.cancelBubble=true; if(event.stopPropagation)event.stopPropagation(); return false;
	},
	renderThumbs: function(p,list) {
		if (!list.id) list.id=new Date().getTime()+Math.random();
		var size=config.macros.pasteUpHelper.thumbsize; var rowsize=4;
		var thumb='<td style="width:%1;height:%1;text-align:center;border:1px solid transparent" '
			+'onmouseover="this.style.border=\'1px solid black\'" '
			+'onmouseout=" this.style.border=\'1px solid transparent\'">'
			+'<img src="%0" title="%0" '
			+'style="border:1px solid #999;max-width:%1;max-height:%1;cursor:pointer" '
			+'onclick="var v=this.title; var list=document.getElementById(\''+list.id+'\'); '
			+'Popup.remove(Popup.stack.length-1); '
			+'list.value=v; list.focus(); return list.onchange.call(list,event);"></td>';
		var out=[];
		var c=0;
		for (var i=0; i<list.options.length; i++) { var src=list.options[i].value;
			if (src==''||src=='_edit') continue;
			if (c && c%rowsize==0) out.push('</tr><tr>');
			if (src.length) { out.push(thumb.format([src,size])); c++; }
		}
		p.innerHTML+="<a href='javascript:;' style='float:right' "
			+" onclick='Popup.remove(Popup.stack.length-1);return false;'>close</a>"
			+" choose an image:<hr>";
		out=out.join('');
		if (out.length) p.innerHTML+='<table><tr>'+out+'</tr></table>';
	},
	addImagePanel: function(ev,root) {
		var cmp=config.macros.pasteUpHelper;
		var cme=config.macros.editSection;
		var p=createTiddlyElement(document.body,"ol",
			"addImagePanel","popup smallform editSectionPanel");
		p.root=root;
		p.innerHTML=store.getRecursiveTiddlerText(cmp.templates['addimage'],'',10);
		var f=p.getElementsByTagName('form')[0];
		// initialize internal form values
		f.panel=p;
		f.action=cmp.uploadScript;
		f.targetlist.value=cmp.imageList.readBracketedList()[0];
		f.targetlist.nextSibling.innerHTML=f.targetlist.value;
		f.uploadpath.value=cmp.uploadPath;
		if (config.extensions.tiddlyspace!==undefined)
			f.csrf_token.value=config.extensions.tiddlyspace.getCSRFToken();

		// display panel
		var x=findPosX(root); var y=findPosY(root);
		var winw=findWindowWidth(); var scrollw=winw-document.body.offsetWidth;
		if(p.offsetWidth>winw*0.75) p.style.width=winw*0.75 + "px";
		if(x+p.offsetWidth>winw-scrollw-1) x=winw-p.offsetWidth-scrollw-1;
		var s=p.style; s.left=x+'px'; s.top=y+'px'; s.display='block';
		if(config.options.chkAnimate && anim)	anim.startAnimating(new Scroller(p));
		else					window.scrollTo(0,ensureVisible(p));
		return cme.ok(ev);
	},
//}}}
// // TYPE-SPECIFIC FORM HANDLING OVERRIDES FOR EditSectionPlugin
//{{{
	getForm: function(tid,type) {
		var cmp=config.macros.pasteUpHelper;
		var cme=config.macros.editSection;
		return cmp.templates[type]||cme.template;
	},
	getInitForm: function(tid,type) {
		var cmp=config.macros.pasteUpHelper;
		var cme=config.macros.editSection;
		return cmp.templates[type]?cmp.initForm:cme.initForm;
	},
	getSaveForm: function(tid,type) {
		var cmp=config.macros.pasteUpHelper;
		var cme=config.macros.editSection;
		return cmp.templates[type]?cmp.saveForm:cme.saveForm;
	},
	initForm: function(elem,form,title,section,type) {
		var cmp=config.macros.pasteUpHelper; // ABBREV
		var tid=title; if (section) tid=[title,section].join('##');
		var txt=store.getTiddlerText(tid,'');
		form.title.value=title;
		form.section.value=section||'';
		form.rawContent.value=txt;
		form.newsection.value=tid;
		form.newsection.nextSibling.innerHTML=tid;

		// EXTRACT IMAGE SRC
		var imgsrc='';
		var pat='/%[.\\s]*?\\r?\\nimage:\\s*\\[img\\(.*,.*\\)\\[(.*)\\]\\]\\r?\\n[.\\s]*?%/';
		var re=new RegExp(pat);	var m=re.exec(txt); txt=txt.replace(re,'');
		if (m) imgsrc=m[1];

		// EXTRACT IMAGE PASTEUP POS/SIZE/ADJUST
		var imgleft=''; var imgtop=''; var imgwidth=''; var imgheight=''; var adjust=false;
		var pat='<<(?:pasteUp|tiddler)\\s+\\[\\[.+::image\\]\\].*?>>';
		var re=new RegExp(pat);	var m=re.exec(txt); txt=txt.replace(re,'');
		if (m) {
			function getXYWH(p) {
				var re=new RegExp(p+'\:([^\\s>]+)'); var ex=re.exec(m[0]); return ex?ex[1]:'';
			}
			imgleft=getXYWH('x');	imgtop=getXYWH('y');
			imgwidth=getXYWH('w');	imgheight=getXYWH('h');
			var adjust=m[0].indexOf(' noadjust')==-1; // 'adjust' CHECKBOX
		}

		// EXTRACT FONTSIZE AND STYLE 
		var size=''; var classname=''; // FIRST CLASSNAME IS FONTSIZE, REST IS STYLENAME
		var pat='<<(?:pasteUp|tiddler)\\s+\\[\\[.+##content\\]\\]\\s+class:"([^"]*)".*?>>';
		var re=new RegExp(pat);	var m=re.exec(txt); txt=txt.replace(re,'');
		if (m) { var t=m[1].split(' '); size=t.shift(); classname=t.join(' '); }

		// EXTRACT CONTENT FROM HIDDEN SECTION (IMAGE BEHIND TEXT)
		var content=txt;
		var pat='/%\\r?\\n!content\\r?\\n((?:.|\\n)*)\\r?\\n!end\\r?\\n%/';
		var re=new RegExp(pat); content=txt.replace(re,'$1');
		if (content==txt) { // FALLBACK: EXTRACT CONTENT FROM CLASS WRAPPER (IMAGE IN FRONT)
			var pat='(.*\\{\\{[^\\{]+\\{\\r?\\n)((?:.|\\n)*)(\\r?\\n\\}\\}\\}.*)';
			var re=new RegExp(pat); content=txt.replace(re,'$2');
			if (content==txt) { // FALLBACK: EXTRACT CONTENT FROM HTML DIV
				var pat='(.*<html><div class="[^"]+">\\r?\\n)((?:.|\\n)*)(\\r?\\n</div></html>.*)';
				var re=new RegExp(pat); content=txt.replace(re,'$2');
			}
		}

		if (form.type) type=form.type.value;
		switch (type) {
			case 'text': // SET TEXT CONTENT
				form.content.value=content;
				if (version.extensions.TextAreaPlugin) new window.TextAreaResizer(form.content);
				break;
			case 'image': // SET IMAGE SRC,X,Y,W,H
				cmp.setList(form.image,cmp.imageList,imgsrc);
				form.imgleft.value	=imgleft;
				form.imgtop.value	=imgtop;
				form.imgwidth.value	=imgwidth;
				form.imgheight.value	=imgheight;
				form.imgadjust.checked	=adjust;
				jQuery('.pasteUpImageAdjust',form).each(
					function(){this.style.display=adjust?'':'none';});
				// SET IMAGE PREVIEW // TBD: BRITTLE DOM REFERENCES
				var td=form.image.parentNode.parentNode;
				var i=td.getElementsByTagName('img')[0];
				if (i) {
					var p=i.parentNode.parentNode;
					var trim=jQuery(form.image.parentNode).height()+2;
					p.style.height=jQuery(td).height()-trim+'px';
					p.style.width=jQuery(td).width()-2+'px';
					cmp.setImagePreview(i,imgsrc,form);
				}
				break;
			case 'place': // SET ELEMENT POSITION/SIZE INPUTS
				var s=elem.style; var a='auto';
				form.left.defaultValue  =form.left.value  =s.left||a;
				form.top.defaultValue   =form.top.value   =s.top||a;
				form.width.defaultValue =form.width.value =s.width||a;
	 			form.height.defaultValue=form.height.value=s.height||a;
	 			form.zindex.defaultValue=form.zindex.value=s.zIndex||a;
				break;
		}
	},
	saveForm: function(here,ev) {	// RETURN CONTENT TO EditSectionPlugin FOR STORAGE
		var cmp=config.macros.pasteUpHelper; // ABBREV
		var cme=config.macros.editSection; // ABBREV
		var f=here.form; var elem=f.panel.root;

		// GET TARGET TITLE/SECTION
		var tid=f.newsection.value;
		var title=tid.split('##')[0];
		var section=tid.split('##')[1];
		var oldsection=f.section.value;
		if (!title) title=story.findContainingTiddler(elem).getAttribute('tiddler');
		if (!title) {
			displayMessage(cme.sectionerr.format([f.newsection.value]));
			f.newsection.focus(); f.newsection.select(); return false;
		}

		// CHECK FOR TIDDLER OVERWRITE
		if (!section && title!=f.title.value && store.tiddlerExists(title)) {
			if (!confirm(config.messages.overwriteWarning.format([title])))
				{ f.newsection.focus(); f.newsection.select(); return cme.ok(ev); }

		}

		// GET NEW TIDDLER/SECTION CONTENT
		var type=f.type?f.type.value:'';
		var txt=f.rawContent.value;
		if (type=='place') { // UPDATE ELEMENT POSITION/SIZE (if changed)
			var left=f.left.value; var top=f.top.value;
			var width=f.width.value; var height=f.height.value;
			var zindex=f.zindex.value;
			var changed=left!=f.left.defaultValue  || top!=f.top.defaultValue
				|| width!=f.width.defaultValue || height!=f.height.defaultValue
				|| zindex!=f.zindex.defaultValue;
			if (changed) config.macros.pasteUp.dragsave(elem,left,top,width,height,zindex);
		} else if (type=='image') {	// UPDATE IMAGE SRC,X,Y,W,H
			txt=cmp.modifyPart(tid,txt,'image',{
				title: f.title.value, src: f.image.value,
				adjust: f.imgadjust.checked, 
				x: f.imgleft.value,  y:f.imgtop.value,
				w: f.imgwidth.value, h:f.imgheight.value });
			cme.updateTiddler(txt,title,section,oldsection);
		} else if (type=='text') {	// UPDATE TEXT
			txt=cmp.modifyPart(tid,txt,'text',f.content.value);
			cme.updateTiddler(txt,title,section,oldsection);
		}
		f.panel.setAttribute('dirty',null); cme.removePanel(f.panel); // CLEAR FLAG AND CLOSE PANEL
		return cme.ok(ev);
	},
	setImagePreview: function(view,src,form) {
		view.src=src;
		view.parentNode.href=view.src;
		view.parentNode.title=src?'CLICK to view \x22'+src+'\x22':'select an image...';
		function setdef(e,def) { e.value=e.value||def; } // SET DEFAULT VALUE (IF BLANK INPUT)
		setdef(form.imgleft,  store.getTiddlerText('PasteUpConfig::ImageLeft',  '0px'));
		setdef(form.imgtop,   store.getTiddlerText('PasteUpConfig::ImageTop',   '0px'));
		setdef(form.imgwidth, store.getTiddlerText('PasteUpConfig::ImageWidth', 'auto'));
		setdef(form.imgheight,store.getTiddlerText('PasteUpConfig::ImageHeight','auto'));
	},
//}}}
// // PART DATA HANDLING
//{{{
	modifyPart: function(tid,txt,mode,val) {
		// DEBUG alert('modifyPart() before=\n'+txt);

		// DETECT HTML or MEDIAWIKI PART (= separate tiddler, tagged with 'html' or 'mediawiki')
		var t=store.getTiddler(tid);
		var isHTML=t && t.isTagged('html')||t.isTagged('mediawiki');

		var contentRE	// CONTENT IN EMBEDDED HIDDEN SECTION
			=/(.*\!content\r?\n)(.*)(\r?\n!end.*)/;
		var classRE	// FONTSIZE, STYLE IN EMBED
			=/(<<(?:pasteUp|tiddler)\s+\[\[.+##content\]\]\s+class:")([^"]*)(".*?>>)/;

		var wrapperRE	// FONTSIZE, STYLE, AND CONTENT IN CLASS WRAPPER
			=/(.*)(\{\{)([^\{]+)(\{\r?\n)((?:.|\r?\n)*)(\r?\n\}\}\})(.*)/;
		var wrapperOut
			='{{%0 %1{\n%2\n}}}';

		var divRE	// FONTSIZE, STYLE, AND CONTENT IN HTML DIV
			=/(.*)(<html><div class=")([^"]+)(">\r?\n)((?:.|\r?\n)*)(\r?\n<\/div><\/html>)(.*)/;
		var divOut
			='<html><div class="%0 %1">\n%2\n</div></html>';

		var imageRE	// IMAGE
			=/(<<(?:pasteUp|tiddler).*?>>\/%[.\s]*?\r?\nimage:\s*\[img\(.*,.*\)\[)(.*)(\]\]\r?\n[.\s]*?%\/)/;
		var imageOut	// IMAGE OUTPUT FORMAT (for new images)
			='<<pasteUp [[%0::image]] noedit%6 x:%2 y:%3 w:%4 h:%5>>/%\nimage: [img(100%,100%)[%1]]\n%/';


		switch(mode) {
		case "text":
			var m=contentRE.exec(txt); // CONTENT IN SECTION
			if (m) txt=txt.replace(contentRE,'$1'+val+'$3');
			else { // FALLBACK: CONTENT IN WRAPPER
				var m=imageRE.exec(txt); var i=(m?m[0]:'');	// GET IMAGE SYNTAX
				txt=txt.replace(imageRE,'');			// REMOVE IMAGE SYNTAX
				var m=wrapperRE.exec(txt);
				if (m) txt=txt.replace(wrapperRE,'$1$2$3$4'+val+'$6$7');
				else { // FALLBACK: CONTENT IN HTML DIV
					var m=divRE.exec(txt);
					if (m) txt=txt.replace(divRE,'$1$2$3$4'+val+'$6$7');
					else txt=val;	// FALLBACK: NO DIV, NO WRAPPER, NO SECTION
				}
				txt=i+txt;	// RESTORE IMAGE SYNTAX (if any)
			}
			break;
		case "image":
			var cfg='PasteUpConfig::'; // abbrev
			var x=val.x||store.getTiddlerText(cfg+'ImageLeft',  '0px');
			var y=val.y||store.getTiddlerText(cfg+'ImageTop',   '0px');
			var w=val.w||store.getTiddlerText(cfg+'ImageWidth', '100%');
			var h=val.h||store.getTiddlerText(cfg+'ImageHeight','auto');
			var m=imageRE.exec(txt);
			if (!m && val.src.length) {				// ADD IMAGE SYNTAX
				var noadjust=store.getTiddlerText(cfg+'ImageAdjust','')!='true';
				var i=imageOut.format([val.title,val.src,x,y,w,h,noadjust?' noadjust':'']);
				txt=i+txt;
			} else if (m && !val.src.length) {			// REMOVE IMAGE SYNTAX
				txt=txt.replace(imageRE,'');
			} else if (m && val.src.length) {			// REVISE IMAGE SYNTAX
				var i=m[1]+val.src+m[3];			//  CHANGE IMAGE SRC
				i=i.replace(/\s+[xywh]\:[^\s>]*/g,'');		//  REMOVE OLD xywh PARAMS
				// INSERT NEW xywh PARAMS
				i=i.replace(/>>/,' x:%0 y:%1 w:%2 h:%3>>'.format([x,y,w,h]));
				// REMOVE OLD noadjust AND ADD NEW noadjust (if 'adjust' not checked)
				i=i.replace(/ noedit noadjust/,' noedit');
				if (!val.adjust) i=i.replace(/ noedit/,' noedit noadjust');
				txt=txt.replace(imageRE,i); // UPDATE IMAGE SYNTAX
			}
			break;
		case "style":
		case "size":
			var m=imageRE.exec(txt); var i=(m?m[0]:'');	// GET IMAGE SYNTAX (if any)
			txt=txt.replace(imageRE,'');			// REMOVE IMAGE SYNTAX
			var s=''; var c='';
			var m=classRE.exec(txt); if (m) {
				var t=m[2].split(' '); s=t.shift(); c=t.join(' ');
				if (mode=='size') s=val; if (mode=='style') c=val;
				txt=txt.replace(classRE,'$1'+s+' '+c+'$3');
			} else { // FALLBACK: GET FONTSIZE/STYLE from CSS WRAPPER or HTML DIV (if any)
				var re=wrapperRE; m=re.exec(txt); if (!m) { re=divRE; m=re.exec(txt); }
				if (m) { var t=m[3].split(' '); var s=t.shift(); var c=t.join(' '); }
				if (mode=='size') s=val; if (mode=='style') c=val;
				if (s||c) {
					if (m)	txt=txt.replace(re,'$1$2'+s+' '+c+'$4$5$6$7'); // UPDATE
					else	txt=(isHTML?divOut:wrapperOut).format([s,c,txt]); // ADD
				} else {
					if (m)	txt=txt.replace(re,'$1$5$7'); // REMOVE
					else	txt=txt; // NO CHANGE!
				}
			}
			txt=i+txt;	// RESTORE IMAGE SYNTAX (if any)
			break;
		}
		// DEBUG alert('modifyPart() after=\n'+txt);
		return txt;
	}
}
//}}}
/***
!!!Form definitions for PasteUpHelper popup editor.
>note: modify shadow tiddlers to customize and/or translate forms
''Edit Text''
//{{{
!PasteUpHelperTemplate_Text
<!--{{{-->
<!--
|Name|PasteUpHelperTemplate_Text|
|Source|http://www.TiddlyTools.com/#PasteUpHelperPlugin|
|Version||
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|Type|template|
|Requires|EditSectionPlugin, PasteUpPlugin|
|Description|enhanced popup editor template used by PasteUpHelperPlugin|
-->
<form action="javascript:;" autocomplete="off" style="white-space:nowrap">
<input type="hidden" name="type" value="text"><!--REQUIRED-->
<input type="hidden" name="title" value=""><!--REQUIRED-->
<input type="hidden" name="section" value=""><!--REQUIRED-->
<input type="hidden" name="rawContent" value=""><!--REQUIRED-->
<!-- HEADING/BUTTONS -->
<table style="padding:0;margin:0;border:0;border-collapse:collapse;width:100%;"><tr><td>
	<div style="font-size:80%;font-style:italic">edit text for:</div>
	<input type="hidden" name="newsection" value="" style="width:98%;margin:0;padding:0;border:0;background:none;" disabled><span></span>
</td><td style="text-align:right;">
	<input type="button" style="width:5em;" value="ok"	onclick="return this.form.save(this,event)">
	<input type="button" style="width:5em;" value="cancel"	onclick="return config.macros.editSection.cancel(this,event)">
</td></tr></table><hr>
<!-- CONTROLS -->
<div macro="tiddler QuickEditToolbar"></div>
<textarea name="content" rows="10" cols="80" style="width:98%"
	onchange="return config.macros.editSection.changed(this,event)"></textarea>
</div></form>
<!--}}}-->
!end
//}}}

''Select Image''
//{{{
!PasteUpHelperTemplate_Image
<!--{{{-->
<!--
|Name|PasteUpHelperTemplate_Image|
|Source|http://www.TiddlyTools.com/#PasteUpHelperPlugin|
|Version||
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|Type|template|
|Requires|EditSectionPlugin, PasteUpPlugin|
|Description|enhanced popup editor template used by PasteUpHelperPlugin|
-->
<form action="javascript:;" autocomplete="off" style="white-space:nowrap">
<input type="hidden" name="type" value="image"><!--REQUIRED-->
<input type="hidden" name="title" value=""><!--REQUIRED-->
<input type="hidden" name="section" value=""><!--REQUIRED-->
<input type="hidden" name="rawContent" value=""><!--REQUIRED-->
<!-- HEADING/BUTTONS -->
<table style="padding:0;margin:0;border:0;border-collapse:collapse;width:100%;"><tr><td>
	<div style="font-size:80%;font-style:italic">select image for:</div>
	<input type="hidden" name="newsection" value="" style="width:98%;margin:0;padding:0;border:0;background:none;" disabled><span></span>
</td><td style="text-align:right;">
	<input type="button" style="width:5em;" value="ok"	onclick="return this.form.save(this,event)">
	<input type="button" style="width:5em;" value="cancel"	onclick="return config.macros.editSection.cancel(this,event)">
</td></tr></table><hr>
<!-- CONTROLS -->
<table style="border-collapse:collapse;width:100%;"><tr valign="top"><td xstyle="width:80%">
	<div>
	<select name="image" size="1" style="width:60%;" onchange="
		if (this.value=='_edit') return false;
		var i=this.parentNode.parentNode.getElementsByTagName('img')[0]
		config.macros.pasteUpHelper.setImagePreview(i,this.value,this.form);
		return config.macros.editSection.changed(this,event);
	"><option value="">select an image...</option>
	</select><input type="button" style="width:20%" value="select" onclick="
		return config.macros.pasteUpHelper.imagePopup(event,this.form.image);
	"><input type="button" style="width:20%" value="add" onclick="
		return config.macros.pasteUpHelper.addImagePanel(event,this.form.image);
	"><br>
	</div>
	<div style="border:1px solid gray;background-color:#ccc;overflow:hidden;min-height:85px;">
		<center><a href="" target="_blank" onclick="
			if (this.href==document.location) { // no image
				var td=this.parentNode.parentNode.parentNode;
				td.getElementsByTagName('select')[0].focus();
				return false;
			}
		"><img src="" style="height:100%;margin:0;padding:0;display:block;">
		</a></center>
	</div>
	<input name='imgadjust' type="checkbox" onclick="
		var vis=this.checked?'':'none';
		jQuery('.pasteUpImageAdjust',this.form).each(function(){this.style.display=vis;});
	">adjustable&nbsp;
</td><td class="pasteUpImageAdjust" style="display:none;padding-top:3px;">
	x-offset<br><input type="text" name="imgleft" style="width:5em"
		onchange="return config.macros.editSection.changed(this,event);"><br>
	y-offset<br><input type="text" name="imgtop" style="width:5em"
		onchange="return config.macros.editSection.changed(this,event);"><br>
	width<br><input type="text" name="imgwidth" style="width:5em"
		onchange="return config.macros.editSection.changed(this,event);"><br>
	height<br><input type="text" name="imgheight" style="width:5em"
		onchange="return config.macros.editSection.changed(this,event);"><br>
</td></tr></table>
</div></form>
<!--}}}-->
!end
//}}}

''Add Image''
//{{{
!PasteUpHelperTemplate_AddImage
<!--{{{-->
<!--
|Name|PasteUpHelperTemplate_AddImage|
|Source|http://www.TiddlyTools.com/#PasteUpHelperPlugin|
|Version|1.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|Type|template|
|Requires|EditSectionPlugin, PasteUpPlugin|
|Description|enhanced popup editor template used by PasteUpHelperPlugin|
-->
<form action="" target="_serverresponse" method="post" enctype="multipart/form-data"
	autocomplete="off" style="white-space:nowrap" class="smallform">
<!-- HEADING/BUTTONS -->
<table style="padding:0;margin:0;border:0;border-collapse:collapse;width:100%;"><tr><td>
	<div style="font-size:80%;font-style:italic">add a new image to:</div>
	<input type="hidden" name="targetlist" value="PasteUpImageList" style="width:98%;margin:0;padding:0;border:0;background:none;" disabled><span></span>
</td><td style="text-align:right;">
	<input type="button" name="add" value="ok" style="width:5em;"
		title="add item to image list" onclick="
		var cmp=config.macros.pasteUpHelper; // ABBREV
		var f=this.form; // ABBREV
		var tid=f.targetlist.value;
		var t=store.getTiddlerText(tid,'');
		var label=f.label.value;
		if (!label.length || label==f.label.defaultValue) {
			alert('Please enter a name for this image');
			f.label.focus(); f.label.select();
			return false;
		}
		if (label.length && t.indexOf(label+'=')!=-1) {
			alert('\x22'+label+'\x22 is already in use.\nPlease enter a different name.');
			f.label.focus(); f.label.select();
			return false;
		}
		var url=f.url.value;
		if (!url.length) {
			alert('Please enter an image location or upload an image file');
			f.url.focus();
			return false;
		}
		var item='\n'+(label.length?label+'=':'')+url;
		var who=config.options.txtUserName; var when=new Date();
		if (config.options.chkForceMinorUpdate) { who=t.modifier||who; when=t.modified||when; }
		store.saveTiddler(tid,tid,t+item,who,when,t.tags,
			config.macros.pasteUp.cloneFields(t.fields));
		displayMessage('New image added to '+tid);
		autoSaveChanges();
		cmp.setList(f.panel.root,cmp.imageList,url);
		f.panel.root.onchange(event);
		f.panel.root.focus();
		f.panel.parentNode.removeChild(f.panel);
		return false;
	">
	<input type="button" name="cancel" value="cancel" style="width:5em;" onclick="
		this.form.panel.root.focus();
		this.form.panel.parentNode.removeChild(this.form.panel);
		return false;
	">
</td></tr></table><hr>
<!-- CONTROLS -->
<div>
<input type="hidden" name="uploadpath" value=""><!-- REQUIRED -->
<input type="hidden" name="csrf_token" value=""><!-- REQUIRED (TIDDLYSPACE) -->
enter a new image name/location:<br>
<input type="text" name="label" size="15" value="name (for listbox)">
<input type="text" name="url" size="33" value="URL or path/filename" onchange="var f=this.form;
	if (this.value==this.defaultValue) return false; // ignore
	if (!f.label.value || f.label.value==f.label.defaultValue) {
		var slash='/'; if (this.value.indexOf('\\')!=-1) slash='\\';
		var parts=this.value.split(slash); var filename=parts[parts.length-1];
		f.label.value=filename.split('.')[0];
	}
"><br>
or, upload a local image file to this workspace:<br>
<input type="hidden" name="filename" value="">
<input type="file" name="file" size="30" onchange=" var f=this.form;
	var slash='/'; if (this.value.indexOf('\\')!=-1) slash='\\';
	var parts=this.value.split(slash); var filename=parts[parts.length-1];
	if (!f.label.value || f.label.value==f.label.defaultValue)
		f.label.value=filename.split('.')[0];
	f.filename.value=filename.replace(/[^A-Za-z0-9\_\-\.]/g,'_');;
	f.url.value=f.uploadpath.value+f.filename.value;
	f.url.onchange();
	if (confirm('Start uploading now?')) f.upload.click();
">
<input type="button" name="upload" value="upload" style="display:inline"
	title="upload file to remote host" onclick="
	this.parentNode.nextSibling.style.display='inline';
	this.form.submit();
	this.form.add.focus();
	return false;
"><br>
</div><div style="display:none">
<a href="javascript:;" style="float:right" onclick="
	this.parentNode.style.display='none'; return false;
">hide</a>server response:<br>
<iframe name="_serverresponse" id="_serverresponse" style="width:100%;height:10em;background:white"></iframe>
</div>
</form>
<!--}}}-->
!end
//}}}

''Place Part''
//{{{
!PasteUpHelperTemplate_Placement
<!--{{{-->
<!--
|Name|PasteUpHelperTemplate_Placement|
|Source|http://www.TiddlyTools.com/#PasteUpHelperPlugin|
|Version||
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|Type|template|
|Requires|EditSectionPlugin, PasteUpPlugin|
|Description|enhanced popup editor template used by PasteUpHelperPlugin|
-->
<form action="javascript:;" autocomplete="off" style="white-space:nowrap">
<input type="hidden" name="type" value="place"><!--REQUIRED-->
<input type="hidden" name="title" value=""><!--REQUIRED-->
<input type="hidden" name="section" value=""><!--REQUIRED-->
<input type="hidden" name="rawContent" value=""><!--REQUIRED-->
<!-- HEADING/BUTTONS -->
<table style="padding:0;margin:0;border:0;border-collapse:collapse;width:100%;"><tr><td>
	<div style="font-size:80%;font-style:italic">set position/size/layer for:</div>
	<input type="hidden" name="newsection" value="" style="width:98%;margin:0;padding:0;border:0;background:none;" disabled><span></span>
</td><td style="text-align:right;">
	<input type="button" style="width:5em;" value="ok"	onclick="return this.form.save(this,event)">
	<input type="button" style="width:5em;" value="cancel"	onclick="return config.macros.editSection.cancel(this,event)">
</td></tr></table><hr>
<!-- CONTROLS -->
<table style="border-collapse:collapse;padding:0;margin:0;border:0;width:100%;"><tr style="vertical-align:bottom"><td style="width:20%">
	left (x)<br>
	<input type="text" name="left" value="x" style="width:7em;margin:0;"
		onchange="return config.macros.editSection.changed(this,event);">
</td><td style="width:20%">
	top (y)<br>
	<input type="text" name="top" value="y" style="width:7em;margin:0;"
		onchange="return config.macros.editSection.changed(this,event);">
</td><td style="width:20%">
	width<br>
	<input type="text" name="width" value="w" style="width:7em;margin:0;"
		onchange="return config.macros.editSection.changed(this,event);">
</td><td style="width:20%">
	height<br>
	<input type="text" name="height" value="h" style="width:7em;margin:0;"
		onchange="return config.macros.editSection.changed(this,event);">
</td><td style="width:20%">
	layer (z-index)<br>
	<input type="text" name="zindex" value="z" style="width:7em;margin:0;"
		onchange="return config.macros.editSection.changed(this,event);">
</td></tr></table>
</form>
<!--}}}-->
!end
//}}}

Default/example CSS for user-defined pasteup styles
^^note: modify [[PasteUpStyleSheet]], [[PasteUpStyleList]] and/or [[PasteUpFontList]] to customize.^^
//{{{
!css
.bigger
	{ font-size:200%; line-height:100%; }
.biggest
	{ font-size:300%; line-height:100%; }
.headline
	{ text-align:center; font-weight:bold; }
.border
	{ border:1px solid; }
!end
//}}}
***/
 
(no image)=
eric=images/eric3.gif
meow=images/meow.gif
meow2=images/meow2.jpg
/***
|Name|[[PasteUpPlugin]]|
|Source|http://www.TiddlyTools.com/#PasteUpPlugin|
|Version|1.3.2|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.5|
|Type|plugin|
|~SeeAlso|[[EditSectionPlugin]] [[PasteUpHelperPlugin]]|
|Description|position/size embedded content with edit-in-place popup editor|
!!!Documentation
> see [[PasteUpPluginInfo]]
!!!Example/Test
<<<
{{{<<tiddler PasteUpPlugin##test style:"border:1px solid blue;color:black;background:white;" edit adjust x:115px y:18px w:190px h:75px>>}}}
<<tiddler PasteUpPlugin##test style:"border:1px solid blue;color:black;background:white;" edit adjust x:115px y:18px w:190px h:75px>>/%
!test
test this content
line 2
line 3
line 4
!end
%/
<<<
!!!Configuration
<<<
<<option chkPasteUpConfirmRemove>>ask for confirmation before removing a part from a page
{{{<<option chkPasteUpConfirmRemove>>}}}
<<option chkPasteUpBoundaryWarning>>warn when an element is moved/sized outside it's container
{{{<<option chkPasteUpBoundaryWarning>>}}}
<<option chkPasteUpEditAll>>automatically enable editing for all embedded content (unless ''noedit'' is used)
{{{<<option chkPasteUpEditAll>>}}}

Also see:
*[[PasteUpConfig]] and related shadows:
**[[DefaultPage]], [[DefaultPart]], [[PasteUpStyleSheet]]
*[[EditSectionPlugin]] (optional, recommended) and related shadows:
**[[EditSectionTemplate]]
*[[PasteUpHelperPlugin]] (optional, recommended) and related shadows:
**[[PasteUpHelperTemplate]], [[PasteUpStyleList]], [[PasteUpFontList]], [[PasteUpImageList]]
<<<
!!!Revisions
<<<
2012.01.29 1.3.2 invoke autoSaveChanges() whenver tiddlers are modified.  Also, when moving a part, calls to displayMessage() to show current position now uses 'noLog' flag (see [[MessageLogPlugin]])
2012.01.08 1.3.1 re-factored clickAction()/dblClickAction() for easier customization and fallback handling when EditSectionPlugin is not installed
2011.12.27 1.3.0 in dragSave(), addPart() and removePart(), handle {{{[[partnames with spaces]]}}} when generating/matching embedded part syntax
2011.09.15 1.2.9 in dragSave(), fixed called to story.refreshTiddler(title...)
2011.09.06 1.2.8 in removePart(), added 'force' param (for use by PasteUpHelperPlugin)
2011.09.04 1.2.7 in dragSave(), support setting of non-default z-Index (default index is "1")
2011.09.03 1.2.6 in setCursor() and isStretch(), only resize if inside pasteup element (i.e, not within an overflow child element)
2011.08.05 1.2.5 in addPasteUpPart(), use "window.readOnly" for IE compatibility
2011.08.02 1.2.4 refactored click() handler and added clickAction(). Moved createMenu() and renderMenu() to [[PasteUpHelperPlugin]]
2011.08.02 1.2.3 in click(), check for existing popup and close it instead (i.e., 'toggle popup display')
2011.08.01 1.2.2 refactored form handling (see [[EditSectionPlugin]]) to support type-specific forms by [[PasteUpHelperPlugin]]
2011.07.23 1.2.1 added chkPasteUpNoMenuLink option and misc code cleanup
2011.07.23 1.2.0 Use edge/corner detect for resize.  Added popup menu.  Cleanup cursor handling.  Fix getMX/getMY for Safari/Webkit
2011.06.19 1.1.3 internal CSS shadow renamed to PasteUpPluginStyles
2011.06.13 1.1.2 in mousedown(), use removeAllPanels instead of Popup.remove
2011.06.10 1.1.1 in dragsave(), skip 'outofbounds' check if message text is blank
2011.06.08 1.1.0 added removePart() handler
2011.06.05 1.0.14 added TiddlySpace cloneFields() to save handlers so editing content automatically copies/owns an included tiddler
2011.05.17 1.0.13 in dragsave(), don't check for out of bounds if container is a pasteUp part itself
2011.05.05 1.0.12 in dragsave(), added custom undo messages (requires UndoPlugin)
2011.05.01 1.0.11 in dragsave(), added "out of bounds" confirmation
2011.02.23 1.0.10 mousetracking: in capture(), invoke release() first (fix for Chrome 'sticky drag' problem?)
2011.02.08 1.0.9 when saving new tiddlers, use config.defaultCustomFields for TiddlySpace compatibility
2011.01.30 1.0.8 in addPart(), retain existing tags when adding part to current tiddler
2011.01.12 1.0.7 in handler(), make sure tiddler element was actually rendered
| Please see [[PasteUpPluginInfo]] for previous revision details |
2010.07.21 0.7.5 alpha prototype (for review - do not distribute)
<<<
!!!Code
***/
// // PLUGIN VERSION
//{{{
version.extensions.PasteUpPlugin= {major: 1, minor: 3, revision: 2, date: new Date(2012,1,29)};
//}}}
// // OPTIONS
//{{{
if (config.options.chkPasteUpEditAll===undefined)		config.options.chkPasteUpEditAll=false;
if (config.options.chkPasteUpConfirmRemove===undefined)		config.options.chkPasteUpConfirmRemove=true;
if (config.options.chkPasteUpBoundaryWarning===undefined)	config.options.chkPasteUpBoundaryWarning=false;

//}}}
// // MACRO DEFINITION
//{{{
config.macros.pasteUp = {
	editMenuTxt:	'edit part...',
	editMenuTip:	'Edit the content for this part',
	removeMenuTxt:	'remove part...',
	removeMenuTip:	'Remove this part from the current page',
	outofboundsmsg: 'Item is outside the visible area of the layout.  Press OK to allow.',
	confirmremovemsg: 'Are you sure you want to remove part "%0" from page "%1"?',
	edgeDetect:	10,	// PIXELS FOR CORNER/BORDER DETECT
	quiet:		false,	// TRUE = SHOW POS/SIZE DURING DRAG
	debug:		false,	// TRUE = SHOW POS/SIZE AFTER DRAG
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		var cmp=config.macros.pasteUp; // abbrev

		// UNPACK PARAMS
		var edit=params.contains('edit')||macroName=='pasteUp'||config.options.chkPasteUpEditAll;
		var noedit=params.contains('noedit');
		var adjust=params.contains('adjust')||macroName=='pasteUp';
		var noadjust=params.contains('noadjust');
		var nopopup=params.contains('nopopup');
		var p=paramString.parseParams('name',null,true,false,true);
		var style=getParam(p,'style');
		var CSSclass=getParam(p,'class');
		var x=getParam(p,'x');
		var y=getParam(p,'y');
		var z=getParam(p,'z');
		var w=getParam(p,'w');
		var h=getParam(p,'h');

		// FIXUP for '##section' references (use current tiddler, if any)
		var sep='##'; var parts=params[0].split(sep);
		var tid=parts[0]; var sec=parts[1];
		var pasteupParams=paramString; // save unmodified params
		if (!tid && sec) {
			var here=story.findContainingTiddler(place)
			var tid=here?here.getAttribute('tiddler'):tiddler?tiddler.title:'';
			arguments[2][0]=tid+sep+sec;
			arguments[4]=paramString.replace(new RegExp(sep+sec),tid+sep+sec);
		}

		// RENDER CONTENT (CORE HANDLER) and GET RESULTING OBJECTS
		cmp.core_handler.apply(config.macros.tiddler,arguments);
		var e=place.lastChild; // rendered tiddler element
		if (!e || !e.getAttribute) return; // element not rendered!
		var t=e.getAttribute('tiddler'); // source title
		if (!t) return; // not a tiddler element!
		var s=e.style; // CSS styles
		e.setAttribute('tid',t); // needed by EditSectionPlugin

		// SET optional CUSTOM CLASS, STYLES, and/or DIRECT POS/SIZE
		if (CSSclass) addClass(e,CSSclass);
		if (style) {
			var parts=style.split(';');
			for (var i=0; i<parts.length; i++) {
				var name=(parts[i].split(':')[0]||'').trim();
				var val =(parts[i].split(':')[1]||'').trim();
				if (name.length && val.length) jQuery(e).css(name,val);
			}
		}
		s.left=x||s.left; s.top=y||s.top; s.zIndex=z||s.zIndex||1;
		s.width=w||s.width; s.height=h||s.height;

		// PASTEUP or NON-DEFAULT POSITION
		function def(e,a) { return (['auto','0px',''].contains(jQuery(e).css(a))); }
		if (macroName=='pasteUp' || !def(e,'left') || !def(e,'top')) {
			e.style.position='absolute'; // ALLOW ELEMENT TO BE POSITIONED
			if (e.parentNode.style.position!='absolute') // FIXUP PARENT FOR RELATIVE OFFSETS
				e.parentNode.style.position='relative';
		}

		// PASTEUP = ALLOW EDIT/ADJUST BY DEFAULT
		if (macroName=='pasteUp') { edit=true; adjust=true; }

		e.editable=edit&&!noedit;
		e.adjustable=adjust&&!noadjust;
		if (readOnly) return; // READONLY = DONE

		// TOOLTIP, CURSOR DEFAULT CONTENT, OUTLINE on hover, add PASTEUP CLASS
		if (e.editable||e.adjustable) {
			e.title=cmp.tooltip(e);				// TOOLTIP = source name
			e.style.cursor='pointer';			// DEFAULT CURSOR = pointer
			if (e.innerHTML=='') wikify('[['+t+']]',e);	// DEFAULT CONTENT = [[source]]
			e.onmouseover=cmp.mouseover;			// SHOW OUTLINE
			e.onmousemove=cmp.mousemove;			// SET CURSOR
			e.onmouseout =cmp.mouseout;			// HIDE OUTLINE
			addClass(e,'pasteUp');
		}

		// EDITABLE = CLICK/DOUBLE-CLICK
		e.helptext='';
		if (e.editable) {
			e.nopopup=nopopup||!config.macros.editSection;
			e.onclick    =cmp.click;
			e.ondblclick =cmp.dblclick;
			if (config.options.chkPasteUpHelper) // PasteUpHelperPlugin
				e.helptext+=', CLICK=menu, SHIFT-CLICK=edit';
			else // EditSectionPlugin (w/o helper) or standard tiddler editor
				e.helptext+=', CLICK=edit';
		}

		// ADJUSTABLE = DRAG/SHIFT-DRAG
		if (e.adjustable) {
			e.pasteupParams=pasteupParams; // used in dragsave() to find matching macro
			e.onmousedown=cmp.mousedown;	// DRAG = MOVE/STRETCH
			e.helptext+=', DRAG=move, LOWER-RIGHT CORNER or SHIFT-DRAG=resize';
		}
		e.title+=e.helptext;
	},
//}}}
// // GENERAL UTILITIES
//{{{
	tooltip: function(e) { // tooltip for embedded elements shows source name
		return e.getAttribute('tiddler'); // source title
	},
	getCSS: function(e,px,css) { // CONVERT element px values into CSS units
		var u=css.replace(/[0-9\.-]*/,''); if (u=='auto'||u=='') u='px'; // get CSS units
		var t=createTiddlyElement(e.parentNode,'div');
		t.style.width='1'+u;
		var r=Math.round(px/t.offsetWidth*10)/10; // round to one decimal place
		t.parentNode.removeChild(t);
		return r+u;
	},
	getMX: function(ev) { ev=ev||window.event; // GET MOUSE X
		if (config.browser.isIE)	return ev.clientX+findScrollX();// IE
		if (config.browser.isSafari) 	return ev.pageX+findScrollX(); 	// Webkit
		else				return ev.pageX;		// Firefox/other
	},
	getMY: function(ev) { ev=ev||window.event; // GET MOUSE Y
		if (config.browser.isIE)	return ev.clientY+findScrollY();// IE
		if (config.browser.isSafari) 	return ev.pageY+findScrollY();	// Webkit
		else				return ev.pageY;		// Firefox/other
	},
	ok: function(ev) { ev=ev||window.event; // HANDLE EVENT
		ev.cancelBubble=true; if(ev.stopPropagation) ev.stopPropagation(); return false;
	},
	getTrack: function(here) { // GET DRAG ELEMENT
		var track=here; // if 'capture' not supported, track in element only
		if (document.body.setCapture) var track=document.body; // IE
		if (window.captureEvents) var track=window; // moz
		return track;
	},
	capture: function () { // CAPTURE MOUSE
		this.release(); // make sure we aren't already tracking
		if (document.body.setCapture) document.body.setCapture(); // IE
		if (window.captureEvents) window.captureEvents(Event.MouseMove|Event.MouseUp,true); // moz
	},
	release: function () { // RELEASE MOUSE
		if (document.body.releaseCapture) document.body.releaseCapture(); // IE
		if (window.releaseEvents) window.releaseEvents(Event.MouseMove|Event.MouseUp); // moz
	},
	setCursor: function(here,ev) { ev=ev||window.event; // SET CURSOR FOR ELEMENT
		var x=this.getMX(ev); var y=this.getMY(ev);
		var left=findPosX(here); var top=findPosY(here);
		var width=here.offsetWidth; var height=here.offsetHeight; var size=this.edgeDetect;
		var isB=(top+height-y>0 && top+height-y<size);
		var isR=(left+width-x>0 && left+width-x<size);
		var c=((isB&&isR)||ev.shiftKey)?'se-resize':isB?'s-resize':isR?'e-resize':'pointer';
		here.style.cursor=c;
	},
	isStretch: function(here,ev) { ev=ev||window.event; // LOWER-RIGHT CORNER FOR STRETCH
		var x=this.getMX(ev); var y=this.getMY(ev);
		var left=findPosX(here); var top=findPosY(here);
		var width=here.offsetWidth; var height=here.offsetHeight; var size=this.edgeDetect;
		var isB=(top+height-y>0 && top+height-y<size);
		var isR=(left+width-x>0 && left+width-x<size);
		return isB||isR||ev.shiftKey;
	},
//}}}
// // MOUSE HANDLERS (click/dblclick,mouseover/mousemove/mouseout)
//{{{
	click: function(ev) { ev=ev||window.event;
		var cmp=config.macros.pasteUp; // abbrev
		cmp.release(); // stop tracking mousemove
		if (Popup.stack.length) { Popup.remove(); return cmp.ok(ev); } // close popup (if any)
		if (!this.changed) cmp.clickAction(this,ev); // ignore click if after move/stretch
		this.changed=false;
		return cmp.ok(ev);
	},
	clickAction: function(here,ev) { // EDIT IN POPUP (use EditSectionPlugin)
		if (here.nopopup || ev.shiftKey) 
			config.macros.pasteUp.dblClickAction(here,ev); // FALLBACK TO NORMAL EDIT
		else
			config.macros.editSection.click.call(here,ev,'all');
	},
	dblclick: function(ev) { ev=ev||window.event;
		var cmp=config.macros.pasteUp; // abbrev
		cmp.dblClickAction(this,ev);
		return cmp.ok(ev);
	},
	dblClickAction: function(here,ev) { // EDIT IN TIDDLER (normal edit)
		var t=here.getAttribute('tiddler').split('##')[0];
		story.displayTiddler(story.findContainingTiddler(this),t,DEFAULT_EDIT_TEMPLATE);
	},
	mouseover: function(ev) { ev=ev||window.event; // SHOW OUTLINE
		addClass(this,'pasteUpBorder');
		return config.macros.pasteUp.ok(ev);
	},
	mousemove: function(ev) { ev=ev||window.event; // SET CURSOR
		config.macros.pasteUp.setCursor(this,ev);
		return true; // NOTE: ALLOW EVENT TO BUBBLE
	},
	mouseout: function(ev) { ev=ev||window.event; // HIDE OUTLINE
		removeClass(this,'pasteUpBorder');
		return config.macros.pasteUp.ok(ev);
	},
//}}}
// // MOUSE DRAG HANDLERS (down,move,up,keyup)
//{{{
	mousedown: function(ev) { ev=ev||window.event; // MOVE/STRETCH
		var cmp=config.macros.pasteUp; // abbrev

		// if popup is showing, close popup and ignore click 
		if (jQuery('.editSectionPanel').length)
			{ config.macros.editSection.removeAllPanels(); return cmp.ok(ev); }

		// ADD DRAG HANDLERS
		var track=cmp.getTrack(this);
		if (!track.save_onmousemove) track.save_onmousemove=track.onmousemove;
		if (!track.save_onkeyup)     track.save_onkeyup    =track.onkeyup;
		if (!track.save_onmouseup)   track.save_onmouseup  =track.onmouseup;
		track.onmousemove=cmp.dragmove;
		track.onkeyup  =cmp.dragkeyup;
		track.onmouseup=cmp.dragup;

		if (this.parentNode.style.position!='absolute') // fixup parent so OFFSETS ARE RELATIVE
			this.parentNode.style.position='relative';

		// INITIAL STATE
		this.changed=false;		// set true when moved/stretched
		track.elem=this;		// tiddler element
		track.stretch=cmp.isStretch(this,ev);
		track.start={
			X: cmp.getMX(ev),	// mouse position
			Y: cmp.getMY(ev),
			T: this.offsetTop,	// element position/size (pixels)
			L: this.offsetLeft,
			W: jQuery(this).width(),
			H: jQuery(this).height(),
			css: {			// original element css values
				T: this.style.top,
				L: this.style.left,
				W: this.style.width,
				H: this.style.height
			}
		}
		return cmp.ok(ev);
	},
	dragmove: function(ev) { ev=ev||window.event; // DRAG: MOVE/STRETCH
		var cmp=config.macros.pasteUp; // abbrev
		cmp.capture(); // capture mouse events during drag
		var e=this.elem; var s=e.style;
		var dX=cmp.getMX(ev)-this.start.X;
		var dY=cmp.getMY(ev)-this.start.Y;
		e.changed=e.changed||(Math.abs(dX)>1)||(Math.abs(dY)>1); // MINIMUM 2px MOVEMENT
		if (!e.changed) return cmp.ok(ev);
		e.style.position='absolute'; // ensure element is MOVEABLE
		if (this.stretch||ev.shiftKey) { // resize
			s.width =cmp.getCSS(e,this.start.W+dX,this.start.css.W);
			s.height=cmp.getCSS(e,this.start.H+dY,this.start.css.H);
		} else { // move
			s.top =cmp.getCSS(e,this.start.T+dY,this.start.css.T);
			s.left=cmp.getCSS(e,this.start.L+dX,this.start.css.L);
		}
		if (!cmp.quiet) {
			var a='auto';
			var msg='[[%0]] x:%1 y:%2 w:%3 h:%4'.format(
				[e.getAttribute('tiddler'),s.left||a,s.top||a,s.width||a,s.height||a]);
			clearMessage(); displayMessage(msg,null,true);
		}
		return cmp.ok(ev);
	},
	dragkeyup: function(ev) { ev=ev||window.event; // DRAG: CANCEL (ESC key)
		var cmp=config.macros.pasteUp; // abbrev
		cmp.setCursor(this.elem,ev);
		if (ev.keyCode==27) {
			cmp.dragcancel(this.elem);
			return this.onmouseup(ev);
		}
		return cmp.ok(ev);
	},
	dragup: function(ev) { ev=ev||window.event; // DRAG: END
		var cmp=config.macros.pasteUp; // abbrev
		cmp.release(); // stop tracking mouse
		this.onmousemove=this.save_onmousemove;
		this.onkeyup    =this.save_onkeyup;
		this.onmouseup  =this.save_onmouseup;
		clearMessage();
		var e=this.elem; var s=e.style;
		cmp.setCursor(e,ev);
		if (e.changed) cmp.dragsave(e,s.left,s.top,s.width,s.height,s.zIndex);
		return cmp.ok(ev);
	},
	dragcancel: function(elem) {
		var orig=config.macros.pasteUp.getTrack(elem).start.css;
		elem.style.top   =orig.T;
		elem.style.left  =orig.L;
		elem.style.width =orig.W;
		elem.style.height=orig.H;
		elem.changed     =false;
		displayMessage('move/size cancelled',null,true);
		cmp.setCursor(e,ev);
	},
//}}}
// // DRAGSAVE -  Update embedded {{{<<pasteUp>>}}} or {{{<<tiddler>>}}} macro
//{{{
	cloneFields: function(fields) { // for TIDDLYSPACE compatibility
		var f=merge({},fields); // copy object
		if (f["server.workspace"]!=config.defaultCustomFields["server.workspace"]) {
			f=merge(f,config.defaultCustomFields); // overwrite with defaults
			f["server.permissions"] = "read, write, create, delete";
			delete f["server.page.revision"];
			delete f["server.title"];
			delete f["server.etag"];
		}
		return f;
	},
	dragsave: function(elem,left,top,width,height,zIndex) {
		var cmp=config.macros.pasteUp; // abbrev

		// FIND CONTAINER (the tiddler/section that transcludes this one)
		var c=elem.parentNode;
		while(c && c.getAttribute('tiddler')==undefined) c=c.parentNode;
		if (!c) return;
		var target=c.getAttribute('tiddler');	
		var txt=store.getTiddlerText(target,'');
		var parts=target.split('##');
		var title=parts[0];
		var section=parts[1];

		// CHECK FOR 'OUT OF BOUNDS'
		if (!hasClass(c,'pasteUp') && cmp.outofboundsmsg.length && config.options.chkPasteUpBoundaryWarning) {
			var w=jQuery(c).width(); var h=jQuery(c).height();
			var l=jQuery(elem).position().left; var r=l+jQuery(elem).width();
			var t=jQuery(elem).position().top;  var b=t+jQuery(elem).height();
			if (l<0 || t<0 || r>w || b>h) if (!confirm(cmp.outofboundsmsg)) {
				cmp.dragcancel(elem); elem.changed=true; // ignore following click
				return;
			}
		}
	
		// FIND <<pasteUp>> or <<tiddler>> MACRO and UPDATE PARAMS
		if (cmp.debug) displayMessage('updating '+target);
		var a='auto'; var fmt=' x:%0 y:%1 w:%2 h:%3';
		if (zIndex!==undefined && zIndex!=1) fmt=' x:%0 y:%1 z:%4 w:%2 h:%3';
		var newparams=fmt.format([left||a,top||a,width||a,height||a,zIndex]);
		var newtxt=''; var pos=0; var t=elem.pasteupParams.escapeRegExp();
		var re=new RegExp('<<(pasteUp|tiddler)\\s+'+t+'>>','mg');
		var matches=re.exec(txt);
		if (!matches) { // NO MATCH = POSSIBLE TIDDLER NAME FIXUP (i.e, '##section')
			var here=story.findContainingTiddler(elem);
			var tid=here?here.getAttribute('tiddler'):'';
			var t=elem.pasteupParams.escapeRegExp().replace(new Regexp(tid),''); // REMOVE FIXUP TIDDLER NAME
			var re=new RegExp('<<(pasteUp|tiddler)\\s+'+t+'>>','mg'); // TRY AGAIN
			var matches=re.exec(txt);
		}
		while (matches) { var m=matches[0];
			newtxt+=txt.substr(pos,re.lastIndex-m.length-pos); // before match
			var parts=m.substr(0,m.length-2).split(' with: ');
			parts[0]=parts[0].replace(/\s+[xyzwh]\:[^\s>]*/g,''); // remove old x,y,z,w,h params
			parts[1]=parts[1]?' with: '+parts[1]+'>>':'>>';
			m=parts[0]+newparams+parts[1];
			if (cmp.debug) displayMessage(m);
			newtxt+=m; pos=re.lastIndex; matches=re.exec(txt);
		}
		newtxt+=txt.substr(pos,txt.length); // remainder 

		// SAVE TIDDLER
		var t=store.getTiddler(title); if (!t) {
			t=new Tiddler();
			t.text=store.getTiddlerText(title,'');
			t.fields=config.defaultCustomFields;
		}
		if (section) { // revise section text
			var oldval=store.getTiddlerText(target).escapeRegExp();
			var pattern=new RegExp('(.*!{1,6}'+section+'\\n)'+oldval+'((?:\\n!{1,6}|$).*)');
			newtxt=t.text.replace(pattern,'$1'+newtxt+'$2');
		}
		var who=config.options.txtUserName; var when=new Date();
		if (config.options.chkForceMinorUpdate) { who=t.modifier||who; when=t.modified||when; }
		store.saveTiddler(title,title,newtxt,who,when,t.tags,cmp.cloneFields(t.fields));
		if (config.macros.undo) {
			var partname=elem.pasteupParams.readBracketedList()[0];
			config.macros.undo.setmsg('move/resize '+partname);
		}
		story.refreshTiddler(title,null,true);
		autoSaveChanges();
},
//}}}
// // ADDPART - Add an embedded {{{<<pasteUp>>}}} part to a tiddler
//{{{
	addPart: function(tid,partname) {
		var cmp=config.macros.pasteUp; // abbrev
		// GET PART TiddlerTitle OR TiddlerTitle##sectionname
		var title=partname.split('##')[0]||tid;
		var section=partname.split('##')[1];
		var part=title+(section?'##'+section:'');
		// GET CONTAINING TIDDLER
		var t=store.getTiddler(tid); if (!t) {
			t=new Tiddler();
			t.text=store.getTiddlerText(tid,'');
			t.fields=config.defaultCustomFields;
		}
		// APPEND PART PASTEUP
		var y=store.getTiddlerText('PasteUpConfig::PartTop',   '0px');
		var x=store.getTiddlerText('PasteUpConfig::PartLeft',  '0px');
		var w=store.getTiddlerText('PasteUpConfig::PartWidth', 'auto');
		var h=store.getTiddlerText('PasteUpConfig::PartHeight','auto');
		var fmt='%0<<pasteUp [[%1]] x:%2 y:%3 w:%4 h:%5>>';
		var txt=t.text+fmt.format([t.text.length?'\n':'',part,x,y,w,h]);
		// SAVE CONTAINER
		var who=config.options.txtUserName; var when=new Date();
		if (config.options.chkForceMinorUpdate)
			{ who=t.modifier||who; when=t.modified||when; }
		store.saveTiddler(tid,tid,txt,who,when,t.tags,cmp.cloneFields(t.fields));
		if (config.macros.undo) config.macros.undo.setmsg('remove '+part+' from '+tid);
		story.refreshTiddler(tid,null,true);
		// CREATE PART IF NEEDED
		if (!store.getTiddlerText(part)) {
			var t=store.getTiddler(title); if(!t) {
				t=new Tiddler();
				t.text=store.getTiddlerText(title,'');
				t.fields=config.defaultCustomFields;
			}
			var txt=store.getTiddlerText('DefaultPart',part).replace(/DefaultPart/g,part);
			if (section) txt='{{hidden{\n!'+section+'\n'+txt+'\n!end '+section+'\n}}}';
			if (!section) t.tags.pushUnique('part');
			store.saveTiddler(title,title,t.text+txt,who,when,t.tags,cmp.cloneFields(t.fields));
			story.refreshTiddler(title,null,true);
			displayMessage('created new part: '+part);
		}
		displayMessage(part+' added to '+tid);
		autoSaveChanges();
		return false;
	},
	removePart: function(elem,force) {
		var cmp=config.macros.pasteUp; // abbrev
		// FIND CONTAINER (the tiddler/section that transcludes this one)
		var c=elem.parentNode;
		while(c && c.getAttribute('tiddler')==undefined) c=c.parentNode;
		if (!c) return false; // NOTHING REMOVED
		var target=c.getAttribute('tiddler');	
		var txt=store.getTiddlerText(target,'');
		var parts=target.split('##');
		var title=parts[0];
		var section=parts[1];

		// ASK FOR CONFIRMATION (if not FORCE)
		var msg=cmp.confirmremovemsg.format([elem.getAttribute('tid'),target]);
		if (!force && config.options.chkPasteUpConfirmRemove && !confirm(msg)) return false;

		// FIND <<pasteUp>> or <<tiddler>> MACRO 
		if (cmp.debug) displayMessage('updating '+target);
		var newtxt=''; var pos=0; var t=elem.pasteupParams.escapeRegExp();
		var re=new RegExp('<<(pasteUp|tiddler)\\s+'+t+'>>','mg');
		var matches=re.exec(txt);
		if (!matches) { // NO MATCH = POSSIBLE TIDDLER NAME FIXUP (i.e, '##section')
			var here=story.findContainingTiddler(elem);
			var tid=here?here.getAttribute('tiddler'):'';
			var t=elem.pasteupParams.escapeRegExp().replace(new Regexp(tid),''); // REMOVE FIXUP TIDDLER NAME
			var re=new RegExp('<<(pasteUp|tiddler)\\s+'+t+'>>','mg'); // TRY AGAIN
			var matches=re.exec(txt);
		}

		// REMOVE MACROS
		while (matches) { var m=matches[0];
			newtxt+=txt.substr(pos,re.lastIndex-m.length-pos); // before match
			if (cmp.debug) displayMessage('removing '+m);
			pos=re.lastIndex; matches=re.exec(txt);
		}
		newtxt+=txt.substr(pos,txt.length); // remainder 

		// SAVE TIDDLER
		var t=store.getTiddler(title); if (!t) return;
		if (section) { // revise section text
			var oldval=store.getTiddlerText(target).escapeRegExp();
			var pattern=new RegExp('(.*!{1,6}'+section+'\\n)'+oldval+'((?:\\n!{1,6}|$).*)');
			newtxt=t.text.replace(pattern,'$1'+newtxt+'$2');
		}
		var who=config.options.txtUserName; var when=new Date();
		if (config.options.chkForceMinorUpdate)
			{ who=t.modifier||who; when=t.modified||when; }
		store.saveTiddler(title,title,newtxt,who,when,t.tags,cmp.cloneFields(t.fields));
		if (config.macros.undo) {
			var partname=elem.pasteupParams.readBracketedList()[0];
			config.macros.undo.setmsg('restore part '+partname+' in '+title);
		}
		story.refreshTiddler(title,null,true);
		displayMessage(partname+' removed from '+title);
		autoSaveChanges();
		return true; // PART REMOVED SUCCESSFULLY
	}
}
//}}}
// // HIJACK {{{<<tiddler>>}}} handler
//{{{
config.macros.pasteUp.core_handler=config.macros.tiddler.handler;
config.macros.tiddler.handler=config.macros.pasteUp.handler;
//}}}
// // MACRO: addPasteUpPart
//{{{
config.macros.addPasteUpPart = {
	label: 'add part',
	prompt: 'add a part to this page',
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		if (window.readOnly) return;
		var label=params[0]||this.label;
		var prompt=params[1]||this.prompt;
		createTiddlyButton(place,label,prompt,this.click);
	},
	click: function(ev) {
		var tid=story.findContainingTiddler(this).getAttribute('tiddler');
		var partname=prompt('Please enter a part name:','NewPart');
		if (partname) config.macros.pasteUp.addPart(tid,partname);
		return config.macros.pasteUp.ok(ev);
	}
};
//}}}
// // TOOLBAR COMMAND: addPasteUpPart
//{{{
config.commands.addPasteUpPart = {
	text: 'add part',
	hideReadOnly: true,
	tooltip: 'add a part to this page',
	handler: function(ev,src,title) {
		return config.macros.addPasteUpPart.click(ev);
	}
};
//}}}
// // DELIVER INTERNAL PLUGIN STYLES TO PasteUpPluginStyles SHADOW
//{{{
var tid='PasteUpPluginStyles';
config.shadowTiddlers[tid]='/*{{{*/\n'+store.getTiddlerText(tiddler.title+'##css','')+'\n/*}}}*/';;
config.annotations[tid]='CSS definitions used internally by PasteUpPlugin.  Do not modify unless you are sure you know what you are doing!';
store.addNotification(tid,refreshStyles);
//}}}
/***
{{{
!css
.hidden
	{ display:none; }
.pasteUp
	{ border:1px solid transparent; z-index:1; }
.pasteUpBorder
	{ border:1px dotted black !important; }
div[tags~="pasteup"].tiddler div.viewer,
div[tags~="part"].tiddler div.viewer,
div[tiddler="DefaultPage"] div.viewer,
div[tiddler="DefaultPageHeader"] div.viewer,
div[tiddler="DefaultPageFooter"] div.viewer,
div[tiddler="DefaultPart"] div.viewer {
	width:[[PasteUpConfig::Width]];
	height:[[PasteUpConfig::Height]];
	padding:0em;
	border:1px solid;
}
!end
}}}
***/
// // REFRESH DISPLAY WHEN PasteUpConfig IS CHANGED (applies user settings)
//{{{
store.addNotification('PasteUpConfig', function(title){ refreshAll(); });
//}}}
// // DELIVER SHADOW CONTENT FOR DefaultPage (for use with {{{<<newTiddler>>}}})
//{{{
config.shadowTiddlers['DefaultPage']=store.getTiddlerText(tiddler.title+'##defaultpage','');
config.annotations['DefaultPage']='This content is used to create new pasteup pages';
//}}}
/***
{{{
!defaultpage
<<pasteUp [[DefaultPageHeader]] x:0px y:0%  w:100% h:10%>>
<<pasteUp [[DefaultPageFooter]] x:0px y:90% w:100% h:10%>>
!end
}}}
***/
// // DELIVER SHADOW CONTENT FOR DefaultPart (used by addPasteUpPart)
//{{{
config.shadowTiddlers['DefaultPart']=store.getTiddlerText(tiddler.title+'##defaultpart','');
config.annotations['DefaultPart']='This content is used to create new parts on pasteup pages';
//}}}
/***
{{{
!defaultpart
This is "DefaultPart"
Please click to edit.
!end
}}}
***/
 
|Name|[[PasteUpPluginInfo]]|
|Source|http://www.TiddlyTools.com/#PasteUpPlugin|
|Documentation|http://www.TiddlyTools.com/#PasteUpPluginInfo|
|Version|1.1.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.5|
|Type|documentation|
|~SeeAlso|EditSectionPlugin PasteUpHelperPlugin|
|Description|documentation for PasteUpPlugin and PasteUpHelperPlugin|
The {{{<<pasteUp>>}}} macro provides enhancements to the {{{<<tiddler>>}}} macro that allow you to ''specify the placement, size and appearance of embedded content'' to create 'free form layouts' using overlapping "paste-up" elements.  You can also ''embed and position paste-up elements within the content of other paste-up elements'', so that adjustments to the position of a containing element affects all the nested elements within it as well (i.e., they move together as a group).

You can use the mouse to ''drag an element to change its position'' (i.e., move the top-left corner), or use ''shift-drag to change its dimensions'' (i.e., move the lower-right corner).  When you release the mouse, changes to the x,y,w,h parameters are automatically updated in the corresponding {{{<<pasteUp>>}}} (or {{{<<tiddler>>}}}) macro (note: this //modifies the tiddler in which the macro occurs//).  You can hand-edit the macro parameters in the tiddler source to customize or further 'fine tune' the layout.

When [[EditSectionPlugin]] is installed, you can ''single-click on an element to display a popup editor'' that permits you to ''directly modify the element's source content'' without having to first locate and open the associated source tiddler.  When [[EditSectionPlugin]] is not present, ''a double-click on an element opens the associated source tiddler in a standard tiddler editor''.

When [[PasteUpHelperPlugin]] is also installed, the default popup editor is enhanced to add extra controls for editing the current size/position (x,y,w,h) of a paste-up element as well as 'helper' controls for selecting from pre-defined, configurable lists of font sizes, styles, and images, along with x,y,w,h values for positioning/sizing the selected image.  The 'helper' then //automatically generates// the TiddlyWiki syntax needed to set the size, position, font, style and image (if any) for a paste-up element.
!!!Usage
<<<
{{{
<<pasteUp TiddlerName class:"classname" noedit noadjust nopopup style:"..." x:... y:... z:... w:... h:... >>
   or
<<tiddler TiddlerName class:"classname" edit adjust nopopup style:"..." x:... y:... z:... w:... h:... >>
}}}
''//(all parameters -- except for ~TiddlerName -- are optional)//''
*''class:"classname"'' (default="")<br>specifies a CSS classname (or combination of space-separated classnames, enclosed in quotes) that will be assigned to the element.
*''style:"..."'' (default="")<br>specifies any valid sequence of one or more CSS "property:value;" pairs (e.g., "border:1px solid black;font-size:300%;") that will be assigned to the element.
*''edit/noedit'' (keyword)<br>enables editing of an embedded {{{<<tiddler>>}}} element.  Note: when using the {{{<<pasteUp>>}}} macro, editing is automatically enabled by default; use ''noedit'' to bypass this handling.
*''adjust/noadjust'' (keyword)<br>enables moving/stretching of an embedded {{{<<tiddler>>}}} element.  Note: when using the {{{<<pasteUp>>}}} macro, moving/stretching is automatically enabled by default; use ''noadjust'' to bypass this handling.
*''nopopup'' (keyword)<br>bypasses single-click popup editing even if [[EditSectionPlugin]] is installed.  When editing is enabled, double-click an element to edit it using a standard tiddler editor.
*''x, y, z, w, h'' (default="auto")<br>specifies the left (x), top (y), z-index "stacking order" (z), width (w), and height (h) of the paste-up element using any valid CSS units of measure (e.g., px, cm, in, em, %, or 'auto').
Notes:
*You can define the position, size and appearance of a paste-up element using any combination of ''class:"..."'', ''style:"..."'', and/or separate ''x, y, z, w, h'' parameters.  Classname-based attributes are applied first, and can be selectively overridden by style-based attributes which, in turn, can be overriden by specific x, y, z, w, and h parameters.  Note: //Classname and style parameter values can contain spaces.  It is a good habit to ''always'' enclose these values within quotes to ensure proper macro handling.//
*{{span{The output format for a part generated by the [[PasteUpHelperPlugin]]-enhanced popup editor is:
{{{
<<pasteUp [[partname::image]] noedit x:0px y:0px w:auto h:auto>>/%
image: [img(100%,auto)[path/file.ext]]
%/{{fontsize classname{
content
}}} 
}}}
* If no image is selected in the popup editor droplist, the image portion of the syntax, up to and including the "{{{%/}}}", is omitted.
* If neither fontsize nor classname is selected, the 'CSS wrapper' around the part content is omitted.
* Note: if you hand-edit the resulting tiddler content, avoid changing any [[PasteUpHelperPlugin]]-generated syntax that may surround your content, as this can prevent the plugin from correctly processing and displaying that content later on.
}}}
<<<
!!!Configuration
<<tiddler PasteUpPlugin##Configuration>>
!!!Examples
<<<
Inline, custom class, editable but not adjustable:
>{{{<<tiddler PasteUpPluginInfo##Sample1 "groupbox" edit>>}}}
><<tiddler PasteUpPluginInfo##Sample1 "groupbox" edit>>
Inline (initial position/size), editable and adjustable ("tear-off" to change position/size):
>{{{<<tiddler PasteUpPluginInfo##Sample1 "groupbox" edit adjust>>}}}
><<tiddler PasteUpPluginInfo##Sample1 "groupbox" edit adjust>>
Pasteup (custom position/size/style), editable and adjustable by default:
>{{{<<pasteUp PasteUpPluginInfo##Sample1 style:"border:1px solid blue;color:black;background:white;" x:4in y:-0.5in w:3in h:auto>>}}}
><<pasteUp PasteUpPluginInfo##Sample1 style:"border:1px solid blue;color:black;background:white;" x:4in y:-0.5in w:3in h:auto>>
Refrigerator magnets (custom size/style, not editable/adjustable, with editable/adjustable nested elements)
>{{{<<tiddler PasteUpPluginInfo##Fridge style:"display:block;border:1px solid;color:black;background:#ccc;" w:3in h:4in>>}}}
><<tiddler PasteUpPluginInfo##Fridge style:"display:block;border:1px solid;color:black;background:#ccc;" w:3in h:4in>>
Example section data:
>{{wrapper{
{{{
!Sample1
This content will be embedded ''inline'' using the extended parameters of the {{{<<tiddler>>}}} or {{{<<pasteUp>>}}} macros.
!!!!!!
}}}
{{{
!Fridge
My Refrigerator:
<<pasteUp PasteUpPluginInfo##MagnetA class:groupbox x:113px y:231px w:auto h:auto>>
<<pasteUp PasteUpPluginInfo##MagnetB class:groupbox x:90px y:47px w:auto h:auto>>
<<pasteUp PasteUpPluginInfo##MagnetC class:groupbox x:13px y:109px w:auto h:auto>>
!!!!MagnetA
Pizza Delivery
30 minutes or less
555-1212
!!!!MagnetB
Shopping: bread, milk, eggs
!!!!MagnetC
A1 Auto Body
123 Main Street
Somewhere, CA 91234
"We'll Fix You Up Good!"
!!!!!!
}}}
}}}
<<<
!!!Revisions
<<<
2011.04.27 1.1.1 merge/clone defaultCustomFields for saving on TiddlySpace
2011.03.19 1.1.0 re-factor mousetracking functions for cleaner event handling
2011.02.23 1.0.10 mousetracking: in capture(), invoke release() first (fix for Chrome 'sticky drag' problem?)
2011.02.08 1.0.9 when saving new tiddlers, use config.defaultCustomFields for TiddlySpace compatibility
2011.01.30 1.0.8 in addPart(), retain existing tags when adding part to current tiddler
2011.01.12 1.0.7 in handler(), make sure tiddler element was actually rendered
2011.01.11 1.0.6 corrected hijack of config.macros.tiddler.handler (avoids stepping on other plugins)
2011.01.03 1.0.5 in addPart(), allow parts to be created as sections of tiddlers or just stand-alone tiddlers
2010.12.31 1.0.4 added {{{<<addPasteUpPart label tip>>}}} macro (same as toolbar command)
2010.12.16 1.0.3 added chkPasteUpEditAll (for global editing) and 'snapshot' CSS class to shadow PasteUpStylesheet (for printing)
2010.12.12 1.0.2 corrected mouse capture for DRAG handling
2010.11.27 1.0.1 added shadows: DefaultPage, DefaultPart, PasteUpStylesheet.  Added PasteUpConfig for default pos/size of new parts and images. Added 'nopopup' keyword (bypasses EditSectionPlugin)
2010.11.15 1.0.0 complete re-write and initial release
2010.11.01 0.9.5 helper controls
2010.10.25 0.9.0 mouse handling
2010.07.23 0.8.0 lots of fixes
2010.07.21 0.7.5 alpha prototype (for review - do not distribute)
<<<
(plain)=
headline
left
center
right
justify
twocolumns
threecolumns
boxed=border
/%
|Name|PasteUpToolbar|
|Source|http://www.TiddlyTools.com/#PasteUpToolbar|
|Version|1.2.5|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.5|
|Type|plugin|
|Description|PasteUp Quickstart command toolbar for use within ViewTemplate|

%/<<tiddler PasteUpCommands##slideshow_toolbar	if:{{config.options.chkSlideshow}}>>/%
%/<<tiddler PasteUpCommands##addpart		if:{{!window.readOnly}}>>/%
%/<<tiddler PasteUpCommands##addpage		if:{{!window.readOnly}}>>/%
%/<<tiddler PasteUpCommands##deletepage		if:{{!window.readOnly}}>>
/%
|''URL:''|http://bradleymeck.tiddlyspot.com/|
|''Description:''|Resources that are Ripe for the Picking|
|''Author:''|BradleyMeck|
%/
/***
|Name|Plain|
|Source|http://www.TiddlyTools.com/#Plain|
|Version||
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|CSS|
|Description|theme: white backgrounds with minimal adjustments|
|StyleSheet|Plain|
|PageTemplateReadOnly|PageTemplateReadOnly|
|EditTemplateReadOnly|EditTemplateReadOnly|
***/

[[StyleSheetAdjustments]]
/*{{{*/
/* ==== Plain ==== */
body { background-color:#ffe !important; }
.menubox { background-color:#fff; }
.viewer	{ border: 1px solid #999; background:#fff; -moz-border-radius:1em;-webkit-border-radius:1em; padding:1em; }
/*}}}*/
/***
|Name|PlayerPlugin|
|Source|http://www.TiddlyTools.com/#PlayerPlugin|
|Version|1.1.4|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|Embed a media player in a tiddler|
!!!!!Usage
<<<
{{{<<player [id=xxx] [type] [URL] [width] [height] [autoplay|true|false] [showcontrols|true|false] [extras]>>}}}

''id=xxx'' is optional, and specifies a unique identifier for each embedded player.  note: this is required if you intend to display more than one player at the same time.

''type'' is optional, and is one of the following: ''windows'', ''realone'', ''quicktime'', ''flash'', ''image'' or ''iframe''.  If the media type is not specified, the plugin automatically detects Windows, Real, QuickTime, Flash video or JPG/GIF images by matching known file extensions and/or specialized streaming-media transfer protocols (such as RTSP:).  For unrecognized media types, the plugin displays an error message.

''URL'' is the location of the media content

''width'' and ''height'' are the dimensions of the video display area (in pixels)

''autoplay'' or ''true'' or ''false'' is optional, and specifies whether the media content should begin playing as soon as it is loaded, or wait for the user to press the "play" button.  Default is //not// to autoplay.

''showcontrols'' or ''true'' or ''false'' is optional, and specifies whether the embedded media player should display its built-in control panel (e.g., play, pause, stop, rewind, etc), if any.  Default is to display the player controls.

''extras'' are optional //pairs// of parameters that can be passed to the embedded player, using the {{{<param name=xxx value=yyy>}}} HTML syntax.

''If you use [[AttachFilePlugin]] to encode and store a media file within your document, you can play embedded media content by using the title of the //attachment tiddler//'' as a parameter in place of the usual reference to an external URL.  When playing an attached media content, you should always explicitly specify the media type parameter, because the name used for the attachment tiddler may not contain a known file extension from which a default media type can be readily determined.
<<<
!!!!!Configuration
<<<
Default player size:
width: <<option txtPlayerDefaultWidth>> height: <<option txtPlayerDefaultHeight>>
<<<
!!!!!Examples
<<<
+++[Windows Media]...
Times Square Live Webcam
{{{<<player id=1 http://www.earthcam.com/usa/newyork/timessquare/asx/tsq_stream.asx>>}}}
<<player id=1 http://www.earthcam.com/usa/newyork/timessquare/asx/tsq_stream.asx>>
===
+++[RealOne]...
BBC London: Live and Recorded news
{{{<<player id=2 http://www.bbc.co.uk/london/realmedia/news/tvnews.ram>>}}}
<<player id=2 http://www.bbc.co.uk/london/realmedia/news/tvnews.ram>>
===
+++[Quicktime]...
America Free TV: Classic Comedy
{{{<<player id=3 http://www.americafree.tv/unicast_mov/AmericaFreeTVComedy.mov>>}}}
<<player id=3 http://www.americafree.tv/unicast_mov/AmericaFreeTVComedy.mov>>
===
+++[Flash]...
Asteroids arcade game
{{{<<player id=4 http://www.80smusiclyrics.com/games/asteroids/asteroids.swf 400 300>>}}}
<<player id=4 http://www.80smusiclyrics.com/games/asteroids/asteroids.swf 400 300>>
Google Video
{{{<<player id=5 flash http://video.google.com/googleplayer.swf?videoUrl=http%3A%2F%2Fvp.video.google.com%2Fvideodownload%3Fversion%3D0%26secureurl%3DoQAAAIVnUNP6GYRY8YnIRNPe4Uk5-j1q1MVpJIW4uyEFpq5Si0hcSDuig_JZcB9nNpAhbScm9W_8y_vDJQBw1DRdCVbXl-wwm5dyUiiStl_rXt0ATlstVzrUNC4fkgK_j7nmse7kxojRj1M3eo3jXKm2V8pQjWk97GcksMFFwg7BRAXmRSERexR210Amar5LYzlo9_k2AGUWPLyRhMJS4v5KtDSvNK0neL83ZjlHlSECYXyk%26sigh%3Dmpt2EOr86OAUNnPQ3b9Tr0wnDms%26begin%3D0%26len%3D429700%26docid%3D-914679554478687740&thumbnailUrl=http%3A%2F%2Fvideo.google.com%2FThumbnailServer%3Fcontentid%3De7e77162deb04c42%26second%3D5%26itag%3Dw320%26urlcreated%3D1144620753%26sigh%3DC3fqXPPS1tFiUqLzmkX3pdgYc2Y&playerId=-91467955447868774               400 326>>}}}
<<player id=5 flash http://video.google.com/googleplayer.swf?videoUrl=http%3A%2F%2Fvp.video.google.com%2Fvideodownload%3Fversion%3D0%26secureurl%3DoQAAAIVnUNP6GYRY8YnIRNPe4Uk5-j1q1MVpJIW4uyEFpq5Si0hcSDuig_JZcB9nNpAhbScm9W_8y_vDJQBw1DRdCVbXl-wwm5dyUiiStl_rXt0ATlstVzrUNC4fkgK_j7nmse7kxojRj1M3eo3jXKm2V8pQjWk97GcksMFFwg7BRAXmRSERexR210Amar5LYzlo9_k2AGUWPLyRhMJS4v5KtDSvNK0neL83ZjlHlSECYXyk%26sigh%3Dmpt2EOr86OAUNnPQ3b9Tr0wnDms%26begin%3D0%26len%3D429700%26docid%3D-914679554478687740&thumbnailUrl=http%3A%2F%2Fvideo.google.com%2FThumbnailServer%3Fcontentid%3De7e77162deb04c42%26second%3D5%26itag%3Dw320%26urlcreated%3D1144620753%26sigh%3DC3fqXPPS1tFiUqLzmkX3pdgYc2Y&playerId=-91467955447868774               400 326>>
YouTube Video
{{{<<player id=6 flash http://www.youtube.com/v/OdT9z-JjtJk 400 300>>}}}
<<player id=6 flash http://www.youtube.com/v/OdT9z-JjtJk 400 300>>
===
+++[Still Images]...
GIF (best for illustrations, animations, diagrams, etc.)
{{{<<player id=7 image images/meow.gif auto auto>>}}}
<<player id=7 image images/meow.gif auto auto>>
JPG (best for photographs, scanned images, etc.)
{{{<<player id=8 image images/meow2.jpg 200 150>>}}}
<<player id=8 image images/meow2.jpg 200 150>>
===
<<<
!!!!!Revisions
<<<
2008.05.10 [1.1.4] in handlers(), immediately return if no params (prevents error in macro).  Also, refactored auto-detect code to make type mapping configurable.
2007.10.15 [1.1.3] in loadURL(), add recognition for .PNG (still image), fallback to iframe for unrecognized media types
2007.08.31 [1.1.2] added 'click-through' link for JPG/GIF images
2007.06.21 [1.1.1] changed "hidecontrols" param to "showcontrols" and recognize true/false values in addition to 'showcontrols', added "autoplay" param (also recognize true/false values), allow "auto" as value for type param
2007.05.22 [1.1.0] added support for type=="iframe" (displays src URL in an IFRAME)
2006.12.06 [1.0.1] in handler(), corrected check for config.macros.attach (instead of config.macros.attach.getAttachment) so that player plugin will work when AttachFilePlugin is NOT installed.  (Thanks to Phillip Ehses for bug report)
2006.11.30 [1.0.0] support embedded media content using getAttachment() API defined by AttachFilePlugin or AttachFilePluginFormatters.  Also added support for 'image' type to render JPG/GIF still images
2006.02.26 [0.7.0] major re-write.  handles default params better.  create/recreate player objects via loadURL() API for use with interactive forms and scripts.
2006.01.27 [0.6.0] added support for 'extra' macro params to pass through to object parameters
2006.01.19 [0.5.0] Initial ALPHA release
2005.12.23 [0.0.0] Started
<<<
!!!!!Code
***/
//{{{
version.extensions.PlayerPlugin= {major: 1, minor: 1, revision: 4, date: new Date(2008,5,10)};

config.macros.player = {};
config.macros.player.html = {};
config.macros.player.handler= function(place,macroName,params) {
	if (!params.length) return; // missing parameters - do nothing
	var id=null;
	if (params[0].substr(0,3)=="id=") id=params.shift().substr(3);
	var type="";
	if (!params.length) return; // missing parameters - do nothing
	var p=params[0].toLowerCase();
	if (p=="auto" || p=="windows" || p=="realone" || p=="quicktime" || p=="flash" || p=="image" || p=="iframe")
		type=params.shift().toLowerCase();
	var url=params.shift(); if (!url || !url.trim().length) url="";
	if (url.length && config.macros.attach!=undefined) // if AttachFilePlugin is installed
		if ((tid=store.getTiddler(url))!=null && tid.isTagged("attachment")) // if URL is attachment
			url=config.macros.attach.getAttachment(url); // replace TiddlerTitle with URL
	var width=params.shift();
	var height=params.shift();
	var autoplay=false;
	if (params[0]=='autoplay'||params[0]=='true'||params[0]=='false')
		autoplay=(params.shift()!='false');
	var show=true;
	if (params[0]=='showcontrols'||params[0]=='true'||params[0]=='false')
		show=(params.shift()!='false');
	var extras="";
	while (params[0]!=undefined)
		extras+="<param name='"+params.shift()+"' value='"+params.shift()+"'> ";
	this.loadURL(place,id,type,url,width,height,autoplay,show,extras);
}

if (config.options.txtPlayerDefaultWidth==undefined) config.options.txtPlayerDefaultWidth="100%";
if (config.options.txtPlayerDefaultHeight==undefined) config.options.txtPlayerDefaultHeight="480"; // can't use "100%"... player height doesn't stretch right :-(

config.macros.player.typeMap={
	windows: ['mms', '.asx', '.wvx', '.wmv', '.mp3'],
	realone: ['rtsp', '.ram', '.rpm', '.rm', '.ra'],
	quicktime: ['.mov', '.qt'],
	flash: ['.swf', '.flv'],
	image: ['.jpg', '.gif', '.png'],
	iframe: ['.htm', '.html', '.shtml', '.php']
};

config.macros.player.loadURL=function(place,id,type,url,width,height,autoplay,show,extras) {

	if (id==undefined) id="tiddlyPlayer";
	if (!width) var width=config.options.txtPlayerDefaultWidth;
	if (!height) var height=config.options.txtPlayerDefaultHeight;
	if (url && (!type || !type.length || type=="auto")) { // determine type from URL
		u=url.toLowerCase();
		var map=config.macros.player.typeMap;
		for (var t in map) for (var i=0; i<map[t].length; i++)
			if (u.indexOf(map[t][i])!=-1) var type=t;
	}
	if (!type || !config.macros.player.html[type]) var type="none";
	if (!url) var url="";
	if (show===undefined) var show=true;
	if (!extras) var extras="";
	if (type=="none" && url.trim().length) type="iframe"; // fallback to iframe for unrecognized media types

	// adjust parameter values for player-specific embedded HTML
	switch (type) {
		case "windows":
			autoplay=autoplay?"1":"0"; // player-specific param value
			show=show?"1":"0"; // player-specific param value
			break;
		case "realone":
			autoplay=autoplay?"true":"false";
			show=show?"block":"none";
			height-=show?60:0; // leave room for controls
			break;
		case "quicktime":
			autoplay=autoplay?"true":"false";
			show=show?"true":"false";
			break;
		case "image":
			show=show?"block":"none";
			break;
		case "iframe":
			show=show?"block":"none";
			break;
	}

	// create containing div for player HTML
	// and add or replace player in TW DOM structure
	var newplayer = document.createElement("div");
	newplayer.playerType=type;
	newplayer.setAttribute("id",id+"_div");
	var existing = document.getElementById(id+"_div");
	if (existing && !place) place=existing.parentNode;
	if (!existing)
		place.appendChild(newplayer);
	else {
		if (place==existing.parentNode) place.replaceChild(newplayer,existing)
		else { existing.parentNode.removeChild(existing); place.appendChild(newplayer); }
	}

	var html=config.macros.player.html[type];
	html=html.replace(/%i%/mg,id);
	html=html.replace(/%w%/mg,width);
	html=html.replace(/%h%/mg,height);
	html=html.replace(/%u%/mg,url);
	html=html.replace(/%a%/mg,autoplay);
	html=html.replace(/%s%/mg,show);
	html=html.replace(/%x%/mg,extras);
	newplayer.innerHTML=html;
}
//}}}

// // Player-specific API functions: isReady(id), isPlaying(id), toggleControls(id), showControls(id,flag)

//{{{
// status values:
// Windows: 0=Undefined, 1=Stopped, 2=Paused, 3=Playing, 4=ScanForward, 5=ScanReverse
//          6=Buffering, 7=Waiting, 8=MediaEnded, 9=Transitioning, 10=Ready, 11=Reconnecting
// RealOne: 0=Stopped, 1=Contacting, 2=Buffering, 3=Playing, 4=Paused, 5=Seeking
// QuickTime: 'Waiting', 'Loading', 'Playable', 'Complete', 'Error:###'
// Flash: 0=Loading, 1=Uninitialized, 2=Loaded, 3=Interactive, 4=Complete
config.macros.player.isReady=function(id)
{
	var d=document.getElementById(id+"_div"); if (!d) return false;
	var p=document.getElementById(id); if (!p) return false;
	if (d.playerType=='windows') return !((p.playState==0)||(p.playState==7)||(p.playState==9)||(p.playState==11));
	if (d.playerType=='realone') return (p.GetPlayState()>1);
	if (d.playerType=='quicktime') return !((p.getPluginStatus()=='Waiting')||(p.getPluginStatus()=='Loading'));
	if (d.playerType=='flash') return (p.ReadyState>2);
	return true;
}
config.macros.player.isPlaying=function(id)
{
	var d=document.getElementById(id+"_div"); if (!d) return false;
	var p=document.getElementById(id); if (!p) return false;
	if (d.playerType=='windows') return (p.playState==3);
	if (d.playerType=='realone') return (p.GetPlayState()==3);
	if (d.playerType=='quicktime') return (p.getPluginStatus()=='Complete');
	if (d.playerType=='flash') return (p.ReadyState<4);
	return false;
}
config.macros.player.showControls=function(id,flag) {
	var d=document.getElementById(id+"_div"); if (!d) return false;
	var p=document.getElementById(id); if (!p) return false;
	if (d.playerType=='windows') { p.ShowControls=flag; p.ShowStatusBar=flag; }
	if (d.playerType=='realone') { alert('show/hide controls not available'); }
	if (d.playerType=='quicktime')      // if player not ready, retry in one second
		{ if (this.isReady(id)) p.setControllerVisible(flag); else setTimeout('config.macros.player.showControls("'+id+'",'+flag+')',1000); }
	if (d.playerType=='flash') { alert('show/hide controls not available'); }
}
config.macros.player.toggleControls=function(id) {
	var d=document.getElementById(id+"_div"); if (!d) return false;
	var p=document.getElementById(id); if (!p) return false;
	if (d.playerType=='windows') var flag=!p.ShowControls;
	if (d.playerType=='realone') var flag=true; // TBD
	if (d.playerType=='quicktime') var flag=!p.getControllerVisible();
	if (d.playerType=='flash') var flag=true; // TBD
	this.showControls(id,flag);
}
config.macros.player.fullScreen=function(id) {
	var d=document.getElementById(id+"_div"); if (!d) return false;
	var p=document.getElementById(id); if (!p) return false;
	if (d.playerType=='windows') p.DisplaySize=3;
	if (d.playerType=='realone') p.SetFullScreen();
	if (d.playerType=='quicktime') { alert('full screen not available'); }
	if (d.playerType=='flash') { alert('full screen not available'); }
}
//}}}

// // Player HTML

//{{{
// placeholder (no player)
config.macros.player.html.none=' \
	<table id="%i%" width="%w%" height="%h%" style="background-color:#111;border:0;margin:0;padding:0;"> \
	<tr style="background-color:#111;border:0;margin:0;padding:0;"> \
	<td width="%w%" height="%h%" style="background-color:#111;color:#ccc;border:0;margin:0;padding:0;text-align:center;"> \
	&nbsp; \
	%u% \
	&nbsp; \
	</td></tr></table>';
//}}}

//{{{
// JPG/GIF/PNG still images
config.macros.player.html.image='\
	<a href="%u%" target="_blank"><img width="%w%" height="%h%" style="display:%s%;" src="%u%"></a>';
//}}}

//{{{
// IFRAME web page viewer
config.macros.player.html.iframe='\
	<iframe id="%i%" width="%w%" height="%h%" style="display:%s%;background:#fff;" src="%u%"></iframe>';
//}}}

//{{{
// Windows Media Player
// v7.1 ID: classid=CLSID:6BF52A52-394A-11d3-B153-00C04F79FAA6
// v9	ID: classid=CLSID:22d6f312-b0f6-11d0-94ab-0080c74c7e95
config.macros.player.html.windows=' \
	<object id="%i%" width="%w%" height="%h%" style="margin:0;padding:0;width:%w%;height:%h%px;" \
		classid="CLSID:22d6f312-b0f6-11d0-94ab-0080c74c7e95" \
		codebase="http://activex.microsoft.com/activex/controls/mplayer/en/nsmp2inf.cab#Version=6,4,5,715" \
		align="baseline" border="0" \
		standby="Loading Microsoft Windows Media Player components..." \
		type="application/x-oleobject"> \
		<param name="FileName" value="%u%"> <param name="ShowControls" value="%s%"> \
		<param name="ShowPositionControls" value="1"> <param name="ShowAudioControls" value="1"> \
		<param name="ShowTracker" value="1"> <param name="ShowDisplay" value="0"> \
		<param name="ShowStatusBar" value="1"> <param name="AutoSize" value="1"> \
		<param name="ShowGotoBar" value="0"> <param name="ShowCaptioning" value="0"> \
		<param name="AutoStart" value="%a%"> <param name="AnimationAtStart" value="1"> \
		<param name="TransparentAtStart" value="0"> <param name="AllowScan" value="1"> \
		<param name="EnableContextMenu" value="1"> <param name="ClickToPlay" value="1"> \
		<param name="InvokeURLs" value="1"> <param name="DefaultFrame" value="datawindow"> \
		%x% \
		<embed src="%u%" style="margin:0;padding:0;width:%w%;height:%h%px;" \
			align="baseline" border="0" width="%w%" height="%h%" \
			type="application/x-mplayer2" \
			pluginspage="http://www.microsoft.com/windows/windowsmedia/download/default.asp" \
			name="%i%" showcontrols="%s%" showpositioncontrols="1" \
			showaudiocontrols="1" showtracker="1" showdisplay="0" \
			showstatusbar="%s%" autosize="1" showgotobar="0" showcaptioning="0" \
			autostart="%a%" autorewind="0" animationatstart="1" transparentatstart="0" \
			allowscan="1" enablecontextmenu="1" clicktoplay="0" invokeurls="1" \
			defaultframe="datawindow"> \
		</embed> \
	</object>';
//}}}

//{{{
// RealNetworks' RealOne Player
config.macros.player.html.realone=' \
	<table width="%w%" style="border:0;margin:0;padding:0;"><tr style="border:0;margin:0;padding:0;"><td style="border:0;margin:0;padding:0;"> \
	<object id="%i%" width="%w%" height="%h%" style="margin:0;padding:0;" \
		CLASSID="clsid:CFCDAA03-8BE4-11cf-B84B-0020AFBBCCFA"> \
		<PARAM NAME="CONSOLE" VALUE="player"> \
		<PARAM NAME="CONTROLS" VALUE="ImageWindow"> \
		<PARAM NAME="AUTOSTART" Value="%a%"> \
		<PARAM NAME="MAINTAINASPECT" Value="true"> \
		<PARAM NAME="NOLOGO" Value="true"> \
		<PARAM name="BACKGROUNDCOLOR" VALUE="#333333"> \
		<PARAM NAME="SRC" VALUE="%u%"> \
		%x% \
		<EMBED width="%w%" height="%h%" controls="ImageWindow" type="audio/x-pn-realaudio-plugin" style="margin:0;padding:0;" \
			name="%i%" \
			src="%u%" \
			console=player \
			maintainaspect=true \
			nologo=true \
			backgroundcolor=#333333 \
			autostart=%a%> \
		</OBJECT> \
	</td></tr><tr style="border:0;margin:0;padding:0;"><td style="border:0;margin:0;padding:0;"> \
	<object id="%i%_controls" width="%w%" height="60" style="margin:0;padding:0;display:%s%" \
		CLASSID="clsid:CFCDAA03-8BE4-11cf-B84B-0020AFBBCCFA"> \
		<PARAM NAME="CONSOLE" VALUE="player"> \
		<PARAM NAME="CONTROLS" VALUE="All"> \
		<PARAM NAME="NOJAVA" Value="true"> \
		<PARAM NAME="MAINTAINASPECT" Value="true"> \
		<PARAM NAME="NOLOGO" Value="true"> \
		<PARAM name="BACKGROUNDCOLOR" VALUE="#333333"> \
		<PARAM NAME="SRC" VALUE="%u%"> \
		%x% \
		<EMBED WIDTH="%w%" HEIGHT="60" NOJAVA="true" type="audio/x-pn-realaudio-plugin" style="margin:0;padding:0;display:%s%" \
			controls="All" \
			name="%i%_controls" \
			src="%u%" \
			console=player \
			maintainaspect=true \
			nologo=true \
			backgroundcolor=#333333> \
		</OBJECT> \
	</td></tr></table>';
//}}}

//{{{
// QuickTime Player
config.macros.player.html.quicktime=' \
	<OBJECT ID="%i%" WIDTH="%w%" HEIGHT="%h%" style="margin:0;padding:0;" \
		CLASSID="clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B" \
		CODEBASE="http://www.apple.com/qtactivex/qtplugin.cab"> \
		<PARAM name="SRC" VALUE="%u%"> \
		<PARAM name="AUTOPLAY" VALUE="%a%"> \
		<PARAM name="CONTROLLER" VALUE="%s%"> \
		<PARAM name="BGCOLOR" VALUE="#333333"> \
		<PARAM name="SCALE" VALUE="aspect"> \
		<PARAM name="SAVEEMBEDTAGS" VALUE="true"> \
		%x% \
		<EMBED name="%i%" WIDTH="%w%" HEIGHT="%h%" style="margin:0;padding:0;" \
			SRC="%u%" \
			AUTOPLAY="%a%" \
			SCALE="aspect" \
			CONTROLLER="%s%" \
			BGCOLOR="#333333" \
			EnableJavaSript="true" \
			PLUGINSPAGE="http://www.apple.com/quicktime/download/"> \
		</EMBED> \
	</OBJECT>';
//}}}

//{{{
// Flash Player
config.macros.player.html.flash='\
	<object id="%i%" width="%w%" height="%h%" style="margin:0;padding:0;" \
		classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" \
		codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,29,0"> \
		<param name="movie" value="%u%"> \
		<param name="quality" value="high"> \
		<param name="SCALE" value="exactfit"> \
		<param name="bgcolor" value="333333"> \
		%x% \
		<embed name="%i%" src="%u%" style="margin:0;padding:0;" \
			height="%h%" width="%w%" quality="high" \
			pluginspage="http://www.macromedia.com/go/getflashplayer" \
			type="application/x-shockwave-flash" scale="exactfit"> \
		</embed> \
	</object>';
//}}}
/***
|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|PreviewPlugin|
|Source|http://www.TiddlyTools.com/#PreviewPlugin|
|Documentation|http://www.TiddlyTools.com/#PreviewPluginInfo|
|Version|1.8.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|add key-by-key wikified preview to any textarea input field|
Provides key-by-key ''LIVE PREVIEW'' of //formatted// tiddler content as you type input into a textarea (multi-line) edit field.
!!!!!Documentation
>see [[PreviewPluginInfo]]
!!!!!Configuration
<<<
Automatically freeze preview updates when a tiddler takes more than <<option txtPreviewAutoFreeze>> milliseconds to render.
<<<
!!!!!Revisions
<<<
2008.01.08 [*.*.*] plugin size reduction: documentation moved to ...Info tiddler
2007.12.04 [*.*.*] update for TW2.3.0: replaced deprecated core functions, regexps, and macros
2007.11.18 [1.8.1] in config.commands.previewTiddler, changed alt command text to use character-based "psuedo-checkbox" instead of embedded html fragment
2007.09.27 [1.8.0] split TidIDE preview functionality into separate stand-alone plugin (see [[TidIDEPlugin]]).  
|please see [[TidIDEPluginInfo]] for additional revision details|
2006.04.15 [0.5.0] Initial ALPHA release. Converted from inline script.
<<<
!!!!!Code
***/
// // version info
//{{{
version.extensions.PreviewPlugin= {major: 1, minor: 8, revision: 1, date: new Date(2007,11,18)};
//}}}

// //  macro definition
//{{{
if (config.options.txtPreviewAutoFreeze==undefined)
	config.options.txtPreviewAutoFreeze=250; // limit (in milliseconds) for auto-freezing preview display

config.macros.preview = {
	renderMsg: "rendering preview...",
	timeoutMsg: " (> %0ms)",
	freezeMsg: " - preview is frozen.  Press [refresh] to re-display.",
	handler: function(place,macroName,params) {
		var hide=params[0]=="hide"; if (hide) params.shift();
		var field=params[0];
		var height=params[1]; if (!height) height=15;
		var here=this.findContainingForm(place);
		if (!here) here=story.findContainingTiddler(place);
		if (!here) here=place.parentNode;
		if (!here) here=place;
		var elems=here.getElementsByTagName("textarea");
		if (field) for (var e=0; e<elems.length; e++)  // find matching textarea (by fieldname)
			if (elems[e].getAttribute("edit")==field) var ta=elems[e];
		else
			if (elems.length) var ta=elems[elems.length-1]; // default to last rendered text area
		if (!ta) {
			var elems=here.getElementsByTagName("input");
			if (field) for (var e=0; e<elems.length; e++)  // find matching input field (by fieldname)
				if (elems[e].getAttribute("edit")==field) var ta=elems[e];
			else
				if (elems.length) var ta=elems[elems.length-1]; // default to last rendered input field
		}
		if (!ta) return false; // no textarea or input field found... do nothing...
		var id=(new Date().getTime()).toString()+Math.random(); // unique instance ID
		ta.id=id+"_edit";
		ta.setAttribute("previewid",id+"_preview");
		ta.saved_onkeyup=ta.onkeyup;
		ta.onkeyup=function(ev) {
			if (this.saved_onkeyup) this.saved_onkeyup.apply(this,arguments);
			config.macros.preview.render(this.id,this.getAttribute("previewid"));
		}
		var html=this.html.replace(/%previd%/g,id+"_preview")
		html=html.replace(/%srcid%/g,id+"_edit");
		html=html.replace(/%hide%/g,hide?"none":"block");
		html=html.replace(/%limit%/g,config.options.txtPreviewAutoFreeze);
		html=html.replace(/%frozen%/g,hide?"checked":"");
		html=html.replace(/%height%/g,height);
		html=html.replace(/%halfheight%/g,height/2);
		createTiddlyElement(place,"span").innerHTML=html;
		this.render(id+"_edit",id+"_preview");
	},
	findContainingForm: function(e) {
		while (e && e.nodeName.toLowerCase()!="form") e=e.parentNode;
		return e;
	},
	render: function(srcid,previd,force) {
		var value=document.getElementById(srcid).value;
		var panel=document.getElementById(previd);
		var f=this.findContainingForm(panel);
		if (!f || (f.freeze.checked && !force)) return;
		var p=panel.firstChild; var d=f.domview; var h=f.htmlview; if (!p||!d||!h) return;
		p.innerHTML="";
		f.status.value=this.renderMsg;
		var start=new Date();
		wikify(value.replace(/\r/g,''),p);
		var end=new Date();
		this.renderDOM(previd);
		this.renderHTML(previd);
		f.status.value="elapsed: "+(end-start+1)+"ms";
		// automatically suspend preview updates for slow rendering tiddlers
		if (end-start+1>config.options.txtPreviewAutoFreeze) {
			f.freeze.checked=true;
			f.status.value+=this.timeoutMsg.format([config.options.txtPreviewAutoFreeze]);
		}
		if (f.freeze.checked) f.status.value+=this.freezeMsg;
	},
	renderDOM: function(id) {
		var panel=document.getElementById(id);
		var f=this.findContainingForm(panel); if (!f) return;
		var p=panel.firstChild; var d=f.domview; var h=f.htmlview; if (!p||!d||!h) return;
		var height=p.getAttribute("height");
		p.style.height=((f.dom.checked||f.html.checked)?height/2:height)+"em";
		if (f.dom.checked) d.value=this.getNodeTree(p,"|  ");
		if (!d.style||!h.style) return;
		d.style.height=height/2+"em";
		d.style.display=f.dom.checked?"inline":"none";
		d.style.width=f.html.checked?"49.5%":"100%";
		h.style.width=f.dom.checked?"49.5%":"100%";
	},
	renderHTML: function(id) {
		var panel=document.getElementById(id);
		var f=this.findContainingForm(panel); if (!f) return;
		var p=panel.firstChild; var d=f.domview; var h=f.htmlview; if (!p||!d||!h) return;
		var height=p.getAttribute("height");
		p.style.height=((f.dom.checked||f.html.checked)?height/2:height)+"em";
		if (f.html.checked) h.value=this.formatHTML(p.innerHTML);
		if (!h.style||!d.style) return;
		h.style.height=height/2+"em";
		h.style.display=f.html.checked?"inline":"none";
		h.style.width=f.dom.checked?"49.5%":"100%";
		d.style.width=f.html.checked?"49.5%":"100%";
	},
	formatHTML: function(txt) {
		if (config.browser.isIE) return txt; // BYPASS - 4/24/2006 due to IE hang problem.  Will fix later...
		var out="";
		var indent="";
		var level=0;
		for (var i=0;i<txt.length;i++) {
			var c=txt.substr(i,1);
			if (c=="<") {
					if (txt.substr(i+1,1)=="/")  indent=indent.substr(0,indent.length-2);
				out+="\n"+indent;
				if (txt.substr(i+1,1)!="/" && txt.substr(i+1,3)!="br>" && txt.substr(i+1,2)!="p>" && txt.substr(i+1,3)!="hr>")  indent+="  ";
			}
			out+=c;
				if (c=="\n")
				out+=indent;
			if (c==">" && txt.substr(i+1,1)!="<")
				out+="\n"+indent;
		}
		return out;
	},
	getNodeTree: function(theNode,theIndent,showPath,inline,thePrefix,thePath)
	{
		if (!theNode) return "";
		if (!thePrefix) thePrefix="";
		if (!thePath) thePath="";
		var mquote='"'+(inline?"{{{":"");
		var endmquote=(inline?"}}}":"")+'"';
		// generate output for this node
		var out = thePrefix;
		if (showPath && thePath.length)
				out += (inline?"//":"")+thePath.substr(1)+":"+(inline?"//":"")+"\r\n"+thePrefix;
		if (theNode.className=="DOMViewer")
			return out+'[DOMViewer]\r\n'; // avoid self-referential recursion
		out += (inline?"''":"")+theNode.nodeName.toUpperCase()+(inline?"''":"");
		if (theNode.nodeName=="#text")
			out += ' '+mquote+theNode.nodeValue.replace(/\n/g,'\\n')+endmquote;
		if (theNode.className)
			out += ' class='+mquote+theNode.className+endmquote;
		if (theNode.type)
			out += ' type='+mquote+theNode.type+endmquote;
		if (theNode.id)
			out += ' id='+mquote+theNode.id+endmquote;
		if (theNode.name)
			out += " "+theNode.name+(theNode.value?"="+mquote+theNode.value+endmquote:"");
		if (theNode.href)
			out += ' href='+mquote+theNode.href+endmquote;
		if (theNode.src)
			out += ' src='+mquote+theNode.src+endmquote;
		if (theNode.attributes && theNode.getAttribute("tiddlyLink")!=undefined)
			out += ' tiddler='+mquote+theNode.getAttribute("tiddlyLink")+endmquote;
		out += "\r\n";
		// recursively generate output for child nodes
		thePath=thePath+"."+theNode.nodeName.toLowerCase();
		thePrefix=theIndent+thePrefix;
		for (var i=0;i<theNode.childNodes.length;i++)
		{
			var thisChild=theNode.childNodes.item(i);
			var theNum=(inline?"~~":"(")+(i+1)+(inline?"~~":")");
			out += this.getNodeTree(thisChild,theIndent,showPath,inline,thePrefix,thePath+theNum);
		}
		return out;
	},
	html: " <form style='width:100%'><span id='%previd%' editID='%srcid%' style='display:%hide%'><div class='viewer' \
			height='%height%' style='margin:0;margin-top:.5em;height:%height%em;overflow:auto;white-space:normal'> \
			&nbsp; \
			</div> \
		<!-- DOM and HTML viewers --> \
		<textarea name=domview cols=60 rows=12 wrap=off \
			onfocus='this.select()' style='display:none;width:100%;height:%halfheight%em;'></textarea><!-- \
		--><textarea name=htmlview cols=60 rows=12 wrap=off \
			onfocus='this.select()' style='display:none;width:100%;height:%halfheight%em;'></textarea> \
		<!-- status line, preview option checkboxes, run/refresh buttons --> \
		<table width='100%' style='border:0;padding:0;margin:0'><tr style='border:0;padding:0;margin:0'> \
		<td style='border:0;padding:0;margin:0'><!-- \
			--><input type=text name=status style='padding:0;width:100%;' \
				title='ELAPSED: time (in milliseconds) used to render tiddler content in preview display'><!-- \
		--></td><td style='width:1%;border:0;padding:0;margin:0;'><!-- \
			--><input type=text name=limit size='6' maxlength='6' style='padding:0;width:5em;text-align:center' \
				value='%limit%ms' title='TIME LIMIT: maximum rendering time (in milliseconds) before auto-freezing preview' \
				onfocus='this.select()' \
				onchange='var val=this.value.replace(/[^0-9]/g,\"\"); if (!val.length) val=this.defaultValue; \
					this.value=val+\"ms\"; config.options.txtPreviewAutoFreeze=val; saveOptionCookie(\"txtPreviewAutoFreeze\"); \
					this.form.freeze.checked=false; config.macros.preview.render(\"%srcid%\",\"%previd%\",true);'><!-- \
		--></td><td style='width:1%;border:0;padding:0;margin:0;'><!-- \
			--><input type=text name=height size='4' maxlength='4' style='padding:0;width:4em;text-align:center' \
				value='%height%em' title='HEIGHT: size (in \"ems\") of preview area, including controls' \
				onfocus='this.select()' \
				onchange='var val=this.value.replace(/[^0-9]/g,\"\");  if (!val.length) val=this.defaultValue; \
					this.value=val+\"em\"; document.getElementById(\"%previd%\").firstChild.setAttribute(\"height\",val); \
					config.macros.preview.render(\"%srcid%\",\"%previd%\",true)'><!-- \
		--></td><td style='width:1%;border:0;padding:0;margin:0;text-align:right;white-space:nowrap'> \
			<input type=checkbox name=dom style='display:inline;width:auto;margin:1px;' \
				title='show Document Object Model (DOM) information' \
				onclick='config.macros.preview.renderDOM(\"%previd%\");'>DOM \
			<input type=checkbox name=html style='display:inline;width:auto;margin:1px;' \
				title='show rendered HTML' \
				onclick='config.macros.preview.renderHTML(\"%previd%\");'>HTML \
			<input type=checkbox name=freeze style='display:inline;width:auto;margin:1px;' %frozen% \
				title='do not update preview display as changes are made' \
				onclick='var p=document.getElementById(\"%previd%\");  \
					if (this.checked) this.form.status.value+=config.macros.preview.freezeMsg; \
					else config.macros.preview.render(\"%srcid%\",\"%previd%\",true);'>freeze \
			<input type=button style='display:inline;width:auto;' value='refresh' \
				title='update preview display' \
				onclick='config.macros.preview.render(\"%srcid%\",\"%previd%\",true)'> \
		</td></tr></table> \
		</span></form>"
}
//}}}

// // toolbar definition
//{{{
config.commands.previewTiddler = {
	text: 'preview',
	tooltip: 'show key-by-key preview',
	text_alt: '\u221Apreview',
	handler: function(event,src,title) {
		var here=story.findContainingTiddler(src); if (!here) return;
		var elems=here.getElementsByTagName("span");
		for (var e=0; e<elems.length; e++) {
			if (elems[e].getAttribute("editid")) {
				var show=elems[e].style.display=="none";
				src.innerHTML=show?this.text_alt:this.text;
				elems[e].style.display=show?"block":"none";
				config.macros.preview.findContainingForm(elems[e]).freeze.checked=!show;
				if (show) config.macros.preview.render(elems[e].getAttribute("editid"),elems[e].id);
			}
		}
		return false;
	}
};
//}}}
/***
|Name|PreviewPluginInfo|
|Source|http://www.TiddlyTools.com/#PreviewPlugin|
|Documentation|http://www.TiddlyTools.com/#PreviewPluginInfo|
|Version|1.8.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|documentation|
|Description|documentation for PreviewPlugin|
Provides key-by-key ''LIVE PREVIEW'' of //formatted// tiddler content as you type input into a textarea (multi-line) edit field.
!!!!!Usage
<<<
Syntax: (in tiddler content)
{{{
<<preview hide fieldname height>>
}}}
//OR// (in [[EditTemplate]])
{{{
<span macro='preview hide fieldname height'></span>
}}}
where:
* 'hide' (optional)<br>is a keyword that causes the preview display to be initially hidden when created.  This is typically used in an [[EditTemplate]] definition, in conjunction with the 'previewTiddler' toolbar syntax (see below).
* fieldname (optional)<br>specifies the name of the tiddler field that is being previewed.  It corresponds to the fieldname specified in the {{{<span class='editor' macro='edit fieldname height'></span>}}} syntax used to define the textarea edit field, and is used to locate and access the source content that is to be previewed.  When omitted, the previewer will automatically associate itself with the last textarea control that precedes it in the rendered tiddler editor display.
* height (optional)<br>defines the total height of the previewer display (including the status line and controls), using CSS "em" (line height) measurements.  The default height value is "15em" (i.e., approximately 15 lines of standard-sized text)

In addition to the preview macro itself, you can place the following in your [[EditTemplate]] to add a tiddler toolbar command that enables you to toggle the preview display once it has been created:
{{{
<span class='toolbar' macro='toolbar previewTiddler'></span>
}}}
when clicked, this command will show/hide ALL preview controls that are displayed in the current tiddler.  Note that, when desired, you can also embed this toolbar command directly into a tiddler by entering the "{{{<<toolbar previewTiddler>>}}}" syntax in the tiddler source.
<<<
!!!!!Examples
<<<
in [[EditTemplate]]:
{{{
<div class='editor' macro='edit foobar 5'></div>
<div class='editor' macro='preview hide foobar 10'></div>
}}}
OR, embedded in tiddler content:
{{{
<<edit foobar 5>><<preview foobar 10>>
}}}
{{smallform{
<<edit foobar 5>><<preview foobar 10>>}}}
By default, the preview display is automatically rendered each time a key is typed into the tiddler content edit field.  As soon as changes are entered, they will be instantly visible within the preview display.  Unfortunately, the partial tiddler source definitions that occur //during// editing may somtimes cause rendering problems, and some exceptionally complex tiddlers make take an unusually long amount of time to completely render their content.   In such cases, key-by-key display updates are undesirable or impractical.

You can select the ''freeze'' checkbox to suspend automatic key-by-key preview display updates.  The preview display will not be re-rendered again until you press the ''refresh'' button or clear the 'freeze' checkbox.  The preview display will also automatically freeze whenever the //rendering time// exceeds a pre-determined time limit (see configuration section), specified in milliseconds.  Note: the ''actual elapsed time'' used to process and render any given content is reported in the preview "status bar" whenever that content is previewed.

In addition to a 'wikified' preview, the previewer display can show a ''DOM viewer'' and/or an ''HTML viewer'' that are also updated with each keystroke.  These text-based displays can be helpful while attempting to correct or enhance the formatting of tiddler content, especially when complex combinations of wiki-syntax produce unexpected or undesired results.
<<<
/%
|''URL:''|http://ptw.sourceforge.net/ptwe.html|
|''Description:''|BramChen's Extensions for TiddlyWiki|
|''Author:''|BramChen|
%/
This package provides a toolbar of interactive 'power tools' that you can use while editing a tiddler to quickly insert TiddlyWiki tiddler links, images, macros, etc. or common formatting sequences directly into tiddler content, as well as perform other functions (such as find/replace, sort, split, convert, etc.) that can be used to modify the current tiddler's source content in a variety of ways.

<<tiddler QuickEditToolbar with: show>>
!!!!!Installation:
<<<
Individual ~QuickEdit buttons are defined in separate tiddlers (e.g., [[QuickEdit_replace]]) that have also been //transcluded// into a single toolbar definition named [[QuickEditToolbar]].  You can edit this definition to add, remove, or rearrange the toolbar buttons to best suit your needs, and then embed the [[QuickEditToolbar]] tiddler into your document's [[EditTemplate]], like this:
{{{
<div macro='tiddler QuickEditToolbar'></div>
}}}
Next, in order to support some of the formatting 'shortcuts' provided by the toolbar, add a reference to the shortcuts CSS class definitions in your [[StyleSheet]]:
{{{
[[StyleSheetShortcuts]]
}}}
By default, the QuickEdit toolbar is hidden until you enable it by using the ''toggleQuickEdit'' command, which you can add to the ~EditToolbar definition in [[ToolbarCommands]]:
{{{
|EditToolbar|... toggleQuickEdit ...|
}}}
You can also toggle the ~QuickEdit toolbar display via a single checkbox option that can be added to [[SideBarOptions]] (or any other desired location):
{{{
<<option chkShowQuickEdit>> show QuickEdit toolbar
}}}
Note: You can 'hard-code' the ''chkShowQuickEdit'' setting, so that the toolbar will be //initially// displayed, by creating a tiddler (e.g., ConfigTweaks), tagged with <<tag systemConfig>>, containing:
{{{
config.options.chkShowQuickEdit=true;
}}}
Alternatively, if you want the toolbar to //always// be displayed, regardless of the option setting, you can add a special keyword, ''show'', to the [[EditTemplate]] syntax, like this:
{{{
<div macro='tiddler QuickEditToolbar with: show'></div>
}}}
<<<
/***
|Name|QuickEditPlugin|
|Source|http://www.TiddlyTools.com/#QuickEditPlugin|
|Documentation|http://www.TiddlyTools.com/#QuickEditPackage|
|Version|2.4.4|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 3.0 License|http://creativecommons.org/licenses/by-sa/3.0/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Description|Support functions for [[QuickEditPackage]]: utility functions, toolbar commands, stylesheets|
!!!!!Documentation
>see [[QuickEditPackage]] for details
!!!!!Revisions
<<<
2011.02.14 2.4.4 fix OSX error: use picker.file.path
2009.06.11 2.4.3 added keyup() function to abbreviate listbox handling for CR and ESC
2009.05.07 2.4.2 added processed() function to abbreviate event handler code
2008.09.07 2.4.1 added removeCookie() function for compatibility with [[CookieManagerPlugin]]
2008.05.17 2.4.0 copied code from StickyPopupPlugin to remove dependency
2008.05.12 2.3.0 added "toggleQuickEdit" command handler (replaces inline script command)
2008.01.11 2.2.0 converted from inline script
2007.03.29 1.0.0 initial release (as inline script)
<<<
!!!!!Code
***/
//{{{
version.extensions.QuickEditPlugin= {major: 2, minor: 4, revision: 4, date: new Date(2011,2,14)};

// SET STYLESHEET
setStylesheet("\
.quickEdit a { border:2px outset ButtonFace; padding:0px 3px !important; \
	-moz-border-radius:.5em; -webkit-border-radius:.5em; \
	-moz-appearance:button !important; -webkit-appearance:push-button !important; \
	background-color:ButtonFace; color:ButtonText !important;  \
	line-height:200%; font-weight:normal; } \
.quickEdit a:hover { border: 2px inset ButtonFace; background-color:ButtonFace; }\
", "quickEditStyles");

// REMOVE COOKIE
if (window.removeCookie===undefined) {
	window.removeCookie=function(name) {
		document.cookie = name+'=; expires=Thu, 01-Jan-1970 00:00:01 UTC; path=/;'; 
	}
}

// UTILITY FUNCTIONS
config.quickEdit = {
	processed: function(ev) { ev=ev||window.event;
		ev.cancelBubble=true;
		if(ev.stopPropagation) ev.stopPropagation();
		return false;
	},
	keyup: function(ev){ var k=(ev||window.event).keyCode;
		if (k==13) this.onclick();
		if (k==27) Popup.remove();
	},
	getField: function(where) {
		var here=story.findContainingTiddler(where); if (!here) return null;
		var e=story.getTiddlerField(here.getAttribute("tiddler"),"text");
		if (e&&e.getAttribute("edit")=="text") return e;
		return null;
	},
	setSelection: function(where,newtext) {
		var e=this.getField(where); if (!e) return false;
		e.focus(); replaceSelection(e,newtext);
		return false;
	},
	wrapSelection: function(where,before,after) {
		var e=this.getField(where); if (!e) return false;
		e.focus(); replaceSelection(e,before+config.quickEdit.getSelection(e)+after);
		return false;
	},
	getSelection: function(e) {
		var seltext="";
		if (e&&e.setSelectionRange)
			seltext=e.value.substr(e.selectionStart,e.selectionEnd-e.selectionStart);
		else if (document.selection) {
			var range = document.selection.createRange();
			if (range.parentElement()==e) seltext=range.text
		}
		return seltext;
	},
	promptForFilename: function(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.modeOpen);
				var thispath = Components.classes['@mozilla.org/file/local;1'].createInstance(Components.interfaces.nsILocalFile);
				thispath.initWithPath(path);
				picker.displayDirectory=thispath;
				picker.defaultExtension='jpg';
				picker.defaultString=file;
				picker.appendFilters(nsIFilePicker.filterAll|nsIFilePicker.filterImages);
				if (picker.show()!=nsIFilePicker.returnCancel)
					var result="file:///"+picker.file.path.replace(/\\/g,'/');
			}
			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|*.*|JPG files|*.jpg|GIF files|*.gif|PNG files|*.png|';
				s.FilterIndex=1; // default to JPG
				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;
	}
}
//}}}

//{{{
if (config.options.chkShowQuickEdit===undefined) config.options.chkShowQuickEdit=false;
config.commands.toggleQuickEdit = {
	hideReadOnly: true,
	getText: function() { return config.options.chkShowQuickEdit?'\u221Aquickedit':'quickedit'; },

	tooltip: 'show QuickEdit toolbar buttons',
	handler: function(event,src,title) {
		var opt='chkShowQuickEdit';
		config.options[opt]=!config.options[opt];
		config.macros.option.propagateOption(opt,"checked", config.options[opt],"input");
		if (config.options[opt]) saveOptionCookie(opt);	else removeCookie(opt);
		src.innerHTML=config.commands.toggleQuickEdit.getText();
		story.forEachTiddler(function(t,e){if (story.isDirty(t)) refreshElements(e);});
		return false;
	}
};
//}}}

// // COPIED FROM [[StickyPopupPlugin]] TO ELIMINATE PLUGIN DEPENDENCY
//{{{
if (config.options.chkStickyPopups==undefined) config.options.chkStickyPopups=false;
Popup.stickyPopup_onDocumentClick = function(ev)
{
	// if click is in a sticky popup, ignore it so popup will remain visible
	var e = ev ? ev : window.event; var target = resolveTarget(e);
	var p=target; while (p) {
		if (hasClass(p,"popup") && (hasClass(p,"sticky")||config.options.chkStickyPopups)) break;
		else p=p.parentNode;
	}
	if (!p) // not in sticky popup (or sticky popups disabled)... use normal click handling
		Popup.onDocumentClick(ev);
	return true;
};
try{removeEvent(document,"click",Popup.onDocumentClick);}catch(e){};
try{addEvent(document,"click",Popup.stickyPopup_onDocumentClick);}catch(e){};
//}}}
/%
|Name|QuickEditToolbar|
|Source|http://www.TiddlyTools.com/#QuickEditToolbar|
|Version|2.4.4|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.2|
|Type|transclusion|
|Requires|QuickEditPlugin|
|Optional|QuickEdit_*|
|Description|format/insert TiddlyWiki content using toolbar buttons|

Usage:
* install [[QuickEditPlugin]] (runtime support functions)

* add the toolbar to [[EditTemplate]]:
	<div macro='tiddler QuickEditToolbar with: show'></div>

* 'show' (optional) forces the toolbar to always be displayed or,
  omit keyword and use <<option chkShowQuickEdit>> setting

* selected QuickEdit buttons can also be added individually to the
  regular tiddler toolbar by adding references directly in [[EditTemplate]]:
	<span class='toolbar' macro='tiddler QuickEdit_...'></span>

* see [[QuickEditPackage]] for additional installation options

%/{{hidden fine center quickEdit{
<<tiddler {{ // show/hide toolbar
	var here=story.findContainingTiddler(place); if (here) var tid=here.getAttribute('tiddler');
	var show='$1'!='$'+'1'||config.options.chkShowQuickEdit||tid=='QuickEditToolbar'; 
	place.style.display=show?'block':'none';
'';}}>>/%

TOOLBAR DEFINITION - add, remove, or re-order items as desired:
= = = = = = = = = =
%/<<tiddler QuickEdit_format>>/%
%/<<tiddler QuickEdit_align>>/%
%/<<tiddler QuickEdit_color>>/%
%/<<tiddler QuickEdit_font>>/%
%/<<tiddler QuickEdit_custom>>/%
%/ &nbsp;/% (SPACER)
%/<<tiddler QuickEdit_replace>>/%
%/<<tiddler QuickEdit_split>>/%
%/<<tiddler QuickEdit_sort>>/%
%/<<tiddler QuickEdit_convert>>/%
%/ &nbsp;/% (SPACER)
%/<<tiddler QuickEdit_link>>/%
%/<<tiddler QuickEdit_insert>>/%
%/<<tiddler QuickEdit_macro>>/%
%/<<tiddler QuickEdit_image>>/%
%/}}}
/%
|Name|QuickEdit_align|
|Source|http://www.TiddlyTools.com/#QuickEdit_align|
|Version|2.4.3|
|Author|Eric Shulman|
|License|see http://www.TiddlyTools.com/#QuickEditPlugin|
|Type|html|
|Requires|QuickEditPlugin|
|Description|quickedit - text alignment|

Usage: see  http://www.TiddlyTools.com/#QuickEditToolbar

%/<html><hide linebreaks><a href="javascript:;" class="tiddlyLink" tabindex="-1" 
title="align text"
onclick="var p=Popup.create(this); if (!p) return false; p.className+=' sticky smallform';
	var s=createTiddlyElement(p,'select'); s.button=this;
	s.options[0]=new Option('select text alignment...','');
	s.options[s.length]=new Option('left','left');
	s.options[s.length-1].title='{{left{...}}}';
	s.options[s.length]=new Option('center','center');
	s.options[s.length-1].title='{{center{...}}}';
	s.options[s.length]=new Option('right','right');
	s.options[s.length-1].title='{{right{...}}}';
	s.options[s.length]=new Option('justify','justify');
	s.options[s.length-1].title='{{justify{...}}}';
	s.options[s.length]=new Option('float left','floatleft');
	s.options[s.length-1].title='{{floatleft{...}}}';
	s.options[s.length]=new Option('float right','floatright');
	s.options[s.length-1].title='{{floatright{...}}}';
	s.size=s.length;
	s.onclick=function(){ if (!this.value.length) return;
		config.quickEdit.wrapSelection(this.button,'{{'+this.value+'{','}}}');
		Popup.remove(); return false;
	};
	s.onkeyup=config.quickEdit.keyup;
	Popup.show();
	s.focus();
	return config.quickEdit.processed(event);"
>align</a></html>
/%
|Name|QuickEdit_color|
|Source|http://www.TiddlyTools.com/#QuickEdit_color|
|Version|2.4.3|
|Author|Eric Shulman|
|License|see http://www.TiddlyTools.com/#QuickEditPlugin|
|Type|html|
|Requires|QuickEditPlugin|
|Description|quickedit - text/background color|

Usage: see  http://www.TiddlyTools.com/#QuickEditToolbar

%/<html><hide linebreaks><a href="javascript:;" class="tiddlyLink" tabindex="-1" 
title="text/background color - @@color:#RGB;background-color:#RGB;...@@"
onclick="var p=Popup.create(this,null,'popup sticky smallform'); if (!p) return false;
 	p.style.padding='2px';
	function hex(d) { return '0123456789ABCDEF'.substr(d,1); }
	var fg=createTiddlyElement(p,'select'); fg.button=this;
	fg.style.width='12em';
	fg.options[0]=new Option('text color...','');
	fg.options[1]=new Option('\xa0 or enter a value','_ask');
	fg.options[2]=new Option('\xa0 or use default color','');
	for (var r=0;r<16;r+=3) for (var g=0;g<16;g+=3) for (var b=0;b<16;b+=3) {
		var label=hex(r)+hex(g)+hex(b);
		fg.options[fg.length]=new Option(label,'#'+label);
		fg.options[fg.length-1].style.color='#'+label;
	}
	fg.onchange=function(){ var val=this.value;
		if (val=='_ask') { val=prompt('Enter a CSS color value');
		if (!val||!val.length) return false; }
		this.options[0].value=val; this.options[0].text=val.length?'text: '+val:'text color...';
		var bg=this.nextSibling;
		for (var i=3;i<bg.options.length;i++) bg.options[i].style.color=val;
		var preview=this.nextSibling.nextSibling.nextSibling;
		var t=config.quickEdit.getSelection(config.quickEdit.getField(this.button));
		t=t.replace(/^@@(color\:.+;)?(background-color\:.+;)?/,'').replace(/@@$/,'');
		if (!t.length) t='~AaBbCcDdEeFfGgHhIiJj 1234567890';
		var fg=this.value; if (fg.length) fg='color:'+fg+';';
		var bg=this.nextSibling.value; if (bg.length) bg='background-color:'+bg+';';
		if (fg.length||bg.length) t='@@'+fg+bg+t+'@@';
		removeChildren(preview); wikify(t,preview);
		this.selectedIndex=0; return false;
	};
	var bg=createTiddlyElement(p,'select'); bg.button=this;
	bg.style.width='12em';
	bg.options[0]=new Option('background color...','');
	bg.options[1]=new Option('\xa0 or enter a value','_ask');
	bg.options[2]=new Option('\xa0 or use default color','');
	for (var r=0;r<16;r+=3) for (var g=0;g<16;g+=3) for (var b=0;b<16;b+=3) {
		var label=hex(15-r)+hex(15-g)+hex(15-b);
		bg.options[bg.length]=new Option(label,'#'+label);
		bg.options[bg.length-1].style.backgroundColor='#'+label;
	}
	bg.onchange=function(){ var val=this.value;
		if (val=='_ask') { val=prompt('Enter a CSS color value');
		if (!val||!val.length) return false; }
		this.options[0].value=val;
		this.options[0].text=val.length?'background: '+val:'background color...';
		var fg=this.previousSibling;
		for (var i=3;i<fg.options.length;i++) fg.options[i].style.backgroundColor=val;
		var preview=this.nextSibling.nextSibling;
		var t=config.quickEdit.getSelection(config.quickEdit.getField(this.button));
		t=t.replace(/^@@(color\:.+;)?(background-color\:.+;)?/,'').replace(/@@$/,'');
		if (!t.length) t='~AaBbCcDdEeFfGgHhIiJj 1234567890';
		var fg=this.previousSibling.value; if (fg.length) fg='color:'+fg+';';
		var bg=this.value; if (bg.length) bg='background-color:'+bg+';';
		if (fg.length||bg.length) t='@@'+fg+bg+t+'@@';
		removeChildren(preview); wikify(t,preview);
		this.selectedIndex=0; return false;
	};
	var b=createTiddlyElement(p,'input',null,null,null,{type:'button'}); b.button=this;
	b.value='ok'; b.style.width='4em';
	b.onclick=function() {
		var fg=this.previousSibling.previousSibling.value; if (fg.length) fg='color:'+fg+';';
		var bg=this.previousSibling.value; if (bg.length) bg='background-color:'+bg+';';
		var t=config.quickEdit.getSelection(config.quickEdit.getField(this.button));
		t=t.replace(/^@@(color\:.+;)?(background-color\:.+;)?/,'').replace(/@@$/,'');
		if (fg.length||bg.length) config.quickEdit.setSelection(this.button,'@@'+fg+bg+t+'@@');
		Popup.remove(); return false;
	};
	var preview=createTiddlyElement(p,'div',null,'viewer'); var s=preview.style;
	s.border='1px solid'; s.margin='2px'; s.width='24em'; s.padding='3px'; s.MozBorderRadius='3px';
	s.overflow='hidden'; s.textAlign='center'; s.whiteSpace='normal';
	var t=config.quickEdit.getSelection(config.quickEdit.getField(this));
	wikify(t.length?t:'~AaBbCcDdEeFfGgHhIiJj 1234567890',preview);
	Popup.show();
	event.cancelBubble=true;if(event.stopPropagation)event.stopPropagation();return false;"
>color</a></html>
/%
|Name|QuickEdit_convert|
|Source|http://www.TiddlyTools.com/#QuickEdit_convert|
|Version|2.4.3|
|Author|Eric Shulman|
|License|see http://www.TiddlyTools.com/#QuickEditPlugin|
|Type|html|
|Requires|QuickEditPlugin|
|Description|quickedit - convert between comma/tab-separated and TW table format|

Usage: see  http://www.TiddlyTools.com/#QuickEditToolbar

%/<html><hide linebreaks><a href="javascript:;" class="tiddlyLink" tabindex="-1" 
title="convert between comma/tab-separated and TW table format"
onclick="var e=config.quickEdit.getField(this);
	if (e) e.focus(); var txt=config.quickEdit.getSelection(e);
	if (txt.indexOf(',')+txt.indexOf('\t')+txt.indexOf('|')==-3) {
		alert('Please select text containing tabs, commas, or TiddlyWiki table syntax.');
		return false;
	}
	var p=Popup.create(this); if (!p) return false; p.className+=' sticky smallform';
	var s=createTiddlyElement(p,'select'); s.button=this;
	s.options[0]=new Option('select a converter...','');
	if (txt.indexOf(',')!=-1) {
		s.options[s.length]=new Option('commas -> table','commasToTable');
		s.options[s.length]=new Option('commas -> tabs','commasToTabs');
	}
	if (txt.indexOf('\t')!=-1) {
		s.options[s.length]=new Option('tabs -> table','tabsToTable');
		s.options[s.length]=new Option('tabs -> commas','tabsToCommas');
	}
	if (txt.indexOf('|')!=-1) {
		s.options[s.length]=new Option('table -> tabs','tableToTabs');
		s.options[s.length]=new Option('table -> commas','tableToCommas');
	}
	s.size=s.length;
	s.onclick=function(){ if (!this.value.length) return;
	        var e=config.quickEdit.getField(this.button); if (!e) return false;
		e.focus(); var txt=config.quickEdit.getSelection(e);
		switch(this.value) {
			case 'tabsToTable':
				txt=txt.replace(/\t/g,'|').replace(/^|$/g,'|');
				txt=txt.replace(/\n/g,'|\n|').replace(/^\|$/g,'');
				break;
			case 'tableToTabs':
				txt=txt.replace(/\t/g,' ').replace(/\|/g,'\t');
				txt=txt.replace(/^\t/g,'').replace(/\t$/g,'');
				txt=txt.replace(/\n\t/g,'\n').replace(/\t\n/g,'\n');
				break;
			case 'commasToTable':
				txt=txt.replace(/,/g,'|').replace(/^|$/g,'|');
				txt=txt.replace(/\n/g,'|\n|').replace(/^\|$/g,''); 
				break;
			case 'tableToCommas':
				txt=txt.replace(/,/g,' ').replace(/\|/g,',');
				txt=txt.replace(/^,/g,'').replace(/,$/g,''); 
				txt=txt.replace(/\n,/g,'\n').replace(/,\n/g,'\n'); 
				break;
			case 'tabsToCommas':
				txt=txt.replace(/\t/g,',');
				break;
			case 'commasToTabs':
				txt=txt.replace(/,/g,'\t');
				break;
		}
		replaceSelection(e,txt);
		Popup.remove(); return false;
	};
	s.onkeyup=config.quickEdit.keyup;
	Popup.show();
	s.focus();
	return config.quickEdit.processed(event);"
>convert</a></html>
/%
|Name|QuickEdit_custom|
|Source|http://www.TiddlyTools.com/#QuickEdit_custom|
|Version|2.4.3|
|Author|Eric Shulman|
|License|see http://www.TiddlyTools.com/#QuickEditPlugin|
|Type|html|
|Requires|QuickEditPlugin|
|Description|quickedit - custom defined formats|

Usage: see  http://www.TiddlyTools.com/#QuickEditToolbar

!help
Reminders:

Custom formats are stored as an "HR-separated list" in [[QuickEdit_customList]], where the first line of each list item is the text 'label' to show in the droplist, followed by one or more lines of wiki content to be inserted into the tiddler source.

Substitution markers can be used to dynamically insert values into the formatted output: $1 inserts the tiddler editor's current selected text. $[[message|default value]] interactively prompts for a value to be inserted. $[[message|$1]] uses the selected text as the default value. $[[message|{{javascript}}]] calculates the default value using javascript code.
!end help

%/<html><hide linebreaks><a href="javascript:;" class="tiddlyLink" tabindex="-1" title="custom defined formats"
onclick="var p=Popup.create(this); if (!p) return false; p.className+=' sticky smallform';
	var s=createTiddlyElement(p,'select'); s.button=this;
	s.options[0]=new Option('select a custom format...','');
	var items=store.getTiddlerText('QuickEdit_customList','').split('\n----\n');
	for (var i=0; i<items.length; i++) {
		if (!items[i].length) continue; var lines=items[i].split('\n');
		var label=lines.shift(); var val=lines.join('\n');
		s.options[s.length]=new Option(label,val); s.options[s.length-1].title=val;
	}
	s.options[s.length]=new Option('[Edit custom formats...]','_edit');
	s.options[s.length-1].title='add/change custom format definitions...';
	s.size=Math.min(s.length,15);
	s.onclick=function(){ if (!this.value.length) return;
		if (this.value=='_edit') {
			alert(store.getTiddlerText('QuickEdit_custom##help'));
			story.displayTiddler(story.findContainingTiddler(this.button),
				'QuickEdit_customList',DEFAULT_EDIT_TEMPLATE);
		} else {
		        var e=config.quickEdit.getField(this.button); if (!e) return false;
			e.focus(); var txt=config.quickEdit.getSelection(e);
			replaceSelection(e, this.value.replace(/\$\x31/g,txt)
				.replace(/\$\[\[[^\]]+\]\]/g, function(t){
					x=t.substr(3,t.length-5).split('|');
					var msg=x[0]; var def=x[1]||'';
					if (def.startsWith('{{')) {
						try{def=eval(def.substr(2,def.length-4))} catch(ex){showException(ex)}
					}
					return prompt(msg,def)||'';
				})
			);
		}
		Popup.remove(); return false;
	};
	s.onkeyup=config.quickEdit.keyup;
	Popup.show();
	s.focus();
	return config.quickEdit.processed(event);"
>custom</a></html>
timestamp
$[[enter a date|{{new Date().formatString('DDD, MMM DDth, YYYY hh12:0mm:0ssam')}}]]
----
scrollbox
@@display:block;height:10em;overflow:auto;$[[enter scrolling content|$1]]@@@@display:block;text-align:right;^^scroll for more...^^@@
----
nested slider
+++[$1]<<tiddler $1>>===
----
big red
@@font-size:36pt;color:red;$1@@
----
/%
|Name|QuickEdit_font|
|Source|http://www.TiddlyTools.com/#QuickEdit_font|
|Version|2.4.3|
|Author|Eric Shulman|
|License|see http://www.TiddlyTools.com/#QuickEditPlugin|
|Type|html|
|Requires|QuickEditPlugin|
|Description|quickedit - select font family|

Usage: see  http://www.TiddlyTools.com/#QuickEditToolbar

%/<html><hide linebreaks><a href="javascript:;" class="tiddlyLink" tabindex="-1" 
title="set font-family CSS attribute - @@font-family:facename;...@@"
onclick="var p=Popup.create(this); if (!p) return false; p.className+=' sticky smallform';
	var s=createTiddlyElement(p,'select'); s.button=this;
	s.options[0]=new Option('select a font family...','');
	var fonts=store.getTiddlerText('QuickEdit_fontList','').split('\n');
	for (var i=0; i<fonts.length; i++) {
		if (!fonts[i].length) continue;
		s.options[s.length]=new Option(fonts[i],fonts[i]);
		s.options[s.length-1].style.fontFamily=fonts[i];
	}
	s.options[s.length]=new Option('[Edit font list...]','_edit');
	s.options[s.length-1].title='enter fonts, one per line...';
	s.size=Math.min(s.length,15);
	s.onclick=function(){
		if (this.value=='_edit')
			story.displayTiddler(story.findContainingTiddler(this.button),'QuickEdit_fontList',DEFAULT_EDIT_TEMPLATE);			
		else
			config.quickEdit.wrapSelection(this.button,'@@font-family:\x22'+this.value+'\x22;','@@');
		Popup.remove(); return false;
	};
	s.onkeyup=config.quickEdit.keyup;
	Popup.show();
	s.focus();
	return config.quickEdit.processed(event);"
>font</a></html>
Arial,helvetica,sans-serif
Times New Roman,times,serif
Courier,monospaced
/%
|Name|QuickEdit_format|
|Source|http://www.TiddlyTools.com/#QuickEdit_format|
|Version|2.4.3|
|Author|Eric Shulman|
|License|see http://www.TiddlyTools.com/#QuickEditPlugin|
|Type|html|
|Requires|QuickEditPlugin|
|Description|quickedit - basic text formats, headings, blockquotes, etc.|

Usage: see  http://www.TiddlyTools.com/#QuickEditToolbar

%/<html><hide linebreaks><a href="javascript:;" class="tiddlyLink" tabindex="-1" 
title="plain text (remove ALL formatting)" accesskey="P" 
onclick="var e=config.quickEdit.getField(this); if (e) e.focus(); var txt=config.quickEdit.getSelection(e);
	config.quickEdit.setSelection(e,wikifyPlainText(txt)); return false;"
>&nbsp;~&nbsp;</a></html>/%

%/<html><hide linebreaks><a href="javascript:;" class="tiddlyLink" tabindex="-1" 
title="''bold''" accesskey="B"
onclick="config.quickEdit.wrapSelection(this,'\x27\x27','\x27\x27'); return false;"
>&nbsp;B&nbsp;</a></html>/%

%/<html><hide linebreaks><a href="javascript:;" class="tiddlyLink" tabindex="-1" 
title="//italics//" accesskey="I" 
onclick="config.quickEdit.wrapSelection(this,'//','//'); return false;"
>&nbsp;I&nbsp;</a></html>/%

%/<html><hide linebreaks><a href="javascript:;" class="tiddlyLink" tabindex="-1" 
title="__underline__" accesskey="U" 
onclick="config.quickEdit.wrapSelection(this,'__','__'); return false;"
>&nbsp;U&nbsp;</a></html>/%

%/<html><hide linebreaks><a href="javascript:;" class="tiddlyLink" tabindex="-1" 
title="--strikethrough--" accesskey="S" 
onclick="config.quickEdit.wrapSelection(this,'--','--'); return false;"
>&nbsp;S&nbsp;</a></html>/%

%/ &nbsp;/%  SPACER

%/<html><hide linebreaks><a href="javascript:;" class="tiddlyLink" tabindex="-1" 
title="format text"
onclick="var p=Popup.create(this); if (!p) return false; p.className+=' sticky smallform';
	var s=createTiddlyElement(p,'select'); s.button=this;
	s.options[0]=new Option('select text format...','');
	s.options[s.length]=new Option('CSS class wrapper','{{$1{,}}},Enter a CSS classname');
	s.options[s.length-1].title='CSS class wrapper - {{classname classname etc{...}}}';
	s.options[s.length]=new Option('inline CSS styles','@@$1,@@,Enter CSS (attribute:value;attribute:value;...;)');
	s.options[s.length-1].title='inline CSS styles - @@attr:value;attr:value;...@@';
	s.options[s.length]=new Option('heading 1','\n!,\n');
	s.options[s.length-1].title='H1 heading - !';
	s.options[s.length]=new Option('heading 2','\n!!,\n');
	s.options[s.length-1].title='H2 heading - !!';
	s.options[s.length]=new Option('heading 3','\n!!!,\n');
	s.options[s.length-1].title='H3 heading - !!!';
	s.options[s.length]=new Option('heading 4','\n!!!!,\n');
	s.options[s.length-1].title='H4 heading - !!!!';
	s.options[s.length]=new Option('heading 5','\n!!!!!,\n');
	s.options[s.length-1].title='H5 heading - !!!!!';
	s.options[s.length]=new Option('blockquote','\n\<\<\<\n,\n\<\<\<\n');
	s.options[s.length-1].title='indented blockquote - \<\<\<';
	s.options[s.length]=new Option('monospaced','{{{,}}}');
	s.options[s.length-1].title='inline monospaced text - {{{...}}}';
	s.options[s.length]=new Option('plain text','\n{{{\n,\n}}}\n');
	s.options[s.length-1].title='multi-line monospaced text box - {{{...}}}';
	s.options[s.length]=new Option('superscript','^^,^^');
	s.options[s.length-1].title='^^superscript^^';
	s.options[s.length]=new Option('subscript','~~,~~');
	s.options[s.length-1].title='~~subscript~~';
	s.options[s.length]=new Option('HTML','<html>,<\x2fhtml>');
	s.options[s.length-1].title='HTML syntax - <html>...<\x2fhtml>';
	s.options[s.length]=new Option('comment','/%,%/');
	s.options[s.length-1].title='comment (hidden content) - /%...%/';
	s.size=s.length;
	s.onclick=function(){ if (!this.value.length) return;
		var parts=this.value.split(',');
		var prefix=parts[0]; var suffix=parts[1]; var ask=parts[2];
		if (ask) {
			var val=prompt(ask); if (!val) { Popup.remove(); return false; }
			prefix=prefix.replace(/\$1/g,val); suffix=suffix.replace(/\$1/g,val);
		}
		config.quickEdit.wrapSelection(this.button,prefix,suffix);
		Popup.remove(); return false;
	};
	s.onkeyup=config.quickEdit.keyup;
	Popup.show();
	s.focus();
	return config.quickEdit.processed(event);"
>format</a></html>
/%
|Name|QuickEdit_image|
|Source|http://www.TiddlyTools.com/#QuickEdit_image|
|Version|2.4.3|
|Author|Eric Shulman|
|License|see http://www.TiddlyTools.com/#QuickEditPlugin|
|Type|html|
|Requires|QuickEditPlugin|
|Description|quickedit - embed an image|

Usage: see  http://www.TiddlyTools.com/#QuickEditToolbar

%/<html><hide linebreaks><a href="javascript:;" class="tiddlyLink" tabindex="-1" 
	title="embed an image (jpg/gif/png) - [img[tooltip|URL]] or [img[tooltip|path/to/file.ext]]"
	onclick="var fn=config.quickEdit.promptForFilename(
		'Enter/select an image file',getLocalPath(document.location.href),'');
	if (!fn) return false;  /* cancelled by user */
	var h=document.location.href; var p=decodeURIComponent(h.substr(0,h.lastIndexOf('/')+1));
	if (fn.startsWith(p)) fn=fn.substr(p.length); /* use RELATIVE path/filename.ext */
	var tip=prompt('Enter a tooltip for this image',''); if (!tip) tip=''; else tip+='|';
	return config.quickEdit.setSelection(this,'[img['+tip+fn+']]');"
>image</a></html>
/%
|Name|QuickEdit_insert|
|Source|http://www.TiddlyTools.com/#QuickEdit_insert|
|Version|2.4.3|
|Author|Eric Shulman|
|License|see http://www.TiddlyTools.com/#QuickEditPlugin|
|Type|html|
|Requires|QuickEditPlugin|
|Description|quickedit - insert content from another tiddler or external file|

Usage: see  http://www.TiddlyTools.com/#QuickEditToolbar

%/<html><hide linebreaks><a href="javascript:;" class="tiddlyLink" tabindex="-1" 
title="insert content from another tiddler or external file"
onclick="var p=Popup.create(this); if (!p) return false; p.className+=' sticky smallform';

	var s2=createTiddlyElement(p,'select'); s2.title='filter by tag';
	s2.options[0]=new Option('filter by tag...','');
	s2.options[s2.length]=new Option('[all tiddlers]','');
	var tags=store.getTags();
	for (var t=0; t<tags.length; t++) s2.options[s2.length]=new Option(tags[t][0],tags[t][0]);
	s2.onchange=function(){
		var tag=this.value;
		var tids=tag.length?store.reverseLookup('tags',tag,true):store.reverseLookup('tags','excludeLists');
		var list=this.nextSibling.nextSibling;
		while (list.length) list.options[0]=null;
		var prompt='select a tiddler or file...';
		if (tag.length) prompt='select a tagged tiddler ['+tids.length+' matches]...';
		list.options[0]=new Option(prompt,'');
		if (!tag.length) list.options[list.length]=new Option('[browse for file...]','_file');
		for (var t=0; t<tids.length; t++) {
			list.options[list.length]=new Option(tids[t].title,tids[t].title);
			list.options[list.length-1].title=tids[t].getSubtitle();
		}
		list.size=Math.min(list.length,10);
		list.selectedIndex=0; list.focus();
		this.style.width=list.offsetWidth+'px';
		if (!tag.length) this.selectedIndex=0;
	};
	createTiddlyElement(p,'br');

	var s=createTiddlyElement(p,'select'); s.button=this;
	s.title='select a tiddler or file';
	s.options[0]=new Option('select a tiddler or file...','');
	s.options[s.length]=new Option('[browse for file...]','_file');
	var tids=store.reverseLookup('tags','excludeLists');
	for (var t=0; t<tids.length; t++) {
		s.options[s.length]=new Option(tids[t].title,tids[t].title);
		s.options[s.length-1].title=tids[t].getSubtitle();
	}
	s.size=Math.min(s.length,10);
	s.onclick=function(){ if (!this.value.length) return false;
		if (this.value=='_file') {
			var fn=config.quickEdit.promptForFilename(
				'Enter/select a text file',getLocalPath(document.location.href),'');
			if (!fn) return false; /* cancelled by user */
			var txt=loadFile(getLocalPath(fn));
			if (!txt) { alert('Error: unable to read contents from \0027'+fn+'\0027'); return; }
		}
		else var txt=store.getTiddlerText(this.value);
		if (!txt) {
			displayMessage(this.value+' not found');
			this.selectedIndex=0; this.focus();
			return false;
		}
		config.quickEdit.setSelection(this.button,txt);
		Popup.remove(); return false;
	};
	s.onkeyup=config.quickEdit.keyup;
	Popup.show();
	s2.style.width=s.offsetWidth+'px';
	s.focus();
	return config.quickEdit.processed(event);"
>insert</a></html>
/%
|Name|QuickEdit_link|
|Source|http://www.TiddlyTools.com/#QuickEdit_link|
|Version|2.4.3|
|Author|Eric Shulman|
|License|see http://www.TiddlyTools.com/#QuickEditPlugin|
|Type|html|
|Requires|QuickEditPlugin|
|Description|quickedit - link to tiddler or external file|

Usage: see  http://www.TiddlyTools.com/#QuickEditToolbar

%/<html><hide linebreaks><a href="javascript:;" class="tiddlyLink" tabindex="-1" 
title="add a link to a tiddler or external file - [[link text|TiddlerName]]"
onclick="var p=Popup.create(this); if (!p) return false; p.className+=' sticky smallform';

	var s2=createTiddlyElement(p,'select'); s2.title='filter by tag';
	s2.options[0]=new Option('filter by tag...','');
	s2.options[s2.length]=new Option('[all tiddlers]','');
	var tags=store.getTags();
	for (var t=0; t<tags.length; t++) s2.options[s2.length]=new Option(tags[t][0],tags[t][0]);
	s2.onchange=function(){
		var tag=this.value;
		var tids=tag.length?store.reverseLookup('tags',tag,true):store.reverseLookup('tags','excludeLists');
		var list=this.nextSibling.nextSibling;
		while (list.length) list.options[0]=null;
		var prompt='select a tiddler or file...';
		if (tag.length) prompt='select a tagged tiddler ['+tids.length+' matches]...';
		list.options[0]=new Option(prompt,'');
		if (!tag.length) list.options[list.length]=new Option('[browse for file...]','_file');
		for (var t=0; t<tids.length; t++) {
			list.options[list.length]=new Option(tids[t].title,tids[t].title);
			list.options[list.length-1].title=tids[t].getSubtitle();
		}
		list.size=Math.min(list.length,10);
		list.selectedIndex=0; list.focus();
		this.style.width=list.offsetWidth+'px';
		if (!tag.length) this.selectedIndex=0;
	};
	createTiddlyElement(p,'br');

	var s=createTiddlyElement(p,'select'); s.button=this;
	s.title='select a tiddler or file';
	s.options[0]=new Option('select a tiddler or file...','');
	s.options[s.length]=new Option('[browse for file...]','_file');
	var tids=store.reverseLookup('tags','excludeLists');
	for (var t=0; t<tids.length; t++) {
		s.options[s.length]=new Option(tids[t].title,tids[t].title);
		s.options[s.length-1].title=tids[t].getSubtitle();
	}
	s.size=Math.min(s.length,10);
	s.onclick=function(){ if (!this.value.length) return false;
		var title=this.value; var txt=title;
		if (title=='_file') {
			title=config.quickEdit.promptForFilename('Select a file',
				getLocalPath(document.location.href),'');
			if (!title) { this.selectedIndex=0; this.focus(); return false; }
			var txt=title.substr(title.lastIndexOf('/')+1);
		}
		var txt=prompt('Enter the text to display for this link',txt);
		if (!txt) { this.selectedIndex=0; this.focus(); return false; }
		config.quickEdit.setSelection(this.button,'[['+txt+'|'+title+']]');
		Popup.remove(); return false;
	};
	s.onkeyup=config.quickEdit.keyup;
	Popup.show();
	s2.style.width=s.offsetWidth+'px';
	s.focus();
	return config.quickEdit.processed(event);"
>link</a></html>
/%
|Name|QuickEdit_macro|
|Source|http://www.TiddlyTools.com/#QuickEdit_macro|
|Version|2.4.3|
|Author|Eric Shulman|
|License|see http://www.TiddlyTools.com/#QuickEditPlugin|
|Type|html|
|Requires|QuickEditPlugin|
|Description|quickedit - embed a macro with 'guide text'|

Usage: see  http://www.TiddlyTools.com/#QuickEditToolbar

Note:
Optional 'guideText' can be used to add suggested defaults/placeholders for specific macro parameters.
Add guideText to your own plugin-defined macros using:
	config.macros.macroName.guideText='guide text goes here';

%/<<tiddler {{
	/* define guide text for a few common TW core macros */
	config.macros.edit.guideText='fieldname #rows';
	config.macros.view.guideText='fieldname (link,wikified,date) format';
	config.macros.slider.guideText='cookie TiddlerName label tooltip';
	config.macros.option.guideText='(txtCookieName,chkCookieName)';
	config.macros.tiddler.guideText='TiddlerName with: params...';
	''; /* must return blank to suppress output */ }}>>/%

%/<html><hide linebreaks><a href='javascript:;' class='tiddlyLink' tabindex='-1' 
title='add a macro - \<\<macroName ...\>\>'
onclick="var p=Popup.create(this); if (!p) return false; p.className+=' sticky smallform';
	var s=createTiddlyElement(p,'select'); s.button=this;
	s.options[0]=new Option('select a macro...','');
	var macros=[]; for (var m in config.macros) if (config.macros[m].handler) macros.push(m); macros.sort();
	for (var i=0; i<macros.length; i++) { var m=macros[i];
		var help=config.macros[m].guideText; if (!help) help=''; else help=' '+help;
		s.options[s.length]=new Option(m,m+help);
		s.options[s.length-1].title='\<\<'+m+help+'\>\>';
	}
	s.size=Math.min(s.length,15);
	s.onclick=function(){ if (!this.value.length) return;
		config.quickEdit.setSelection(this.button,'\<\<'+this.value+'\>\>');
		Popup.remove(); return false;
	};
	s.onkeyup=config.quickEdit.keyup;
	Popup.show();
	s.focus();
	return config.quickEdit.processed(event);"
>macro</a></html>
/%
|Name|QuickEdit_replace|
|Source|http://www.TiddlyTools.com/#QuickEdit_replace|
|Version|2.4.5|
|Author|Eric Shulman|
|License|see http://www.TiddlyTools.com/#QuickEditPlugin|
|Type|html|
|Requires|QuickEditPlugin|
|Description|quickedit - find/replace selected text with replacement text|

Usage: see  http://www.TiddlyTools.com/#QuickEditToolbar
!!!Revisions
<<<
2010.12.26 2.4.5 fix use getField(this) to support hijacks by editSectionPlugin
<<<
%/<html><hide linebreaks><a href="javascript:;" class="tiddlyLink" tabindex="-1" 
title="find/replace selected text with replacement text"
onclick="var p=Popup.create(this,null,'popup sticky smallform'); if (!p) return false;
	var e=config.quickEdit.getField(this);
	var s=config.quickEdit.getSelection(e); 
	var t=createTiddlyElement(p,'input'); t.onfocus=function(){this.select()};
	t.value=s.length?s:'enter target text';
	var r=createTiddlyElement(p,'input'); r.onfocus=function(){this.select()};
	r.value='enter replacement text';
	var b=createTiddlyElement(p,'button',null,null,'?');
	b.style.width='2em';
	b.title='FIND/FIND NEXT target text';
	b.root=this;
	b.onclick=function(ev) { /* FIND */
		var e=config.quickEdit.getField(this.root);
		var t=this.previousSibling.previousSibling;
		var tv=t.value.replace(/\\t/mg,'\t').unescapeLineBreaks();
		e.focus();
		if (e.setSelectionRange) { /* MOZ */
			var newstart=e.value.indexOf(tv,e.selectionStart+1);
			if (newstart==-1) newstart=e.value.indexOf(tv); /* wrap around */
			if (newstart==-1) { alert('\u0022'+t.value+'\u0022 not found'); t.focus(); return; }
			e.setSelectionRange(newstart,newstart+tv.length);
			var linecount=e.value.split('\n').length;
			var thisline=e.value.substr(0,e.selectionStart).split('\n').length;
			e.scrollTop=Math.floor((thisline-1-e.rows/2)*e.scrollHeight/linecount);
		} else if (document.selection) { /* IE */
			var range=document.selection.createRange();
			if(range.parentElement()==e) {
				range.collapse(false);
				var found=false; try{found=range.findText(v,e.value.length,4)}catch(e){}
				if (found) range.select();
				else { alert('\u0022'+t.value+'\u0022 not found'); t.focus(); }
			}
		}
	};
	b=createTiddlyElement(p,'button',null,null,'=');
	b.style.width='2em';
	b.title='REPLACE selected text';
	b.root=this;
	b.onclick=function(ev) { /* REPLACE */
		var e=config.quickEdit.getField(this.root);
		var t=this.previousSibling.previousSibling.previousSibling;
		var r=this.previousSibling.previousSibling;
		var rv=r.value.replace(/\\t/mg,'\t').unescapeLineBreaks();
		if (   (e.selectionStart!==undefined && e.selectionEnd==e.selectionStart)
		    || (document.selection && document.selection.createRange().text==''))
			this.previousSibling.click(); /* no selection... do FIND first */
		if (   (e.selectionStart!==undefined && e.selectionEnd==e.selectionStart)
		    || (document.selection && document.selection.createRange().text==''))
			{ t.focus(); return; } /* still no selection... goto target input */
		e.focus(); replaceSelection(e,rv);
	};
	b=createTiddlyElement(p,'button',null,null,'+');
	b.style.width='2em';
	b.title='REPLACE selected text AND FIND NEXT target text';
	b.onclick=function(ev) { /* REPLACE and FIND NEXT */
		this.previousSibling.click();
		this.previousSibling.previousSibling.click();
	};
	b=createTiddlyElement(p,'button',null,null,'!');
	b.style.width='2em';
	b.title='REPLACE ALL occurrences of target text';
	b.root=this;
	b.onclick=function(ev) { /* REPLACE ALL */
		var e=config.quickEdit.getField(this.root);
		var t=this.previousSibling.previousSibling.previousSibling.previousSibling.previousSibling;
		var r=this.previousSibling.previousSibling.previousSibling.previousSibling;
		var tv=t.value.replace(/\\t/mg,'\t').unescapeLineBreaks();
		var rv=r.value.replace(/\\t/mg,'\t').unescapeLineBreaks();
		if (!tv.length) { alert('Please enter the target text'); t.focus(); return; }
		var m='This will replace all occurrences of:\n\n'+tv+'\n\nwith:\n\n'+rv+'\n\nAre you sure?';
		if (!confirm(m)) { r.focus(); r.select(); return; }
		e.value=e.value.replace(new RegExp(tv.escapeRegExp(),'gm'),rv);
		e.focus(); e.select(); Popup.remove();
	};
	Popup.show();
	if (!s.length) {t.focus();t.select()} else {r.focus();r.select()}
	event.cancelBubble=true;if(event.stopPropagation)event.stopPropagation();return false;"
>replace</a></html>
/%
|Name|QuickEdit_sort|
|Source|http://www.TiddlyTools.com/#QuickEdit_sort|
|Version|2.4.3|
|Author|Eric Shulman|
|License|see http://www.TiddlyTools.com/#QuickEditPlugin|
|Type|html|
|Requires|QuickEditPlugin|
|Description|quickedit - sort lines of text|

Usage: see  http://www.TiddlyTools.com/#QuickEditToolbar

%/<html><hide linebreaks><a href="javascript:;" class="tiddlyLink" tabindex="-1" 
title="sort lines of text"
onclick="var p=Popup.create(this); if (!p) return false; p.className+=' sticky smallform';
	var s=createTiddlyElement(p,'select'); s.button=this;
	s.options[0]=new Option('select sort order...','');
	s.options[s.length]=new Option('ascending','A');
	s.options[s.length-1].title='ascending';
	s.options[s.length]=new Option('descending','D');
	s.options[s.length-1].title='descending';
	s.size=s.length;
	s.onclick=function(){ if (!this.value.length) return;
		var e=config.quickEdit.getField(this.button); if (!e) return false;
		var lines=config.quickEdit.getSelection(e).split('\n').sort();
		if (this.value=='D') lines=lines.reverse();
		replaceSelection(e,lines.join('\n'));
		e.focus();
		Popup.remove(); return false;
	};
	s.onkeyup=config.quickEdit.keyup;
	Popup.show();
	s.focus();
	return config.quickEdit.processed(event);"
>sort</a></html>
/%
|Name|QuickEdit_split|
|Source|http://www.TiddlyTools.com/#QuickEdit_split|
|Version|2.4.3|
|Author|Eric Shulman|
|License|see http://www.TiddlyTools.com/#QuickEditPlugin|
|Type|html|
|Requires|QuickEditPlugin|
|Description|quickedit - move selection to new tiddler and insert link, embedded tiddler, or slider|

Usage: see  http://www.TiddlyTools.com/#QuickEditToolbar

Based on ideas originally developed by YannPerrin
(http://yann.perrin.googlepages.com/twkd.html#easySlicer)

%/<html><hide linebreaks><a href="javascript:;" class="tiddlyLink" tabindex="-1" 
title="move selection to new tiddler and insert link, embedded tiddler, or slider"
onclick="var p=Popup.create(this); if (!p) return false; p.className+=' sticky smallform';
	p.style.whiteSpace='nowrap';
	var i=createTiddlyElement(p,'input');
	i.defaultValue='Enter a new tiddler title';
	i.onfocus=function(){this.select()};
	var s=createTiddlyElement(p,'select'); s.button=this;
	s.options[0]=new Option('select type...','');
	s.options[0].title='select split type';
	s.options[1]=new Option('link','link');
	s.options[1].title='replace with [[TiddlerName]]';
	s.options[2]=new Option('embed','embed');
	s.options[2].title='replace with \<\<tiddler TiddlerName\>\>';
	s.options[3]=new Option('slider','slider');
	s.options[3].title='replace with \<\<slider \u0022\u0022 [[TiddlerName]] [[label]] [[tooltip]]\>\>';
	s.onchange=function(){
		if (s.previousSibling.value==s.previousSibling.defaultValue)
			{ alert('A tiddler title is required'); s.selectedIndex=0; s.previousSibling.focus(); return false; }
		var tid=s.previousSibling.value;
		if (store.tiddlerExists(tid) && !confirm(config.messages.overwriteWarning.format([tid])))
			{ s.previousSibling.focus(); return false; }
		switch(s.value) {
			case 'link':
				var newtxt='[['+tid+']]';
				break;
			case 'embed':
				var newtxt='\<\<tiddler [['+tid+']]\>\>';
				break;
			case 'slider':
				var label=prompt('Enter a slider label',tid);
				if (!label) { Popup.remove(); return false; }
				var tip=prompt('Enter a slider tooltip',label);
				if (!tip) { Popup.remove(); return false; }
				var newtxt='\<\<slider \u0022\u0022 [['+tid+']] [['+label+']] [['+tip+']]\>\>';
				break;
		}
		var txt=config.quickEdit.getSelection(config.quickEdit.getField(this.button));
		store.saveTiddler(tid,tid,txt,config.options.txtUserName,new Date(),[],{});
		story.displayTiddler(story.findContainingTiddler(this.button),tid);
		config.quickEdit.setSelection(this.button,newtxt);
		Popup.remove(); return false;
	};
	Popup.show();
	event.cancelBubble=true;if(event.stopPropagation)event.stopPropagation();return false;"
>split</a></html>
/***
|Name|[[QuickNotePlugin]]|
|Source|http://www.TiddlyTools.com/#QuickNotePlugin|
|Version|2.1.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|create quick notes using username+timestamp as tiddler titles|
!!!!!Documenatation
>see [[QuickNotePluginInfo]]
!!!!!Revisions
<<<
2011.06.07 2.1.0 added tiddler:... parameter (default=username)
2011.04.27 2.0.1 merge/clone defaultCustomFields for saving on TiddlySpace
| Please see [[QuickNotePluginInfo]] for previous revision details |
2009.09.15 1.0.0 initial release (transclusion)
<<<
!!!!!Code
***/
//{{{
version.extensions.QuickNotePlugin={ major:2, minor:1, revision:0, date:new Date(2011,6,7) };
config.macros.quickNote = {
	addedMsg: 'Note added to: "%0"',
	createdMsg: 'Created new note tiddler: "%0"',
	shadow: function(tid,txt) {
		config.shadowTiddlers[tid]=txt;
		config.annotations[tid]='see QuickNotePlugin';
	},
	init: function() {
		this.shadow('QuickNote',
			'<<quickNote dateformat:"$1" tags:"$2" tiddler:"$3">>');
		this.shadow('QuickNotePluginPanel',
			store.getTiddlerText('QuickNotePlugin##html',''));
	},
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		var p=paramString.parseParams('name',null,true,false,true);
		var s=createTiddlyElement(place,'span');
		s.innerHTML=store.getTiddlerText('QuickNotePluginPanel','');
		var f=s.getElementsByTagName('form')[0]; if (!f) return;
		f.id=new Date().getTime()+Math.random().toString(); // globally unique ID
		var v=getParam(p,'dateformat',''); v=v=='$1'?'':v; f.dateformat.value=v;
		var v=getParam(p,'tags'      ,''); v=v=='$2'?'':v; f.tags.value=v;
		var v=getParam(p,'tiddler'   ,config.options.txtUserName); v=v=='$3'?'':v; f.target.value=v;
		if (v=='here') {
			var here=story.findContainingTiddler(place);
			if (here) f.target.value=here.getAttribute('tiddler');
		}
		this.tick(f.id);
	},
	tick: function(id) {
		var f=document.getElementById(id); if (!f) return;
		f.title.value=f.target.value+new Date().formatString(f.dateformat.value);
		window.setTimeout('config.macros.quickNote.tick("'+id+'")',1000);
	},
	saveNote: function(f) {
		var tid=f.title.value; if (!tid.length) return;
		var t=store.getTiddler(tid); var existing=t!=null;
		if (!existing) { t=new Tiddler(); t.text=store.getTiddlerText(tid,''); }
		var who =t&&config.options.chkForceMinorUpdate?t.modifier:config.options.txtUserName;
		var when=t&&config.options.chkForceMinorUpdate?t.modified:new Date();
		var txt =t.text+(t.text.length?'\n':'')+f.txt.value;
		var tags=t.tags.slice(0); var newtags=f.tags.value.readBracketedList();
		for (var i=0; i<newtags.length; i++) tags.pushUnique(newtags[i]);
		var fields=merge({},config.defaultCustomFields,true)
		store.saveTiddler(tid,tid,txt,who,when,tags,fields);
		autoSaveChanges(); story.displayTiddler(null,tid);
		if (existing) displayMessage(this.addedMsg.format([tid]));
		else displayMessage(this.createdMsg.format([tid]));
	}
}
//}}}
/***
!!!!!Shadow tiddler: QuickNotePluginPanel
{{{
!html
<html><nowiki><form class="quickNote" style="display:inline;margin:0;padding:0;white-space:nowrap;">
<input type=hidden name="dateformat" disabled value="">
<input type=hidden name="target" disabled value="">
<input type=text name="title" disabled value="" title="title for new tiddler" style="width:50%">
<input type=text name="tags" value="" title="tags for new tiddler" style="width:40%">
<input type=button value="save" style="width:8%"
	onclick="config.macros.quickNote.saveNote(this.form); return false;"><br>
<textarea name="txt" rows="5" cols="60" style="width:100%"></textarea>
</form></html>
!end
}}}
***/
 
/***
|Name|QuickNotePluginInfo|
|Source|http://www.TiddlyTools.com/#QuickNotePlugin|
|Documentation|http://www.TiddlyTools.com/#QuickNotePluginInfo|
|Version|2.1.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|documentation|
|Description|documentation for QuickNotePlugin|
!!!!!Usage
<<<
{{{
<<quickNote tiddler:"..." dateformat:"..." taglist:"...">>
}}}
*''tiddler'' //(default=username)//<br>target tiddler in which to add note text.  Note: to refer to the current tiddler, use special //keyword value:// ''"here"'' (i.e., "tiddler:here")
*''dateformat'' //(default=none)//<br>format string (e.g. """YYYY0MM0DD0hh0mm0ss""") used to generate a unique tiddler title for each new note that is created, by combining the TW username with a //timestamp// for the current time.
*''taglist'' //(optional)//<br>one or more space-separated tag values (e.g., "tag tag [[tag with spaces]] tag tag ...") that will be added to newly created notes.
For backward-compatibility with existing document content, you can also use the {{{<<tiddler>>}}} macro to transclude the [[QuickNote]] //shadow tiddler//, like this:
{{{
<<tiddler QuickNote with: "dateformat" "taglist" "tiddler">>
}}}
Note: transclusion uses //unnamed// parameters that ''must occur in the order shown above''.  You can use "" as placeholders to apply default parameter values.
<<<
!!!!!Examples
<<<
{{{<<quickNote dateformat:"-YYYY0MM0DD0hh0mm0ss" tags:"quicknote journal">>}}}
<<quickNote dateformat:"-YYYY0MM0DD0hh0mm0ss" tags:"quicknote journal">>
<<<
!!!!!Revisions:
<<<
2011.06.07 2.1.0 added tiddler: macro parameter
2011.04.27 2.0.1 merge/clone defaultCustomFields for saving on TiddlySpace
2011.03.06 2.0.0 converted to plugin.  Handle append to existing tiddler.  Added autosave.
2009.09.15 1.0.0 initial release (transclusion)
<<<
/%
!info
|Name|QuickSearchPopup|
|Source|http://www.TiddlyTools.com/#QuickSearchPopup|
|Version|2.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Requires|SearchOptionsPlugin, StickyPopupPlugin|
|Description|popup list of tiddlers containing text matching specified text or current tiddler title|
Usage
<<<
{{{
<<tiddler QuickSearchPopup>>
<<tiddler QuickSearchPopup with: "searchtext" "label">>
}}}
*''searchtext'' (optional, default=current tiddler title)
*''label'' (optional) text for popup command link
*''tip'' (optional) tooltip for popup command link
<<<
Example
<<<
{{{<<tiddler QuickSearchPopup with: {{tiddler.title}} "click me">>}}}
<<tiddler QuickSearchPopup##show with: {{tiddler.title}} "click me">>
<<<
!end
!show
<html><nowiki><a href="javascript:;" title="$3"
	onmouseover="var t='$1';
		this.title=t.length?('list tiddlers containing text: \''+t+'\''):'disabled: no text to match';
	"
	onclick="var t='$1'; if (!t.length) return;
		var p=Popup.create(this); if (!p) return;
		addClass(p,'sticky');
		var d=createTiddlyElement(p,'div');
		d.style.whiteSpace='normal';
		d.style.width='auto';
		d.style.padding='2px';
		wikify('\<\<search [['+t+']] report=summary+list [[$2\n----\n]]\>\>',d);
		Popup.show();
		event.cancelBubble = true;
		if (event.stopPropagation) event.stopPropagation();
		return(false);
">$2</a></html>
!end
%/<<tiddler {{var src='QuickSearchPopup'; src+(tiddler&&tiddler.title==src?'##info':'##show')}}
with:	{{'$1'!='$'+'1'?'$1':(story.findContainingTiddler(place)||place).getAttribute('tiddler')||'';}}
	{{'$2'!='$'+'2'?'$2':'see also'}}
	{{'$3'!='$'+'3'?'$3':'list tiddlers containing matching text'}}
>>
{{selected{
TiddlyTools ~QuickStart&trade; documents provide a fast, easy way to get started with TiddlyWiki.   Each ~QuickStart document offers a different pre-installed package of TiddlyTools plugins, scripts, styles and templates, ready for you to customize to fit your needs.
<<tiddler ToggleSliders with: 'here' 'show all' 'hide all'>><script>
	place.lastChild.className='selected toolbar';
	place.lastChild.style.marginTop='-.7em';
</script><hr>//Please select a document://
*+++{{bold{[TW.html: TiddlyWiki home page]}}}{{borderleft{
<<tiddler QuickStart##links with: TW.html>>a complete copy of ~TiddlyWiki v<<version>> including all content from [[http://www.TiddlyWiki.com|http://www.TiddlyWiki.com]]}}}<br>===

*+++{{bold{[empty.html: This space intentionally left blank]}}}{{borderleft{
<<tiddler QuickStart##links with: empty.html>>an empty copy of ~TiddlyWiki v<<version>>, with //no tiddlers// in it.  Use to build your own documents from scratch.}}}<br>===

*+++{{bold{[importexport.html: Mix 'em, match 'em, trade 'em with your friends]}}}{{borderleft{
<<tiddler QuickStart##links with: importexport.html>>import/export selected tiddlers using interactive control panels, save from web (download //with// changes), save to web (upload to server), save as, load-on-demand, temporary tiddlers, external tiddlers.}}}<br>===

*+++{{bold{[basics.html: A solid, all-purpose starter toolkit]}}}{{borderleft{
<<tiddler QuickStart##links with: basics.html>>a selected set of feature enhancements, including TiddlyTools' CoreTweaks, search options, goto tiddler, breadcrumbs, rearrange/fold/unfold tiddlers, toggle sidebars, resize/autosize editor, QuickEditToolbar, "save as", drag-and-drop files to create tiddlers, single-page mode, HTML print/snapshots, inline scripting (dynamic content generation and custom 'onclick' commands), image resizing, nested sliders, boolean tag matching, tagged templates, and more...}}}<br>===

*+++{{bold{[moveable.html: Free range tiddlers with room to roam!]}}}{{borderleft{
<<tiddler QuickStart##links with: moveable.html>>undock, move, and resize tiddlers and other page elements using the mouse.  Use named 'panel maps' to save/reload different page layouts.  Background popup menu (use ~ALT-CLICK) provides panel management functions including //interactive map viewer/editor// and //document navigation compass// controls.  Custom tiddler templates and stylesheets are applied so all tiddlers are automatically made into moveable panels for a complete 'desktop' experience.}}}<br>===

*+++{{bold{[pasteup.html: flyers, pamphlets, posters, newsletters, etc.]}}}{{borderleft{
<<tiddler QuickStart##links with: pasteup.html>>Use the mouse to interactively position/size overlapping embedded 'paste-up' content.  Create multi-page layouts for flyers, pamphlets, posters, newsletters, etc.  Single-click to edit paste-up parts using a convenient popup editor.}}}<br>===

*+++{{bold{[tiddlyblog.html: Portable blogging - anytime, anywhere!]}}}{{borderleft{
<<tiddler QuickStart##links with: tiddlyblog.html>>~TiddlyBlog combines tiddler 'journals', with StorySaverPlugin, MiniBrowser, FAQViewer, CalendarPlugin, QuickEditToolbar, and other TiddlyTools power tools, to provide a completely portable, self-contained blogging environment.  Copy your tiddlyblog onto a USB stick and take it with you wherever you go!  Share your tiddlyblog with friends, family, co-workers, clients, etc. by attaching it to an email message or publish it online using a [[free TiddlySpot account|http://www.TiddlySpot.com]].}}}<br>===

*+++{{bold{[tiddlybard.html: "The play's the thing..."]}}}{{borderleft{
<<tiddler QuickStart##links with: tiddlybard.html>>Selected works of William Shakespeare - Comedies, Tragedies, and Sonnets, in a convenient, easy-to-read format with full text searching.  Sonnets can also be cross-indexed by keywords (using tags).  Each tiddler has an associated 'Discussion' tab, making it ideal for keeping course notes, assignment questions/answers, or any other commentary related to the content of that play.}}}<br>===

}}}/%

HIDDEN SECTIONS

!links
{{selected{{{toolbar{@@display:block;font-size:150%;line-height:100%;margin-top:-1em;[[view|quickstart/$1]]|[[download|http://www.TiddlyTools.com/download.php?file=quickstart/$1]]@@}}}}}}
!end links

!badge
{{floatright{@@display:block;{margin:0 1em;{{groupbox center{
//~TiddlyTools ~QuickStart&trade;//:
''$1''
----
[[try it now!|quickstart/$1]]|[[download...|http://www.TiddlyTools.com/download.php?file=quickstart/$1]]}}}@@}}}
!end badge

%/
The way to learn to use TiddlyWiki is to forget that you don't know how to use TiddlyWiki...
----
"Knock, Knock"...  "Who's there?"... "Oh! I guess you know that one..."
----
In theory, there is no difference between theory and practice. But, in practice, there is.
----
Sometimes when reading Goethe I have the paralyzing suspicion that he is trying to be funny.
----
A witty saying proves nothing.         
----
The problem with some people is that when they aren't drunk, they're sober.
----
The great thing about television is that if something important happens anywhere in the world, day or night, you can always change the channel.
----
Don't be so humble - you are not that great.
----
The combination "ough" can be pronounced in nine different ways. The following sentence contains them all: "A rough-coated, dough-faced, thoughtful ploughman strode through the streets of Scarborough; after falling into a slough, he coughed and hiccoughed." 
----
If you lived here, you'd be home by now...
----
I love my dust. It shows I had something better to do.
----
Time flies like an arrow... Fruit flies like a banana [Groucho Marx]
----
If you don't know where you're going, you'll probably end up somewhere else.
----
Weebles wobble... but they don't fall down!
----
It's all very simple... or else it's all very complex... or perhaps it's neither... or both.
----
Accepting reality is the first step to insanity
----
Oops!  Sorry. My karma ran over your dogma.
----
If it looks like a duck, walks like a duck and sounds like a duck, it's probably something else.
----
Some times you feel like a nut, some times you bolt.
----
Santaclaustrophobia... The feeling that Christmas is closing in all around you.
----
Why is abbreviation such a long word?
----
Diplomacy is the art of saying 'Nice doggie!'... until you can find a rock.
----
Scientists working on cloning technology have done what the american educational system has been doing for years - producing identical sheep.
----
Umm... What's another word for thesaurus?
----
Give me ambiguity or give me something else
----
Don't anthropomorphize your computer, it doesn't like it.
----
Ninth Law of Cartoon Physics: Everything falls faster than an anvil.
----
Oh yeah?  Far out!
----
Boycott Shampoo - Demand the REAL poo!
----
Remember: Don't sweat the petty things... and don't pet the sweaty things.
----
Sign in lunch room: "Shoes are required to eat in the cafeteria..." (and hand-written below: "...socks can eat anywhere they want.")
----
Don't be irreplaceable, if you can't be replaced, you can't be promoted.
----
5 out of 4 people have problems with fractions...
----
Osborne's Law of Mathematics: Variables won't; constants aren't.
----
Always remember you're unique, just like everyone else.
----
Something to ponder: What was the best thing *before* sliced bread?   Hmmm...
----
Physics Joke #27: Two hydrogen atoms bump into each other while walking down the street: 'Are you alright?'... 'No, I lost an electron!'... 'Are you sure?'... 'Yeah, I'm Positive!'
----
The one thing I can't stand is intolerant people!
----
Old programmers never die. . . they just can't C as well.
----
World Shortest 'Bar' joke: A guy walks into a bar...   OUCH! he says...
----
Never judge a man 'til you have walked a mile in his shoes, because by then, he's a mile away, you've got his shoes, and you can say whatever the hell you want to.
----
The problem with troubleshooting is that real trouble shoots back.
----
These are the roots of rhythm: boom, de boom, de-boom, ding-dong, ooh! [Leila ~Gallagher-Breen]
----
These are the roots of music: boom-chicky-chicky boom, meow, meow, baddom, baddom,  ding-aling-a-long, chicky-boom! [Leila ~Gallagher-Breen]
----
Classified ad (in Physics Quarterly): Got Mole problems?  Call Avagadro Exterminators: 602-1023
----
He who laughs last thinks slowest
----
Would a fly without wings be called a walk?
----
The winner of the World's Worst Analogy contest: 'The little boat glided across the water in exactly the way a bowling ball wouldn't.'
----
From the 'say what?!?' files: We are ready for any unforeseen event that may or may not occur. [Dan Quayle 9/22/90]
----
I believe you should live each day as if it is your last, which is why I don't have any clean laundry because, come on, who wants to wash clothes on the last day of their life? [Jack Handy]
----
PRINTER - A device consisting of three main parts: the case, the jammed paper tray, and the blinking red light.
----
Dilbert's Laws of Work: The more crap you put up with, the more crap you are going to get.
----
Q: Why'd the electron cross the road? A: 'Cause he was already on the other side...
----
When the going gets tough, remember STRESSED spelled backwards is DESSERTS.
----
Foobar... baz. Mumble: frotz, gronk, snork. Snerfle? Natter and gromish!
----
Pentiums melt in your PC, not in your hand.
----
everyone is cute... even me.  But in purple... I'm STUNNING!! [Londo Mollari] 
----
I always wanted to be somebody, but I should have been more specific. [Lily Tomlin] 
----
It's OK to change horses in mid-stream, especially if the first horse can't swim! [Laura Shulman] 
----
Work is the curse of the drinking classes. [Oscar Wilde] 
----
We have only two things to worry about:  That things will never get back to normal, and that they already have.
----
Intelligence is a funny thing: those who don't have it think they do, and those who do are smart enough to know better.
----
Life is hard, Love is strange.  Nothing lasts, people change.   Dream of a long and wonderful future, but live now.
----
'Can you prove any of the stuff you believe in?', my friend asked. When I said that's not how belief works, he nodded and said that's what he thought but he was just checking to make sure he hadn't missed a key point.
----
Life ... It's a good place to be!
----
Do not follow where the path may lead.  Go, instead, where there is no path, and leave a trail.
----
History is made at night... character is what you are in the dark. [Dr. Emilio Lizardo, aka Lord John Worfin] 
----
You can't always get what you want... but if you try sometimes, you just may find, that you get what you need. [The Rolling Stones] 
----
The only man who behaved sensibly was my tailor; he took my measurement anew every time he saw me, while all the rest went on with their old measurements and expected them to fit me. [George Bernard Shaw] 
----
In matters of style, swim with the current: in matters of principle, stand like a rock. [Thomas Jefferson] 
----
Great things are not done by impulse, but by a series of small things brought together. [Vincent van Gogh] 
----
'I think there is a world market for maybe five computers.' [Thomas Watson, chairman of IBM, 1943] 
----
We have to live today by what truth we can get today, and be ready tomorrow to call it falsehood. [William James] 
----
There are two ways of spreading light: to be the candle or the mirror that reflects it. [Edith Wharton] 
----
Talent develops in tranquility, character in the full current of human life. [Johann Wolfgang von Goethe (1749-1832)] 
----
Our firmest convictions are apt to be the most suspect; they mark our limitations and our bounds.  Life is a petty thing unless it is moved by the indomitable urge to extend its boundaries. [Jose Ortega y Gasset] 
----
It takes courage to grow up and turn out to be who you really are. [e e cummings (1894-1962)] 
----
If we knew what it was we were doing, it would not be called research, would it? [Albert Einstein] 
----
To invent, you need a good imagination and a pile of junk. [Thomas Edison] 
----
Dare to be naive. [R. Buckminster Fuller] 
----
Quiet minds cannot be perplexed or frightened, but go on in fortune or misfortune at their own private pace, like a clock during a thunderstorm. [Robert Louis Stevenson] 
----
In the struggle between yourself and the world, second the world. [Franz Kafka] 
----
Every man's condition is a solution in hieroglyph to those inquiries he would put.  He acts it as life before he apprehends it as truth. [Ralph Waldo Emerson] 
----
One can remain alive...if one is unafraid of change, insatiable in intellectual curiosity, interested in big things, and happy in small ways. [Edith Wharton] 
----
a rock is like space because it doesnt move; and space is like a rock because it is empty.  words are buddhas. [Jack Kerouac] 
----
The whole problem with the world is that fools and fanatics are always so certain of themselves, and wiser people so full of doubts. [Bertrand Russell] 
----
Doubt is not a pleasant state of mind, but certainty is absurd. [Voltaire] 
----
Education is not the filling of a pail, but the lighting of a fire. [William Butler Yeats] 
----
If you take yourself too seriously, no one else will take you seriously enough... [Eric Shulman] 
----
There are only four questions of value in life... What is sacred? Of what is the spirit made? What is worth living for, and what is worth dying for? The answer to each is the same: only love. [Don Juan ~DeMarco] 
----
If you are a dreamer, come in.  If you are a dreamer, a wisher, a liar, a hope-er, a pray-er, a magic bean buyer... If you're a pretender, come sit by my fire... For we have some flax-golden tales to spin.  Come in!  Come in! [Shel Silverstein] 
----
O money, money, money, I'm not necessarily one of those who think thee holy, But I often stop to wonder how thou canst go out so fast when thou comest in so slowly. [Ogden Nash] 
----
There is no progress without struggle. [Frederick Douglass] 
----
Before you can do something, you must become something. [Goethe] 
----
The man who follows the crowd will usually get no further than the crowd.  The man who walks alone is likely to find himself in places no one has ever been. [Alan ~Ashley-Pit] 
----
Weep not for the dead for they are but empty cages from which the bird has flown. [Tibetan Book of The Dead] 
----
I wish it would dawn upon engineers that, in order to be an engineer, it is not enough to be an engineer. [Jose Ortega y Gasset] 
----
Every exit is an entry somewhere. [Tom Stoppard] 
----
Wherever we are, it is but a stage on the way to somewhere else, and whatever we do, however well we do it, it is only a preparation to do something else that shall be different. [Robert Louis Stevenson] 
----
We judge ourselves by what we feel capable of doing, while others judge us by what we have already done. [Henry Wadsworth Longfellow] 
----
All our words are but crumbs that fall down from the feast of the mind. [Kahlil Gibran, "Sand and Foam"] 
----
It's a lot harder to find joy than it is to find bread.  Feed your soul first, then go shopping. [Eric Shulman] 
----
Why do you hasten to remove anything which hurts your eye, while if something affects your soul you postpone the cure until next year? [Horace] 
----
Not to know is bad.  Not to want to know is worse.  Not to hope is unthinkable.  Not to care is unforgivable.  [Nigerian folk saying] 
----
Only half of writing is saying what you mean. The other half is preventing people from reading what they expected you to mean. [James Richardson, 'Ploughshares'] 
----
There are no shortcuts to anyplace worth going. [Beverly Sills] 
----
Somewhere, something incredible is waiting to be known. [Carl Sagan] 
----
Courage is the price that Life extracts for granting peace. [Amelia Earhart] 
----
Great things are not done by impulse, but by a series of small things brought together. [Vincent van Gogh] 
----
Choose a job you love, and you will never have to work a day in your life. [Confucius] 
----
There is only one success - to be able to spend your life in your own way. [Christopher Morley] 
----
We choose our joys and sorrows long before we experience them. [Kahlil Gibran] 
----
It is all a frame of mind, this enjoyment of living. [Lin Yutang] 
----
Work for something because it is good, not just because it stands a chance to succeed. [Vaclav Havel] 
----
The easiest way to get what you want is to help others get what they want. [Deepak Chopra] 
----
All generalizations are false, including this one. [Bucky Radfish]
----
In science, 'fact' can only mean 'confirmed to such a degree that it would be perverse to withhold provisional assent.' I suppose that apples might start to rise tomorrow, but the possibility does not merit equal time in physics classrooms. [Stephen Jay Gould (1941 - 2002)]
----
Twenty years from now, you will be more disappointed by the things you didn't do, than by the ones you did. So throw off the bowlines. Sail away from the safe harbor. Catch the trade winds in your sails. Explore, dream... [Mark Twain]
----
To live only for some future goal is shallow.  It's the sides of the mountain that sustain life, not the top. [Robert M. Pirsig]
----
Nothing is so contagious as enthusiasm; it moves stones, it charms brutes.  Enthusiasm is the genius of sincerity, and truth accomplishes no victories without it. [Edward G. E. ~Bulwer-Lytton (1803 - 1873)]
----
The past is but the beginning of a beginning, and all that is and has been is but the twilight of the dawn. [Herbert George Wells]
----
We grow great by dreams. All big men are dreamers. They see things in the soft haze of a spring day or in the red fire of a long winter's evening. Some of us let these great dreams die, but others nourish and protect them; nurse them through bad days till they bring them to the sunshine and light, which comes always to those who sincerely hope that their dreams will come true. [Woodrow Wilson]
----
Be brave enough to live life creatively. The creative is the place where no one else has ever been.  You have to leave the city of your comfort and go into the wilderness of your intuition. You can't get there by bus, only by hard work and risk and by not quite knowing what you're doing. What you'll discover will be wonderful. What you'll discover will be yourself. [Alan Alda]
----
If we had no winter, the spring would not be so pleasant; if we did not sometimes taste of adversity, prosperity would not be so welcome.
----
Solitude, if rightly used, becomes not only a privilege but a necessity.  Only a superficial soul fears to fraternize with itself.
----
One of the symptoms of an approaching nervous breakdown is the belief that one's work is terribly important.
----
Hope is like a road in the country: there was never a road, but when many people walk on it, the road comes into existence.
----
You can only find truth with logic if you have already found truth without it.
----
Love is always bestowed as a gift - freely, willingly and without expectation. We don't love to be loved; we love to love.
----
Always listen to experts. They'll tell you what can't be done, and why. Then do it.
----
Distance between two hearts is not an obstacle; rather a great reminder of just how strong true love can be.
----
Not everything that can be counted counts, and not everything that counts can be counted.
----
Life's challenges are not supposed to paralyze you, they're supposed to help you discover who you are.
----
Nothing splendid has ever been achieved except by those who dared believe that something inside them was superior to circumstances.
----
Whether you think that you can, or that you can't, you are usually right.
----
The only time you run out of chances is when you stop taking them.
----
Knowledge speaks, but wisdom listens.
----
Too often we give our children answers to remember rather than problems to solve.
----
Books are the shoes with which we tread the footsteps of great minds.  A book may lie dormant for fifty years or for two thousand years in a forgotten corner of a library, only to reveal, upon being opened, the marvels or the abysses that it contains, or the line that seems to have been written for me alone. In this respect the writer is not different from any other human being: whatever we say or do can have far-reaching consequences.
----
A people that values its privileges above its principles soon loses both.
----
Treat everyone with politeness, even those who are rude to you. Not because they are nice, but because you are.
----
The ultimate measure of a man is not where he stands in moments of comfort and convenience, but where he stands in times of challenge and controversy.  What lies behind us and what lies before us, are only small matters compared to what lies within us. 
----
In your presence even my shadow acquires the sensation of touch.
----
Being in charge of your own reality is a little tougher; it takes a lot of thinking and brutal honesty. [Phil Glatz]
----
There are always going to be amazingly creative people doing wonderful things. [Phil Glatz]
----
The trick is to rise above the symptoms of being aware, and actually BE aware. [Phil Glatz]
----
A revolution is coming - a revolution which will be peaceful if we are wise enough; compassionate if we care enough; successful if we are fortunate enough - but a revolution which is coming whether we will it or not. We can affect its character, we cannot alter its inevitability. [John F. Kennedy]
----
On two occasions I have been asked (by members of Parliament!), 'Pray, Mr. Babbage, if you put into the machine wrong figures, will the right answers come out?' I am not able rightly to apprehend the kind of confusion of ideas that could provoke such a question. [Charles Babbage]
----
Those parts of the system that you can hit with a hammer (not advised) are called hardware; those program instructions that you can only curse at are called software.
----
There are two ways of constructing a software design. One way is to make it so simple that there are obviously no deficiencies, and the other way to make it so complicated that there are no obvious deficiencies. The first method is far more difficult. [Charles A. R. Hoare]
/***
|Name|QuoteOfTheDayPlugin|
|Source|http://www.TiddlyTools.com/#QuoteOfTheDayPlugin|
|Documentation|http://www.TiddlyTools.com/#QuoteOfTheDayPluginInfo|
|Version|1.4.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|Display a randomly selected "quote of the day" from a list defined in a separate tiddler|

!!!!!Documentation
>see [[QuoteOfTheDayPluginInfo]]
!!!!!Revisions
<<<
2008.03.21 [1.4.1] in showNextItem(), corrected handling for random selection so that //initial// index value will randomized correctly instead of always showing first item, even when randomizing.  Thanks to Riccardo Gherardi for finding this.
| Please see [[QuoteOfTheDayPluginInfo]] for previous revision details |
2005.10.21 [1.0.0] Initial Release.  Based on a suggestion by M.Russula
<<<
!!!!!Code
***/
//{{{
version.extensions.QuoteOfTheDayPlugin= {major: 1, minor: 4, revision: 1, date: new Date(2008,3,21)};
config.macros.QOTD = {
	clickTooltip: "click to view another item",
	timerTooltip: "auto-timer stopped...  'mouseout' to restart timer",
	timerClickTooltip: "auto-timer stopped...  click to view another item, or 'mouseout' to restart timer",
	handler:
	function(place,macroName,params) {
		var tid=params.shift(); // source tiddler containing HR-separated quotes
		var p=params.shift();
		var click=true; // allow click for next item
		var inline=false; // wrap in slider for animation effect
		var random=true; // pick an item at random (default for "quote of the day" usage)
		var folder=false; // use local filesystem folder list
		var cookie=""; // default to no cookie
		var next=0; // default to first item (or random item)
		while (p) {
			if (p.toLowerCase()=="noclick") var click=false;
			if (p.toLowerCase()=="inline") var inline=true;
			if (p.toLowerCase()=="norandom") var random=false;
			if (p.toLowerCase().substr(0,7)=="cookie:") var cookie=p.substr(8);
			if (!isNaN(p)) var delay=p;
			p=params.shift();
		}
		if ((click||delay) && !inline) {
			var panel = createTiddlyElement(null,"div",null,"sliderPanel");
			panel.style.display="none";
			place.appendChild(panel);
			var here=createTiddlyElement(panel,click?"a":"span",null,"QOTD");
		}
		else
			var here=createTiddlyElement(place,click?"a":"span",null,"QOTD");
		here.id=(new Date()).convertToYYYYMMDDHHMMSSMMM()+Math.random().toString(); // unique ID
		// get items from tiddler or file list
		var list=store.getTiddlerText(tid,"");
		if (!list||!list.length) { // not a tiddler... maybe an image directory?
			var list=this.getImageFileList(tid);
			if (!list.length) { // maybe relative path... fixup and try again
				var h=document.location.href;
				var p=getLocalPath(decodeURIComponent(h.substr(0,h.lastIndexOf("/")+1)));
				var list=this.getImageFileList(p+tid);
			}
		}
		if (!list||!list.length) return false; // no contents... nothing to display!
		here.setAttribute("list",list);
		if (delay) here.setAttribute("delay",delay);
		here.setAttribute("random",random);
		here.setAttribute("cookie",cookie);
		if (click) {
			here.title=this.clickTooltip
			if (!inline) here.style.display="block";
			here.setAttribute("href","javascript:;");
			here.onclick=function(event)
				{ config.macros.QOTD.showNextItem(this); }
		}
		if (config.options["txtQOTD_"+cookie]!=undefined) next=parseInt(config.options["txtQOTD_"+cookie]);
		here.setAttribute("nextItem",next);
		config.macros.QOTD.showNextItem(here);
		if (delay) {
			here.title=click?this.timerClickTooltip:this.timerTooltip
			here.onmouseover=function(event)
				{ clearTimeout(this.ticker); };
			here.onmouseout=function(event)
				{ this.ticker=setTimeout("config.macros.QOTD.tick('"+this.id+"')",this.getAttribute("delay")); };
			here.ticker=setTimeout("config.macros.QOTD.tick('"+here.id+"')",delay);
		}
	},
	tick: function(id) {
		var here=document.getElementById(id); if (!here) return;
		config.macros.QOTD.showNextItem(here);
		here.ticker=setTimeout("config.macros.QOTD.tick('"+id+"')",here.getAttribute("delay"));
	},
	showNextItem:
	function (here) {
		// hide containing slider panel (if any)
		var p=here.parentNode;
		if (p.className=="sliderPanel") p.style.display = "none"
		// get a new quote
		var index=here.getAttribute("nextItem"); 
		var items=here.getAttribute("list").split("\n----\n");
		if (index<0||index>=items.length) index=0;
		if (here.getAttribute("random")=="true") index=Math.floor(Math.random()*items.length);
		var txt=items[index];
		// re-render quote display element, and advance index counter
		removeChildren(here); wikify(txt,here);
		index++; here.setAttribute("nextItem",index);
		var cookie=here.getAttribute("cookie");
		if (cookie.length) {
			config.options["txtQOTD_"+cookie]=index.toString();
			saveOptionCookie("txtQOTD_"+cookie);
		}
		// redisplay slider panel (if any)
		if (p.className=="sliderPanel") {
			if(anim && config.options.chkAnimate)
				anim.startAnimating(new Slider(p,true,false,"none"));
			else p.style.display="block";
		}
	},
	getImageFileList: function(cwd) { // returns HR-separated list of image files
		function isImage(fn) {
			var ext=fn.substr(fn.length-3,3).toLowerCase();
			return ext=="jpg"||ext=="gif"||ext=="png";
		}
		var files=[];
		if (config.browser.isIE) {
			cwd=cwd.replace(/\//g,"\\");
			// IE uses ActiveX to read filesystem info
			var fso = new ActiveXObject("Scripting.FileSystemObject");
			if(!fso.FolderExists(cwd)) return [];
			var dir=fso.GetFolder(cwd);
			for(var f=new Enumerator(dir.Files); !f.atEnd(); f.moveNext())
				if (isImage(f.item().path)) files.push("[img[%0]]".format(["file:///"+f.item().path.replace(/\\/g,"/")]));
		} else {
			// FireFox (mozilla) uses "components" to read filesystem info
			// get security access
			if(!window.Components) return;
			try { netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); }
			catch(e) { alert(e.description?e.description:e.toString()); return []; }
			// open/validate directory
			var file=Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
			try { file.initWithPath(cwd); } catch(e) { return []; }
			if (!file.exists() || !file.isDirectory()) { return []; }
			var folder=file.directoryEntries;
			while (folder.hasMoreElements()) {
				var f=folder.getNext().QueryInterface(Components.interfaces.nsILocalFile);
				if (f instanceof Components.interfaces.nsILocalFile)
					if (isImage(f.path)) files.push("[img[%0]]".format(["file:///"+f.path.replace(/\\/g,"/")]));
			}
		}
		return files.join("\n----\n");
	}
}
//}}}
/***
|Name|QuoteOfTheDayPluginInfo|
|Source|http://www.TiddlyTools.com/#QuoteOfTheDayPlugin|
|Documentation|http://www.TiddlyTools.com/#QuoteOfTheDayPluginInfo|
|Version|1.4.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|documentation|
|Description|Documentation for QuoteOfTheDayPlugin|
!!!!!Usage
<<<
{{{<<QOTD tiddlername norandom noclick inline cookie:cookiename delay>>}}}
* ''tiddlername'' is the name of a tiddler containing your list of quotes, each separated by a horizontal line (use {{{----}}} on a line by itself).
* Each time the macro is rendered it will display a different quotation, selected at random from the specified tiddler.  To display quotes in the sequence in which they occur in the tiddler, you can use the ''norandom'' keyword.
* When using ''norandom'', you can also specify an optional ''cookie:cookiename'' parameter which will be used to track the //index// of the next quote to be displayed, so that each subsequent rendering of the macro can continue the sequence of quotes as entered in the source tiddler, even in between browser sessions.
* By default, clicking on the rendered quote will select and display another random quote.  Use the optional ''noclick'' keyword parameter to disable this "onClick" handling.
* By default, a clickable or timed quote will be displayed insider a 'slider' panel, so that standard TW animation effects will be used.  However, slider panels are always rendered as "block-level" content, forcing a newline both before and after the slider panel.  Use the ''inline'' keyword parameter to bypass this side-effect and display a clickable/timed quote without automatically adding surrounding linebreaks.
* The quote can also be refreshed automatically, by specifying a numeric ''delay'' parameter (in milliseconds) which enables a countdown timer.  When the mouse is over the quote, the timer is automatically stopped.  Moving the mouse away from the quote content restarts the timer.
<<<
!!!!!Example
<<<
{{{<<QOTD Quotations 10000>>}}}
<<QOTD Quotations 10000>>
<<<
!!!!!Revisions
<<<
2008.03.21 1.4.1 in showNextItem(), corrected handling for random selection so that //initial// index value will randomized correctly instead of always showing first item, even when randomizing.  Thanks to Riccardo Gherardi for finding this.
2008.01.16 1.4.0 support using a local image file directory instead of tiddler name for getting list of items.  If specified tiddler does not exist in the document, macro attempts to use tiddlername as a local directory name (using either absolute or relative path) and get list of all JPG/GIF/PNG files.
2007.08.06 1.3.0 added support for "cookie:cookiename" param
2007.05.03 1.2.1 corrected logic for handling "inline" display (i.e., bypass slider and use of 'block' for quote elements)
2007.05.03 1.2.0 added sliderPanel wrapper around quote to take advantage of core-supported slider animation.  Use "noslider"/"inline" keyword param to suppress use of slider.  Also added tooltips for click, delay, and click+delay modes.
2007.04.16 1.1.2 code cleanup
2007.04.16 1.1.1 onClick handling now supports sequential as well as random order
2007.04.14 1.1.0 added onClick handling for selecting and display a new random quote
2005.10.21 1.0.0 Initial Release.  Based on a suggestion by M.Russula
<<<
/***
|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;
	}
};
//}}}
/***
|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
//}}}
***/
 
/%
|''URL:''|http://solo.dc3.com/tw/|
|''Description:''|Bob Denny's extensions to TiddlyWiki|
|''Author:''|BobDenny|
%/
/%
!info
|Name|RefreshPageDisplay|
|Source|http://www.TiddlyTools.com/#RefreshPageDisplay|
|Version|2.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Description|create a link to redraw all page elements without restarting|
Usage
<<<
{{{
<<tiddler RefreshPageDisplay>>
<<tiddler RefreshPageDisplay with: label>>
}}}
<<<
Example
<<<
{{{<<tiddler RefreshPageDisplay with: "click me">>}}}
<<tiddler RefreshPageDisplay##show with: "click me">>
<<<
!end
!show
<html><nowiki><a href="javascript:;" title="Redisplay current page content WITHOUT RESTARTING!"
onmouseover="
	this.href='javascript:void(eval(decodeURIComponent(%22(function(){try{('
	+encodeURIComponent(encodeURIComponent(this.onclick))
	+')()}catch(e){alert(e.description?e.description:e.toString())}})()%22)))';"
onclick="
	story.forEachTiddler(function(t,e){story.refreshTiddler(t,null,true)});
	refreshDisplay();
 	return false;"
>$1</a></html>
!end
%/<<tiddler {{var src='RefreshPageDisplay'; src+(tiddler&&tiddler.title==src?'##info':'##show')}}
	with: {{'$1'=='$'+'1'?'refresh page display':'$1'}}>>
/%
!info
|Name|RefreshTiddler|
|Source|http://www.TiddlyTools.com/#RefreshTiddler|
|Version|2.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Description|create a link to force an immediate refresh of the current tiddler|
Usage
<<<
{{{
<<tiddler RefreshTiddler>>
<<tiddler RefreshTiddler with: label tip>>
}}}
<<<
Example
<<<
{{{<<tiddler RefreshTiddler with: "click me">>}}}
<<tiddler RefreshTiddler##show with: "click me">>
content displayed at <<today 0hh:0mm:0ss>>
<<<
!end
!show
<html><nowiki><a href="javascript:;" title="$2"
onclick="
	var here=story.findContainingTiddler(this);
	if (here) story.refreshTiddler(here.getAttribute('tiddler'),null,true);
	return false;
">$1</a></html>
!end
%/<<tiddler {{var src='RefreshTiddler'; src+(tiddler&&tiddler.title==src?'##info':'##show')}}
	with:	{{'$1'!='$'+'1'?'$1':'refresh'}}
		{{'$2'!='$'+'2'?'$2':'redisplay current tiddler content'}}
>>
/***
|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(); }
		}
	}
}
//}}}
/%
!info
|Name|ReplaceDoubleClick|
|Source|http://www.TiddlyTools.com/#ReplaceDoubleClick|
|Version|2.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Description|disable doubleclick-to-edit-tiddler or replace doubleclick with shift/ctrl/alt+singleclick|
Usage:
<<<
{{{
<<tiddler ReplaceDoubleClick>> or
<<tiddler ReplaceDoubleClick with: key trigger>>
}}}
*''key'' (optional)
**''none'' (default=disables double-click)
**''ctrl, shift,'' or ''alt'' invokes the action only when the indicated key is used in combination with the mouse.
*''trigger'' (optional)<br>is either 'click' or 'doubleclick' (default).
<<<
Example:
<<<
{{{<<tiddler ReplaceDoubleClick with: shift click>>}}}
<<tiddler ReplaceDoubleClick with: shift click>>//(use shift+click to edit this tiddler)//
<<<
!end
!show
<<tiddler {{
	var here=story.findContainingTiddler(place);
	if (here && here.ondblclick) {
		here.setAttribute('editKey','none');
		var key='$1'; if (key=='$'+'1') key='none'
		if (['shift','ctrl','alt'].contains(key))
			here.setAttribute('editKey',key+'Key');
		var trigger=('$2'=='click')?'onclick':'ondblclick';
		here.save_dblclick=here.ondblclick;
		here.ondblclick=null;
		if (here.getAttribute('editKey')!='none')
			here[trigger]=function(e) {
				var ev=e?e:window.event;
				if (ev[this.getAttribute('editKey')])
					this.save_dblclick.apply(this,arguments);
			}
	}'';}}>>
!end
%/<<tiddler {{var src='ReplaceDoubleClick';src+(tiddler&&tiddler.title==src?'##info':'##show')}} with: [[$1]] [[$2]]>>
/%
!info
|Name|ReplaceTiddlerTitle|
|Source|http://www.TiddlyTools.com/#ReplaceTiddlerTitle|
|Version|2.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Description|replace tiddler's title text with other content - may include wiki syntax|
Usage:
<<<
{{{
<<tiddler ReplaceTiddlerTitle with: [[new title text]]>>
}}}
*text can include wiki-syntax formatting (even links and macros!)
*all double-quotes must be preceded by backslash (e.g., {{{[[He said, \"like this\"]]}}})
*if the text contains any macros that use //evaluated parameters//, the closing {{{}} }}}sequence in those parameters must be backslash-quoted (e.g., {{{[[<<someMacro {{...eval param...}\}>>]]}}})
<<<
!end
!show
<<tiddler {{
	var here=story.findContainingTiddler(place); if (here) {
		var nodes=here.getElementsByTagName("*");
		for (var i=0; i<nodes.length; i++) if (hasClass(nodes[i],"title"))
			{ removeChildren(nodes[i]); wikify("$1",nodes[i]); break; }
	}
'';}}>>
!end
%/<<tiddler {{'ReplaceTiddlerTitle##'+('$1'=='$'+'1'?'info':'show')}} with: [[$1]]>>
/%
!info
|Name|ResetChangeCounters|
|Source|http://www.TiddlyTools.com/#ResetChangeCounters|
|Version|2.0.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Description|Reset all TiddlyWiki option cookies (with confirmation)|
Usage
<<<
{{{
<<tiddler ResetChangeCounters>>
<<tiddler ResetChangeCounters with: label>>
}}}
<<<
Example
<<<
{{{<<tiddler ResetChangeCounters with: 'reset counters'>>}}}
<<tiddler ResetChangeCounters##show with: 'reset counters'>>
<<<
!end
!show
<html><nowiki><a href="javascript:;" title="$2"
onmouseover="
	this.href='javascript:void(eval(decodeURIComponent(%22(function(){try{('
	+encodeURIComponent(encodeURIComponent(this.onclick))
	+')()}catch(e){alert(e.description?e.description:e.toString())}})()%22)))';"
onclick="
	var msg='Are you sure you want to remove the change counters from these tiddlers:\n\n';
	var t=store.getTiddlers('title'); var tids=[];
	for (var i=0;i<t.length;i++) {
		var v=store.getValue(t[i],'changecount');
		if (v) { msg+=t[i].title+' ('+v+')\n'; tids.push(t[i]); }
	}
	msg+='\nPress OK to proceed';
	if (!confirm(msg)) return false;
	for (var i=0;i<tids.length;i++) tids[i].clearChangeCount();
	displayMessage('Change counters have been reset to 0');
	displayMessage('Don\'t forget to save your document!');
	return false;
">$1</a></html>
!end
%/<<tiddler {{var src='ResetChangeCounters'; src+(tiddler&&tiddler.title==src?'##info':'##show')}}
with:	{{'$1'!='$'+'1'?'$1':'&empty; - Reset tiddler change counters...'}}
	{{'$2'!='$'+'2'?'$2':'remove change counters from all tiddlers in this document'}}
>>
/%
!info
|Name|ResetOptionCookies|
|Source|http://www.TiddlyTools.com/#ResetOptionCookies|
|Version|2.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Description|Reset all TiddlyWiki option cookies (with confirmation)|
Usage
<<<
{{{
<<tiddler ResetOptionCookies>>
<<tiddler ResetOptionCookies with: label>>
}}}
<<<
Example
<<<
{{{<<tiddler ResetOptionCookies with: "reset cookies">>}}}
<<tiddler ResetOptionCookies##show with: "reset cookies">>
<<<
!end
!show
<html><nowiki><a href="javascript:;" title="$2"
onmouseover="
	this.href='javascript:void(eval(decodeURIComponent(%22(function(){try{('
	+encodeURIComponent(encodeURIComponent(this.onclick))
	+')()}catch(e){alert(e.description?e.description:e.toString())}})()%22)))';"
onclick="
	// 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=/;'; 
		}
	}
	var opts=new Array(); var p=document.cookie.split('; ');
	for (var i=0;i<p.length;i++){
		var c=p[i]; var v=''; var pos=p[i].indexOf('=');
		if (pos!=-1) { c=p[i].substr(0,pos); v=unescape(p[i].slice(pos+1)); }
		if (config.options[c]!==undefined) opts.push(c);
	} opts.sort();
	var msg='There are '+opts.length+' option cookies:\n\n'+opts.join(', ');
	msg+='\n\nPress OK to proceed, or press CANCEL to keep options unchanged';
	if (!confirm(msg)) return false;
	var msg='OK: reset all options at once, CANCEL: confirm each option, one at a time';
	var quiet=confirm(msg);
	for (var i=0;i<opts.length;i++)
		if (quiet || confirm('Press OK to reset option: '+opts[i])) 
			removeCookie(opts[i]);
 	return false;
">$1</a></html>
!end
%/<<tiddler {{var src='ResetOptionCookies'; src+(tiddler&&tiddler.title==src?'##info':'##show')}}
with:	{{'$1'!='$'+'1'?'$1':'&lowast; - Reset all cookie options...'}}
	{{'$2'!='$'+'2'?'$2':'Clear all TiddlyWiki options stored in browser cookies (w/confirmation)'}}
>>
/%
!info
|Name|RollText|
|Source|http://www.TiddlyTools.com/#RollText|
|Version|2.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|Type|transclusion|
|Requires|AnimationEffecsPlugin|
|Description|display text phrase a word-at-a-time, using AnimationEffectPlugin|
Usage
<<<
{{{
<<tiddler RollText with: "text" timing speed pause repeat>>
}}}
<<<
!end
!out
$1
!end
!msg
RollText uses AnimationEffectsPlugin, available for download and installation from http://www.TiddlyTools.com
!end
!show
<<tiddler RollText##out with: {{
	var out="";
	var txt="$1";
	var what="fontSize";
	var format="%0%";
	var start=0;
	var stop=100;
	var txt=store.getTiddlerText('RollText##msg');
	if ("$1"!="$"+"1") txt="$1";
	var timing=500; if ("$2"!="$"+"2") timing=$2; // time in between start of one word and the next (ms)
	var speed=800; if ("$3"!="$"+"3") speed=$3; // speed for word to zoom in/out (ms)
	var pause=1500; if ("$4"!="$"+"4") pause=$4; // delay between zoom in and zoom out
	var repeat=2; if ("$5"!="$"+"5") repeat=$5; // animation cycles
	var parts=txt.split(" ");
	var when=0;
	var item="<<animate [[%0 ]] %1 %2 %3 %4 %5 %6 %7 %8>\>";
	for (var p=0; p<parts.length; p++) {
		out+=item.format([parts[p],what,format,start,stop,when,speed,repeat,pause]);
		when+=timing;
	}
	if ("$1"=="$"+"1") out="{{center medium{\n"+out+"}\}\}";
	out;
}}>>
!end
%/<<tiddler {{var src='RollText'; src+(tiddler&&tiddler.title==src?'##show':'##show');}}
	with: [[$1]] [[$2]] [[$3]] [[$4]] [[$5]]>>
/***
|Name|RunTiddlerPlugin|
|Source|http://www.TiddlyTools.com/#RunTiddlerPlugin|
|Version|1.2.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|command to invoke tiddler content as if tagged with systemConfig (i.e., a plugin)|
!!!!!Usage/Example
<<<
Toolbar command:
>{{{<<toolbar runTiddler>>}}} (in tiddler content)
>{{{<span class='toolbar' macro='toolbar runTiddler'></span>}}} (in ViewTemplate definition)
><<toolbar runTiddler>>
>when clicked, invokes the current tiddler as javascript code
Macro function:
>{{{<<runTiddler TiddlerName>>}}} or {{{<<runTiddler TiddlerName label tip>>}}}
>if only a TiddlerName is provided, the specified tiddler is automatically invoked as javascript code as soon as the macro is rendered.  If //optional// ''label'' and ''tip'' parameters are present, a command link is created that, when clicked, invokes the specified tiddler as javascript code.
<<<
!!!!!Revisions
<<<
2008.09.01 [1.2.1] fixed return value from command handler to prevent IE from attempt to leave the page
2008.08.26 [1.2.0] added optional label and tooltip params to macro (creates 'onclick' button to invoke specified tiddler)
2008.08.26 [1.1.0] added {{{<<runTiddler TiddlerName>>}}} macro to invoke specified tiddler
2007.09.27 [1.0.0] toolbar command based on run button functionality from TidIDEPlugin
<<<
!!!!!Code
***/
//{{{
version.extensions.RunTiddlerPlugin= {major: 1, minor: 2, revision: 1, date: new Date(2008,9,1)};
//}}}
//{{{
config.commands.runTiddler = {
	text: 'run',
	tooltip: 'evaluate tiddler content as systemConfig (plugin) javascript code',
	warning: "Warning!!  Processing '%0' as a systemConfig (plugin) tiddler may produce unexpected results! Are you sure you want to proceed?",
	completed: "%0: Processing completed",
	handler: function(event,src,title) {
		var here=story.findContainingTiddler(src); if (!here) return;
		return this.invoke(here.getAttribute("tiddler"),true,false);
	},
	invoke: function(tid,ask,quiet) {
		if (ask && !confirm(this.warning.format([tid]))) return false;
		var text=store.getTiddlerText(tid); if (!text) return false;
		try { window.eval(text); if (!quiet) displayMessage(config.commands.runTiddler.completed.format([tid])); }
		catch(ex) { displayMessage(config.messages.pluginError.format([exceptionText(ex)])); }
		return false;
	}
};
//}}}
//{{{
config.macros.runTiddler = {
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		var tid=params[0];
		var label=params[1];
		var tip=params[2]||config.commands.runTiddler.tooltip;
		if (!label) config.commands.runTiddler.invoke(tid,false,true);
		else createTiddlyButton(place,label,tip,function(){
			return config.commands.runTiddler.invoke(this.getAttribute("tid"),true,false);
		},"button").setAttribute("tid",tid);
	}
}
//}}}
|    !panelname|   !x |   !y |   !w |   !h |   !z | !fold | !hover |h
|     SampleMap|   350|   200|   550|  auto|      |       |        |
|      mainmenu|     0|    30|    80|   115|     2|       |        |
|   accessories|    15|   160|    80|   125|     3|       |        |
|    powertools|    50|   352|    80|   125|     4|       |    √   |
/***
|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 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) {
			if (overwrite) return out; // skip merge... forced overwrite
			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) && (merge||confirm(this.mergeprompt.format([target])))) {
					var existing=remoteStore.getTiddlers('title');
					for (var i=0; i<existing.length; i++)
						if (!titles.contains(existing[i].title))
							out.push(this.formatItem(remoteStore,filetype,existing[i],url));
					if (!quiet) displayMessage(this.mergestatus.format([tids.length,out.length-tids.length]));
				}
			}
		}
		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||'';
	}
};
//}}}
//{{{
// automatically add saveAs to backstage
config.tasks.saveAs = {
	text: 'saveAs',
	tooltip: config.macros.saveAs.prompt,
	action: function(){ clearMessage(); config.macros.saveAs.go(); }
}
config.backstageTasks.splice(config.backstageTasks.indexOf('save')+1,0,'saveAs');
//}}}
|Name|SaveAsPluginInfo|
|Source|http://www.TiddlyTools.com/#SaveAsPlugin|
|Documentation|http://www.TiddlyTools.com/#SaveAsPluginInfo|
|Version|2.7.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|documentation|
|Description|Documentation for SaveAsPlugin|
>//Note: This plugin replaces ''[[NewDocumentPlugin]]'' (except for the HTML+CSS "snapshot" features, which are now provided by [[SnapshotPlugin]].//
!!!!!Usage
<<<
This plugin automatically adds a 'save as' command to the TiddlyWiki 'backstage' menu so you can quickly create an exact copy of the current TiddlyWiki document.  The plugin also defines a macro that you can use to place a "save as..." command link into your sidebar/mainmenu/any tiddler (or wherever you like).  When the command link is clicked, a system-specific dialog box will be displayed so you can select/enter the desired target path and filename.
{{{
<<saveAs "label:..." "prompt:..." "filename:..." "type:..." "limit:..."
	quiet replace merge open filter|ask|here|none>>
}}}
//(all parameters are optional)//
*''label:...''<br>custom link text (instead of "save as...")
*''prompt:...''<br>custom tooltip text
*''filename:...''<br>default filename to be shown when asking for an output path/file
*''type:...''<br>a keyword, indicating one of the following output file formats:
**''~TiddlyWiki''<br>(or ''wiki'' or ''tw'') a TiddlyWiki HTML document 
**''~PureStore''<br>(or ''store'' or ''ps'') a TiddlyWiki "PureStore" HTML export file (just tiddlers, no core code)
**''~PlainText''<br>(or ''text'' or ''tx'') a plain text file listing of tiddler //source// content
**''Comma''<br>(or ''csv'' or ''cs'') a Comma-Separated Value (CSV) database/spreadsheet file
**''~NewsFeed''<br>(or ''xml'' or ''rss'' or ''nf'') an RSS ~NewsFeed XML file
*''limit:...''<br>output is limited to the specified number of tiddlers
*''quiet''<br>normally, when using filtering (see below), the number of matching tiddlers is reported and you are asked to confirm before saving those tiddlers to a new file.  Use the ''quiet'' keyword to suppress this confirmation step.
*''replace''<br>overwrites existing output file, if any, without confirmation.
*''merge''<br>merges with existing output file, if any, without confirmation.
*''open''<br>opens the newly created document file in a separate browser tab/window.
*''filter''<br>selects a subset of tiddlers to be written into the new document.  If omitted, all tiddlers in the document are written to the new file.  ''filter'' can either:
**a tag value<br>selects only tiddlers that are tagged with that value.  To select tiddlers based on a combination of tags, you can install [[MatchTagsPlugin]] to construct complex 'tag expressions' using full 'boolean' logic with AND, OR, and NOT operators, as well as nested parentheses.
**''ask''<br>prompts you to enter a tag (or tag expression) whenever you click on the 'save as...' command
**''here''<br>selects the current tiddler (if any).  If the command is not embedded within a tiddler, you will be prompted to enter a tiddler title.
**''none''<br>omits all tiddlers and creates a new //empty// document
<<<
!!!!!Examples
<<<
save all tiddlers:
>{{{<<saveAs>>}}}<br>try it: <<saveAs>>
save only tiddlers matching a single tag:
>{{{<<saveAs "label:create Import/Export starter" "filename:TW+ImportExport.html" ImportExportPackage>>}}}
>try it: <<saveAs "label:create Import/Export starter" "filename:TW+ImportExport.html" "ImportExportPackage>>
save to a ~PureStore format:
>{{{<<saveAs "label:create Import/Export archive" "filename:ImportExportPackage.html" type:PureStore open ImportExportPackage>>}}}
>try it: <<saveAs "label:create Import/Export archive" "filename:ImportExportPackage.html" type:PureStore open ImportExportPackage>>
save to a ~PlainText format:
>{{{<<saveAs "label:create Import/Export source listing" type:PlainText open ImportExportPackage>>}}}
>try it: <<saveAs "label:create Import/Export source listing" type:PlainText open ImportExportPackage>>
save tiddlers matching a complex combination of tags (requires [[MatchTagsPlugin]]):
>{{{<<saveAs (alpha or settings) and not systemConfig>>}}}
>try it: <<saveAs (alpha or settings) and not systemConfig>>
prompt for tag or tag expression each time:
>{{{<<saveAs "label:custom save as..." ask>>}}}
>try it: <<saveAs "label:custom save as..." ask>>
save this tiddler:
>{{{<<saveAs "label:save this tiddler..." {{"filename:"+tiddler.title}} quiet here>>}}}
>try it: <<saveAs "label:save this tiddler..." {{"filename:"+tiddler.title}} quiet here>>
<<<
!!!!!Revisions
<<<
2009.10.13 2.7.0 added 'here' param (saves current tiddler)
2009.08.16 2.6.2 fixed handling for backstage
2009.08.04 2.6.1 fixed handling when limit is omitted.
2009.08.03 2.6.0 added 'limit:nn' parameter.
2009.08.02 2.5.3 in getData(), if type=RSS, sort by modified (most recent first).
2009.07.03 2.5.2 TW252 fixup: don't call convertUTF8ToUnicode() for local loadFile() I/O
2009.04.30 2.5.1 custom fields in CSV output.
2009.04.19 2.5.0 added CSV format.
2008.09.29 2.4.3 in getData(), convert UTF8 to Unicode before merging (fixes international characters).
2008.09.28 2.4.2 in go(), fixed typo that prevented backstage SaveAs from working.
2008.09.24 2.4.1 if rewriting *current* file and chkSaveBackups and/or chkGenerateAnRssFeed is enabled, then write a backup file or RSS feed, respectively
2008.09.24 2.4.0 when 'open' param is used and file is saved to current location, reload() page instead of opening a new tab/window.  Added 'filename' param to specify default filename.  Added 'replace' and 'merge' keyword params to control file handling without asking user.  Improved use of 'quiet' flag to eliminate more unwanted messages
2008.09.19 2.3.2 fixed backstage SaveAs command (was defaulting to empty document).  in formatItem(), removed unnecessary convertUnicodeToUTF8() (was causing double-conversion!)
2008.09.16 2.3.1 fixed IE 'navigate away' error by returning false from button onclick handler
2008.09.11 2.3.0 added support for alternative file formats: ~PlainText (TX), ~PureStore (PS), or ~NewsFeed (XML) in addition to existing ~TiddlyWiki (TW) document format
2008.09.06 2.2.1 corrected handling of autoopen attribute so it only applies when "open" param is specified
2008.08.01 2.2.0 added "open" param to auto-open newly saved document
2008.07.20 2.1.3 added "quiet" param to bypass confirmation when using tag filter
2008.04.22 2.1.2 corrected use of getTarget() to check for "user cancelled"
2008.04.22 2.1.1 documentation fixes
2008.04.22 2.1.0 added support for tag filtering to completely replace [[NewDocumentPlugin]] (now retired)
2008.04.12 2.0.1 automatically add "saveAs" to backstage commands
2008.04.12 2.0.0 initial release based on [[NewDocumentPlugin]]

__Previous revisions from [[NewDocumentPlugin]]__
2008.04.20 1.8.0 added support for 'noCSS' and 'viewer' params for alternative snapshot output
2008.01.08 [*.*.*] plugin size reduction: documentation moved to ...Info tiddler
2007.12.04 [*.*.*] update for ~TW2.3.0: replaced deprecated core functions, regexps, and macros
2007.03.30 1.7.0 added support for "print" param as alternative for "snap".  When "print" is used, the filename is ignored and ouput is directed to another browser tab/window, where the print dialog is then automatically triggered
2007.03.30 1.6.1 added support for "here" keyword for current tiddler elementID and "prompt:text" param for specifying tooltip text
2007.02.12 1.6.0 in onClickNewDocument(), reset HTML source 'markup'
2006.10.23 1.5.1 in onClickNewDocument(), get saved parameter value for snapID instead of using default "contentWrapper" (oops!)
2006.10.18 1.5.0 new optional param for 'snap'... specify alternative DOM element ID (default is still "contentWrapper")
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
<<<
/%
!info
|Name|SaveBreadcrumbs|
|Source|http://www.TiddlyTools.com/#SaveBreadcrumbs|
|Version|2.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Description|write the current list of breadcrumbs to a 'story' tiddler|
Usage
<<<
{{{
<<tiddler SaveBreadcrumbs>>
<<tiddler SaveBreadcrumbs with: label>>
}}}
<<<
Example
<<<
{{{<<tiddler SaveBreadcrumbs with: "click me">>}}}
<<tiddler SaveBreadcrumbs##show with: "click me">>
<<<
!end
!show
<html><nowiki><a href="javascript:;" title="$2"
onclick="
	if (!config.macros.breadcrumbs) return; // not installed
	if (!config.macros.breadcrumbs.crumbs.length) return; // no crumbs
	var msg='Enter the name of a tiddler in which to save the current breadcrumbs';
	var tid=prompt(msg,'DefaultTiddlers'); 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='[['+config.macros.breadcrumbs.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'));
	return false;
">$1</a></html>
!end
%/<<tiddler {{var src='SaveBreadcrumbs'; src+(tiddler&&tiddler.title==src?'##info':'##show')}}
	with:	{{'$1'!='$'+'1'?'$1':'save breadcrumbs'}}
		{{'$2'!='$'+'2'?'$2':'save breadcrumbs to tiddler'}}
>>
/***
|Name|SaveFromWebConfig|
|Source|http://www.TiddlyTools.com/#SaveFromWebConfig|
|Documentation|http://www.TiddlyTools.com/#SaveFromWebPluginInfo|
|Version|1.3.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|configuration settings for SaveFromWebPlugin|
***/
/***
!!!!! URL for server-side 'reflector' script.
***/
//{{{
config.options.txtSaveFromWebScriptURL="savefromweb.php";
//}}}
/***
>Script can be hosted on ANY web server that supports PHP5.
***/
/***
!!!!! URL for TiddlyWiki core source
***/
//{{{
config.options.txtSaveFromWebSourceFile="http://www.TiddlyTools.com/empty.html";
//}}}
/***
>document URL for retrieving TiddlyWiki core source code. Using an *empty* TW minimizes data transfer for retrieving TW core. Can be on ANY domain... If blank, get core source code from current document URL.
***/
/***
!!!!! Target filename
***/
//{{{
config.options.txtSaveFromWebTargetFilename="";
//}}}
/***
>specifies the destination filename for the downloaded file. Can be any valid filename for local filesystem and appears as the default value when you are prompted to save the file.  If blank, the filename of the current document (or the domain name if there is no filename in the URL) is used.
***/
/***
!!!!! Pre-fetch option:
***/
//{{{
config.options.chkSaveFromWebPreFetch=false;
//}}}
/***
<<<
* true=get (and cache) TW core code when document is first loaded (i.e., when plugin is initialized)
* false=get and cache core code the first time the file is being saved
This option causes the plugin to retrieve the TiddlyWiki core source as soon as you load the document, instead of waiting for the first time you save.  This ensures that the TiddlyWiki core source can still be saved to the local filesystem even if your network connection is dropped before you save your changes.  Note that, even without pre-fetching, the core source is always cached after it is retrieved, so that subsequent saves don't do extra work to get it again.
<<<
***/
/***
!!!!! Local I/O option
***/
//{{{
config.options.chkSaveFromWebAttemptLocalIO=false;
//}}}
/***
<<<
(requires browser security permissions, i.e., "trusted site" settings).
The plugin will try to obtain security permission for direct filesystem I/O.  If you grant filesystem access to the script, then it writes the document directly to your filesystem, and doesn't use the server-side reflector script at all.  This allows you to save a remote file to your local filesystem, even if your net connection drops after you open the document. Note: if filesystem permissions are not granted, the plugin will automatically attempt to use the server-side reflector script as a fallback... even if no longer connected to the net.
<<<
***/
 
/***
|Name|SaveFromWebPlugin|
|Source|http://www.TiddlyTools.com/#SaveFromWebPlugin|
|Documentation|http://www.TiddlyTools.com/#SaveFromWebPluginInfo|
|Version|1.3.2|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|extend 'save changes' to get remote document contents and save to local filesystem |
Normally, when you are viewing a TiddlyWiki document over the web (i.e., not via {{{file://}}}) and you select the "save changes" (or "save to disk") command, an error message is displayed: //__"You need to save this TiddlyWiki to a file before you can save changes."__//  This plugin extends the use of {{{<<saveChanges>>}}} so that when you are viewing and/or editing a remote TiddlyWiki document, instead of receiving this somewhat confusing and unhelpful message, you can still click the "save changes" (or "save to disk") command to ''store a copy of the remote document directly onto your local filesystem'', //including any unsaved tiddler changes/additions you have made while working on-line.//
!!!!!Documentation
>see [[SaveFromWebPluginInfo]]
!!!!!Configuration
> see [[SaveFromWebConfig]]
!!!!!Revisions
<<<
2011.02.14 1.3.2 fix OSX error: use picker.file.path
2008.09.29 1.3.1 in saveFromWeb(), do NOT convert UTF8 to Unicode when merging retrieved source for submission to server-side reflector script.  Fixes mangling of international characters and symbols.
|please see [[SaveFromWebPluginInfo]] for additional revision details|
2007.06.26 1.0.0 initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.SaveFromWebPlugin= {major: 1, minor: 3, revision: 2, date: new Date(2011,2,14)};
//}}}

//{{{
// DEFAULT SETTINGS
if (config.options.txtSaveFromWebScriptURL==undefined)
	config.options.txtSaveFromWebScriptURL="savefromweb.php";
if (config.options.txtSaveFromWebTargetFilename==undefined)
	config.options.txtSaveFromWebTargetFilename=""; // use current filename when blank
if (config.options.txtSaveFromWebSourceFile==undefined)
	config.options.txtSaveFromWebSourceFile=""; // use current URL when blank
if (config.options.chkSaveFromWebAttemptLocalIO==undefined)
	config.options.chkSaveFromWebAttemptLocalIO=true; // true=try to use local filesystem I/O (requires security permissions)
if (config.options.chkSaveFromWebPreFetch==undefined)
	config.options.chkSaveFromWebPreFetch=false; // true=retrieve TW core when document is first loaded
//}}}

//{{{
// OPTIONAL: get TW core source code when plugin is loaded (i.e., once per document session)
if (document.location.protocol!="file:" && config.options.chkSaveFromWebPreFetch) {
	// retrieve TW source from server...
	var src=document.location.href;
	if (config.options.txtSaveFromWebSourceFile && config.options.txtSaveFromWebSourceFile.length)
		src=config.options.txtSaveFromWebSourceFile;
	var target=config.options.txtSaveFromWebTargetFilename;
	if (!target.length) { // use current filename
		var loc=document.location.pathname;
		var slashpos=loc.lastIndexOf("/");
		target=(slashpos==-1)?loc:loc.substr(slashpos+1);
		if (!target.length) target=document.location.host+".html";
	}
	var xhr=loadRemoteFile(src,function(success,target,txt,src,xhr){if(success)config.saveFromWebSourceCache=txt;},target);
}
//}}}

//{{{
window.saveFromWeb_saveChanges = window.saveChanges;
window.saveChanges = function(onlyIfDirty,tiddlers) {
	// if on file:, just use standard core save handling
	if(document.location.protocol == "file:") { window.saveFromWeb_saveChanges.apply(this,arguments); return; }
	clearMessage();
	// get target filename
	var target=config.options.txtSaveFromWebTargetFilename;
	if (!target.length) { // use current filename
		var loc=document.location.pathname;
		var slashpos=loc.lastIndexOf("/");
		target=(slashpos==-1)?loc:loc.substr(slashpos+1);
		if (!target.length) target=document.location.host+".html";
	}
	// get TW core source location
	var src=document.location.href;
	if (config.options.txtSaveFromWebSourceFile && config.options.txtSaveFromWebSourceFile.length)
		src=config.options.txtSaveFromWebSourceFile;
	// if core source has already been cached, go straight to saving the file...
	if (config.saveFromWebSourceCache)
		{ window.saveFromWeb(true,target,config.saveFromWebSourceCache,src,null); return; }
	// otherwise, retrieve TW source from server...
	displayMessage("Retrieving TiddlyWiki core from "+src);
	var xhr=loadRemoteFile(src,window.saveFromWeb,target);
	if (!xhr) { // couldn't load remote, report core error message
		displayMessage("Could not retrieve TiddlyWiki core... download unsuccessful.");
		alert(config.messages.notFileUrlError);
		if(store.tiddlerExists(config.messages.saveInstructions))
			story.displayTiddler(null,config.messages.saveInstructions);
	}
	return;
}
//}}}

//{{{
window.saveFromWeb = function(success,target,txt,url,xhr) {
	if(!success) {
		displayMessage("Could not retrieve TiddlyWiki core... download unsuccessful.");
		alert(config.messages.cantSaveError);
		if(store.tiddlerExists(config.messages.saveInstructions))
			story.displayTiddler(null,config.messages.saveInstructions);
		return;
	}
	// Locate the storeArea div's in the original source
	var posDiv=locateStoreArea(txt);
	if(!posDiv) { alert(config.messages.invalidFileError.format([url])); return; }

	// cache the document source so subsequent saves don't have to retrieve the source each time
	if (!config.saveFromWebSourceCache) config.saveFromWebSourceCache=txt;

	// if we can get local filesystem access, then ask for a filename and merge/write the file
	if (config.options.chkSaveFromWebAttemptLocalIO) {
		try {
			// get local target path+filename (may be blocked by browser security)
			var target=promptForFilename( "Save file as:","C:\\",target,"html");
			if (!target || !target.length) return;
			saveBackup(target,txt);
			saveRss(target);
			saveEmpty(target,txt,posDiv);
			saveMain(target,txt,posDiv);
			return;
		} catch(e) { }
	}
	// otherwise, fallback to using online 'reflector' script (if any)
	if (config.options.txtSaveFromWebScriptURL.length) {
		displayMessage("Merging tiddlers with core and preparing for download...");
		var merged=txt.substr(0,posDiv[0]+startSaveArea.length)+"\n"+
			store.allTiddlersAsHtml()+"\n"+txt.substr(posDiv[1]);
		var title=getPageTitle().htmlEncode();
		merged=merged.replaceChunk("<title"+">","</title"+">"," "+title+" ");
		merged=updateLanguageAttribute(merged);
		merged=updateMarkupBlock(merged,"PRE-HEAD","MarkupPreHead");
		merged=updateMarkupBlock(merged,"POST-HEAD","MarkupPostHead");
		merged=updateMarkupBlock(merged,"PRE-BODY","MarkupPreBody");
		merged=updateMarkupBlock(merged,"POST-SCRIPT","MarkupPostBody");
		// create form in a hidden frame and submit it to server
		var html='<input type="hidden" name="filename" value="">'
			+'<input type="hidden" name="contents" value="">';
		var form=window.createHiddenForm(config.options.txtSaveFromWebScriptURL,html);
		form.filename.value=target;
		form.contents.value=merged;
		form.submit();
	}
}
//}}}

//{{{
window.createHiddenForm=function(action,body) {
	var f=document.getElementById("saveFromWebFrame");
	if (f) document.body.removeChild(f);
	var f=createTiddlyElement(document.body,"iframe","saveFromWebFrame");
	f.style.width="0px"; f.style.height="0px"; f.style.border="0px";
	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('<form target="_self" action="'+action+'" method="post" enctype="multipart/form-data">'+body+'</form>');
	d.close();
	return d.getElementsByTagName("form")[0];
}
//}}}

//{{{
// note: if blocked by browser security, this function will throw an error...
// the CALLING function should use "try{...} catch(e){...}" to handle the security errors
window.promptForFilename=function(msg,path,file,defext) {
	var result="";
	if(window.Components) { // moz
		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);
		picker.displayDirectory=null;
		picker.defaultExtension=defext;
		picker.defaultString=file;
		picker.appendFilters(nsIFilePicker.filterAll|nsIFilePicker.filterText|nsIFilePicker.filterHTML);
		if (picker.show()!=nsIFilePicker.returnCancel) var result=picker.file.path;
	}
	else { // IE (XP only)
		var s = new ActiveXObject('UserAccounts.CommonDialog');
		s.Filter='All files|*.*|Text files|*.txt|HTML files|*.htm;*.html|';
		s.FilterIndex=1; // default to ALL files;
		s.InitialDir=path;
		s.FileName=file;
		if (s.showOpen()) var result=s.FileName;
	}
	return result;
}
//}}}
|Name|SaveFromWebPluginInfo|
|Source|http://www.TiddlyTools.com/#SaveFromWebPlugin|
|Documentation|http://www.TiddlyTools.com/#SaveFromWebPluginInfo|
|Version|1.3.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|documentation|
|Description|documentation for SaveFromWebPlugin|
Normally, when you are viewing a TiddlyWiki document over the web (i.e., not via {{{file://}}}) and you select the "save changes" (or "save to disk") command, an error message is displayed: //__"You need to save this TiddlyWiki to a file before you can save changes."__//  This plugin extends the use of {{{<<saveChanges>>}}} so that when you are viewing and/or editing a remote TiddlyWiki document, instead of receiving this somewhat confusing and unhelpful message, you can still click the "save changes" (or "save to disk") command to ''store a copy of the remote document directly onto your local filesystem'', //including any unsaved tiddler changes/additions you have made while working on-line.//
!!!!!Usage
<<<
When you select <<saveChanges>> while viewing a remote document (i.e., a URL starting with http: rather than file:), the plugin first ''retrieves the TiddlyWiki core source code from the original document'' file stored on the remote server.  Then, it ''combines that core source with the tiddlers'' contained in the currently loaded document, ''including any changes you have made.''

While the next step //should// be to simply write the merged core+tiddler data directly to your hard drive, certain JavaScript features, such as reading/writing directly to the local filesystem, require expanded "cross-domain" privileges that are normally restricted for use only with ''signed'' scripts.  Although some browsers will let you grant filesystem permissions to a remotely-loaded script, this usually involves either a series of popup confirmation messages or manually re-configuring (and/or disabling) your browser's built-in security protections, which often include settings and options that most users find difficult to understand and inconvenient to access.

To avoid these security complications, the "save from web" processing requires just a few additional steps to prepare the modified document and deliver it to your browser: rather than writing the document data directly to the local filesystem, the plugin ''sends the merged core+tiddler data to a small companion script installed on the remote server'' (see savefromweb.php, below).  This simple "reflector" script then immediately ''downloads the new document data back to the browser'', which prompts you to either open the downloaded document for viewing or save it to your local hard drive.  Once the document has been stored on your filesystem, you can open that copy in your browser and work offline with full access to all TiddlyWiki features.

Important note for users of Internet Explorer's Popup Blocker feature...
>{{block{
//The default security settings of IE's "Popup Blocker" feature will warn you whenever an attempt is made to download a file in response to a scripted action such as the internal javascript processing performed by SaveFromWebPlugin.  However, if you then click IE's yellow warning message and select the 'download this file...' menu command, this will also cause IE to attempt a 'page transition' away from the currently loaded TiddlyWiki document... but, because there are unsaved changes in the document, you will first receive a confirmation message, allowing you to cancel the page transition.  Regrettably, this also prevents the download from succeeding.  Unfortunately, if you permit the page transition to occur, then your TiddlyWiki document is immediately reloaded and all the unsaved tiddler changes are discarded... and the download still fails to complete!//

''__To permit SaveFromWebPlugin to function properly with Internet Explorer, you will need to adjust the "download" security setting...__''
#From the ''Tools > Internet Options > Security'' tab,
#Select the "Internet" security zone (or what ever zone you are using to view the remote document)
#Press the "Custom level..." button
#In the "Settings" listbox, scroll to the "Downloads" section
#''ENABLE "automatic prompting for downloads"''(the first setting in the section)
#Press OK to accept the new settings.
}}}
<<<
!!!!!Configuration
> see [[SaveFromWebConfig]]
!!!!! Server script installation
<<<
On your web server, in the same directory as your published document, create a file called ''{{{savefromweb.php}}}'', containing the following PHP server-side script.
//{{{
<?php
// savefromweb.php
// Author: Eric L. Shulman / ELS Design Studios
// Source: http://www.TiddlyTools.com/savefromweb.php
// License: http://www.TiddlyTools.com/#LegalStatements
// Usage: install the php script on the server in the same directory as your TiddlyWiki document(s)

// This script 'reflects' any contents sent to it (via form POST) so they are
// sent back to the browser as a binary file.  This invokes the browser's built-in
// download-and-save handling, which does not require security permissions to access
// the local filesystem.

$args=$_POST;
header('Pragma: private');
header('Cache-control: private, must-revalidate');
header('Content-type: application/binary; charset="UTF-8"');
header('Content-disposition: attachment; filename="'.$args['filename'].'"');
$c=$args['contents'];
$c=str_replace("\\'","'",$c); // decode single-quotes
$c=str_replace("\\\"","\"",$c); // decode double-quotes
$c=str_replace("\\\\","\\",$c); // decode backslashes
$c=str_replace("\r\n","\n",$c); // change CRLF to LF
print $c;
?>
//}}}
<<<
!!!!!Direct filesystem access (browser security permissions)
<<<
Although sending the merged document data from browser to server and back again allows it to be saved to your filesystem without requiring you to extensively re-configure your browser's built-in security protections, it also increases the overall processing time because the document's data is actually being transmitted //three// times: it is first retrieved from the remote server to get the TiddlyWiki core source; then, after merging with the updated tiddler data, it is sent back to the server, which immediately 'reflects' it back to the browser for final handling by the built-in "file download" interface.

However, ''if you are accessing a "trusted site"'' (perhaps on a server within a secure private network), depending upon the specific options provided by your browser, ''you may be able to eliminate the round-trip processing by authorizing the appropriate filesystem security permissions in your browser''.  When filesystem access has been permitted, instead of making the round trip with the merged core+tiddler data, the plugin will directly prompt you for a destination path/file, using your computer's "native" path/file selection interface, and then write new the TiddlyWiki document data directly to the indicated location on your local file system.

FireFox users: please see [[FAQ_BrowserSecurity]] for information on configuring your browser to permit remote filesystem access from trusted sites
<<<
!!!!!Revisions
<<<
2008.09.29 1.3.1 in saveFromWeb(), do NOT convert UTF8 to Unicode when merging retrieved source for submission to server-side reflector script.  Fixes mangling of international characters and symbols.
2008.01.08 [*.*.*] plugin size reduction: documentation moved to SaveFromWebPluginInfo
2007.08.08 1.3.0 added caching of the downloaded TW core source code so it only has to be retrieved once.
2007.08.08 1.2.5 Added option to 'pre-fetch' the TW core so background download-and-cache is performed each time the document is loaded.  added option to try using direct filesystem access (with permissions) to bypass the round-trip through the server-side reflector script if the connection to the network is dropped after the document was loaded into the browser.  If permissions are not granted, fallback to use the server-side reflector script.
2007.08.07 1.2.0 removed 'download only' optimization.  The round-trip takes longer, but permits the reflector script to be located ANYWHERE on the net, at ANY valid URL, instead of having to use the same server location as the remote document.
2007.07.27 1.1.1 new documentation and code cleanup
2007.07.26 1.1.0 re-wrote to support savefromweb.php remote "reflector" script.  Allows use of browser's native download dialog to receive file as a fallback alternative to using local filesystem I/O (which would require additional security permissions)
2007.06.27 1.0.1 in saveFromWeb(), pass content from server through convertUnicodeToUTF8() before writing to file.
2007.06.26 1.0.0 initial release
<<<
/***
|Name|SaveTiddlerToFilePlugin|
|Source|http://www.TiddlyTools.com/#SaveTiddlerToFilePlugin|
|Documentation|http://www.TiddlyTools.com/#SaveTiddlerToFilePlugin|
|Version|1.1.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|toolbar command to save tiddler source definition to an external text file|
!!!!!Usage/Example
<<<
Embedded as a macro in tiddler content:
{{{
<<saveTiddlerToFile label:text prompt:text filename:text path:text>>
}}}
or, as a tiddler toolbar command in [[ViewTemplate]]:
{{{
<span class='toolbar' macro='toolbar saveTiddlerToFile'></span>
}}}
where:
* ''label'' //(optional)//<br>specifies the text to display for the command
* ''prompt'' //(optional)//<br>specifies the mouseover 'tooltip' text for the command
* ''filename'' //(optional)//<br>specifies the default filename to create.  You can use "*" within the filename as a 'substitution marker' that will be automatically replaced with the current tiddler's title.    If ''file'' is omitted, a system-specific 'ask for filename' dialog box will be displayed, using 'tiddlername.tid' as the suggested default filename.  //Note: if the tiddler is a plugin (tagged with <<tag systemConfig>>), then the suggested filename will use ".js" instead of ".tid"//
* ''path'' //(optional)//<br>specifies the default folder in which to create the output file.  If the path begins with "./" (or ".\" for Windows) it is treated as a relative path, and the path containing the current document will be prepended to create a full path reference.  Otherwise, the specified path must be a full path reference.  You can use "*" within the path as a 'substitution marker' that will be automatically replaced with the current tiddler's title.  If ''path'' is omitted, the path containing the current document will be used by default.
Examples:
>{{{<<saveTiddlerToFile>>}}}<br>Try it: <<saveTiddlerToFile>>
>{{{<<saveTiddlerToFile label:"save 'txt' file to current folder..." filename:*.txt>>}}}<br>Try it: <<saveTiddlerToFile label:"save 'txt' file to current folder..." filename:*.txt>>
>{{{<<saveTiddlerToFile label:"save 'txt' file to archive..." filename:*.txt path:./archive>>}}}<br>Try it: <<saveTiddlerToFile label:"save 'txt' file to archive..." filename:*.txt path:./archive>>
<<<
!!!!!Configuration
<<<
When {{{<span class='toolbar' macro='toolbar saveTiddlerToFile'></span>}}} is used to create a tiddler toolbar command, the default values for all parameters are applied (e.g., you will be prompted to select/enter a filename with a ".tid" or ".js" extension).  You can override these defaults by writing the following into a tiddler tagged with <<tag systemConfig>>:
{{{
config.commands.saveTiddlerToFile.filename="...";
config.commands.saveTiddlerToFile.path="...";
}}}
<<<
!!!!!Revisions
<<<
2011.02.14 1.1.1 fix OSX error: use picker.file.path
2008.04.22 1.1.0 converted from inline script to tiddler toolbar command
2007.06.26 1.0.0 initial release as inline script
<<<
!!!!!Code
***/
//{{{
version.extensions.SaveTiddlerToFilePlugin= {major: 1, minor: 1, revision: 1, date: new Date(2011,2,14)};

config.macros.saveTiddlerToFile = {
	label: "save this tiddler to a file",
	prompt: "save this tiddler's SOURCE text to a local file",
	askmsg: "select an output filename for this tiddler",
	okmsg: "Tiddler source written to %0",
	failmsg: "An error occurred while creating %0",
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		params = paramString.parseParams("anon",null,true,false,false);
		var label=getParam(params,"label",this.label);
		var prompt=getParam(params,"prompt",this.prompt);
		var filename=getParam(params,"filename","");
		var path=getParam(params,"path","");
		var btn=createTiddlyButton(place,label,prompt,
			function(event){config.macros.saveTiddlerToFile.go(this,event)});
		btn.setAttribute("filename",filename);
		btn.setAttribute("path",path);
	},
	go: function(src,event) {
		var cms=config.macros.saveTiddlerToFile; // abbreviation
		var here=story.findContainingTiddler(src); if (!here) return;
		var tid=here.getAttribute('tiddler');
		var filename=src.getAttribute("filename")||"";
		filename=filename.replace(/\*/g,tid);
		var path=src.getAttribute("path")||"";
		path=path.replace(/\*/g,tid);
		if (!path.length||path.substr(0,2)=="./"||path.substr(0,2)==".\\") {
			var curr=getLocalPath(document.location.href);
			var slashpos=curr.lastIndexOf("/"); if (slashpos==-1) slashpos=curr.lastIndexOf("\\"); 
			if (slashpos!=-1) curr=curr.substr(0,slashpos+1); // remove filename, leave trailing slash
			var trailingslash=curr.indexOf("\\")!=-1?"\\":"/"; // fixup for missing trailing slash
			if (path.length && path.substr(path.length,1)!=trailingslash) path+=trailingslash;
			path=!path.length?curr:curr+path.substr(2); // convert relative path to absolute path
		}
		var deffn=tid+(store.getTiddler(tid).isTagged("systemConfig")?".js":".tid");
		var target=filename.length?path+filename:cms.askForFilename(cms.askmsg,path,deffn); // ask
		if (!target||!target.length) return false; // cancelled by user
		var msg=saveFile(target,store.getTiddlerText(tid))?cms.okmsg:cms.failmsg;
		clearMessage(); displayMessage(msg.format([target]),"file:///"+target.replace(/\\/g,'/'));
	},
	askForFilename: function(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='tid';
				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;*.tid;*.js|HTML files|*.htm;*.html|';
				s.FilterIndex=2; // default to TEXT 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;
	}
}

// // toolbar definition
config.commands.saveTiddlerToFile= {
	text: "file",
	tooltip: config.macros.saveTiddlerToFile.prompt,
	filename: "",
	path: "",
	handler: function(event,src,title) {
		var ccs=config.commands.saveTiddlerToFile;
		if (ccs.filename.length) src.setAttribute("filename",ccs.filename);
		if (ccs.path.length) src.setAttribute("path",ccs.path);
		config.macros.saveTiddlerToFile.go(src,event);
		return false;
	}
};
//}}}
/%
!info
|Name|SaveToClipboard|
|Source|http://www.TiddlyTools.com/#SaveToClipboard|
|Version|1.3.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion, bookmarklet|
|Description|save current document to clipboard|
|Browsers|FireFox, IE, Safari, Chrome, Opera (fallback)|
Usage
<<<
{{{
<<tiddler SaveToClipboard>>
<<tiddler SaveToClipboard with: label>>
}}}
Some browsers lack direct file I/O functions and/or do not currently support use of the [[tiddlysaver.jar|http://www.tiddlywiki.com/#TiddlySaver]] Java extension, preventing use of the normal <<saveChanges>> command to update the stored document.  As a workaround, the <<tiddler SaveToClipboard##show with: "save to clipboard">> command ''copies the source for the current document, including all tiddler changes, directly to the system clipboard'', so you can paste the clipboard contents into a new, empty file (using a text editor), save it to your local filesystem with an '.html' extension, and then open it in your browser to continue working locally.  

To construct the new file content, the previously saved file is first read in, and then merged with the current set of tiddlers (including all new/revised content).  If the saved file is not available (e.g., it was renamed/deleted after it was opened, or it is stored on a remote server that is not currently accessible), only the TiddlyWiki 'storeArea' is output to the clipboard (i.e., TiddlyWiki "~PureStore" format).  Tiddlers saved in PureStore-formatted files can be imported into an empty TiddlyWiki document using the ''backstage>import'' feature (or TiddlyTools' [[ImportTiddlersPlugin|http://www.TiddlyTools.com#ImportTiddlersPlugin]]).  You can [[obtain an empty TiddlyWiki document from http://www.TiddlyWiki.com|http://www.TiddlyWiki.com/empty.html]].

Note: some browsers do not permit program-controlled access to the system clipboard.  In this case, the clipboard output is instead ''displayed as plain text in a new browser tab/window'', so you can manually select and copy that text to the clipboard before pasting it to a new, empty file as described above.
<<<
Example
<<<
{{{<<tiddler SaveToClipboard with: "save to clipboard">>}}}
<<tiddler SaveToClipboard##show with: "save to clipboard">>
^^Note: drag this command link to your browser toolbar to create an [[InstantBookmarklet|InstantBookmarklets]]^^
<<<
<<tiddler SaveToClipboard##code with: {{store.getTiddlerText('SaveToClipboard##show')}}>>
!end
!code
Code
<<<
{{{
$1
}}}
<<<
!end
!show
<html><nowiki><a href="javascript:;" title="save current document to clipboard"
onmouseover="
	this.href='javascript:void(eval(decodeURIComponent(%22(function(){try{('
	+encodeURIComponent(encodeURIComponent(this.onclick))
	+')()}catch(e){alert(e.description?e.description:e.toString())}})()%22)))';"
onclick="
	if(typeof version==undefined||version.title!='TiddlyWiki')
		{alert(document.location.href+'\n\nis not a TiddlyWiki document');return false;}

	window.saveToClipboard=function(success,params,txt,url,xhr) {
		function copy(out) {
			if(window.Components) { // FIREFOX
				netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
				var id='@mozilla.org/widget/clipboardhelper;1';
				var clip=Components.classes[id].getService(Components.interfaces.nsIClipboardHelper);
				clip.copyString(out);
			} else if(window.clipboardData) { // IE
				window.clipboardData.setData('text',out);
			} else if(document.execCommand) { // CHROME, SAFARI, IE6
				var ta=document.createElement('textarea');
				ta.style.position='absolute';
				ta.style.left='-100%';
				document.body.appendChild(ta);
				ta.value=out; ta.select();
				document.execCommand('Copy',false,null);
				document.body.removeChild(ta);
			} else throw('cannot access clipboard');
		}
		var pos=locateStoreArea(txt||'');
		if(success&&pos) {
			displayMessage(txt.length+' bytes read, adding new/revised tiddlers...');
			var out=updateOriginal(txt,pos,url);
		} else {
			if (!confirm('cannot load source file.\ncopy tiddler \x22store area\x22 only?')) return;
			var pre='<!--POST-SHADOWAREA-->\n<div id=\x22storeArea\x22>\n';
			var post='</div>/n<!--POST-STOREAREA-->\n';
			var out=pre+store.allTiddlersAsHtml()+post;
		}
		var msg=out.length+' bytes copied to ';
		try	 { copy(out); msg+='clipboard'; }
		catch(e) { // FALLBACK
			alert('Sorry, direct clipboard access is not currently available.\n\n'
				+'The output will be displayed in another browser tab/window.\n'
				+'Select the entire text there and copy/paste into a local file');
			var t='<html><body><pre>'+out.htmlEncode()+'</pre></body></'+'html>';
			var w=window.open(); var d=w.document; d.open(); d.write(t); d.close();
			msg+='another tab/window';
		}
		displayMessage(msg);
	}
	var url=document.location.href;
	clearMessage(); displayMessage('loading TiddlyWiki code from'); displayMessage(url);
	if (document.location.protocol!='file:') loadRemoteFile(url, window.saveToClipboard);
	else window.saveToClipboard(true,null,loadOriginal(getLocalPath(url)),url,null);
 	return false;
">$1</a></html>
!end
%/<<tiddler {{var src='SaveToClipboard'; src+(tiddler&&tiddler.title==src?'##info':'##show')}}
	with: {{'$1'!='$'+'1'?'$1':'[+] - copy entire document to clipboard'}}>>
/%
!info
|Name|ScrollBox|
|Source|http://www.TiddlyTools.com/#ScrollBox|
|Version|1.0.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Description|show tiddler content in a fixed-height scrolling area|
Usage
<<<
{{{
<<tiddler ScrollBox with: TiddlerName height arg1 arg2 arg3 ... arg7>>
}}}
*''height'' is a CSS measurement (e.g., 10em, 200px, 3in, etc.)
*''arg1 - arg7'' (optional) parameters passed along to the specified tiddler
<<<
Example
>{{{<<tiddler ScrollBox with: StyleSheetLayout 15em>>}}}
><<tiddler ScrollBox##show with: StyleSheetLayout 15em>>
!end
!show
@@display:block;height:$2;overflow:auto;<<tiddler $1
	with: [[$3]] [[$4]] [[$5]] [[$6]] [[$7]] [[$8]] [[$9]]
>>@@@@display:block;text-align:right;^^scroll for more^^@@
!end
%/<<tiddler {{'ScrollBox##'+('$'+'1'=='$1'?'info':'show')}}
with: [[$1]] {{'$2'!='$'+'2'?'$2':'auto'}} {{'$3'!='$'+'3'?'$3':''}}
{{'$4'!='$'+'4'?'$4':''}} {{'$5'!='$'+'5'?'$5':''}} {{'$6'!='$'+'6'?'$6':''}}
{{'$7'!='$'+'7'?'$7':''}} {{'$8'!='$'+'8'?'$8':''}} {{'$9'!='$'+'9'?'$9':''}}>>
This package allows you to set fixed or percentage heights with scrollbars (as needed) for various page elements.  You can also set the number of //flowed columns// of tiddlers to show in the story area (FireFox only), and whether the sidebars scroll with the page content (default) or remain fixed in position as the rest of the page content is scrolled.  In addition, the [[ScrollBox]] tiddler allows you to display a specified tiddler in a fixed-height scrolling area embedded within another tiddler.
/***
|Name|SearchOptionsPlugin|
|Source|http://www.TiddlyTools.com/#SearchOptionsPlugin|
|Documentation|http://www.TiddlyTools.com/#SearchOptionsPluginInfo|
|Version|3.0.10|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|extend core search function with additional user-configurable options|
Adds extra options to core search function including selecting which data items to search, enabling/disabling incremental key-by-key searches, and generating a ''list of matching tiddlers'' instead of immediately displaying all matches.  This plugin also adds syntax for rendering 'search links' within tiddler content to embed one-click searches using pre-defined 'hard-coded' search terms.
!!!!!Documentation
>see [[SearchOptionsPluginInfo]]
!!!!!Configuration
<<<
<<tiddler SearchOptions>>
<<option chkSearchResultsOptions>> Include {{{options...}}} slider in "search again" form
<<<
!!!!!Revisions
<<<
2011.04.08 3.0.10 fixed typo in CSS in formatSearchResults_buttons().  Restore missing options in Configuration section.
|please see [[SearchOptionsPluginInfo]] for additional revision details|
2005.10.18 1.0.0 Initial Release
<<<
!!!!!Code
***/
//{{{
version.extensions.SearchOptionsPlugin= {major: 3, minor: 0, revision: 10, date: new Date(2011,3,18)};
//}}}
//{{{
var defaults={
	chkSearchTitles:	true,
	chkSearchText:		true,
	chkSearchTags:		true,
	chkSearchFields:	true,
	chkSearchTitlesFirst:	true,
	chkSearchList:		true,
	chkSearchHighlight:	true,
	chkSearchListTiddler:	false,
	chkSearchByDate:	false,
	chkIncrementalSearch:	true,
	chkSearchShadows:	true,
	chkSearchOpenTiddlers:	false,
	chkSearchResultsOptions:true,
	chkSearchExcludeTags:	true,
	txtSearchExcludeTags:	'excludeSearch',
	txtIncrementalSearchDelay:	500,
	txtIncrementalSearchMin:	3
}; for (var id in defaults) if (config.options[id]===undefined)
	config.options[id]=defaults[id];
if (config.macros.search.reportTitle==undefined)
	config.macros.search.reportTitle="SearchResults"; // note: not a cookie!
config.macros.search.label+="\xa0"; // a little bit of space just because it looks better
//}}}
// // searchLink: {{{[search[text to find]] OR [search[text to display|text to find]]}}}
//{{{
config.formatters.push( {
	name: "searchLink",
	match: "\\[search\\[",
	lookaheadRegExp: /\[search\[(.*?)(?:\|(.*?))?\]\]/mg,
	prompt: "search for: '%0'",
	handler: function(w)
	{
		this.lookaheadRegExp.lastIndex = w.matchStart;
		var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
		if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
			var label=lookaheadMatch[1];
			var text=lookaheadMatch[2]||label;
			var prompt=this.prompt.format([text]);
			var btn=createTiddlyButton(w.output,label,prompt,
				function(){story.search(this.getAttribute("searchText"))},"searchLink");
			btn.setAttribute("searchText",text);
			w.nextMatch = this.lookaheadRegExp.lastIndex;
		}
	}
});
//}}}
// // incremental search uses option settings instead of hard-coded delay and minimum input values
//{{{
var fn=config.macros.search.onKeyPress;
fn=fn.toString().replace(/500/g, "config.options.txtIncrementalSearchDelay||500");
fn=fn.toString().replace(/> 2/g, ">=(config.options.txtIncrementalSearchMin||3)");
eval("config.macros.search.onKeyPress="+fn);
//}}}
// // REPLACE story.search() for option to "show search results in a list"
//{{{
Story.prototype.search = function(text,useCaseSensitive,useRegExp)
{
	var co=config.options; // abbrev
	var re=new RegExp(useRegExp ? text : text.escapeRegExp(),useCaseSensitive ? "mg" : "img");
	if (config.options.chkSearchHighlight) highlightHack=re;
	var matches = store.search(re,co.chkSearchByDate?"modified":"title","");
	if (co.chkSearchByDate) matches=matches.reverse(); // most recent first
	var q = useRegExp ? "/" : "'";
	clearMessage();
	if (!matches.length) {
		if (co.chkSearchListTiddler) discardSearchResults();
		displayMessage(config.macros.search.failureMsg.format([q+text+q]));
	} else {
		if (co.chkSearchList||co.chkSearchListTiddler) 
			reportSearchResults(text,matches);
		else {
			var titles = []; for(var t=0; t<matches.length; t++) titles.push(matches[t].title);
			this.closeAllTiddlers(); story.displayTiddlers(null,titles);
			displayMessage(config.macros.search.successMsg.format([matches.length, q+text+q]));
		}
	}
	highlightHack = null;
}
//}}}
// // REPLACE store.search() for enhanced searching/sorting options
//{{{
TiddlyWiki.prototype.search = function(searchRegExp,sortField,excludeTag,match)
{
	var co=config.options; // abbrev
	var tids = this.reverseLookup("tags",excludeTag,!!match,sortField);
	var opened=[]; story.forEachTiddler(function(tid,elem){opened.push(tid);});

	// eliminate tiddlers tagged with excluded tags
	if (co.chkSearchExcludeTags&&co.txtSearchExcludeTags.length) {
		var ex=co.txtSearchExcludeTags.readBracketedList();
		var temp=[]; for(var t=tids.length-1; t>=0; t--)
			if (!tids[t].tags.containsAny(ex)) temp.push(tids[t]);
		tids=temp;
	}

	// scan for matching titles first...
	var results = [];
	if (co.chkSearchTitles) {
		for(var t=0; t<tids.length; t++) {
			if (co.chkSearchOpenTiddlers && !opened.contains(tids[t].title)) continue; 
			if(tids[t].title.search(searchRegExp)!=-1) results.push(tids[t]);
		}
		if (co.chkSearchShadows)
			for (var t in config.shadowTiddlers) {
				if (co.chkSearchOpenTiddlers && !opened.contains(t)) continue; 
				if ((t.search(searchRegExp)!=-1) && !store.tiddlerExists(t))
					results.push((new Tiddler()).assign(t,config.shadowTiddlers[t]));
			}
	}
	// then scan for matching text, tags, or field data
	for(var t=0; t<tids.length; t++) {
		if (co.chkSearchOpenTiddlers && !opened.contains(tids[t].title)) continue; 
		if (co.chkSearchText && tids[t].text.search(searchRegExp)!=-1)
			results.pushUnique(tids[t]);
		if (co.chkSearchTags && tids[t].tags.join(" ").search(searchRegExp)!=-1)
			results.pushUnique(tids[t]);
		if (co.chkSearchFields && store.forEachField!=undefined)
			store.forEachField(tids[t],
				function(tid,field,val) {
					if (val.search(searchRegExp)!=-1) results.pushUnique(tids[t]);
				},
				true); // extended fields only
	}
	// then check for matching text in shadows
	if (co.chkSearchShadows)
		for (var t in config.shadowTiddlers) {
			if (co.chkSearchOpenTiddlers && !opened.contains(t)) continue; 
			if ((config.shadowTiddlers[t].search(searchRegExp)!=-1) && !store.tiddlerExists(t))
				results.pushUnique((new Tiddler()).assign(t,config.shadowTiddlers[t]));
		}

	// if not 'titles first', or sorting by modification date,
	// re-sort results to so titles, text, tag and field matches are mixed together
	if(!sortField) sortField = "title";
	var bySortField=function(a,b){
		if(a[sortField]==b[sortField])return(0);else return(a[sortField]<b[sortField])?-1:+1;
	}
	if (!co.chkSearchTitlesFirst || co.chkSearchByDate) results.sort(bySortField);

	return results;
}
//}}}
// // HIJACK core {{{<<search>>}}} macro to add "report" and "simple inline" output
//{{{
config.macros.search.SOP_handler=config.macros.search.handler;
config.macros.search.handler = function(place,macroName,params)
{
	// if "report", use SearchOptionsPlugin report generator for inline output
	if (params[1]&&params[1].substr(0,6)=="report") {
		var keyword=params[0];
		var options=params[1].split("=")[1]; // split "report=option+option+..."
		var heading=params[2]?params[2].unescapeLineBreaks():"";
		var matches=store.search(new RegExp(keyword.escapeRegExp(),"img"),"title","excludeSearch");
		if (matches.length) wikify(heading+window.formatSearchResults(keyword,matches,options),place);
	} else if (params[1]) {
		var keyword=params[0];
		var heading=params[1]?params[1].unescapeLineBreaks():"";
		var seperator=params[2]?params[2].unescapeLineBreaks():", ";
		var matches=store.search(new RegExp(keyword.escapeRegExp(),"img"),"title","excludeSearch");
		if (matches.length) {
			var out=[];
			for (var m=0; m<matches.length; m++) out.push("[["+matches[m].title+"]]");
			wikify(heading+out.join(seperator),place);
		}
	} else
		config.macros.search.SOP_handler.apply(this,arguments);
};
//}}}
// // SearchResults panel handling
//{{{
setStylesheet(".searchResults { padding:1em 1em 0 1em; }","searchResults"); // matches std tiddler padding

config.macros.search.createPanel=function(text,matches,body) {

	function getByClass(e,c) { var d=e.getElementsByTagName("div");
		for (var i=0;i<d.length;i++) if (hasClass(d[i],c)) return d[i]; }
	var panel=createTiddlyElement(null,"div","searchPanel","searchPanel");
	this.renderPanel(panel,text,matches,body);
	var oldpanel=document.getElementById("searchPanel");
	if (!oldpanel) { // insert new panel just above tiddlers
		var da=document.getElementById("displayArea");
		da.insertBefore(panel,da.firstChild);
	} else { // if panel exists
		var oldwrap=getByClass(oldpanel,"searchResults");
		var newwrap=getByClass(panel,"searchResults");
		// if no prior content, just insert new content
		if (!oldwrap) oldpanel.insertBefore(newwrap,null);
		else {	// swap search results content but leave containing panel intact
			oldwrap.style.display='block'; // unfold wrapper if needed
			var i=oldwrap.getElementsByTagName("input")[0]; // get input field
			if (i) { var pos=this.getCursorPos(i); i.onblur=null; } // get cursor pos, ignore blur
			oldpanel.replaceChild(newwrap,oldwrap);
			panel=oldpanel; // use existing panel
		} 
	}
	this.showPanel(true,pos);
	return panel;
}

config.macros.search.renderPanel=function(panel,text,matches,body) {

	var wrap=createTiddlyElement(panel,"div",null,"searchResults");
	wrap.onmouseover = function(e){ addClass(this,"selected"); }
	wrap.onmouseout = function(e){ removeClass(this,"selected"); }
	// create toolbar: "open all", "fold/unfold", "close"
	var tb=createTiddlyElement(wrap,"div",null,"toolbar");
	var b=createTiddlyButton(tb, "open all", "open all matching tiddlers", function() {
		story.displayTiddlers(null,this.getAttribute("list").readBracketedList()); return false; },"button");
	var list=""; for(var t=0;t<matches.length;t++) list+='[['+matches[t].title+']] ';
	b.setAttribute("list",list);
	var b=createTiddlyButton(tb, "fold", "toggle display of search results", function() {
		config.macros.search.foldPanel(this); return false; },"button");
	var b=createTiddlyButton(tb, "close", "dismiss search results",	function() {
		config.macros.search.showPanel(false); return false; },"button");
	createTiddlyText(createTiddlyElement(wrap,"div",null,"title"),"Search for: "+text); // title
	wikify(body,createTiddlyElement(wrap,"div",null,"viewer")); // report
	return panel;
}

config.macros.search.showPanel=function(show,pos) {
	var panel=document.getElementById("searchPanel");
	var i=panel.getElementsByTagName("input")[0];
	i.onfocus=show?function(){config.macros.search.stayFocused(true);}:null;
	i.onblur=show?function(){config.macros.search.stayFocused(false);}:null;
	if (show && panel.style.display=="block") { // if shown, grab focus, restore cursor
		if (i&&this.stayFocused()) { i.focus(); this.setCursorPos(i,pos); }
		return;
	}
	if(!config.options.chkAnimate) {
		panel.style.display=show?"block":"none";
		if (!show) { removeChildren(panel); config.macros.search.stayFocused(false); }
	} else {
		var s=new Slider(panel,show,false,show?"none":"children");
		s.callback=function(e,p){e.style.overflow="visible";}
		anim.startAnimating(s);
	}
	return panel;
}

config.macros.search.foldPanel=function(button) {
	var d=document.getElementById("searchPanel").getElementsByTagName("div");
	for (var i=0;i<d.length;i++) if (hasClass(d[i],"viewer")) var v=d[i]; if (!v) return;
	var show=v.style.display=="none";
	if(!config.options.chkAnimate)
		v.style.display=show?"block":"none";
	else {
		var s=new Slider(v,show,false,"none");
		s.callback=function(e,p){e.style.overflow="visible";}
		anim.startAnimating(s);
	}
	button.innerHTML=show?"fold":"unfold";
	return false;
}

config.macros.search.stayFocused=function(keep) { // TRUE/FALSE=set value, no args=get value
	if (keep===undefined) return this.keepReportInFocus;
	this.keepReportInFocus=keep;
	return keep
}	

config.macros.search.getCursorPos=function(i) {
	var s=0; var e=0; if (!i) return { start:s, end:e };
	try {
		if (i.setSelectionRange) // FF
			{ s=i.selectionStart; e=i.selectionEnd; }
		if (document.selection && document.selection.createRange) { // IE
			var r=document.selection.createRange().duplicate();
			var len=r.text.length; s=0-r.moveStart('character',-100000); e=s+len;
		}
	}catch(e){};
	return { start:s, end:e };
}
config.macros.search.setCursorPos=function(i,pos) {
	if (!i||!pos) return; var s=pos.start; var e=pos.end;
	if (i.setSelectionRange) //FF
		i.setSelectionRange(s,e);
	if (i.createTextRange) // IE
		{ var r=i.createTextRange(); r.collapse(true); r.moveStart("character",s); r.select(); }
}
//}}}
// // SearchResults report generation
// note: these functions are defined globally, so they can be more easily redefined to customize report formats//
//{{{
if (!window.reportSearchResults) window.reportSearchResults=function(text,matches)
{
	var cms=config.macros.search; // abbrev
	var body=window.formatSearchResults(text,matches);
	if (!config.options.chkSearchListTiddler) // show #searchResults panel
		window.scrollTo(0,ensureVisible(cms.createPanel(text,matches,body)));
	else { // write [[SearchResults]] tiddler
		var title=cms.reportTitle;
		var who=config.options.txtUserName;
		var when=new Date();
		var tags="excludeLists excludeSearch temporary";
		var tid=store.getTiddler(title); if (!tid) tid=new Tiddler();
		tid.set(title,body,who,when,tags);
		store.addTiddler(tid);
		story.closeTiddler(title);
		story.displayTiddler(null,title);
	}
}

if (!window.formatSearchResults) window.formatSearchResults=function(text,matches,opt)
{
	var body='';
	var title=config.macros.search.reportTitle
	var q = config.options.chkRegExpSearch ? "/" : "'";
	if (!opt) var opt="all";
	var parts=opt.split("+");
	for (var i=0; i<parts.length; i++) { var p=parts[i].toLowerCase();
		if (p=="again"||p=="all")   body+=window.formatSearchResults_again(text,matches);
		if (p=="summary"||p=="all") body+=window.formatSearchResults_summary(text,matches);
		if (p=="list"||p=="all")    body+=window.formatSearchResults_list(text,matches);
		if (p=="buttons"||p=="all") body+=window.formatSearchResults_buttons(text,matches);
	}
	return body;
}

if (!window.formatSearchResults_again) window.formatSearchResults_again=function(text,matches)
{
	var title=config.macros.search.reportTitle
	var body='';
	// search again
	body+='{{span{<<search "'+text.replace(/"/g,'&#x22;')+'">> /%\n';
	body+='%/<html><input type="button" value="search again"';
	body+=' onclick="var t=this.parentNode.parentNode.getElementsByTagName(\'input\')[0];';
	body+=' config.macros.search.doSearch(t); return false;">';
	if (!config.options.chkSearchResultsOptions) // omit "options..."
		body+='</html>';
	else {
		body+=' <a href="javascript:;" onclick="';
		body+=' var e=this.parentNode.nextSibling;';
		body+=' var show=e.style.display!=\'block\';';
		body+=' if(!config.options.chkAnimate) e.style.display=show?\'block\':\'none\';';
		body+=' else anim.startAnimating(new Slider(e,show,false,\'none\'));';
		body+=' return false;">options...</a>';
		body+='</html>@@display:none;border-left:1px dotted;margin-left:1em;padding:0;padding-left:.5em;font-size:90%;/%\n';
		body+='	%/<<tiddler SearchOptions>>@@';
	};
	body+='}}}\n\n';
	return body;
}

if (!window.formatSearchResults_summary) window.formatSearchResults_summary=function(text,matches)
{
	// summary: nn tiddlers found matching '...', options used
	var body='';
	var co=config.options; // abbrev
	var title=config.macros.search.reportTitle
	var q = co.chkRegExpSearch ? "/" : "'";
	body+="''"+config.macros.search.successMsg.format([matches.length,q+"{{{"+text+"}}}"+q])+"''\n";
	var opts=[];
	if (co.chkSearchTitles) opts.push("titles");
	if (co.chkSearchText) opts.push("text");
	if (co.chkSearchTags) opts.push("tags");
	if (co.chkSearchFields) opts.push("fields");
	if (co.chkSearchShadows) opts.push("shadows");
	if (co.chkSearchOpenTiddlers) body+="^^//search limited to displayed tiddlers only//^^\n";
	body+="~~&nbsp; searched in "+opts.join(" + ")+"~~\n";
	body+=(co.chkCaseSensitiveSearch||co.chkRegExpSearch?"^^&nbsp; using ":"")
		+(co.chkCaseSensitiveSearch?"case-sensitive ":"")
		+(co.chkRegExpSearch?"pattern ":"")
		+(co.chkCaseSensitiveSearch||co.chkRegExpSearch?"matching^^\n":"");
	return body;
}

if (!window.formatSearchResults_list) window.formatSearchResults_list=function(text,matches)
{
	// bullet list of links to matching tiddlers
	var body='';
	var co=config.options; // abbrev
	var pattern=co.chkRegExpSearch?text:text.escapeRegExp();
	var sensitive=co.chkCaseSensitiveSearch?"mg":"img";
	var link='{{tiddlyLinkExisting{<html><nowiki><a href="javascript:;" onclick="'
		+'if(config.options.chkSearchHighlight)'
		+'	highlightHack=new RegExp(\x27'+pattern+'\x27.escapeRegExp(),\x27'+sensitive+'\x27);'
		+'story.displayTiddler(null,\x27%0\x27);'
		+'highlightHack = null; return false;'
		+'" title="%2">%1</a></html>}}}';
	for(var t=0;t<matches.length;t++) {
		body+="* ";
		if (co.chkSearchByDate)
			body+=matches[t].modified.formatString('YYYY.0MM.0DD 0hh:0mm')+" ";
		var title=matches[t].title;
		var fixup=title.replace(/'/g,"\\x27").replace(/"/g,"\\x22");
		var tid=store.getTiddler(title);
		var tip=tid?tid.getSubtitle():''; tip=tip.replace(/"/g,"&quot;");
		body+=link.format([fixup,title,tip])+'\n';
	}
	return body;
}

if (!window.formatSearchResults_buttons) window.formatSearchResults_buttons=function(text,matches)
{
	// embed buttons only if writing SearchResults to tiddler
	if (!config.options.chkSearchListTiddler) return "";
	// "open all" button
	var title=config.macros.search.reportTitle;
	var body="";
	body+="@@display:block;<html><input type=\"button\" href=\"javascript:;\" "
		+"onclick=\"story.displayTiddlers(null,[";
	for(var t=0;t<matches.length;t++)
		body+="'"+matches[t].title.replace(/\'/mg,"\\'")+"'"+((t<matches.length-1)?", ":"");
	body+="],1);\" accesskey=\"O\" value=\"open all matching tiddlers\"></html> ";
	// "discard SearchResults" button
	body+="<html><input type=\"button\" href=\"javascript:;\" "
		+"onclick=\"discardSearchResults()\" value=\"discard "+title+"\"></html>";
	body+="@@\n";
	return body;
}

if (!window.discardSearchResults) window.discardSearchResults=function()
{
	// remove the tiddler
	story.closeTiddler(config.macros.search.reportTitle);
	store.deleteTiddler(config.macros.search.reportTitle);
	store.notify(config.macros.search.reportTitle,true);
}
//}}}
// // DELIVER [[SearchOptions]] shadow payload
//{{{
config.shadowTiddlers.SearchOptions = store.getTiddlerText('SearchOptionsPlugin##panel','');
config.annotations.SearchOptions    = 'created by SearchOptionsPlugin';
//}}}
/***
//{{{
!panel
search in:
  {{nowrap{<<option chkSearchTitles>>titles <<option chkSearchText>>text <<option chkSearchTags>>tags}}} /%
%/{{nowrap{<<option chkSearchFields>>fields <<option chkSearchShadows>>shadows}}}
----
  {{nowrap{<<option chkCaseSensitiveSearch>>case-sensitive}}} /%
%/{{nowrap{<<option chkRegExpSearch>>match text patterns}}}
  {{nowrap{<<option chkIncrementalSearch>>key-by-key search:}}} /%
	%/{{threechar smallform nowrap{<<option txtIncrementalSearchMin>> or more characters}}} /%
	%/{{threechar smallform nowrap{<<option txtIncrementalSearchDelay>> msec delay}}}<hr>
  {{nowrap{<<option chkSearchList>>show results in a list &nbsp; &nbsp;}}} /%
%/{{nowrap{<<option chkSearchListTiddler>>save list in ''[[SearchResults]]''}}}
  {{nowrap{<<option chkSearchTitlesFirst>>show title matches first}}} /%
%/{{nowrap{<<option chkSearchByDate>>sort results by date}}} /%
%/{{nowrap{<<option chkSearchHighlight>>highlight matching text}}}
----
{{nowrap{<<option chkSearchOpenTiddlers>>search open tiddlers only}}}
{{nowrap{<<option chkSearchExcludeTags>>exclude tiddlers tagged with:}}}
{{editor{<<option txtSearchExcludeTags>>}}}
!end
//}}}
***/
 
/***
|Name|SearchOptionsPluginInfo|
|Source|http://www.TiddlyTools.com/#SearchOptionsPlugin|
|Documentation|http://www.TiddlyTools.com/#SearchOptionsPluginInfo|
|Version|3.0.10|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|documentation|
|Description|Documentation for SearchOptionsPlugin|
Extend core search function with additional user-configurable options including selecting which data items to search, enabling/disabling incremental key-by-key searches, and generating a ''list of matching tiddler'' instead of immediately displaying all matches.  This plugin also adds syntax for rendering 'search links' within tiddler content to embed one-click searches using pre-defined 'hard-coded' search terms.
!!!!!Search link Syntax
<<<
To insert a 'search link' into tiddler content, you can write:
{{{
[search[text to find]]
}}}
or
{{{
[search[text to display|text to find]]
}}}
Clicking on the resulting search link will trigger the search functionality, just as if the specified 'text to find' had been entered into the standard search input field usually displayed in the document sidebar.
<<<
!!!!!Inline output: search macro syntax
<<<
Alternatively, to embed search results lists directly into your tiddler content, you can use:
{{{
<<search "text" report>> (report is a literal keyword)
<<search "text" "heading" "separator">> (simple inline generator)
}}}
<<<
!!!!!Inline output examples:
<<<
*+++*[&lt;&lt;search "wood"&gt;&gt;]>...
<<search "wood">>
===

*+++*[&lt;&lt;search "wood" "/%%/"&gt;&gt;]>...
<<search "wood" "/%%/">>
===

*+++*[&lt;&lt;search "wood" "See also: "&gt;&gt;]>...
<<search "wood" "See also: ">>
===

*+++*[&lt;&lt;search "wood" "See also:\n*" "\n*"&gt;&gt;]>...
<<search "wood" "See also:\n*" "\n*">>
===

*+++*[&lt;&lt;search "wood" report=list "See also:"&gt;&gt;]>...
<<search "wood" report=list "See Also:" >>
===

*+++*[&lt;&lt;search "wood" report&gt;&gt;]>...
<<search "wood" report>>
===

*+++*[&lt;&lt;search "wood" report=&gt;&gt;]>...
<<search "wood" report=>>
===

*+++*[&lt;&lt;search "wood" report=all&gt;&gt;]>...
<<search "wood" report=all>>
===

*+++*[&lt;&lt;search "wood" report=summary+buttons+again+list&gt;&gt;]>...
<<search "wood" report=summary+buttons+again+list>>
===

*+++*[&lt;&lt;search "wood" report=summary+again&gt;&gt;]>...
<<search "wood" report=summary+again>>
===

*+++*[&lt;&lt;search "wood" report=summary&gt;&gt;]>...
<<search "wood" report=summary>>
===

<<<
!!!!!Configuration
<<<
<<tiddler SearchOptions>><<option chkSearchResultsOptions>> Include {{{options...}}} slider in "search again" form
>//Note: You can customize the search options display by editing the [[SearchOptions]] shadow tiddler.  You can also embed these options in your content by using any of the following standard TiddlyWiki macros://
{{{
<<tiddler SearchOptions>>
<<slider chkSearchOptions [[SearchOptions]] options "show search options">>
<<tabs chkSomeCookieName ... "options" "show search options" [[SearchOptions]] ... >>
}}}
<<<
!!!!!Revisions
<<<
2011.04.08 3.0.10 fixed typo in CSS in formatSearchResults_buttons().  Restore missing options in Configuration section.
2011.03.18 3.0.9 moved configuration controls to [[SearchOptions]] shadow tiddler
2010.05.03 3.0.8 added chkSearchResultsOptions to allow/omit the "options..." slider from the "search again" form
2010.02.25 3.0.7 in formatSearchResults_list, added declaration of local 'co' variable
2009.09.22 3.0.6 in TiddlyWiki.prototype.search, added 'match' param for core compatibility
2009.01.16 3.0.5 added chkSearchOpenTiddlers option to limit searches to displayed tiddlers only
2009.01.15 3.0.4 in formatSearchResults_list(), corrected link generation to properly handle single-quotes and double-quotes in tiddler titles
2009.01.09 3.0.3 added chkSearchHighlight to optionally disable highlighting of matched text
2009.01.05 3.0.2 in formatSearchResults_list(), set/clear 'highlightHack' via HTML links so that search term will be highlighted when displaying tiddlers.
2008.10.14 3.0.1 changed panel class from "tiddler" to "searchPanel" and added style definition for "searchPanel".  Fixes ticket #771 (in IE, links from search results were reporting errors due to "fake" tiddler class wrapper)
2008.10.02 3.0.0 added optional list of tags to use for excluding tiddler from searches (default="excludeLists").
2008.09.24 2.9.9 performance improvment to reportSearchResults(): when rendering a real SearchResults tiddler, store.notify() isn't needed since the results tiddler is always explicitly closed and redrawn each time.
2008.09.20 2.9.8 corrected createPanel() and renderPanel() so toolbar will be correctly shown/hidden on mouseover/mouseout.
2008.09.19 2.9.7 fixes to panel handling for IE, Safari, and others.  Changed panel id to #searchPanel and added .searchResults CSS class wrapper around panel content.  Fixed fold/unfold handling.
2008.09.18 2.9.6 refactored panel handling code, added 'fold/unfold' panel toolbar command, added dynamic 'title' (shows search term), added txtIncrementalSearchMin option
2008.09.17 2.9.5 added focus and cursor handling for 'search again' field in #searchResults DIV report so that an incremental key-by-key search doesn't interfere with continuous typing into the field.
2008.09.17 2.9.4 fix 'flicker' when updating #searchResults DIV by wikify()ing to an 'offscreen' DIV and then using replaceChild() instead of using removeChildren() followed by wikify()
2008.09.16 2.9.3 changed report layout, added "search again" and collapsible 'options' section with incremental search checkbox and "txtIncrementalSearchDelay" timer tweak to onKeyPress()
2008.08.25 2.9.2 added animation to search results DIV.  Also, the #searchResults DOM element is only auto-created if it does not exist ... and when closed, the DIV is simply hidden rather than removed.  This allows custom placement of search results report in the PageTemplate definition.
2008.08.23 2.9.1 story column search results uses {{{<<moveablePanel>>}}}
2008.08.22 2.9.0 default is now to show search results at top of story column, similar to FND's SimpleSearchPlugin display, with an option to generate SearchResults tiddler as before.  Also changed 'chkSearchIncremental' to 'chkIncrementalSearch' to match core option variable
2008.08.12 2.8.2 change default for chkSearchByDate back to FALSE, and adjusted "list" and "again" output formats (minor tweaks requested by PhilWhitehouse for use on TiddlyWiki.com)
2008.08.11 2.8.1 changed defaults for chkSearchTitlesFirst, chkSearchList and chkSearchShadows to TRUE to enable enhanced search results output as soon as plugin is installed.
2008.06.21 2.8.0 added extended syntax for {{{<<search "text" report heading>> and <<search "text" "heading" "seperator">>}}}
2008.05.03 2.7.1 in searchLink formatter handler(), use separate setAttribute() call instead of passing attribs to createTiddlyButton().  Avoids conflict with errant code in TiddlerNotesPlugin (v2.1 26/10/07)
2008.04.29 2.7.0 added searchLink formatter (syntax: {{{[search[text]]}}} or {{{[search[display|text]]}}})
2008.04.08 2.6.2 don't automatically add options to AdvancedOptions shadow tiddler
2007.02.17 2.6.1 added redefinition of config.macros.search.onKeyPress() to restore check to bypass key-by-key searching (i.e., when chkSearchIncremental==false), which had been unintentionally removed with v2.6.0
2007.02.13 2.6.0 remove redefinition of config.macros.search.handler since core now includes handling for ENTER key.
2007.02.08 2.5.1 include 'temporary' tag when creating SearchResults (for use with TemporaryTiddlersPlugin)
2007.01.29 2.5.0 added support for "sort results by date".  Default is to sort alphabetically (standard).  When sorted by dates, most recent changes are shown first
2006.10.10 2.4.0 added support for "search in tiddler data" (tiddler.fields)  Default is to search extended data.
2006.04.06 2.3.0 added support for "search in shadow tiddlers".  Default is *not* to search in the shadows (i.e. standard TW behavior).  Note: if a shadow tiddler has a 'real' counterpart, only the real tiddler is searched, since the shadow is inaccessible for viewing/editing.
2006.02.03 2.2.1 rewrite timeout clearing code and blank search text handling to match 2.0.4 core release changes.  note that core no longer permits "blank=all" searches, so neither does this plugin.  To search for all, use "." with text patterns enabled.
2006.02.02 2.2.0 in search.handler(), KeyHandler() function clears 'left over' timeout when search input is < 3 chars.  Prevents searching on shorter text when shortened by rapid backspaces (<500msec)
2006.02.01 2.1.9 in Story.prototype.search(), correct inverted logic for using/not using regular expressions when searching
also, blank search text now presents "No search text.  Continue anyway?" confirm() message box, so search on blank can still be processed if desired by user.
2006.02.01 2.1.8 in doSearch(), added alert/return if search text is blank
2006.01.20 2.1.7 fixed setting of config.macros.search.reportTitle so that Tweaks can override it.
2006.01.19 2.1.6 improved SearchResults formatting, added a "search again" form to the report (based on a suggestion from MorrisGray)
define results report title using config.macros.search.reportTitle instead of hard-coding the tiddler title
2006.01.18 2.1.5 Created separate functions for reportSearchResults(text,matches) and discardSearchResults(), so that other developers can create alternative report generators.
2006.01.17 2.1.4 Use regExp.search() instead of regExp.test() to scan for matches.  Correctd the problem where only half the matching tiddlers (the odd-numbered ones) were being reported.
2006.01.15 2.1.3 Added information (date/time, username, search options used) to SearchResults output
2006.01.10 2.1.2 use displayTiddlers() to render matched tiddlers.  This lets you display multiple matching tiddlers, even if SinglePageModePlugin is enabled.
2006.01.08 2.1.1 corrected invalid variable reference, "txt.value" to "text" in story.search()
2006.01.08 2.1.0 re-write to match new store.search(), store.search.handler() and story.search() functions.
2005.12.30 2.0.0 Upgraded to TW2.0.  When rendering SearchResults tiddler, closeTiddler() first to ensure display is refreshed.
2005.12.26 1.4.0 added option to search for matching text in tiddler tags
2005.12.21 1.3.7 use \\ to 'escape' single quotes in tiddler titles when generating "Open all matching tiddlers" link.  Also, added access key: "O", to trigger "open all" link.  Based on a suggestion by UdoBorkowski.
2005.12.18 1.3.6 call displayMessage() AFTER showing matching tiddlers so message is not cleared too soon
2005.12.17 1.3.5 if no matches found, just display message and delete any existing SearchResults tiddler.
2005.12.17 1.3.4 use {/%%/{/%%/{  and }/%%/}/%%/} to 'escape' display text in SearchResults tiddler to ensure that formatting contained in search string is not rendered.  Based on a suggestion by UdoBorkowski.
2005.12.14 1.3.3 tag SearchResults tiddler with 'excludeSearch' so it won't list itself in subsequent searches. Based on a suggestion by UdoBorkowski.
2005.12.14 1.3.2 added "open all matching tiddlers..." link to search results output. Based on a suggestion by UdoBorkowski.
2005.12.10 1.3.1 added "discard search results" link to end of search list tiddler output for quick self-removal of 'SearchResults' tiddler.
2005.12.01 1.3.0 added chkSearchIncremental to enable/disable 'incremental' searching (i.e., search after each keystroke) (default is ENABLED).
added handling for Enter key so it can be used to start a search. Based on a suggestion by LyallPearce
2005.11.25 1.2.1 renamed from SearchTitleOrTextPlugin to SearchOptionsPlugin
2005.11.25 1.2.0 added chkSearchList option.  Based on a suggestion by RodneyGomes
2005.10.19 1.1.0 added chkSearchTitlesFirst option.  Based on a suggestion by ChristianHauck
2005.10.18 1.0.0 Initial Release.  Based on a suggestion by LyallPearce.
<<<
/***
|Name|SectionLinksPlugin|
|Source|http://www.TiddlyTools.com/#SectionLinksPlugin|
|Documentation|http://www.TiddlyTools.com/#SectionLinksPlugin|
|Version|1.4.2|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|allow tiddler sections in TiddlyLinks to be used as anchor points|
This plugin enhances tiddler links so that they can include section references that ''auto-scroll to the indicated section heading'' within a tiddler (i.e., similar to the 'anchor' behavior provided in HTML by {{{<a name="foo">}}} and {{{<a href="#foo">...</a>}}}).  The {{{<<tiddler>>}}} macro syntax has also be extended to allow section references without a tiddler name, so that transclusion of //hidden sections from the same tiddler// can be easily accomplished.  The plugin also adds a new macro, <<sectionTOC>> which can auto-generate and embed a 'Table of Contents' outline view into a tiddler to enable quick navigation to sections within that tiddler.
!!!Usage
<<<
!!!!~TiddlyLink syntax
You can link to a section of a tiddler by adding the "##sectionname" syntax to the tiddlername:
{{{
[[SomeTiddler##SomeSection]]
}}}
When clicked, the tiddler is displayed and the specified section heading is automatically scrolled into view. If the tiddler title is omitted or the 'here' keyword is used, e.g.,
{{{
[[##SomeSection]] or [[here##SomeSection]]>>
}}}
then the current containing tiddler is implied by default.
!!!!HTML anchor syntax
You can use HTML syntax to create a scrollable 'anchor' location within a tiddler without use of the standard TW section heading syntax:
{{{
<html><a name="sectionname" /></html>
}}}
You can then link to that section using the enhanced TiddlyLink syntax as above.
!!!!{{{<<tiddler>>}}} macro 
The {{{<<tiddler>>}}} syntax has been extended so that when the tiddler title is omitted or the 'here' keyword is used, e.g.,
{{{
<<tiddler ##SomeSection>> or <<tiddler here##SomeSection>>
}}}
then the current containing tiddler is implied by default.
!!!!"""<<sectionTOC>>""" macro
This macro generates a 'Table of Contents' outline-style bullet list with links to all sections within the current tiddler.  Simply place the following macro at the //end of the tiddler content// (i.e., following all section headings).  Important note: //''The {{{<<sectionTOC>>}}} macro must occur at the end of the tiddler in order to locate the rendered section headings that precede it.''//
{{{
<<sectionTOC>> or <<sectionTOC className>>
}}}
To position the macro's //output// within the tiddler, you must create a special 'target element' that uses a specific classname (default='sectionTOC'), like this:
{{{
{{sectionTOC{}}}
}}}
When the {{{<<sectionTOC>>}}} macro is rendered, it will find the matching 'sectionTOC'-classed element and writes it's output there.  You can also add the macro and/or target elements directly to the [[ViewTemplate]] definition, so that every tiddler can automatically display the table of contents:
{{{
<span class='sectionTOC'></span> <!-- target element -->
...
<span macro='sectionTOC'></span> <!-- must be at end of tiddler -->
}}}
<<<
!!!Configuration
<<<
You can change the {{{<<SectionTOC>>}}} output link format by adding the following statement to a tiddler tagged with <<tag systemConfig>>
{{{
config.macros.sectionTOC.linkFormat='[[%0|##%0]]';
}}}
The default value (shown above) produces a link to each section within the tiddler, using "%0" to insert the section name into the link.  You can add extra formatting to generate additional output to suit your purposes.  For example, if you have EditSectionPlugin installed, you could include a link that invokes that plugin's popup editor directly from each item in the TOC display, like this:
{{{
config.macros.sectionTOC.linkFormat='[[%0|##%0]] <<editSection [[##%0]] [[(edit)]]>>';
}}}
<<<
!!!Examples
<<<
links to sections defined by ''TW heading syntax'' (e.g, {{{!!!sectionname}}}):{{indent{
[[SectionLinksPlugin##onClickTiddlerLink]]
[[##onClickTiddlerLink]] //(current tiddler implied)//}}}
links to anchors defined by ''HTML syntax'' (e.g., {{{<html><a href="anchorname"></html>}}}):{{indent{
[[SectionLinksPlugin##sampleanchorlink]]
[[##sampleanchorlink]] //(current tiddler implied)//}}}
<<<
!!!Revisions
<<<
2011.12.21 1.4.2 refactor sectionTOCformat to permit customization
2011.02.08 1.4.1 in isExternalLink() hijack, strip section references before testing for external link
2010.08.09 1.4.0 in scrollToSection(), added support for using HTML <a name="..."> anchor elements
2009.08.21 1.3.4 added handling to ignore leading/trailing whitespace in section references
2009.08.21 1.3.3 in createTiddlyLink(), add tiddlyLinkNonExistingSection class if matching section is not found
2009.08.14 1.3.2 in createTiddlyLink(), don't override core value for ~TiddlyLink attribute
2009.08.02 1.3.1 in sectionTOC.handler(), trim leading/trailing whitespace from generated section links
2009.08.01 1.3.0 in scrollToSection(), apply 3-tier section matching (exact, startsWith, contains)
2009.07.06 1.2.2 fixed displayTiddler() hijack
2009.07.03 1.2.1 in {{{<<sectionTOC>>}}}, suppress output if target is not found
2009.06.02 1.2.0 added support for 'here' keyword in {{{[[here##section]]}}} links and {{{<<tiddler here##section>>}}} macro
2009.04.09 1.1.1 in sectionTOC macro, make target visible when TOC is rendered.
2009.01.18 1.1.0 added {{{<<sectionTOC>>}}} macro to generate numbered-bullet links to sections of current tiddler
2009.01.06 1.0.0 converted to stand-alone plugin
2008.10.14 0.0.0 initial release (as [[CoreTweaks]] #784 - http://trac.tiddlywiki.org/ticket/784)
<<<
!!!Code
***/
//{{{
version.extensions.SectionLinksPlugin= {major: 1, minor: 4, revision: 2, date: new Date(2011,12,21)};

Story.prototype.scrollToSection = function(title,section) {
	if (!title||!section) return; var t=this.getTiddler(title); if (!t) return null;
	var elems=t.getElementsByTagName('*');
	var heads=[]; var anchors=[];
	for (var i=0; i<elems.length; i++)
		if (['H1','H2','H3','H4','H5'].contains(elems[i].nodeName)) heads.push(elems[i]);
	for (var i=0; i<elems.length; i++)
		if (elems[i].nodeName=='A' && (elems[i].getAttribute('name')||'').length) anchors.push(elems[i]);
	var found=null;
	for (var i=0; i<heads.length; i++)
		if (getPlainText(heads[i]).trim()==section) { found=heads[i]; break; }
	if (!found) for (var i=0; i<heads.length; i++)
		if (getPlainText(heads[i]).trim().startsWith(section)) { found=heads[i]; break; }
	if (!found) for (var i=0; i<heads.length; i++)
		if (getPlainText(heads[i]).trim().indexOf(section)!=-1) { found=heads[i]; break; }
	if (!found) for (var i=0; i<anchors.length; i++)
		if (anchors[i].getAttribute('name')==section) { found=anchors[i]; break; }
	if (!found) for (var i=0; i<anchors.length; i++)
		if (anchors[i].getAttribute('name').startsWith(section)) { found=anchors[i]; break; }
	if (!found) for (var i=0; i<anchors.length; i++)
		if (anchors[i].getAttribute('name').indexOf(section)!=-1) { found=anchors[i]; break; }
	if (found) {
		// if section heading is collapsed, click to expand it - see [[FoldHeadingsPlugin]]
		if (hasClass(found,'foldable') && found.nextSibling.style.display=='none') found.onclick();
		// scroll *after* tiddler animation
		var delay=config.options.chkAnimate?config.animDuration+100:0;
		setTimeout('window.scrollTo('+findPosX(found)+','+findPosY(found)+')',delay);
		return found;
	}
}
//}}}
/***
!!!!core hijacks
***/
/***
!!!!!createTiddlyLink
***/
//{{{
// [[tiddlername##section]] and [[##section]]
if (!window.createTiddlyLink_section)
	window.createTiddlyLink_section=window.createTiddlyLink;
window.createTiddlyLink=function(place,title) {
	var t=story.findContainingTiddler(place); var tid=t?t.getAttribute('tiddler'):'';
	var parts=title.split(config.textPrimitives.sectionSeparator);
	var title=parts[0]; var section=parts[1]; if (section) section=section.trim();
	if (!title.length || title.toLowerCase()=='here') title=tid;  // default=current tiddler
	arguments[1]=title;
	var btn=createTiddlyLink_section.apply(this,arguments);
	if (section) {
		btn.setAttribute('section',section);
		if (store.getTiddlerText(title+config.textPrimitives.sectionSeparator+section)===null)
			addClass(btn,'tiddlyLinkNonExistingSection');
	}
	return btn;
}
//}}}
/***
!!!!!onClickTiddlerLink
***/
//{{{
if (!window.onClickTiddlerLink_section)
	window.onClickTiddlerLink_section=window.onClickTiddlerLink;
window.onClickTiddlerLink=function(ev) {
	var e=ev||window.event;	var target=resolveTarget(e); var title=null;
	while (target!=null && title==null) {
		title=target.getAttribute('tiddlyLink');
		section=target.getAttribute('section');
		target=target.parentNode;
	} 
	var t=story.findContainingTiddler(target); var tid=t?t.getAttribute('tiddler'):'';
	if (title!=tid||!section) // avoid excess scrolling for intra-tiddler links
		onClickTiddlerLink_section.apply(this,arguments);
	story.scrollToSection(title,section);
	return false;
}
//}}}
/***
!!!!! displayTiddler
***/
//{{{
if (!Story.prototype.displayTiddler_section)
	Story.prototype.displayTiddler_section=Story.prototype.displayTiddler;
Story.prototype.displayTiddler = function(srcElement,tiddler)
{
	var title=(tiddler instanceof Tiddler)?tiddler.title:tiddler;
	var parts=title.split(config.textPrimitives.sectionSeparator);
	var title=parts[0]; var section=parts[1]; if (section) section=section.trim();
	if (!title.length || title.toLowerCase()=='here') {
		var t=story.findContainingTiddler(place);
		title=t?t.getAttribute('tiddler'):'';
	}
	arguments[1]=title;  // default=current tiddler
	this.displayTiddler_section.apply(this,arguments);
	story.scrollToSection(title,section);
}
//}}}
/***
<html><a name="sampleanchorlink" /></html>This is a sample ''anchor link'': {{{<html><a name="sampleanchorlink" /></html>}}}
!!!!!isExternalLink
***/
//{{{
if (!config.formatterHelpers.isExternalLink_section)
	config.formatterHelpers.isExternalLink_section=config.formatterHelpers.isExternalLink;
config.formatterHelpers.isExternalLink=function(link) {  // remove section references before testing
	var l=link.split(config.textPrimitives.sectionSeparator)[0];
	return config.formatterHelpers.isExternalLink_section(l);
}
//}}}
/***
!!!!!tiddler.handler
***/
//{{{
if (!config.macros.tiddler.handler_section)
	config.macros.tiddler.handler_section=config.macros.tiddler.handler;
config.macros.tiddler.handler=function(place,macroName,params,wikifier,paramString,tiddler)
{
	if (!params[0]) return;
	var sep=config.textPrimitives.sectionSeparator;
	var parts=params[0].split(sep); var tid=parts[0]; var sec=parts[1]; if (sec) sec=sec.trim();
	if ((tid.toLowerCase()=='here'||!tid.length) && sec) { // fixup for 'here##section' and '##section'
		var here=story.findContainingTiddler(place)
		var tid=here?here.getAttribute('tiddler'):tiddler?tiddler.title:'';
		arguments[2][0]=tid+sep+sec;
		arguments[4]=paramString.replace(new RegExp('(here)?'+sep+sec),tid+sep+sec);
	}
	config.macros.tiddler.handler_section.apply(this,arguments);
}
//}}}
/***
!!!!sectionTOC macro
***/
//{{{
config.macros.sectionTOC = {
	targetClass: 'sectionTOC',
	linkFormat: '[[%0|##%0]]',
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		var out=[];
		var targetClass=params[0]||this.targetClass;
		var t=story.findContainingTiddler(place); if (!t) return;
		var elems=t.getElementsByTagName('*');
		var level=5; // topmost heading level
		for (var i=0; i<elems.length; i++) {
			var txt=getPlainText(elems[i]).trim();
			var link=this.linkFormat.format([txt]);
			switch(elems[i].nodeName) {
				case 'H1': out.push('#'+link);		level=1; break;
				case 'H2': out.push('##'+link);		level=level<2?level:2; break;
				case 'H3': out.push('###'+link);	level=level<3?level:3; break;
				case 'H4': out.push('####'+link);	level=level<4?level:4; break;
				case 'H5': out.push('#####'+link);	level=level<5?level:5; break;
				default: if (hasClass(elems[i],targetClass)) var target=elems[i];
			}
		}
		// trim excess bullet levels
		if (level>1) for (var i=0; i<out.length; i++) out[i]=out[i].substr(level-1);
		// show numbered list
		if (out.length && target) {
			if (target.style.display=='none') target.style.display='block';
			wikify(out.join('\n'),target);
		}
	}
}
//}}}
/***
!!!Invoke macro
{{{
<<sectionTOC>>
}}}
***/
// //<<sectionTOC>>
TiddlyTools PHP ShowArgs Test (POST) - one tiddler
<!--{{{-->
<!-- MODIFY THE ACTION URL IN THE FOLLOWING FORM DEFINITION -->
<form target="_blank" method="post" action="http://www.tiddlytools.com/showargs.php" enctype="multipart/form-data">
<input type="hidden" name="source" value="%source%">
<input type="hidden" name="title" value="%title%">
<input type="hidden" name="created" value="%created%">
<input type="hidden" name="modified" value="%modified%">
<input type="hidden" name="author" value="%author%">
<textarea style="width:100%;height:85%;font-size:8pt" rows="20" name="content">source link: %source%#%title% 
created on: %created%
last edit: %modified%
by: %author%
tags: %tags%

%content%</textarea>
<div style="text-align:center">
<input type="submit" value="send">
<input type="reset" value="reset">
<input type="button" value="cancel" onclick="window.close();return false;">
<br><font size=-2>This form is for demonstration purposes only</font><!-- remove after release -->
<br><font size=-2>ALPHA TEST - DO NOT USE IN YOUR OWN DOCUMENT - DO NOT DISTRIBUTE</font><!-- remove after release -->
</div>
</form>
<!--}}}-->
----
TiddlyTools PHP ShowArgs Test (POST) - all tiddlers
<!--{{{-->
<!-- MODIFY THE ACTION URL IN THE FOLLOWING FORM DEFINITION -->
<form target="_blank" method="post" action="http://www.tiddlytools.com/showargs.php" enctype="multipart/form-data">
<input type="hidden" name="source" value="%source%">
Complete TiddlyWiki 'StoreArea' (includes ALL tiddlers):
<textarea style="width:100%;height:75%;font-size:8pt" rows="10" name="content">%alltiddlers%</textarea>
<div style="text-align:center">
<input type="submit" value="send">
<input type="reset" value="reset">
<input type="button" value="cancel" onclick="window.close();return false;">
<br><font size=-2>This form is for demonstration purposes only</font><!-- remove after release -->
<br><font size=-2>ALPHA TEST - DO NOT USE IN YOUR OWN DOCUMENT - DO NOT DISTRIBUTE</font><!-- remove after release -->
</div>
</form>
<!--}}}-->
----
TiddlyTools PHP ShowArgs Test (GET) - one tiddler
<!--{{{-->
<!-- MODIFY THE ACTION URL IN THE FOLLOWING FORM DEFINITION -->
<form target="_blank" method="get" action="http://www.tiddlytools.com/showargs.php">
<input type="hidden" name="source" value="%source%">
<input type="hidden" name="title" value="%title%">
<input type="hidden" name="created" value="%created%">
<input type="hidden" name="modified" value="%modified%">
<input type="hidden" name="author" value="%author%">
<textarea style="width:100%;height:85%;font-size:8pt" rows="20" name="content">source link: %source%#%title% 
created on: %created%
last edit: %modified%
by: %author%
tags: %tags%
- - - - - - - - - - -
%content%</textarea>
<div style="text-align:center">
<input type="submit" value="send">
<input type="reset" value="reset">
<input type="button" value="cancel" onclick="window.close();return false;">
<br><font size=-2>This form is for demonstration purposes only</font><!-- remove after release -->
<br><font size=-2>ALPHA TEST - DO NOT USE IN YOUR OWN DOCUMENT - DO NOT DISTRIBUTE</font><!-- remove after release -->
</div>
</form>
<!--}}}-->
/***
|Name|SendTiddlerPlugin|
|Source|http://www.TiddlyTools.com/#SendTiddlerPlugin|
|Version|0.8.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin,toolbar|
|Requires|[[SendTiddlerConfig]]|
|Description|send tiddler source content or raw storeArea DIVs to remote URLs for server-side storage/processing|
|Status| ALPHA DEVELOPMENT - USE WITH CARE - SUBJECT TO CHANGE |
''sendTiddler'' toolbar command submits tiddler source content to remote URLs for server-side processing.  Useful for posting tiddler content to on-line blog services or custom-built server-side storage mechanisms.
!!!!!Usage
<<<
Select ''send'' tiddler toolbar command to view a popup list of destinations servers.

When you select a server, a separate browser window (or popup) will open, containing a server-specific HTML form for sending the tiddler content along with extra input fields as needed to enter additional information to be sent (e.g., account, username, keywords, options, etc.).  Review/enter information as desired, and then press the ''send'' button.  A separate window will be opened to display the response from the remote server.
<<<
!!!!!Configuration
<<<
Destination servers are defined in the [[SendTiddlerConfig]] tiddler.  Each definition is separated by a {{{----}}} (horizontal rule).  The first line of each definition is the text that will appear in the ''send'' toolbar popup menu.  The remaining lines of each contain an HTML form, beginning with <form method="..." action="..."> appropriate for that destination server, followed by form input fields (and possibly hidden fields) to contain the specific values needed for processing the form on the server.

Some tiddler values can be automatically inserted into the form, based on the tiddler being sent.  To insert these values, you can embed any of the following ''field markers'' into your custom-defined form definition (using a {{{%marker%}}} format). When the form is displayed, these markers will be automatically replaced by the corresponding tiddler field value.
* content - the current contents of the current tiddler
* source - the URL of the current TiddlyWiki document
* title - the title of the current tiddler
* created - the date the tiddler was initially created
* modified - the date the tiddler was last modified
* author - the TiddlyWiki username of the last person to edit the tiddler
* tags - a (space-separated) list of tags for the tiddler
* alltiddlers - all tiddlers, encoded as TW "storeArea" DIVs
* SHA1 - cryto-encoded value corresponding to current tiddler  or alltiddlers content
<<<
!!!!!Installation Notes
<<<
If you are using the default (shadow) ViewTemplate, the plugin automatically updates the template to include the ''sendTiddler'' toolbar command.  If you have created a custom ViewTemplate tiddler, you will need to manually add the ''sendTiddler'' toolbar command to your existing template:
{{{
<!-- add 'sendTiddler' command to existing editor toolbar definition -->
<div class='toolbar' macro='toolbar ... sendTiddler ... '>
}}}
<<<
!!!!!Revisions
<<<
2008.01.05 [0.8.0] added support for 'SHA1' replacement marker (uses Crypto functions to generate hashcode based on content (single tiddler or all tiddlers).  Used by SharedRecords.org.
2007.06.05 [0.7.2] 'edit server list' onclick handler now returns false to prevent IE page transition
2007.02.15 [0.7.0] use split/join for replacing marker text in content (avoids regexp problem with handling of $ in target string)
2007.02.09 [0.6.0] added support for 'alltiddlers' replacement marker
2006.11.05 [0.5.0] alpha test - user-defined forms
2006.11.04 [0.1.0] alpha test - static form definition
2006.11.03 [0.0.0] started
<<<
!!!!!Code
***/
//{{{
version.extensions.SendTiddlerPlugin= {major: 0, minor: 8, revision: 0, date: new Date(2008,1,5)};

config.commands.sendTiddler = {
	text: 'send',
	tooltip: 'send this tiddler\'s source content to a server',
	hideReadOnly: false,
	dateFormat: 'DDD, MMM DDth YYYY hh:0mm:0ss',
	serverList: 'SendTiddlerConfig', // tiddler containing server form definitions
	html: '<html><head><title>Send tiddler to: %description%</title></head>\
		<body style="background:#eee;font-family:arial,helvetica">%form%</body></html>',
	handler: function(event,src,title) {
		config.commands.sendTiddler.showpopup(src);
		event.cancelBubble = true;
		if (event.stopPropagation) event.stopPropagation();
		return false;
	},
	showpopup: function(place) {
		var here=story.findContainingTiddler(place);
		var popup=Popup.create(place); if (!popup) return;
		createTiddlyText(popup,"select a destination:");
		var t=store.getTiddlerText(config.commands.sendTiddler.serverList);
		if (t && t.trim().length) {
			var parts=t.split("\n----\n");
			for (var p=0; p<parts.length; p++) {
				var lines=parts[p].split("\n");
				var label=lines.shift(); // 1st line=popup display text
				var form=lines.join("\n") // remaining lines=form to use
				var a=createTiddlyButton(createTiddlyElement(popup,'li'),
					label, "", config.commands.sendTiddler.invokeForm);
				a.setAttribute("description",label); // server description
				a.setAttribute("tiddler",here?here.getAttribute('tiddler'):null); // send this tiddler
				a.setAttribute("form",form); // form to use
			}
		}
		createTiddlyButton(createTiddlyElement(popup,'li'), 'edit server list...', '',
			function(){story.displayTiddler(null,config.commands.sendTiddler.serverList,2);return false;});
		Popup.show(popup,false);
	},
	invokeForm: function() {
		var id=this.getAttribute('tiddler'); if (!id) return;
		var tid=store.getTiddler(id);
		var html=config.commands.sendTiddler.html;
		html=html.split("%"+"form%").join(this.getAttribute("form"));
		html=html.split("%"+"description%").join(this.getAttribute("description"));
		html=html.split("%"+"source%").join(document.location.href);
		html=html.split("%"+"title%").join(tid.title);
		html=html.split("%"+"author%").join(tid.modifier);
		html=html.split("%"+"created%").join(tid.created.formatString(config.commands.sendTiddler.dateFormat));
		html=html.split("%"+"modified%").join(tid.modified.formatString(config.commands.sendTiddler.dateFormat));
		html=html.split("%"+"tags%").join(tid.tags.join(" "));
		
		var txt=tid.text;
		html=html.split("%"+"content%").join(txt.htmlEncode());
		if (html.indexOf("%"+"alltiddlers%")!=-1) { // only if needed (for efficiency)
			var txt=store.allTiddlersAsHtml();
			html=html.split("%"+"alltiddlers%").join(txt.htmlEncode());
		}
		if (Crypto && (html.indexOf("%"+"SHA1%")!=-1)) { // only if needed (for efficiency)
			var sha1=Crypto.hexSha1Str(txt).toLowerCase();
			html=html.split("%"+"SHA1%").join(sha1);
		}
		// create and submit hidden form
		var f=document.getElementById("sendTiddlerFrame");
		if (f) document.body.removeChild(f);
		var f=createTiddlyElement(document.body,"iframe","sendTiddlerFrame");
		f.style.width="0px"; f.style.height="0px"; f.style.border="0px";
		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(html); d.close();
		d.getElementsByTagName("form")[0].submit();
		return false;
	}
};

// tweak shadow ViewTemplate to add "sendTiddler" command (following "editTiddler")
config.shadowTiddlers.ViewTemplate=config.shadowTiddlers.ViewTemplate.replace(/editTiddler/,"editTiddler sendTiddler");
//}}}
/***
|Name|SetIconPlugin|
|Source|http://www.TiddlyTools.com/#SetIconPlugin|
|Documentation|http://www.TiddlyTools.com/#SetIconPluginInfo|
|Version|1.9.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.3|
|Type|plugin|
|Description|add an image to a toolbar, macro, or slider link|
!!!!!Documentation
>see [[SetIconPluginInfo]]
!!!!!Configuration
<<<
<<option chkIconsShowImage>> show images on links
<<option chkIconsShowText>> include link text with images
default image style: {{stretch{<<option txtIconsCSS>>}}}
<<<
!!!!!Revisions
<<<
2011.10.02 1.9.1 use plain text instead of innerHTML for link tooltips
2011.10.02 1.9.0 added 'find:...' macro param (for use with tabsets)
| see [[SetIconPluginInfo]] for additional revision details |
2008.05.09 1.0.0 initial release (as inline script)
<<<
!!!!!Code
***/
//{{{
version.extensions.SetIconPlugin= {major: 1, minor: 9, revision: 1, date: new Date(2011,10,2)};

if (config.options.chkIconsShowImage===undefined)
	config.options.chkIconsShowImage=true;
if (config.options.chkIconsShowText===undefined)
	config.options.chkIconsShowText=true;
if (config.options.txtIconsCSS===undefined)
	config.options.txtIconsCSS="vertical-align:middle;width:auto;height:auto";

config.macros.setIcon = {
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		if (!config.options.chkIconsShowImage) return; // text-only - do nothing
		var src=params[0]; if (!src) return;  // no image src specified - do nothing
		var p=paramString.parseParams('name',null,true,false,true);
		var label=getParam(p,'find'); if (label) params.shift(); // optional find:"..."
		var css=params[1]; if (!css||!css.length) css=config.options.txtIconsCSS;
		var after=params[2]&&params[2].toUpperCase()=="RIGHT";
		var notext=params[2]&&params[2].toUpperCase()=="NOTEXT";

		// find nearest link element
		var btn=place.lastChild; // look for sibling link
		while (btn && (btn.nodeName!="A" || label&&!btn.innerHTML.startsWith(label)))
			btn=btn.previousSibling;
		if (!btn) { // look for child link
			var links=place.getElementsByTagName("A");
			for (var i=links.length-1; i>=0; i--)
				if (!label || links[i].innerHTML.startsWith(label)) { btn=links[i]; break; }
		}
		if (!btn) { // look for parent link
			var btn=place.parentNode.lastChild;
			while (btn && (btn.nodeName!="A" || label&&!btn.innerHTML.startsWith(label)))
				btn=btn.previousSibling;
		}
		if (!btn) { // look for cousin link (e.g. TABS in TABSETS)
			var links=place.parentNode.getElementsByTagName("A");
			for (var i=links.length-1; i>=0; i--)
				if (!label || links[i].innerHTML.startsWith(label)) { btn=links[i]; alert('found'); break; }
		}
		if (!btn) return; // can't find a link - do nothing

		// set icon and command text/tip
		var txt=btn.innerHTML; var tip=getPlainText(btn);
		if (config.macros.attach && config.macros.attach.isAttachment(src))
			src=config.macros.attach.getAttachment(src); // retrieve attachment (if any)
		btn.innerHTML="<img src='"+src+"' style='"+css+"'>";
		if (config.options.chkIconsShowText && !notext)
			btn.innerHTML=after?txt+btn.innerHTML:btn.innerHTML+txt;
		else
			btn.title=tip+" - "+btn.title; // add text to tooltip

		// adjust nested slider button text/tip
		if (btn.getAttribute("closedtext")!=null) {
			btn.setAttribute("closedtext",btn.innerHTML);
			btn.setAttribute("openedtext",btn.innerHTML);
			if (!config.options.chkIconsShowText || notext) {
				btn.setAttribute("closedtip",txt.toUpperCase()+": "+btn.getAttribute("closedtip"));
				btn.setAttribute("openedtip",txt.toUpperCase()+": "+btn.getAttribute("openedtip"));
			}
		}
	}
};
//}}}
/***
|Name|SetIconPlugin|
|Source|http://www.TiddlyTools.com/#SetIconPlugin|
|Documentation|http://www.TiddlyTools.com/#SetIconPluginInfo|
|Version|1.9.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.3|
|Type|documentation|
|Description|documentation for SetIconPlugin|
!!!!!Syntax
<<<
{{{
<<setIcon image find:"..." style iconpos>>
}}}
where:
*''image''<br>tiddlername for an attached image or a URL for an external image
*''find:"..."''(optional)<br>finds a link that starts with the specified text (for use with """<<tabs>>""")
*''style'' (optional)<br>CSS style attributes applied to the image (default="vertical-align:middle;width:auto;height:auto")
*''iconpos''(optional)<br>indicates the placement of the image relative to the link text.  Use keywords: ''left'', ''right'' or ''notext'' (default=''left'', i.e., the text follows the image).  ''notext'' hides the link text, even if the global option (see Configuration section, below) is set to display the link text along with image.  //Note:  when specifying the non-default //''right''// or //''notext''// value, you can use "" as a placeholder for the ''style'' parameter to apply the standard CSS styles)//
<<<
!!!!!Usage
<<<
First, create a link element using any of:
* ''links:''<br>&nbsp;&nbsp;"""[[TiddlerName]]""" or """[[text|TiddlerName]]""" or """[[text|URL]]"""
* ''macros that generate links:''<br>&nbsp;&nbsp;"""<<toolbar ...>>""", """<<slider ...>>""", """<<tabs ...>>""", """<<saveChanges>>""", etc.
* ''inline sliders:'' (using NestedSlidersPlugin)<br>&nbsp;&nbsp;"""+++[sliderlabel]...==="""
* '''onclick' scripts:'' (using InlineJavascriptPlugin)<br>&nbsp;&nbsp;"""<script label="...">...</script>"""
* ''~HTML-based links:''<br>&nbsp;&nbsp;"""<html><a href="...">...</a></html>"""
* ''transcluded links:'' (where the output of the specified ~TiddlerName contains a link)<br>&nbsp;&nbsp;"""<<tiddler TiddlerName>>""" 
Then, ''embed the """<<setIcon>>""" macro immediately following the generated link''.  The macro looks for the last rendered link element that occurs //within the same DOM container// and adds the specified image to that link.  If an optional find:"..." parameter is provided, then the macro looks for a matching link that starts with the indicated label, working backward from the last rendered link within the DOM container.

Note: links embedded via the """<<tiddler>>""" macro or HTML syntax are rendered within a //child// DOM element container.  To ensure that """<<setIcon>>""" will find the correct link, you can isolate the child DOM element container along with the associated """<<setIcon>>""" macro that follows it by enclosing both elements within a surrounding SPAN 'class wrapper' element, like this:
{{{
{{span{<<tiddler SomeTranscludedLink>><<setIcon ...>>}}}
{{span{<html><a href="...">...</a></html><<setIcon ...>>}}}
}}}
This same technique should also be applied for any other macros that may generate output that is nested within their own containing DOM elements.  Similarly, link elements created by macros embedded directly in the ViewTemplate or EditTemplate using HTML syntax (i.e, """<span macro='...'></span>""") are also rendered within their own DOM element containers.  To ensure that the correct link is located, """<span macro='setIcon ...'></span>""" should be inserted //within// the span that invokes the link-generating macro, like this:
{{{
<span macro='...'>
   <span macro='setIcon ...'></span>
</span>
}}}
Alternatively, your can surround the paired link+icon sequence in an enclosing span, like this:
{{{
<span>
   <span macro='...'></span>
   <span macro='setIcon ...'></span>
</span>
}}}
''In general, whether the link element is rendered in tiddler content or directly from a template, if you are uncertain when an 'isolation span' is needed, you can always choose to surround every link+icon sequence within a enclosing span, regardless of the type of link content being rendered.''
<<<
!!!!!Examples
<<<
''~TiddlyLink:'' [[About]]<<setIcon information.png>>
{{{
[[About]]<<setIcon information.png>>
}}}
''toolbar command:'' <<toolbar jump>><<setIcon page_go.png>>
{{{
in tiddler content:
	<<toolbar jump>><<setIcon page_go.png>>
in template definitions:
	<span class='toolbar' macro='toolbar jump'>
		<span macro='setIcon page_go.png'></span>
	</span>
}}}
''slider macro:''<<slider "" PluginManager Plugins "view installed plugin status">><<setIcon cog.png>>
{{{
in tiddler content:
	<<slider "" PluginManager Plugins "view installed plugin status">><<setIcon cog.png>>
in template definitions:
	<span macro='slider ...'>
		<span macro='setIcon page_go.png'></span>
	</span>
}}}
''nested (inline) slider:'' +++[settings]<<list filter [tag[settings]]>>===<<setIcon wrench.png>>
{{{
+++[settings]
	<<list filter [tag[settings]]>>
===<<setIcon wrench.png>>
}}}
''onclick script:'' <script label="print document">window.print();</script><<setIcon printer.png>>
{{{
<script label="print document">
	window.print();
</script><<setIcon printer.png>>
}}}
''tiddler macro:'' {{span{<<tiddler SiteUrl>><<setIcon exclamation.png>>}}}
{{{
in tiddler content:
	{{span{<<tiddler SiteUrl>><<setIcon exclamation.png>>}}}
in template definitions:
	<span macro='tiddler ...'>
		<span macro='setIcon exclamation.png'></span>
	</span>
}}}
''tabs macro:'' {{span{<<tabs chkDemo About About About Legal Legal LegalStatements>><<setIcon information.png find:"About">><<setIcon exclamation.png find:"Legal">>}}}
{{{
in tiddler content:
	{{span{<<tabs chkTest About ... Legal ...>><<setIcon information.png find:"About">><<setIcon exclamation.png find:"Legal">>}}}
in template definitions:
	<span macro='tabs chkDemo About ... Legal ...>
		<span macro='setIcon information.png find:"About"'></span>
		<span macro='setIcon exclamation.png find:"Legal"'></span>
        </span>
}}}
''HTML link:'' {{span{<html><a href="http://www.TiddlyWiki.com">TiddlyWiki.com</a></html><<setIcon server_go.png>>}}}
{{{
in tiddler content:
	{{span{<html><a href="http://www.TiddlyWiki.com">TiddlyWiki.com</a></html><<setIcon server_go.png>>}}}
in template definitions:
	<span>
		<a href="http://www.TiddlyWiki.com">TiddlyWiki.com</a>
		<span macro='setIcon server_go.png'></span>
	</span>
}}}
''macro link:'' {{span{<<saveChanges>><<setIcon disk.png>>}}}
{{{
in tiddler content:
	{{span{<<saveChanges>><<setIcon disk.png>>}}}
in template definitions:
	<span macro='saveChanges'>
		<span macro='setIcon disk.png'></span>
	</span>
}}}
<<<
!!!!!Configuration
<<<
<<option chkIconsShowImage>> show icons on links //(unchecked=text-only)//
^^{{{<<option chkIconsShowImage>>}}}^^
<<option chkIconsShowText>> include link text with images //(unchecked=icons-only, ignored if no icons displayed)//
^^{{{<<option chkIconsShowText>>}}}^^
default image style: {{stretch{<<option txtIconsCSS>>}}}
^^{{{<<option txtIconsCSS>>}}}^^
<<<
!!!!!Revisions
<<<
2011.10.02 1.9.1 use plain text instead of innerHTML for link tooltips
2011.10.02 1.9.0 added 'find:...' macro param (for use with tabsets)
2008.05.11 1.8.0 added optional 'notext' value for iconpos to force text to be hidden for specific links
2008.05.11 1.7.0 support use within template definitions by looking for nearest link using: siblings, children, parents, or cousins.  Also, major documentation re-write with improved examples
2008.05.11 1.6.0 added optional iconpos param to control icon placement ("left" or "right", default="left")
2008.05.10 1.5.0 converted to plugin/macro and reduced code size by moving documentation into SetIconPluginInfo
2008.05.10 1.4.0 handle links contained in {{{<<tiddler>>}}} and {{{<html>...</html}}}
2008.05.10 1.3.0 added support for setting styles on images
2008.05.09 1.2.0 handle links created by TiddlyLinks, sliders, and nested sliders syntax
2008.05.09 1.1.0 added support for external URLs and options for displaying text with images
2008.05.09 1.0.0 initial release (as inline script)
<<<
/%
!info
|Name|SetPopupsHeight|
|Source|http://www.TiddlyTools.com/#SetPopupsHeight|
|Version|2.0.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Description|use CSS to set a scrolling, fixed or percentage height for popups (e.g. tags display)|
Usage
<<<
{{{
<<tiddler SetPopupsHeight>>
}}}
Try it:
<<tiddler SetPopupsHeight##show>>
<<<
!end

!show
<<tiddler {{
	if (config.options.txtPopupsHeight===undefined)
		config.options.txtPopupsHeight='auto';
'';}}>>popup height: {{smallform{<<option txtPopupsHeight>><<tiddler {{
	var t=place.lastChild;
	t.style.width='4em'; t.style.textAlign='center';
	t.title='enter height using px, em, in, cm, %, or auto';
	t.onfocus=function(){this.select();};
	t.onblur=function(){this.onchange();}; /* for IE */
	if (!t.coreOnChange) t.coreOnChange=t.onchange;
	t.onchange=function() { // hijack: update CSS when field changes
		if (this.coreOnChange) this.coreOnChange();
		window.setPopupsHeight();
	};
	window.setPopupsHeight=function() {
		var opt='txtPopupsHeight';
		var h=config.options[opt]; if (!h.length) h='auto';
		if (!h.replace(/[0-9]*/,'').length) h+='px';
		config.macros.option.propagateOption(opt,'value',h,'input');
		if (config.options[opt]=='auto') removeCookie(opt);
		var top=findPosY(document.getElementById('tiddlerDisplay'));
		if (h.indexOf('%')!=-1)
			h=((findWindowHeight()-top)*parseInt(h.replace(/[%]/,''))/100)+'px';
		var heightParam=(config.browser.isIE?'height':'max-height')+':'+h;
		var overflowParam='overflow:'+(h!='auto'?'auto':'visible')+' !important'; 
		var css='.popup { '+heightParam+'; '+overflowParam+'; }';
		setStylesheet(css,'popupStyles');
	};
	if (window.addEventListener) // so % height can auto-adjust if window is resized
		window.addEventListener('resize',window.setPopupsHeight,false);
	if (window.removeCookie===undefined) { // if not already defined by TW core...
		window.removeCookie=function(name) {
			document.cookie = name+'=; expires=Thu, 01-Jan-1970 00:00:01 UTC; path=/;'; 
		};
	}
	window.setPopupsHeight(); // apply CSS during startup


'';}}>>}}}
!end

%/<<tiddler {{var src='SetPopupsHeight'; src+(tiddler&&tiddler.title==src?'##info':'##show');}}>>
/%
!info
|Name|SetSidebarTabsHeight|
|Source|http://www.TiddlyTools.com/#SetSidebarTabsHeight|
|Version|2.0.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Description|use CSS to set a fixed, scrolling or percentage height for the sidebar tabs area|
Usage
<<<
{{{
<<tiddler SetSidebarTabsHeight>>
}}}
Try it:
<<tiddler SetSidebarTabsHeight##show>>
<<<
!end

!show
<<tiddler {{
	if (config.options.txtSidebarTabsHeight===undefined)
		config.options.txtSidebarTabsHeight='auto';
'';}}>>tabs height: {{smallform{<<option txtSidebarTabsHeight>><<tiddler {{
	var t=place.lastChild;
	t.style.width='4em'; t.style.textAlign='center';
	t.title='enter height using px, em, in, cm, %, or auto';
	t.onfocus=function(){this.select();};
	t.onblur=function(){this.onchange();}; /* for IE */
	if (!t.coreOnChange) t.coreOnChange=t.onchange;
	t.onchange=function() { // hijack: update CSS when field changes
		if (this.coreOnChange) this.coreOnChange();
		window.setSidebarTabsHeight();
	};
	window.setSidebarTabsHeight=function() {
		var opt='txtSidebarTabsHeight';
		var h=config.options[opt]; if (!h.length) h='auto';
		if (!h.replace(/[0-9]*/,'').length) h+='px';
		config.macros.option.propagateOption(opt,'value',h,'input');
		if (config.options[opt]=='auto') removeCookie(opt);
		var top=findPosY(document.getElementById("sidebarTabs"));
		if (h.indexOf('%')!=-1)
			h=((findWindowHeight()-top)*parseInt(h.replace(/[%]/,''))/100)+'px';
		var heightParam=(config.browser.isIE?"height":"max-height")+":"+h;
		var overflowParam='overflow:'+(h!='auto'?'auto':'hidden')+' !important'; 
		var css='#sidebarTabs { '+heightParam+'; '+overflowParam+'; }';
		setStylesheet(css,"sidebarTabsStyles");
	};
	if (window.addEventListener) // so % height can auto-adjust if window is resized
		window.addEventListener('resize',window.setSidebarTabsHeight,false);
	if (window.removeCookie===undefined) { // if not already defined by TW core...
		window.removeCookie=function(name) {
			document.cookie = name+'=; expires=Thu, 01-Jan-1970 00:00:01 UTC; path=/;'; 
		};
	}
	window.setSidebarTabsHeight(); // apply CSS during startup
'';}}>>}}}
!end

%/<<tiddler {{var src='SetSidebarTabsHeight'; src+(tiddler&&tiddler.title==src?'##info':'##show');}}>>
/%
!info
|Name|SetStoryHeight|
|Source|http://www.TiddlyTools.com/#SetStoryHeight|
|Version|2.0.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Description|set a scrolling, fixed or percentage height for the central story|
Usage
<<<
{{{
<<tiddler SetStoryHeight>>
}}}
Try it:
<<tiddler SetStoryHeight##show>>
<<<
!end

!show
<<tiddler {{
	if (config.options.txtStoryHeight===undefined)
		config.options.txtStoryHeight='auto';
'';}}>>story height: {{smallform{<<option txtStoryHeight>><<tiddler {{
	var t=place.lastChild;
	t.style.width='4em'; t.style.textAlign='center';
	t.title='enter height using CSS px, em, in, cm, % or auto';
	t.onfocus=function(){this.select();};
	t.onblur=function(){this.onchange();};
	if (!t.coreOnChange) t.coreOnChange=t.onchange;
	t.onchange=function() { // hijack: update CSS when field changes
		if (this.coreOnChange) this.coreOnChange();
		window.setStoryHeight();
	};
	window.setStoryHeight=function() {
		var opt='txtStoryHeight';
		var h=config.options[opt]; if (!h.length) h='auto';
		if (!h.replace(/[0-9]*/,'').length) h+='px';
		config.macros.option.propagateOption(opt,'value',h,'input');
		if (h=='auto') removeCookie(opt);
		var top=findPosY(document.getElementById('tiddlerDisplay'));
		if (h.indexOf('%')!=-1)
			h=((findWindowHeight()-top)*parseInt(h.replace(/[%]/,''))/100)+'px';
		var heightParam=(config.browser.isIE?'height':'max-height')+':'+h;
		var overflowParam='overflow:'+(h!='auto'?'auto':'visible')+' !important'; 
		var css='#tiddlerDisplay { '+heightParam+'; '+overflowParam+'; }';
		setStylesheet(css,'storyHeightStyles');
	};
	if (window.addEventListener) // so % height can auto-adjust if window is resized
		window.addEventListener('resize',window.setStoryHeight,false);
	if (window.removeCookie===undefined) { // if not already defined by TW core...
		window.removeCookie=function(name) {
			document.cookie = name+'=; expires=Thu, 01-Jan-1970 00:00:01 UTC; path=/;'; 
		};
	}
'';}}>>
!end

%/<<tiddler {{var src='SetStoryHeight'; src+(tiddler&&tiddler.title==src?'##info':'##show');}}>>
/%
!info
|Name|SetTiddlerBackground|
|Source|http://www.TiddlyTools.com/#SetTiddlerBackground|
|Version|2.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|Type|transclusion|
|Description|set tiddler background and font color CSS attributes|
Usage
<<<
{{{
<<tiddler SetTiddlerBackground with: bgstyle fgstyle matchtag class>>
}}}
*''bgstyle'' and ''fgstyle'' (optional, but specify at least one)<br>are CSS background style attributes (most often color values, e.g., #rgb or #rrggbb)
*''matchtag'' (optional)<br>is a tag value that allows selective control of tiddler background/foreground colors
*''class'' (optional)<br>is the class of the tiddler element to which the fgstyle/bgstyle will be applied Default is 'viewer'.  Use 'title' to set the background of the tiddler's 'title' area instead of its 'viewer' area.
The bgstyle and fgstyle assignments are only performed if the tiddler has the matching tag (or if no matchtag value is specified).  Also, to set either bgstyle or fgstyle (but not both), you can use a dash ('-') as a placeholder for the value you do NOT want to set.  For example:
{{{
<<tiddler SetTiddlerBackground with: #F00 - urgent>>
}}}
sets the bgstyle (but NOT the fgstyle) to RED for only those tiddlers tagged with 'urgent'.  Also, note that in that instead of using #RGB color definitions, you can also use CSS color keywords (i.e., 'red', 'yellow', 'green') or *any* other valid CSS value that can be applied to the 'background' style attribute.  For example, to use a background image for any tiddler tagged with 'wallpaper', you can write:
{{{
<<tiddler SetTiddlerBackground with: url("images/bg.jpg") - wallpaper>>
}}}
You can use this script several times in a row to define a set of tag-to-color mappings, stored in a *single* convenient tiddler (e.g, [[BackgroundColors]]), containing something like this:
{{{
<<tiddler SetTiddlerBackground with: red - urgent>>
<<tiddler SetTiddlerBackground with: yellow - active>>
<<tiddler SetTiddlerBackground with: green - done>>
}}}
To apply the set of tag-based color mappings, embed:
{{{
<<tiddler BackgroundColors>> (in tiddler content) OR
<span macro='tiddler BackgroundColors' style='display:none'></span> (in ViewTemplate, for all tiddlers)
}}}
and then set the desired tag value(s) onto specific tiddlers.  To add more color mappings, just edit the [[BackgroundColors]] tiddler and then start tagging tiddlers accordingly.
<<<
!end
!show
<<tiddler {{
	if ('$1'!='$'+'1' && '$1'!='-') var bg='$1';
	if ('$2'!='$'+'2' && '$2'!='-') var fg='$2';
	if ('$3'!='$'+'3' && '$3'!='-') var tag='$3';
	if ('$4'!='$'+'4' && '$4'!='-') var c='$4'; else var c='viewer';
	var here=story.findContainingTiddler(place);
	var t=store.getTiddler(here?here.getAttribute('tiddler'):'');
	if (!tag||t&&t.isTagged(tag)) {
		var e=here;
		if (c!='tiddler') {
			var elems=e.getElementsByTagName('*');
			for (var i=0; i<elems.length; i++)
				if (hasClass(elems[i],c)) { var e=elems[i]; break; }
		}
		if (e&&bg) { e.style.backgroundImage='none'; e.style.background=bg; }
		if (e&&fg) { e.style.color=fg; }
	}
'';}}>>
!end
%/<<tiddler {{var src='SetTiddlerBackground'; src+(tiddler&&tiddler.title==src?'##info':'##show');}}
	with: [[$1]] [[$2]] [[$3]] [[$4]]>>
/%
!info
|Name|SetTiddlerColumns|
|Source|http://www.TiddlyTools.com/#SetTiddlerColumns|
|Version|2.0.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Description|use CSS3 '-moz-column-count' to set single or multi-column tiddler layout|
Usage
<<<
{{{
<<tiddler SetTiddlerColumns>>
}}}
*note: '-moz-column-count' not available in InternetExplorer
Try it:
<<tiddler SetTiddlerColumns##show>>
<<<
!end

!show
<<tiddler {{
	if (config.options.txtTiddlerColumns===undefined)
		config.options.txtTiddlerColumns='1';
'';}}>>tiddler columns: {{smallform{<<option txtTiddlerColumns>><<tiddler {{
	var t=place.lastChild;
	t.style.width='4em'; t.style.textAlign='center';
	t.title='enter number of columns';
	t.onfocus=function(){this.select();};
	t.onblur=function(){this.onchange();}; /* for IE */
	if (!t.coreOnChange) t.coreOnChange=t.onchange;
	t.onchange=function() { // hijack: update CSS when field changes
		if (this.coreOnChange) this.coreOnChange();
		window.setTiddlerColumns();
	};
	window.setTiddlerColumns=function() {
		var opt='txtTiddlerColumns';
		var cols=config.options[opt]||''; if (!cols.length) cols='1';
		config.macros.option.propagateOption(opt,'value',cols,'input');
		if (cols=='1') removeCookie(opt);
		if (!config.browser.isIE)
			document.getElementById('tiddlerDisplay').style.MozColumnCount=cols;
	}
	if (window.removeCookie===undefined) { // if not already defined by TW core...
		window.removeCookie=function(name) {
			document.cookie = name+'=; expires=Thu, 01-Jan-1970 00:00:01 UTC; path=/;'; 
		}
	}
	window.setTiddlerColumns(); // apply CSS during startup

'';}}>>
!end

%/<<tiddler {{var src='SetTiddlerColumns'; src+(tiddler&&tiddler.title==src?'##info':'##show');}}>>
/%
!info
|Name|SetTiddlerHeight|
|Source|http://www.TiddlyTools.com/#SetTiddlerHeight|
|Version|2.0.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Description|use CSS to set a fixed or percentage height for each tiddler|
Usage
<<<
{{{
<<tiddler SetTiddlerHeight>>
}}}
Try it:
<<tiddler SetTiddlerHeight##show>>
<<<
!end

!show
<<tiddler {{
	if (config.options.txtTiddlerHeight===undefined)
		config.options.txtTiddlerHeight='auto';
'';}}>>tiddler height: {{smallform{<<option txtTiddlerHeight>><<tiddler {{
	var t=place.lastChild;
	t.style.width='4em'; t.style.textAlign='center';
	t.title='enter height using px, em, in, cm, %, or auto';
	t.onfocus=function(){this.select();};
	t.onblur=function(){this.onchange();}; /* for IE */
	if (!t.coreOnChange) t.coreOnChange=t.onchange;
	t.onchange=function() { // hijack: update CSS when field changes
		if (this.coreOnChange) this.coreOnChange();
		window.setTiddlerHeight();
	};
	window.setTiddlerHeight=function() {
		var opt='txtTiddlerHeight';
		var h=config.options[opt]; if (!h.length) h='auto';
		if (!h.replace(/[0-9]*/,'').length) h+='px';
		config.macros.option.propagateOption(opt,'value',h,'input');
		if (config.options[opt]=='auto') removeCookie(opt);
		var top=findPosY(document.getElementById('tiddlerDisplay'));
		if (h.indexOf('%')!=-1)
			h=((findWindowHeight()-top)*parseInt(h.replace(/[%]/,''))/100)+'px';
		var heightParam=(config.browser.isIE?'height':'max-height')+':'+h;
		var overflowParam='overflow:'+(h!='auto'?'auto':'visible')+' !important'; 
		var css='.viewer { '+heightParam+'; '+overflowParam+'; }';
		setStylesheet(css,'tiddlerHeightStyles');
	};
	if (window.addEventListener) // so % height can auto-adjust if window is resized
		window.addEventListener('resize',window.setTiddlerHeight,false);
	if (window.removeCookie===undefined) { // if not already defined by TW core...
		window.removeCookie=function(name) {
			document.cookie = name+'=; expires=Thu, 01-Jan-1970 00:00:01 UTC; path=/;'; 
		};
	}
	window.setTiddlerHeight(); // apply CSS during startup
'';}}>>}}}
!end

%/<<tiddler {{var src='SetTiddlerHeight'; src+(tiddler&&tiddler.title==src?'##info':'##show');}}>>
/***
|Name|SetUserNamePlugin|
|Source|http://www.TiddlyTools.com/#SetUserNamePlugin|
|Version|1.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|prompt for TiddlyWiki username|
!!!!!Usage
<<<
{{{
<<setUserName>>
<<setUserName force>>
}}}
If the default username ("YourName") is currently set, the macro automatically prompts for a new username. The optional 'force' keyword triggers a prompt even if a non-default username has already been set.  When the plugin is installed, the default (shadow) EditTemplate definition is updated to invoke the macro (using 
template syntax: {{{<span macro='setUserName'></span>}}}).  As a result, whenever a user attempts to edit/create a tiddler AND have not yet entered a username, they will be automatically prompted to enter a new username.  If you are using a customized EditTemplate, you will need to edit it yourself to add the above syntax.

{{{
<<showUserName>>
}}}
Displays the current username.  Clicking the name prompts for a new username.  Note: for backward-compatibility, the plugin also creates a shadow tiddler named [[ShowUserName]] so you can invoke the macro by using: {{{<<tiddler ShowUserName>>}}}
<<<
!!!!!Revisions
<<<
2012.07.11 1.1.0 added ShowUserName macro and shadow (replaces ShowUserName transclusion)
2006.12.01 1.0.0 initial release - converted from SetUserName inline script
<<<
!!!!!Code
***/
//{{{
version.extensions.SetUserNamePlugin= {major: 1, minor: 1, revision: 0, date: new Date(2012,7,11)};

config.macros.setUserName = {
	msg: "Please set your username",
	handler: function(place,macroName,params) {
		// only prompt when needed or forced
		var force=params[0]&&params[0].toLowerCase()=="force";
		if (!force && (readOnly || config.options.txtUserName!="YourName")) return;
		var opt="txtUserName";
		var who=prompt(this.msg,config.options[opt]);
		if (!who||!who.trim().length) return; // cancelled by user
		config.options[opt]=who;
		saveOptionCookie(opt);
		config.macros.option.propagateOption(opt,"value",config.options[opt],"input");
	}
}

config.macros.showUserName = {
	msg: "click to set your username",
	handler: function(place,macroName,params) {
		createTiddlyButton(place,config.options.txtUserName,this.msg,this.action);
	},
	action: function(ev) {
		var place=resolveTarget(ev);
		config.macros.setUserName.handler(resolveTarget(ev),"showUserName",['force']);
		place.innerHTML=config.options.txtUserName;
		return false;
	}
}

config.shadowTiddlers.ShowUserName="<<showUserName>>";

// add trigger to default shadow EditTemplate (custom templates: add this by hand)
config.shadowTiddlers.EditTemplate+="<span macro='setUserName'></span>";
//}}}
/%
!info
|Name|ShowAge|
|Source|http://www.TiddlyTools.com/#ShowAge|
|Version|1.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|Type|transclusion|
|Description|show elapsed years/months/days between two dates|
Usage
<<<
{{{
<<tiddler ShowAge with: startdate enddate>>
}}}
*''startdate''<br>starting date, using any javascript-recognized date format, such as ''YYYY/MM/DD'' ("1962/07/24"), or ''MM/DD/YYY'' ("07/24/1962"), or ''Month DD, YYY'' ("July 24, 1962").  Use keyword ''today'' for the current date.
*''enddate'' (optional, default=''"today"'')<br>ending date, using javascript-recognized date format
Note: the elapsed date calculation uses an //averaged// 30.4 days/month.  For dates greater than one month apart, the resulting number of elapsed //days// may be only approximate.
<<<
Examples
<<<
*{{{This tiddler is <<tiddler ShowAge with: "2009/10/23">> old}}}<br>This tiddler is <<tiddler ShowAge##show with: "2009/10/23">> old
*{{{Eric is <<tiddler ShowAge with: "July 24, 1962">> old}}}<br>Eric is <<tiddler ShowAge##show with: "July 24, 1962">> old
*{{{There are <<tiddler ShowAge with: "today" "January 1, 2100">> until the next century}}}<br>There are <<tiddler ShowAge##show with: "today" "January 1, 2100">> until the next century
<<<
!end

!show
<<tiddler ShowAge##out with: {{
	var out=[];
	var start=new Date(); if ('$1'!='$'+'1' && '$1'!='today') start=new Date('$1');
	var end  =new Date(); if ('$2'!='$'+'2' && '$2'!='today') end  =new Date('$2');
	var hs=3600000; var ds=24*hs; var ms=30.4*ds; var ys=365*ds;
	var age=end.getTime()-start.getTime();
	var y=Math.floor(age/ys);
	var m=Math.floor((age-y*ys)/ms);
	var d=Math.floor((age-y*ys-m*ms)/ds)+1;
	if (y) out.push(y+' year' +(y>1?'s':''));
	if (m) out.push(m+' month'+(m>1?'s':''));
	if (d) out.push(d+' day'  +(d>1?'s':''));
	if (!out.length) out.push('0 days');
out.join(', ');}}>>
!out
$1
!end

%/<<tiddler {{var src='ShowAge'; src+(tiddler&&tiddler.title==src?'##info':'##show');}}
	with: [[$1]] [[$2]]>>
/%
|Name|ShowAllByTags|
|Source|http://www.TiddlyTools.com/#ShowAllByTags|
|Version|1.1.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|script|
|Requires|InlineJavascriptPlugin|
|Description|for each tag, show a numbered list of all tiddlers with that tag|

Usage:
	<<tiddler ShowAllByTags with: "tag tag tag">>
where
	"tag tag tag" (optional)
		quoted, space-separated, bracketed list of tags to **exclude** from the display

!Revisions
2008.08.04 [1.1.0] added optional parameter to exclude specified tags
!end Revisions

%/<script>
	var ex=[];
	if ("$1"!="$"+"1") ex="$1".readBracketedList();
	var tags = store.getTags();
	if(tags.length == 0) return "no tags in document";
	var out="";
	for(var t=0; t<tags.length; t++) {
		if (ex.contains(tags[t][0])) continue;
		out+="*[["+tags[t][0]+"]] ("+tags[t][1]+")"+"\n";
		var tids=store.getTaggedTiddlers(tags[t][0]);
		for (i=0; i<tids.length; i++) out+="##[["+tids[i].title+"]]\n";
	}
	return out;
</script>
/%

NOTE: To be properly displayed, this tiddler needs HTMLFormattingPlugin installed

%/<html><hide linebreaks><table class="borderless"><tr><td style="text-align:center">
	[[Tiddler Icons|ShowAllIcons]] (from the [[Silk|http://www.famfamfam.com/lab/icons/silk/]] collection): &nbsp;<br>
	{{fine{//(move mouse over icons to view descriptions) &nbsp; //}}}
</td><td>
	<a href="javascript:;" style="background:transparent; display:block; padding-top:.5em"
		onclick="story.displayTiddler(story.findContainingTiddler(this),'ShowAllIcons');return false;">
	<<tiddlerIcons recent>>
	<<tiddlerIcons changed>>
	<<tiddlerIcons unsaved>>
	<<tiddlerIcons Trash>>
	<<tiddlerIcons core>>
	<<tiddlerIcons systemConfig>>
	<<tiddlerIcons tag>>
	<<tiddlerIcons CSS>>
	<<tiddlerIcons html>>
	<<tiddlerIcons template>>
	<<tiddlerIcons script>>
	<<tiddlerIcons attachment>>
	<<tiddlerIcons settings>>
	<<tiddlerIcons pluginInfo>>
	<<tiddlerIcons faq>>
	<<tiddlerIcons task>>
	</a>
</td></tr></table></html>
/%
|Name|ShowAllPermalinks|
|Source|http://www.TiddlyTools.com/#ShowAllPermalinks|
|Version|1.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|script|
|Description|generate a list containing permalinks for every tiddler in the document|
%/{{small smallform{<html><form style='display:inline'>
	<textarea name=txt rows=10 style='width:100%' onfocus="this.select()"></textarea>
</form></html><script>
	var out=outtxt=""; 
	var tids=store.getTiddlers("title","excludeLists");
	for (var t=0; t<tids.length; t++) {
		var url=store.getTiddlerText("SiteUrl");
		if (!url) url=document.location.href;
		var permalink=encodeURIComponent(String.encodeTiddlyLink(tids[t].title));
		out+="[["+tids[t].title+"|"+url+"#"+permalink+"]]\n";
		outtxt+=url+"#"+permalink+"\n";
	}
	place.lastChild.firstChild.txt.value=outtxt;
	return "{{threecolumns{"+out+"}}}";
</script>}}}
/%
!info
|Name|ShowDocumentInfo|
|Source|http://www.TiddlyTools.com/#ShowDocumentInfo|
|Version|2.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Description|show TiddlyWiki version, document timestamp, and plugin info|
Usage
<<<
{{{
<<tiddler ShowDocumentInfo>>
<<tiddler ShowDocumentInfo with: label>>
}}}
<<<
Example
<<<
{{{<<tiddler ShowDocumentInfo with: "info">>}}}
<<tiddler ShowDocumentInfo##show with: "info">>
<<<
<<tiddler ShowDocumentInfo##code with: {{store.getTiddlerText('ShowDocumentInfo##show')}}>>
!end
!code
Code
<<<
{{{
$1
}}}
<<<
!end
!show
<html><nowiki><a href="javascript:;" title="Show TiddlyWiki version, filedate and tiddler summary"
onmouseover="
	this.href='javascript:void(eval(decodeURIComponent(%22(function(){try{('
	+encodeURIComponent(encodeURIComponent(this.onclick))
	+')()}catch(e){alert(e.description?e.description:e.toString())}})()%22)))';"
onclick="
	if(typeof version==undefined||version.title!='TiddlyWiki')
		{alert(document.location.href+'\n\nis not a TiddlyWiki document');return false;}
	var ver=version.major+'.'+version.minor+'.'+version.revision;
	var tids=window.store.getTiddlers('modified').reverse();
	var plugins=window.store.getTaggedTiddlers('systemConfig','modified').reverse();
	var msg='TiddlyWiki version: '+ver
		+'\nDocument modified: '+document.lastModified
		+'\nLast tiddler changed: '+tids[0].title
		+'\n\nThere are a total of '+tids.length+' tiddlers,'
		+' including '+plugins.length+' plugins:\n\n';
	var fmt='YYYY.0MM.0DD 0hh:0mm:0ss'
	msg+=plugins.map(function(t){return t.modified.formatString(fmt)+' | '+t.title;}).join('\n');
	alert(msg);
 	return false;
">$1</a></html>
!end
%/<<tiddler {{var src='ShowDocumentInfo'; src+(tiddler&&tiddler.title==src?'##info':'##show')}}
	with: {{'$1'!='$'+'1'?'$1':'[i] - Show TiddlyWiki document info...'}}>>
/%
!info
|Name|ShowImage|
|Source|http://www.TiddlyTools.com/#ShowImage|
|Version|1.0.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Description|display attached tiddler image without supporting plugin|
Usage:
<<<
# First, use [[AttachFilePlugin]] to create tiddlers containing base64-encoded image data with a fallback remote URL reference.
# You can then discard the plugin and associated supporting tiddlers ([[AttachFileMIMETypes]], [[AttachFilePluginFormatters]]), leaving only the attachment tiddlers (plus this tiddler, ShowImage, of course).
# Use the following syntax to display the attached images without any plugins:
{{{
<<tiddler ShowImage with: [[TiddlerName]] "tooltip" "width">>
}}}
where:
*''~TiddlerName''<br>title of the attachment tiddler to be displayed
*''tooltip'' //(optional)//<br>mouseover help text for the image (default=attachment title)
*''width'' //(optional)//<br>CSS width measurement - resizes image height proportionally (default=auto)
Note: the fallback remote URL will be used if encoded data is not attached or you are using InternetExplorer, which does not currently support the data:// URI. 
<<<
Example:
<<<
{{{
<<tiddler ShowImage with: [[AttachFileSample]] "meow!" "30px">>
}}}
<<tiddler ShowImage with: [[AttachFileSample]] "meow!" "30px">>
<<<
!end

!show
<html><img src="missing.jpg" title="$2" style="width:$3" /></html><<tiddler {{
	var src=store.getTiddlerText("$1##data");
	if (!src||config.browser.isIE)
		src=store.getTiddlerText("$1##url","missing.jpg");
	place.lastChild.firstChild.src=src;
}}>>
!end

%/<<tiddler {{"ShowImage##"+("$1"=="$"+"1"?"info":"show")}} with:
	[[$1]]
	{{"$2"=="$"+"2"?"$1"  :"$2"}}
	{{"$3"=="$"+"3"?"auto":"$3"}}
>>
/%
!info
|Name|ShowLocalDirectory|
|Source|http://www.TiddlyTools.com/#ShowLocalDirectory|
|Version|2.0.2|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Description|display local filesystem directory listings|
Usage
<<<
{{{
<<tiddler ShowLocalDirectory>>
<<tiddler ShowLocalDirectory with: localpath format>>
}}}
*''localpath'' uses system-specific file naming conventions (or keyword "here" for the current document directory).  Note: for Windows filesystem, use doubled backslashes and enclose the entire path in square brackets (e.g., {{{[[C:\\temp\\foo]]}}})
*''format'' determines the type of output produced:
**''plain''<br>show fully-qualified path/filenames ~AS-IS, without any additional formatting.
**''list''<br>show fully-qualified path/filenames, so that the local system-specific filename can be *displayed* while linking to a valid system-independent "file:" URL for browser navigation.
**''directory'' (default)<br>show header followed by a formatted table, containing links for filenames, filesizes (in bytes), and modification dates, plus a summary footer reporting the total file and byte counts.
<<<
Revisions
<<<
2011.02.14 2.0.2 fix OSX error: use picker.file.path
<<<
Example
<<<
{{{<<tiddler ShowLocalDirectory>>}}}
<<tiddler ShowLocalDirectory##show>>
<<<
!end

!init
<<tiddler {{
	window.getCurrentFolder=function() {
		var h=document.location.href;
		return getLocalPath(decodeURIComponent(h.substr(0,h.lastIndexOf("/")+1)));
	}
	window.getParentFolder=function(cwd) {
		var lastchar=cwd.substr(cwd.length-1,1);
		if (lastchar=="/" || lastchar=="\\") cwd=cwd.substr(0,cwd.length-1);
		var pos=cwd.lastIndexOf("/"); if (pos==-1) pos=cwd.lastIndexOf("\\");
		return pos!=-1?cwd.substr(0,pos+1):null;
	}
	window.askForFolder=function(cwd) {
		if (config.browser.isIE) {
			try { // XPSP2 IE only
				var s = new ActiveXObject('UserAccounts.CommonDialog');
				s.InitialDir=cwd.replace(/\//g,"\\");
				s.FileName=''; s.Filter='All files|*.*|'; s.FilterIndex=1;
				var path=s.showOpen()?s.FileName.substr(0,s.FileName.lastIndexOf("\\")+1):null;
			}
			catch(e) { var path=prompt("Enter a directory path:",cwd.replace(/\//g,"\\"));	}
		} else { // FireFox
			if(!window.Components) return;
			try { netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); }
			catch(e) { alert(e.description?e.description:e.toString()); return; }
			var nsIFilePicker = window.Components.interfaces.nsIFilePicker;
			var picker = Components.classes['@mozilla.org/filepicker;1'].createInstance(nsIFilePicker);
			picker.init(window, "Select a folder", nsIFilePicker.modeGetFolder);
			var thispath = Components.classes['@mozilla.org/file/local;1'].createInstance(Components.interfaces.nsILocalFile);
			try { thispath.initWithPath(cwd.replace(/\\/g,"/")); }
			catch(e) { thispath.initWithPath(getLocalPath(decodeURIComponent(document.location.href.substr(0,document.location.href.lastIndexOf("/")+1)))); }
			picker.displayDirectory=thispath;
			picker.appendFilters(nsIFilePicker.filterAll); picker.defaultString=''; picker.defaultExtension=''; 
			var path=picker.show()!=nsIFilePicker.returnCancel?picker.file.path:null;
		}
		return path;
	}
	window.getFileList=function(cwd) { // returns array of file info (path,name,size,isFolder,url,modified)
		var files=[];
		if (config.browser.isIE) {
			cwd=cwd.replace(/\//g,"\\");
			var fso = new ActiveXObject("Scripting.FileSystemObject");
			if(!fso.FolderExists(cwd)) return [];
			var dir=fso.GetFolder(cwd);
			for(var f=new Enumerator(dir.SubFolders); !f.atEnd(); f.moveNext())
				files.push({ path:f.item().path, name:f.item().name, size:f.item().size,
					url:"file:///"+f.item().path.replace(/\\/g,"/"), isFolder:fso.FolderExists(f.item().path),
					modified:new Date(f.item().DateLastModified).formatString("YYYY.0MM.0DD 0hh:0mm:0ss")});
			for(var f=new Enumerator(dir.Files); !f.atEnd(); f.moveNext())
				files.push({ path:f.item().path, name:f.item().name, size:f.item().size,
					url:"file:///"+f.item().path.replace(/\\/g,"/"), isFolder:fso.FolderExists(f.item().path),
					modified:new Date(f.item().DateLastModified).formatString("YYYY.0MM.0DD 0hh:0mm:0ss")});
		} else { // FF
			if(!window.Components) return;
			try { netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); }
			catch(e) { alert(e.description?e.description:e.toString()); return null; }
			var file=Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
			try { file.initWithPath(cwd); } catch(e) { return []; }
			if (!file.exists() || !file.isDirectory()) { return []; }
			var folder=file.directoryEntries;
			while (folder.hasMoreElements()) {
				var f=folder.getNext().QueryInterface(Components.interfaces.nsILocalFile);
				if (f instanceof Components.interfaces.nsILocalFile)
					files.push({path:f.path, name:f.leafName, size:f.fileSize,
						isFolder:f.isDirectory(), url:"file:///"+f.path.replace(/\\/g,"/"),
						modified:new Date(f.lastModifiedTime).formatString("YYYY.0MM.0DD 0hh:0mm:0ss")});
			}
		}
		return files;
	}

	window.renderDirectoryList=function(target,cwd,fmt) {
		var files=getFileList(cwd);
		if (!files||!files.length) { // maybe relative directory... fixup and try again...
			var fixup=getCurrentFolder()+cwd;
			var files=getFileList(fixup);
			if (!files||!files.length) {
				var out="{{errorButton{error reading "+cwd+"}\}\}";
				removeChildren(target); wikify(out,target);
				target.style.display="block";
				return false;
			} else cwd=fixup;
		}
		if (!cwd||!cwd.length) cwd=config.options.txtLocalDirectory;
		if (!cwd||!cwd.length) cwd=getCurrentFolder();
		config.options.txtLocalDirectory=cwd;
		var header=""; var item=""; var folderitem=""; var folderlink=""; var footer="";
		switch (fmt) {
			case "plain": item=folderitem="<nowiki>%0</nowiki>\n"; break;
			case "list": item=folderitem="[[%1|file:///%0]]\n"; break;
			default:
				var header="Index of {{{%0}\}\}\n^^(as of %1)^^\n|filename&nbsp;&nbsp;| size&nbsp;&nbsp;|modified|h\n";
				var item="|[[%1|%2]]&nbsp;&nbsp;| %3&nbsp;&nbsp;|%4|\n";
				var folderlink='<html><a href="javascript:;" title="open %1..." onclick="';
				folderlink+='	var t=this.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode;';
				folderlink+="	window.renderDirectoryList(t,'%0','');";
				folderlink+='	return false;';
				folderlink+='">%1</a></html>';
				var folderitem='|'+folderlink+'&nbsp;&nbsp;| |%4|\n';
				var footer="|>|>|>| !Total of %0 bytes in %1 files |f\n|borderless sortable|k\n";
				var showDirectory=true;
				break;
		}
		var out=header.format([cwd,new Date().toLocaleString()]);
		if (showDirectory) {
			var p=getParentFolder(cwd);
			if (p) files.unshift({path:p, name:"(parent folder)", size:0, isFolder:true, url:"file:///"+p.replace(/\\/g,"/"),
				modified:new Date().formatString("YYYY.0MM.0DD 0hh:0mm:0ss")});
		}
		var total=0;
		for (var i=0; i<files.length; i++) {
			var line=(files[i].isFolder?folderitem:item).format([files[i].path,files[i].name,files[i].url,files[i].size,files[i].modified]);
			if (showDirectory) line=line.replace(/\\/g,"\\\\"); // fixup for PC-style file paths embedded in 'folderlink'
			if (!files[i].isFolder) total+=files[i].size;
			out+=line;
		}
		out+=footer.format([total,files.length]);
		removeChildren(target); wikify(out,target); target.style.display="block";

		// make table sortable (code adapted from [[TableSortingPlugin]]
		var c = config.tableSorting; if (!c) return; // no sortable tables
		var table = target.getElementsByTagName("table")[0];
		if (table) {
			var x=null, rev,
				thead=table.getElementsByTagName('thead')[0],
				headers=thead.rows[thead.rows.length-1].cells;
			for (var j=0; j<headers.length; j++){
				var h = headers[j];
				if (hasClass(h,"nosort")) continue;
				h.setAttribute("index",j);
				h.onclick = function(){c.sortTable(this); return false;};
				h.ondblclick = stopEvent;
				if(h.getElementsByTagName("span").length == 0)
					createTiddlyElement(h,"span",null,"hidden",c.uarrow); 
				if(!x && hasClass(h,"autosort"))
					{ x = j; rev = hasClass(h,"reverse"); }
			}
			if(x) c.sortTable(headers[x],rev);
		}
	}
'';}}>>
!end

!selectFolder
<html><a href='javascript:;' onclick='
	var path=askForFolder(getCurrentFolder());
	var target=this.parentNode.parentNode.parentNode.nextSibling;
	if (path) window.renderDirectoryList(target,path,"");
	return false;
'>select a folder</a>
| <a href='javascript:;' onclick='
	var target=this.parentNode.parentNode.parentNode.nextSibling;
	window.renderDirectoryList(target,getCurrentFolder(),"");
	return false;
'>use document location...</a>
| <a href='javascript:;' onclick='
	var target=this.parentNode.parentNode.parentNode.nextSibling;
	window.renderDirectoryList(target,config.options.txtLocalDirectory,"");
	return false;
'>refresh list...</a>
<nowiki></html>
!end

!show
<<tiddler ShowLocalDirectory##init>>{{hidden small{
<<tiddler ShowLocalDirectory##selectFolder>>
----
}}}@@display:none;content automatically replaced@@<<tiddler {{
	var cwd=getCurrentFolder(); // default to current folder
	if ("$1"=="$"+"1") // show 'select a folder' command
		place.lastChild.previousSibling.style.display="block";
	else if ("$1".toLowerCase()=="here") // use document directory
		cwd=getCurrentFolder();
	else // use path param as specified
		cwd="$1";
	window.renderDirectoryList(place.lastChild,cwd,"$2");
'';}}>>
!end

%/<<tiddler {{ var src='ShowLocalDirectory'; src+(tiddler&&tiddler.title==src?'##info':'##show')}}
	with: [[$1]] [[$2]]>>
/%
!info
|Name|ShowObject|
|Source|http://www.TiddlyTools.com/#ShowObject|
|Version|1.5.0|
|Author|Eric Shulman|
|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|transclusion|
|Description|display TiddlyWiki runtime objects|
Usage:
<<<
{{{
<<tiddler ShowObject with: "function, object or DOM element">>
}}}
<<<
Examples:
<<<
*function:<br>{{{<<tiddler ShowObject with: "main">>}}} <<slider
	{{config.options.foo=false;'foo';}}
	ShowObject##Function_example 'view result...'>>
*object:<br>{{{<<tiddler ShowObject with: "config.messages">>}}} <<slider
	{{config.options.foo=false;'foo';}}
	ShowObject##Object_example 'view result...'>>
*DOM element:<br>{{{<<tiddler ShowObject with: "mainMenu">>}}} <<slider
	{{config.options.foo=false;'foo';}}
	ShowObject##DOM_example 'view result...'>>
<<<
!Function_example
<<tiddler ShowObject with: "main">>
!Object_example
<<tiddler ShowObject with: "config.messages">>
!DOM_example
<<tiddler ShowObject with: "mainMenu">>
!end

%/<<tiddler {{

// written 2008 by Eric L Shulman
// re-use outside of TiddlyWiki is permitted
// with proper credit and links to:
// http://www.TiddlyTools.com/#ShowObject
// http://www.TiddlyTools.com/#LegalStatements

window.showObject=function(thing) {
	if (document.getElementById(thing))
		var out=function(id){
			var t=document.getElementById(id).innerHTML
			var t2=''; var indent=''; var level=0;
			for (var i=0;i<t.length;i++) { var c=t.substr(i,1);
				if (c=='<') {
					if (t.substr(i+1,1)=='/')
						indent=indent.substr(0,indent.length-2);
					t2+='\n'+indent;
					if (t.substr(i+1,1)!='/'
						&& t.substr(i+1,3)!='br>'
						&& t.substr(i+1,2)!='p>'
						&& t.substr(i+1,3)!='hr>') indent+='  ';
				}
				t2+=c;
				if (c=='\n') t2+=indent;
				if (c=='>' && t.substr(i+1,1)!='<') t2+='\n'+indent;
			}
			return t2;
		}(thing);
	else if (typeof(thing)=='function')
		var out=function(obj){
			return obj.toSource?obj.toSource(true):obj.toString();
		}(thing);
	else if (typeof(thing)!='undefined') {
		var out=function(obj,indent,level) {
			if (level>10)
				return '...';
			if (obj && obj.exec!==undefined)
				return obj.toString(); 
			if (typeof obj=='function')
				return 'function(...){...}';
			if (typeof obj=='string')
				return '"'+obj+'"';
			if (typeof obj=='object') {
				var t=[]; for(var p in obj) {
					var v=(p=='innerHTML')?
						'...':arguments.callee(obj[p],indent+'  ',level+1);
					t.push(indent+'  '+p+': '+v);
				}
				return '{\n'+t.join(',\n')+'\n'+indent+'}';
			}
			return obj.toString();
		}(thing,'',0);
	} else var out=' ???';
	return out.htmlEncode();
};
// end of portable code

'';}}>><<tiddler {{'$1'=='$'+'1'?'ShowObject##info':'ShowObject##format'}}
	with: $1 {{window.showObject(typeof $1==='undefined'?'$1':$1)}}>>/%

DEFINE OUTPUT FORMAT: $1=name, $2=results from showObject(name)
!format
<html><nowiki><pre>$1 =$2</pre></html>
!end
%/
/%
!info
|Name|ShowPlugins|
|Source|http://www.TiddlyTools.com/#ShowPlugins|
|Version|2.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Description|generates a report of all installed plugins in a [[PluginInfo]] shadow tiddler|
Usage
<<<
{{{
<<tiddler ShowPlugins>>
<<tiddler ShowPlugins with: label>>
}}}
<<<
Example
<<<
{{{<<tiddler ShowPlugins with: "click me">>}}}
<<tiddler ShowPlugins##show with: "click me">>
<<<
!end
!show
<html><nowiki><a href="javascript:;" title="view a list of all installed plugins"
onmouseover="
	this.href='javascript:void(eval(decodeURIComponent(%22(function(){try{('
	+encodeURIComponent(encodeURIComponent(this.onclick))
	+')()}catch(e){alert(e.description?e.description:e.toString())}})()%22)))';"
onclick="
	var plugins=window.store.getTaggedTiddlers('systemConfig','title');
	var out='|Title|Date|Size|Author|Version|~CoreVersion|h\n|sortable|k\n';
	out+=plugins.map(function(t) {
		return '|'+'[['+t.title+']]'
		+'|'+t.modified.formatString('YYYY.0MM.0DD')
		+'|'+t.text.length
		+'|'+store.getTiddlerSlice(t.title,'Author')
		+'|'+store.getTiddlerSlice(t.title,'Version')
		+'|'+store.getTiddlerSlice(t.title,'CoreVersion')+'|';
	}).join('\n');
	config.shadowTiddlers.PluginInfo=out;
	story.displayTiddler(null,'PluginInfo');"
>$1</a></html>
!end
%/<<tiddler {{var src='ShowPlugins'; src+(tiddler&&tiddler.title==src?'##info':'##show')}}
	with: {{'$1'=='$'+'1'?'PluginInfo':'$1'}}>>
/***
|Name|[[ShowPopupPlugin]]|
|Source|http://www.TiddlyTools.com/#ShowPopupPlugin|
|Version|2.1.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|display tiddler content in a TiddlyWiki popup panel|
!!!!!Documenatation
>see [[ShowPopupPluginInfo]]
!!!!!Revisions
<<<
2011.03.13 2.1.1 in click(), removed check for popup already shown (prevents nested popups!)
| Please see [[ShowPopupPluginInfo]] for previous revision details |
2006.09.09 1.0.0 initial release (transclusion)
<<<
!!!!!Code
***/
//{{{
version.extensions.ShowPopupPlugin=
	{ major:2, minor:1, revision:1, date:new Date(2011,3,13) };
config.macros.showPopup = {
	tip: 'display "%0" in a popup',
	init: function() {
		config.shadowTiddlers.ShowPopup =
			'<<showPopup tiddler:[[$1]] label:"$2" tip:"$3" buttonClass:"button $4" width:"$5" popupClass:"$6" "$7">>';
		config.annotations.ShowPopup =
			'created by ShowPopupPlugin';
	},
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		var p=paramString.parseParams('name',null,true,false,true);
		var tid=getParam(p,'tiddler','TiddlerName');
		var label=getParam(p,'label',tid);
		var tip=getParam(p,'tip',this.tip.format([tid]));
		var buttonClass=getParam(p,'buttonClass','');
		var width=getParam(p,'width','auto');
		var popupClass=getParam(p,'popupClass','');
		var above=params.contains('above');
		var mouseover=params.contains('mouseover');
		var b=createTiddlyButton(place, label, tip, this.click, buttonClass, null, null,
			{ tid:tid, popupClass:popupClass, width:width, above:above });
		b.innerHTML=label; // render HTML for entities, images, etc
		if (mouseover) b.onmouseover=b.onclick;  // option: mouseover triggers click
	},
	click: function(ev) { var ev=ev||window.event;
		// DISABLED if (Popup.find(this)!=-1)return false; // popup already shown!
		var p=Popup.create(this); if(!p)return false; // popup not created!
		addClass(p,this.getAttribute('popupClass'));
		var d=createTiddlyElement(p,'div');
		var s=d.style; s.whiteSpace='normal'; s.width=this.getAttribute('width'); s.padding='2px';
		wikify(store.getTiddlerText(this.getAttribute('tid'),''),d);
		if (this.getAttribute('above')!='true') Popup.show();
		else Popup.show('top','left',{x:0,y:-jQuery(d).outerHeight()});
		ev.cancelBubble=true; if(ev.stopPropagation)ev.stopPropagation(); return false;
	}
}
//}}}
/***
|Name|ShowPopupPluginInfo|
|Source|http://www.TiddlyTools.com/#ShowPopupPlugin|
|Documentation|http://www.TiddlyTools.com/#ShowPopupPluginInfo|
|Version|2.1.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|documentation|
|Description|documentation for ShowPopupPlugin|
!!!!!Usage
<<<
{{{
<<showPopup tiddler:[[TiddlerName]] label:"..." tip:"..." buttonClass:"..." width:"..." popupClass:"..." above>>
}}}
*''~TiddlerName''<br>title of the tiddler to be displayed
*''label''<br>text for the command link //(default=~TiddlerName)//
*''tooltip''<br>mouseover help text for the link //(default="display ~TiddlerName in a popup")//
*''buttonClass''<br>CSS classname applied to the command text //(default=button)//
*''width''<br>width of the popup (using CSS measurements) //(default=auto)//
*''popupClass''<br>CSS classname applied to the popup panel. //(default=none)//<br>Use 'sticky' for persistent popups (see StickyPopupPlugin)
*''above''<br>when this keyword is used, the bottom of the popup will be aligned with the top of the command link text label (i.e., the popup appears //above// the label).
*''mouseover''<br>when this keyword is used, the popup is shown whenever the mouse is moved over the label, without requiring a click (i.e., a "hot spot")
For backward-compatibility with existing document content, you can also use the {{{<<tiddler>>}}} macro to transclude the [[ShowPopup]] //shadow tiddler//, like this:
{{{
<<tiddler ShowPopup with: [[TiddlerName]] label tooltip buttonClass width popupClass 'above'>>
}}}
Note: transclusion uses //unnamed// parameters that must occur in the order shown above.  You can use "" as placeholders to apply default parameter values.
<<<
!!!!!Examples
<<<
Popup below label (defaults):
>{{{<<showPopup tiddler:GettingStarted>>}}}
><<showPopup tiddler:GettingStarted>>
Popup above label:
>{{{<<showPopup tiddler:GettingStarted above>>}}}
><<showPopup tiddler:GettingStarted above>>
Popup mouseover above label:
>{{{<<showPopup above mouseover tiddler:GettingStarted>>}}}
><<showPopup above mouseover tiddler:GettingStarted>>
<<<
!!!!!Revisions:
<<<
2011.03.13 2.1.1 in click(), removed check for popup already shown (prevents nested popups!)
2011.03.12 2.1.0 added 'mouseover' param
2011.03.05 2.0.1 in click(), fixed popup alignment when NOT using 'above'
2011.03.03 2.0.0 converted to plugin and added optional 'above' keyword param
2009.09.10 1.2.0 documentation/code cleanup
2007.03.02 1.1.0 added class, width, popupClass params
2006.09.09 1.0.0 initial release (transclusion)
<<<
/***
|Name|[[ShowReferencesPlugin]]|
|Source|http://www.TiddlyTools.com/#ShowReferencesPlugin|
|Version|2.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|format and display references to the current tiddler|
!!!!!Documenatation
>see [[ShowReferencesPluginInfo]]
!!!!!Revisions
<<<
2011.03.01 2.0.0 converted to plugin and added optional TiddlerName and message params
| Please see [[ShowReferencesPluginInfo]] for previous revision details |
2006.09.04 1.0.0 original release (transclusion)
<<<
!!!!!Code
***/
//{{{
version.extensions.ShowReferencesPlugin =
	{ major:2, minor:0, revision:0, date:new Date(2011,3,1) };
config.macros.showReferences = {
	defaultFormat: '[[%0]]\n',
	fallbackMsg: 'no references',
	init: function() {
		config.shadowTiddlers.ShowReferences =
			'<<showReferences "$1" [[$2]] "$3">>';
		config.annotations.ShowReferences =
			'created by ShowReferencesPlugin';
	},
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		var here=story.findContainingTiddler(place);
		var tid=here?here.getAttribute('tiddler'):'';
		var fmt=params[0];	if (!fmt||fmt=='$1')	 fmt	=this.defaultFormat;
		var title=params[1];	if (!title||title=='$2') title	=tid;
		var msg=params[2];	if (!msg||msg=='$3')	 msg	=this.fallbackMsg;
		var refs=store.getReferringTiddlers(title);
		var out='';
		fmt=fmt.unescapeLineBreaks();
		for(var r=0; r<refs.length; r++)
			if(refs[r].title!=title && !refs[r].isTagged('excludeLists'))
				out+=fmt.format([refs[r].title]);
		wikify(out.length?out:msg,place);
	}
}
//}}}
/***
|Name|ShowReferencesPluginInfo|
|Source|http://www.TiddlyTools.com/#ShowReferencesPlugin|
|Documentation|http://www.TiddlyTools.com/#ShowReferencesPluginInfo|
|Version|2.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|documentation|
|Description|documentation for ShowReferencesPlugin|
!!!!!Usage
<<<
{{{
<<showReferences "format" [[TiddlerName]] "message">>
}}}
*''format'' (optional, default={{{"[[%0]]\n"}}})<br>lists references as links, one per line, using %0 as a 'substitution marker' to insert the reference tiddler's title.
*''TiddlerName'' (optional, default=current tiddler)<br>specifies the tiddler whose references are to be displayed.
*''message'' (optional, default={{{"no references"}}})<br>specifies a message to display when there are no references.
You can also use the [[ShowReferences]] //shadow tiddler// to transclude the macro output or embed it within a slider or tabset:
{{{
<<tiddler ShowReferences with: "format" [[TiddlerName]] "message">>
<<slider ... [[ShowReferences]] label tooltip >>
<<tabs ... label tooltip [[ShowReferences]] ...>>
}}}
Note: {{{<<slider>>}}} and {{{<<tabs>>}}} macros do //not// support use of extra parameters to specify a custom format, ~TiddlerName, or message.  The default format, current tiddler, and message will be used.
<<<
!!!!!Configuration
<<<
You can edit [[ShowReferences]] to specify //non-default// custom parameters values for use with transclusion, slider or tabs macros, or add additional content to display before/after the macro output.  You can also customize the //default// message text (i.e., "no references") by adding the following line to a tiddler tagged with 'systemConfig':
{{{
config.macros.fallbackMsg="your text here";
}}}
or
{{{
config.macros.fallbackMsg=""; // omits fallback message
}}}
<<<
!!!!!Examples
<<<
one per line: {{{<<showReferences "[[%0]]\n" [[GettingStarted]]>>}}}
{{indent{<<showReferences "[[%0]]\n" [[GettingStarted]]>>}}}
comma-separated: {{{<<showReferences "[[%0]], " [[GettingStarted]]>>}}}
{{indent{<<showReferences "[[%0]] " [[GettingStarted]]>>}}}
bullet items: {{{<<showReferences "* [[%0]]\n" [[GettingStarted]]>>}}}
<<showReferences "* [[%0]]\n" [[GettingStarted]]>>
numbered items: {{{<<showReferences "# [[%0]]\n" [[GettingStarted]]>>}}}
<<showReferences "# [[%0]]\n" [[GettingStarted]]>>
<<<
!!!!!Revisions
<<<
2011.03.01 2.0.0 converted to plugin and added optional TiddlerName and message params
2006.09.13 1.1.0 added format param
2006.09.04 1.0.0 original release (transclusion)
<<<
/%
!info
|Name|ShowSimilarTiddlers|
|Source|http://www.TiddlyTools.com/#ShowSimilarTiddlers|
|Version|2.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|Type|transclusion|
|Description|list tiddlers, by number of shared tags|
Usage
<<<
{{{
<<tiddler ShowSimilarTiddlers>>
<<tiddler ShowSimilarTiddlers with: TiddlerName limit>>
}}}
*''~TiddlerName'' (optional)<br>title of the tiddler whose tags are to be matched (default=current tiddler)
*''limit'' (optional)<br>only report tiddlers if they have //at least// the indicated number of tags in common (default=1)
<<<
Example
<<<
{{{<<tiddler ShowSimilarTiddlers>>}}}
<<tiddler ShowSimilarTiddlers##show>>
<<<
!end
!out
$1
!end
!show
<<tiddler ShowSimilarTiddlers##out with: {{
	var out=[]; var similar={}; var rank=[];
	var here=story.findContainingTiddler(place);
	var title='$1'!='$'+'1'?'$1':here?here.getAttribute('tiddler'):'';
	var limit='$2'!='$'+'2'?'$2':1;
	var tid=store.getTiddler(title);
	var tids=store.reverseLookup('tags','excludeLists');
	if (tid) for (var i=0; i<tids.length; i++) { var t=tids[i];
		if (t.title==tid.title) continue;
		var tags=[]; for (var j=0; j<t.tags.length; j++)
			if (tid.tags.contains(t.tags[j])) tags.push(t.tags[j]);
		if (tags.length >= limit) {
			similar[tids[i].title]=tags;
			if (!rank[tags.length]) rank[tags.length]=new Array();
			rank[tags.length].push(tids[i].title);
		}
	}
	for (var r=rank.length-1; r>=0; r--) { if (!rank[r]) continue;
		out.push('*%0 shared tags:'.format([r,rank[r].length]));
		for (var t=0; t<rank[r].length; t++)
			out.push('##[[%0]] ~~("""%1""")~~'.format([rank[r][t],similar[rank[r][t]].join(', ')]));
	}
	out.join('\n');
}}>>
!end
%/<<tiddler {{var src='ShowSimilarTiddlers'; src+(tiddler&&tiddler.title==src?'##info':'##show');}}
	with: [[$1]]>>
/%
!info
|Name|ShowTabsForTags|
|Source|http://www.TiddlyTools.com/#ShowTabsForTags|
|Version|2.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Description|generate a tabbed display for tiddlers with a specified set of tags|
Usage
<<<
{{{
<<tiddler ShowTabsForTags with: "tag tag ...">>
}}}
*''"tag tag..."''<br>is a space-separated list of tag values, ALL of which must be present on the tiddlers that are to be displayed.
<<<
Example
<<<
{{{<<tiddler ShowTabsForTags with: package>>}}}
<<tiddler ShowTabsForTags##show with: package>>
<<<
!end
!out
{{left wrap{$1}}}
!end
!show
<<tiddler ShowTabsForTags##out with: {{
	var tags="$1".readBracketedList();
	// get matching tiddlers in date order (newest first) and add params to tabs macro output
	var out="";
	if (tags.length) {
		var tids=store.getTaggedTiddlers(tags[0],'modified').reverse();
		for (var t=0; t<tids.length; t++)
			if (tids[t].tags.containsAll(tags))
				out+='[[%0 ]] "view %0" [[%0]]'.format([tids[t].title]); 
	}
	out.length?"<<tabs tabTabsForTags "+out+">\>"
		:"There are no tiddlers tagged with <<tag "+tags.join(">\> and <<tag ")+">\>";
}}>>
!end
%/<<tiddler {{var src='ShowTabsForTags'; src+(tiddler&&tiddler.title==src?'##info':'##show');}}
	with: [[$1]]>>
/%
!info
|Name|ShowTiddlerStatistics|
|Source|http://www.TiddlyTools.com/#ShowTiddlerStatistics|
|Version|1.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion |
|Description|display document summary / tiddler stats (newest, oldest, largest, smallest, etc.)|
Usage
<<<
{{{
<<tiddler ShowTiddlerStatistics>>
}}}
!end
!show
{{nowrap{
$1
}}}
!end
!summary
{{fine{There are ''%0 tiddlers'', including:''<<tag systemConfig [[%1 plugins]]>>''+''<<tag transclusion [[%2 transclusions]]>>''(%3 total bytes)}}}
!end
!table
|borderless|k
| last change:&nbsp;|[[%0]] {{fine{(updated %1)}}}|
| newest:&nbsp;|[[%2]] {{fine{(created %3)}}}|
| oldest:&nbsp;|[[%4]] {{fine{(created %5)}}}|
| smallest:&nbsp;|[[%6]] {{fine{(%7 bytes)}}}|
| largest:&nbsp;|[[%8]] {{fine{(%9 bytes)}}}|
!end
%/<<tiddler ShowTiddlerStatistics##show with: {{
	var tiddlers=store.getTiddlers("modified","excludeLists");
	var last=tiddlers[tiddlers.length-1];
	var total=oldest=newest=smallest=largest=0;
	for (var i=0; i<tiddlers.length; i++) {
		total+=tiddlers[i].text.length;
		if (!oldest || tiddlers[i].created<oldest)
			{ var oldest=tiddlers[i].created; var oldtid=tiddlers[i]; }
		if (!newest || tiddlers[i].created>newest)
			{ var newest=tiddlers[i].created; var newtid=tiddlers[i]; }
		if (!smallest || tiddlers[i].text.length<smallest)
			{ var smallest=tiddlers[i].text.length; var smalltid=tiddlers[i]; }
		if (!largest || tiddlers[i].text.length>largest)
			 { var largest=tiddlers[i].text.length; var largetid=tiddlers[i]; }
	}
	var out=store.getTiddlerText("ShowTiddlerStatistics##summary").format([
		tiddlers.length,
		store.getTaggedTiddlers("systemConfig").length,
		store.getTaggedTiddlers("transclusion").length,
		total]);
	out+='\n'+store.getTiddlerText("ShowTiddlerStatistics##table").format([
		last.title, last.modified.formatString("MMM DDth YYYY, 0hh:0mm"),
		newtid.title, newtid.created.formatString("MMM DDth YYYY, 0hh:0mm"),
		oldtid.title, oldtid.created.formatString("MMM DDth YYYY, 0hh:0mm"),
		smalltid.title, smalltid.text.length,
		largetid.title, largetid.text.length]);
	out;
}}>>
+++(goto)*[goto]...{{borderleft{
	<<tiddler SiteMenuGoto>>}}}===
+++(search)*[search]...{{borderleft{
	<<tiddler SiteMenuSearch>>}}}===
+++(file)*[file]...{{borderleft{
	<<tiddler SiteMenuFile>>}}}===
+++(edit)*[edit]...{{borderleft{
	<<tiddler SiteMenuEdit>>}}}===
+++(view)*[view]...{{borderleft{
	<<tiddler SiteMenuView>>}}}===
+++(options)*[options]...{{borderleft{
	<<tiddler SiteMenuOptions>>}}}===
+++(calendar)[calendar]...{{borderleft{
	{{groupbox{{{small{<<calendar thismonth>><script>
		place.lastChild.style.width="100%";
	</script>}}}}}}}}}===
{{small{
@@display:block;line-height:2em;margin-left:.5em;<<unsavedChanges command "unsaved changes (%0)">>@@/%
%/+++(contents)[contents]...
	<<tabs txtMainTab
		Listbox 'TableOfContentsPlugin enhanced listbox' SideBarTabs##Listbox
		Timeline Timeline TabTimeline
		All 'All tiddlers' TabAll
		Tags 'All tags' TabTags
		Authors 'All tiddlers, sorted by author (modifier)' SideBarTabs##Authors
		Missing 'Missing tiddlers' TabMoreMissing
		Orphans 'Orphaned tiddlers' TabMoreOrphans
		Shadowed 'Shadowed tiddlers' TabMoreShadowed
>>===<script>
	var s=place.lastChild.button.style;
	s.marginLeft=".3em"; s.display="block"; s.padding=".2em";
</script>}}}/%
!Listbox
<<tableOfContents "label:select a tiddler" date:YYYY.0MM.0DD width:100% padding:0 margin:0>><script>place.lastChild.lastChild.style.color="#000";</script>
!Authors
<script>
	var out=[]; var who='';
	var tids=store.getTiddlers('modifier');
	for (i=0; i<tids.length; i++) { var t=tids[i];
		if (who!=t.modifier) {
			who=t.modifier;
			out.push('by '+who+':');
		}
		out.push('{{indent{[['+t.title+']]}}}');
	}
	return out.join('');
</script>
!end
%/
/***
|Name|SideBySide|
|Source|http://www.TiddlyTools.com/#Plain|
|Version||
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|CSS|
|Requires|ToolbarCommands|
|Description|default theme with side-by-side editor/preview display|
|StyleSheet|StyleSheet|
|EditTemplate|##EditTemplate|
|PageTemplateReadOnly|PageTemplateReadOnly|
|EditTemplateReadOnly|##EditTemplateReadOnly|
***/

!!!EditTemplate
<!--{{{-->
<span class='toolbar' macro='toolbar [[ToolbarCommands::EditToolbar]]'></span>
<div class='title' macro='view title'></div>
<div style='clear:both'></div>
<div class='editor' macro='edit title'></div>
<div macro='tiddler QuickEditToolbar'></div>
<div class='editor'>
        <table style='width:100%'><tr style='vertical-align:top'>
                <td style='width:50%'><span macro='edit text'></span></td>
                <td style='width:50%'><span macro='preview text'></span></td>
        </tr></table>
</div>
<span macro='resizeEditor'></span><span macro='setUserName'></span>
<div class='editor' macro='edit tags'></div>
<div class='toolbar editorFooter' style='text-align:left !important;float:left !important'>
	<span macro='message views.editor.tagPrompt'></span>
	<span macro='tagChooser'></span>
</div>
<div style='clear:both'></div>
<!--}}}-->
!!!!!end EditTemplate

!!!EditTemplateReadOnly
<!--{{{-->
<span class='toolbar' macro='toolbar [[ToolbarCommands::EditToolbarReadOnly]]'></span>
<div class='title' macro='view title'></div>
<div style='clear:both'></div>
<div class='editor' macro='edit title'></div>
<div class='editor'>
        <table style='width:100%'><tr style='vertical-align:top'>
                <td style='width:50%'><span macro='edit text'></span></td>
                <td style='width:50%'><span macro='preview text'></span></td>
        </tr></table>
</div>
<span macro='resizeEditor'></span>
<div class='editor' macro='edit tags'></div>
<div class='toolbar editorFooter' style='text-align:left !important;float:left !important'>
	<span macro='message views.editor.tagPrompt'></span>
	<span macro='tagChooser'></span>
</div>
<div style='clear:both'></div>
<!--}}}-->
!!!!!end EditTemplateReadOnly
/***
|Name|SinglePageModePlugin|
|Source|http://www.TiddlyTools.com/#SinglePageModePlugin|
|Documentation|http://www.TiddlyTools.com/#SinglePageModePluginInfo|
|Version|2.9.7|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|Show tiddlers one at a time with automatic permalink, or always open tiddlers at top/bottom of page.|
This plugin allows you to configure TiddlyWiki to navigate more like a traditional multipage web site with only one tiddler displayed at a time.
!!!!!Documentation
>see [[SinglePageModePluginInfo]]
!!!!!Configuration
<<<
<<option chkSinglePageMode>> Display one tiddler at a time
><<option chkSinglePagePermalink>> Automatically permalink current tiddler
><<option chkSinglePageKeepFoldedTiddlers>> Don't close tiddlers that are folded
><<option chkSinglePageKeepEditedTiddlers>> Don't close tiddlers that are being edited
<<option chkTopOfPageMode>> Open tiddlers at the top of the page
<<option chkBottomOfPageMode>> Open tiddlers at the bottom of the page
<<option chkSinglePageAutoScroll>> Automatically scroll tiddler into view (if needed)

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


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

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

Notes:
* {{block{
The "display one tiddler at a time" option can also be //temporarily// set/reset by including a 'paramifier' in the document URL: {{{#SPM:true}}} or {{{#SPM:false}}}. You can also use {{{SPM:expression}}}, where 'expression' is any javascript statement that evaluates to true or false.  This allows you to create hard-coded links in other documents that can selectively enable/disable the use of this option based on various programmatic conditions, such as the current username. For example, using
&nbsp;&nbsp;&nbsp;{{{#SPM:config.options.txtUserName!="SomeName"}}}
enables 'one tiddler at a time' display for all users //other than// "~SomeName")}}}
* If more than one display mode is selected, 'one at a time' display takes precedence over both 'top' and 'bottom' settings, and if 'one at a time' setting is not used, 'top of page' takes precedence over 'bottom of page'.
* When using Apple's Safari browser, automatically setting the permalink causes an error and is disabled.
<<<
!!!!!Revisions
<<<
2008.10.17 2.9.6 changed chkSinglePageAutoScroll default to false
2008.06.12 2.9.5 corrected 'scroll to top of page' logic in auto-scroll handling
2008.06.11 2.9.4 added chkSinglePageKeepEditedTiddlers option
2008.06.05 2.9.3 in displayTiddler(), bypass single/top/bottom mode handling if startingUp.  Allows multiple tiddlers to be displayed during startup processing (e.g., #story:DefaultTiddlers), even if single/top/bottom mode is enabled.
2008.04.18 2.9.2 in displayTiddler() and checkLastURL(), handling for Unicode in tiddler titles (remove explicit conversion between Unicode and UTF, as this is apparently done automatically by encode/decodeURIComponent, resulting in double-encoding!
2008.04.08 2.9.1 don't automatically add options to AdvancedOptions shadow tiddler
2008.04.02 2.9.0 in displayTiddler(), when single-page mode is in use and a tiddler is being edited, ask for permission to save-and-close that tiddler, instead of just leaving it open.
2008.03.29 2.8.3 in displayTiddler(), get title from tiddler object (if needed).  Fixes errors caused when calling function passes a tiddler *object* instead of a tiddler *title*
2008.03.14 2.8.2 in displayTiddler(), if editing specified tiddler, just move it to top/bottom of story *without* re-rendering (prevents discard of partial edits).
2008.03.06 2.8.1 in paramifier handler, start 'checkURL' timer if chkSinglePageMode is enabled
2008.03.06 2.8.0 added option, {{{config.options.chkSinglePageKeepFoldedTiddlers}}}, so folded tiddlers won't be closed when using single-page mode.  Also, in checkURL(), if hash is a ''permaview'' (e.g., "#foo bar baz"), then display multiple tiddlers rather than attempting to display "foo bar baz" as a single tiddler
2008.03.05 2.7.0 added support for "SPM:" URL paramifier
2008.03.01 2.6.0 in hijack of displayTiddler(), added 'title' argument to closeAllTiddlers() so that target tiddler isn't closed-and-reopened if it was already displayed.  Also, added config.options.chkSinglePageAutoScrolloption to bypass automatic 'scroll into view' logic (note: core still does it's own ensureVisible() handling)
2007.12.22 2.5.3 in checkLastURL(), use decodeURIComponent() instead of decodeURI so that tiddler titles with commas (and/or other punctuation) are correctly handled.
2007.10.26 2.5.2 documentation cleanup
2007.10.08 2.5.1 in displayTiddler(), when using single-page or top-of-page mode, scrollTo(0,0) to ensure that page header is in view.
2007.09.13 2.5.0 for TPM/BPM modes, don't force tiddler to redisplay if already shown.  Allows transition between view/edit or collapsed/view templates, without repositioning displayed tiddler.
2007.09.12 2.4.0 added option to disable automatic permalink feature.  Also, Safari is now excluded from permalinking action to avoid bug where tiddlers don't display after hash is updated.
2007.03.03 2.3.1 fix typo when adding BPM option to AdvancedOptions (prevented checkbox from appearing)
2007.03.03 2.3.0 added support for BottomOfPageMode (BPM) based on request from DaveGarbutt
2007.02.06 2.2.3 in Story.prototype.displayTiddler(), use convertUnicodeToUTF8() for correct I18N string handling when creating URL hash string from tiddler title (based on bug report from BidiX)
2007.01.08 2.2.2 use apply() to invoke hijacked core functions
2006.07.04 2.2.1 in hijack for displayTiddlers(), suspend TPM as well as SPM so that DefaultTiddlers displays in the correct order.
2006.06.01 2.2.0 added chkTopOfPageMode (TPM) handling
2006.02.04 2.1.1 moved global variable declarations to config.* to avoid FireFox 1.5.0.1 crash bug when assigning to globals
2005.12.27 2.1.0 hijack displayTiddlers() so that SPM can be suspended during startup while displaying the DefaultTiddlers (or #hash list).  Also, corrected initialization for undefined SPM flag to "false", so default behavior is to display multiple tiddlers
2005.12.27 2.0.0 Update for TW2.0
2005.11.24 1.1.2 When the back and forward buttons are used, the page now changes to match the URL.  Based on code added by Clint Checketts
2005.10.14 1.1.1 permalink creation now calls encodeTiddlyLink() to handle tiddler titles with spaces in them
2005.10.14 1.1.0 added automatic setting of window title and location bar ('auto-permalink').  feature suggestion by David Dickens.
2005.10.09 1.0.1 combined documentation and code in a single tiddler
2005.08.15 1.0.0 Initial Release
<<<
http://www.TiddlyTools.com/faq.html
<script>
	if(!(addClass instanceof Function) || !(removeClass instanceof Function)) return;
	place.onmouseover = function(e){ addClass(this,"selected"); }
	place.onmouseout = function(e){ removeClass(this,"selected"); }
</script>/%
%/{{mouseover{
{{floatright nowrap{
+++^25em^*[goto]...{{fine wrap{
	<<moveablePanel>><<tiddler SiteMenuGoto>>}}}===
 +++^20em^*[search]...{{wrap{
	<<moveablePanel>>{{floatright{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}}}/%
	%/<<tiddler SiteMenuSearch>>}}}===
 | +++^18em^*[file]...{{wrap{
	<<moveablePanel>>file
----
	<<tiddler SiteMenuFile>>}}}===
 +++^16em^*[edit]...{{wrap{
	<<moveablePanel>>edit
----
	<<tiddler SiteMenuEdit>>}}}===
 +++^16em^*[view]...{{wrap{
	<<moveablePanel>>view
----
	<<tiddler SiteMenuView>>}}}===
 +++^18em^*[options]...{{wrap{
	<<moveablePanel>>options
----
	<<tiddler SiteMenuOptions>>}}}===
 | +++^18em^*[calendar]...{{wrap{
	<<moveablePanel>>calendar
----
	{{small{<<calendar thismonth>><script>place.lastChild.style.width="100%";</script>}}}===
 +++^18em^*[contents]...{{wrap{
	<<moveablePanel>>contents
----
	<<tabs txtMainTab
		Listbox 'TableOfContentsPlugin enhanced listbox' SideBarTabs##Listbox
		Timeline Timeline TabTimeline
		All 'All tiddlers' TabAll
		Tags 'All tags' TabTags
		Authors 'All tiddlers, sorted by author (modifier)' SideBarTabs##Authors
		Missing 'Missing tiddlers' TabMoreMissing
		Orphans 'Orphaned tiddlers' TabMoreOrphans
		Shadowed 'Shadowed tiddlers' TabMoreShadowed
>>}}}===
}}}{{nowrap{<script label="welcome">  // ALWAYS OPEN AT TOP OF COLUMN
	story.closeTiddler('Welcome'); story.displayTiddler(null,'Welcome',1); return false;
</script> | +++^60%^*[about]...{{wrap{
	<<moveablePanel>>[[About TiddlyTools|About]]
----
	<<tiddler About>>}}}===
&nbsp;+++^60em^*[catalog]...{{small wrap{
	<<moveablePanel>><<tiddler CatalogTabs>>}}}<script>
		place.style.background="none"; place.style.border=0; place.style.padding=0;
	</script>===
&nbsp;+++(SiteMenu_faq)^60%^[faq|Tricks, Tips, and FAQs for using TiddlyWiki/TiddlyTools]...{{wrap{
	<<moveablePanel name:faq_sitemenu>>[[Tricks, Tips, and FAQs|FAQViewer]]
----
	{{smallform{{{hidden{<<tiddler GetTheFAQs>>}}}<<faqViewer faq 'groupbox height35em scrollbars' -modified 'YYYY.0MM.0DD - '>>}}}}}}===
&nbsp;+++^60%^*[contact]...{{wrap{
	<<moveablePanel>>[[Contact TiddlyTools|Contact]]
----
	<<tiddler Contact>>}}}===
&nbsp;+++^60em^*[donations|express your appreciation and help support TiddlyTools]...{{wrap{
	<<moveablePanel>>[[Donate to TiddlyTools|Donations]]
----
	{{small{<<tiddler Donations>>}}}}}}===
&nbsp;+++^60%^*[quickstart]...{{wrap{
	<<moveablePanel>>[[Download TiddlyTools QuickStart documents|QuickStart]]
----
	<<tiddler QuickStart>>}}}===
 | +++^60%^*[&copy;|copyright, licensing and other legal notices]...{{wrap{
	<<moveablePanel>>LegalStatements
----
	<<tiddler ScrollBox with: LegalStatements 30em>>}}}===
&nbsp;+++(SiteMenu_extras)[extras]...
	{{wrap{<<tiddler SiteMenuExtras>>}}}===
}}}/%
%/}}}
{{fine{
{{floatright{<<option chkForceMinorUpdate>><<tiddler {{
	var s=place.lastChild.style; s.margin=s.padding=0;
'';}}>><html><a href='javascript:;'
	title="keep current date/time/author when making tiddler changes"
	onclick="config.options.chkForceMinorUpdate=!config.options.chkForceMinorUpdate;
		this.parentNode.previousSibling.click();
		return false;
">minor changes</a><nowiki></html>}}}<script>
	if(readOnly)place.lastChild.style.display="none";
</script><<tiddler ToggleReadOnly>>}}}{{bordertop block{
<<newTiddler label:'new tiddler (general purpose)' title:'NewTiddler' prompt:'create a standard all-purpose tiddler'>>
	{{borderleft{
	{{fine{__//or, select a tiddler type://__}}}
	{{twocolumns{
	<<newTiddler label:'temporary' title:'NewTemporaryTiddler' tag:temporary prompt:'create a temporary tiddler'>>
	<<newJournal label:'journal' title:'DD MMM YYYY' tag:journal prompt:'create a journal (dated) tiddler'>>
	<<newTiddler label:'plugin' title:'NewPlugin' text:{{store.getTiddlerText('BlankPlugin','')}} tag:systemConfig prompt:'create a plugin tiddler'>>
	<<newTiddler label:'script' title:'NewScript' text:{{store.getTiddlerText('BlankScript','')}} tag:script prompt:'create an inline javascript tiddler'>>
	<<newTiddler label:'bookmark' title:'NewBookmark' text:{{store.getTiddlerText('BlankBookmark','')}} tag:'bookmark' prompt:'create a bookmark tiddler'>>
	<<newTiddler label:'CD' title:'NewCD' template:'CDEditTemplate' text:'enter track info and/or liner notes' tag:'CD' prompt:'create a CD/album information tiddler'>>
	<<newTiddler label:'FAQ' title:'NewFAQ' tag:faq text:{{store.getTiddlerText('BlankFAQ','')}} prompt:'create a FAQ/HowTo article'>>
	<<newTiddler label:'task' title:'NewTask' text:{{store.getTiddlerText('BlankTask','')}} tag:task fields:'status:"not started"' prompt:'create a task tracking tiddler'>>
	<<newTiddler label:'photo/video' title:'NewMedia' template:'MediaEditTemplate' text:'enter description' tag:'media' fields:'mediatype:"auto"' prompt:'create a media viewer/information tiddler'>>
	}}}}}}{{bordertop fine{
{{center{<script label="remove temporary tiddlers...">
	var tids=store.getTaggedTiddlers(config.options.txtTemporaryTag);
	if (!tids.length) { displayMessage("There are no temporary tiddlers to remove"); return false; }
	var titles=[]; for (t=0;t<tids.length;t++) titles.push(tids[t].title);
	var msg="This will remove "+titles.length+" tiddler"+(titles.length==1?"":"s");
	msg+=" tagged with '"+config.options.txtTemporaryTag+"':\n\n"
		+titles.join(", ")+"\n\nIs it OK to proceed?";
	if (!confirm(msg)) return false;
	for (t=0;t<tids.length;t++)
		{ story.closeTiddler(tids[t].title,true,false); store.removeTiddler(tids[t].title); }
	return false;
</script>}}}}}}<script>
	if (config.options.txtTemporaryTag==undefined) // TemporaryTiddlersPlugin not installed
		place.lastChild.style.display="none";
</script>}}}<script>
	if (readOnly) // hide menu items & show read-only message
		{ place.lastChild.style.display="none"; return; }
	if (config.macros.emptyTrash!=undefined) // if TrashPlugin is installed
		return "{{bordertop{\n{{floatright fine{<<emptyTrash>>}}}<<tag Trash>>}}}";
</script>
&nbsp;&nbsp;&nbsp; +++^70%^[browser|open web sites/media streams from inside TiddlyWiki]...
	<<moveablePanel name:minibrowser_sitemenu>>MiniBrowser
----
	<<miniBrowser>>===
&nbsp; +++^20em^[calculator]...<<moveablePanel name:microcalc_sitemenu>>MicroCalc<<tiddler MicroCalc>>===
&nbsp; +++^[clock]...<<moveablePanel name:clock_sitemenu>><script>
		place.menu.style.top="-1.5em";
	</script>{{menubox center{
	<script>var s=place.style;s.margin="-1.5em";</script>{{big{<<tiddler DigitalClock>>}}}}}}===
&nbsp; +++^15em^[timer|track elapsed time for any task or activity]...
	<<moveablePanel name:timer_sitemenu>>~TaskTimer
	{{center smallform{<<taskTimer ask>><script>
		place.lastChild.firstChild.style.width="100%";
	</script>}}}===
&nbsp; +++^18em^[calendar]...
	<<moveablePanel name:calendar_sitemenu>>calendar
----
	{{small{<<calendar thismonth>><script>place.lastChild.style.width="100%";</script>}}}===
&nbsp; +++^20em^[tiddlypod|playlist for audio streams (midi, mp3, etc.)]...
	<<moveablePanel name:tiddlypod_sitemenu>><script>
		place.menu.style.top=".2em";
	</script>{{center fine{<script>
		place.style.margin="-.5em 0";
	</script>//<<tiddlyPod listlength:20em width:200>>//}}}===
&nbsp; +++^[tiddlylife|Cellular Automata: Conway's "Game of Life"]...
	<<moveablePanel name:tiddlylife_sitemenu>>[[TiddlyLife|TiddlyLifePlugin]]: Conway's "Game of Life"
----
	{{center small nowrap{
	<<life cellsize:.8em tid:GliderDance>>}}}===
 | +++^30em^[panels|Panel Manager Map Viewer]...
	[[PanelManager Map Viewer|PanelManagerPlugin]]
----
	{{center{<<moveablePanel commands>><<moveablePanel viewer>>}}}<<moveablePanel name:panelmanager_sitemenu fold hover manager height:auto>>===
&nbsp; +++^70%^[cookies|Manage TiddlyWiki persistent cookie settings]...
	<<moveablePanel name:cookies_sitemenu>>CookieManager / CookieJar
----
	<<tiddler ScrollBox with: CookieJar 30em>>===
&nbsp; +++^70%^[tweaker]...
	<<moveablePanel name:tweaker_sitemenu>>TiddlerTweaker
----
	{{small smallform{<<tiddler TiddlerTweaker>>}}}===
&nbsp; +++^70%^[tidIDE|TiddlyWiki Integrated Development Environment]...
	{{fine block smallform left{<<moveablePanel name:tidIDE_sitemenu>>TiddlyWiki Integrated Development Environment
	<<tidIDE id:sitemenu +SystemInfo CompareTiddlers edit>>}}}===
&nbsp; +++^[files|view local files and folders (offline use only)]...
	<<moveablePanel name:files_sitemenu>>ShowLocalDirectory //(offline use only)//
----
	<<tiddler ScrollBox with: ShowLocalDirectory 40em>>===
&nbsp; <script label="jash" title="JASH: Javascript Shell">
	clearMessage(); toggleJash();
</script><script>
	place.lastChild.className="button";
</script>/%
%/&nbsp; +++^25em^[bookmarklets|TiddlyWiki tear-off toolbar command links]...
	<<moveablePanel name:bookmarklets_sitemenu>>{{fine{
	<<tiddler InstantBookmarklets>>}}}===
@@display:block;{{borderbottom{
<<saveChanges>>}}}@@<script>
	if(readOnly)place.lastChild.style.display="none";
</script>@@display:block;{{borderbottom{
<<saveAs "filename:new.html" open>>}}}@@@@display:block;<<upload>> {{fine{//(password req'd)//}}}@@<script>
	if(readOnly)place.lastChild.style.display="none";
</script>@@display:block;{{borderbottom{
[[download from web|QuickStart]]}}}@@@@display:block;<<attach>>@@<script>
	if(readOnly)place.lastChild.style.display="none";
</script>@@display:block;<<importTiddlers link>>@@<script>
	if(readOnly)place.lastChild.style.display="none";
</script>@@display:block;{{borderbottom{
<<exportTiddlers>>}}}@@+++(newdocument)*[new document...]...<<tiddler NewDocumentList>>===
{{smallform{
	<script label="tiddler:" title="select a tiddler title or open matching tiddler">
	// send a return key to the gotoTiddler input field
	var form=place.parentNode.nextSibling.firstChild;
	config.macros.gotoTiddler.inputKeyHandler({keyCode:13},form.gotoTiddler,form.list);
	return false;
</script><script>
	place.lastChild.style.fontWeight="normal";
</script>
<<gotoTiddler search inputstyle:"display:block;width:98.5%;margin:0;font-size:8pt;" liststyle:"width:85%;font-size:8pt;">>/%
%/}}}/%
%/{{selected{{{toolbar fine{
	<<tiddler BreadcrumbsCommand>>/%
	%/ <<showPopup tiddler:FavoriteTiddlers label:"favorites" tip:"quick access to favorite tiddlers">>/%
	%/ <<openStory popup>>/%
	%/ <<tiddler QuickSearchPopup with: {{tiddler?tiddler.title:""}} "see also">>/%
%/}}}}}}{{clear{
}}}
{{block{{{floatright{<<option chkRandomTheme>><script>
	place.lastChild.title="select a random theme at startup";
</script><<switchTheme [[label:randomize]] [[prompt:select a random theme at startup]] [[*]]>>}}}++++(themes)[themes]
	<<switchTheme width:100%>>
===
}}}{{block{+++(displayoptions)[display]...
	{{borderleft{
	<<option chkSinglePageMode>> one tiddler at a time
	<<tiddler ToggleSiteMenu>>
	<<tiddler ToggleSiteTitles>>
	<<tiddler ToggleBreadcrumbs>>
	<<tiddler ToggleScrollingSidebars>>
	<<option chkAnimate>> enable animation effects
	<<option chkShowQuickEdit>><script>
		var chk=place.lastChild;
		chk.coreOnChange=chk.onchange;
		chk.onchange=function() {
			// refresh active editors when checkbox is toggled
			if (this.coreOnChange) this.coreOnChange.apply(this,arguments);
			story.forEachTiddler(function(t,e){if (story.isDirty(t)) refreshElements(e);});
		};
	</script> show ~QuickEdit toolbar
	<<option chkPopupPreviews>> shift-click previews links
	commands: <<option chkIconsShowText>>text <<option chkIconsShowImage>>icons
	}}}
===
}}}{{block{+++(displayoptions_page)[layout]
	{{borderleft{
	{{floatleft right{
	<<tiddler SetStoryHeight>>
	<<tiddler SetSidebarTabsHeight>>
	<<tiddler SetPopupsHeight>>
	<<tiddler SetTiddlerHeight>>
	<<tiddler SetTiddlerColumns>>}}}
	{{clear block{}}}}}}
===
}}}@@display:block;+++(saving)[saving]...
	{{borderleft{
	<<option chkAutoSave>> auto save
	<<option chkSaveBackups>> create backup file
	<<option chkTemporaryKeep>> keep temporary tiddlers
	<<option chkGenerateAnRssFeed>> create .xml file}}}===
@@@@display:block;+++(upload)[upload]...
	{{borderleft{
	<<tiddler SiteMenuOptionsUpload>>}}}===
@@@@display:block;+++[username]...
	<<option txtUserName>><script>
		place.lastChild.setAttribute("autocomplete","off");
		var s=place.lastChild.style;s.width="98%";s.fontSize="8pt";
	</script>===
@@@@display:block;+++(cookies)[cookies]...
	{{smallform{<<cookieManager>>}}}===
@@[[AdvancedOptions]]<script>
	place.lastChild.style.fontStyle="normal";
	place.lastChild.style.fontWeight="normal";
	place.lastChild.innerHTML="advanced options...";
</script>
@@display:block;+++[script URL]...
<<option txtUploadStoreUrl>><script>
	place.lastChild.title="URL for server-side upload processing";
	place.lastChild.setAttribute("autocomplete","off")
	var s=place.lastChild.style;s.width="98%";s.fontSize="8pt";s.margin="0";
</script>===
@@@@display:block;+++[target path]...
<<option txtUploadDir>><script>
	place.lastChild.title="target path (blank=same as script URL)";
	place.lastChild.setAttribute("autocomplete","off")
	var s=place.lastChild.style;s.width="98%";s.fontSize="8pt";s.margin="0";
</script>===
@@@@display:block;+++[target filename]...
<<option txtUploadFilename>><script>
	place.lastChild.title="target filename (blank=use current filename)";
	place.lastChild.setAttribute("autocomplete","off")
	var s=place.lastChild.style;s.width="98%";s.fontSize="8pt";s.margin="0";
</script>===
@@@@display:block;+++[backup path]...
<<option txtUploadBackupDir>><script>
	place.lastChild.title="backup path (blank=same as path)";
	place.lastChild.setAttribute("autocomplete","off")
	var s=place.lastChild.style;s.width="98%";s.fontSize="8pt";s.margin="0";
</script>===@@
<script>
	// timestamp for generating GUID (globally unique ID)
	config.renderTime=new Date().getTime();
</script>/%
%/{{selected{{{toolbar{+++[options|set search options]#sidebarSearchOptions:
	<<tiddler SearchOptions>>===
<script>place.lastChild.id+=config.renderTime;</script>/%
%/}}}{{small editor{<<search>>}}}<<DOM move {{"sidebarSearchOptions"+config.renderTime}}>>}}}
{{borderbottom{
<<tiddler RefreshPageDisplay>><script>
	place.lastChild.style.fontWeight="normal"
</script>}}}{{borderbottom{
<<moveablePanel menu label:[[panel manager]] prompt:[[Moveable Panel Panel Manager Popup Control Panel]]>>
<<permaview>>
<<snapshot label:"HTML snapshot" id:ask>>
{{span{<<saveStory ask "save story to tiddler" "save current story view into a tiddler, e.g., DefaultTiddlers">>
<<tiddler SaveBreadcrumbs>>}}}<script>
	if(readOnly)place.lastChild.style.display="none";
</script>}}}{{borderbottom{
<<option chkSaveStory>><script>
	place.lastChild.style.margin=place.lastChild.style.padding="0";
</script> [[enable story saver|StorySaverPlugin]]<script>
	place.lastChild.title="automatically remember/redisplay current story view in between browser sessions"
</script>
}}}<<closeAll>>
/%
|Name|SiteNews|
|Source|http://www.TiddlyTools.com/#SiteNews|
|Version|1.1.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|script|
|Requires|InlineJavascriptPlugin, AnimationEffectsPlugin, RollText, StyleSheetShortcuts|
|Description|Custom TiddlyTools SiteNews headline generator|

!bannerFormat
//<<animate "[[What's new at TiddlyTools|SiteNews]]" fontSize %0% 0 140 0 500>>
{{siteSubtitle bold{<<tiddler RollText with: "plugins... macros... scripts... templates... styles ...and&nbsp;more!" 700 500 500>><<animate "Small Tools for Big Ideas!" fontSize %0% 0 100 5000 500>>}}}//
!end bannerFormat

!itemFormat
|borderless widetable|k
|{{left big italic nowrap{[[%1]]&nbsp;&nbsp;&nbsp;}}} | {{right fine nowrap{''%3''<br>//updated by %2//}}}|
{{fine center NOThidden bordertop{{{block italic gray underline{%5}}}{{block small{"""%6"""}}}}}}
!end itemFormat

%/{{center{<<tiddler SiteNews##bannerFormat>><script>
if (config.news===undefined) config.news={
	list:[],
	getNews: function() {
		var ex=this.exclude.readBracketedList();
		var tids=store.getTiddlers("modified","excludeLists").reverse();
		var list=[];
		for (var t=0; t<tids.length; t++) {
			if (tids[t].tags.containsAny(ex)) continue;
			var title=tids[t].title;
			var who=tids[t].modifier;
			var when=tids[t].modified.formatString(this.datefmt);
			var size=tids[t].text.length;
			var desc=store.getTiddlerSlice(title,"Description")||"";
			var revs=store.getTiddlerText(title+"##Revisions","");
			if (!revs.length) continue;
			var itemtxt=revs.split("\n")[1]||"";
			if (itemtxt.length>this.cliplen) itemtxt=itemtxt.substr(0,this.cliplen)+"...";
			list.push(this.itemfmt.format([list.length+1,title,who,when,size,desc,itemtxt]));
		}
		return list;
	},
	nextNews: function(id) {
		var here=document.getElementById(id); if (!here) return;
		var out=this.list[here.next++];
		if (here.next>=this.list.length) here.next=0;
		here.style.display="none"; removeChildren(here); wikify(out,here);
		if(anim && config.options.chkAnimate)
			anim.startAnimating(new Slider(here,true,false,"none"));
		else
			here.style.display="block";
		here.timer=setTimeout("config.news.nextNews('"+here.id+"')",here.tick*1000);
	},
	startNews: function(here,tick,wait,force) {
		if (!here) return;
		if (!config.news.list.length||force) // init only once for performance savings
			config.news.list=config.news.getNews(); // get news from Revisions
		if (!here.id) here.id="news_"+new Date().getTime()+Math.random();
		here.style.cursor="pointer";
		here.title=this.tip;
		here.tick=tick;
		here.wait=wait;
		here.next=0;
		here.timer=0;
		here.onclick=function() { // manual advance
			if (this.timer) { clearTimeout(this.timer); this.timer=0; }
			config.news.nextNews(this.id);
		}
		here.onmouseover=function() { // stop auto
			if (this.timer) { clearTimeout(this.timer); this.timer=0; }
			var info=this.childNodes[1]; // show more info
			if (info.style.display!="block") {
				if (anim && config.options.chkAnimate)
					anim.startAnimating(new Slider(info,true,false,"none"));
				else info.style.display="block";
			}
		}
		here.onmouseout=function() { // resume auto
			if (!this.timer)
				this.timer=setTimeout("config.news.nextNews('"+this.id+"')",this.tick*1000);
		}
		here.timer=setTimeout("config.news.nextNews('"+here.id+"')",place.wait*1000);
	}
};
// configuration settings
merge(config.news,{
	cliplen: 80,
	tip: "click for next item",
	exclude: "excludeNews pluginInfo",
	datefmt: "DDD MMM DDth YYYY hh12:0mm am",
	itemfmt: store.getTiddlerText("SiteNews##itemFormat")
});
// show automatic news
config.news.startNews(place,7,10,true);
</script>
}}}
http://www.TiddlyTools.com/proxy.php?url=
//Tiddlers do easily 80% of what you're looking for and, if you really want to nail the remaining 20%, you can find almost anything on www.TiddlyTools.com.// - ''~PeterMerel''
----
//TiddlyTools is a treasure trove of high quality, well maintained TiddlyWiki plugins// - ''www.TiddlyWiki.org''
----
//You're the plugin ~MacGyver! It seems that whenever there's a problem, you just barge in with a URL to TiddlyTools which solves the issue.// - ''FND''
----
//TiddlyTools.com is actually the work of one man - at least he *claims* he's just one man, but output seems to indicate something more like a Borg-style collective...// - ''~DanielBaird''
----
//An avalanche of addons which boosts the limits of ~JavaScript to unknown heights// - ''www.orbifold.net''
----
//You didn't feed me, but you gave me grain and explained me how a mill works. ;-) That's more than helping. Thank you very much.// - ''~WinterKnight''
----
//I've been a devoted user of your TiddlyTools adaptations for so long, that I've fallen into the trap of simply staying in quiet awe of the work you do.// - ''~HansWobbe''
----
//Wow Eric - it's amazing!! You solve problems in a way that the solution comes earlier than the problem! // - ''~MichaelTarnowski''
----
//TiddlyWiki is far and away the best wiki technology on the planet today. Go check www.TiddlyTools.com if you don't believe me...// - ''~PeterMerel''
----
//Dang it, Eric, you have to stop coming up with the solution before I have a chance to suggest it! :-)// - ''~KenGirard''
----
//...all I can say is "wow"! This site is amazing!// - ''~SamWalker''
----
//I've seldom seen so much output on a consistent basis that is always of the highest quality.// - ''~HansWobbe''
----
//You make absolutely the best tools, thank you!// - ''~BenjaminMigliori''
----
//www.TiddlyTools.com... there are some real gems in there!// - ''~TedPavlic''
----
//It's very clear that TiddlyWiki is ~MoreWikiThanWiki.  ...go visit www.TiddlyTools.com and click on "extras"...''this is not your father's ~WikiWikiWeb...''// - ''~PeterMerel''
----
//Thanks for being so smart, Eric! // - ''~DaveParker''
----
//Amazing extensions, ...so many fabulous features!// - ''~JeffChen''
----
//..."Hey Mister, TiddlyTools Doesn't Suck!!"... ;-)  Awesome stuff!  ... // - ''~PaulReiber''
This tiddler is included in the PageTemplate as a ''hidden SPAN''.  You can use it include macros or inline scripts that are automatically invoked whenever the document is loaded.
!!!!![[SetTiddlerColumns]]
<<<
sets the number of tiddler columns to display using the -moz-column-count, -moz-column-width, and -moz-column-gap CSS attributes (currently supported by Firefox only).
{{{<<tiddler SetTiddlerColumns>>}}}
<<tiddler SetTiddlerColumns>>
<<<
!!!!![[SetSidebarTabsHeight]]
<<<
sets a fixed or percentage height for the sidebar tabs, or 'auto' (default) to allow as much room it needs.
{{{<<tiddler SetSidebarTabsHeight>>}}}
<<tiddler SetSidebarTabsHeight>>
<<<
!!!!![[SetPopupsHeight]]
<<<
sets a fixed or percentage height for popup displays (e.g., tab popups), or 'auto' (default) to allow as much room needed.
{{{<<tiddler SetPopupsHeight>>}}}
<<tiddler SetPopupsHeight>>
<<<
!!!!![[SetStoryHeight]]
<<<
sets a fixed or percentage height for the story column, or 'auto' (default) to allow as much room as needed.
{{{<<tiddler SetStoryHeight>>}}}
<<tiddler SetStoryHeight>>
<<<
!!!!![[SetTiddlerHeight]]
<<<
sets a fixed or percentage height for each tiddler, or 'auto' (default) to allow each tiddler to use as much room as it needs.
{{{<<tiddler SetTiddlerHeight>>}}}
<<tiddler SetTiddlerHeight>>
<<<
!!!!![[ToggleSiteTitles]]
<<<
sets the visibility (//display:none// or //display:block//) of the SiteTitle/SiteSubtitle display area ('page titles', DOM ID=//header//)
{{{<<tiddler ToggleSiteTitles>>}}}
<<tiddler ToggleSiteTitles>>
<<<
!!!!![[ToggleSiteMenu]]
<<<
sets the visibility (//display:none// or //display:block//) of the SiteMenu display area ('menubar', DOM ID=//siteMenu//).
<script show>
// show site menu by default
if (config.options.chkHideSiteMenu==undefined)
	config.options.chkHideSiteMenu="false";
</script>{{{<<tiddler ToggleSiteMenu>>}}}
<<tiddler ToggleSiteMenu>>
<<<
!!!!![[VisitCounter]]
<<<
tracks and displays a quick reminder of how many times you have viewed this document as well as the date and time of your last visit.  This information is stored privately in your browser using cookies (txtVisitCount and txtLastVisit), and are //never// accessible to any other parties.
{{{<<tiddler VisitCounter with: TiddlyTools>>}}}
<<tiddler VisitCounter with: TiddlyTools>>
<<<
!!!!![[ToggleLeftSidebar]], [[ToggleRightSidebar]] 
<<<
set the visibility (//display:none// or //display:block//) of the MainMenu ('left sidebar', DOM ID=//mainMenu//) and SideBarOptions ('right sidebar', DOM ID=//sidebar//) displays.
<script show>
	// default sidebar visibility
	if (config.options.chkShowLeftSidebar==undefined)
		config.options.chkShowLeftSidebar=true;
	if (config.options.chkShowRightSidebar==undefined)
		config.options.chkShowRightSidebar=false;
</script>
|{{{<<tiddler ToggleLeftSidebar>>}}} |<<tiddler ToggleLeftSidebar>> |
|{{{<<tiddler ToggleRightSidebar>>}}} |<<tiddler ToggleRightSidebar>> |
<<<
!!!!![[ToggleScrollingSidebars]]
<<<
sets 'position:fixed' for the sidebars, so that they remain fixed in place (aka, "hover") when the rest of the page content is scrolled.
{{{<<tiddler ToggleScrollingSidebars>>}}}
<<tiddler ToggleScrollingSidebars>>
<<<
<script>
	if(!(addClass instanceof Function) || !(removeClass instanceof Function)) return;
	place.onmouseover = function(e){
		addClass(this,"selected");
		addClass(document.getElementById("backstageButton"),"selected")
	}
	place.onmouseout = function(e){
		removeClass(this,"selected");
		removeClass(document.getElementById("backstageButton"),"selected")
	}
	var btn=document.getElementById("backstageButton"); if(!btn) return;
	btn.onmouseover = function(e){
		addClass(this,"selected");
		addClass(document.getElementById("siteSubtitle"),"selected");
	}
	btn.onmouseout = function(e){
		removeClass(this,"selected");
		removeClass(document.getElementById("siteSubtitle"),"selected");
	}

</script>{{floatright mouseover{@@display:block;position:fixed;margin-top:.9em;margin-left:-2px;line-height:100%;{{span{/%
	%/<<moveablePanel menu>>
	@@display:block;margin-left:-2px;<<tiddler ToggleFullScreen with: "&loz;" "&loz;">>@@/%
	%/@@display:block;margin-left:-1px;margin-top:2px;position:relative;/%
		%/+++^20em^[&uml;|playlist for audio streams (midi, mp3, etc.)]...
	<<moveablePanel name:tiddlypod_header>><script>
		place.menu.style.top=".2em";
	</script>{{center fine{<script>
		place.style.margin="-.5em 0";
	</script>//<<tiddlyPod listlength:20em width:200>>//}}}===@@/%
%/}}}@@}}}/%
%/{{right{
{{small nowrap{/%
%/{{floatright{&nbsp;&nbsp;}}}[>img[i4: Intuitive Interfaces for Intelligent Interactions|i4logo.gif]]/%
%///@@display:block;padding:.2em 0 .3em 0;font-size:20pt;font-family:"Trebuchet MS";[[ELS Design Studios|ELSDesignStudios]]@@///%
%/<<animate "Intuitive Interfaces for Intelligent Interactions" top %0px -100 0 9500 1000>>/%
%/}}}/%
%/<<animate = +top %0px -100 0 8000 2000>>/%
%/<<animate = +left %0% -50  0 8000 2000>>/%
%/}}}/%
%/
<<tiddler HideTiddlerTags>>/%

TIMESTAMP (for creating unique slider panel DOM id's)
%/<script> config.renderTime=new Date().getTime(); </script>/%

BEGIN TOOLBAR
%/{{toolbar right floatright mouseover fine{/%

STATS
%/++++(SiteSummary_stats){{plain{[stats|show tiddler statistics][&radic;stats|hide tiddler statistics]}}}#SiteSummary_stats:...
	@@display:block;height:.5em;@@{{small indent{
	<<tiddler ShowTiddlerStatistics>>}}}===
<script> place.lastChild.id+=config.renderTime; </script>/%

VISITS
%/++++(SiteSummary_visits){{plain{[visits|show personal visit counter][&radic;visits|hide personal visit counter]}}}#SiteSummary_visits:...
	@@display:block;height:.5em;@@{{left fine{
	<<tiddler VisitCounter with: TiddlyTools "This is your first visit... {{medium bold italic{[[Welcome to TiddlyTools!|About]]}\}\}">>}}}===
<script> place.lastChild.id+=config.renderTime;
	if (config.visitCount<2 && startingUp) {
		story.closeTiddler("About");
		story.displayTiddler(story.findContainingTiddler(place),"About");
	}
</script>/%

RECENT CHANGES
%/++++(SiteSummary_changes){{plain{[changes|show recent changes info][&radic;changes|hide recent changes info]}}}#SiteSummary_changes:...
	@@display:block;height:.5em;@@+++*{{small{[changes|show recent changes list][]}}}...
		{{smallform{<<recentChanges 90>>}}}===<script>
		var btn=place.lastChild.button;
		var txt=wikifyPlainText("<<recentChanges 90 summary>>");
		btn.innerHTML=txt;
		btn.setAttribute("closedtext",txt);
	</script>===
<script> place.lastChild.id+=config.renderTime; </script>/%

NEWS
%/+++(SiteSummary_news){{plain{[news|announcements and site news][&radic;news|announcements and site news]}}}#SiteSummary_news:...
	{{floatright{@@display:block;height:6em;{{viewer fine center nowrap{
	<<tiddler SiteNews>><<tiddler {{
		var s=place.style; s.padding=s.margin='2px 1em';
	'';}}>>}}}@@}}}===
<script> place.lastChild.id+=config.renderTime; </script>/%

%/}}}/% END TOOLBAR

UPDATE NOTICE
%/{{left{
''{{nowrap{TiddlyTools was updated on}}} {{nowrap{<<date filedate "DDD, MMM DDth YYYY at 0hh12:0mm:0ss am">>}}}''}}}/%

PLACE STACK OF PANELS
%/<<DOM move {{"SiteSummary_stats"+config.renderTime}}>>/%
%/<<DOM move {{"SiteSummary_visits"+config.renderTime}}>>/%
%/<<DOM move {{"SiteSummary_changes"+config.renderTime}}>>/%
%/<<DOM move {{"SiteSummary_news"+config.renderTime}}>>
{{small{
{{floatleft{@@font-size:20pt;/%

TT zooms in at 2.5sec... "iddly ools" zooms at 3.5sec
%/<html><a href="http://www.TiddlyTools.com/" target="_blank" title="Visit www.TiddlyTools.com"><i>/%
%/<<animate "T" fontSize %0% 0 150 2500 1000>>/%
%/<<animate "iddly" fontSize %0% 0 150 3500 800>>/%
%/<<animate "T" fontSize %0% 0 150 2500 1000>>/%
%/<<animate "ools" fontSize %0% 0 150 3500 800>>/%
%/</i></a></html>/%

tag line slides in at 10sec to end animation
%/@@@@font-family:Trebuchet MS;// Small Tools for Big Ideas!{{smaller{&trade;}}}//<<animate = fontSize %0% 0 140 10000 1>><<animate = +left %0px -500 0 10000 2500>>@@/%

version info zooms in at 3.5sec and remains for 1.5sec, then zooms out again.
%/{{tiny{// with TiddlyWiki v<<version>>//<<animate = fontSize %0% 0 100 3500 200 2 1500>>}}}/%

greeting zooms out at 2sec
%/{{siteSubtitle nowrap{//<<animate " Welcome to TiddlyTools!..." fontSize %0% 300 0 2000 500>>//}}}/%

modification date zooms in at 6sec and remains for 3sec, then zooms out again.
%/{{fine{<<animate {{new Date(document.lastModified).formatString('// updated on mmm DDth, YYYY hh:0mm:0ss//')}} fontSize %0% 0 100 6000 200 2 3000>>}}}/%

%/}}}
http://tiddlytools.github.io/
/%
!info
|Name|SlideshowTimer|
|Source|http://www.TiddlyTools.com/#SlideshowTimer|
|Version|2.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|Type|transclusion|
|Description|slideshow countdown timer closes current tiddler and opens another one in its place|
Usage
<<<
{{{
<<tiddler SlideshowTimer with: NextTiddlerTitle delay close fold>>
}}}
*''NextTiddlerTitle''<br>the title of any existing tiddler
*''delay'' (optional, default=15 seconds)<br>the number of seconds before switching to the next tiddler
*''close'' //or// ''fold'' (optional)<br>close/fold the current tiddler when the next tiddler is opened
Notes:
*Moving the mouse over the timer pauses the countdown, moving away resumes the countdown.
*Click the timer to immediately advance to the next tiddler.
*When the timer shows "0:00", clicking will reset the countdown
<<<
Example
<<<
{{{<<tiddler SlideshowTimer with: About 15>>}}}
<<tiddler SlideshowTimer##show with: About 15>>
<<<
!end

!show
{{span{}}}<<tiddler {{
	var tid='$1';
	var delay='$'+'2'!='$2'?'$2'*1000:15000;
	var mode='$3';
	var now=new Date().getTime();
	var target=place.lastChild;
	if (!target.timer) {
		target.id=now+Math.random(); // unique ID
		target.title="timer is paused... click for next tiddler: '"+this.tid+"'";
		target.style.cursor='pointer';
		target.tid=tid;
		target.delay=delay;
		target.mode=mode;
		target.stopTime=now+delay;
		target.innerHTML=delay/1000;
		target.tick = function() {
			var remaining=Math.floor((this.stopTime-new Date().getTime())/1000);
			if (remaining||this.paused) {
				if (!this.paused) this.innerHTML='0:'+String.zeroPad(remaining,2);
				var code="var e=document.getElementById('"+this.id+"'); if(e)e.tick()";
				target.timer=setTimeout(code,500);
			} else this.onclick();
		};
		target.onmouseover=function()
			{ var remaining=this.stopTime-new Date().getTime(); this.paused=Math.max(remaining,0); };
		target.onmouseout=function()
			{ this.stopTime=new Date().getTime()+this.paused; this.paused=0; };
		target.onclick = function() {
			if (!this.timer) {
				this.paused=this.delay;
				this.innerHTML='0:'+String.zeroPad(Math.floor(this.delay/1000),2);
				var code="var e=document.getElementById('"+this.id+"'); if(e)e.tick()";
				this.title="timer is paused... click for next tiddler: '"+this.tid+"'";
				this.timer=setTimeout(code,500);
				return false;
			}
			this.timer=clearTimeout(this.timer);
			this.title='click to reset timer to '+Math.floor(this.delay/1000)+' seconds';
			this.innerHTML='0:00';
			var here=story.findContainingTiddler(this);
			if (store.getTiddlerText(this.tid)) story.displayTiddler(here,this.tid);
			if (mode=='close') story.closeTiddler(here.getAttribute('tiddler'));
			if (mode=='fold' && config.commands.collapseTiddler) // see CollapseTiddlerPlugin
				config.commands.collapseTiddler.handler(null,here,here.getAttribute('tiddler'));
			return false;
		};
		var code="var e=document.getElementById('"+target.id+"'); if(e)e.tick()";
		target.timer=setTimeout(code,500);
	}
'';}}>>
!end
%/<<tiddler {{var src='SlideshowTimer'; src+(tiddler&&tiddler.title==src?'##info':'##show');}}
	with: [[$1]] [[$2]] {{'$3'.toLowerCase()}}>>
/***
|Name|SnapshotPlugin|
|Source|http://www.TiddlyTools.com/#SnapshotPlugin|
|Documentation|http://www.TiddlyTools.com/#SnapshotPluginInfo|
|Version|1.4.3|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|save or print HTML+CSS image of rendered document content|
This plugin provides a macro as well as tiddler toolbar commands to create a file or browser window containing the //rendered// CSS-and-HTML that is currently being displayed for selected elements of the current document.
!!!!!Documentation
>see [[SnapshotPluginInfo]]
!!!!!Configuration
<<<
<<option chkSnapshotHTMLOnly>> output HTML only (omit CSS)
<<<
!!!!!Revisions
<<<
2011.02.14 1.4.3 fix OSX error: use picker.file.path
2011.01.03 1.4.2 added snapshotSaveViewer toolbar command
2010.12.15 1.4.1 added 'snapshot' class to wrapper
|please see [[SnapshotPluginInfo]] for additional revision details|
2008.04.21 1.0.0 initial release - derived from [[NewDocumentPlugin]] with many improvements...
<<<
!!!!!Code
***/
//{{{
version.extensions.SnapshotPlugin= {major: 1, minor: 4, revision: 3, date: new Date(2011,2,14)};

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

config.macros.snapshot = {
	snapLabel: "save a snapshot",
	printLabel: "print a snapshot",
	snapPrompt: "save an HTML image",
	printPrompt: "print an HTML image",
	hereID: "here",
	viewerID: "viewer",
	storyID: "story",
	allID: "all",
	askID: "ask",
	askTiddlerID: "askTiddler",
	askDOMID: "askDOM",
	askMsg: "select an element...",
	hereItem: "tiddler: '%0'",
	viewerItem: "tiddler: '%0' (content only)",
	storyItem: "story column (one file)",
	storyFilesItem: "story column (multiple files)",
	allItem: "entire document",
	tiddlerItem: "select a tiddler...",
	IDItem: "select a DOM element by ID...",
	HTMLItem: "[%0] output HTML only (omit CSS)",
	fileMsg: "select or enter a target path/filename",
	defaultFilename: "snapshot.html",
	okmsg: "snapshot written to %0",
	failmsg: "An error occurred while creating %0",
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		var printing=params[0]&&params[0]=="print"; if (printing) params.shift();
		params = paramString.parseParams("anon",null,true,false,false);
		var id=getParam(params,"id","here");
		var label=getParam(params,"label",printing?this.printLabel:this.snapLabel);
		var prompt=getParam(params,"prompt",printing?this.printPrompt:this.snapPrompt);
		var btn=createTiddlyButton(place,label,prompt, function(ev){
			this.setAttribute("snapID",this.getAttribute("startID"));
			config.macros.snapshot.go(this,ev)
		});
		btn.setAttribute("startID",id);
		btn.setAttribute("snapID",id);
		btn.setAttribute("printing",printing?"true":"false");
		btn.setAttribute("HTMLOnly",config.options.chkSnapshotHTMLOnly?"true":"false");
	},
	go: function(here,ev) {
		var cms=config.macros.snapshot; // abbreviation
		var id=here.getAttribute("snapID");
		var printing=here.getAttribute("printing")=="true";
		var HTMLOnly=here.getAttribute("HTMLOnly")=="true";

		if (id==cms.askID||id==cms.askTiddlerID||id==cms.askDOMID) {
			cms.askForID(here,ev);
		} else if (id==cms.storyID) {
			story.forEachTiddler(function(t,e) {
				var out=cms.getsnap(e,e.id,printing,HTMLOnly);
				if (printing) cms.printsnap(out);
				else cms.savesnap(out,e.getAttribute('tiddler')+'.html');
			});
		} else {
			if (id==cms.allID) id="contentWrapper";
			var snapElem=document.getElementById(id);
			if (id==cms.hereID || id==cms.viewerID)
				var snapElem=story.findContainingTiddler(here);
			if (snapElem && hasClass(snapElem,"tiddler") && (id==cms.viewerID || HTMLOnly)) {
				// find viewer class element within tiddler element
				var nodes=snapElem.getElementsByTagName("*");
				for (var i=0; i<nodes.length; i++)
					if (hasClass(nodes[i],"viewer")) { snapElem=nodes[i]; break; }
			}
			if (!snapElem) // not in a tiddler or no viewer element or unknown ID
				{ e.cancelBubble=true; if(e.stopPropagation)e.stopPropagation(); return(false); }
			// write or print snapshot
			var out=cms.getsnap(snapElem,id,printing,HTMLOnly);
			if (printing) cms.printsnap(out); else cms.savesnap(out);
		}
		return false;
	},
	askForID: function(here,ev) {
		var ev = ev ? ev : window.event; 
		var cms=config.macros.snapshot; // abbreviation
		var id=here.getAttribute("snapID");
		var indent='\xa0\xa0\xa0\xa0';
		var p=Popup.create(here); if (!p) return false; p.className+=' sticky smallform';
		var s=createTiddlyElement(p,'select'); s.button=here;
		if (id==cms.askID) {
			s.options[s.length]=new Option(cms.askMsg,cms.askID);
			var tid=story.findContainingTiddler(here);
			if(tid) { 
				var title=tid.getAttribute("tiddler");
				if (here.getAttribute("HTMLOnly")!="true")
					s.options[s.length]=new Option(indent+cms.hereItem.format([title]),cms.hereID);
				s.options[s.length]=new Option(indent+cms.viewerItem.format([title]),cms.viewerID);
			}
			s.options[s.length]=new Option(indent+cms.tiddlerItem,cms.askTiddlerID);
			s.options[s.length]=new Option(indent+cms.IDItem,cms.askDOMID);
			s.options[s.length]=new Option(indent+cms.storyItem,"tiddlerDisplay");
			s.options[s.length]=new Option(indent+cms.storyFilesItem,cms.storyID);
			s.options[s.length]=new Option(indent+cms.allItem,"contentWrapper");
		}
		if (id==cms.askDOMID) {
			s.options[s.length]=new Option(cms.IDItem,cms.askDOMID);
			var elems=document.getElementsByTagName("*");
			var ids=[];
			for (var i=0;i<elems.length;i++)
				if (elems[i].id.length && elems[i].className!="animationContainer")
					ids.push(elems[i].id);
			ids.sort();
			for (var i=0;i<ids.length;i++) s.options[s.length]=new Option(indent+ids[i],ids[i]);
		}
		if (id==cms.askTiddlerID) {
			s.options[s.length]=new Option(cms.tiddlerItem,cms.askTiddlerID);
			var elems=document.getElementsByTagName("div");
			var ids=[];
			for (var i=0;i<elems.length;i++) { var id=elems[i].id;
				if (id.length && id.substr(0,story.idPrefix.length)==story.idPrefix && id!="tiddlerDisplay")
					ids.push(id);
			}
			ids.sort();
			for (var i=0;i<ids.length;i++) s.options[s.length]=new Option(indent+ids[i].substr(story.idPrefix.length),ids[i]);
		}
		s.options[s.length]=new Option(cms.HTMLItem.format([here.getAttribute("HTMLOnly")=="true"?"\u221a":"_"]),cms.HTMLItem);
		s.onchange=function(ev){
			var ev = ev ? ev : window.event; 
			var cms=config.macros.snapshot; // abbreviation
			var here=this.button;
			if (this.value==cms.HTMLItem) {
				config.options.chkSnapshotHTMLOnly=!config.options.chkSnapshotHTMLOnly;
				here.setAttribute("HTMLOnly",config.options.chkSnapshotHTMLOnly?"true":"false");
				config.macros.option.propagateOption("chkSnapshotHTMLOnly","checked",
					config.options.chkSnapshotHTMLOnly,"input");
			} else
				here.setAttribute("snapID",this.value);
			config.macros.snapshot.go(here,ev);
			return false;
		};
		Popup.show();
		ev.cancelBubble=true;
		if(ev.stopPropagation)ev.stopPropagation();
		return false;
	},
	getpath: function() {
		// get current path
		var path=getLocalPath(window.location.href);
		var slashpos=path.lastIndexOf("/");
		if (slashpos==-1) slashpos=path.lastIndexOf("\\"); 
		if (slashpos!=-1) path=path.substr(0,slashpos+1); // trim filename
		return path;
	},
	getsnap: function(snapElem,id,printing,HTMLOnly) {
		var cms=config.macros.snapshot; // abbreviation
		var out='<head><meta http-equiv="Content-Type" content="text/html;charset=utf-8" />';
		if (printing)
			out+='<base href="file:///'+cms.getpath().replace(/\\/g,'/')+'"></base>\n';
		if (!HTMLOnly) {
			var styles=document.getElementsByTagName('style');
			var fmt='<style>\n/* stylesheet=%0 */\n%1\n\n</style>\n';
			for(var i=0; i < styles.length; i++)
				out+=fmt.format([styles[i].getAttribute('id'),styles[i].innerHTML]);
		}
		out+='</head>\n';

		var elems=snapElem.getElementsByTagName('input');
		for (var i=0; i<elems.length; i++) { var e=elems[i];
			if (e.type=='text')		e.defaultValue=e.value;
			if (e.type=='checkbox')	 	e.defaultChecked=e.checked;
			if (e.type=='radiobutton')	e.defaultChecked=e.checked;
		}
		var elems=snapElem.getElementsByTagName('textarea');
		for (var i=0; i<elems.length; i++)	elems[i].defaultValue=elems[i].value;

		var fmt='<body>\n\n<div class="snapshot %0">%1</div>\n\n</body>\n';
		out+=fmt.format([(id==cms.viewerID?'tiddler viewer':''),snapElem.innerHTML]);

		return '<html>\n'+out+'</html>';
	},
	printsnap: function(out) {
		var win=window.open("","_blank","");
		win.document.open();
		win.document.writeln(out);
		win.document.close();
		win.focus(); // bring to front
		win.print(); // trigger print dialog
	},
	savesnap: function(out,target) {
		var cms=config.macros.snapshot; // abbreviation
		// make sure we are local
		if (window.location.protocol!="file:")
			{ alert(config.messages.notFileUrlError); return; }
		var target=target||cms.askForFilename(cms.fileMsg,cms.getpath(),cms.defaultFilename);
		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) {
			var h=document.location.href;
			var cwd=getLocalPath(decodeURIComponent(h.substr(0,h.lastIndexOf('/')+1)));
			target=cwd+target;
		}
		var link="file:///"+target.replace(/\\/g,'/'); // link for message text
		var ok=saveFile(target,convertUnicodeToUTF8(out));
		var msg=ok?cms.okmsg.format([target]):cms.failmsg.format([target]);
		displayMessage(msg,link);
	},
	askForFilename: function(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.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=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;
	}
};
//}}}

// // TOOLBAR DEFINITIONS
//{{{
config.commands.snapshotSave = {
	text: "snap",
	tooltip: config.macros.snapshot.snapPrompt,
	handler: function(ev,src,title) {
		src.setAttribute("snapID","ask");
		src.setAttribute("printing","false");
		src.setAttribute("HTMLOnly",config.options.chkSnapshotHTMLOnly?"true":"false");
		config.macros.snapshot.go(src,ev);
		return false;
	}
};
config.commands.snapshotSaveViewer = {
	text: "snap",
	tooltip: config.macros.snapshot.snapPrompt,
	handler: function(ev,src,title) {
		src.setAttribute("snapID","viewer");
		src.setAttribute("printing","false");
		src.setAttribute("HTMLOnly",config.options.chkSnapshotHTMLOnly?"true":"false");
		config.macros.snapshot.go(src,ev);
		return false;
	}
};
config.commands.snapshotPrint = {
	text: "print",
	tooltip: config.macros.snapshot.printPrompt,
	handler: function(ev,src,title) {
		src.setAttribute("snapID","ask");
		src.setAttribute("printing","true");
		src.setAttribute("HTMLOnly",config.options.chkSnapshotHTMLOnly?"true":"false");
		config.macros.snapshot.go(src,ev);
		return false;
	}
};
config.commands.snapshotPrintViewer = {
	text: "print",
	tooltip: config.macros.snapshot.printPrompt,
	handler: function(ev,src,title) {
		src.setAttribute("snapID","viewer");
		src.setAttribute("printing","true");
		src.setAttribute("HTMLOnly",config.options.chkSnapshotHTMLOnly?"true":"false");
		config.macros.snapshot.go(src,ev);
		return false;
	}
};
//}}}

// // COPIED FROM [[StickyPopupPlugin]] TO ELIMINATE PLUGIN DEPENDENCY
//{{{
if (config.options.chkStickyPopups==undefined) config.options.chkStickyPopups=false;
Popup.stickyPopup_onDocumentClick = function(ev)
{
	// if click is in a sticky popup, ignore it so popup will remain visible
	var e = ev ? ev : window.event; var target = resolveTarget(e);
	var p=target; while (p) {
		if (hasClass(p,"popup") && (hasClass(p,"sticky")||config.options.chkStickyPopups)) break;
		else p=p.parentNode;
	}
	if (!p) // not in sticky popup (or sticky popups disabled)... use normal click handling
		Popup.onDocumentClick(ev);
	return true;
};
try{removeEvent(document,"click",Popup.onDocumentClick);}catch(e){};
try{addEvent(document,"click",Popup.stickyPopup_onDocumentClick);}catch(e){};
//}}}
/***
|Name|SnapshotPluginInfo|
|Source|http://www.TiddlyTools.com/#SnapshotPlugin|
|Documentation|http://www.TiddlyTools.com/#SnapshotPluginInfo|
|Version|1.4.2|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|documentation|
|Description|Documentation for SnapshotPlugin|
This plugin provides a macro as well as tiddler toolbar commands that creates a file or opens a new browser window containing the //rendered// HTML and CSS style definitions that are being displayed for selected elements of the current document.
!!!!!Usage:
<<<
As a macro embedded in tiddler content:
{{{
<<snapshot print label:text prompt:text id:elementID|here|viewer|story|all|ask>
}}}
where:
*''print'' //(optional)//<br>when present, causes the snapshot output to be directed to a new browser tab/window instead of saving it to a file.  In addition, the print dialog for that tab/window is automatically invoked.
*''label'' //(optional)//<br>is the text to be displayed for the command link generated by the macro
*''prompt'' //(optional)//<br>is the 'tool tip' message displayed when you mouseover the command link
*''id:...'' //(optional)//<br>specifies the document element to be captured, and can be one of:
**''elementID''<br>is a specific DOM element ID, such as "displayArea", "mainMenu", "contentWrapper", etc.
**''here''<br>the containing tiddler in which the macro (or toolbar command) occurs, including the tiddler title and subtitle (date/time/author) information.
**''viewer''<br>same as ''here'', but omits the tiddler title, subtitle and toolbar elements (i.e., it includes //only// the content of the tiddler)
**''story''<br>selects all currently displayed tiddlers (i.e., the 'story column')
**''all''<br>selects the entire document contents, including page header, main menu and sidebar displays
**''ask''<br>when the snapshot command link is clicked, a droplist is displayed so you can choose from several pre-defined elements: "current tiddler", "story column", or "entire document", or "DOM element ID..."  When DOM element ID is chosen, the droplist is refreshed to show the individual ID's for all currently rendered DOM elements (at least, the ones that have ID's).  For any given DOM element ID, only the portions of the document that are contained //within// the specified DOM element will be transcribed to the resulting snapshot or print output.  
//''NOTE: when no parameters are specified, the macro creates a snapshot file using the containing tiddler as the default element.'' (e.g., equivalent to {{{<<snapshot id:here>>}}}//

The snapshot/print functions can also be embedded as tiddler toolbar commands in [[ViewTemplate]]:
{{{
<span class='toolbar' macro='toolbar snapshotSave'></span>
<span class='toolbar' macro='toolbar snapshotSaveViewer'></span>
<span class='toolbar' macro='toolbar snapshotPrint'></span>
<span class='toolbar' macro='toolbar snapshotPrintViewer'></span>
}}}
* By default, the toolbar commands use the "id:ask" option to display a droplist of elements to select from.  The "...Viewer" form of each command bypasses the droplist and automatically selects the current tiddler viewer area for saving/printing.

Please note that, although the snapshot/print that is created using the HTML+CSS of the displayed content, ''there is NO javascript code'' written into the snapshot.  As a result, the snapshot only ''reproduces the //appearance// of the displayed content, allowing you to //view// or //print// the result'', but does not permit you to interact with it in other ways.

For example, even simple processing (such as mouseover highlighting) will not function from the snapshot.  You can't click a TiddlyLink to open other tiddlers, because A) there is no code that handles the click and B) there is no underlying 'storeArea' (and core code) to retrieve and render anything!  You also can't use ANY command links, since these also require javascript code (and the core) to operate. 

__''Custom CSS for printing''__
There can be differences in the appearance of snapshot output when rendered on different devices (e.g. screen vs. printer).  Although these differences are typically very minor, it is sometimes necessary to define alternative CSS styles to account for the differences in device characteristics, such as font metrics, page sizes, resolutions, etc.  You can use the {{{@@media}}} wrapper within your custom StyleSheet CSS to define printer-specific formatting:
{{{
@media print {
...
}
}}}
The plugin places the snapshot output within a custom CSS class wrapper, using the classname, "{{{.snapshot}}}".  This enables you to define and apply custom formatting rules to 'fine tune' the appearance of the snapshot output, regardless of the intended output device.  For example, the following rule will override and hide tiddler borders and background colors when displaying and/or printing snapshots.
{{{
.snapshot .viewer { border:0 !important; background-color:none !important; }
}}}
<<<
!!!!!Examples:
<<<
{{{<<snapshot>>}}}: <<snapshot>>
{{{<<snapshot id:mainMenu>>}}}: <<snapshot id:mainMenu>>
{{{<<snapshot print id:story>>}}}: <<snapshot print id:story>>
{{{<<snapshot print id:ask>>}}}: <<snapshot print id:ask>>
{{{<<snapshot print noCSS id:viewer>>}}}: <<snapshot print noCSS id:viewer>>
<<<
!!!!!Configuration
<<<
<<option chkSnapshotHTMLOnly>> output HTML only (omit CSS)
<<<
!!!!!Revisions
<<<
2011.01.03 1.4.2 added snapshotSaveViewer toolbar command
2010.12.15 1.4.1 added 'snapshot' class to wrapper
2010.11.20 1.4.0 added snapshotPrintViewer toolbar command
2009.10.12 1.3.0 added multi-file story snapshot
2009.09.25 1.2.1 in getSnap(), added META tag to set UTF-8 encoding for I18N support
2009.06.04 1.2.0 added handling in getSnap() so current form input values are shown in snapshots
2008.05.16 1.1.1 added try..catch around addEvent/removeEvent calls to avoid error in Opera
2008.04.28 1.1.0 removed 'viewerHTML' from 'ask' droplist and replaced with toggle for "output HTML only".  Removed 'noCSS' parameter and replaced with config.options.chkSnapshotHTMLOnly global option.  Added "select a tiddler..." to 'ask' droplist
2008.04.24 1.0.1 in saveSnap(), convert output from Unicode to UTF before passing to saveFile().  Fixes "unknown name" error in IE's file.Write() function.
2008.04.21 1.0.0 initial release - derived from [[NewDocumentPlugin]] with many improvements, including: "ask for ID" using droplist of available DOM elements, use "<base href=...>" for correctly resolving image references, wrap 'viewer only' output in class="tiddler viewer" for proper application of inherited CSS styles, snapshotSave and snapshotPrint tiddler toolbar command definitions, and more...

__Excerpted revisions from [[NewDocumentPlugin]] (obsolete)__
2008.04.20 1.8.0 added support for 'noCSS' and 'viewer' params for alternative snapshot output
2007.03.30 1.7.0 added support for "print" param as alternative for "snap".  When "print" is used, the filename is ignored and ouput is directed to another browser tab/window, where the print dialog is then automatically triggered.
2007.03.30 1.6.1 added support for "here" keyword for current tiddler elementID and "prompt:text" param for specifying tooltip text
2006.10.18 1.5.0 new optional param for 'snap'... specify alternative DOM element ID (default is still "contentWrapper").  Based on a suggestion from Xavier Verges.
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.03 1.0.0 Created.
<<<
/***

''Inspired by [[TiddlyPom|http://www.warwick.ac.uk/~tuspam/tiddlypom.html]]''

|Name|SplashScreenPlugin|
|Created by|SaqImtiaz|
|Location|http://tw.lewcid.org/#SplashScreenPlugin|
|Version|0.21 |
|Requires|~TW2.08+|
!Description:
Provides a simple splash screen that is visible while the TW is loading.

!Installation
Copy the source text of this tiddler to your TW in a new tiddler, tag it with systemConfig and save and reload. The SplashScreen will now be installed and will be visible the next time you reload your TW.

!Customizing
Once the SplashScreen has been installed and you have reloaded your TW, the splash screen html will be present in the MarkupPreHead tiddler. You can edit it and customize to your needs.

!History
* 20-07-06 : version 0.21, modified to hide contentWrapper while SplashScreen is displayed.
* 26-06-06 : version 0.2, first release

!Code
***/
//{{{
window.old_lewcid_splash_restart=window.restart;

window.restart = function()
{   if (document.getElementById("SplashScreen"))
        document.getElementById("SplashScreen").style.display = "none";
      if (document.getElementById("contentWrapper"))
        document.getElementById("contentWrapper").style.display = "block";
    
    window.old_lewcid_splash_restart();
   
    if (splashScreenInstall)
       {if(config.options.chkAutoSave)
			{saveChanges();}
        displayMessage("TW SplashScreen has been installed, please save and refresh your TW.");
        }
}


var oldText = store.getTiddlerText("MarkupPreHead");
if (oldText.indexOf("SplashScreen")==-1)
   {var siteTitle = store.getTiddlerText("SiteTitle");
   var splasher='\n\n<style type="text/css">#contentWrapper {display:none;}</style><div id="SplashScreen" style="border: 3px solid #ccc; display: block; text-align: center; width: 320px; margin: 100px auto; padding: 50px; color:#000; font-size: 28px; font-family:Tahoma; background-color:#eee;"><b>'+siteTitle +'</b> is loading<blink> ...</blink><br><br><span style="font-size: 14px; color:red;">Requires Javascript.</span></div>';
   if (! store.tiddlerExists("MarkupPreHead"))
       {var myTiddler = store.createTiddler("MarkupPreHead");}
   else
      {var myTiddler = store.getTiddler("MarkupPreHead");}
      myTiddler.set(myTiddler.title,oldText+splasher,config.options.txtUserName,null,null);
      store.setDirty(true);
      var splashScreenInstall = true;
}
//}}}
/%
|Name|SplitTiddler|
|Source|http://www.TiddlyTools.com/#SplitTiddler|
|Version|1.9.5|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|html|
|Description|split tiddler contents into separate tiddlers|

%/<html><nowiki><style>
#tiddlerSplitTiddler .tagged { display:none; }
#tiddlerSplitTiddler .label { font-size:90%;font-style:italic;white-space:nowrap; }
#tiddlerSplitTiddler table, #tiddlerSplitTiddler tr, #tiddlerSplitTiddler td
	{ border:0; margin:0; padding:0; }
</style><table><tr><td><form>
<table style='width:100%'><tr><td style='width:20%'>
	<div class='label'>source tiddler:</div>
	<select name='src' value='' style='width:99%;padding:2px;margin:0'
		title='select a tiddler containing source material'>
	<option value=''>select a tiddler...</option>
	</select>
</td><td style='width:20%'>
	<div class='label'>target title format:</div>
	<input name='titleformat' value='%0 - %1' style='width:99%'
		title='format for target tiddler titles'>
</td><td style='width:20%'>
	<div class='label'>output format:</div>
	<input name='format' value='%4' style='width:99%'
		title='format for target tiddler content'>
</td><td style='width:20%'>
	<div class='label'>target field:</div>
	<input name='fieldname' value='text' style='width:99%'
		title='field to hold content in target tiddler'>
</td><td style='width:20%'>
	<div class='label'>add tags:</div>
	<input name='tags' value='' style='width:99%'
		title='tags for target tiddlers'>
</td></tr></table>
<div style='font-size:80%;font-style:italic;text-align:center;color:gray'>
%0=source title, %1=first line of item, %2=first word of item, %3=item number, %4=item content
</div>
<div style='float:left;margin-right:1em'>
<div class='label'>split source content by:</div>
<div style='line-height:2.1em'>
<input type='radio' name='splitby' value='charcount'>every
<input name='charcount' value='1000' onfocus='this.select()' style='width:3em'
	title='split content every N characters'> characters<br>
<input type='radio' name='splitby' value='linecount'>every
<input name='linecount' value='20' onfocus='this.select()' style='width:3em'
	title='split content every N lines'> lines<br>
<input type='radio' name='splitby' value='match' CHECKED>match
<input name='sep' value='\n----\n' onfocus='this.select()' style='width:8em'
	title='match character sequence to split content'><br>
&nbsp; <input type='checkbox' name='regexp' title='match using regular expressions (text patterns)'>use RegExp text pattern<br>
</div></div>
<div style='float:left;margin-right:1em'>
<div class='label'>options:</div>
<input type='checkbox' name='warn' checked>confirm overwrites<br>
<input type='checkbox' name='show'>show tiddlers when done<br>
<input type='checkbox' name='limit'>create only
<input name='maxtids' value='8' style='width:2em'> tiddlers<br>
<input type='checkbox' name='index' checked>create an index tiddler<br>
&nbsp;&nbsp; index item format:
<input name='indexformat' value='<<tiddler [[%0 - %1]]>>' style='width:10em'
	title='%0=target tiddler title'>
</div>
<input type='button' style='float:right;height:5em;margin-top:2.5em' value='split tiddler' onclick="
	var f=this.form;
	if (!f.src.value.length)
		{ alert('select a tiddler title'); f.src.focus(); return false; }
	if (!f.titleformat.value.length)
		{ alert('enter a target title format'); f.titleformat.focus(); return false; }
	if (!f.src.value.length)
		{ alert('enter an output item format'); f.format.focus(); return false; }
	var start=new Date().getTime();
	var src=store.getTiddlerText(f.src.value);
	if (!src) { displayMessage('\x27'+f.src.value+'\x27 not found'); return false; }
	var tags=f.tags.value;
	var parts=[];
	if (f.splitby[0].checked) { /* chars */
		for (var i=0; i<src.length; i+=f.charcount.value)
			parts.push(src.substr(i,f.charcount.value));
	} else if (f.splitby[1].checked) { /* lines */
		var lines=src.split('\n');
		var t=''; var c=f.linecount.value;
		while (lines.length) {
			t+=lines.shift()+'\n'; c--;
			if (!c) { parts.push(t); var c=f.linecount.value; t=''; }
		}
	} else { /* match text/regexp */
		var sep=!f.regexp.checked?f.sep.value.unescapeLineBreaks():new RegExp(f.sep.value);
		var pieces=src.split(sep);
		for (var i=0; i<pieces.length; i++) if (pieces[i].length) parts.push(pieces[i]);
	}
	var msg='Found '+parts.length+' items in \x27'+f.src.value+'\x27. OK to proceed?';
	if (!confirm(msg)) return false;
	if (parts.length) store.suspendNotifications();
	var pad=parts.length.toString().length;
	var tids=[]; var out=[];
	var srctitle=f.src.value;
	var fmt=f.format.value.unescapeLineBreaks();
	var titlefmt=f.titleformat.value.unescapeLineBreaks();
	var fieldname=f.fieldname.value.toLowerCase();
	var indexfmt=f.indexformat.value.unescapeLineBreaks();
	var max=f.limit.checked?f.maxtids.value:parts.length;
	var warn=f.warn.checked;
	for (var p=0; p<max; p++) {
		var lines=parts[p].split('\n');
		var firstline=lines[0];
		var firstword=firstline.split(' ')[0];
		var itemnum=String.zeroPad(p+1,pad);
		if (titlefmt.indexOf('%2')!=-1) /* remove firstword if used in title */
			{ var words=lines[0].split(' '); words.shift(); lines[0]=words.join(' '); var discard=!words.length; }
		if (titlefmt.indexOf('%1')!=-1 || discard) /* remove firstline if used in title */
			lines.shift();
		var content=lines.join('\n');
		var args=[srctitle,firstline,firstword,itemnum,content];
		var tid=titlefmt.format(args).replace(/[\[\]\|]/g,'_');
		var txt=fmt.format(args);
		var fields={}; if (fieldname!='text')
			{ fields[fieldname]=txt; txt='<<view '+fieldname+' wikified>>'; }
		var tags=tags.format(args);
		if (warn && store.tiddlerExists(tid) && !confirm(config.messages.overwriteWarning.format([tid])))
			continue;
		store.saveTiddler(tid,tid,txt,config.options.txtUserName,new Date(),tags,fields);
		if (f.index.checked) out.push(indexfmt.format(args));
		tids.pushUnique(tid);
	}
	var elapsed=(new Date().getTime()-start)/1000;
	if (parts.length) store.resumeNotifications();
	if (tids.length) {
		if (f.index.checked) {
			var tid=f.src.value+'Index';
			if (!warn||!store.tiddlerExists(tid)||confirm(config.messages.overwriteWarning.format([tid])))
				store.saveTiddler(tid,tid,out.join('\n'),config.options.txtUserName,new Date(),[],{});
		}
		store.notifyAll();
		if (f.show.checked) story.displayTiddlers(story.findContainingTiddler(this),tids);
		displayMessage('created '+tids.length+' target tiddlers in '+elapsed+' seconds');
	}
"><div style='clear:both'></div>
</form></td></tr></table></html><<tiddler {{
	var list=place.lastChild.getElementsByTagName('form')[0].src;
	store.forEachTiddler(function(title,tiddler){
		list.options[list.length]=new Option(title,title);
	});
'';}}>>
/***
|Name|StickyPopupPlugin|
|Source|http://www.TiddlyTools.com/#StickyPopupPlugin|
|Version|1.0.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|allow mouse interactions inside popups without automatically closing them|
Usually, when a TW popup is displayed, it is automatically closed whenever a click occurs //anywhere// in the document, either //inside// or //outside// the popup itself.  This plugin makes popups persistent (a.k.a, "sticky"), allowing you to perform multiple mouse interactions on content //inside// the popup (e.g., entering form fields, opening links, selecting text, etc.), remaining visible until you click //outside// the popup or perform an action that opens another popup (only one popup can be displayed at any given time).
!!!!!Configuration
<<<
You can cause popups to behave in a persistent ("sticky") manner simply by selecting the option checkbox below.  The selected popup display behavior will be applied to ALL popups in the document automatically.
><<option chkStickyPopups>> make all popups "sticky"
>{{{usage: <<option chkStickyPopups>>}}}
<<<
!!!!!Usage
<<<
If you are developing your own plugins or inline scripts that create popups programmatically using the core function:
{{{
Popup.create(this)
}}}
you can provide additional parameters that specify the desired CSS classname(s) to assign to the popup DOM element.  The default class when none is specified is simply "popup".  To create a //sticky// popup, simply enter a custom class combination like this:
{{{
Popup.create(this,null,"sticky popup")
}}}
<<<
!!!!!Revisions
<<<
2008.05.16 [1.0.1] added try..catch around addEvent/removeEvent calls to avoid error in Opera
2007.11.25 [1.0.0] initial release - moved from [[CoreTweaks]]
<<<
!!!!!Code
***/
//{{{
version.extensions.StickyPopupPlugin= {major: 1, minor: 0, revision: 1, date: new Date(2008,5,16)};

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

Popup.stickyPopup_onDocumentClick = function(ev)
{
	// if click is in a sticky popup, ignore it so popup will remain visible
	var e = ev ? ev : window.event; var target = resolveTarget(e);
	var p=target; while (p) {
		if (hasClass(p,"popup") && (hasClass(p,"sticky")||config.options.chkStickyPopups)) break;
		else p=p.parentNode;
	}
	if (!p) // not in sticky popup (or sticky popups disabled)... use normal click handling
		Popup.onDocumentClick(ev);
	return true;
};
try{removeEvent(document,"click",Popup.onDocumentClick);}catch(e){};
try{addEvent(document,"click",Popup.stickyPopup_onDocumentClick);}catch(e){};
//}}}
<<tiddler {{
	place.onmouseover = function(e){ addClass(this,"selected"); }
	place.onmouseout = function(e){ removeClass(this,"selected"); }
'';}}>>/%
%/{{center{
{{mouseover{{{floatleft{<<tiddler ToggleLeftSidebar>>}}}{{floatright{<<tiddler ToggleRightSidebar>>}}}}}}{{smallform fine{<<unsavedChanges panel>>}}}
}}}
/***
|Name|StorySaverPlugin|
|Source|http://www.TiddlyTools.com/#StorySaverPlugin|
|Documentation|http://www.TiddlyTools.com/#StorySaverPluginInfo|
|Version|1.8.3|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Requires|MarkupPostBody|
|Description|save/restore current tiddler view between browser sessions|
Automatically save a list of currently viewed tiddlers (the 'story') in a local cookie, {{{txtSavedStory}}} and then open those tiddlers when the document is reloaded, so you can resume working from the same place you left off!!  Also, use {{{<<saveStory>>}}} and {{{<<openStory>>}}} macros to quickly save/re-display stories stored in tiddlers, using a command link, droplist, or popup display.
!!!!!Documentation
>see [[StorySaverPluginInfo]]
!!!!!Configuration
<<<
<<option chkSaveStory>> use automatic story cookie (reopens tiddlers on startup)
<<option chkStoryAllowAdd>>include 'add a story' command in droplist/popup
<<option chkStoryFold>>fold story tiddlers when opening a story (see [[CollapseTiddlersPlugin]])
<<option chkStoryClose>>close other tiddlers when opening a story
<<option chkStoryTop>>open story tiddlers at top of column
<<option chkStoryBottom>>open story tiddlers at bottom of column
<<<
!!!!!Revisions
<<<
2009.10.20 1.8.3 fix handling for 'add' item in popup menu
|please see [[StorySaverPluginInfo]] for additional revision details|
2007.10.05 1.0.0 initial release. Moved [[SetDefaultTiddlers]] inline script and rewrote as a {{{<<saveStory>>}}} macro.
<<<
!!!!!Code
***/
//{{{
version.extensions.StorySaverPlugin= {major: 1, minor: 8, revision: 3, date: new Date(2009,10,20)};

var defaults={
	chkSaveStory:		false,
	chkStoryFold:		true,
	chkStoryClose:		true,
	chkStoryAllowAdd:	true,
	chkStoryTop:		true,
	chkStoryBottom:		false
};
for (var id in defaults) if (config.options[id]===undefined)
	config.options[id]=defaults[id];

// 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=/;'; 
	}
}

// save or clear story cookie on exit
if (window.coreTweaks_confirmExit==undefined) {
	window.coreTweaks_confirmExit=window.confirmExit;
	window.confirmExit=function() {
		if (config.options.chkSaveStory) { // save cookie
			var links=[];
			story.forEachTiddler(function(title,element){links.push('[['+title+']]');});
			config.options.txtSavedStory=links.join(' ');
			saveOptionCookie('txtSavedStory');
		} else removeCookie('txtSavedStory');
		return window.coreTweaks_confirmExit.apply(this,arguments);
	}
}
//}}}
/***
''apply saved story on startup:'' //important note: the following code is actually located in [[MarkupPostBody]].  This is because it needs to supercede the core's getParameters() function, which is called BEFORE plugins are loaded, preventing the normal plugin-based hijack method from working, while code loaded into [[MarkupPostBody]] will be processed as soon as the document is read, even before the TW main() function is invoked.//
<<tiddler MarkupPostBody>>
***/
//{{{
config.macros.saveStory = {
	label: 'set default tiddlers',
	defaultTiddler: 'DefaultTiddlers',
	prompt: 'store a list of currently displayed tiddlers in another tiddler',
	askMsg: 'Enter the name of a tiddler in which to save the current story:',
	tag: 'story',
	excludeTag: 'excludeStory',
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		var tid=params.shift()||'DefaultTiddlers';
		var label=params.shift()||this.label;
		var tip=params.shift()||this.prompt;
		var btn=createTiddlyButton(place,label,tip,this.setTiddler,'button');
		btn.setAttribute('tid',tid);
		btn.setAttribute('extratags','[['+params.join(']] [[')+']]');
	},
	setTiddler: function() {
		var cms=config.macros.saveStory; // abbrev
		// get list of current open tiddlers
		var tids=[];
		story.forEachTiddler(function(title,element){
			var t=store.getTiddler(title);
			if (!t || !t.isTagged(cms.excludeTag)) tids.push('[['+title+']]');
		});
		// get target tiddler
		var tid=this.getAttribute('tid');
		if (!tid || tid=='ask') {
			tid=prompt(cms.askMsg,cms.defaultTiddler);
			if (!tid || !tid.length) return false; // cancelled by user
		}
		if(store.tiddlerExists(tid) && !confirm(config.messages.overwriteWarning.format([tid])))
			return false;
		tids=tids.join('\n');
		var t=store.getTiddler(tid); var tags=t?t.tags:[];
		var extratags=(this.getAttribute('extratags')||'').readBracketedList();
		for (var i=0; i<extratags.length; i++) tags.pushUnique(extratags[i]);
		tags.pushUnique(cms.tag);
		store.saveTiddler(tid,tid,tids,config.options.txtUserName,new Date(),tags,t?t.fields:null);
		story.displayTiddler(null,tid);
		story.refreshTiddler(tid,null,true);
		displayMessage(tid+' has been '+(t?'updated':'created'));
		return false;
	}
}
//}}}
//{{{
config.macros.openStory = {
	label: 'open story: %0',
	prompt: 'open the set of tiddlers listed in: %0',
	popuplabel: 'stories',
	popupprompt: 'view a set of tiddlers',
	tag: 'story',
	selectprompt: 'select a story...',
	optionsprompt: 'viewing options...',
	foldcmd: '[%0] fold story',
	foldprompt: 'fold story tiddlers when opening a story',
	closecmd: '[%0] close others',
	closeprompt: 'close other tiddlers when opening a story',
	topcmd: '[%0] open at top',
	topprompt: 'open story tiddlers at top of column',
	bottomcmd: '[%0] open at bottom',
	bottomprompt: 'open story tiddlers at bottom of column',
	addcmd: 'add a story...',
	addprompt: 'create a new story',
	excludeTag: 'excludeStory',
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		if (params[0].toLowerCase()=='list') return this.createList(place,params);
		else if (params[0].toLowerCase()=='popup') return this.createPopup(place,params);
		else this.createButton(place,params);
	},
	showStory: function(tid,fold) {
		var co=config.options; // abbrev
		var tids=[];
		var t=store.getTiddler(tid);
		var tagged=store.getTaggedTiddlers(tid,'title');
		if (tagged.length) // if tiddler IS a tag, use tagged tiddlers as story
			for (var i=0; i<tagged.length; i++) tids.push(tagged[i].title);
		else if (t) { // get tiddler list from content
			if (!t.linksUpdated) t.changed();
			for (var i=0; i<t.links.length; i++) {
				var tid=store.getTiddler(t.links[i]);
				if (tid && !tid.isTagged(this.excludeTag))
					tids.push(t.links[i]);
			}
		}
		var template=null;
		if (fold||co.chkStoryFold) template='CollapsedTemplate'; // see [[CollapseTiddlersPlugin]]
		if (!store.tiddlerExists('CollapsedTemplate')) template=null;
		if (co.chkStoryClose) story.closeAllTiddlers();
		var pos='top'; var first=tids[0];
		if (!story.isEmpty() && co.chkStoryBottom) { pos='bottom'; tids=tids.reverse(); }
		story.displayTiddlers(pos,tids,template);
		var cmd='var t=story.getTiddler("'+first+'");if(t)window.scrollTo(0,t.offsetTop);';
		var delay=config.options.chkAnimate?config.animDuration+100:0;
		setTimeout(cmd,delay);
	},
	createButton: function(place,params) {
		var tid=params[0]||'';
		var label=params[1]||this.label; label=label.format([tid]);
		var tip=params[2]||this.prompt; tip=tip.format([tid]);
		var fold=(params[3]&&(params[3].toLowerCase()=='fold'))||config.options.chkStoryFold;
		var fn=function(){config.macros.openStory.showStory(this.getAttribute('tid'),this.getAttribute('fold')); return false; };
		var btn=createTiddlyButton(place,label,tip,fn,'button');
		btn.setAttribute('tid',tid);
		if (fold) btn.setAttribute('fold',fold);
	},
	createPopup: function(place,params) {
		params.shift(); // discard 'popup' keyword
		var label=params.shift()||this.popuplabel;
		var tip=params.shift()||this.popupprompt;
		var btn=createTiddlyButton(place,label,tip,this.showPopup,'button');
		btn.setAttribute('filter',params.shift()||config.macros.openStory.tag);
	},
	showPopup: function(ev) { var e=ev||window.event;
		var co=config.options; // abbrev
		var cmo=config.macros.openStory; // abbrev
		var indent='\xa0\xa0';
		var p=Popup.create(this); if (!p) return false;
		createTiddlyText(createTiddlyElement(p,'li'),cmo.selectprompt);
		var stories=store.filterTiddlers('[tag['+this.getAttribute('filter')+']]');
		for (var s=0; s<stories.length; s++) {
			var label=indent+stories[s].title;
			var tip=cmo.prompt.format([stories[s].title]);
			var fn=function(){config.macros.openStory.showStory(this.getAttribute('tid'));return false;};
			var btn=createTiddlyButton(createTiddlyElement(p,'li'),label,tip,fn,'button');
			btn.setAttribute('tid',stories[s].title);
		}
		createTiddlyText(createTiddlyElement(p,'li'),cmo.optionsprompt);
		if (store.tiddlerExists('CollapsedTemplate')) {
			var label=indent+cmo.foldcmd.format([co.chkStoryFold?'x':'\xa0\xa0']);
			var tip=cmo.foldprompt;
			var fn=function(){ config.macros.option.propagateOption(
				'chkStoryFold','checked',!config.options.chkStoryFold,'input'); return false; };
			var btn=createTiddlyButton(createTiddlyElement(p,'li'),label,tip,fn,'button');
		}
		var label=indent+cmo.closecmd.format([co.chkStoryClose?'x':'\xa0\xa0']);
		var tip=indent+cmo.closeprompt;
		var fn=function(){ config.macros.option.propagateOption(
			'chkStoryClose','checked',!config.options.chkStoryClose,'input'); return false; };
		var btn=createTiddlyButton(createTiddlyElement(p,'li'),label,tip,fn,'button');
		if (!co.chkStoryClose) {
			var label=indent+cmo.topcmd.format([co.chkStoryTop?'x':'\xa0\xa0']);
			var tip=indent+cmo.topprompt;
			var fn=function(){
				config.macros.option.propagateOption(
					'chkStoryTop','checked',!config.options.chkStoryTop,'input');
				config.macros.option.propagateOption(
					'chkStoryBottom','checked',!config.options.chkStoryTop,'input');
				return false;
			};
			var btn=createTiddlyButton(createTiddlyElement(p,'li'),label,tip,fn,'button');
			var label=indent+cmo.bottomcmd.format([co.chkStoryBottom?'x':'\xa0\xa0']);
			var tip=indent+cmo.botprompt;
			var fn=function(){
				config.macros.option.propagateOption(
					'chkStoryBottom','checked',!config.options.chkStoryBottom,'input');
				config.macros.option.propagateOption(
					'chkStoryTop','checked',!config.options.chkStoryBottom,'input');
				return false;
			};
			var btn=createTiddlyButton(createTiddlyElement(p,'li'),label,tip,fn,'button');
		}
		if (!readOnly && co.chkStoryAllowAdd) {
			var label=cmo.addcmd;
			var tip=cmo.addprompt;
			var fn=config.macros.saveStory.setTiddler;
			createTiddlyElement(createTiddlyElement(p,'li'),'hr');
			var btn=createTiddlyButton(createTiddlyElement(p,'li'),label,tip,fn,'button');
		}
		Popup.show();
		e.cancelBubble=true;if(e.stopPropagation)e.stopPropagation();
		return false;
	},
	createList: function(place,params) {
		var cmo=config.macros.openStory; // abbrev
		var s=createTiddlyElement(place,'select',null,'storyListbox');
		s.size=1;
		s.onchange=function() {
			if (this.value=='_fold') {
				config.macros.option.propagateOption('chkStoryFold','checked',
					!config.options.chkStoryFold,'input');
				cmo.refreshList();
			} else if (this.value=='_close') {
				config.macros.option.propagateOption('chkStoryClose','checked',
					!config.options.chkStoryClose,'input');
				cmo.refreshList();
			} else if (this.value=='_top') {
				config.macros.option.propagateOption('chkStoryTop','checked',
					!config.options.chkStoryTop,'input');
				cmo.refreshList();
			} else if (this.value=='_bottom') {
				config.macros.option.propagateOption('chkStoryBottom','checked',
					!config.options.chkStoryBottom,'input');
				cmo.refreshList();
			} else if (this.value=='_add')
				config.macros.saveStory.setTiddler.apply(this,arguments);
			else cmo.showStory(this.value);
		}
		params.shift(); // discard 'list' keyword
		s.setAttribute('filter',params.shift()||cmo.tag);
		setStylesheet('.storyListbox { width:100%; }', 'StorySaverStyles');
		store.addNotification(null,this.refreshList); this.refreshList();
		return;
	},
	refreshList: function() {
		var cmo=config.macros.openStory; // abbrev
		var indent='\xa0\xa0\xa0\xa0';
		var lists=document.getElementsByTagName('select');
		for (var i=0; i<lists.length; i++) { if (lists[i].className!='storyListbox') continue;
			var here=lists[i];
			var stories=store.filterTiddlers('[tag['+here.getAttribute('filter')+']]');
			while (here.length) here.options[0]=null; // remove current list items
			here.options[here.length]=new Option(cmo.selectprompt,'',true,true);
			for (var s=0; s<stories.length; s++)
				here.options[here.length]=new Option(indent+stories[s].title,stories[s].title);
			if (!readOnly && config.options.chkStoryAllowAdd)
				here.options[here.length]=new Option(cmo.addcmd,'_add');
			here.options[here.length]=new Option(cmo.optionsprompt,'');
			if (store.tiddlerExists('CollapsedTemplate')) {
				var msg=cmo.foldcmd.format([config.options.chkStoryFold?'x':'\xa0\xa0']);
				here.options[here.length]=new Option(indent+msg,'_fold');
			}
			var msg=cmo.closecmd.format([config.options.chkStoryClose?'x':'\xa0\xa0']);
			here.options[here.length]=new Option(indent+msg,'_close',false,false);
			if (!config.options.chkStoryClose) {
				var msg=cmo.topcmd.format([config.options.chkStoryTop?'x':'\xa0\xa0']);
				here.options[here.length]=new Option(indent+msg,'_top',false,false);
				var msg=cmo.bottomcmd.format([config.options.chkStoryBottom?'x':'\xa0\xa0']);
				here.options[here.length]=new Option(indent+msg,'_bottom',false,false);
			}
		}
	}
}
//}}}
/***
|Name|StorySaverPlugin|
|Source|http://www.TiddlyTools.com/#StorySaverPlugin|
|Documentation|http://www.TiddlyTools.com/#StorySaverPluginInfo|
|Version|1.8.3|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|documentation|
|Requires|MarkupPostBody|
|Description|documentation for [[StorySaverPlugin]]|
Automatically saves a list of currently viewed tiddlers (the "story") in a local cookie, {{{txtSavedStory}}} and then opens those tiddlers when the document is subsequently reloaded, allowing you to quickly resume working with the document from the same place you left off!! The plugin also defines {{{<<saveStory>>}}} and {{{<<openStory>>}}} macros that allow you to quickly save/re-display stories stored in tiddlers, using simple, one-click command links or droplists.
!!!!!Usage
<<<
If a document URL does not contain a paramifier (i.e., a "#..." suffix), then the saved story cookie (if any) will be used //as if// it had been entered as a permaview (e.g., a "#tiddler tiddler tiddler..." suffix on the URL), bypassing the [[DefaultTiddlers]] definition.  This behavior is automatically applied whenever the plugin is installed in your document.  You can enable/disable the automatic cookie-based StorySaver feature by using the checkbox below:
><<option chkSaveStory>> enable StorySaverPlugin
>//usage:// {{{<<option chkSaveStory>>}}}
You can also temporarily //bypass// the redisplay of a saved story ''without disabling the StorySaver cookie'' by including a trailing "#" at the end of the document URL.  This will cause your document to be loaded into the browser without displaying //any// initial tiddlers at all.  Alternatively, you can enter {{{#story:storyname}}} on the end of the URL (e.g., {{{#story:DefaultTiddlers}}}) to display any specific saved story, regardless of the value of the cookie-based saved story.

__''saveStory macro:''__
The {{{<<saveStory>>}}} macro lets you write the list of currently viewed tiddlers to a specified tiddler name (e.g., DefaultTiddlers, MyFavorites, etc.).  Tiddlers containing saved stories are automatically tagged with <<tag story>>, so that they can be recognized by the {{{<<storyViewer>>}}} macro (see [[StoryViewerPlugin]]).  The syntax for the {{{<<saveStory>>}}} macro is:
{{{
<<saveStory storyname label tooltip tag tag tag...>>
}}}
*''storyname''<br>is the target tiddler in which to save the current story.  If you use the keyword, ''ask'', in place of the tiddlername, you will be prompted to enter a tiddler title when saving the story (default: DefaultTiddlers).
*''label'' and ''tooltip''<br>are the link text and mouseover guide-text
*''tag tag tag...'' (optional)<br>are extra tags that are added when saving a story tiddler (in addition to the default<<tag story>>tag).

__''openStory macro:''__
To redisplay a saved story, the {{{<<openStory>>}}} macro can be used to embed either a droplist of all saved stories, or a link for a specified story.  Selecting from the droplist or clicking the link opens the corresponding set of tiddlers.  
{{{
<<openStory list tagValue>>
<<openStory popup label tooltip tagValue>>
<<openStory storyname label tooltip fold>>
}}}
*''list''<br>shows a droplist of all saved stories, plus additional commands/viewing options.  Selecting a story opens the corresponding tiddlers.
*''popup''<br>shows a popup display containing a list of all saved stories, plus additional commands/viewing options.  Selecting a story opens the corresponding tiddlers.  ''label'' and ''tooltip'' are optional and provide alternative display text and mouseover help text, respectively.
*''storyname''<br>is a tiddler containing a saved story.  //Note: You can also use a tag value as a storyname, in which case the story view will be composed of all tiddlers tagged with the specified tag value.//
*''label''<br>is the command link text (default: "open story: %0", where %0 is replaced by the storyname).
*''tooltip''<br>is the command mouseover guide-text (default: "open the set of tiddlers listed in: '%0'"),
*''tagValue'' (optional, default='story')<br>specifies an alternative tag value to match when listing story tiddlers.  Note: if MatchTagsPlugin is installed, you can also use a compound //boolean tag expression//, enclosed within doubled square brackets.
*''fold''<br>If this optional keyword is present, the story tiddlers are initially 'folded' using [[CollapsedTemplate]] instead of the usual [[ViewTemplate]] (see [[CollapseTiddlersPlugin]]).

__''excludeStory tag:''__
Any tiddlers tagged with<<tag excludeStory>>will be automatically omitted when creating new story tiddlers with {{{<<saveStory>>}}}.  Similarly, if a tiddler that is part of a saved story is tagged with<<tag excludeStory>>, it will not be displayed when that story is opened via {{{<<openStory>>}}}.

__''PermaView command link enhancement:''__
In order to further aide in saving/restoring the list of tiddlers currently being viewed, the core {{{<<permaview>>}}} command has been enhanced, so its link value always includes the current story view tiddler list as a paramifier in the URL.  This let you quickly use the browser's right-click menu directly on the permalink command text to "bookmark this link...".  Depending upon your system, you may also be able to drag the 'permaview' link directly from the page and drop it onto your desktop to create an instant permaview-bearing URL shortcut icon.
<<<
!!!!!Examples
<<<
*{{{<<saveStory TestStory "save a test story">>}}}<br>{{smallform{<<saveStory TestStory "save a test story">>}}}
*{{{<<openStory TestStory>>}}}<br><<openStory TestStory>>
*{{{<<openStory list>>}}}<br>{{smallform{<<openStory list>>}}}
*{{{<<openStory popup label tooltip>>}}}<br>{{smallform{<<openStory popup>>}}}
<<<
!!!!!Configuration
<<<
<<option chkSaveStory>> use automatic story cookie (reopens tiddlers on startup)
<<option chkStoryAllowAdd>>include 'add a story' command in droplist/popup
<<option chkStoryFold>>fold story tiddlers when opening a story (see [[CollapseTiddlersPlugin]])
<<option chkStoryClose>>close other tiddlers when opening a story
<<option chkStoryTop>>open story tiddlers at top of column
<<option chkStoryBottom>>open story tiddlers at bottom of column
<<<
!!!!!Revisions
<<<
2009.10.20 1.8.3 fix handling for 'add' item in popup menu
2009.08.29 1.8.2 added 'return false' to all button handlers to fix IE page-transition error
2009.08.23 1.8.1 fixed 'excludeStory' handling for links to missing tiddlers
2009.08.20 1.8.0 added 'excludeStory' tag handling
2009.07.27 1.7.1 corrected test for {{{chkStoryAllowAdd}}} when rendering //list// output
2009.07.27 1.7.0 added options: {{{chkStoryAllowAdd=true}}}, {{{chkStoryTop=true}}}, and {{{chkStoryBottom=false}}}.  Also, autoscroll to first tiddler in story
2009.07.26 1.6.0 added optional 'extratags' param to {{{<<saveStory>>}}} and 'tagfilter' to {{{<<openStory>>}}}
2009.07.06 1.5.1 in setTiddler(), use pushUnique() to avoid double 'story' tag
2009.04.24 1.5.0 added optional 'fold' param to {{{<<openStory StoryName ...>>}}} macro
2008.09.07 1.4.3 added removeCookie() function for compatibility with [[CookieManagerPlugin]]
2008.07.11 1.4.2 in confirmExit(), corrected bracketing for titles containing spaces
2008.03.10 [*.*.*] plugin size reduction: documentation moved to [[StorySaverPluginInfo]]
2008.01.01 1.4.1 sort list of stories alphabetically
2008.01.01 1.4.0 added popup option
2007.12.31 1.3.1 instead of readBracketedList(), use internal tiddler.links[] to retrieve story list from tiddler content. Allows more flexible formatting of story tiddler content: anything content that is not a tiddler link is automatically filtered out of the list.
2007.10.23 1.3.0 split {{{<<storyViewer>>}}} macro definition into stand-alone [[StoryViewerPlugin]] to allow separate installation of story saving vs. story viewing features.
2007.10.21 1.2.0 added {{{<<openStory>>}}} and {{{<<storyViewer>>}}} macros.
2007.10.20 1.1.0 in setTiddler(), automatically add "story" tag to saved story tiddlers
2007.10.18 1.0.1 added default initialization for chkSaveStory option value.  Also, in setTiddler(), call displayTiddler() after saving story to ensure that altered tiddler is shown to the user.
2007.10.05 1.0.0 initial release.   Moved [[SetDefaultTiddlers]] inline script and rewrote as a {{{<<saveStory>>}}} macro.  Moved permaview "mouseover HREF" enhancement from [[CoreTweaks]].
<<<
/***
|Name|[[StoryViewerPlugin]]|
|Source|http://www.TiddlyTools.com/#StoryViewerPlugin|
|Documentation|http://www.TiddlyTools.com/#StoryViewerPluginInfo|
|Version|1.4.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|view a set of tiddlers using a droplist, "first/previous/next/last" links, or timed slideshow|
The {{{<<storyViewer>>}}} macro allows you to quickly ''display //and// navigate between a set of tiddlers'', using a droplist of titles and/or individual "first/previous/next/last" buttons/text links.  It also provides a "slideshow" feature that permits you to ''present one tiddler at a time with a countdown timer to automatically advance to the next tiddler'' after a specified number of seconds.
!!!!!Documentation
> see [[StoryViewerPluginInfo]]
!!!!!Revisions
<<<
2011.03.11 1.4.0 added 'sort:fieldname' parameter
2011.01.24 1.3.4 in droplist onchange handler, don't clear slideshow 'started' flag (allows slideshow to continue after manual navigation)
|please see [[StoryViewerPluginInfo]] for additional revision details|
2007.10.23 1.0.0 Initial release, split {{{<<storyViewer>>}}} macro definition from [[StorySaverPlugin]] to allow separate installation of story saving vs. story viewing features.
<<<
!!!!!Code
***/
//{{{
version.extensions.StoryViewerPlugin= {major: 1, minor: 4, revision: 0, date: new Date(2011,3,11)};

config.macros.storyViewer = {
	tag:			"story",
	storynotfoundmsg:	"'%0' is an empty/unrecognized story",
	firstcmd:		"first",
	firstbutton:		"<<",
	firstmsg:		"first: '%0'",
	nextcmd:		"next",
	nextbutton:		">",
	nextmsg:		"next: '%0'",
	previouscmd:		"previous",
	previousbutton:		"<",
	prevmsg:		"previous: '%0'",
	lastcmd:		"last",
	lastbutton:		">>",
	lastmsg:		"last: '%0'",
	refreshmsg:		"redisplay '%0'",
	refreshmsg:		"",
	autostart:		false,
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {

		var parsed=paramString.parseParams('anon',null,true,false,false);
		var here=story.findContainingTiddler(place);
		if (here) var tid=here.getAttribute("tiddler");
		var storyname="";
		var p=params.shift();
		var keywords=['first','previous','here','next','last','list','links','timer','sort'];
		if (!p || keywords.indexOf(p.split(':')[0])!=-1) {
			// find story from current tiddler name
			if (!tid) return; // not in a tiddler... do nothing!
			var stories=store.getTaggedTiddlers(this.tag);
			if (!stories) return;
			for (var s=0; s<stories.length; s++) {
				if (!stories[s].linksUpdated) stories[s].changed();
				var tids=stories[s].links.slice(0);
				if (tids.contains(tid)) { storyname=stories[s].title; break; }
			}
			if (!storyname.length) return; // current tiddler is not part of a saved story
		}
		else { storyname=p; p=params.shift(); } // user-specified story name

		var sortby=getParam(parsed,'sort','title');
		var tids=this.getStory(storyname,sortby); // get tiddler list

		var target=null;
		switch (p?p.split(':')[0]:'') {
			case 'first':
				target=tids[0];
				break;
			case 'previous':
				var i=tids.indexOf(tid);
				if (i!=-1) var target=tids[Math.max(i-1,0)];
				break;
			case 'here':
				if (tid) target=tid;
				break;
			case 'next':
				var i=tids.indexOf(tid);
				if (i!=-1) var target=tids[Math.min(i+1,tids.length-1)];
				break;
			case 'last':
				target=tids[tids.length-1];
				break;
			case 'links':
				this.renderAllLinks(place,storyname);
				break;
			case 'timer':
				var delay=parseInt(getParam(parsed,'timer',15))*1000; // msecs between slides
				var autostart=params[0]=='autostart'; if (autostart) params.shift();
				var action=params[0]; // null/close/fold
				this.renderTimer(place,tids,tid,delay,autostart,action);
				break;
			case 'list':
			default:
				var prompt=getParam(parsed,'prompt',storyname+'...');
				var nobuttons=params.contains("nobuttons");
				var allbuttons=params.contains("allbuttons");
				var onlybuttons=params.contains("onlybuttons");
				this.renderList(place,tids,tid,storyname,prompt,nobuttons,allbuttons,onlybuttons);
				break;
		}
		var label=getParam(parsed,'label',params[0]||target);
		if (target) this.renderLink(place,tid,target,label);
	},
	getStory: function(storyname,sortby) { // READ TIDDLER LIST
		var tids=[];
		var fn=store.getMatchingTiddlers||store.getTaggedTiddlers;
		var tagged=store.sortTiddlers(fn.apply(store,[storyname]),sortby||'title');
		if (tagged.length) // if storyname is a tag, get tagged tiddlers rather than links
			for (var t=0; t<tagged.length; t++) tids.push(tagged[t].title);
		else {
			var t=store.getTiddler(storyname);
			if (t && !t.linksUpdated) t.changed();
			var tids=t?t.links.slice(0):[];
		}
		return tids;
	},
	renderLink: function(place,tid,target,label) {
		// override default labelling with specified text (if any)
		if (tid==target) { // self-referential links turn into 'refresh links'
			var btn=createTiddlyButton(place,null,this.refreshmsg.format([tid]), function() {
				var here=story.findContainingTiddler(place).getAttribute("tiddler");
				story.refreshTiddler(here,null,true);
			});
			wikify(label,btn); 
		}
		else // create link
			wikify(label,createTiddlyLink(place,target,false));
	},
	renderAllLinks: function(place,storyname) {
		var out="{{floatleft{";
		out+="<<storyViewer [["+storyname+"]] first first>> &nbsp;";
		out+="<<storyViewer [["+storyname+"]] previous previous>> &nbsp;";
		out+="}}}";
		out+="{{floatright{";
		out+="&nbsp; <<storyViewer [["+storyname+"]] next next>>";
		out+="&nbsp; <<storyViewer [["+storyname+"]] last last>>";
		out+="}}}";
		out+="{{center{<<storyViewer [["+storyname+"]] here>>}}}";
		wikify(out,place);
	},
	renderList: function(place,tids,tid,storyname,prompt,nobuttons,allbuttons,onlybuttons) {
		var h="";
		h+='<form style="display:inline">';
		if ((!nobuttons||onlybuttons) && allbuttons) {
			h+='<input type="button" value="'+this.firstbutton+'" ';
			h+='	style="padding:0" title="'+(tids[0]?this.firstmsg.format([tids[0]]):'')+'"';
			h+=' onclick="if (this.form.list.length<2) return; ';
			h+='	this.form.list.selectedIndex=1; this.form.list.onchange();">';
		}
		if (!nobuttons||onlybuttons) {
			h+='<input type="button" value="'+this.previousbutton+'" style="padding:0 0.3em"';
			h+=' onclick="if (this.form.list.length<2) return; ';
			h+=' 	var i=this.form.list.selectedIndex-1; if (i<1) i=1; ';
			h+='	this.form.list.selectedIndex=i; this.form.list.onchange();"';
			h+=' onmouseover="if (this.form.list.length<2) return; ';
			h+=' 	var i=this.form.list.selectedIndex-1; if (i<1) i=1; ';
			h+='	var v=this.form.list.options[i].value; if (!v.length) return; ';
			h+='	this.title=config.macros.storyViewer.prevmsg.format([v]);">';
		}
		h+='<select size="1" name="list"';
		if (onlybuttons) h+=' style="display:none;"';
		h+=' onchange="if (this.value) story.displayTiddler(this,this.value);">';
		h+='<option value="">'+prompt+'</option>';
		for (i=0; i<tids.length; i++) {
			h+='<option '+
				(tids[i]==tid?'selected ':'')+
				'value="'+tids[i]+'">\xa0\xa0'+tids[i]+'</option>';
		}
		h+='</select>';
		if (!nobuttons||onlybuttons) {
			h+='<input type="button" value="'+this.nextbutton+'" style="padding:0 0.3em"';
			h+=' onclick="var i=this.form.list.selectedIndex+1; ';
			h+='	if (i>this.form.list.options.length-1) i=this.form.list.options.length-1; ';
			h+='	this.form.list.selectedIndex=i; this.form.list.onchange();"';
			h+=' onmouseover="var i=this.form.list.selectedIndex+1; ';
			h+='	if (i>this.form.list.options.length-1) i=this.form.list.options.length-1; ';
			h+='	var v=this.form.list.options[i].value; if (!v.length) return;';
			h+='	this.title=config.macros.storyViewer.nextmsg.format([v]);">';
		}
		if ((!nobuttons||onlybuttons) && allbuttons) {
			h+='<input type="button" value="'+this.lastbutton+'" ';
			h+='	style="padding:0" title="'+(tids[tids.length-1]?this.lastmsg.format([tids[tids.length-1]]):'')+'"';
			h+=' onclick="this.form.list.selectedIndex=this.form.list.options.length-1; this.form.list.onchange();">';
		}
		h+='</form>';
		createTiddlyElement(place,"span").innerHTML=h;
	},
	renderTimer: function(place,tids,tid,delay,autostart,action) {
		var now=new Date().getTime(); // msec
		var target=createTiddlyElement(null,'input',now+Math.random()); // unique ID
		target.setAttribute('type','button'); target.style.padding='0';
		place.appendChild(target);
		target.tid		=tids[Math.min(tids.indexOf(tid)+1,tids.length-1)]||''; // next tiddler
		target.action		=action;
		target.formatTimer	=this.formatTimer;
		target.start		=this.startTimer;
		target.stop		=this.stopTimer;
		target.onmouseover	=this.pauseTimer;
		target.onmouseout	=this.resumeTimer;
		target.tick		=this.timerTick;
		target.onclick		=this.timerClick;
		target.next		=this.timerNext;
		target.start(delay,autostart);
	},
	formatTimer: function(t) {
		return '0:'+String.zeroPad(Math.floor(t/1000),2);
	},
	startTimer: function(delay,start) {
		var co=config.options; // abbrev
		start=config.macros.storyViewer.started=start||config.macros.storyViewer.started;
		var now=new Date().getTime(); // msec
		this.started=start;
		this.delay=delay;
		this.paused=start?0:delay;
		this.stopTime=now+delay; // msec
		this.title='CLICK='+(start?'reset':'start')+" slideshow timer... next: '"+this.tid+"'";
		this.style.cursor='pointer';
		this.value=this.formatTimer(delay);
		if (start) {
			var code="var e=document.getElementById('"+this.id+"'); if(e)e.tick()";
			this.timer=setTimeout(code,500);
		}
		return false;
	},
	stopTimer: function() {
		this.timer=clearTimeout(this.timer);
		this.started=config.macros.storyViewer.started=false;
		this.paused=0;
		this.title="CLICK=start slideshow timer... next: '"+this.tid+"'";
		this.value=this.formatTimer(this.delay);
		return false;
	},
	pauseTimer: function() {
		if (!this.started) return;
		var now=new Date().getTime(); // msec
		this.paused=Math.max(this.stopTime-now,0);
		this.stopTime=now+this.paused;
		return false;
	},
	resumeTimer: function() {
		if (!this.started || !this.paused) return;
		var now=new Date().getTime(); // msec
		this.stopTime=now+this.paused;
		this.paused=0;
		return false;
	},
	timerTick: function() {
		var now=new Date().getTime(); // msec
		if (!this.started)
			this.stopTime=now+this.delay;
		else if (this.paused) {
			this.stopTime=now+this.paused;
			this.title="[PAUSED] MOUSEOUT=resume, CLICK=reset... next: '"+this.tid+"'";
		}
		var remaining=this.stopTime-now;
		if (remaining>0) {
			if (this.started && !this.paused) this.value=this.formatTimer(remaining);
			var code="var e=document.getElementById('"+this.id+"'); if(e)e.tick()";
			this.timer=setTimeout(code,500);
		} else {
			this.stop();
			this.next();
		}
		return false;
	},
	timerClick: function() {
		return this.started?this.stop():this.start(this.delay,true);
	},
	timerNext: function() { // OPEN NEXT TIDDLER
		var here=story.findContainingTiddler(this);
		config.macros.storyViewer.started=true; // next slide autostarts to continue slideshow
		if (this.tid) story.displayTiddler(here,this.tid);
		config.macros.storyViewer.started=false;
		if (!here) return false;
		var t=here.getAttribute('tiddler');
		if (this.action=='close') story.closeTiddler(t);
		if (this.action=='fold' && config.commands.collapseTiddler) // see CollapseTiddlerPlugin
			config.commands.collapseTiddler.handler(null,here,t);
		return false;
	}
}
//}}}
//{{{
config.paramifiers.story = {
	onstart: function(v) {
		var t=store.getTiddler(v); if (t) t.changed();
		var list=t?t.links:store.getTiddlerText(v,"").parseParams("open",null,false);
		story.displayTiddlers(null,list);
	}
};
//}}}
/***
|Name|StoryViewerPluginInfo|
|Source|http://www.TiddlyTools.com/#StoryViewerPlugin|
|Documentation|http://www.TiddlyTools.com/#StoryViewerPluginInfo|
|Version|1.4.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|documentation|
|Description|documentation for StoryViewerPlugin|
The {{{<<storyViewer>>}}} macro allows you to quickly ''display //and// navigate between a set of tiddlers'', using a droplist of titles and/or individual "first/previous/next/last" buttons/text links.  It also provides a "slideshow" feature that permits you to ''present one tiddler at a time with a countdown timer to automatically advance to the next tiddler'' after a specified number of seconds.
!!!!!Usage
<<<
{{{
<<storyViewer storyname|tagvalue list buttonoption prompt:... sort:...>>
<<storyViewer storyname|tagvalue first|previous|here|next|last sort:...>>
<<storyViewer storyname|tagvalue links sort:fieldname>>
<<storyViewer storyname|tagvalue timer:nnn autostart close|fold sort:...>>
}}}
where:
* ''storyname'' or ''tagvalue''<br>specifies a set of tiddler titles, defined either by matching a tag value, or by creating a tiddler, tagged with <<tag story>>, containing a space-separated list of titles.  //Note: You can use the {{{<<saveStory>>}}} macro (see [[StorySaverPlugin]]) to automatically create stories using the titles of the tiddlers that are currently being viewed.//  If you omit the storyname/tagname parameter, the plugin will attempt to identify a suitable story by locating the current tiddler title within a saved story tiddler.  The story view controls are not displayed unless the current tiddler title is explicitly found in at least one saved story.
** Note: if [[MatchTagsPlugin]] is installed, you can use a compound //boolean tag expression//, enclosed within doubled square brackets.  This allows you to generate sets of stories based on complex combinations of tags, rather than matching just one tag value.  [[MatchTagsPlugin]] also allows you to use a //wildcard// expression, ".*" (without quotes), that will match all tiddlers, regardless of their tag value(s).
* ''list''<br>displays a droplist of tiddlers for the specified story, with previous/next pushbuttons on either side of the list.  You can also specify which buttons will appear when using a droplist:
** ''allbuttons''<br>displays buttons for first/last as well as previous/next.
** ''nobuttons''<br>displays the droplist without any buttons
** ''onlybuttons''<br>hides the droplist and shows just the buttons
* ''prompt:...'' (default={{{"storyname..."}}})<br>specifies non-selectable label text to use as the first item in the droplist.
* ''sort:fieldname'' //(optional)//<br>when a ''tagvalue'' is used to select tiddlers, you can specify a tiddler fieldname that can be used to sort the resulting list of tiddlers, with an optional "-" prefix to indicate descending vs. ascending ordering, e.g, "sort:-modified" will generate a list of tiddlers in reverse date order (newest tiddler first).
* ''first'' or ''previous'' or ''here'' or ''next'' or ''last''<br>displays an individual link to the indicated tiddler within the story. The next/previous links are automatically calculated relative to the current tiddler.  ''here'' displays the current tiddler title.
* ''links''<br>displays the set of first, previous, here, next and last links with just one convenient macro invocation, allowing you to quickly and easily embed story navigation links into any tiddler content.
* ''timer:nnn''<br>displays an automatic countdown 'slideshow' timer, where ''nnn'' is the number of seconds between slides.  Click on the timer to start the countdown.  The countdown is paused when hovering over the timer.  Click a //running// timer to immediately advance to the next tiddler in the story.  Optional slideshow parameters:
** ''autostart''<br>automatically starts the countdown without an initial click.
** ''close'' or ''fold''<br>close or fold (see [[CollapseTiddlerPlugin]]) the current tiddler when the next tiddler in the story is opened. The default is to simply display the next tiddler following the current one.
<<<
!!!!!Examples
<<<
{{smallform{
{{{
<<storyViewer MenuDefinitions list nobuttons>>
}}}
><<storyViewer MenuDefinitions list nobuttons>> //uses "saved story" tiddler//
{{{
<<storyViewer pluginInfo>>
}}}
><<storyViewer pluginInfo>>
{{{
<<storyViewer pluginInfo list allbuttons prompt:"TiddlyTools menu definitions...">>
}}}
><<storyViewer pluginInfo list allbuttons prompt:"TiddlyTools menu definitions...">>
{{{
<<storyViewer pluginInfo first>>
<<storyViewer pluginInfo previous>>
<<storyViewer pluginInfo next>>
<<storyViewer pluginInfo last>>
}}}
><<storyViewer pluginInfo first>>
><<storyViewer pluginInfo previous>>
><<storyViewer pluginInfo next>>
><<storyViewer pluginInfo last>>
{{{
<<storyViewer pluginInfo previous label:"back">>
<<storyViewer pluginInfo next label:"forward">>
}}}
><<storyViewer pluginInfo previous label:"back">>
><<storyViewer pluginInfo next label:"forward">>
{{{
<<storyViewer pluginInfo links>>
}}}
><<storyViewer pluginInfo links>>
{{{
<<storyViewer pluginInfo timer:20 fold>>
}}}
><<storyViewer pluginInfo timer:20 fold>>
{{{
<<storyViewer ".*" prompt:"timeline..." sort:-modified>>
}}}
><<storyViewer ".*" prompt:"timeline..." sort:-modified>>
}}}
<<<
!!!!!Revisions
<<<
2011.03.11 1.4.0 added 'sort:fieldname' parameter
2011.01.24 1.3.4 in droplist onchange handler, don't clear slideshow 'started' flag (allows slideshow to continue after manual navigation)
2011.01.12 1.3.3 added config.macros.storyViewer.started (controls 'autostart' for automatic presentation of multiple pages)
2011.01.11 1.3.2 use pushbutton instead of text to display slideshow timer
2011.01.11 1.3.1 code and documentation cleanup
2011.01.10 1.3.0 added slideshow (params= timer:nnn, autostart, close/fold).  Added custom prompt for droplist (param= prompt:"text"). Added support for [[MatchTagsPlugin]]
2008.06.05 1.2.0 added custom story paramifier to extract story titles from tiddler links instead of using parseParams.  Permits use of links from any tiddler as a story, even if it contains wiki-syntax formatting in addition to list of tiddler titles
2008.03.10 *.*.* plugin size reduction: documentation moved to [[StoryViewerPluginInfo]]
2007.12.31 1.1.0 instead of readBracketedList(), use internal tiddler.links[] to retrieve story list from tiddler content.  Allows more flexible formatting of story tiddler content.
2007.12.04 *.*.* update for TW2.3.0: replaced deprecated core functions, regexps, and macros
2007.10.23 1.0.0 Initial release, split {{{<<storyViewer>>}}} macro definition from [[StorySaverPlugin]] to allow separate installation of story saving vs. story viewing features.
<<<
/***
|Description|default stylesheet definitions|
|StyleSheet|StyleSheet|
|PageTemplateReadOnly|PageTemplateReadOnly|
|EditTemplateReadOnly|EditTemplateReadOnly|
***/

/***
Apply TiddlyTools common adjustments to standard styles:
----
***/
[[StyleSheetAdjustments]]

/***
Change this to set the default "theme":
----
***/
[[EdgeOfNight]]
/***
|Name|StyleSheetAdjustments|
|Source|http://www.TiddlyTools.com/#StyleSheetAdjustments|
|Version||
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|CSS|
|Description|adjust TiddlyWiki default shadow stylesheets definitions|
***/

[[StyleSheetPlugins]] /* include adjustments to plugin-supplied definitions */
[[StyleSheetShortcuts]] /* include formatting "shortcut" definitions */
[[Jash.css]] /* Javascript Shell (jash) Styles */

/***
These 'style tweaks' can be easily included in other stylesheet tiddler so they can share a baseline look-and-feel that can then be customized to create a wide variety of 'flavors'.
/***
!body /%==================================================%/
IE needs explicit "position:static" declaration (fixes 'partial background display bug')
***/
/*{{{*/
body { font-family: Verdana,Arial,Helvetica; position:static; }
/*}}}*/

/***
!backstage /%==================================================%/
fix for bug #347/#349, wherein backstageCloak covers backstagePanel whenever fixed elements are present
***/
/*{{{*/
#backstageCloak { z-index:49; }
#backstagePanel { margin:0em 0.5em 0em 0.5em; } 
#backstageButton a:hover
	{background-color:transparent !important;}

/*}}}*/

/***
!common colors /%==================================================%/
***/
/*{{{*/
/* these seem to have been omitted from the core defaults for link styles */
a { color:#014; }
a:hover	{ color:#def; }
/*}}}*/

/***
!HTML forms /%==================================================%/
***/
/*{{{*/
/* eliminate whitespace before/after form controls */
form { margin:0;padding:0; }
/*}}}*/

/***
!basic styling /%==================================================%/
***/
/*{{{*/
/* reduce whitespace before/after horizontal rule */
hr { margin:2px 0 1px 0;padding:0; }
/*}}}*/

/***
!header and titles /%==================================================%/
IE needs explicit "position:static" declaration (fixes 'background display hides text bug')
***/
/*{{{*/
.header
	{ background:transparent; padding:.2em 1em; position:static; margin-bottom:.5em; }
.headerShadow, .headerForeground
	{ padding:.5em; }
.header a, .header .button, .header .tiddlyLinkExisting, .header .tiddlyLinkNonExisting
	{ font-weight: normal; }
.header .externalLink,
.siteSubtitle a, .siteSubtitle .button, .siteSubtitle .tiddlyLinkExisting, .siteSubtitle .tiddlyLinkNonExisting
	{ text-decoration:none; }
.header table
	{ border-collapse: collapse !important; }

/*}}}*/

/***
!displayArea /%==================================================%/
***/
/*{{{*/
#displayArea
	{ margin:0em 17em 0em 11em; }
/*}}}*/


/***
!popups /%==================================================%/
white-space:nowrap prevents items from wrapping if popup is near right edge of window
z-index:1000 makes sure popup is above EVERYTHING else
***/
/*{{{*/
.popup
	{ white-space: nowrap; z-index:1000; color: #000; background: #ffe; border: 1px solid #000;
		-moz-border-radius-topright: 5px; -moz-border-radius-bottomleft: 5px; -moz-border-radius-bottomright: 5px;
		-webkit-border-top-right-radius: 5px; -webkit-border-bottom-left-radius: 5px; -webkit-border-bottom-right-radius: 5px; }
.popup a, .popup .button, .popup .tiddlyLinkExisting, .popup .tiddlyLinkNonExisting
	{ font-weight: normal; font-style: normal; }
.popup hr
	{ color: #000; background: #ddd; border: 0; }
.popup li.disabled
	{ color: #999; }
.popup li a, .popup li a:visited
	{ color: #300; padding:1px; }
.popup li a:hover
	{ background: #006; color: #fff !important;}
/*}}}*/

/***
!messageArea /%==================================================%/
***/
/*{{{*/
#messageArea
	{ font-size:90%; -moz-border-radius:1em;-webkit-border-radius:1em; background:#eee; }
/*}}}*/

/***
!main menu (left sidebar) /%==================================================%/
***/
/*{{{*/
#mainMenu
	{ z-index:1; width:9em; text-align:left; margin:0; margin-left:1.5em; padding:0; clear:both; }
*[id="mainMenu"] /* moz browsers only */
	{ width:auto !important; } 
/*}}}*/

/***
!sidebar (right sidebar) /%==================================================%/
***/
/*{{{*/
#sidebar
	{ width:18em; margin-right:1em; clear:both; }
#sidebarTabs .tab
	{ font-size:90%; -moz-border-radius-topleft:.5em; -moz-border-radius-topright:.5em;
		-webkit-border-top-left-radius:.5em; -webkit-border-top-right-radius:.5em; }
#sidebarTabs .tabContents
	{ background:transparent; border:1px solid #999; padding:.5em; height:auto; overflow:auto; width:92.5%; }
#sidebarTabs .tabContents .tabContents
	{ background:transparent; border:1px solid #999; padding:.5em; height:auto; }
#sidebarOptions input[type="text"]
	{ font-size:8pt; }
}
*/
/*}}}*/

/***
!tabs /%==================================================%/
***/
/*{{{*/
.tabset
	{ padding: 0.2em 0 0 0; }
.tab
	{ padding:0 1px 0 1px; }
.viewer .tab
	{ padding:0 .5em 0 .5em; }
.tabSelected
	{ border: 1px solid; border-bottom: 0px !important; margin-bottom:-2px !important;
		 -moz-border-radius-topleft:.5em; -moz-border-radius-topright:.5em;
		 -webkit-border-top-left-radius:.5em; -webkit-border-top-right-radius:.5em;}
.tabUnselected
	{ border: 1px solid #999; border-bottom:0px;
		-moz-border-radius-topleft:.5em; -moz-border-radius-topright:.5em;
		-webkit-border-top-left-radius:.5em; -webkit-border-top-right-radius:.5em;}
.tabContents
	{ border: 1px solid; -moz-border-radius:1em;-webkit-border-radius:1em; padding: 1em; }
/*}}}*/

/***
!tiddler display elements /%==================================================%/
***/
/*{{{*/
.tiddler { padding: 0 1em 1em 1em; }
.annotation {
	border: 1px solid;
	-moz-border-radius:.5em;
	-webkit-border-radius:.5em;
	margin: .5em 0;
	padding: .2em .5em;
	font-size:90%;
}
.button, .button:hover, .button:active,
.viewer .button, .viewer .button:hover, .viewer .button:active
	{ background:transparent; border:0; }
.toolbar
	{ float:right; display:inline; padding-bottom:0; visibility:hidden; }
.selected .toolbar
	{ visibility:visible; }
.toolbar .floatingPanel
	{ visibility:visible !important; } /* make sure floating panels from toolbars don't disappear on mouseout */
.toolbar .button, .toolbar a
	{ border:1px solid transparent; background:transparent; margin:0px 1px; padding:0px .2em; -moz-border-radius:.5em;-webkit-border-radius:.5em; }
.toolbar
	{color:[[ColorPalette::TertiaryLight]];}
.toolbar a
	{color:[[ColorPalette::TertiaryLight]];}
.selected .toolbar
	{color:[[ColorPalette::Foreground]];}
.selected .toolbar, .selected .toolbar .button, .selected .toolbar a
	{ color:#006; }
.toolbar .button:hover, .toolbar a:hover
	{ border:1px solid #69c !important; background:#006 !important; color:#fff !important; }
.shadow .tagging, .shadow .tagged
	{ display:none; }
.tagging, .tagged
	{ background-color: #ccc; border: 1px solid; }
.selected .tagging, .selected .tagged
	{ background-color:#eee; border: 1px solid #999; }
.tagging, .tagged
	{ -moz-border-radius:1em;-webkit-border-radius:1em; }
.subtitle
	{ font-size:90%; }
.shadow input, .shadow textarea, .shadow button, .shadow checkbox, .shadow radio, .shadow select
	{ font-size:90%; }
.shadow input, .shadow textarea, .shadow button, .shadow checkbox, .shadow radio, .shadow select
	{ font-size:90%; }
.editor input
	{ font-size: 8pt;}
.editor textarea
	{ font-size: 8pt; font-family:monospace; }
.editor select
	{ font-size: 8pt; border:1px solid; }
.title
	{ font-size: 12pt; line-height:120%; }
.viewer
	{ font-size: 9pt; padding: 0.7em; text-align:justify; }
.viewer pre, .viewer code, .viewer blockquote
	{ font-size:8pt; text-align:left; }
.viewer pre 
	{ background:#ffe; border:1px solid; }
.viewer table, .viewer table tr, .viewer table td
	{ border:1px solid; }
.viewer hr {
	margin: 1px; padding:1px;
	border:0;
	border-top: solid 1px #666;
	color: #666;
}
.viewer blockquote {
	line-height: 1.5em;
	padding-left: 1em;
	margin-left: 1em;
	border-left: 1px dotted;
}
/*}}}*/
/***
|Name|StyleSheetPlugins|
|Source|http://www.TiddlyTools.com/#StyleSheetPlugins|
|Version||
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|CSS|
|Description|custom definitions for plugin-specific ID's and classes|
>Important Note: ''this tiddler is highly-customized for the TiddlyTools document'' and you may need to extensively modify, supplement, replace or remove portions of these definitions in order to best fit //YOUR// document needs.
***/
/***
!MoveablePanelPlugin - searchResults
***/
/*{{{*/
.undocked .searchResults {
	border:1px solid #abe; -moz-border-radius:1em; -webkit-border-radius:1em;
	padding:0em; background:#003; min-width:35em;
}
.undocked .searchResults .title { margin-left:.5em; }
.undocked .searchResults .viewer { -moz-border-radius: 0 0 1em 1em; }
.undocked .searchResults .viewer ul { max-height:20em; overflow:auto; }
.undocked .searchResults .toolbar { margin-top:.3em; padding-right:.5em; }
/*}}}*/
/***
!PageTemplate - siteMenu 
***/
/*{{{*/
.siteMenu
	{ background:transparent; padding:.5em; padding-top:0; margin:0; }
.siteMenu a, .siteMenu .button, .siteMenu .tiddlyLinkExisting, .siteMenu .tiddlyLinkNonExisting
	{ font-weight: normal; font-style: normal; }
/*** LEAVE THESE OUT FOR NOW
.siteMenu .button, .siteMenu a
	{ border:1px solid transparent; background:transparent; margin:0px; padding:0px 1px; -moz-border-radius:.5em;-webkit-border-radius:.5em; }
.siteMenu .button:hover, .siteMenu a:hover
	{ border:1px solid #69c; background:#006; color:#fff; }
***/
/*}}}*/
/***
!PageTemplate - storyMenu 
***/
/*{{{*/
.storyMenu
	{ display:block; margin:0em 1em .5em 1em; }
.storyMenu a, .storyMenu .button, .storyMenu .tiddlyLinkExisting, .storyMenu .tiddlyLinkNonExisting
	{ font-weight: normal; font-style: normal; text-decoration:none; }
/*}}}*/
/***
!NestedSlidersPlugin 
***/
/*{{{*/
.floatingPanel
	{ z-index:700; padding:1em; margin:0em; border:1px solid; -moz-border-radius:1em;-webkit-border-radius:1em; font-size:8pt; text-align:left; }
.floatingPanel hr
	{ margin:2px 0 1px 0; padding:0; }
#sidebarOptions .sliderPanel
	{ margin:0; padding:0; font-size:1em; background:transparent; }
#sidebarOptions .sliderPanel a
	{ font-weight:normal; }
#sidebarOptions .sliderPanel blockquote
	{ margin:0;padding:0;margin-left:1em; border-left:1px dotted; padding-left:1em }

.selected .floatingPanel .button,
.selected .floatingPanel a:link,
.selected .floatingPanel a:hover,
.selected .floatingPanel a:visited,
.floatingPanel .button,
.floatingPanel a:link,
.floatingPanel a:hover,
.floatingPanel a:visited
	{ color:[[ColorPalette::PrimaryDark]] !important; }

/*}}}*/
/***
!CheckboxPlugin 
***/
/*{{{*/
input[type="Checkbox"]
	{ margin-top:2px;margin-bottom:2px; }
/*}}}*/
/***
!BreadcrumbsPlugin 
***/
/*{{{*/
/* smaller size for bread crumbs (see BreadcrumbsPlugin) */
#breadCrumbs
	{ display:none; margin:0em 1em; padding-bottom:.5em; font-size:7pt; } /* display:block is set by plugin when crumbs are in use */
/*}}}*/
/***
!TableOfContentsPlugin 
***/
/*{{{*/
#sidebarTabs .tabContents *[class="TOCList"] /* MOZ ONLY */
	{ background-color: transparent; border-color:transparent !important; }
/*}}}*/
/***
!AttachFilePlugin 
***/
/*{{{*/
#sidebar .attachPanel
	{ right:115%; top:3em; text-align:left; }
/*}}}*/
/***
!ImportTiddlersPlugin 
***/
/*{{{*/
#sidebar #importPanel
	{ right:115%; top:6em; text-align:left; }
/*}}}*/
/***
!ExportTiddlersPlugin 
***/
/*{{{*/
#sidebar #exportPanel
	{ right:115%; top:9em; text-align:left; }
/*}}}*/
/***
!QuoteOfTheDayPlugin
***/
/*{{{*/
.QOTD
	{ color:inherit !important; background:inherit !important; }
/*}}}*/
/***
!TableSorterPlugin
***/
/*{{{*/
.sortedCol
	{ color:inherit !important; background:inherit !important; }
/*}}}*/
/***
|Name|StyleSheetPrint|
|Source|http://www.TiddlyTools.com/#StyleSheetPrint|
|Version||
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|CSS|
|Description|adjustments for printing|
***/

/*{{{*/
@media print {

#mainMenu, #sidebar, #messageArea, .toolbar, .tagged, .tagging, .subtitle, .header
	{display: none !important;}
#breadCrumbs, #siteMenu, #storyMenu
	{ display:none !important; }
#displayArea
	{ margin: 1em !important; }
noscript /* Fixes a feature in Firefox 1.5.0.2 where print preview displays the noscript content */
	{ display:none; }
.tiddler
	{ page-break-after:always; }
/*****
use this for 3x5 index cards:
.tiddler { height:3in !important; width:5in !important; overflow:none !important; }
*****/

}
/*}}}*/
/***
|Name|StyleSheetShortcuts|
|Source|http://www.TiddlyTools.com/#StyleSheetShortcuts|
|Version||
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|CSS|
|Description|'convenience' classes for common formatting, alignment, boxes, tables, etc.|

These 'style tweaks' can be easily included in other stylesheet tiddler so they can share a baseline look-and-feel that can then be customized to create a wide variety of 'flavors'.
***/
/*{{{*/

/* text alignments */
.left
	{ display:block;text-align:left; }
.center
	{ display:block;text-align:center; }
.center table
	{ margin:auto !important; }
.right	
	{ display:block;text-align:right; }
.justify
	{ display:block;text-align:justify; }
.indent
	{ display:block;margin:0;padding:0;border:0;margin-left:2em; }
.floatleft
	{ float:left; }
.floatright
	{ float:right; }
.valignTop, .valignTop table, .valignTop tbody, .valignTop th, .valignTop tr, .valignTop td
	{ vertical-align:top; }
.valignBottom, .valignBottom table, .valignBottom tbody, .valignBottom th, .valignBottom tr, .valignBottom td
	{ vertical-align:bottom; }
.clear
	{ clear:both; }
.wrap
	{ white-space:normal; }
.nowrap
	{ white-space:nowrap; }
.hidden
	{ display:none; }
.show
	{ display:inline !important; }
.span
	{ display:span; }
.block
	{ display:block; }
.relative
	{ position:relative; }
.absolute
	{ position:absolute; }

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

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

/* plain list items (no bullets or indent) */
.nobullets li { list-style-type: none; margin-left:-2em; }

/* vertical tabsets - courtesy of Tobias Beer */
.vTabs .tabset {float:left;display:block;padding:0px;margin-top:.5em;min-width:20%;}
.vTabs .tabset .tab {display:block;text-align:right;padding:2px 3px 2px 7px; margin:0 1px 1px 0;}
.vTabs .tabContents {margin-left:20%;max-width:80%;padding:5px;}
.vTabs .tabContents .tabContents {border:none; background:transparent;}

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

/* page breaks */
.breakbefore { page-break-before:always; }
.breakafter { page-break-before:always; } 

/* show/hide browser-specific content for InternetExplorer vs. non-IE ("moz") browsers */
*[class="ieOnly"]
	{ display:none; } /* hide in moz (uses CSS selector) */
* html .mozOnly, *:first-child+html .mozOnly
	{ display: none; } /* hide in IE (uses IE6/IE7 CSS hacks) */

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

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

/* stretchable images (auto-size to fit tiddler) */
.stretch img { width:95%; }

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

/* scrolled content */
.scrollbars { overflow:auto; }
.height10em { height:10em; }
.height15em { height:15em; }
.height20em { height:20em; }
.height25em { height:25em; }
.height30em { height:30em; }
.height35em { height:35em; }
.height40em { height:40em; }

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

/* stretchable edit fields and textareas (auto-size to fit tiddler) */
.stretch input { width:99%; }
.stretch textarea { width:99%; }

/* compact input fields (limited to a few characters for entering percentages and other small values) */
.onechar input   { width:1em; }
.twochar input   { width:2em; }
.threechar input { width:3em; }
.fourchar input  { width:4em; }
.fivechar input  { width:5em; }

/* text colors */
.white { color:#fff !important }
.gray  { color:#999 !important }
.black { color:#000 !important }
.red   { color:#f66 !important }
.green { color:#0c0 !important }
.blue  { color:#99f !important }

/* rollover highlighting */
.mouseover 
	{color:[[ColorPalette::TertiaryLight]] !important;}
.mouseover a
	{color:[[ColorPalette::TertiaryLight]] !important;}
.selected .mouseover
	{color:[[ColorPalette::Foreground]] !important;}
.selected .mouseover .button, .selected .mouseover a
	{color:[[ColorPalette::PrimaryDark]] !important;}

/* rollover zoom text */
.zoomover
	{ font-size:80% !important; }
.selected .zoomover
	{ font-size:100% !important; }

/* [[ColorPalette]] text colors */
.Background	{ color:[[ColorPalette::Background]];	 }
.Foreground	{ color:[[ColorPalette::Foreground]];	 }
.PrimaryPale	{ color:[[ColorPalette::PrimaryPale]];	 }
.PrimaryLight	{ color:[[ColorPalette::PrimaryLight]];	 }
.PrimaryMid	{ color:[[ColorPalette::PrimaryMid]];	 }
.PrimaryDark	{ color:[[ColorPalette::PrimaryDark]];	 }
.SecondaryPale	{ color:[[ColorPalette::SecondaryPale]]; }
.SecondaryLight	{ color:[[ColorPalette::SecondaryLight]];}
.SecondaryMid	{ color:[[ColorPalette::SecondaryMid]];	 }
.SecondaryDark	{ color:[[ColorPalette::SecondaryDark]]; }
.TertiaryPale	{ color:[[ColorPalette::TertiaryPale]];	 }
.TertiaryLight	{ color:[[ColorPalette::TertiaryLight]]; }
.TertiaryMid	{ color:[[ColorPalette::TertiaryMid]];	 }
.TertiaryDark	{ color:[[ColorPalette::TertiaryDark]];	 }
.Error		{ color:[[ColorPalette::Error]];	 }

/* [[ColorPalette]] background colors */
.BGBackground	  { background-color:[[ColorPalette::Background]];	}
.BGForeground	  { background-color:[[ColorPalette::Foreground]];	}
.BGPrimaryPale	  { background-color:[[ColorPalette::PrimaryPale]];	}
.BGPrimaryLight	  { background-color:[[ColorPalette::PrimaryLight]];	}
.BGPrimaryMid	  { background-color:[[ColorPalette::PrimaryMid]];	}
.BGPrimaryDark	  { background-color:[[ColorPalette::PrimaryDark]];	}
.BGSecondaryPale  { background-color:[[ColorPalette::SecondaryPale]]; 	}
.BGSecondaryLight { background-color:[[ColorPalette::SecondaryLight]];	}
.BGSecondaryMid	  { background-color:[[ColorPalette::SecondaryMid]];	}
.BGSecondaryDark  { background-color:[[ColorPalette::SecondaryDark]]; 	}
.BGTertiaryPale	  { background-color:[[ColorPalette::TertiaryPale]];	}
.BGTertiaryLight  { background-color:[[ColorPalette::TertiaryLight]]; 	}
.BGTertiaryMid	  { background-color:[[ColorPalette::TertiaryMid]];	}
.BGTertiaryDark	  { background-color:[[ColorPalette::TertiaryDark]];	}
.BGError	  { background-color:[[ColorPalette::Error]];	 	}
/*}}}*/
/***
|Name|SwitchThemePlugin|
|Source|http://www.TiddlyTools.com/#SwitchThemePlugin|
|Documentation|http://www.TiddlyTools.com/#SwitchThemePluginInfo|
|Version|5.4.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.3|
|Type|plugin|
|Description|Select alternative TiddlyWiki template/stylesheet 'themes' from a droplist|
!!!!!Documentation
>see [[SwitchThemePluginInfo]]
!!!!!Configuration
<<<
Current theme:<<switchTheme width:auto>>
<<option chkRandomTheme>> select a random theme at startup
//Note: to prevent a given theme from being chosen at random, tag it with <<tag excludeTheme>>//
<<<
!!!!!Installation Note
>As of 4/13/2008, a "core patch" function that provides backward-compatibility with TW2.3.x has been split into a separate tiddler, [[SwitchThemePluginPatch]], to reduce installation overhead for //this// plugin.  ''You should only install the patch tiddler when using this plugin in documents based on a core version prior to TW2.4.0''
!!!!!Revisions
<<<
2009.10.01 [5.4.1] changed 'noRandom' tag to 'excludeTheme' and recognize 'excludeLists' tag
| Please see [[SwitchThemePluginInfo]] for previous revision details |
2008.01.22 [5.0.0] Completely re-written and renamed from [[SelectStylesheetPlugin]] (now retired)
//history for retired SelectStylesheetPlugin omitted//
2005.07.20 [1.0.0] initial release (as SelectStylesheetPlugin)
<<<
!!!!!Code
***/
//{{{
version.extensions.SwitchThemePlugin= {major: 5, minor: 4, revision: 1, date: new Date(2009,10,1)};

config.macros.switchTheme = {
	handler: function(place,macroName,params) {
		setStylesheet(".switchTheme {width:100%;font-size:8pt;margin:0em}","switchThemePlugin");
		if (params[0] && (params[0].substr(0,6)=="width:"))	var width=(params.shift()).substr(6);
		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);
		if (params[0] && params[0].trim().length) // create a link that sets a specific theme
			createTiddlyButton(place,label?label:params[0],prompt?prompt:params[0],
				function(){ config.macros.switchTheme.set(params[0]); return false;});
		else { // create a select list of available themes
			var theList=createTiddlyElement(place,"select",null,"switchTheme",null);
			theList.size=1;
			if (width) theList.style.width=width;
			theList.onchange=function() { config.macros.switchTheme.set(this.value); return true; };
			this.refresh(theList);
		}
	},
	refresh: function(list) {
		var indent = String.fromCharCode(160)+String.fromCharCode(160);
		while(list.length > 0){list.options[0]=null;} // clear list
		list.options[list.length] = new Option("select a theme:","",true,true);
		list.options[list.length] = new Option(indent+"[default]","StyleSheet");
		list.options[list.length] = new Option(indent+"[random]","*");
		var themes=store.getTaggedTiddlers("systemTheme");
		for (var i=0; i<themes.length; i++)
			if (themes[i].title!="StyleSheet" && !themes[i].isTagged('excludeLists'))
				list.options[list.length]=new Option(indent+themes[i].title,themes[i].title);
		// show current selection
		for (var t=0; t<list.options.length; t++)
			if (list.options[t].value==config.options.txtTheme)
				{ list.selectedIndex=t; break; }
	},
	set: function(theme) {
		if (!theme||!theme.trim().length) return;
		if (theme=="*") { // select a random theme (except themes with "excludeTheme")
			var curr=config.options.txtTheme;
			var themes=store.getTaggedTiddlers("systemTheme");
			if (!themes.length) return false;
			var which=Math.floor(Math.random()*themes.length);
			while (themes[which].title==curr
				||themes[which].tags.contains('excludeTheme','excludeLists'))
					which=Math.floor(Math.random()*themes.length);
			theme=themes[which].title;
		}
		// apply selected theme
		story.switchTheme(theme);
		// sync theme droplists
		var elems=document.getElementsByTagName("select");
		var lists=[]; for (var i=0; i<elems.length; i++)
			if (hasClass(elems[i],"switchTheme")) lists.push(elems[i]);
		for (var k=0; k<lists.length; k++)
			for (var t=0; t<lists[k].options.length; t++)
				if (lists[k].options[t].value==config.options.txtTheme)
					{ lists[k].selectedIndex=t; break; }
		return;
	}
}
//}}}
// // option to select a random theme at startup (if enabled)
//{{{
if (config.options.chkRandomTheme===undefined)
	config.options.chkRandomTheme=false;
if (config.options.chkRandomTheme)
	config.macros.switchTheme.set("*");
//}}}
// // hijack switchTheme to add Check/Init/Reset code handlers
//{{{
if (Story.prototype.switchTheme_saved===undefined) { // only once
Story.prototype.switchTheme_saved=Story.prototype.switchTheme;
Story.prototype.switchTheme=function(t){
	function run(t,s){
		var f=store.getTiddlerText(store.getTiddlerSlice(t,s));
		return f?eval('(function(){\n'+f+'\n})()'):false;
	}
	if (!startingUp && (run(config.options.txtTheme,'Reset')||run(t,'Check'))) return;
	this.switchTheme_saved.apply(this,arguments);
	run(t,'Init');
}
}
//}}}
/***
|Name|SwitchThemePluginInfo|
|Source|http://www.TiddlyTools.com/#SwitchThemePlugin|
|Documentation|http://www.TiddlyTools.com/#SwitchThemePluginInfo|
|Version|5.4.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.3|
|Type|documentation|
|Description|documentation for SwitchThemePlugin|
This plugin replaces the features previously provided by SelectStylesheetPlugin, and uses the ''TiddlyWiki core "theme" mechanism'' to select alternative templates and styles.  ''//This plugin requires TiddlyWiki version 2.3.0 or later//''
!!!!!Usage
<<<
{{medium{__Defining a theme:__}}}
First, create/import a tiddler containing CSS definitions and tag it with<<tag systemTheme>>.  At the top of the tiddler, embed a //slice table// with at least one slice, "~StyleSheet", whose value is the name of the tiddler itself, e.g., in a tiddler called [[MyTheme]], write:
{{{
/***
|StyleSheet|MyTheme|
***/
}}}
>Note use of {{{/***}}} and {{{***/}}} around the slice table.   This syntax allows the browser to skip over the slice table definition when processing the ~CSS-syntax embedded within the tiddler.
A theme tiddler can also define one or more additional slices that associate customized versions of [[PageTemplate]], [[ViewTemplate]], and/or [[EditTemplate]], for use with that theme:
{{{
/***
|PageTemplate|MyPageTemplate|
|ViewTemplate|MyViewTemplate|
|EditTemplate|MyEditTemplate|
***/
}}}
where the slice //name// is the standard template name, and the slice //value// is the title of the alternative custom template to use.  You can also associate a secondary set of ''"read only" templates that will be automatically applied whenever a document is being viewed online'' (i.e., via http: protocol)
{{{
|PageTemplateReadOnly|MyWebPageTemplate|
|ViewTemplateReadOnly|MyWebViewTemplate|
|EditTemplateReadOnly|MyWebEditTemplate|
}}}
These alternative templates can be used to present a reduced-feature "reader" interface when viewed on-line by others, while still offering a full-featured "author" interface when working locally.

In addition to the TW core slices described above, the plugin allows you to define extra slices that refer to tiddlers (or tiddler sections) containing ''custom javascript code that can be invoked whenever theme switching occurs''.  A theme can include any of the following special plugin-enhanced slices:
{{{
|Check|MyThemeCheck|
|Init|MyThemeInit|
|Reset|MyThemeReset|
}}}
*{{block{
The code referenced by the ''Check'' slice (if any) is invoked ''before switching'' to a selected theme.  ''If this code returns a non-zero (or true) result, then the new theme will not be applied.  A zero (or false) value allows the theme switch to continue as usual.''  For example, the following code asks for confirmation, allowing the user to cancel the theme switch:
{{{
return !confirm('Are you sure you want to use this theme?');
}}}
}}}
*After a theme has been applied, the code referenced by the ''Init'' slice (if any) is invoked.  This can be used to perform theme-related ''side-effects'', such as modifying various {{{config.options['...']}}} settings or displaying instructions/messages.
*When switching to another theme, any code referenced by a ''Reset'' slice //in the current theme// is invoked before the new theme is applied.  ''If this code returns a non-zero result, then the new theme will not be applied.''  As with the ''Check'' code, this can be used to ask the user to confirm before switching themes.  However, the primary intent of the ''Reset'' code is to permit restoration any modified settings that were altered by ''Init'' code that was previously invoked for the current theme.

{{medium{__Selecting a theme from a droplist:__}}}
To display a droplist of available themes, use this syntax:
{{{
<<switchTheme width:nnn>>
}}}
*''width:nnn[cm|px|em|%]'' (optional)<br>specifies the width of the droplist (using CSS measurements)(default=100%)
All tiddlers tagged with<<tag systemTheme>> will be included in the droplist of available themes for you to select (except those also tagged with <<tag excludeLists>>.  The current selection is stored in a TiddlyWiki option cookie ("txtTheme") that is applied automatically each time you reload your document.  If the selected theme does not exist in the document (e.g., it was deleted/renamed after being selected), the [default] CSS tiddler, [[StyleSheet]], will be used as a fallback.  If [random] is seleced, the plugin automatically selects a random theme.  You can exclude a theme from being randomly selected by tagging it with <<tag excludeTheme>>.

Example:
{{{<<switchTheme width:30%>>}}}
<<switchTheme width:30%>>

{{medium{__Selecting a theme from a command link:__}}}
The {{{<<switchTheme>>}}} macro can also be used to embed a command link that, when clicked, will apply a specific, pre-selected theme, using the following syntax:
{{{
<<switchTheme "label:link text" "prompt:tooltip text" TiddlerName>>
}}}
* ''label:text'' and ''prompt:text'' (optional)<br>define the link text the 'tooltip' text that appears near the mouse pointer when placed over the link, respectively.
*''~TiddlerName''<br>specifies the name of the theme tiddler to be applied (e.g., {{{<<switchTheme [[Woodshop]]>>}}}
Examples:
{{{
<<switchTheme Plain>>
<<switchTheme Blackout>> 
<<switchTheme Woodshop>>
<<switchTheme Textures>>
<<switchTheme [[Edge of Night]]>>
<<switchTheme label:[default] StyleSheet>>
<<switchTheme label:randomize *>>
}}}
<<switchTheme Plain>> <<switchTheme Blackout>> <<switchTheme Woodshop>> <<switchTheme Textures>> <<switchTheme [[Edge of Night]]>> <<switchTheme label:[default] StyleSheet>> <<switchTheme label:randomize *>>

NOTE:
>You can also create a command link that specifies "*" for the theme name.  This will select a theme //at random// from the list of available themes.  To prevent a given theme from being selected, tag it with <<tag excludeTheme>>.
<<<
!!!!!Configuration
<<<
<<option chkRandomTheme>> select a random theme at startup
//Note: to prevent a given theme from being chosen at random, tag it with <<tag excludeTheme>>//
<<<
!!!!!Revisions
<<<
2009.10.01 5.4.1 changed 'noRandom' tag to 'excludeTheme' and recognize 'excludeLists' tag
2009.09.28 5.4.0 added Check/Init/Reset slices for invoking code during theme switching
2008.04.23 5.3.0 added option for chkRandomTheme (select random theme at startup)
2008.04.13 5.2.0 moved TW2.3.x fixup for core's switchTheme() function to [[SwitchThemePluginPatch]] and simplified random theme handling.  Also, changed "Web*" prefix to "*ReadOnly" suffix for compatibility with TW240 core convention.
2008.02.01 5.1.3 in response to a change for core ticket #435 (see http://trac.tiddlywiki.org/changeset/3450) -- in switchTheme, use config.refresherData.* values (if defined), instead of config.refreshers.*  This change allows the plugin to work with both the current release (~TW230) AND the upcoming ~TW240 release.
2008.02.01 5.1.2 in switchTheme, replace hard-coded "~StyleSheet" with config.refreshers.stylesheet (used as name of loaded styles)
2008.01.30 5.1.1 changed tag-detection to use "systemTheme" instead of "theme" for compatibility with core theme switching mechanism.
2008.01.26 5.1.0 added support for txtTheme="*" (applies random theme at startup) and {{{<<randomTheme>>}}} macro (selects/applies a random theme when a command link is clicked)
2008.01.25 5.0.1 in refresh() and set(), removed use of ">" to indicate current theme 
2008.01.22 5.0.0 Completely re-written and renamed from [[SelectStylesheetPlugin]] (now retired)
>//previous history for [[SelectStylesheetPlugin]] omitted//
2005.07.20 1.0.0 Initial Release
<<<
/***
|Name|SwitchThemePluginPatch|
|Source|http://www.TiddlyTools.com/#SwitchThemePluginPatch|
|Documentation|http://www.TiddlyTools.com/#SwitchThemePluginPatch|
|Version|5.2.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.3|
|Type|plugin|
|Description|Patch core switchTheme() function for backward-compatibility with TW2.3.0 and earlier|
!!!!!Usage
<<<
This "patch" plugin provides backward-compatibility needed to enable [[SwitchThemePlugin]] to operate correctly under TW2.3.x or earlier.
{{medium{You should not install this plugin if you are using TW2.4.0 or above}}}
<<<
!!!!!Revisions
<<<
2008.05.09 [5.2.1] Simplified patch code for use with TW230 ONLY - NOT NEEDED FOR TW240 or above
2008.04.13 [5.2.0] moved from SwitchThemePlugin and updated for TW240b1.  Patch code will be simplified further once TW240 final release is available.
<<<
!!!!!Code
***/
//{{{
// OVERRIDE OF CORE story.switchTheme()
// for use with TW230, which uses config.refreshers, while TW240 uses config.refresherData
// also provides fallback for existing Web* slice naming convention
if (!config.refresherData) { // DETECT TW2.3
Story.prototype.switchTheme = function(theme)
{
	if(safeMode) 
		return;
		
	isAvailable = function(title) { 
		var s = title ? title.indexOf(config.textPrimitives.sectionSeparator) : -1; 
		if(s!=-1) 
			title = title.substr(0,s); 
		return store.tiddlerExists(title) || store.isShadowTiddler(title); 
 	};

	getSlice = function(theme,slice) {
		if(readOnly)
			var r = store.getTiddlerSlice(theme,slice+"ReadOnly")
		            || store.getTiddlerSlice(theme,"Web"+slice); // fallback naming convention
		var r = r || store.getTiddlerSlice(theme,slice);
		if(r && r.indexOf(config.textPrimitives.sectionSeparator)==0)
			r = theme + r;
		return isAvailable(r) ? r : slice;
	};

	replaceNotification = function(i,name,theme,slice) {
		var newName = getSlice(theme,slice);
		if(name!=newName && store.namedNotifications[i].name==name) {
			store.namedNotifications[i].name = newName;
			return newName;
		}
		return name;
	};

	var pt = config.refreshers.pageTemplate;
	var vi = DEFAULT_VIEW_TEMPLATE;
	var vt = config.tiddlerTemplates[vi];
	var ei = DEFAULT_EDIT_TEMPLATE;
	var et = config.tiddlerTemplates[ei];

	for(var i=0; i<config.notifyTiddlers.length; i++) {
		var name = config.notifyTiddlers[i].name;
		switch(name) {
		case "PageTemplate":
			config.refreshers.pageTemplate = replaceNotification(i,config.refreshers.pageTemplate,theme,name);
			break;
		case "StyleSheet":
			removeStyleSheet(config.refreshers.styleSheet);
			config.refreshers.styleSheet = replaceNotification(i,config.refreshers.styleSheet,theme,name);
			break;
		case "ColorPalette":
			config.refreshers.colorPalette = replaceNotification(i,config.refreshers.colorPalette,theme,name);
			break;
		default:
			break;
		}
	}
	config.tiddlerTemplates[vi] = getSlice(theme,"ViewTemplate");
	config.tiddlerTemplates[ei] = getSlice(theme,"EditTemplate");
	if(!startingUp) {
		var switchedTemplates=config.refreshers.pageTemplate!=pt || config.tiddlerTemplates[vi]!=vt || config.tiddlerTemplates[ei]!=et;
		if(switchedTemplates) {
			refreshAll();
			story.refreshAllTiddlers(true);
		} else {
			setStylesheet(store.getRecursiveTiddlerText(config.refreshers.styleSheet,"",10),config.refreshers.styleSheet);
		}
		config.options.txtTheme = theme;
		saveOptionCookie("txtTheme");
	}
};
} // end if (!config.refresherData) 
//}}}
/***
|Name|SystemInfoPlugin|
|Source|http://www.TiddlyTools.com/#SystemInfoPlugin|
|Version|1.7.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|view system internal data and settings|
~TidIDE (//prounounced "Tie Dyed"//) - ''Tid''dlyWiki ''I''ntegrated ''D''evelopment ''E''nvironment - tools for ~TiddlyWiki authors and editors.  

You can use the {{{<<systemInfo>>}}} control panel to view a variety of system internal data and functions, and view/modify ''all'' of ~TiddlyWiki's internal config.option.* settings.  NOTE: Non-default config.options are stored in cookies and are retrieved whenever the TW document is loaded into a browser; however, ''core TW functions and custom-defined plugins can explicitly ignore or reset any locally-stored cookie values and use their own, internally-defined values'' instead.  As a result, changes to these may be completely ignored, or may only have an effect during the current TW document "session" (i.e., until the TW document is reloaded), even though a persistent cookie value has been saved.
!!!!!Usage/Example
<<<
{{{<<systemInfo>>}}}
{{smallform{<<systemInfo>>}}}
<<<
!!!!!Revisions
<<<
''2007.10.31 [1.7.1]'' code reduction: when filling globals droplist, instead of using a large, static "global exclusion list", simply skip global *functions*, while still listing all other global properties, including key TW internal objects such as "config".
''2007.09.09 [1.7.0]'' split from TidIDEPlugin
|please see [[TidIDEPluginInfo]] for additional revision details|
''2006.04.15 [0.5.0]'' Initial ALPHA release. Converted from inline script.
<<<
!!!!!Code
***/
//{{{
version.extensions.SystemInfoPlugin= {major: 1, minor: 7, revision: 1, date: new Date(2006,10,31)};
config.shadowTiddlers.SystemInfo="<<systemInfo>>";
config.macros.systemInfo = {
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		var span=createTiddlyElement(place,"span")
		span.innerHTML=this.html;
		this.getsys(span.getElementsByTagName("form")[0]); // initialize form
	},
	getsys: function(f) {
		f.sysview.value="";

		// OPTIONS
		while (f.sys_opts.options.length > 1) { f.sys_opts.options[1]=null; } // clear list
		f.config_view.value="";  // clear edit field
		var cookies = { };
		if (document.cookie != "") {
			var p = document.cookie.split("; ");
			for (var i=0; i < p.length; i++) {
				var pos=p[i].indexOf("=");
				if (pos==-1)
					cookies[p[i]]="";
				else
					cookies[p[i].substr(0,pos)]=unescape(p[i].slice(pos+1));
			}
		}
		var c=1;
		var opt=new Array(); for (var i in config.options) opt.push(i); opt.sort();
		for(var i=0; i<opt.length; i++) {
			if ((opt[i].substr(0,3)=="txt")||(opt[i].substr(0,3)=="chk")) {
				var txt = (opt[i].substr(0,3)=="chk"?("["+(config.options[opt[i]]?"x":"_")+"] "):"")+opt[i]+(cookies[opt[i]]?" (cookie)":"");
				var val = config.options[opt[i]];
				f.sys_opts.options[c++]=new Option(txt,val,false,false);
			}
		}

		// STYLESHEETS
		while (f.sys_styles.options.length > 1) { f.sys_styles.options[1]=null; } // clear list
		var c=1;
		var styles=document.getElementsByTagName("style");
		for(var i=0; i < styles.length; i++) {
			var id=styles[i].getAttribute("id"); if (!id) id="(default)";
			var txt=id;
			var val="/* stylesheet:"+txt+" */\n"+styles[i].innerHTML;
			f.sys_styles.options[c++]=new Option(txt,val,false,false);
		}

		// SHADOWS
		while (f.sys_shadows.options.length > 1) { f.sys_shadows.options[1]=null; } // clear list
		var c=1;
		for(var s in config.shadowTiddlers) f.sys_shadows.options[c++]=new Option(s,config.shadowTiddlers[s],false,false);

		// NOTIFICATIONS
		while (f.sys_notify.options.length > 1) { f.sys_notify.options[1]=null; } // clear list
		var c=1;
		for (var i=0; i<store.namedNotifications.length; i++) {
			var n = store.namedNotifications[i];
			var fn = n.notify.toString();
			fn = fn.substring(fn.indexOf("function ")+9,fn.indexOf("{")-1);
			var txt=(n.name?n.name:"any change")+"="+fn;
			var val="/* notify: "+txt+" */\n"+n.notify.toString();
			f.sys_notify.options[c++]=new Option(txt,val,false,false);
		}

		// MACROS
		while (f.sys_macros.options.length > 1) { f.sys_macros.options[1]=null; } // clear list
		var c=1;
		var macros=new Array(); for (var m in config.macros) macros.push(m); macros.sort();
		for(var i=0; i < macros.length; i++)
			f.sys_macros.options[c++]=new Option(macros[i],this.showObject(config.macros[macros[i]]),false,false);

		// COMMANDS
		while (f.sys_commands.options.length > 1) { f.sys_commands.options[1]=null; } // clear list
		var c=1;
		for(var cmd in config.commands)
			f.sys_commands.options[c++]=new Option(cmd,this.showObject(config.commands[cmd]),false,false);

		// FORMATTERS
		while (f.sys_formatters.options.length > 1) { f.sys_formatters.options[1]=null; } // clear list
		var c=1;
		for(var i=0; i < config.formatters.length; i++)
			f.sys_formatters.options[c++]=new Option(config.formatters[i].name,this.showObject(config.formatters[i]),false,false);

		// PARAMIFIERS
		while (f.sys_params.options.length > 1) { f.sys_params.options[1]=null; } // clear list
		var c=1;
		for(var param in config.paramifiers)
			f.sys_params.options[c++]=new Option(param,this.showObject(config.paramifiers[param]),false,false);

		// GLOBALS
		//global variables and functions (excluding most DOM and ~TiddyWiki core definitions)://
		while (f.sys_globals.options.length > 1) { f.sys_globals.options[1]=null; } // clear list
		if (config.browser.isIE) return; // BYPASS - 8/16/2006 // DON'T LIST GLOBALS IN IE... throws object error - WFFL
		try {
			var c=1;
			for (var v in window) if ((typeof window[v])!='function') {
				var t=window[v];
				if ((typeof window[v])=='object') {
					var t='';
					for (var p in window[v]) {
						t+=((typeof window[v][p])!='function')?('['+typeof window[v][p]+'] '+p):p;
						t+=((typeof window[v][p])!='function')?('='+window[v][p]):'';
						t+='\n';
					}
				}
				f.sys_globals.options[c++]=new Option(((typeof window[v])!='function')?('['+typeof window[v]+'] '+v):v,t,false,false);
			}	
		}
		catch(e) { ; }
	},
	setsys: function(f) {
		if (f.sys_opts.selectedIndex==0) return; // heading - do nothing
		var name=f.sys_opts.options[f.sys_opts.selectedIndex].text.replace(/\[[Xx_]\] /,'').replace(/ \(cookie\)/,'')
		var value=f.config_view.value;
		config.options[name]=value;
		saveOptionCookie(name);
		f.sys_opts.options[f.sys_opts.selectedIndex].value=value;
		return;
	},
	showObject: function(o) { // generate formatted output for displaying object references
		var t="";
		for (var p in o) {
			if (typeof o[p]=="function") {
				t+="- - - - - - - - - - "+p+" - - - - - - - - - -\n";
				t+=o[p].toString();
				t+="\n- - - - - - - - - - END: "+p+" - - - - - - - - - -\n";
			}
			else
				t+='['+typeof o[p]+'] '+p+": "+o[p]+"\n";
		}
		return t;
	},
	html: "\
	<form style='display:inline;margin:0;padding:0;'> \
		<!-- configurable options --> \
		<table style='width:100%;border:0;padding:0;margin:0'><tr style='border:0;padding:0;margin:0'> \
		<td style='width:30%;border:0;padding:0;margin:0'> \
			<select size=1 name='sys_opts' style='width:100%;' \
				onchange='this.form.config_view.value=this.value'> \
				<option value=\"\">config.options.*</option> \
			</select> \
		</td><td style='width:50%;border:0;padding:0;margin:0;'> \
			<input type=text name='config_view' size=60 style='width:99%;' value=''> \
		</td><td style='width:20%;white-space:nowrap;border:0;padding:0;margin:0;'> \
			<input type=button style='width:50%;' value='set option' title='save this TiddlyWiki option value' \
				onclick='config.macros.systemInfo.setsys(this.form);config.macros.systemInfo.getsys(this.form);'><!-- \
			--><input type=button style='width:50%;' value='refresh' title='retrieve current options and system values' \
				onclick='this.form.sysview.style.display=\"none\"; config.macros.systemInfo.getsys(this.form);'> \
		</td></tr><tr style='border:0;padding:0;margin:0'><td colspan=3 \
				style='white-space:nowrap;width:100%;border:0;padding:0;margin:0'> \
			<!-- system objects --> \
			<select size=1  name='sys_styles' style='width:25%;' \
				onchange='this.form.sysview.style.display=\"block\"; this.form.sysview.value=this.value'> \
				<option value=\"\">stylesheets...</option> \
			</select><select size=1  name='sys_shadows' style='width:25%;' \
				onchange='this.form.sysview.style.display=\"block\"; this.form.sysview.value=this.value'> \
				<option value=\"\">shadows...</option> \
			</select><select size=1  name='sys_notify' style='width:25%;' \
				onchange='this.form.sysview.style.display=\"block\"; this.form.sysview.value=this.value'> \
				<option value=\"\">notifications...</option> \
			</select><select size=1  name='sys_globals' style='width:25%;' \
				onchange='this.form.sysview.style.display=\"block\"; this.form.sysview.value=this.value'> \
				<option value=\"\">globals...</option> \
			</select><br><select size=1  name='sys_macros' style='width:25%;' \
				onchange='this.form.sysview.style.display=\"block\"; this.form.sysview.value=this.value'> \
				<option value=\"\">macros...</option> \
			</select><select size=1  name='sys_commands' style='width:25%;' \
				onchange='this.form.sysview.style.display=\"block\"; this.form.sysview.value=this.value'> \
				<option value=\"\">commands...</option> \
			</select><select size=1  name='sys_formatters' style='width:25%;' \
				onchange='this.form.sysview.style.display=\"block\"; this.form.sysview.value=this.value'> \
				<option value=\"\">formatters...</option> \
			</select><select size=1  name='sys_params' style='width:25%;' \
				onchange='this.form.sysview.style.display=\"block\"; this.form.sysview.value=this.value'> \
				<option value=\"\">paramifiers...</option> \
			</select> \
			<!-- system value display area --> \
			<span style='white-space:normal;'><textarea id='sysview' name=sysview cols=60 rows=12 \
				onfocus='this.select()' style='width:99.5%;height:16em;display:none'></textarea></span> \
		</td></tr></table> \
	</form>"
}
//}}}
/***
|Name|TableOfContentsPlugin|
|Source|http://www.TiddlyTools.com/#TableOfContentsPlugin|
|Documentation|http://www.TiddlyTools.com/#TableOfContentsPluginInfo|
|Version|2.4.3|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|replace the standard tabbed contents list with a scrolling listbox|
When there are many tiddlers in a document, the standard 'tabbed list of tiddlers' in the right-hand sidebar can become very long, occupying a lot of page space and requiring a lot scrolling in order to locate and select a tiddler.  The TableOfContentsPlugin addresses this problem by replacing the standard tabbed list display with a single listbox/droplist control that uses a very small amount of page space, regardless of the number of tiddlers in the document.
!!!!!Documentation
>see [[TableOfContentsPluginInfo]]
!!!!!Configuration
<<option chkTOCShow>> display table of contents listbox
<<option chkTOCIncludeHidden>> include tiddlers tagged with <<tag excludeLists>> in listbox
listbox shows <<option txtTOCListSize>> lines, sorted by <<option txtTOCSortBy>>
!!!!!Revisions
<<<
2008.04.09 [2.4.3] restored config.options.chkTOCShow and onClickTOCMenu() handler
|please see [[TableOfContentsPluginInfo]] for additional revision details|
2005.06.13 [1.0.0] Initial Release (as adaptation - predates TiddlyWiki plugin architecture!!)
<<<
!!!!!Code
***/
//{{{
version.extensions.TableOfContentsPlugin= {major: 2, minor: 4, revision: 3, date: new Date(2008,4,9)};
//}}}

// // 1.2.x compatibility
//{{{
if (!window.story) window.story=window;
if (!store.getTiddler) store.getTiddler=function(title){return store.tiddlers[title]}
if (!store.addTiddler) store.addTiddler=function(tiddler){store.tiddlers[tiddler.title]=tiddler}
if (!store.deleteTiddler) store.deleteTiddler=function(title){delete store.tiddlers[title]}
//}}}

//{{{
// define defaults for cookie-based option values
if (config.options.txtTOCSortBy==undefined)	config.options.txtTOCSortBy="modified";
if (config.options.txtTOCListSize==undefined)	config.options.txtTOCListSize=19;
if (config.options.chkTOCShow==undefined)	config.options.chkTOCShow=true;
if (config.options.chkTOCIncludeHidden==undefined)	config.options.chkTOCIncludeHidden=false;

// define macro "tableOfContents" to render controls
config.macros.tableOfContents = { label: "contents" };
config.macros.tableOfContents.cmdMax=8; // index of maximum command item

config.macros.tableOfContents.css = '\
.TOC { padding:0.5em 1em 0.5em 1em; }\
.TOC a { padding:0em 0.25em 0em 0.25em; color:inherit; }\
.TOCList { width: 100%; font-size:8pt; margin:0em; }\
';

config.macros.tableOfContents.html = '\
<div style="text-align:right">\
	<span style="float:left">\
	<a href="JavaScript:;" id="TOCMenu" style="padding: 0em;"\
		onclick="onClickTOCMenu(this)" title="show/hide table of contents">%label%</a>\
	</span>\
	<a href="JavaScript:;" id="TOCSmaller" style="display:inline"\
		onclick="resizeTOC(this)" title="reduce list size">&#150;</a>\
	<a href="JavaScript:;" id="TOCLarger"style="display:inline"\
		onclick="resizeTOC(this)" title="increase list size">+</a>\
	<a href="JavaScript:;" id="TOCMaximize"style="display:inline"\
		onclick="resizeTOC(this)" title="maximize/restore list size">=</a>\
</div>\
';

config.macros.tableOfContents.handler = function(place,macroName,params) { 
	var parsedParams = new Array();
	parsedParams['label']=this.label;
	parsedParams['inline']=false;
	while (params.length>0) {
		if (params[0]=="label:none") parsedParams['label']="";
		else if (params[0].substr(0,6)=="label:") parsedParams['label']=params[0].substr(6);
		if (params[0].substr(0,7)=="prompt:") parsedParams['prompt']=params[0].substr(7);
		if (params[0].substr(0,8)=="padding:")parsedParams['padding']=params[0].substr(8);
		if (params[0].substr(0,7)=="margin:") parsedParams['margin']=params[0].substr(7);
		if (params[0].substr(0,5)=="sort:")   parsedParams['sortby']=params[0].substr(5);
		if (params[0].substr(0,5)=="date:")   parsedParams['date']=params[0].substr(5);
		if ((params[0]=="size:auto")||(params[0]=="size:0")) parsedParams['autosize']=true;
		else if (params[0] && (params[0].substr(0,5)=="size:")) parsedParams['requestedSize']=params[0].substr(5);
		if (params[0].substr(0,6)=="width:") parsedParams['width']=params[0].substr(6);
		if (params[0]=="hidelist") parsedParams['hidelist']=true;
		if (params[0]=="inline")   parsedParams['inline']=true;
		if (params[0]=="-title")   parsedParams['hide_title']=true;
		if (params[0]=="-date")    parsedParams['hide_date']=true;
		if (params[0]=="-author")  parsedParams['hide_author']=true;
		if (params[0]=="-creator") parsedParams['hide_creator']=true;
		if (params[0]=="-tags")    parsedParams['hide_tags']=true;
		if (params[0]=="-missing") parsedParams['hide_missing']=true;
		if (params[0]=="-orphans") parsedParams['hide_orphans']=true;
		if (params[0]=="-shadows") parsedParams['hide_shadows']=true;
		params.shift(); 
	}
	setStylesheet(config.macros.tableOfContents.css,"tableOfContents");
	var newTOC=createTiddlyElement(place,parsedParams['inline']?"span":"div",null,"TOC",null)
	if (parsedParams['margin'])	{ newTOC.style.margin=parsedParams['margin']; }
	if (parsedParams['padding'])	{ newTOC.style.padding=parsedParams['padding']; }
	if (parsedParams['label']!="") newTOC.innerHTML=config.macros.tableOfContents.html.replace(/%label%/,parsedParams['label']);
	var newTOCList=createTOCList(newTOC,parsedParams)
	refreshTOCList(newTOCList);
	store.addNotification(null,reloadTOCLists);	// reload listbox after every tiddler change
}

// IE needs explicit global scoping for functions/vars called from browser events
window.onChangeTOCList=onChangeTOCList;
window.onClickTOCList=onClickTOCList;
window.onDblClickTOCList=onDblClickTOCList;
window.reloadTOCLists=reloadTOCLists;
window.refreshTOCList=refreshTOCList;
window.onClickTOCMenu=onClickTOCMenu;
window.resizeTOC=resizeTOC;
	
function createTOCList(place,params) {
	var list = createTiddlyElement(place,"select",null,"TOCList",params['prompt'])
	list.params=params;
	list.onchange=onChangeTOCList;
	list.onclick=onClickTOCList;
	list.ondblclick=onDblClickTOCList;
	list.onkeyup=onKeyUpTOCList;
	list.style.display=config.options.chkTOCShow ? "block" : "none" ;
	list.sortBy=config.options.txtTOCSortBy;
	list.dateFormat="DD MMM YYYY";
	list.requestedSize=config.options.txtTOCListSize;
	list.expandall=false;
	list.cmdMax=config.macros.tableOfContents.cmdMax;
	if (params['hide_title'])   list.cmdMax--;
	if (params['hide_date'])    list.cmdMax--;
	if (params['hide_author'])  list.cmdMax--;
	if (params['hide_creator']) list.cmdMax--;
	if (params['hide_tags'])    list.cmdMax--;
	if (params['hide_missing']) list.cmdMax--;
	if (params['hide_orphans']) list.cmdMax--;
	if (params['hide_shadows']) list.cmdMax--;
	if (params['sortby'])       { list.sortBy=params['sortby']; list.noSortCookie=true; }
	if (params['date'])         { list.dateFormat=params['date']; }
	if (params['autosize'])     { list.autosize=true; list.noSizeCookie=true; }
	if (params['requestedSize']){ list.requestedSize=params['requestedSize']; list.noSizeCookie=true; }
	if (params['width'])        { list.style.width=params['width']; }
	if (params['hidelist'])     { list.style.display ="none" ; list.noShowCookie=true; }
	if (params['expandall'])    { list.expandall=true; }
	return list;
}

function onChangeTOCList() {
	var thisTiddler=this.options[this.selectedIndex].value;
	if ((this.size==1)&&(thisTiddler!='')&&(this.selectedIndex>this.cmdMax))
		story.displayTiddler(null,thisTiddler,1);
	refreshTOCList(this);
	return false;
}
function onClickTOCList(e) {
	if (!e) var e = window.event;
	if (this.size==1) return; // don't toggle display for droplist
	if (e.shiftKey) { this.expandall=!this.expandall; refreshTOCList(this);}
	e.cancelBubble = true; if (e.stopPropagation) e.stopPropagation();
	return true;
}
function onDblClickTOCList(e) {
	if (!e) var e = window.event;
	var thisTiddler=this.options[this.selectedIndex].value;
	if ((thisTiddler!='')&&(this.selectedIndex>this.cmdMax))
		story.displayTiddler(null,thisTiddler,1);
	e.cancelBubble = true; if (e.stopPropagation) e.stopPropagation();
	return false;
}
function onKeyUpTOCList(e) {
	if (!e) var e = window.event;
	if (e.keyCode!=13) return true;
	var thisTiddler=this.options[this.selectedIndex].value;
	if ((thisTiddler!='')&&(this.selectedIndex>this.cmdMax))
		story.displayTiddler(null,thisTiddler,1);
	e.cancelBubble = true; if (e.stopPropagation) e.stopPropagation();
	return false;
}
function reloadTOCLists() {
	var all=document.all? document.all.tags("select") : document.getElementsByTagName("select");
	for (var i=0; i<all.length; i++)
		if (all[i].className=="TOCList")
			{ all[i].selectedIndex=-1; refreshTOCList(all[i]); }
}
 
function refreshTOCList(list) {
	var selectedIndex = list.selectedIndex;
	if (selectedIndex==-1) selectedIndex=0;
	var sortBy = list.sortBy;
	var showHidden = config.options.chkTOCIncludeHidden && !(config.options.chkHttpReadOnly && readOnly);

	if (selectedIndex==0) sortBy=list.sortBy;	// "nnn tiddlers" heading - use previous sort order
	else if (selectedIndex<=list.cmdMax)sortBy=list.value;
	else { if (list.options[list.selectedIndex].value=='') expandTOC(list); return; }

	list.sortBy = sortBy; // save current sort order
	if (!list.noSortCookie) { config.options.txtTOCSortBy=sortBy; saveOptionCookie("txtTOCSortBy"); }

	// get the list of tiddlers
	var tiddlers = [];
	switch (sortBy) {
		case "missing":	tiddlers=store.getMissingLinks(); break;
		case "tags": tiddlers=store.getTags(); break;
		case "orphans":	tiddlers=store.getOrphans(); break;
		case "shadows": for (var t in config.shadowTiddlers) tiddlers.push(t); tiddlers.sort();	break;
		default: tiddlers=store.getTiddlers(sortBy=='creator'?'modifier':sortBy,showHidden?'':'excludeLists'); break;
	}

	// clear current listbox contents
	while (list.length > 0) { list.options[0] = null; }
	list.saved=null;

	// add heading and control items to list
	var i=0;
	var theHeading=tiddlers.length+' tiddlers:';
	if (sortBy=='missing') theHeading=tiddlers.length+' missing tiddlers:';
	if (sortBy=='orphans') theHeading=tiddlers.length+' orphaned tiddlers:';
	if (sortBy=='tags')    theHeading=tiddlers.length+' tags:';
	if (sortBy=='shadows') theHeading=tiddlers.length+' shadow tiddlers:';
	var indent=String.fromCharCode(160)+String.fromCharCode(160);
	var sel=">";
	list.options[i++]=new Option(theHeading,'');
	function headerOpt(txt,val) { return new Option(((sortBy==val)?sel:indent)+' ['+txt+']',val); }
	if (!list.params['hide_title'])   list.options[i++]=headerOpt('by title','title');
	if (!list.params['hide_date'])    list.options[i++]=headerOpt('by date','modified');
	if (!list.params['hide_author'])  list.options[i++]=headerOpt('by author','modifier');
	if (!list.params['hide_creator']) list.options[i++]=headerOpt('by creator','creator');
	if (!list.params['hide_tags'])    list.options[i++]=headerOpt('by tags','tags');
	if (!list.params['hide_missing']) list.options[i++]=headerOpt('missing','missing');
	if (!list.params['hide_orphans']) list.options[i++]=headerOpt('orphans','orphans');
	if (!list.params['hide_shadows']) list.options[i++]=headerOpt('shadows','shadows');
	// output the tiddler list
	switch(sortBy) {
		case "title":
			for (var t = 0; t < tiddlers.length; t++)
				list.options[i++] = new Option(tiddlers[t].title,tiddlers[t].title);
			break;
		case "modified":
		case "modifier":
		case "creator":
			if (sortBy=="modified") tiddlers.reverse(); // show newest first
			if (sortBy=="creator") { // sort by custom field with fallback value
				tiddlers.sort(function (a,b) {
					var v1=a.fields.creator||a.modifier;
					var v2=b.fields.creator||b.modifier;
					return (v1==v2)?0:(v1>v2?1:-1);
				});
			}
			var lastSection = "";
			for (var t = 0; t < tiddlers.length; t++){
				var tiddler = tiddlers[t];
				var theSection = "";
				var m=tiddler.modified;
				if (sortBy=="modified") theSection=m.getFullYear()+'.'+(m.getMonth()+1)+'.'+m.getDate();
				if (sortBy=="modifier") theSection = tiddler.modifier;
				if (sortBy=="creator") theSection=tiddler.fields['creator']||tiddler.modifier;
				if (theSection != lastSection) {
					lastSection = theSection;
					if (sortBy=="modified") theSection = m.formatString(list.dateFormat);
					list.options[i++] = new Option('+ '+theSection,"");
				}
				list.options[i++] = new Option(indent+indent+tiddler.title,tiddler.title);
			}
			expandTOC(list);
			break;
		case "tags":
			// tagged tiddlers, by tag
			var tagcount=0;
			var lastTag = null;
			for (var t = 0; t < tiddlers.length; t++) {  // actually a list of tags, not tiddlers... 
				var theTag = tiddlers[t][0]; var tid=store.getTiddler(theTag);
				if (tid && tid.isTagged('excludeLists')) continue; // skip excluded tags
				var temp = store.getTaggedTiddlers(theTag);
				var tagged=[]; for (var q=0; q<temp.length; q++) // hide excluded tiddlers
					if (!temp[q].isTagged('excludeLists')) tagged.push(temp[q]); 
				if (tagged.length) { tagcount++;
					list.options[i++]=new Option('+ '+theTag+" ("+tagged.length+")","");
					for(var r=0; r<tagged.length; r++)
						list.options[i++]=
							new Option(indent+indent+tagged[r].title,tagged[r].title);
				}
			}
			// count untagged tiddlers
			var temp = store.getTiddlers("title");
			var c=0; for (var r=0; r<temp.length;r++) if (!temp[r].tags.length) c++;
			// create 'pseudo-tag' listing untagged tiddlers (if any)
			if (c>0) {
				list.options[i++] = new Option("+ untagged ("+c+")","");
				for (var r=0; r<temp.length;r++) if (!temp[r].tags.length)
					list.options[i++] = new
						Option(indent+indent+temp[r].title,temp[r].title);
			}
			list.options[0].text=tagcount+' tags:';
			expandTOC(list);
			break;
		case "missing": case "orphans": case "shadows":
			for (var t = 0; t < tiddlers.length; t++)
				list.options[i++] = new Option(tiddlers[t],tiddlers[t]);
			break;
	}
	list.selectedIndex=selectedIndex; // select current control item
	list.size = (list.autosize)?list.options.length:list.requestedSize;
}

// show/hide branch of TOCList based on current selection
function expandTOC(list) {
	var selectedIndex = list.selectedIndex;
	if (selectedIndex==-1) selectedIndex=0;
	var sortBy = list.sortBy;

	// don't collapse/expand list for alpha-sorted "flatlist" TOC contents
	// or list control items
	if ((sortBy=="title")||(sortBy=="missing")||(sortBy=="orphans")||(sortBy=="shadows")) return;
	if ((selectedIndex>0)&&(selectedIndex<=list.cmdMax)) return;

	// get current selected text/value and cache the 
	// complete list.  Then clear the current list contents
	var theText = list.options[selectedIndex].text;
	var theValue = list.options[selectedIndex].value;
	if (!list.saved) {
		list.saved=new Array();
		for (var i=0;i<list.length;i++) list.saved[i]=list.options[i];
	}
	while (list.length > 0) { list.options[0] = null; }

	// put back heading items until item text matches current selected heading
	var i=0;
	for (var t=0; t<list.saved.length; t++) {
		var opt=list.saved[t];
		if (list.expandall||(opt.value=='')||(i<=list.cmdMax)) list.options[i++] = opt;
		if (opt.text==theText) break;
	}
	selectedIndex=i-1;	// this is the NEW index of the current selected heading
	// put back items with value!='' until value==''
	for ( t++; t<list.saved.length; t++) {
		var opt=list.saved[t];
		if (list.expandall||opt.value!='') list.options[i++] = opt;
		if (opt.value=='') break;
	}
	// put back remaining items with value==''
	for ( ; t<list.saved.length; t++) {
		var opt=list.saved[t];
		if (list.expandall||opt.value=='') list.options[i++] = opt;
	}
	list.selectedIndex = selectedIndex;
	list.size = (list.autosize)?list.options.length:list.requestedSize;
}

// these functions process clicks on the 'control links' that are displayed above the listbox
function getTOCListFromButton(which) {
	var list = null;
	switch (which.id) {
		case 'TOCMenu':
			var theSiblings = which.parentNode.parentNode.parentNode.childNodes;
			var thePlace=which.parentNode.parentNode.parentNode.parentNode.parentNode.id;
			break;
		case 'TOCSmaller': case 'TOCLarger': case 'TOCMaximize':
			var theSiblings = which.parentNode.parentNode.childNodes;
			var thePlace=which.parentNode.parentNode.parentNode.parentNode.id;
			break;
	}
	for (var k=0; k<theSiblings.length; k++)
		if (theSiblings[k].className=="TOCList") { list=theSiblings[k]; break; }
	return list;
}
function onClickTOCMenu(which) {
	var list=getTOCListFromButton(which); if (!list) return;
	var opening = list.style.display=="none";
	if(config.options.chkAnimate) anim.startAnimating(new Slider(list,opening,false,"none"));
	else list.style.display = opening ? "block" : "none" ;
	if (!list.noShowCookie) { config.options.chkTOCShow = opening; saveOptionCookie("chkTOCShow"); }
	return(false);
}
function resizeTOC(which) {
	var list=getTOCListFromButton(which); if (!list) return;
	var size = list.size;
	if (list.style.display=="none")	// make sure list is visible
		if(config.options.chkAnimate) anim.startAnimating(new Slider(list,true,false,"none"));
		else list.style.display = "block" ;
	switch (which.id) {
		case 'TOCSmaller':	// decrease current listbox size
			if (list.autosize) { list.autosize=false; size=config.options.txtTOCListSize; }
			if (size==1)	break;
			size -= 1;	// shrink by one line
			list.requestedSize = list.size = size;
			break;
		case 'TOCLarger':	// increase current listbox size
			if (list.autosize) { list.autosize=false; size=config.options.txtTOCListSize; }
			if (size>=list.options.length)	break;
			size += 1;	// grow by one line
			list.requestedSize = list.size = size;
			break;
		case 'TOCMaximize':	// toggle autosize
			list.autosize  = (list.size!=list.options.length);
			list.size = (list.autosize)?list.options.length:list.requestedSize;
			break;
	}
	if (!list.noSizeCookie && !list.autosize)
		{ config.options.txtTOCListSize=size; saveOptionCookie("txtTOCListSize"); }
}
//}}}
|Name|TableOfContentsPluginInfo|
|Source|http://www.TiddlyTools.com/#TableOfContentsPlugin|
|Documentation|http://www.TiddlyTools.com/#TableOfContentsPluginInfo|
|Version|2.4.3|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|documentation|
|Description|documentation for TableOfContentsPlugin|
When there are many tiddlers in a document, the standard 'tabbed list of tiddlers' in the right-hand sidebar can become very long, occupying a lot of page space and requiring a lot scrolling in order to locate and select a tiddler.  This plugin replaces the standard tabs with a listbox/droplist control that uses a very small amount of page space, regardless of the number of tiddlers in the document.
!!!!!Usage
<<<
{{{
<<tableOfContents label:... sort:... date:... size:...
	width:... padding:... margin:... prompt:... inline hidelist
	-title -date -author -creator -tags -missing -orphans -shadows
}}}
*''label:text'' (default="contents")<br>the text that appears above the listbox.
*''sort:fieldtype''<br>sets the initial display order for items in the listbox.  'fieldtype' is one of: ''title, modified, modifier, creator, tags, missing, orphans,'' or ''shadows''.
*''date:format''<br>format for dates in listbox display, using TiddlyWiki date formatting (e.g. "DDD, MMM DD YYY")
*''size:nnn'' (default=1)<br>the initial number of lines to display in the listbox.  If size=1, a droplist is created, otherwise a fixed-size listbox is created.  You can use "size:0" or "size:auto" to display a varible-height listbox that automatically adjusts to fit the current list contents without scrolling.
*''width:...'' (default=100%)<br>the width of the listbox/droplist, using CSS units cm, px, em, or %.  You can also use a ".TOCList" custom CSS class definition to override the built-in CSS declarations for the listbox.
*''padding:...''<br>sets listbox CSS padding style
*''margin:...''<br>sets listbox CSS margin style
*''prompt:...''<br>sets non-selectable prompt text that is displayed as the first line of the listbox //(note: this feature is not supported by the listbox control on all browsers)//.  Let's you include a short text message (such as "select a tiddler"), even when displaying a compact single-line droplist.
*''inline''<br>By default, the listbox is rendered inside a {{{<div>}}} element.  This keyword causes the plugin to use a {{{<span>}}} instead, allowing for more flexible 'inline' placement when embedded within other content.
*''hidelist''<br>when present, only the listbox label and size controls will be appear when first displayed.  Clicking the label toggles the listbox display.
*''-title, -date, -author, -creator, -tags, -missing, -orphans, -shadows''<br>Omits the indicated list command item and corresponding listbox content.  
Select (or double-click) a title from the listbox to open a tiddler, or select a 'command' items to set the order and type of tiddlers that are shown in the list:
*''[by title]''<br>displays all tiddlers in the document in alphanumeric order
*''[by date/author/creator/tags]''<br>displays indented sections, sorted accordingly, with headings (indicated by a '+') that can be expanded, one at a time, to view the list of tiddlers in that section. You can also ''shift-click'' on a section heading expand/collapse all sections at once.
*''[missing]''<br>displays tiddlers that have been referenced within the document but do not yet exist.
*''[orphans]''<br>displays tiddlers that do exist in the document but have not been referenced by a link from anywhere else within the document.
*''[shadows]''<br>displays special default/fallback tiddlers that are used by TiddlyWiki to configure built-in features and add-on macros/extensions.
The ''size of the listbox can be adjusted'' so you can view more (or less) tiddler titles at one time.  Select ''[-]'' to reduce the size by one line, ''[+]'' to increase the size by one line, or ''[=]'' to autosize the list to fit the current contents (toggles on/off). //Note: If the listbox is reduced to a single line, it displayed as a droplist instead of a fixed-sized listbox.//  You can ''show/hide the entire listbox'' by selecting the "contents" label that appears above the listbox.
<<<
!!!!!Configuration
<<option chkTOCShow>> display table of contents listbox
<<option chkTOCIncludeHidden>> include tiddlers tagged with <<tag excludeLists>> in listbox
listbox shows <<option txtTOCListSize>> lines, sorted by <<option txtTOCSortBy>>
!!!!!Parameters
<<<
<<<
!!!!!Examples
<<<
{{{<<tableOfContents "label:all tiddlers" sort:title width:40% size:1>>}}}
<<tableOfContents "label:all tiddlers" sort:title width:40% size:1>>
{{{<<tableOfContents "label:by date" sort:modified size:1 width:40%>>}}}
<<tableOfContents "label:by date" sort:modified size:1 width:40%>>
{{{<<tableOfContents "label:tagged tiddlers" sort:tags size:1 width:40%>>}}}
<<tableOfContents "label:tagged tiddlers" sort:tags size:1 width:40%>>
{{{<<tableOfContents "label:shadow tiddlers" sort:shadows size:1 width:40%>>}}}
<<tableOfContents "label:shadow tiddlers" sort:shadows size:1 width:40%>>
<<<
!!!!!Revisions
<<<
2008.04.09 2.4.3 restored config.options.chkTOCShow and onClickTOCMenu() handler
2008.04.07 2.4.2 added "Configuration" section and removed config.options.chkTOCShow and onClickTOCMenu() handler
2008.01.08 [*.*.*] plugin size reduction: documentation moved to ...Info tiddler
2007.12.25 2.4.1 code cleanup and performance improvements
2007.12.25 2.4.0 renamed 'system' section to 'shadows' (and no longer list plugins, etc. in that section).  Also, added 'by creator' sort order (with fallback to 'modifier' if 'creator' custom field is undefined). Thanks to RA for suggestion and code tweaks.
2007.12.04 [*.*.*] update for TW2.3.0: replaced deprecated core functions, regexps, and macros
2007.03.22 2.3.2 in refreshTOCLists(), when sorting by date, use convertToLocalYYYYMMDDHHMM() instead of formatString() to compare dates for 'section headings' and only use formatString() when actually generating the section heading date display.  Improves performance significantly for date sorted listbox, especially in documents with hundreds of tiddlers.  Suggestion by AndreasHoefler.
2007.03.21 2.3.1 in refreshTOCLists(), only get list of 'select' elements, instead of scanning through all elements (saves significant time during refresh events.  Suggestion by AndreasHoefler.
2006.11.27 2.3.0 added ability to omit sections from listbox via macro params (e.g., "-date -tags", etc.).  Based on request from DavidWinfield.
2006.05.21 2.2.7 added onkeyup handling for enter key (=view selected tiddler, equivalent to double-click)
2006.02.14 2.2.6 FF1501 fix: add 'var r' and 'var k' to unintended global variable declarations in refreshTOCList() and getTOCListFromButton().  Thanks for report from AndreasHoefler.
2006.02.04 2.2.5 add 'var' to unintended global variable declarations to avoid FireFox 1.5.0.1 crash bug when assigning to globals
2005.12.21 2.2.2 in onClickTOCList() and onDblClickTOCList(), prevent mouse events from 'bubbling' up to other handlers
2005.10.30 2.2.1 in refreshTOCList(), fixed calculation of "showHidden" to check for 'readOnly' (i.e., "via HTTP") flag.  Based on a report from LyallPearce
2005.10.30 2.2.0 hide tiddlers tagged with 'excludeLists' (with option to override, i.e., "include hidden tiddlers")
2005.10.09 2.1.0 combined documentation and code in a single tiddler
added click toggle for expand-all vs. show-one-branch
2005.08.07 2.0.0 major re-write to not use static ID values for listbox controls, so that multiple macro instances can exist without corrupting each other or the DOM.  Moved HTML and CSS definitions into plugin code instead of using separate tiddlers.  Added macro parameters for label, sort, date, size, width, hidelist and showtabs
2005.08.03 1.0.3 added "showtabs" optional parameter
2005.07.27 1.0.2 core update 1.2.29: custom overlayStyleSheet() replaced with new core setStylesheet().  Added show/hide toggle (click on 'contents' link)
2005.07.23 1.0.1 added parameter checks and corrected addNotification() usage
2005.07.20 1.0.0 Initial Release
<<<
/***
|''Name:''|TableSortingPlugin|
|''Description:''|Dynamically sort tables by clicking on column headers|
|''Author:''|Saq Imtiaz ( lewcid@gmail.com )|
|''Source:''|http://tw.lewcid.org/#TableSortingPlugin|
|''Code Repository:''|http://tw.lewcid.org/svn/plugins|
|''Version:''|2.02|
|''Date:''|25-01-2008|
|''License:''|[[Creative Commons Attribution-ShareAlike 3.0 License|http://creativecommons.org/licenses/by-sa/3.0/]]|
|''~CoreVersion:''|2.2.3|
!!Usage:
* Make sure your table has a header row
** {{{|Name|Phone Number|Address|h}}}<br> Note the /h/ that denote a header row 
* Give the table a class of 'sortable'
** {{{
|sortable|k
|Name|Phone Number|Address|h
}}}<br>Note the /k/ that denotes a class name being assigned to the table.
* To disallow sorting by a column, place {{{<<nosort>>}}} in it's header
* To automatically sort a table by a column, place {{{<<autosort>>}}} in the header for that column
** Or to sort automatically but in reverse order, use {{{<<autosort reverse>>}}}

!!Example:
|sortable|k
|Name |Salary |Extension |Performance |File Size |Start date |h
|ZBloggs, Fred |$12000.00 |1353 |+1.2 |74.2Kb |Aug 19, 2003 21:34:00 |
|ABloggs, Fred |$12000.00 |1353 |1.2 |3350b |09/18/2003 |
|CBloggs, Fred |$12000 |1353 |1.200 |55.2Kb |August 18, 2003 |
|DBloggs, Fred |$12000.00 |1353 |1.2 |2100b |07/18/2003 |
|Bloggs, Fred |$12000.00 |1353 |01.20 |6.156Mb |08/17/2003 05:43 |
|Turvey, Kevin |$191200.00 |2342 |-33 |1b |02/05/1979 |
|Mbogo, Arnold |$32010.12 |2755 |-21.673 |1.2Gb |09/08/1998 |
|Shakespeare, Bill |£122000.00|3211 |6 |33.22Gb |12/11/1961 |
|Shakespeare, Hamlet |£9000 |9005 |-8 |3Gb |01/01/2002 |
|Fitz, Marvin |€3300.30 |5554 |+5 |4Kb |05/22/1995 |

***/
// /%
//!BEGIN-PLUGIN-CODE
config.tableSorting = {
	
	darrow: "\u2193",
	
	uarrow: "\u2191",
	
	getText : function (o) {
		var p = o.cells[SORT_INDEX];
		return p.innerText || p.textContent || '';
	},
	
	sortTable : function (o,rev) {
		SORT_INDEX = o.getAttribute("index");
		var c = config.tableSorting;
		var T = findRelated(o.parentNode,"TABLE");
		if(T.tBodies[0].rows.length<=1) 
			return;
		var itm = "";
		var i = 0;
		while (itm == "" && i < T.tBodies[0].rows.length) {
			itm = c.getText(T.tBodies[0].rows[i]).trim();
			i++;
		}
		if (itm == "") 
			return; 	
		var r = [];
		var S = o.getElementsByTagName("span")[0];		
		c.fn = c.sortAlpha; 
		if(!isNaN(Date.parse(itm)))
			c.fn = c.sortDate; 
		else if(itm.match(/^[$|£|€|\+|\-]{0,1}\d*\.{0,1}\d+$/)) 
			c.fn = c.sortNumber; 
		else if(itm.match(/^\d*\.{0,1}\d+[K|M|G]{0,1}b$/)) 
			c.fn = c.sortFile; 
		for(i=0; i<T.tBodies[0].rows.length; i++) {
			 r[i]=T.tBodies[0].rows[i]; 
		} 
		r.sort(c.reSort);
		if(S.firstChild.nodeValue==c.darrow || rev) {
			r.reverse();
			S.firstChild.nodeValue=c.uarrow;
		} 
		else 
			S.firstChild.nodeValue=c.darrow;
		var thead = T.getElementsByTagName('thead')[0]; 
		var headers = thead.rows[thead.rows.length-1].cells;
		for(var k=0; k<headers.length; k++) {
			if(!hasClass(headers[k],"nosort"))
				addClass(headers[k].getElementsByTagName("span")[0],"hidden");
		}
		removeClass(S,"hidden");
		for(i=0; i<r.length; i++) { 
			T.tBodies[0].appendChild(r[i]);
			c.stripe(r[i],i);
			for(var j=0; j<r[i].cells.length;j++){
				removeClass(r[i].cells[j],"sortedCol");
			}
			addClass(r[i].cells[SORT_INDEX],"sortedCol");
		}
	},
	
	stripe : function (e,i){
		var cl = ["oddRow","evenRow"];
		i&1? cl.reverse() : cl;
		removeClass(e,cl[1]);
		addClass(e,cl[0]);
	},
	
	sortNumber : function(v) {
		var x = parseFloat(this.getText(v).replace(/[^0-9.-]/g,''));
		return isNaN(x)? 0: x;
	},
	
	sortDate : function(v) {
		return Date.parse(this.getText(v));
	},

	sortAlpha : function(v) {
		return this.getText(v).toLowerCase();
	},
	
	sortFile : function(v) { 		
		var j, q = config.messages.sizeTemplates, s = this.getText(v);
		for (var i=0; i<q.length; i++) {
			if ((j = s.toLowerCase().indexOf(q[i].template.replace("%0\u00a0","").toLowerCase())) != -1)
				return q[i].unit * s.substr(0,j);
		}
		return parseFloat(s);
	},
	
	reSort : function(a,b){
		var c = config.tableSorting;
		var aa = c.fn(a);
		var bb = c.fn(b);
		return ((aa==bb)? 0 : ((aa<bb)? -1:1));
	}
};

Story.prototype.tSort_refreshTiddler = Story.prototype.refreshTiddler;
Story.prototype.refreshTiddler = function(title,template,force,customFields,defaultText){
	var elem = this.tSort_refreshTiddler.apply(this,arguments);
	if(elem){
		var tables = elem.getElementsByTagName("TABLE");
		var c = config.tableSorting;
		for(var i=0; i<tables.length; i++){
			if(hasClass(tables[i],"sortable")){
				var x = null, rev, table = tables[i], thead = table.getElementsByTagName('thead')[0], headers = thead.rows[thead.rows.length-1].cells;
				for (var j=0; j<headers.length; j++){
					var h = headers[j];
					if (hasClass(h,"nosort"))
						continue;
					h.setAttribute("index",j);
					h.onclick = function(){c.sortTable(this); return false;};
					h.ondblclick = stopEvent;
					if(h.getElementsByTagName("span").length == 0)
						createTiddlyElement(h,"span",null,"hidden",c.uarrow); 
					if(!x && hasClass(h,"autosort")) {
						x = j;
						rev = hasClass(h,"reverse");
					}
				}
				if(x)
					c.sortTable(headers[x],rev);		
			}
		}
	}
	return elem; 
};

setStylesheet("table.sortable span.hidden {visibility:hidden;}\n"+
	"table.sortable thead {cursor:pointer;}\n"+
	"table.sortable .nosort {cursor:default;}\n"+
	"table.sortable td.sortedCol {background:#ffc;}","TableSortingPluginStyles");

function stopEvent(e){
	var ev = e? e : window.event;
	ev.cancelBubble = true;
	if (ev.stopPropagation) ev.stopPropagation();
	return false;	
}	

config.macros.nosort={
	handler : function(place){
		addClass(place,"nosort");
	}	
};

config.macros.autosort={
	handler : function(place,m,p,w,pS){
		addClass(place,"autosort"+" "+pS);		
	}	
};
//!END-PLUGIN-CODE
// %/
/***
|Name|TagCloudPlugin|
|Source|http://www.TiddlyTools.com/#TagCloudPlugin|
|Version|1.7.0|
|Author|Eric Shulman|
|Original Author|Clint Checketts|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|present a 'cloud' of tags (or links) using proportional font display|
!Usage
<<<
{{{
<<cloud type action:... limit:... tag tag tag ...>>
<<cloud type action:... limit:... +TiddlerName>>
<<cloud type action:... limit:... -TiddlerName>>
<<cloud type action:... limit:... =tagvalue>>
}}}
where:
* //type// is a keyword, one of:
** ''tags'' (default) - displays a cloud of tags, based on frequency of use
** ''links'' - displays a cloud of tiddlers, based on number of links //from// each tiddler
** ''references'' - displays a cloud of tiddlers, based on number of links //to// each tiddler
* ''action:popup'' (default) - clicking a cloud item shows a popup with links to related tiddlers<br>//or//<br> ''action:goto'' - clicking a cloud item immediately opens the tiddler corresponding to that item
* ''limit:N'' (optional) - restricts the cloud display to only show the N most popular tags/links
* ''tag tag tag...'' (or ''title title title'' if ''links''/''references'' is used)<br>shows all tags/links in the document //except// for those listed as macro parameters
* ''+TiddlerName''<br>show only tags/links read from a space-separated, bracketed list stored in a separate tiddler.
* ''-TiddlerName''<br>show all tags/links //except// those read from a space-separated, bracketed list stored in a separate tiddler.
* ''=tagvalue'' (//only if type=''tags''//)<br>shows only tags that are themselves tagged with the indicated tag value (i.e., ~TagglyTagging usage)
//note: for backward-compatibility, you can also use the macro {{{<<tagCloud ...>>}}} in place of {{{<<cloud ...>>}}}//
<<<
!Examples
<<<
//all tags excluding<<tag systemConfig>>, <<tag excludeMissing>> and <<tag script>>//
{{{<<cloud systemConfig excludeMissing script>>}}}
{{groupbox{<<cloud systemConfig excludeMissing script>>}}}
//top 10 tags excluding<<tag systemConfig>>, <<tag excludeMissing>> and <<tag script>>//
{{{<<cloud limit:10 systemConfig excludeMissing script>>}}}
{{groupbox{<<cloud limit:10 systemConfig excludeMissing script>>}}}
//tags listed in// [[FavoriteTags]]
{{{<<cloud +FavoriteTags>>}}}
{{groupbox{<<cloud +FavoriteTags>>}}}
//tags NOT listed in// [[FavoriteTags]]
{{{<<cloud -FavoriteTags>>}}}
{{groupbox{<<cloud -FavoriteTags>>}}}
//links to tiddlers tagged with 'package'//
{{{<<cloud action:goto =package>>}}}
{{groupbox{<<cloud action:goto =package>>}}}
//top 20 most referenced tiddlers//
{{{<<cloud references limit:20>>}}}
{{groupbox{<<cloud references limit:20>>}}}
//top 20 tiddlers that contain the most links//
{{{<<cloud links limit:20>>}}}
{{groupbox{<<cloud links limit:20>>}}}
<<<
!Revisions
<<<
2009.07.17 [1.7.0] added {{{-TiddlerName}}} parameter to exclude tags that are listed in the indicated tiddler
2009.02.26 [1.6.0] added {{{action:...}}} parameter to apply popup vs. goto action when clicking cloud items
2009.02.05 [1.5.0] added ability to show links or back-links (references) instead of tags and renamed macro to {{{<<cloud>>}}} to reflect more generalized usage.
2008.12.16 [1.4.2] corrected group calculation to prevent 'group=0' error
2008.12.16 [1.4.1] revised tag filtering so excluded tags don't affect calculations
2008.12.15 [1.4.0] added {{{limit:...}}} parameter to restrict the number of tags displayed to the top N most popular
2008.11.15 [1.3.0] added {{{+TiddlerName}}} parameter to include only tags that are listed in the indicated tiddler
2008.09.05 [1.2.0] added '=tagname' parameter to include only tags that are themselves tagged with the specified value (i.e., ~TagglyTagging usage)
2008.07.03 [1.1.0] added 'segments' property to macro object.  Extensive code cleanup
<<<
!Code
***/
//{{{
version.extensions.TagCloudPlugin= {major: 1, minor: 7 , revision: 0, date: new Date(2009,7,17)};
//Originally created by Clint Checketts, contributions by Jonny Leroy and Eric Shulman
//Currently maintained and enhanced by Eric Shulman
//}}}
//{{{
config.macros.cloud = {
	tagstip: "%1 tiddlers tagged with '%0'",
	refslabel: " (%0 references)",
	refstip: "%1 tiddlers have links to '%0'",
	linkslabel: " (%0 links)",
	linkstip: "'%0' has links to %1 other tiddlers",
	groups: 9,
	init: function() {
		config.macros.tagCloud=config.macros.cloud; // for backward-compatibility
		config.shadowTiddlers.TagCloud='<<cloud>>';
		config.shadowTiddlers.StyleSheetTagCloud=
			'/*{{{*/\n'
			+'.tagCloud span {line-height: 3.5em; margin:3px;}\n'
			+'.tagCloud1{font-size: 80%;}\n'
			+'.tagCloud2{font-size: 100%;}\n'
			+'.tagCloud3{font-size: 120%;}\n'
			+'.tagCloud4{font-size: 140%;}\n'
			+'.tagCloud5{font-size: 160%;}\n'
			+'.tagCloud6{font-size: 180%;}\n'
			+'.tagCloud7{font-size: 200%;}\n'
			+'.tagCloud8{font-size: 220%;}\n'
			+'.tagCloud9{font-size: 240%;}\n'
			+'/*}}}*/\n';
		setStylesheet(store.getTiddlerText('StyleSheetTagCloud'),'tagCloudsStyles');
	},
	getLinks: function(tiddler) { // get list of links to existing tiddlers and shadows
		if (!tiddler.linksUpdated) tiddler.changed();
		var list=[]; for (var i=0; i<tiddler.links.length; i++) {
			var title=tiddler.links[i];
			if (store.isShadowTiddler(title)||store.tiddlerExists(title))
				list.push(title);
		}
		return list;
	},
	handler: function(place,macroName,params) {
		// unpack params
		var inc=[]; var ex=[]; var limit=0; var action='popup';
		var links=(params[0]&&params[0].toLowerCase()=='links'); if (links) params.shift();
		var refs=(params[0]&&params[0].toLowerCase()=='references'); if (refs) params.shift();
		if (params[0]&&params[0].substr(0,7).toLowerCase()=='action:')
			action=params.shift().substr(7).toLowerCase();
		if (params[0]&&params[0].substr(0,6).toLowerCase()=='limit:')
			limit=parseInt(params.shift().substr(6));
		while (params.length) {
			if (params[0].substr(0,1)=='+') { // read taglist from tiddler
				inc=inc.concat(store.getTiddlerText(params[0].substr(1),'').readBracketedList());
			} else if (params[0].substr(0,1)=='-') { // exclude taglist from tiddler
				ex=ex.concat(store.getTiddlerText(params[0].substr(1),'').readBracketedList());
			} else if (params[0].substr(0,1)=='=') { // get tag list using tagged tags
				var tagged=store.getTaggedTiddlers(params[0].substr(1));
				for (var t=0; t<tagged.length; t++) inc.push(tagged[t].title);
			} else ex.push(params[0]); // exclude params
			params.shift();
		}
		// get all items, include/exclude specific items
		var items=[];
		var list=(links||refs)?store.getTiddlers('title','excludeLists'):store.getTags();
		for (var t=0; t<list.length; t++) {
			var title=(links||refs)?list[t].title:list[t][0];
			if (links)	var count=this.getLinks(list[t]).length;
			else if (refs)	var count=store.getReferringTiddlers(title).length;
			else 		var count=list[t][1];
			if ((!inc.length||inc.contains(title))&&(!ex.length||!ex.contains(title)))
				items.push({ title:title, count:count });
		}
		if(!items.length) return;
		// sort by decending count, limit results (optional)
		items=items.sort(function(a,b){return(a.count==b.count)?0:(a.count>b.count?-1:1);});
		while (limit && items.length>limit) items.pop();
		// find min/max and group size
		var most=items[0].count;
		var least=items[items.length-1].count;
		var groupSize=(most-least+1)/this.groups;
		// sort by title and draw the cloud of items
		items=items.sort(function(a,b){return(a.title==b.title)?0:(a.title>b.title?1:-1);});
		var cloudWrapper = createTiddlyElement(place,'div',null,'tagCloud',null);
		for (var t=0; t<items.length; t++) {
			cloudWrapper.appendChild(document.createTextNode(' '));
			var group=Math.ceil((items[t].count-least)/groupSize)||1;
			var className='tagCloudtag tagCloud'+group;
			var tip=refs?this.refstip:links?this.linkstip:this.tagstip;
			tip=tip.format([items[t].title,items[t].count]);
			if (action=='goto') { // TAG/LINK/REFERENCES GOTO
				var btn=createTiddlyLink(cloudWrapper,items[t].title,true,className);
				btn.title=tip;
				btn.style.fontWeight='normal';
			} else if (!links&&!refs) { // TAG POPUP
				var btn=createTiddlyButton(cloudWrapper,items[t].title,tip,onClickTag,className);
				btn.setAttribute('tag',items[t].title);
			} else { // LINK/REFERENCES POPUP
				var btn=createTiddlyButton(cloudWrapper,items[t].title,tip,
					function(ev) { var e=ev||window.event; var cmt=config.macros.cloud;
						var popup = Popup.create(this);
						var title = this.getAttribute('tiddler');
						var count = this.getAttribute('count');
						var refs  = this.getAttribute('refs')=='T';
						var links = this.getAttribute('links')=='T';
						var label = (refs?cmt.refslabel:cmt.linkslabel).format([count]);
						createTiddlyLink(popup,title,true);
						createTiddlyText(popup,label);
						createTiddlyElement(popup,'hr');
						if (refs) {
							popup.setAttribute('tiddler',title);
							config.commands.references.handlePopup(popup,title);
						}
						if (links) {
							var tiddler = store.fetchTiddler(title);
							var links=config.macros.cloud.getLinks(tiddler);
							for(var i=0;i<links.length;i++)
								createTiddlyLink(createTiddlyElement(popup,'li'),
									links[i],true);
						}
						Popup.show();
						e.cancelBubble=true; if(e.stopPropagation) e.stopPropagation();
						return false;
					}, className);
				btn.setAttribute('tiddler',items[t].title);
				btn.setAttribute('count',items[t].count);
				btn.setAttribute('refs',refs?'T':'F');
				btn.setAttribute('links',links?'T':'F');
				btn.title=tip;
			}
		}
	}
};
//}}}
/***
|Name|TagGridPlugin|
|Source|http://www.TiddlyTools.com/#TagGridPlugin|
|Documentation|http://www.TiddlyTools.com/#TagGridPluginInfo|
|Version|1.7.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|Generate a cross-referenced grid of tiddlers, based on tag values|
!!!!!Documentation
>see [[TagGridPluginInfo]]
!!!!!Revisions
<<<
2008.04.21 [1.7.0] added support for "filter:..." param to exclude tiddlers from grid
2008.01.08 [*.*.*] plugin size reduction: documentation moved to ...Info tiddler
2007.12.04 [*.*.*] update for TW2.3.0: replaced deprecated core functions, regexps, and macros
2007.07.24 [1.6.5] corrected handling for @TiddlerName with excluded tags, so that excluded tags are not actually removed from the @TiddlerName source tiddler.
|please see [[TagGridPluginInfo]] for additional revision details|
2006.10.05 [1.0.0] initial release (converted from prototype inline script)
<<<
!!!!!Code
***/
//{{{
version.extensions.TagGridPlugin= {major: 1, minor: 7, revision: 0, date: new Date(2008,4,21)};

config.macros.tagGrid= {
	verbose:false, // display debugging/performance feedback messages
	warn:true,	// display workload warning message before rendering
	threshold:300000, // workload warning threshold (workload=# of comparisons to perform)
	handler:
	function(place,macroName,params) {

		// get columns
		var columntags=params.shift(); var cols=[];
		if ((!columntags)||(columntags=="all")) // no param (or "all") - use all tags
			{ var all=store.getTags(); for (i=0;i<all.length;i++) cols.push(all[i][0]); }
		else if (columntags.substr(0,1)=="+") // get tag list from tiddler content
			{ var t=store.getTiddlerText(columntags.substr(1)); if (t&&t.length) cols=t.readBracketedList(); }
		else if (columntags.substr(0,1)=="@") // get tag list from tiddler tags
			{ var t=store.getTiddler(columntags.substr(1)); if (t&&t.tags) for (i=0;i<t.tags.length;i++) cols.push(t.tags[i]); }
		else if (columntags.substr(0,1)=="=")  // get names of "tagtiddlers" tagged with meta-tag
			{ var t=store.getTaggedTiddlers(columntags.substr(1)); for (i=0;i<t.length;i++) cols.push(t[i].title); }
		else cols=columntags.readBracketedList();
		if (!cols.length) { wikify("~TagGrid: no columns to display\n",place); return; }

		// exclude specific column tags
		if (params[0]&&params[0].substr(0,8)=="exclude:") {
			var ex=params.shift().substr(8).readBracketedList();
			for (x=0; x<ex.length; x++) {
				var i=cols.indexOf(ex[x]);
				if (i!=-1) cols.splice(i,1); // remove excluded tags
			}
		}

		// get rows
		var rowtags=params.shift(); var rows=[];
		if ((!rowtags)||(rowtags=="all")) // no param (or "all") - use all tags
			{ var all=store.getTags(); for (i=0;i<all.length;i++) rows.push(all[i][0]); }
		else if (rowtags.substr(0,1)=="+") // get tag list from tiddler content
			{ var t=store.getTiddlerText(rowtags.substr(1)); if (t&&t.length) rows=t.readBracketedList(); }
		else if (rowtags.substr(0,1)=="@") // get tag list from tiddler tags
			{ var t=store.getTiddler(rowtags.substr(1)); if (t&&t.tags) for (i=0;i<t.tags.length;i++) rows.push(t.tags[i]); }
		else if (rowtags.substr(0,1)=="=")  // get names of "tagtiddlers" tagged with meta-tag
			{ var t=store.getTaggedTiddlers(rowtags.substr(1)); for (i=0;i<t.length;i++) rows.push(t[i].title); }
		else rows=rowtags.readBracketedList();
		if (!rows.length) { wikify("~TagGrid: no rows to display\n",place); return; }

		// exclude specific row tags
		if (params[0]&&params[0].substr(0,8)=="exclude:") {
			var ex=params.shift().substr(8).readBracketedList();
		 	for (x=0; x<ex.length; x++) {
				var i=rows.indexOf(ex[x]);
				if (i!=-1) rows.splice(i,1); // remove excluded tags
			}
		}

		// get optional tiddler filter
		if (params[0]&&params[0].substr(0,7).toUpperCase()=="FILTER:")
			var filter=params.shift().substr(7);

		// get optional flag keywords and/or color gradient endpoints
		var defOpen=false;
		var colorAll=false;
		var sortRows=false;
		var sortColumns=false;
		var showInline=false;
		var p=params.shift();
		while (p) {
			switch (p.toUpperCase()) {
				case "OPEN":
					defOpen=true; break;
				case "COLORALL":
					colorAll=true; break;
				case "SORTROWS":
					sortRows=true; break;
				case "SORTCOLUMNS":
					sortColumns=true; break;
				case "INLINE":
					showInline=true; break;
				default:
					if (startcolor==undefined) var startcolor=p;
					else if (endcolor==undefined) var endcolor=p;
					else alert("unexpected parameter: '"+p+"'");
					break;
			}
			p=params.shift();
		}

		// get the tiddlers
		if (filter&&filter.length)
			var tiddlers=store.filterTiddlers(filter);
		else
			var tiddlers=store.getTiddlers("modified","excludeLists");

		// show "workload warning"... get permission to proceed...
		if (this.warn) {
			var workload=rows.length*cols.length*tiddlers.length;
			var warning="Cross-indexing %0 tiddlers in %1 row%3 by %2 column%4...\n(up to %5 comparisons MAY be needed)\n\n";
			warning+="This may take a while.  It is OK to proceed?";
			warning=warning.format([tiddlers.length,rows.length,cols.length,rows.length!=1?"s":"",cols.length!=1?"s":"",workload]);
			if (workload>this.threshold&&!confirm(warning)) { wikify("~TagGrid: display cancelled by user\n",place); return; }
		}

		// sort row and column tags in decending order, by frequency of use
		if (sortRows||sortColumns) {
			var tags=store.getTags(); var tagcount={}; for (i=0; i<tags.length; i++) tagcount[tags[i][0]]=tags[i][1];
			if (sortRows) rows.sort(function(a,b){return (!tagcount[a]||tagcount[a]<tagcount[b])?+1:(tagcount[a]==tagcount[b]?0:-1);});
			if (sortColumns) cols.sort(function(a,b){return (!tagcount[a]||tagcount[a]<tagcount[b])?+1:(tagcount[a]==tagcount[b]?0:-1);});
		}

		// cross-index tiddlers by tags, building lists of tiddler titles into grid[i][j] (sparse array)
		var time1=new Date();
		var grid=new Array();
		var max=0;  // track maximum cross-index value
		for (var t=0;t<tiddlers.length;t++) { // for each tiddler
			for (var i=0;i<tiddlers[t].tags.length;i++) { // for each tag in tiddler
				var row=rows.indexOf(tiddlers[t].tags[i]); if (row==-1) continue; // this tag not in rows
				if (!grid[row]) grid[row]=new Array(); // create row as needed
				for (var j=0;j<tiddlers[t].tags.length;j++) {  // for each tag in tiddler
					var col=cols.indexOf(tiddlers[t].tags[j]); if (col==-1) continue; // this tag not in columns
					if (!grid[row][col]) grid[row][col]=new Array(); // create cell
					grid[row][col].push("[["+tiddlers[t].title+"]]"); // add tiddler title to cell
					if (max<grid[row][col].length) max=grid[row][col].length; // check for new maximum
				}
			}
		}

		// compute gradient color map
		if (startcolor && endcolor) {
			var digits="0123456789ABCDEF";
			function hexToDec(s) // 2-digit conversion
				{ return digits.indexOf(s.substr(0,1).toUpperCase())*16+digits.indexOf(s.substr(1,1).toUpperCase()); }
			function decToHex(d) // 2-digit conversion
				{ return digits.substr(Math.floor(d/16),1)+digits.substr(d%16,1); }
			var steps=max;
			var startR=hexToDec(startcolor.substr(0,2));
			var startG=hexToDec(startcolor.substr(2,2));
			var startB=hexToDec(startcolor.substr(4,2));
			var endR=hexToDec(endcolor.substr(0,2));
			var endG=hexToDec(endcolor.substr(2,2));
			var endB=hexToDec(endcolor.substr(4,2));
			var rangeR=endR-startR;
			var rangeG=endG-startG;
			var rangeB=endB-startB;
			var stepR=rangeR/steps; if (stepR>0) stepR=Math.floor(stepR); else stepR=Math.ceil(stepR);
			var stepG=rangeG/steps; if (stepG>0) stepG=Math.floor(stepG); else stepG=Math.ceil(stepG);
			var stepB=rangeB/steps; if (stepB>0) stepB=Math.floor(stepB); else stepB=Math.ceil(stepB);
			var colors=[];
			colors[0]=startcolor;
			for (var i=1; i<steps; i++)
				colors[i]=decToHex(startR+stepR*i)+decToHex(startG+stepG*i)+decToHex(startB+stepB*i);
			colors[steps-1]=endcolor; // fixup for roundoff error
		}

		// generate HTML table containing popups (and optional inline links)
		var time2=new Date();
		var out="<html><table cellpadding='0' cellspacing='0' style='border:0;border-collapse:collapse'>";
		// column headings
		out+="<tr style='border:0;'><td style='text-align:right;border:0'>";
		out+="<a href='' style='font-size:80%;'";
		out+="	title='show all column headings'";
		out+="	onclick='return config.macros.tagGrid.toggleAllColumns(this,event,"+defOpen+")'>"+(defOpen?"&lt;&lt;&lt;":"&gt;&gt;&gt;")+"</a>";
		out+="</td>";
		for (var i=0;i<cols.length;i++) {
			out+="<td style='text-align:center;cursor:pointer;border:0;padding-left:2px;padding-right:2px' ";
			out+="	title='show/hide column heading' ";
			out+="	onclick='return config.macros.tagGrid.toggleColumn(this,event)'>";
			out+="<a href='' title='open tag tiddler'";
			if (!defOpen) out+="	style='display:none' ";
			out+="	onclick='story.displayTiddler(this,\""+cols[i]+"\");return false'>"+cols[i]+"</a>";
			out+="</td>";
		}
		out+="</tr>";
		for (var i=0;i<rows.length;i++) {
			// row heading
			var rowlink="<a href='' onclick='story.displayTiddler(this,\""+rows[i]+"\");return false'>"+rows[i]+"</a>";
			out +="<tr style='border:0'>";
			out +="<td style='text-align:right;border:0;padding-right:2px'>"+rowlink+"</td>";
			for (var j=0;j<cols.length;j++) {
				var content="";
				var bgcolor="transparent"; // default empty cell background
				if (colors && colorAll) bgcolor="#"+colors[0]; // empty cell background uses startcolor 
				var bordercolor=""; // default border color (inherits current CSS value)
				if (colors) bordercolor="#"+colors[Math.floor(colors.length/2-1)]; // border uses mid-tone color 
				var linkstyle=""; // use default unless background color is very light or very dark
				var cross=(grid[i]&&grid[i][j])?grid[i][j]:null;
				var hdr=rows[i]+(rows[i]!=cols[j]?(" + "+cols[j]):"");
				if (cross) {
					// cross-tagged list of tiddlers (in a popup)
					var label="<b>"+cross.length+"</b>";
					var tip=hdr;
					var list=cross.sort().join(' ').replace(/'/g,"\\'").replace(/"/g,'&quot;');
					var handler="return config.macros.tagGrid.popup(this,event,\'"+rows[i]+"\',\'"+cols[j]+"\',\'"+list+"\')";
					if (colors) {
						var c=colors[cross.length-1];
						bgcolor="#"+c;
						linkstyle="style='color:#000000 !important'";
						// invert link color if background is very light
						if (c.substr(0,2)<"60" || c.substr(2,2)<"60" || c.substr(4,2)<"60")
							linkstyle="style='color:#FFFFFF !important'";
					}
				} else {
					var label="&nbsp;-&nbsp;";
					var tip="create a new tiddler tagged with: "+hdr;
					var list="";
					var handler="var title=config.macros.newTiddler.title;";
					handler+="story.displayTiddler(this,title,DEFAULT_EDIT_TEMPLATE);";
					handler+="story.setTiddlerTag(title,\'"+rows[i]+"\',+1);";
					handler+="story.setTiddlerTag(title,\'"+cols[j]+"\',+1);";
					handler+="story.focusTiddler(title,\'text\');return(false);";
				}
				if (!showInline || !cross)
					content+='<a href="javascript:;" '+linkstyle+' onclick="'+handler+'" title="'+tip+'">'+label+'</a>';
				if (showInline && cross) {
					content+="<div "+linkstyle+"><span style='white-space:nowrap'>";
					content+=hdr+" ("+label+")";
					content+="</span></div><hr>";
					// list tiddler links inline in table cell
					for (t=0; t<cross.length; t++) {
						var title=cross[t].replace(/\[\[/g,'').replace(/\]\]/g,'');
						var handler="story.displayTiddler(null,'"+title+"');return false;"
						var tid=store.getTiddler(title);
						var author=tid.modifier;
						var date=tid.modified.toLocaleString();
						var tip=config.messages.tiddlerLinkTooltip.format([title,author,date]);
						if (t>0) content+="<br>";
						content+='<a href="javascript:;" '+linkstyle+' onclick="'+handler+'" title="'+tip+'">'+title+'</a>';
					}
					content+="<hr>";
					handler="var tids=\'"+list+"\'.readBracketedList();story.displayTiddlers(this,tids); return(false);"
					tip="display all tiddlers tagged with: "+hdr;
					content+='<a href="javascript:;" '+linkstyle+' onclick="'+handler+'" title="'+tip+'">open all...</a><br>';
					handler="var title=config.macros.newTiddler.title;";
					handler+="story.displayTiddler(this,title,DEFAULT_EDIT_TEMPLATE);";
					handler+="story.setTiddlerTag(title,\'"+rows[i]+"\',+1);";
					handler+="story.setTiddlerTag(title,\'"+cols[j]+"\',+1);";
					handler+="story.focusTiddler(title,'text'); return(false);"
					tip="create a new tiddler tagged with: "+hdr;
					content+='<a href="javascript:;" '+linkstyle+' onclick="'+handler+'" title="'+tip+'">new tiddler...</a>';
				}
				out+="<td style='background-color:"+bgcolor+";border:1px solid "+bordercolor+" !important;text-align:center'>"+content+"</td>";
			}
			out+="</tr>";
		}
		out+="</table>";
		out+="</html>";
		createTiddlyElement(place,"span").innerHTML=out;
		var time3=new Date();
		if (this.verbose) displayMessage("TagGrid: scan="+(time2-time1)+", generate table="+(time3-time2));
	},
	popup:
	function(here,event,row,col,list) {
		var tids=list.replace(/&quot;/g,'"').readBracketedList();
		var hdr=row+(row!=col?(" AND "+col):"");
		if (tids.length) {
			var p=Popup.create(here); if (!p) return;
			createTiddlyText(p,hdr);
			createTiddlyElement(p,'hr');
			for(var t=0; t<tids.length; t++) createTiddlyLink(createTiddlyElement(p,'li'),tids[t],true);
			createTiddlyElement(p,'hr');
			createTiddlyButton(createTiddlyElement(p,'li'),
				"open all...", "display all tiddlers tagged with: "+hdr,
				function(){story.displayTiddlers(null,tids); return(false);});
			var a=createTiddlyButton(createTiddlyElement(p,'li'),
				"new tiddler...", "create a new tiddler tagged with: "+hdr,
				function(){
					var title=config.macros.newTiddler.title;
					story.displayTiddler(this,title,DEFAULT_EDIT_TEMPLATE);
					story.setTiddlerTag(title,this.getAttribute("rowtag"),+1);
					story.setTiddlerTag(title,this.getAttribute("coltag"),+1);
					story.focusTiddler(title,"text");
					return(false);
				});
			a.setAttribute("rowtag",row);
			a.setAttribute("coltag",col);
			Popup.show();
		}
		event.cancelBubble = true;
		if (event.stopPropagation) event.stopPropagation();
		return(false);
	},
	toggleAllColumns:
	function(here,event,defOpen) {
		if (here.expanded==undefined) here.expanded=defOpen;
		var ex=here.expanded=!here.expanded; 
		here.innerHTML=ex?"&lt;&lt;&lt;":"&gt;&gt;&gt;";
		here.title=ex?'hide all column headings':'show all column headings';
		var cells=here.parentNode.parentNode.getElementsByTagName("td");
		for (i=1; i<cells.length; i++) cells[i].firstChild.style.display=ex?"inline":"none";
		event.cancelBubble = true;
		if (event.stopPropagation) event.stopPropagation();
		return(false);
	},
	toggleColumn:
	function(here,event) {
		here.firstChild.style.display=(here.firstChild.style.display=="none")?"inline":"none";
		event.cancelBubble = true;
		if (event.stopPropagation) event.stopPropagation();
		return(false);
	}
};
//}}}
/***
|Name|TagGridPluginInfo|
|Source|http://www.TiddlyTools.com/#TagGridPlugin|
|Documentation|http://www.TiddlyTools.com/#TagGridPluginInfo|
|Version|1.7.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|documentation|
|Description|documentation for TagGridPlugin|
!!!!!Usage
<<<
Specify which tags should be used for the columns and rows of the grid to ''see a particular cross-section'' of your document, or use //all// tags to ''get an instant 'birds-eye' overview of your entire document''.

Each grid cell contains a label with the number of tiddlers in that grid cell.  Click the number to ''show a popup of cross-indexed tiddler titles''.  Grid cells with no matching tiddlers contain a "-" (dash) that can be clicked to ''create new tiddlers automatically pre-tagged with that cell's combination of tags.''

To keep the grid display from getting very wide, the grid tags used as column headings are not initially displayed.  ''Click directly above the column to show/hide that heading'', or toggle all column headings at once by clicking the {{{>>>}}} symbol in the upper-left corner of the grid display.  Clicking a displayed row/column tag heading opens the tiddler whose title is that tag name.

The macro syntax to include a tag grid in your tiddler content is:
{{{
<<tagGrid "columntags" "exclude:tags" "rowtags" "exclude:tags" "filter:tiddlerfilter" startcolor endcolor open inline colorall sortrows sortcolumns>>
}}}
where:

''rowtags/columntags'' are each:
* a ''quoted'' space-separated lists of tags: {{{"tag1 tag2 [[tag3 with spaces]] tag4 ..."}}}
* //or,// a tiddler name preceded by "+": {{{+TiddlerName}}} where the specified tiddler contains a space-separated list of tags (same format as DefaultTiddlers)
* //or,// a tiddler name preceded by "@": {{{@TiddlerName}}} to use the same tags as those that are tagging the specified tiddler (i.e., the tiddler is a representative example of the kind of tags you are interested in cross-indexing)
* //or,// a tag name preceded by "=": {{{=tagName}}} to use the group of tags that are themselves, in turn, tagged with the indicated tagName (i.e., useful when you have defined a 'meta-tag'/classification system, a.k.a. "~TagglyTagging" techniques)
* //or,// keyword: {{{all}}} (use all tags)
* if only columntags are specified, rows display all tags by default
* if no parameters are provided, both rows and columns display all tags
''exclude:tag tag tag''
* This //optional// parameter can be placed immediately following the columntags and/or rowtags parameter to selectively omit certain tags from the grid row or column headings.  You can exclude several tags at once by enclosing the entire parameter in quotes, e.g.: {{{"exclude:tag tag tag"}}}.  This parameter is generally only needed to adjust the set of row/column headings that will be applied when using the {{{@TiddlerName}}} syntax.   Otherwise, you can simply omit the undesired rows/column headings directly from the specified columntags and/or rowstags parameters.
''"filter:tiddlerfilter"''
* By default, all tiddlers in the document are scanned to determine the contents of the grid cells.  The //optional// filter parameter allows you to specify a subset of tiddler to be scanned.  The syntax for this parameter is: {{{"filter:[tag[tagname]]"}}}, which will select only tiddlers with the indicated tag.  For more advanced selection of tiddlers, you can install [[MatchTagsPlugin]], which extends the {{{[tag[...]]}}} filter syntax to permit use of full boolean expressions, e.g., {{{"filter:[tag[NOT tag1]]"}}} or {{{"filter:[tag[tag1 AND NOT tag2]]"}}} or {{{"filter:[tag[(tag1 AND tag2) OR (tag3 AND NOT tag4)]]"}}}, etc.
''startcolor/endcolor''
* describes a ''color gradient'' where the grid cell background color is calculated as a combination of  the starting and ending colors, in proportion to the cell value
* colors are specified using 6-digit hex-coded RGB values (e.g., red="~FF0000", green="00FF00", blue="0000FF")
* the cells with the lowest number use the starting background color
* the cells with the highest number use the ending background color
* if one or both color values are omitted, all cells have //transparent// backgrounds
''open''
* causes the grid column headings to be shown when the grid is initially displayed (you can hide all the column headings using the &lArr; link, or just toggle one heading by clicking //near// the tag text.  (Note: clicking //on// the tag text will open the tiddler with the same name as the tag.
''inline''
* by default, cells with cross-indexed tiddlers display the total number of tiddlers in the cell.  When this number is clicked, a popup is displayed, containing links to the individual tiddlers in that cell.  However, the popup display makes it difficult to compare the contents of two or more cells because only one popup can be displayed at any given time.  To address this, you can use the ''inline'' keyword parameter to ''display the grid contents directly in the cells'', without using any popups.  While this can make the grid display significantly larger (to fit the text of each cell), it also enables quick comparisons between cells.  Inline rendering of the cell contents also makes it possible to print the entire grid contents for easy off-line reporting and analysis.
''colorall''
* by default, cells with no cross-indexed tiddlers have a //transparent// background (e.g., the tiddler's background colors shows through).  However, this can create a 'patchwork' appearance to the grid.  Add the ''colorall'' keyword parameter to force these 'empty' cells to use the specified startcolor instead of a transparent background.
''sortrows/sortcolumns''
* rowtags and columntags are normally displayed in the order specified in the macro parameters, or in alphabetical order when ''all'' is used to generate the list of tags.  Adding the ''sortrows'' and/or ''sortcolumns'' keyword parameters will sort the tags in decending order so that the most frequently used tags are displayed first (i.e., towards the top-left corner).
<<<
!!!!!Examples
<<<
{{{<<tagGrid +FavoriteTags +FavoriteTags eeeeff 3333ff colorall sortrows sortcolumns>>}}}
<<tagGrid +FavoriteTags +FavoriteTags eeeeff 3333ff colorall sortrows sortcolumns>>
<<<
!!!!!Revisions
<<<
2008.04.21 1.7.0 added support for "filter:..." param to exclude tiddlers from grid
2008.01.08 [*.*.*] plugin size reduction: documentation moved to ...Info tiddler
2007.12.04 [*.*.*] update for TW2.3.0: replaced deprecated core functions, regexps, and macros
2007.07.24 1.6.5 corrected handling for @TiddlerName with excluded tags, so that excluded tags are not actually removed from the @TiddlerName source tiddler.
2007.07.04 1.6.4 fix fatal "unterminated string" popup error caused by tiddlers containing double-quotes (now being encoded using "&quot;")
2007.03.08 1.6.3 use global flag to replace ALL single-quotes in tiddler titles (fixes popups where more than one tiddler title had a ' in it)
2007.03.06 1.6.2 removed debugging alert()s... D'oh!
2007.03.06 1.6.1 fix handling for excluding tags (was only removing last tag in list)
2007.03.05 1.6.0 added "exclude:tag tag tag..." parameter handling for both rows and columns
2006.12.20 1.5.1 fixed bordercolor calculation and CSS so grid correctly uses midtone-color for table cell borders
2006.12.09 1.5.0 added 'inline' keyword parameter to display tiddler titles directly in grid cells (in addition to popup)
2006.11.03 1.4.0 changed {{{=TiddlerName}}} param usage to {{{@TiddlerName}}} and added {{{=tagName}}} usage for specifying TagglyTagging "meta-tagged" groups of tag (based on ideas by GregWolff)
2006.11.03 1.3.3 performance optimization: calculate maximum cross-index value while building grid (eliminates extra calc during colormapping)
2006.10.29 1.3.2 fixes for IE: in decToHex and hexToDec, use substr() instead array indexing.  Also, use {{{>>>}}} and {{{<<<}}} instead of {{{&rArr;}}} and {{{&lArr;}}} for 'toggle headings' link text
2006.10.29 1.3.1 suppress border around table
2006.10.21 1.3.0 added {{{=TiddlerName}}} and {{{open}}} parameter handling
2006.10.17 1.2.1 fixed row/column sorting to properly sort undefined tags to the end of the list
2006.10.16 1.2.0 added optional row/column sorting and improved parameter parsing
2006.10.15 1.1.0 added features: background gradients, collapsible column headings, eliminated table borders around row/column headings
2006.10.06 1.0.1 calls to displayTiddler() use 'this' instead of 'null'
2006.10.05 1.0.0 initial release (converted from prototype inline script)
<<<
/***
|Name|TaggedTemplateTweak|
|Source|http://www.TiddlyTools.com/#TaggedTemplateTweak|
|Documentation|http://www.TiddlyTools.com/#TaggedTemplateTweakInfo|
|Version|1.6.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|use alternative ViewTemplate/EditTemplate for specific tiddlers|
This plugin extends the core function, story.chooseTemplateForTiddler(), so that any given tiddler can be viewed and/or edited using alternatives to the standard tiddler templates.
!!!!!Documentation
>see [[TaggedTemplateTweakInfo]]
!!!!!Revisions
<<<
2009.09.02 [1.6.1] apply field-based template (if any) *before* tag-based template
| please see [[TaggedTemplateTweakInfo]] for previous revision details |
2007.06.11 [1.0.0] initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.TaggedTemplateTweak= {major: 1, minor: 6, revision: 1, date: new Date(2009,9,2)};

if (!config.options.txtTemplateTweakFieldname)	
	config.options.txtTemplateTweakFieldname='template';

Story.prototype.taggedTemplate_chooseTemplateForTiddler = Story.prototype.chooseTemplateForTiddler
Story.prototype.chooseTemplateForTiddler = function(title,template)
{
	// get core template and split into theme and template name
	var coreTemplate=this.taggedTemplate_chooseTemplateForTiddler.apply(this,arguments);
	var theme=""; var template=coreTemplate;
	var parts=template.split(config.textPrimitives.sectionSeparator);
	if (parts[1]) { theme=parts[0]; template=parts[1]; }
	else theme=config.options.txtTheme||""; // if theme is not specified
	theme+=config.textPrimitives.sectionSeparator;

	// look for template using title as prefix
	if (!store.getTaggedTiddlers(title).length) { // if tiddler is not a tag
		if (store.getTiddlerText(theme+title+template))
			{ return theme+title+template; } // theme##TitleTemplate
		if (store.getTiddlerText(title+template))
			{ return title+template; }	 // TitleTemplate
	}

	// look for templates using custom field value as prefix
	var v=store.getValue(title,config.options.txtTemplateTweakFieldname);
	if (store.getTiddlerText(theme+v+template))
		{ return theme+v+template; }	// theme##valueTemplate
	if (store.getTiddlerText(v+template))
		{ return v+template; }		// valueTemplate

	// look for template using tags as prefix
	var tiddler=store.getTiddler(title);
	if (!tiddler) return coreTemplate; // tiddler doesn't exist... use core result
	for (i=0; i<tiddler.tags.length; i++) {
		var t=tiddler.tags[i]+template; // add tag prefix to template
		var c=t.substr(0,1).toUpperCase()+t.substr(1); // capitalized for WikiWord title
		if (store.getTiddlerText(theme+t))	{ return theme+t; } // theme##tagTemplate
		if (store.getTiddlerText(theme+c))	{ return theme+c; } // theme##TagTemplate
		if (store.getTiddlerText(t)) 		{ return t; }	    // tagTemplate
		if (store.getTiddlerText(c))		{ return c; }	    // TagTemplate
	}
	
	// no match... use core result
	return coreTemplate;
}
//}}}
/***
|Name|TaggedTemplateTweakInfo|
|Source|http://www.TiddlyTools.com/#TaggedTemplateTweak|
|Documentation|http://www.TiddlyTools.com/#TaggedTemplateTweakInfo|
|Version|1.6.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|documentation|
|Description|Documentation for TaggedTemplateTweak|
This plugin extends the core function, story.chooseTemplateForTiddler(), so that any given tiddler can be viewed and/or edited using alternatives to the standard tiddler templates.  To select alternative templates, a 'template prefix' is determined by using the tiddler's title or matching a tag value or using a value stored in a custom tiddler field.  
!!!!!Usage
<<<
*The plugin first attempts to use the tiddler's //title// as a prefix added to the standard TiddlyWiki template titles, [[ViewTemplate]] and [[EditTemplate]] (i.e., ''TiddlerNameViewTemplate'' and ''TiddlerNameEditTemplate'').  This allows you to associate a custom template with a specific tiddler, without needing to add any special tags or custom field values to that individual tiddler.  
*You can also define a tiddler's template prefix by using a //custom tiddler field// named 'template'.  If no corresponding template was found using the tiddler's title, then the tiddler's 'template' field value, if present, will be used as a prefix (e.g., if template='SomeThing', then [[SomeThingViewTemplate]] will be applied).
*If no template is found using the either the title or 'template' field, then each of the tiddler's tags is tried as a template prefix, until a corresponding template, if any, is found.  For example, any tiddlers that are tagged with ''<<tag media>>'' could find alternative templates named [[mediaViewTemplate]] and [[mediaEditTemplate]].
*If you using a systemTheme, the plugin will also tries adding the currently selected theme name (specified by {{{config.options.txtTheme}}}) to the template name (e.g. ''[[SomeTheme##MediaViewTemplate]]'') so that the alternative template definitions can be contained as //sections// within a single systemTheme tiddler.
*Lastly, if no alternative template is found at all, the standard [[ViewTemplate]] or [[EditTemplate]] definition as determined by the TiddlyWiki core handler is used.
Notes:
*You can redefine the //name// of the custom field used to store the template prefix.  For example, to use the name of a TiddlyWeb server-side 'bag' as a prefix (so that tiddlers from separate bags can have different appearances), add the following to a tiddler tagged with<<tag systemConfig>>:{{block{
{{{
config.options.txtTemplateTweakFieldname='server.bag'; // use TiddlyWeb bag name as prefix
}}}
}}}
*To permit use of templates that have proper WikiWord tiddler titles (e.g., [[MediaViewTemplate]] and [[MediaEditTemplate]]), the plugin also attempts to use a capitalized form of the tag value (e.g., ''Media'') as a prefix.  //This capitalization is for comparison purposes only and will not alter the actual tag values that are stored in the tiddler.//
<<<
!!!!!Examples
<<<
|Sample tiddler| tag | view template | edit template |
|[[MediaSample - QuickTime]]| <<tag media>> | [[MediaViewTemplate]] | [[MediaEditTemplate]] |
|[[MediaSample - Windows]]| <<tag media>> | [[MediaViewTemplate]] | [[MediaEditTemplate]] |
|[[CDSample]]| <<tag CD>> | [[CDViewTemplate]] | [[CDEditTemplate]] |
|<<newTiddler label:"create new task..." title:SampleTask tag:task text:"Type some text and then press DONE to view the task controls">> | <<tag task>> | [[TaskViewTemplate]] | [[EditTemplate]] |

//(note: if these samples are not present in your document, please visit// http://www.TiddlyTools.com/ //to view these sample tiddlers on-line)//
<<<
!!!!!Revisions
<<<
2009.09.02 1.6.1 apply field-based template (if any) *before* tag-based template
2009.07.31 1.6.0 added support for using custom field value as prefix
2009.05.04 1.5.2 check for tiddler exist *after* title-as-prefix (allows shadow tiddlers to use custom templates)
2009.01.06 1.5.1 reversed logic so that title-as-prefix takes precedence over tag-matched prefix
2008.12.18 1.5.0 added handling for using tiddler //title// as prefix (e.g., {{{SomeTiddlerViewTemplate}}}) 
2008.08.29 1.4.1 corrected handling for tiddlers with no matching tagged template when non-default theme is in effect (e.g., use "MyTheme##ViewTemplate").
2008.05.15 1.4.0 support use of *shadow* tagged templates (e.g., [[DiscussionViewTemplate]] created by [[DiscussionPlugin]])
2008.05.10 1.3.0 corrected handling for determining core template when using theme with sections
2008.05.01 1.2.5 added support for tagged templates stored as sections in a theme
2008.04.01 1.2.0 added support for using systemTheme section-based template definitions (requested by Phil Hawksworth)
2008.01.22 [*.*.*] plugin size reduction - documentation moved to [[TaggedTemplateTweakInfo]]
2007.06.23 1.1.0 re-written to use automatic 'tag prefix' search instead of hard coded check for each tag.  Allows new custom tags to be used without requiring code changes to this plugin.
2007.06.11 1.0.0 initial release
<<<
Tiddlers that are tagged with<<tag task>>can be used to ''describe specific tasks'' and ''assign'' them to individuals, ''track'' the status (e.g., "not started", "in progress", "done", etc.), and ''record elapsed time'' of specific activities connected to a given task.

Task tiddlers are displayed using a custom [[TaskViewTemplate]], which automatically embeds extra task-related controls directly in the tiddler //view//, allowing you to quickly ''assign and track task progress, without needing to edit the tiddler content.''

''To start a new task, simply create a tiddler, enter some text (e.g., notes about the task), add tag<<tag task>>, and then press 'done' to start viewing the tiddler.''  Alternatively, you can add the following """<<newTiddler>>""" macro in your SideBarOptions (or any other tiddler) to insert a<<newTiddler label:'new task' title:'NewTask' tag:'task' prompt:'create a task tiddler'>>command into your document:
{{{
<<newTiddler label:'new task' title:'NewTask' tag:'task' prompt:'create a task tiddler'>>
}}}
/***
|Name|TaskTimerPlugin|
|Source|http://www.TiddlyTools.com/#TaskTimerPlugin|
|Documentation|http://www.TiddlyTools.com/#TaskTimerPluginInfo|
|Version|1.4.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|'timer' button automatically writes start/end/elapsed time into tiddler content|
Quickly generate 'timed task' logs that can be used for status reports, billing purposes, etc.  
!!!!!Documentation
> see [[TaskTimerPluginInfo]]
!!!!!Configuration
> see [[TaskTimerPluginConfig]]
!!!!!Revisions
<<<
2008.11.10 [1.4.1] in elapsed time calculation, truncate start/stop times to nearest second (avoids 1-second 'round-down' error)
|please see [[TaskTimerPluginInfo]] for additional revision details|
2007.03.14 [0.5.0] converted from inline script
<<<
!!!!!Code
***/
//{{{
version.extensions.TaskTimerPlugin= {major: 1, minor:4, revision: 1, date: new Date(2008,11,10)};

config.macros.taskTimer = {
	label: "start timer",
	title: "press to start the task timer",
	format: "|%4|%0|%1|%2|%3|\\n", // note: double-backslash-en, also date is %4 (for backward compatibility)
	defText: " ", // default description text
	todayKeyword: "today",
	todayFormat: "0MM/0DD/YYYY", // default format - superceded by CalendarPlugin, DatePlugin, or DatePluginConfig
	datestampFormat: "YYYY-0MM-0DD", // date stamp format
	buttonFormat: "%0 - %2",  // timer button formats: %0=current time, %1=start time, %2=elapsed time
	defHeader: "|//Date//|//Description//|//Started//|//Stopped//|//Elapsed//|\n",
	defTarget: "ActivityReport",
	descrMsg: "Enter a short description for this activity.  Press [cancel] to continue timer.",
	askMsg: "Enter the title of a tiddler in which to record this activity.  Press [cancel] to continue timer.",
	errMsg: "'%0' is not a valid tiddler title.  Please try again...\n\n",
	createdMsg: "'%0' has been created",
	updatedMsg: "'%0' has been updated",
	marker: "/%"+"tasktimer"+"%/",
	tag: "task",
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		var target=params.shift(); // get optional target tiddler title
		if (!target) target="";
		var format=this.format; if (params[0]) format=params.shift(); // get optional output format
		var descrMsg=this.descrMsg; if (params[0]) descrMsg=params.shift(); // get optional message text
		var defText=this.defText; if (params[0]) defText=params.shift(); // get optional default text
		var onclick="config.macros.taskTimer.toggle(this,'"+target+"','"+format+"','"+descrMsg+"','"+defText+"')";
		createTiddlyElement(place,"span").innerHTML =
			'<input type="button" value="start timer" title="'+this.title+'" onclick="'+onclick+'">';
	},
	toggle: function(here,target,format,msg,defText) {
		if (!target || !target.length || target=="here") {
			var  tid=story.findContainingTiddler(here);
			target=tid?tid.getAttribute("tiddler"):"ask";
		}
		if (!here.running) { // not running... start timer...
			here.startTime=new Date();
			var now=here.startTime.formatString("0hh:0mm:0ss");
			here.title=(here.target||target)+" - started at "+now;
			here.value=this.buttonFormat.format([now,now,"00:00:00"]);
			here.id=new Date().getTime()+Math.random().toString(); // unique ID
			here.ticker=setTimeout("config.macros.taskTimer.tick('"+here.id+"')",500);
			here.running=true;
		} else {
			if (target=="ask") {
				target=prompt(this.askMsg,here.target||this.defTarget);
				while (target && !target.trim().length)
					target=prompt(this.errMsg.format([target])+this.askMsg,here.target||this.defTarget);
				if (!target) return; // user cancelled input...  continue timer
			}
			var txt=prompt(msg,defText); // get description from user
			if (!txt) return; // user cancelled input...  continue timer
			if (target==this.todayKeyword || target.substr(0,this.todayKeyword.length+1)==this.todayKeyword+":")
				target=(new Date()).formatString(this.getJournalFormat(target));
			here=document.getElementById(here.id); // RE-get button element after timer has stopped...
			clearTimeout(here.ticker);
			here.target=target;
			var before=this.defHeader;
			var after=this.marker+"\n";
			var tiddler=store.getTiddler(here.target);
			if (tiddler && tiddler.text.length) {
				var pos=tiddler.text.indexOf(this.marker);
				if (pos==-1) pos=tiddler.text.length; // no marker, append content to end
				var before=tiddler.text.substr(0,pos); // everything up to marker
				if (before.length&&before.substr(before.length-1)!="\n") before+="\n"; // start on a new line
				var after=tiddler.text.substr(pos); // marker+everything else
			}
			var now=new Date(Math.floor(new Date()/1000)*1000);
			var then=new Date(Math.floor(here.startTime/1000)*1000);
			var diff=new Date(now-then);
			var s=diff.getUTCSeconds(); if (s<10) s="0"+s;
			var m=diff.getUTCMinutes(); if (m<10) m="0"+m;
			var h=diff.getUTCHours(); if (h<10) h="0"+h;
			var start=then.formatString("0hh:0mm:0ss");
			var stop=now.formatString("0hh:0mm:0ss");
			var elapsed=h+":"+m+":"+s;
			var dateStamp=now.formatString(config.macros.taskTimer.datestampFormat);
			var newtxt=before+format.format([txt,start,stop,elapsed,dateStamp])+after;
			var newtags=(tiddler?tiddler.tags:['task']); // include 'task' tag when creating new tiddlers
			store.saveTiddler(here.target,here.target,newtxt,config.options.txtUserName,new Date(),newtags,tiddler?tiddler.fields:null);
			if (!tiddler) displayMessage(this.createdMsg.format([here.target]));
			else displayMessage(this.updatedMsg.format([here.target]));
			here.running=false;
			here.value=this.label;
			here.title=this.title;
			var  tid=story.findContainingTiddler(here);
			if (!tid || tid.getAttribute("tiddler")!=target) // display target tiddler, but only when button is not IN the target tiddler
				{ story.displayTiddler(story.findContainingTiddler(here),here.target); story.refreshTiddler(here.target,1,true); }
		}
	},
	tick: function(id) {
		var here=document.getElementById(id); if (!here) return;
		var now=new Date();
		var diff=new Date(now-here.startTime);
		var s=diff.getUTCSeconds(); if (s<10) s="0"+s;
		var m=diff.getUTCMinutes();  if (m<10) m="0"+m;
		var h=diff.getUTCHours();  if (h<10) h="0"+h;
		var elapsed=h+":"+m+":"+s;
		now=now.formatString("0hh:0mm:0ss");
		var start=here.startTime.formatString("0hh:0mm:0ss");
		here.value=this.buttonFormat.format([now,start,elapsed]);
		here.ticker=setTimeout("config.macros.taskTimer.tick('"+id+"')",500);
	},
	getJournalFormat: function(target) {
		var fmt=target.split(":"); fmt.shift(); fmt=fmt.join(":");
		if (!fmt || !fmt.length) { // if date format was not specified
			if (config.macros.date)  // if installed, use default from DatePlugin
				fmt=config.macros.date.linkformat;
			if (config.macros.calendar) { // if installed, use default from CalendarPlugin
				if (!config.macros.date) // hard-coded calendar fallback if no DatePlugin
					fmt=config.macros.calendar.tiddlerformat;
				else // journalDateFmt is set when calendar is rendered with DatePlugin
					fmt=config.macros.calendar.journalDateFmt;
			}
		}
		if (!fmt) { // if not specified and no DatePlugin/CalendarPlugin
			// get format from <<newJournal>> in SideBarOptions
			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]) fmt = pa[0]; }
		}
		if (!fmt) var fmt=this.todayFormat; // no "newJournal"... final fallback.
		return fmt;
	}
}
//}}}
/***
|Name|TaskTimerPluginConfig|
|Source|http://www.TiddlyTools.com/#TaskTimerPluginConfig|
|Documentation|http://www.TiddlyTools.com/#TaskTimerPluginInfo|
|Version|1.3.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|formats other optional settings for TaskTimerPlugin|
***/
//{{{
// default target tiddler title (when 'ask' option is used)
config.macros.taskTimer.defTarget="ActivityReport";

// table heading (when creating **new** target tiddlers only)
config.macros.taskTimer.defHeader="|//Date//|//Description//|//Started//|//Stopped//|//Elapsed//|\n";

// note: double-backslash-en, also datestamp is %4 (for backward compatibility)
config.macros.taskTimer.format="|%4|%0|%1|%2|%3|\\n";

// date stamp format (used with %4, above)
config.macros.taskTimer.datestampFormat="YYYY-0MM-0DD";

// default description text - note: do not use empty string (e.g., "")
config.macros.taskTimer.defText=" ";

// format for target tiddler title (when "today" option is used)
// otherwise, value is superceded by CalendarPlugin, DatePlugin, DatePluginConfig,
// or format from <<newJournal>> macro embedded in SideBarOptions
config.macros.taskTimer.todayFormat="0MM/0DD/YYYY";

// marker for locating 'insertion point' in target tiddler
config.macros.taskTimer.marker="/%"+"tasktimer"+"%/"; //

// default tag (when creating **new** target tiddlers only)
config.macros.taskTimer.tag="task";
//}}}
/***
|Name|TaskTimerPlugin|
|Source|http://www.TiddlyTools.com/#TaskTimerPlugin|
|Documentation|http://www.TiddlyTools.com/#TaskTimerPluginInfo|
|Version|1.4.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|documentation|
|Description|documentation for TaskTimerPlugin|
Quickly generate 'timed task' logs that can be used for status reports, billing purposes, etc.  
!!!!!Usage
<<<
{{{
<<taskTimer TiddlerName "output format" "prompt text" "default description">>
}}}
creates a 'stopwatch' button that, when pressed, displays the elapsed time (in seconds).  Pressing the button again stops the timer, and prompts for a 'target tiddler' (default: [[ActivityReport]] and a 'task description' and writes the description, starttime, endtime, and elapsed time into the indicated tiddler's content.

''~TiddlerName'' //or// ''ask'' //or// ''here'' //or// ''today'' //or// ''"""today:YYYY0MM0DD"""''
>If you omit the ''~TiddlerName'' parameter or use the keyword, ''here'', the output is inserted into the current tiddler.  If you use the keyword, ''ask'', then you will be prompted for a ~TiddlerName each time you press the button to stop the timer.  If you use the keyword, ''today'', then the current date is used as the ~TiddlerName.  You can specify any date format you like by appending it to the "today:" keyword.  If the format is omitted, the format will match that used by {{{<<newJournal>>}}} macro or the {{{<<date>>}}} and {{{<<calendar>>}}} macros (if [[DatePlugin]] and/or [[CalendarPlugin]] are installed).
>
>If the target tiddler does not yet exist, it will be automatically created when a timer activity is recorded for the first time.  Note: When used in a non-tiddler area (such as MainMenu), you should either provide a specific ~TiddlerName value (e.g., {{{<<taskTimer MainMenu>>}}} or use the ''ask'' or '''today'' keywords.
''output format''
>The default output format is: {{{|%4|%0|%1|%2|%3|}}} where %0, %1, %2, %3 and %4 are automatically replaced with the description, starttime, stoptime, elapsed time and current date values, respectively.  This format generates a single row using TiddlyWiki table format, allowing each subsequent timed task to add another row to an existing table of recorded activities.  If this table format is not appropriate for your needs, you can provide an alternative formatting string, using the %n substitution markers to place those values where you want.
>
>//Please note: ''Do not use either single-quotes or double-quotes within the format string, as this interferes with the plugin's button generating code.  Also, for backward-compatibility with previous versions of this plugin, the date value is indicated using the %4 'substitution marker', even though it is displayed as the first item in the table row.''//
''insertion point marker''
>The task timer output is usually appended to the end of the target tiddler content.  However, you may choose to insert the output //anywhere// within the tiddler content simply by embedding an 'insertion point marker', consisting of the keyword "tasktimer", enclosed in TW style comments, like this: ''{{{/%}}}{{{tasktimer}}}{{{%/}}}''.  When the marker is present in the tiddler source, the timed task report output is placed immediately //before// that marker, instead of at the end of the tiddler.
<<<
!!!!!Configuration
<<<
You can further customize the formats used by creating a separate tiddler, e.g. [[TaskTimerPluginConfig]], tagged with<<tag systemConfig>>, that contains any combination of the following javascript statements:
{{{
// default target tiddler title (when 'ask' option is used)
config.macros.taskTimer.defTarget="ActivityReport";

// table heading (when creating **new** target tiddlers only)
config.macros.taskTimer.defHeader="|//Date//|//Description//|//Started//|//Stopped//|//Elapsed//|\n";

// note: double-backslash-en, also datestamp is %4 (for backward compatibility)
config.macros.taskTimer.format="|%4|%0|%1|%2|%3|\\n";

// date stamp format (used with %4, above)
config.macros.taskTimer.datestampFormat="YYYY-0MM-0DD";

// default description text - note: do not use empty string (e.g., "")
config.macros.taskTimer.defText=" ";

// format for target tiddler title (when "today" option is used)
// otherwise, use format from CalendarPlugin, DatePlugin, DatePluginConfig,
// or <<newJournal>> macro embedded in SideBarOptions
config.macros.taskTimer.todayFormat="0MM/0DD/YYYY";

// marker for locating 'insertion point' in target tiddler
config.macros.taskTimer.marker="/%tasktimer%/";

// default tag (when creating **new** target tiddlers only)
config.macros.taskTimer.tag="task";
}}}
<<<
!!!!!Examples
<<<
{{{<<taskTimer>>}}}
<<taskTimer>>
|//Date//|//Description//|//Started//|//Stopped//|//Elapsed//|
/%tasktimer%/
{{{<<taskTimer ask>>}}}
<<taskTimer ask>>
<<<
!!!!!Revisions
<<<
2008.11.10 1.4.1 in elapsed time calculation, truncate start/stop times to nearest second (avoids 1-second 'round-down' error)
2008.10.31 1.4.0 added 'buttonFormat' for custom timer button display using %0=current, %1=start, %2=elapsed
2008.03.12 1.3.0 added 'datestampFormat' for including date in standard output.  Also, for clarity, renamed 'getDateFormat()' to 'getJournalFormat()'.
2008.03.10 [*.*.*] plugin size reduction - documentation moved to [[TaskTimerPluginInfo]]
2007.12.13 1.2.2 in getDateFormat(), cleanup fallback logic 
2007.06.28 1.2.1 pass current tiddler.fields to saveTiddler(), so updates to existing tiddler won't lose custom fields
2007.06.25 1.2.0 added optional "default text" param for specifying the default description for new activity log entries
2007.06.22 1.1.0 added "today" and "today:MMDDYYYY" as special keywords.  Generates tiddlername from current date, and uses date format defined in CalendarPlugin, DatePlugin, or DatePluginConfig if any of those tiddlers is installed.  Also, don't stop timer until user completes entering of prompted inputs (e.g., after asking for a target tiddler and activity description)
2007.05.22 1.0.0 target tiddler created when stopping timer button (i.e., second button press) instead of when starting timer.  Default header content includes comment marker.  Target tiddler is tagged with "task".
2007.04.04 0.8.2 moved handling for 'here' param into toggle().  In toggle(), only render target tiddler if button is not in that tiddler... fixes problem where starting timer with target=here was re-rendering (and thus re-initializing) the timer button (immediately stopping the timer)
2007.03.21 0.8.1 handle case where target tiddler is deleted while timer is running.
2007.03.21 0.8.0 use UTC time functions to calculate elapsed time in hours, minutes, and seconds
2007.03.20 0.7.0 added lots of cool features, like automatically creating tiddlers, with prompting, etc.
2007.03.14 0.5.0 converted from inline script
<<<
<!--{{{-->
<!--
|Name|TaskViewTemplate|
|Source|http://www.TiddlyTools.com/#TaskViewTemplate|
|Version||
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|template|
|Requires|ToolbarCommands, TaggedTemplateTweak, ListboxPlugin, CheckboxPlugin, TaskTimerPlugin, WikifyPlugin, NestedSlidersPlugin, MoveablePanelPlugin, CommentPlugin, ToggleSliders |
|Description|custom version of view template used when tiddler is tagged with "task"|
-->
<span class='toolbar' macro='toolbar [[ToolbarCommands::ViewToolbar]]'></span>
<span class='title'>
	<span class='floatleft' macro='tiddlerIcons' style='cursor:auto !important;'></span>
	<span macro='view title'></span>
</span>
<span class='subtitle'>
	<span style='white-space:nowrap' macro='view modified date [[DDD, MMM DDth YYYY]]'></span>
</span>
<div class='tagClear'></div>
<div class='tagging' macro='tagging'></div>
<div class='tagged' macro='tags'></div>
<!-- TASK CONTROLS one line hanging "bubble" (bottom right) -->
<div class='viewer'>
	<div macro='view text wikified'></div>
	<div class="floatright block" style="height:2em;padding-top:2px;">
		<div class="center viewer smallform" style="padding:.5em 1em">
			<span class='fine subtitle'>task status:</span>
			<span macro='select status rows:1 allowOther "not started" "in progress" "on hold" "completed"'></span>
			<span class='fine subtitle'>assigned to:</span>
			<span macro='select assigned rows:1 allowBlank allowOther +TaskAssignmentList allowEdit'></span>
			<span macro='checkbox urgent@'></span>
			<span class='fine subtitle'>urgent</span>
			<span macro='taskTimer'></span>
			<span class='fine subtitle' style='padding-left:1em'
				macro='wikify [[+++^40em^{{small{[add a note]}}}...<<moveablePanel>>add a note<html><hr></html><<comment here "" "+++!!!!![%when% (%who%): %subject%]>...\n%message%\n===\n">>=== | <<tiddler ToggleSliders with: here "view all" "close all">>]]'></span>
		</div>
	</div>
</div>
<div class='tagClear'></div>
<!--}}}-->
/***
|Name|TemporaryTiddlersPlugin|
|Source|http://www.TiddlyTools.com/#TemporaryTiddlersPlugin|
|Version|1.1.2|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|blocks tiddlers tagged with "temporary" from being saved into the TW file|
!!!!!Usage
<<<
When the TW document is saved (either to local disk or remote URL), any tiddlers tagged with "temporary" will be skipped over, so that they are not written to the file.  To keep a temporary tiddler, simply edit it and remove the tag before saving the file.  This feature can be combined with various plugins that can automatically create new tiddlers, such as [[SearchOptionsPlugin]] ([[SearchResults]]) and [[ImportTiddlersPlugin]] ([[ImportedTiddlers]]) so that these transient results are not retained when you save you document.

You can also use this tag with the {{{<<loadTiddlers>>}}} macro and the //auto-tagging// features provided by [[ImportTiddlersPlugin]], so that each time you open your document, you can automatically retrieve an up-to-date set of common tiddlers that are stored in another document (either local or via remote URL), without those tiddlers being retained when you save your document.
<<<
!!!!!Configuration
<<<
When saving the document:
<<option chkTemporaryQuiet>> Suppress reporting of individual temporary tiddlers that have not been saved
<<option chkTemporaryKeep>> Keep temporary tiddlers (i.e., ignore the 'temporary' tag)
Enter a tag value to use when marking tiddlers as temporary: <<option txtTemporaryTag>>
<<<
!!!!!Revisions
<<<
2008.11.14 [1.1.2] added "nnn temporary tiddlers not saved" summary message
2008.04.08 [1.1.1] don't automatically add configuration options to AdvancedOptions tiddler
2008.03.01 [1.1.0] added support for recognizing 'temporary' flag stored as a tiddler *field* (as an optional alternative to using a tag)
2007.02.08 [1.0.0] initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.TemporaryTiddlersPlugin= {major: 1, minor: 1, revision: 2, date: new Date(2008,11,14)};

// configuration defaults
if (config.options.chkTemporaryKeep ==undefined) config.options.chkTemporaryKeep =false;
if (config.options.chkTemporaryQuiet==undefined) config.options.chkTemporaryQuiet=true;
if (config.options.txtTemporaryTag==undefined) config.options.txtTemporaryTag="temporary";
// lingo
config.messages.TemporaryWarning = "'%0' ...temporary tiddler";
config.messages.TemporarySummary = "%0 temporary tiddlers will not be saved";
// core override
SaverBase.prototype.externalize = function(store) 
{
	var results=[]; var totaltemps=0;
	var tiddlers=store.getTiddlers("title");
	for (var t=0; t<tiddlers.length; t++) {
		if (config.options.chkTemporaryKeep||!(tiddlers[t].fields['temporary']||tiddlers[t].isTagged(config.options.txtTemporaryTag)))
			results.push(this.externalizeTiddler(store, tiddlers[t]));
		else {
			if (!config.options.chkTemporaryQuiet) // notify user that tiddler won't be saved
				displayMessage(config.messages.TemporaryWarning.format([tiddlers[t].title]));
			totaltemps++;
		}
	}
	if (totaltemps) displayMessage(config.messages.TemporarySummary.format([totaltemps]));
	return results.join("\n");
}
//}}}
PasteUpPluginHelper test:
<<tag alpha>>
<<pasteUp TestPart style:"border:1px solid blue;color:black;background:white;" x:3in y:0.6in w:3in h:auto>>
+++!!![nonexistent tag link shows popup]...
/***
FooBar
***/
<script show>
if (!window.onClickTiddlerLink_taglink)
	window.onClickTiddlerLink_taglink=window.onClickTiddlerLink;
window.onClickTiddlerLink=function(ev) {
	var e=ev||window.event;	var target=resolveTarget(e); var title=null;
	while (target!=null && title==null) {
		title=target.getAttribute('tiddlyLink');
		target=target.parentNode;
	}
	var t=store.getTiddlerText(title);
	if (t) onClickTiddlerLink_taglink.apply(this,arguments);
	else {
		alert('tiddler not found!');
	}
	return false;
}
</script>
===
+++!!![createTiddler paramifier]...
{{{
config.paramifiers.createTiddler = {
	onstart: function(v) {
		if(readOnly) return;
		var d=document.createElement('div');
		wikify('<<newTiddler title:'+v+'>>',d);
		d.getElementsByTagName('A')[0].onclick();
	}
};
}}}
===
+++!!![StatusLiner]...
/%
!out
$1
!end
!link
<a href="javascript:;" title="%0" tid="%1" onclick="
	var msg=this.innerHTML+'\n\status: ';
	var s=prompt(msg,this.title); if (!s) return false;
	var t=store.getTiddler(this.getAttribute('tid')); if (!t) return false;
	var pat=((this.title!='?'?this.title+'\|':'')+this.innerHTML+'\n').escapeRegExp();
	var txt=t.text.replace(new RegExp(pat,'mg'),s+'|'+this.innerHTML+'\n');
	var who=config.options.chkForceMinorUpdate?t.modifier:config.options.txtUserName;
	var when=config.options.chkForceMinorUpdate?t.modified:new Date();
	store.saveTiddler(t.title,t.title,txt,who,when,t.tags,t.fields);
	story.refreshTiddler(t.title,null,true);
	this.title=s;
	return false;
">%2</a><br>
!end
%/<<tiddler NewTiddler##out with: {{
	var out=[];
	out.push('<html><nowiki><div style="white-space:nowrap;overflow:auto;">');
	var tid='Greetings';
	var lines=store.getTiddlerText(tid,'').split('\n');
	var link=store.getTiddlerText('TestTiddler##link');
	for (var i=0; i<lines.length; i++) {
		var parts=lines[i].split('|');
		var status=parts[0];
		var txt=parts[1]||parts[0];
		if (!parts[1]) status='?';
		out.push(link.format([status,tid.split('##')[0],txt]));
	}
	out.push('</div></html>');
	out.join('');
}}>>
===
+++!!![ToggleClass]...
|Description|toggle extra class on text contained in specified wrapper class|
Usage:
{{{
<<tiddler ToggleClass with: "label" targetClass toggleClass>>
}}}
*"label" specifies the command/link text.  Use quotes to surround text containing spaces (default is "toggle hints")
*'targetClass' specifies the class of element that will be altered (default is "hint")
*'toggleClass' specifies the additional class to be added or removed from all target elements (default is "highlight").
Target elements are designated by containing them in class wrappers, for example:
{{hint{this text will be toggled}}}... but this text won't...
<script label="toggle hints" show>
	if (!(addClass instanceof Function) || !(removeClass instanceof Function)) return;
	var here=story.findContainingTiddler(place); if (!here) return false;
	var elems=here.getElementsByTagName("*");
	var targetClass="hint"; if ("$"+"2"!="$2") targetClass="$2";
	var toggleClass="highlight"; if ("$"+"3"!="$3") toggleClass="$3";
	for (var e=0; e<elems.length; e++)
		if (hasClass(elems[e],targetClass))
			if (hasClass(elems[e],toggleClass))
				removeClass(elems[e],toggleClass);
			else
				addClass(elems[e],toggleClass);
	return false;
</script><script>
	if ("$"+"1"!="$1") place.lastChild.innerHTML="$1";
</script>
===
+++!!![AnimationEffect vertical scroller]...
{{{
Usage:
<<tiddler VScroll with: TiddlerName height duration delay >>

Example:
<<tiddler VScroll with: About 7em 10000 1000>>

@@display:block;padding:0;margin:0;height:$2;overflow:hidden;
{{block{
<<tiddler [[$1]]>><<animate = top %0px 0 {{-place.clientHeight}} $4 $3>>}}}@@
}}}
===
+++!!![append to tiddler]...
add a single-line of input to the end of the current tiddler:
<html><nowiki><form style="white-space:nowrap" onsubmit="this.btn.onclick(); return false">
<input type="text" name="in" style="width:90%" value="">
<input type="button" name="btn" style="width:8%" value="ok" onclick="
	if (!this.form.in.value.length) return false; 
	if (this.form.in.value==this.form.in.defaultValue) return false; 
	var here=story.findContainingTiddler(this); if (!here) return false;
	var title=here.getAttribute('tiddler');
	var tid=store.getTiddler(title);
	var now=new Date();
	var datefmt='YYYY.0MM.0DD 0hh:0mm:0ss';
	var txt=(tid?tid.text:'')+'\n'+now.formatString(datefmt)+this.form.in.value;
	var who=tid?tid.modifier:config.options.txtUserName;
	var when=tid?tid.modified:now;
	var tags=tid?tid.tags:[];
	var fields=tid?tid.fields:{};
	store.saveTiddler(title,title,txt,who,when,tags,fields);
"></form></html>
===
+++!!![Show slices]...
{{smallform small{<html><hide linebreaks><form><!--
	--><select name="tidlist" size=1 style="width:40%" 
		onchange="var target=this.form.parentNode.nextSibling.nextSibling; removeChildren(target); wikify(this.value,target);">
		<option value="">select a tiddler...</option>
	</select><input type="text" name="re" style="width:50%" title="tiddler slice pattern (store.slicesRE)"><!--
	--><input type="button" name="set" value="set" style="width:9%" title="set slice pattern and re-scan for slices"
		onclick="store.slicesRE=new RegExp(this.form.re.value,'gm');
			var tid=story.findContainingTiddler(this).getAttribute('tiddler');
			story.refreshTiddler(tid,null,true);"></form></html><script>

	// initialize form field
	var form=place.lastChild.getElementsByTagName("form")[0];
	var re=store.slicesRE.toString();
	re=re.substring(1,re.length-3); // strip delimiters/flags from re
	form.re.value=re;

	// define slice filter (only report indicated slices)
	var filter={ Name:1, Source:1, Version:1, Author:1, License:1,
		CoreVersion:1, Type:1, Requires:1, Overrides:1, Description:1 };
	var filter=null; // show all defined slices - remove this line to use pre-defined filter

	var allslices=[]; // will be filled with names of all slices from all tiddlers
	var slicefmt='\'\'"""%0"""\'\'\n&nbsp;&nbsp;%1\n'; // indented format
	var slicefmt='| %0|%1|\n'; // table format - remove this line to use indented format
	var slicefmt='\'\'%0=\'\'%1\n'; // var=val format - remove this line to use indented format
	var tiddlers=store.getTiddlers("title");
	for (var i=0; i<tiddlers.length; i++) {
		var tid=tiddlers[i];
		var slices=store.calcAllSlices(tid.title);
		var sliceout=[]; var slicecount=0;
		for (var s in filter?filter:slices) {
			sliceout.push(slicefmt.format([s,slices[s]?slices[s]:'-']));
			if (slices[s] || !filter) slicecount++;
			if (slices[s]) allslices.pushUnique("{{{"+s+"}}}");
		}
		if (slicecount) form.tidlist.options[form.tidlist.length]=new Option(tid.title+"("+slicecount+")","<<<\n"+sliceout.join('')+"<<<\n",false,false);
	}
	var out="{{small wrap{There are %0 slice names used in this document.  +++[view list...][hide list...]>{{small{\n%1\n}}}===\n"
	return out.format([allslices.length,"#"+allslices.join('\n#')]);
</script>@@display:block;/%replace with dynamic content%/@@}}}
===
+++!!![Search with tag filter]...
<<tiddler {{config.options['txtMySearch']='';'';}}>><<option txtMySearch>>/%
%/<html><nowiki><form style='display:inline'>
<select name='tags'><option value=''>Filter by tag:</option></select>
<input type='button' value='search' onclick="
	var text=config.options['txtMySearch'];
	var useRE=config.options['chkRegExpSearch'];
	var useCase=config.options['chkCaseSensitiveSearch'];
	highlightHack=new RegExp(useRE?text:text.escapeRegExp(),useCase?'mg':'img');
	var matches=store.search(highlightHack,'tags',this.form.tags.value,true);
	highlightHack=null;
	var q=useRE?'/':'\x27';
	if(matches.length>0) {
//		story.closeAllTiddlers();
		story.displayTiddlers(null,matches);
		displayMessage(config.macros.search.successMsg.format([matches.length.toString(),q+text+q]));
	} else
		displayMessage(config.macros.search.failureMsg.format([q+text+q]));
	return false;
"></form></html><<tiddler {{
	var list=place.lastChild.getElementsByTagName('form')[0].tags;
	var tags=store.getTags()
	for (var t=0;t<tags.length;t++)
		list.options[list.length]=new Option(tags[t][0],tags[t][0]);
'';}}>>
===
+++!!![ListSections]...
<script>
var title=prompt('enter tiddler title','SectionLinksPlugin'); if (!title) return;
var pattern=/(^|\n)!{1,6}([^eE\n][^nN\n][^dD\n])[^\n]*\n/g;
var matches=store.getTiddlerText(title).match(pattern);
var out='<<tabs txtCurrentTab ';
for (var i=0;i<matches.length;i++) {
	var m=matches[i].replace(/!{1,6}|\n/g,'').replace(/"/g,'\\x22').replace(/>>/g,'>\\>').replace(/\}\}\}/g,'}\\}\\}');
	out+= '{{"'+m+'"}} {{"'+m+'"}} {{"'+title+'##'+m+'"}} ';
}
out += '>>';
return out;
</script>
===
+++!!![Report missing tiddler errors in &lt;&lt;tiddler&gt;&gt; macro]...
<script>
var lines=['config.macros.tiddler.handler='];
lines=lines.concat(config.macros.tiddler.handler.toString().split('\n'));
lines.splice(2,0,'if (!store.getTiddlerText(params[0])) return wikify("Error in [["+tiddler.title+"]]: <nowiki><<tiddler [[</nowiki>"+params[0]+"<nowiki>]]>></nowiki> not found",place);');
eval(lines.join('\n'));
</script>
===
+++!!![ShowTagsAsTabs]...
<script>

// get tiddlers and separate them into groups
var groups={};
var tids=store.getTiddlers();
for (var t=0; t<tids.length; t++) {
	for (var i=0; i<tids[t].tags.length; i++) {
		var g=tids[t].tags[i];
		if (!groups[g]) groups[g]=[];	
		groups[g].push(tids[t]);
	}
}

// generate a tiddler with bullet lists contained in group sections
var title='TagsAsTabs';
var out=[];
for (var g in groups) {
	out.push('!'+g);
	for (var i=0; i<groups[g].length; i++)
		out.push('*[['+groups[g][i].title+']]');
	out.push('!end');
}
config.shadowTiddlers[title]=out.join('\n');

// NOTE: as of TW252, the core doesn't handle sections in *shadows*
// As a temporary workaround, this HACK creates a real tiddler.
// See CoreTweaks for corrected store.getTiddlerText() definition
// store.saveTiddler(title,title,out.join('\n'),config.options.txtUserName,new Date(),[],{});

// generate heading and <<tabs>> macro to show group sections
var out=[];
for (var g in groups)
	out.push('[['+g+']] [['+g+']] [[TagsAsTabs##'+g+']]');
var heading='There are '+tids.length+' tiddlers in '+out.length+' groups:<br>';
var tabs='<<tabs txtTagsAsTabs '+out.join(' ')+'>>';
return heading+tabs;
</script>
===
+++!!![ShowTransclusions]...
<html><hide linebreaks>
<a href="javascript:;" title="list tiddlers that have transcluded this tiddler" onclick="
	var t=story.findContainingTiddler(this).getAttribute('tiddler');
	var m=new RegExp('\<\<tiddler (\\[\\[)?'+t+'(\\]\\])?( with: .*)?\>\>','');
	var s=store.search(m,'text','excludeLists');
	var out=[];
	if (!s.length) out.push('no matching tiddlers');
	for (var i=0;i<s.length;i++) out.push(s[i].title);
	var p=Popup.create(this);
	var d=createTiddlyElement(p,'div');
	var s=d.style; s.padding='2px'; s.textAlignment='left';
	wikify(out.join('\n'),d);
	Popup.show();
	event.cancelBubble=true;
	if (event.stopPropagation) event.stopPropagation();
	return false;
">transcluded by</a></html>
===
+++!!![YouTube]...
<html><object width="425" height="355" style="width:100%;height:auto;"><param name="movie" value="http://www.youtube.com/v/_PxOCNcTGu8&hl=en&rel=0"></param><embed src="http://www.youtube.com/v/_PxOCNcTGu8&hl=en&rel=0" type="application/x-shockwave-flash" width="600" height="500"></embed></object></html>
===
+++!!![ListByTagExampleScript]...
<script show>
var tids=store.getTaggedTiddlers('$1');
var out=[];
out.push('There are '+tids.length+' tiddlers tagged with: <<tag $1>>');
out.push('|title|size|tags|creator|h');
for (var i=0; i<tids.length; i++) { var t=tids[i];
	var f=store.getValue(t.title,'creator')||'';
	out.push('|'+t.title+'|'+t.text.length+'|'+'[['+t.tags.join(']] [[')+']]'+'|');
}
out.push('|sortable|k');
return out.join('\n');
</script>
===
+++!!![FamilyTreeExample]...

+++[John Smith]>
	yyyy/mm/dd - yyyy/mm/dd
	2 children:
	+++[John Smith, Jr]>
		yyyy/mm/dd - yyyy/mm/dd
		2 children:
		+++[John Smith, III]>
			yyyy/mm/dd - 
		===

		+++[Jill Smith]>
			yyyy/mm/dd - 
		===
	===

	+++[Jane (Smith) Jones]>
		yyyy/mm/dd - yyyy/mm/dd
		2 children:
		+++[James Jones]>
			yyyy/mm/dd - 
		===

		+++[Jessica Jones]>
			yyyy/mm/dd - 
		===
	===
===

===
+++!!![Dictionary/TableMaker]...
<script>
window.Dictionary=function(tags,headings) {
	var out=[];
	out.push('|'+headings.join('|')+'|h'); // headings
	var tids=store.getTiddlers();
	for (var i=0; i<tids.length; i++) {
		var cols=[];
		if (!tids[i].tags.containsAll(tags)) continue;
		for (var h=0; h<headings.length; h++) {
			var c=store.getTiddlerSlice(tids[i].title,headings[h]);
			if (!c) var c='<<tiddler '+tids[i].title+'##'+headings[h]+'>>';
			cols.push(c);
		}
		out.push('|'+cols.join('|')+'|');
	}
	out.push('|sortable|k');
	return out.join('\n');
}
return window.Dictionary(['foo','bar'],['English','French','Description']);
</script>
===
+++!!![parse CSV]...
<script show>
window.parseCSV=function(txt) {
	var lines=txt.split('\n'); var names=lines[0].split(','); txt=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');
	txt=txt.replace(/\x22((?:[^\x22]|\x22\x22)*?)\x22/g,
		function(x){ return x.substr(1,x.length-2).replace(/\,/g,comma).replace(/\n/g,newline); });

	// PARSE lines
	var lines=txt.split('\n');
	var results=[];
	for (var i=1; i<lines.length; i++) { if (!lines[i].length) continue;
		var values=lines[i].split(',');
		// DECODE commas, newlines and doubled-quotes within quoted values
		for (var v=0; v<values.length; v++)
			values[v]=values[v].replace(commaRE,',').replace(newlineRE,'\n').replace(/\x22\x22/g,'\x22');
		// EXTRACT field value
		var fields={}; for (var v=0; v<values.length; v++) fields[names[v].toLowerCase()]=values[v];
		results.push(fields);
	}
	return results;
}
</script>
===
+++!!![list all fields]...
<script>
	var out=[]; var allFields={};
	var tids=store.getTiddlers('title');
	for (var i=0; i<tids.length; i++) for (var f in tids[i].fields) {
		if (!allFields[f]) allFields[f]=[];
		allFields[f].push(tids[i].title);
	}
	var fmt='*%0<br>%1';
	for (var f in allFields) out.push(fmt.format([f,'[['+allFields[f].join(']], [[')+']]']));
	return 'There are '+out.length+' fields:\n\n'+out.join('\n');
</script>
===
+++!!![RetagTiddlers]...
/%
|Name|RetagTiddlers|
|Source|http://www.TiddlyTools.com/#OpenTaggedTiddlers|
|Version|0.5.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.3|
|Type|script|
|Requires|InlineJavascriptPlugin|
|Description|quickly modify tags on matching tiddlers|
|Status:|ALPHA EXPERIMENTAL - please report problems / make suggestions: [[Contact]]|

Usage: <<tiddler RetagTiddlers with: "label" "tagToMatch" "sortBy" "action" "tags" "show">>

label (required)
	text to display
tagToMatch (required)
	tag value used to select tiddlers.
	If MatchTagsPlugin is installed, "tagToMatch" can be a boolean tag expression.
sortBy (optional, default="title")
	is a tiddler field that determines the order of the matched tiddlers.
	Use "-" as a prefix to specify decending order (e.g., "-modified" sorts tiddlers by most-recently changed).
action (optional, default="ask")
	one of: "ask", "set", "add", "remove", "replace".
tags (required, except for "ask" action)
	if set/add/remove action is specified, "tags" is a quoted, space-separated list of tag values to be applied
	if replace action is specified, tags is a quoted, space-separated list of //exactly two tags//: "oldtag newtag"
show (optional)
	is a keyword that causes each matching tiddler to be displayed after modification

Except as noted, all parameters are optional but must be written in the order shown above, if present.  You can use "" as a placeholder equivalent to the default value for any parameter you wish to skip.

%/<script label="$1">
	var list=[];
	var match="$2";
	var sortBy="$3"; if ((sortBy=="$"+"3")) sortBy="title";
	var action="$4"; if ((action=="$"+"4")) action="prompt";
	var tags="$5".readBracketedList();
	var show=("$6"=="show");
	if (action=="replace" && !tags[1]) {
		displayMessage("Retag error: 'replace' must specify exactly two tags");
		return;
	}
	var filter="[tag[%0]][sort[%1]]".format([match,sortBy]);
	var tids=store.filterTiddlers(filter);
	var changed=0;
	for (var i=0;i<tids.length;i++) { var tid=tids[i];
		var newtags=[];
		switch (action) {
			case "set":
				newtags=tags;
				changed++;
				break;
			case "add":
				for (var t=0; t<tid.tags.length; t++)
					newtags.push(tid.tags[t]);
				for (var t=0; t<tags.length; t++)
					newtags.pushUnique(tags[t]);
				changed++;
				break;
			case "remove":
				for (var t=0; t<tid.tags.length; t++)
					if (tags.indexOf(tid.tags[t])==-1)
						newtags.pushUnique(tid.tags[t]);
				changed++;
				break;
			case "replace":
				for (var t=0; t<tid.tags.length; t++)
					newtags.pushUnique(tid.tags[t]==tags[0]?tags[1]:tid.tags[t]);
				changed++;
				break;
			case "ask":
			default:
				var msg="Modify current tags on '"+tid.title+"'\n(Press Cancel for no change to this tiddler)";
				var t=prompt(msg,tid.getTags());
				if (!t) continue;
				newtags=t.readBracketedList();
				changed++;
				break;
		}
		var who=config.options.chkForceMinorUpdate?tid.modifier:config.options.txtUserName;
		var when=config.options.chkForceMinorUpdate?tid.modified:new Date();
		store.saveTiddler(tid.title,tid.title,tid.text,who,when,newtags,tid.fields);
		displayMessage("%0: tags='%1'".format([tid.title,newtags]));
	}
	if (changed && show) {
		for (var i=0;i<tids.length;i++) list.push(tids[i].title);
		story.displayTiddlers(story.findContainingTiddler(place),list);
	}
	displayMessage(changed+" tiddler%0 ha%1 been changed".format([changed!=1?"s":"",changed!=1?"ve":"s"]));
	return false;
</script>
===
+++!!![Regexp Converter Script]...
<script label="convert">
var lines=store.getTiddlerText('corefunctions.txt').split('\n');
var out=[];
for (var i=0; i<lines.length; i++) {
//	var re=/\|[0-9]*\|.*\.js\|([^\|]*).*$/;
	var re=/(.*) = function\(.*$/;
	var match=re.exec(lines[i]);
	if (!match) out.push(lines[i]);
	else out.push(match[1]);
}
store.saveTiddler('corefunctions2.txt','corefunctions2.txt',out.join('\n'),config.options.txtUserName,new Date(),[],{});
return 'out='+out.length;
</script>
===
+++!!![ParseTiddlerParams]...
Usage:
{{{
<<tiddler TiddlerName with: foo=bar "baz=mumble frotz" gronk debug=true>>
}}}
----
<script show>
	// convert "name=value" tiddler params to args['name'] "associative array"
	var args={};
	if ('$1'!='$'+'1') { var t='$1'.split('='); args[t.shift()]=t.join('='); }
	if ('$2'!='$'+'2') { var t='$2'.split('='); args[t.shift()]=t.join('='); }
	if ('$3'!='$'+'3') { var t='$3'.split('='); args[t.shift()]=t.join('='); }
	if ('$4'!='$'+'4') { var t='$4'.split('='); args[t.shift()]=t.join('='); }
	if ('$5'!='$'+'5') { var t='$5'.split('='); args[t.shift()]=t.join('='); }
	if ('$6'!='$'+'6') { var t='$6'.split('='); args[t.shift()]=t.join('='); }
	if ('$7'!='$'+'7') { var t='$7'.split('='); args[t.shift()]=t.join('='); }
	if ('$8'!='$'+'8') { var t='$8'.split('='); args[t.shift()]=t.join('='); }
	if ('$9'!='$'+'9') { var t='$9'.split('='); args[t.shift()]=t.join('='); }
 
	// now you can do something with the args[]...
	var out='';
	if (args['debug']) for (var arg in args) out+=arg+' is: "'+args[arg]+'"\n';
	return out;		
</script>
===
+++!!![plugin sniffer]...
//{{{
window.core_isPluginExecutable=isPluginExecutable;
window.isPluginExecutable=function(plugin) {

	var r=window.core_isPluginExecutable.apply(this,arguments);
	if (!r) return;

	var err=''
	var t=plugin.tiddler.title;
	var u='http://www.TiddlyTools.com/';
	var ver=function(x,y){return (!x||!x.length||!x.startsWith(y))?false:x};
	var msg=function(x)  {return '"'+x+'" is missing/invalid. '}
	var n=plugin["Name"]; var s=plugin["Source"]; var l=plugin["License"];
	if(!(  ver(n,t)))err+=msg('Name');
	if(!(s=ver(s,u)))err+=msg('Source');
	if(!(l=ver(l  )))err+=msg('License');
	if(!err.length) return true;
	err+='Please re-install from '+(s||d||(u+'#'+(n||t)));
	err+=' [See '+(s?(d||l||u):(l||u))+' for more information]';
	plugin.log.push(err);
	return false;
}
if(typeof(verifyPlugin)=='undefined') function verifyPlugin(u) {
	var up=''; var t=tiddler.title;
	var get=function(x)  {return store.getTiddlerSlice(t,x)};
	var ver=function(x,y){return (!x||!x.length||!x.startsWith(y))?false:x};
	var msg=function(x)  {return '"'+x+'" is missing/invalid. '}
	var n=get('Name'); var s=get('Source'); var d=get('Documentation'); var l=get('License');
	if(!(  ver(n,t)))up+=msg('Name');
	if(!(s=ver(s,u)))up+=msg('Source');
	if(!(d=ver(d,u)))up+=msg('Documentation');
	if(!(l=ver( l )))up+=msg('License');
	if(!up.length) return;
	up+='Please re-install from '+(s||d||(u+'#'+(n||t)));
	up+=' [See '+(s?(d||l||u):(l||u))+' for more information]';
	throw(up);
}
if(verifyPlugin)verifyPlugin('http://www.TiddlyTools.com/');
//}}}
===
+++!!![save changes with forced refresh]...
{{{
<script label="save to disk">
	// adds forced refresh to 'save to disk' handling
	saveChanges();
	var anim=config.options.chkAnimate; // save animation setting
	config.options.chkAnimate=false; // suspend animation
	store.notify("SideBarTabs",true); // force refresh after saving
	config.options.chkAnimate=anim; // restore animation setting
	return false;
</script><script>
	place.lastChild.innerHTML=config.macros.saveChanges.label;
	place.lastChild.title=config.macros.saveChanges.prompt;
	place.lastChild.style.fontWeight="normal";
</script>
}}}
===
+++!!![vChumby embed code]...
{{{
!vChumby
<html><hide linebreaks>
	<embed width="492" height="405" quality="high" bgcolor="#FFFFFF" wmode="transparent"
		name="virtualchumby" type="application/x-shockwave-flash"
		src="http://www.chumby.com/virtualchumby2.swf"
		FlashVars="_chumby_profile_url=http%3A%2F%2Fwww.chumby.com%2Fxml%2Fvirtualprofiles%2F$1&amp;baseURL=http%3A%2F%2Fwww.chumby.com"
		pluginspage="http://www.macromedia.com/go/getflashplayer">
	</embed>
</html>
!end
}}}
===
+++!!![vChumby DarkClocks]...<<tiddler TestTiddler##vChumby with: EE97A8A0-FEC1-11DC-BFF1-00156009DD9B>>===
+++!!![vChumby 4Eric]...<<tiddler TestTiddler##vChumby with: 69115A74-6BE9-11DD-9807-001B24F07EF4>>===
+++!!![Using MatchTagsPlugin with CheckboxPlugin to create a table of tiddlers]...
Set/clear <<tag excludeLists>> on tiddlers tagged with <<tag sample>>
<script>
   var tids=store.getMatchingTiddlers("sample");
   var out="";
   var itemfmt="|<<tiddler CheckboxToggleTag with: excludeLists '' %0>> %0";
   var columns=3;
   for (var t=0; t<tids.length; t++) {
      out+=itemfmt.format(["[["+tids[t].title+"]]"]);
      if ((t+1)%columns==0 || t==tids.length-1) out+="|\n";
   }
   return out;
</script>
===
<script>
	// note: we can't use a field in the current tiddler to track the status value,
	// because it triggers an automatic re-render when saving the new status value
	// so we create/use hidden "TiddlerName_data" tiddler to hold value(s)

        window.initStatus=function(elem,id) {
		var here=story.findContainingTiddler(elem); if (!here) return;
		var tid=here.getAttribute("tiddler")+"_data"; 
		if (!store.tiddlerExists(tid)) // make sure tiddler exists
			store.saveTiddler(tid,tid,"",
				config.options.txtUserName,new Date(),"excludeLists",{});
		if (store.getValue(tid,id)===undefined)
			store.setValue(tid,id,0); // init new value
		window.showStatus(elem,store.getValue(tid,id));
	}
        window.showStatus=function(elem,val) {
                var colors=["#900","#090","#009"];
                var text=["red","green","blue"];
		if (val===undefined || val>=colors.length) val=0;
                elem.style.backgroundColor=colors[val];
                elem.innerHTML=text[val];
                return val;
	}
        window.nextStatus=function(event,id) {
		var here=story.findContainingTiddler(event.target); if (!here) return;
		var tid=here.getAttribute("tiddler")+"_data"; 
		var val=store.getValue(tid,id); // get status
		val=window.showStatus(event.target,parseInt(val)+1); // cycle and render status
		store.setValue(tid,id,val); // store new status
        }
</script>+++!!![Using custom fields with onclick handler to cycle status values]...
|foo|<script>window.initStatus(place,"id1");place.onclick=function(event){window.nextStatus(event,"id1")};</script>|
|bar|<script>window.initStatus(place,"id2");place.onclick=function(event){window.nextStatus(event,"id2")};</script>|
===
+++!!![recent changes popups]...
<<date popup Y M D-1 "yesterday" "DDD MMM DDth YYYY">><script>
	place.lastChild.title="tiddlers that were created/edited yesterday";
</script>/%
%/ <<date popup today "today" "DDD MMM DDth YYYY">><script>
	place.lastChild.title="tiddlers that were created/edited today";
</script>/%
===
+++!!![relative font sizes]...
|{{big{big}}}|@@font-size:14pt;big 14pt@@|@@font-size:1.5em;big 1.5em@@|
|{{medium{medium}}}|@@font-size:12pt;medium 12pt@@|@@font-size:1.3em;medium 1.3em@@|
|{{normal{normal}}}|@@font-size:9pt;normal 9pt@@|@@font-size:1em;normal 1em@@|
|{{small{small}}}|@@font-size:8pt;small 8pt@@|@@font-size:0.85em;small 0.85em@@|
|{{fine{fine}}}|@@font-size:7pt;fine 7pt@@|@@font-size:0.75em;fine 0.75em@@|
|{{tiny{tiny}}}|@@font-size:6pt;tiny 6pt@@|@@font-size:0.65em;tiny 0.65em@@|
===
+++!!![encode bookmarklet URI from onclick handler]...
<html><hide linebreaks><a href=""
onmouseover="this.href='javascript:void(eval(decodeURIComponent(%22(function(){try{('
	+encodeURIComponent(encodeURIComponent(this.onclick))
	+')()}catch(e){alert(e.description?e.description:e.toString())}})()%22)))';"
onclick="alert('yop! we are here!')">drag this to the toolbar!</a></html>
===
+++!!![Use core tiddler macro to execute inline javscript]...
before
<<tiddler {{
	var here="TestTiddler"
	var t="\n{{{\n"+store.getTiddlerText(title)+"\n\}\}\}\n";
	var c=document.getElementById("tiddler"+title).childNodes;
	for (var i=0; i<c.length; i++) if (hasClass(c[i],"viewer")) { wikify(t,c[i]); break; } ;
	"";
}}>>
after
===
+++!!![extended String prototype for $n marker subtitutions]...
<script label="test it..." show>
String.prototype.substitute=function(args) { // replace "substitution markers" ($1-$9) with macro param values (if any)
	if (!args || !args.length) return this;
	var n=args.length; if (n>9) n=9;
	var t=this; for(var i=0; i<n; i++) { var re=new RegExp("\\$" + (i + 1),"mg"); t=t.replace(re,args[i]); }
	return t;
}
alert("test $1 foobar".substitute(["mumble"]));
</script>
===
+++!!![Conditionally displayed browser-specific content, using CSS classes]...
When applying these CSS rules:
/*{{{*/
*[class="ieOnly"]
	{ display:none; }
* html .mozOnly, *:first-child+html .mozOnly
	{ display: none; }
/*}}}*/
the following source content
<<<
"""
You are using {{ieOnly{Microsoft Internet Explorer}}}{{mozOnly{a mozilla-based browser}}}...
"""
<<<
is rendered by this browser as:
<<<
You are using {{ieOnly{Microsoft Internet Explorer}}}{{mozOnly{a mozilla-based browser}}}...
<<<
===
+++!!![RollText using content from a macro]...
{{big center{
<<tiddler RollText with: {{wikifyPlainText("\<\<QOTD Quotations\>\>").replace(/"/g,"\\\"")}} 500 500 3000>>}}}
===
+++!!![RollText using content from another tiddler]...
{{big center{
<<tiddler RollText with: {{wikifyPlainTest("About").replace(/"/g,"\\\"")}} 500 500 3000>>}}}
===
+++!!![Remote click a slider button from a separate onclick link]...
+++[label]#slider_id:...
	slider contents
	goes here
===

<script label="toggle slider panel">
	var e=document.getElementById("slider_id");
	if (e && e.button) window.onClickNestedSlider({target:e.button});
</script>
===
/***
|Name|TextAreaPlugin|
|Source|http://www.TiddlyTools.com/#TextAreaPlugin|
|Documentation|http://www.TiddlyTools.com/#TextAreaPluginInfo|
|Version|2.3.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|Adds Find/Again keyboard search, autosize, and 'stretch bar' resize for textarea controls|
!!!!!Documentation
>see [[TextAreaPluginInfo]]
!!!!!Configuration
<<<
<<option chkTextAreaExtensions>> use control-f (find), control-g (find again) inside text area
<<option chkDisableAutoSelect>> place cursor at start of textarea instead of pre-selecting content
<<option chkResizeEditor>> modify shadow EditTemplate to add resizeable text area (and autosize command)
<<<
!!!!!Revisions
<<<
2011.10.28 2.3.0 added resizeHere macro to add stretch bar to current container (e.g., sidebar panels)
|please see [[TextAreaPluginInfo]] for additional revision details|
2006.01.22 1.0.0 Moved from temporary "System Tweaks" tiddler into 'real' TextAreaPlugin tiddler.
<<<
!!!!!Code
***/
//{{{
version.extensions.TextAreaPlugin= {major: 2, minor: 3, revision: 0, date: new Date(2011,10,28)};

if (config.options.chkTextAreaExtensions===undefined) config.options.chkTextAreaExtensions=true;
if (config.options.chkDisableAutoSelect===undefined) config.options.chkDisableAutoSelect=true;
if (config.options.chkResizeEditor===undefined) config.options.chkResizeEditor=true;

// automatically tweak shadow EditTemplate to add "autosizeEditor" toolbar command
if (config.options.chkResizeEditor)
	config.shadowTiddlers.EditTemplate=config.shadowTiddlers.EditTemplate.replace(/deleteTiddler/,"deleteTiddler autosizeEditor");
// automatically tweak shadow EditTemplate to add "resizeEditor" macro
if (config.options.chkResizeEditor)
	config.shadowTiddlers.EditTemplate+="<span macro='resizeEditor'></span>";

// Put focus in a specified tiddler field
Story.prototype.TextAreaExtensions_focusTiddler=Story.prototype.focusTiddler;
Story.prototype.focusTiddler = function(title,field)
{
	this.TextAreaExtensions_focusTiddler.apply(this,arguments); // first call core
	var e = this.getTiddlerField(title,field);
	if (e && config.options.chkDisableAutoSelect) {
		if (e.setSelectionRange) // FF
			e.setSelectionRange(0,0);
		else if (e.createTextRange) // IE
			{ var r=e.createTextRange(); r.collapse(true); r.select(); }
	}
	if (e && config.options.chkTextAreaExtensions) addKeyDownHandlers(e);
}
//}}}

//{{{
function addKeyDownHandlers(e)
{
	// exit if not textarea or element doesn't allow selections
	if (e.tagName.toLowerCase()!="textarea"||!e.setSelectionRange||e.initialized) return;

	// utility function: exits keydown handler and prevents browser from processing the keystroke
	var processed=function(ev) {
		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;
	}
	// capture keydown in edit field
	e.saved_onkeydown=e.onkeydown; // save current keydown handler (if any)
	e.onkeydown=function(ev) { if (!ev) var ev=window.event;
		var key=ev.keyCode;
		if (!key) {
			var char=event.which?event.which:event.charCode;
			if (char==102) key=70;
			if (char==103) key=71;
		}
		// process CTRL-F (find matching text) or CTRL-G (find next match)
		if (ev.ctrlKey && (key==70||key==71)) {

			// prompt for text to find
			var defFind=e.findText?e.findText:e.value.substring(e.selectionStart,e.selectionEnd);
			if (key==70||!e.findText||!e.findText.length) // ctrl-f or no saved search text
				{ var f=prompt("find:", defFind); e.focus(); if (f) e.findText=f; }
			if (!e.findText||!e.findText.length) return processed(ev); //  if no search text, exit

			// do case-insensitive match with 'wraparound'...  if not found, alert and exit 
			var newstart=e.value.toLowerCase().indexOf(e.findText.toLowerCase(),e.selectionStart+1);
			if (newstart==-1) newstart=e.value.toLowerCase().indexOf(e.findText.toLowerCase());
			if (newstart==-1) { alert("'"+e.findText+"' not found"); e.focus(); return processed(ev); }

			// set new selection, scroll it into view, and report line position in status bar
			e.setSelectionRange(newstart,newstart+e.findText.length);
			var linecount=e.value.split('\n').length;
			var thisline=e.value.substr(0,e.selectionStart).split('\n').length;
			e.scrollTop=Math.floor((thisline-1-e.rows/2)*e.scrollHeight/linecount);
			window.status="line: "+thisline+"/"+linecount;
			return processed(ev);
		}
		if (e.saved_onkeydown) // call previous keydown handler (if any)
			e.saved_onkeydown(ev);
	}
	e.initialized=true;
}
//}}}

// // 'autosize' toolbar command
//{{{
config.commands.autosizeEditor = {
	text: 'autosize',
	tooltip: 'automatically adjust the editor height to fit the contents',
	text_alt: '\u221Aautosize',
	hideReadOnly: false,
	handler: function(event,src,title) {
		var here=story.findContainingTiddler(src); if (!here) return;
		var ta=here.getElementsByTagName('textarea'); if (!ta) return;
		for (i=0;i<ta.length;i++) {
			// only autosize textareas actually used to edit tiddler fields
			if (ta[i].getAttribute("edit")==undefined) continue;
			ta[i].button=src;
			if (!ta[i].maxed)
				config.commands.autosizeEditor.on(ta[i]);
			else
				config.commands.autosizeEditor.off(ta[i],true);
		}
		return false;
	},
	on: function(e) {
		if (e.maxed) return; // already autosizing!
		if (e.savedheight==undefined)
			e.savedheight=e.style.height;
		if (e.savedkeyup==undefined) {
			e.savedkeyup=e.onkeyup;
			e.onkeyup=function(ev) {
				if (!ev) var ev=window.event; var e=resolveTarget(ev);
				e.style.height=e.scrollHeight+'px';
				if (e.savedkeyup) e.savedkeyup();
			}
		}
		// IE reports error: "not implemented" for onkeypress
		if (!config.browser.isIE && e.savedkeypress==undefined) {
			e.savedkeypress=e.onkeypress;
			e.onkeypress=function(ev) {
				if (!ev) var ev=window.event; var e=resolveTarget(ev);
				if (ev.keyCode==33) { // PGUP
					if (window.scrollByPages) window.scrollByPages(-1);
					return false;
				}
				if (ev.keyCode==34) { // PGDN
					if (window.scrollByPages) window.scrollByPages(1);
					return false;
				}
				if (e.savedkeypress) e.savedkeypress();
			}
		}
		e.style.height=e.scrollHeight+'px';
		if (e.button) e.button.innerHTML=config.commands.autosizeEditor.text_alt;
		e.maxed=true;
	},
	off: function(e,resetHeight) {
		if (resetHeight) e.style.height=e.savedheight;
		e.onkeyup=e.savedkeyup;
		// IE reports error: "not implemented" for onkeypress
		if (!config.browser.isIE) e.onkeypress=e.savedkeypress;
		if (e.button) e.button.innerHTML=config.commands.autosizeEditor.text;
		e.maxed=false;
	}
};

config.macros.autosizeEditor={
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		var here=story.findContainingTiddler(place); if (!here) return;
		var ta=here.getElementsByTagName('textarea'); if (!ta) return;
		for (i=0;i<ta.length;i++) {
			// only autosize textareas actually used to edit tiddler fields
			if (ta[i].getAttribute("edit")==undefined) continue;
			config.commands.autosizeEditor.on(ta[i]);
		}
		return false;
	}
}
//}}}

// // grab-and-stretch handle
//{{{
config.macros.resizeEditor = { // add stretch bar to editor textarea
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		var here=story.findContainingTiddler(place); if (!here) return;
		var ta=here.getElementsByTagName('textarea');
		if (ta) for (i=0;i<ta.length;i++) {
			// only resize tiddler editor textareas
			if (ta[i].getAttribute("edit")==undefined) continue;
			new window.TextAreaResizer(ta[i]);
		}
	}
}

config.macros.resizeTiddler = { // add stretch bar to tiddler viewer element
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		var here=story.findContainingTiddler(place); if (!here) return;
		var elems=here.getElementsByTagName('div');
		if (elems) for (i=0;i<elems.length;i++) if (hasClass(elems[i],'viewer')) break;
		if (i<elems.length) new window.TextAreaResizer(elems[i]);
	}
}

config.macros.resizeFrame = { // add stretch bar to iframes
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		var here=story.findContainingTiddler(place); if (!here) return;
		var fr=here.getElementsByTagName('iframe');
		if (fr) for (i=0;i<fr.length;i++) new window.TextAreaResizer(fr[i]);
	}
}

config.macros.resizeListbox = { // add stretch bar to listbox controls
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		var here=story.findContainingTiddler(place); if (!here) here=place;
		var fr=here.getElementsByTagName('select');
		if (fr) for (i=0;i<fr.length;i++) new window.TextAreaResizer(fr[i]);
	}
}

config.macros.resizeHere = { // add stretch bar to containing element
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		new window.TextAreaResizer(place);
	}
}

// TextAreaResizer script by Jason Johnston (jj@lojjic.net)
// Created August 2003.  Use freely, but give me credit.
// adds a handle below textareas that the user can drag with the mouse to resize the textarea.
// MODIFIED by ELS for use with TW

window.TextAreaResizer = function(elt) {
	this.element = elt;
	this.create();
}
window.TextAreaResizer.prototype = {
	create : function() {
		var elt = this.element;
		var thisRef = this;
		var h = this.handle = document.createElement("div");
		h.style.height = "3px"; // was 4px... looked too fat!
		h.style.overflow = "hidden"; // ELS: force IE to trim height to < 1em
		var adjust=elt.nodeName=='textarea'?4:0;  // 4 pixels for textarea border edge
//		h.style.width=(elt.offsetWidth-adjust)+"px";
		h.style.width="auto";
		h.style.backgroundColor = "#999"; // ELS: standard mid-tone (dark) gray
		h.style.cursor = "s-resize";
		h.title = "Drag to resize text box";
		h.onmousedown=function(evt){thisRef.dragStart(evt)};
		elt.parentNode.insertBefore(h, elt.nextSibling);
	},
	dragStart : function(evt) {
		if (!evt) var evt=window.event;
		this.dragStop(evt); // ELS: stop any current drag processing first
		var thisRef = this;
		this.dragStartY = evt.clientY;
		this.dragStartH = this.element.offsetHeight;
		document.savedmousemove=document.onmousemove;
		document.onmousemove=this.dragMoveHdlr=function(evt){thisRef.dragMove(evt)};
		document.savedmouseup=document.onmouseup;
		document.onmouseup=this.dragStopHdlr=function(evt){thisRef.dragStop(evt)};
	},
	dragMove : function(evt) {
		if (!evt) var evt=window.event;
		// ELS: make sure height is at least 10px
		var h=this.dragStartH+evt.clientY-this.dragStartY;
		if (h<10) h=10; this.element.style.height=h+"px";
		// ELS: match handle to textarea width (which may have changed due to document scrollbars)
//		var adjust=this.element.nodeName.toLowerCase()=='textarea'?4:0; // 4 pixels for textarea
//		this.handle.style.width=(this.element.offsetWidth-adjust)+"px";
		// ELS: when manually resizing, disable autoresizing (without restoring saved height)
		if (this.element.maxed!=undefined && this.element.maxed)
			config.commands.autosizeEditor.off(this.element,false);
	},
	dragStop : function(evt) {
		if (!evt) var evt=window.event;
		document.onmousemove=(document.savedmousemove!=undefined)?document.savedmousemove:null;
		document.onmousemove=(document.savedmouseup!=undefined)?document.savedmouseup:null;
	},
	destroy : function() {
		var elt = this.element;
		elt.parentNode.removeChild(this.handle);
		elt.style.height = "";
	}
};
//}}}
/***
|Name|TextAreaPluginInfo|
|Source|http://www.TiddlyTools.com/#TextAreaPlugin|
|Documentation|http://www.TiddlyTools.com/#TextAreaPluginInfo|
|Version|2.3.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|documentation|
|Description|Documentation for TextAreaPlugin|
!!!!!Usage
<<<
When installed, this plugin automatically adds Find/Again keyboard search and autosize ('fit to content') handling to the tiddler editor's text area input.  It also provides macros that can add 'stretch bars' that allow you to interactively resize to the text area as well as other rendered elements, including: tiddlers, iframes, listboxes, sliders, tabs, and general 'CSS wrapper' containing elements.

When in the tiddler editor's text area you can use ''Control-F'' and ''control-G'' to ''"Find text"'' and ''"find text aGain"'', respectively.  This permits you to to use a combination of keyboard controls to "search-and-replace" (e.g., ctrl-F to find/select the desired text, ctrl-C to paste in the replacement, and then ctrl-G to find/select the next matching text).

The ''autosize'' toolbar command is automatically added to the default shadow EditTemplate, and toggles the tiddler editor textarea height between default fixed-height and "fit the current contents".  When autosized, the text area height will change automatically to match the current number of lines contained in the tiddler source definition.

If desired, you can manually ''add the 'autosizeEditor' toolbar command to the editor toolbar:''
{{{
// add command keyword to end of {{{EditToolbar}}} slice definition in [[ToolbarCommands]]:
|EditToolbar| ... autosizeEditor|
}}}
Alternatively, you can ''enable autosize by default:'' by invoking the 'autosizeEditor' macro, directly from the EditTemplate:
{{{
// add to the end of the EditTemplate:
<span macro='autosizeEditor'></span>
}}}

To ''add a stretch bar below the editor text area:'', invoke the 'resizeEditor' macro, directly from the EditTemplate:
{{{
// add to the end of the EditTemplate 
<span macro='resizeEditor'></span>
}}}

To ''add a stretch bar to another element type'', embed the appropriate {{{<<resize...>>}}} macro in your tiddler content, immediately following the desired element (or at the end of the tiddler):
{{{
<<resizeTiddler>> - add a stretch bar to the containing tiddler
<<resizeFrame>> - add a stretch bar to all IFRAMEs in the current tiddler
<<resizeListbox>> - add a stretch bar to all listboxes in the current tiddler
<<resizeHere>> - add a stretch bar to the current containing element (i.e., a slider or tab panel)
}}}
>{{smaller{Note: you can also invoke these macros directly from the ViewTemplate or EditTemplate:
{{{
<span macro='resizeTiddler'></span> or
<span macro='resizeFrame'></span> or
<span macro='resizeListbox'></span> or
}}}
}}}
<<<
!!!!!Configuration
<<<
<<option chkTextAreaExtensions>> add control-f (find), control-g (find again) to editor text areas
<<option chkDisableAutoSelect>> place cursor at start of textarea instead of pre-selecting content
<<option chkResizeEditor>> auto-modify shadow EditTemplate to add resizeable text area (and autosize command)
<<<
!!!!!Revisions
<<<
2011.10.28 2.3.0 added resizeHere macro to add stretch bar to current container (e.g., sidebar panels)
2009.04.08 2.2.1 added autosizeEditor macro to enable automatic autosizing without using toolbar command
2009.04.06 2.2.0 added resizeListbox macro definition and adjusted dragbar width calculation.
2008.01.08 2.1.9 fixed default setting of uninitialized option values so that "false" is not treated as "undefined"
2008.01.07 2.1.8 added 'initialized' flag so keyDownHandlers() will only be added once to each control (prevents recursion errors)
2007.12.21 2.1.7 in dragMove(), subtract 4-pixel 'fudge factor' when adjusting drag bar width to match textarea width.  Apparently textarea 'offsetWidth' includes the 2-pixel surrounding edge, but CSS 100% calculation does NOT, resulting is an increase in the textarea width when displayed in a variable-width moveable panel.
2007.11.19 2.1.6 fix fatal IE errors by NOT setting 'onkeypress' handler (which IE reports as "not implemented").  Also, only add autosize grab bar to textareas that are actually used to edit tiddler fields (i.e., they have an "edit=fieldname" attribute).  This prevents undesirable autosizing of textareas used for HTML/DOM display by [[PreviewPlugin]].
2007.11.18 2.1.5 in config.commands.autosizeEditor, changed alt command text to use character-based "psuedo-checkbox" instead of embedded html fragment
2007.09.04 2.1.4 in window.TextAreaResizer.prototype.create(), set initial grab handle width to auto instead of matching textarea.offsetWidth (which can be initially==0)
2007.04.29 2.1.3 in addKeyDownHandlers(), used 'findText' instead of 'find', hopefully to avoid strict ECMAScript1.5 error on certain browsers.
2007.03.01 2.1.2 use apply() to invoke hijacked core function
2006.11.16 2.1.0 restored chkDisableAutoSelect (place cursor at start of textarea instead of pre-selecting content)
2006.11.16 2.0.0 removed chkDisableEscapeKey (obsolete... use custom EditTemplate to change toolbar definition).  Rewrote focusTiddler as a HIJACK instead of just overwriting core function (permits other plugins to also hijack function).  Removed TAB character processing (now built-in as of TW2.1).  Merged code from ResizeEditorPlugin:
> 2006.11.16 [1.3.x] merged with TextAreaPlugin
> 2006.11.02 1.3.1 in DragMove() and DragStop(), check for undefined properties so IE doesn't report "Not Implemented" error when property is referenced without having been previously initialized.
> 2006.11.01 1.3.0 added 'resizeEditor' MACRO for 'grab handle' stretch resizing (based on code from Jon Scully and Jason Johnston (jj@lojjic.net).  
> 2006.11.01 1.2.6 removed increaseEditor, decreaseEditor, and resizeEditor toolbar COMMAND definitions (resize by setting 'rows' property of textarea field conflicts with resize via style.height CSS attribute as set by autosize/drag).
> 2006.11.01 1.2.5 fixed 'savedkeypress' handling (was writing to savedkeyup by mistake)
> 2006.10.28 1.2.4 added '+' to 'saveTiddler' toolbar command (enables ctrl-enter keyhandling)
> 2006.10.18 1.2.3 added decreaseEditor and increaseEditor commands
> 2006.10.18 1.2.2 onkeypress handling to redirect PGUP/PGDN to window.scrollByPages() (works in FF, but not yet in IE)
> 2006.10.18 1.2.1 fixed references to default string constants (oops!)
> 2006.10.18 1.2.0 renamed 'resizeEditor' to 'autosizeEditor' and added new 'resizeEditor' toolbar command to prompt for # of rows to display
> 2006.10.02 1.1.1 show checkbox in button label (when automatic resizing is enabled)
> 2006.10.01 1.1.0 added 'onkeyup' automatic fit-to-contents handling
> 2006.09.30 1.0.0 initial release
2006.08.01 1.1.2 improved processed() utility function to handle IE5 and IE6, as well as calling preventDefault() for moz browsers.  Thanks to Bradley Meck for research and code examples.
2006.07.09 1.1.1 removed chkDisableAutoSelect
2006.02.14 1.1.0 added option for chkDisableEscapeKey (default is standard action)
2006.01.22 1.0.1 only add extra key processing for TEXTAREA elements (not other edit fields).
added option to enable/disable textarea keydown extensions (default is "standard keys" only)
2006.01.22 1.0.0 Moved from temporary "System Tweaks" tiddler into 'real' TextAreaPlugin tiddler.
<<<
/***
|Name|Textures|
|Source|http://www.TiddlyTools.com/#Textures|
|Version||
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|CSS|
|Description|theme: stone/parchment backgrounds|
|StyleSheet|Textures|
|PageTemplateReadOnly|PageTemplateReadOnly|
|EditTemplateReadOnly|EditTemplateReadOnly|
***/

[[StyleSheetAdjustments]]
/*{{{*/
/* ==== Textures ==== */
body
	{ background-image: url('[[TexturesStucco]]'); background-color:#eee; }
.tagging, .tagged
	{ background-color: transparent; border: 1px solid #ccc; }
.selected .tagging, .selected .tagged
	{ background-image: url('[[TexturesParchment]]'); background-color:#edb; border: 1px solid #999; }
.menubox
	{ background-image: url('[[TexturesParchmentGray]]'); background-color:#fff; }
.viewer
	{ background-image: url('[[TexturesParchmentGray]]'); background-color:#fff; border: 1px solid #999; -moz-border-radius:1em;-webkit-border-radius:1em; padding:1em; }
.groupbox
	{ background-image: url('[[TexturesParchment]]'); background-color:#ffe; }
.header	{ background-image: url('[[TexturesMarbleBlack]]'); background-color:#113; border:0; border-bottom:5px solid #090; color:#ccf !important; }
.header a { color:#ccf; }
.header a:hover	{ color:#fff; }

/* invert rollover highlighting in header */
.header .mouseover, .header .mouseover .button, .header .mouseover a,
#backstageButton .mouseover, #backstageButton .mouseover .button, #backstageButton .mouseover a
	{color:[[ColorPalette::PrimaryDark]] !important;}
.header .selected .mouseover, #backstageButton .selected .mouseover
	{color:[[ColorPalette::PrimaryLight]] !important;}
.header .selected .mouseover .button, .header .selected .mouseover a,
#backstageButton .selected .mouseover .button, #backstageButton .selected .mouseover a
	{color:[[ColorPalette::TertiaryLight]] !important;}

.siteSubtitle { color:#0c0; }
.floatingPanel, #messageArea, .attachPanel, #importPanel, #exportPanel, #sidebarTabs .tabContents 
	{ background: #eee; background-image: url('[[TexturesParchmentGray]]');}
#messageArea { border:1px solid #000; -moz-border-radius:0;-webkit-border-radius:0; }

.viewer h1,.viewer h2,.viewer h3,.viewer h4,.viewer h5 { background: #666; color:#fff; }
.tabContents /* .viewer .tabContents, #sidebarTabs .tabContents */
	{ background-image: url('[[TexturesParchmentGray]]'); background-color:#fff; }

/*}}}*/
!usage
{{{[img[TexturesCrumpled]]}}}
[img[TexturesCrumpled]]
!notes

!type
image/jpg
!file
./images/crumpled.jpg
!url

!data
data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEBLAEsAAD/2wBDABQODxIPDRQSEBIXFRQYHjIhHhwcHj0sLiQySUBMS0dARkVQWnNiUFVtVkVGZIhlbXd7gYKBTmCNl4x9lnN+gXz/2wBDARUXFx4aHjshITt8U0ZTfHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHz/wAARCAEAAQADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDpqOtGaKyKFpO9LjNOAoAb0pGPFSbQetN8kZ+830osBFTwKcExS4xRYBAKUUUtMBelNLe9Nb5qjIIpXAlyexo3EdTUPI9aOvelcdhxYk0H1oC04rkUANDU9WB4zimbfegLQIl20baQNTs1QCYpcUZpDIBQIdiio9xanDNAC0baKM0wEII6daiaMMc7TU9GKVhlbyqTG3tU54qMsW46CpsO4lKOaAPTgU4cUALShaQN7U4ZqhChadQDRTEFFFJmgBSKSk34o8xT1oAOlNahmP8ADj60zYSeTUjAtSgE05Y6kCiiwEYjpyxr6VIBRVWEIFX0oKr6UtJTAjZB1FJUtMdD68UmgI6N1IaApqRiZJ704ClC08CiwCAU6koNUIKSl4pwoAaM06jNIx+WgCJyM03ikIyetLUFCg8Uopop3NAh4FKKKDViClptKKQAaKTdSZoAWkK5pQM08LQAwIBTgKfiinYAAoxRmmlqYDmO2o/MpaQrmkAbqXdUR+WilcZPuo3VCGpwancRJu9qTrSUUAJS0UUAFJRSGgBRS02loAdUTtninnpUJ60mMKCaMjNOCk/SpGNGT0qQLgU4KFop2EOpcUUZqhCbRTSMU+lwKAIwtKFAp+BR0osAYoPFIW9Kb70APzTCTRRQAlFFGaACjdSUUgAtntTduadSigY3yxS7Md6GNMOaAJBS1FuIp4kouA+kpN9JupiFJptG6m7hUjHZozTdwpN1AD81Fyx70/dRupAKqc08CmBj0pQWP0qgHU7pQuB06+tLTEQ7m79Kdv8ASjaKNmKQwDGnZpu2lFAh2aQtSE02mAu6jdmjFLikAZozSUUALSUUlAAabnBoJoAFIY6gmlC8Ujg9qYADSkVHk56U8GkAhFNqTrTStADBSilxim5BPWkMKQpS0UARlDQNw+lSDrzUoCkdKLBcrinAVI0fpTCCtFgAGpVVh7U2Nec1Jhh6U0IaTt60hkxQct97rQFApgL0p1IaBQIWjNGaQ0wENAoAp1IBKKKM0wCkoLYpu9T3pDFphDGncUtIBuMUbgKXNIRQABjT99MxQKAFNIPanUd6AIyzUbm9aeVBpCtICM/Ny1O6UnSgc0DClFLilFACinY9KQClqhC7qOGpM0mfagRIBig+lN3Y6ZNHzUwFxSUuPU0pFADeD160YFITSUgHYNGPekBpjE+tAx5bFIWNRln9ab5j+gpXCxIWppeo8uaT5uhFK47Di2aafUVIse7oPzqQQjvRYLkCFj0qUFsc0skYUfKM4qNZMHmjYCSlpccUYpiG/SkzT9o70u1aLANpM1JtFIUFOwCA+tBo27eppuaQARmmbak60uKLAMFPApcUtFgEoozRTEGKXFJS0ALRRRTAWmlvSlpMUAIRRSmjFIBGPFNpWPNGKQxuKXApaKAG4pQtLS0WAKUGiimIKayBue9OxRQBGEcHipNrDtS0qn1osA3FNxU2M00pTsAwUMT2pSpFApAR/NnpTgnrUgWjbRYBuKMU/FGKdgG0lPxRtosBGRSdKl20m2iwDRS0uwU7bRYBuKWhiFGTUJuB2ovYCemtUS3I/iFPDbuQaLgAHuaOlLTHcUgDFLioixbp/Om4NK4yfikyvqKiC09UzQA7FOxQFxTqoQmKMUtJmgBKWkpRzQAUUu00hB9KAFBp2aj5pS2BQBJRUO80bzRcCaiot9G+i4ElFR7qUNRcB+aM03NFMBd1JzS0UAJzRniiikBC+ZH9qURqO2frUnGaKVhjCqnnGaAig8AU7FAosBEZd3Smk0nlgHrShGP0qdRiAVIq0oWn4p2EIB7U7mgUtUIOaM0lFABRRSUgAU7OBTd1HWmAFiTRj0oxS5xQAmT60ZoyTQBigAK00ipMUhFFgI8GkqSkxUjGgUvSlpKAHClzUdOBp3EPpeabmlzTAWkzijdSMaAG0xmdemMU40daQyLz2U8inrMCu5uKQqKQxg9uanUehNnjoKOT2qMTEUCde4aquKxLilxUfnA/dFHmMfai6ESU0tUZY+tMLGjmHYlLgUwy1HnNGKm47DtzMeuKkXjqSajFSChCCjFLTgKYCAUYp1FMQg4ooopgOFLTKcOaADFIVp2cUmaAGUhqQ/N1phGKQCUUUbaQwozTTnFMO6i4Dy9IHJpmaWlcZLmjOKavzDil2/jTEKOTTvypjHA2rwai8xu9FwG0VIVpMVNhixL3qUrQgwKdVpCITGc0CKpttITjgUWC5EVC0bS3NScdKWlYCLpTlUmlZc04cCiwAF96djFJRuHrVCFpKC3pTc0ALRSUoFIApaWkpgFFFJQAUbqKSkAuRTdwprNxURyDmk2MlJpppu71p340hhikxxTsUqkA5NACom0ZY0uT24FGd3elxTENxxTGGDUpphFDAU80BcmlwBSrQA7FLSE461G8hPTpVCHs3YUgpEbdS0hhRRRQIWikzSE0AB9KMUUUhgaKUDNLimA0fpTxikopiHUlJRmgApKWkpAFNZsUO+2oSxY0mxi5zRQCRxTutIYwrmk5FSgYpCKLBcjGfWnbM06jvQAbM+tAVh0JpyinZosIaGJ60u4d6Uqpo20wACndBQzqvWqzzbjgZFF7ASPJk03FNUbqfjFIYnQ1KjBh71HSdD70AS0U0NS7qYheaKKKADFLSZpc0wE6U7NJijpQAtFGaCKYhKKKTNIYtMd9oprzAdOTUY3ufumk2OwFixpQKeIsdadtxSsFxoWnYopaBCUc0hBpVagBKXFKy03JpgB4ozSdaXFIYoNKTTc4p6lfSmIh+83NP2g9QDSAU6kMMACilpKYhtBFLxR3pDECkd6Rj6U48U3vQAm4inB6aRTelICYGlDVDupd2KdwsTA+tGahD0u40XFYkzShqi3U15MUXHYmZwo5qNd8x/up60xPmPIqYL+dG4bDkhRRwPxNPwKQHFKOaokSjFOpaYEe2k21LSYosBHimkelTbaaVpWGNX070jDmlKntShvwpAMxinYHfNDLxTeaAHbQaa+FHWjNRnrSAeKXNFGKACiiimAUCk6mn8UAMY00Up/OikMSkYUuKcFJoAh2mj61Nsyad5Q70WC5BilXpzU3lDtzTGifPA4osFyJiTwBT0iXq2TUwVQvzEUfKfaiwXFVkHRcUrNTcDtSdaoQmaN1GKMCkA4PS7qZtpcUAPD08HNRBafVCHUUlIWAoAWlpnmf7JNN+0J3/Wi6AkKhgfWomXbS+evan71IzS0YyEtxTafJt7AimipGf//Z
!usage
{{{[img[TexturesMarbleBlack]]}}}
[img[TexturesMarbleBlack]]
!notes

!type
image/jpg
!file
./images/marble_black.jpg
!url

!data
data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEBLAEsAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/wAALCAB8AOABAREA/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/9oACAEBAAA/APNILaC1UlMliOrHJpGlBIA6d9tQvIDhQASf4eeMdjUEkqoCqqCc8bSeTT4GGAhgKRn/AGuSRUn2iONMrEN57nn/AD1qvIXkbk+ucCnD5I8r83fG3JzTwmGYOyr/AHeO/tUQVipIYbuzVPEdyAfKNv8AFgjjHXn+tIr8M5bBJx0PJ70g6nhueOemKjSIjdklmPOW607aobgbTke2TTQB8isCoY5GOhP0pSrumckIDjHehY8ru+Xp1qT5yu0DJHA29MVS4LnL5Ung9aVwzMQilV9h+dL5jHBkJI/vMeevp+NWLREklULtcZBPtjFMm+ZvMRQysemcc0jJ8px8mDxkU3dhBuHz5GFA/l7VcGnzAF9uWwcDd0pEsG8wedtOfQj0pXcKodnAB6g8YqtJchR+7A3HuegpE3yfIiNnbnGP84p/2ObnMeOeuevftT0spEYSMYyc884FNePYCVKquegH9BSbgGGTyDnp0p4Un+E9c9TxTEOXJPPI57elPUI248lVzu9R/n86GfKAFc98Z4HrxUm4FVI25Pf0qIg7DuweMnJpj7mQhQS5+UEnGPepniAOCecZCnkj/wCvTfmfaM5B9fT1prtFGy7WLMCTlTxToXWV+dynbkkrnjv/AEqKaXZlA5POeOmO1V2GXLnPzdO+alwyoHYfJ0J/pT9qBFBBAPvyPwpkMfmSKg+UKQSSegrUWNWmQQspUHccAEH8e1EtokjkSOflOPvcetNit4Y2yFC7epJzTnuAH2q7Y6CmeYWLEYHpxVIWkssvyBnIHXHP5k1Ze0ht2BnlLOQAEBpj6gUJSBFRMdcc/wD1qrrJJJIvmMcH8c09YYQQMqM53cGrAZpEKsBsB5GMduMGmDGCfJC+ucnNNIZmxt2r2PX8MU0b0JAiO3IHv9cVIzJEmWU+YG3d/wDHnimoIWUMsjO+ASqjBXNI24HZhuuevI55p33JQo5IOfmIxTHk8o5CHeB8vQfjULzSyOrBxk9ccY79fSkCAA4OT1PvzSjaTjoevykVLE5Qso53rtLDtzTBsRWyrSFhyxHapBHFbt5pBYjhVYjr9O9ONxJwnlp5ZzhVPbHP1pPsmQpRjtPqMf1q9HbxIfMVfmYfdcDb/KlaVU4jAGOML65xUHmEyMQ2M+ppHcRgee2CcFduG/So450yZFRmIOFz0z9aikllfIwsfPQf5/GrNxdlMRW5IRBjIP3jVR5CZXZzubHUt39qhPHIBC4wCRz78VZtosyqu2JtwwDvwQOc8fhVoyJGI8fIX6Y5wP6fSoFkYM4Ll2GCSf8APNRCdycEjPQFRUckjldrSNnp1GKhLuT1bPTJYmhZArguS4ySQep/zj9KnDQxIQrHLc5HJI9PapFuWlG4KeOCCRzx/wDWpXaTjHAPPqV696hIAPzHOeTntTm2kEg888DgD8aTa2QDwDz0xTgM8jk+3pT4o2cjAIXOameJ3l8rIAzkkDgf/Xoayl5bbGMgKAWxiplhjt1UqATnmpTMjEjaqjttOf5VBJIWbAJGPUdRVeSQ4aMHDd/b1qLqdpOCBnjHPtTSFyNuT3/wqTzMwBdoIDdMjNPhie7mAAYIANxznAqsXl3EqeSuMIOo/wDr0wIWUnIGcADvz0p+AFIKqCP4hjHrx71Or/uGdQsfzKpG/ORzxk/QcegqNmJlU53YIJxg4+n0pVk3MWBLbiMDaOR9KY4baSfxPpzUJ+QHn8if600l3baqk5/lUqRiPk4Z+uc9Pb61KdsgIYc/3u4NOVcAKowq/wB7qf6daYWzxnv6U04yAeT1wRmnKjfdxgZ79Kf5eBnqoODx07GnpGGYgAnjnjpV4EQxdRnGT2qJZnYnBVVxg56Claf532sD2yOaiaTdlnY7iOMj+tRC5TONxx3JFI8m47YgQCeWIHNRhljKgAH8B0pcKuRJzj+50/OkUZGAMkdR6/jT22/cQfNuz+H4VZnxBZxwJnMuC5B7kdP51UkYq4AU5RvU9sc9fbtTkY5IjtkyenmEn8efpTXBfbkrgdQuADn09c0sgZYY0DYx877hjk/1xUL5QHkjPPvzUkaKYVkBbIOODj+lEaEuQXxnnGOKaFUHdjLdN1OwN2R2HJxSH72OSBwMU4Yxljj0wM0p3IMdM8io9oxz09CevvT8A/dUknqxNCqN21AfcD8asRQNK+eSOpJFXFjW3Tqd2BxmqNxMXY8YyKrMxG4jJ3ck57UxS5+5njrjv/nilX5uXyzdeDSYGORg5z1qWMBuqlgOo6nFW7fT5JMmQ+XGOfmHX8P8anXToMkvcBgCOhH6mpBJZ2qM0exmY9uT+n1qIakAwxCsbFc7sdP0+lU5pDPJyRvxwO/4VG7SMyszZbrnbhh+NJu7tvfJ+YM3BpciXZEBHnOA3cj3/nSz/LK5AyvTAx045z9fp0pPLjXIYhzjnAIH+frTmYmMFNqjPHb/AD2oRGJGwN16k9DTzbnGWyvP3aDbsv3F3Z4ApBayt1IGeuakW1IYZbAHeoriMALhiQep96hUK5YLuJHQ1bWyYYMhGP7o+9/hUyRwoeh/GgXAiPB4HtUFxcAkBXHIyGBqqZQFIQAnuSP8+lNCcfN8xOCOcBT+dSiABiWX7vUYxUiwszDyoi3YHHFTNbWsH+vzNLj7iHAH1p6SJA260gEef4nOQR+f9aZNcGTBkuMjghUXGfxqNnxDgqqwlfkXONx/Hk9qaxg8vCByTjG9hge+BTW2hsDBVudxA/yKRZmRCyqFJJ+YD8aYqljhOBjORThHu5ILdehHIp0akNvOcKOMDrUbMdxwgAbk8Y5p4XH8J4OCCM81cSLdErvjjHQ0ruFBVcAetRNcD+HqBgd//rVIJBhOR9cVGbglsID16A0BjGeeXPbOQPf61H5oaRQylhnpnrVjcsfCJGhxjPU/hUbzLkhyoGenSoPNMoKxru5HJB4qb7FM+GyGHrjinrpzKh3yIo9Qcn8f/wBdCvZWxVVUyn165qVZLF8ExhW7fLinm/jTISMEZJyeKhfVOR5caqB0OM1VN1MSM7OvZAcUokMuzLZcnrTJZQuUDDO7JC9iPXvUQ3P8pJJ44HP0+nWlIIwGU55zz+tSRuqn7ocgdG7CnEqF6YxwNvT8qjGBkMgOF5z/ADzUoXDHCcA9QDz7VKYZMBQjLxnaOfzpjWbAZJVcc/Mefp/OrC+XENqLv7kkZqGe4BY854GBiq0rSdOcYHX0qHgDLEAN2HP+fWlWXb8ozt9ByPyq20axthAWbAIbdwM+lIbZht3BgSe3r/hVi1sSWLHhAc7qr3Cusr7MHr37VEsL5O4sxJ6AVoRxCziLSYMhHYE7R/WoDcSOcl8jOMA1VmlZ32novr1JoVXONqsSemFq0tlIwG4bB/EWOcU65toXiQQyK5UksOMnis/ZwdpwOTz34/nSj5jyVYkfePapAC0i8sQe59KYG2jt78il3Mu4YyO/PTn1pO+cgknoTjvTQBxkcepp28ptA3cDof1q95KAAht2D/EeP0pzBY/l+9jkn60guGUFdxyeeaiYgMc9hxTXYEYJJ7CombBztH5Zz71HK2SwUFR2OMUsMQIGeACNz56fT3qZNgwVjXtgkkmr9uQ8W9wSU9V4xTmv1zjb8uTyDmoJbp5V2xE89QBmo7YOpzIm5MYO7v71M16m75AAegO3Bqo7meTLZds4A/rSiBUwzPjBztFONxk7VXd3wR+v4UnnEt93vkj1p8kjyAtuK447j/8AV3qCMESDByy87vWknjQYmTJR84Gfu98UiDzV+UbQPUZJNNXgl2XGD9DTGwCeNo9RnpQRk72IbPXaMUKoyRjOOScVKqEkKigjI6Dr/nmrcVjgiS4YBf7nr/nimA7Hyx6dqjaYFs7cseRzionZidzHIxk5PSkeNdw5JAGc0z95uz1BPqaOSQqkg/XOKkWNWIyT9AP8iraWgYjezbR2TAx+dTx29un3VYkc/MDUzXG1euMjnJ4FUPNVf9WgY5zuPahpXI6DPrjGKj+f7xGQOdp+v5+lK7wqdzIeT/8ArpolAwqDk9uP1o8tjguwwO2acCAGUD124Oef6j/GmuVVcqQ21sZA4/8ArUoctwBv7KOw/CgLsAVuMe2MHHNNDFE8t/mjJxkHPPt709YlXBUuS3CkdOvT61AUy5Z8nAG7vSHeV5zt689PapFhaQ4QE/QHmpUs8Eb2VQe/XIqcMsRyiYAHDHn9aYXJJb3HU1BtBI2lj/Fk+vfHtTWx9wAkdDim7hwqnG3pzwM9c0rFQqrgnksc+9NEeeDg8+macsSjGc9eatoEjG4gfiaGuRGh4IwKga9kccKAOucUzBdwx5Oee4+lSqSr+WY2YjktjgcU5gduA7AnnAXOPc81W2zI8YEgKdWxxn2NTMhYAMVAI+X/AOvSL8oIOGI44HA/xpUUdXlWMjtuzzSSb0I3Ec45Hf8ADtURdzIxk4Veck0M4AHOTnsalWUsMNglh1Of0qMqDkEHkYznvU8TSKCq5KnqDUrJ5mCQMHjkcg+tIsUKgbhntg0eaAMDgegqMzheScn1zmm+dkn5cZ6k0pJ3DnJ4OcEnrTOe559McVIkasC0pCr1z2qUJbYxvKkDIJ5yKjkQBiQQRnGc9PzpGiwowyr6UqvEm8E7hnA44+tMEwYYCDnpu60yRXcnAHHbGKFTDgtjIORTnb/noxyRyBTxK+CSSM8k+pPc/nUbON2ecn2prOScAgHrgUzO0BlkYknpt6frTzKQV2yHpk45NNXAw4JJ5+YcnP8AhUkaFtrYyeTkjpSSRvGeM8ZOBSiLjkZOOg/rUkaEk9C2OhFP8tedx/OhY8nJIz2J60/O5SVGOeoGcUm3bEVJGT61HKwT03A9utQKoLZyOeuPSpeuMA9PxprFtowSCcY4p4KYBwgJPbvSEo7qDJxnkY4pJJFR8DAI4554pPKQwCRWJwcEVWZmUBFxtznrRHl2b5ctjjnipWt8j52AwcEA96lCkAnlm649aWAlo2kY/Kp7VGcPIxPTP6dqA6g5Dcg55NQmbd3weuf8KQHcW2qSfUf59aVRgMfvHPAHIB/rUsFuZU3uMIPfr7VYRYwxkChcfKvIxj1FKWCruHykdyMcf4c0oYyIDnbz6UBWgBV2xu5SjyjnAb5iSMnmnOYwAJGJx3HGaaG83cECjuAT+NMd12hywAGeB+X+frVUSu53ZP0Jp3OM988+9PjAAz93HpUxbZkFyOBwSaQj5A2B35POaqllUEhienXjFLGw2SOScYwoA5z7UsVlJKM7tiZwu4cmtBbW3t8eWMuO/c1BLaxsS7FgCTnHf/PNAjVF+QKq9waYpUyEleD0KjpTGSTlo87z7dKllAeILwmeW2jPPHaqzQSoSd6spHDFv880v2aQr8rIzHr83+IpJLWRDlpIzHkfPx19PWpUtbZvuyu2D8wBAyfy4ome4hbZCAFz0Vc8/wAzxioDcTyn/dGPlGAOOlTQswjwyj5ewx0/z/OrKKN3zZGDyScUgeNQQGOB6daUqspLOwIx/F1qM7Tnayd8Y4z/AJ/rUZkjcZljCrzy3H5VE04JVYRtXOB6/WiV/MYgR7VU8Etk9e5pFwUwTgbh704DCjJwf72OlSLI7IxXBYkDIHWiNwTuV1LgZye5/wAmmvLJuO884/iOeKZp8S3ChXzjPbjvWt5EMJCJEmAvBI560ju3PPTpVZycDk/N1pEfcgBVeg5xz0qCaZsdunp71ZZRHGdoxSZyhJAyvSopWOV9xzSyqEZ2XqAGH1pyu0tuGc5Kjg/hT3UOREw3JxwfwqM2sI/5Zg9OtKT8x4HAGKYxYyRjcQFxjBpk7uMMGOee9Pf5SAOBgN+NRh239e9WEUeXu78/1qvdkxeWiEgEcnvVbbvmAYk8dT16GpmAG3HoKRAGlCnpxT4lG3p2/rTPvRjP+eBSffbn+72+hq1ZQJNPIr5wqlgAe9V7kbZGwT8pOK//2Q==
!usage
{{{[img[TexturesParchment]]}}}
[img[TexturesParchment]]
!notes

!type
image/jpg
!file
./images/parchment.jpg
!url

!data
data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCACAAIADASIAAhEBAxEB/8QAGQABAQEBAQEAAAAAAAAAAAAAAgEDAAQH/8QAKRAAAgICAQMEAQQDAAAAAAAAAAECERIhMQNBURMiYXFSMkJioYGCsv/EABcBAQEBAQAAAAAAAAAAAAAAAAABAgP/xAAYEQEBAQEBAAAAAAAAAAAAAAAAAREhMf/aAAwDAQACEQMRAD8A+5pqJ0+oqpOzJ25HY+6mzlrblFvfYtLOuxq3SrsTuMNHBPdUVrGqOcqR1jiEn27HOuwYzXAm6KI9cgT91drNG7QUldgctrXBWqdEbrk5yx33CEqdqix1qtAU09cMV64EaWW5NAa91it67Ek0qFR3bQJxvZPW3jjKjpSsm6SFFUqbF32CMZZXI1qloQR1/khedvRClDWURJ2rOxXgtVXgmDjlt7Eu5HrZcMdKKA0sTRRctoMtLyKBg7VGqSSpgV1sSk0Ia5u6BgrLje2iNpOnsUZyaTqztrkLjcsjWD4VGWiWV20P5EpLhrQpSVeTeIx7lSZqsZdhJIYjPB8sD/o9AGovuLDdZxlSoTmsaRHBrgPw2Bybt+Cdx5VGgOl3JSuSrfkcYrG2FSXDEp1F+QOlFpfAJRTRXk1yZSUre2KrWPSTF6bNW6QZSr7LiBTWi41GyrqruSUlLgLro32Q20uTK2uAuUnyNSlOdoGb/wBSY3zsNtN2jOj1RbcV7gdRceQLqPDgnqeUXR1uMXfJKTmtjisnQ/Td/AAj0/6NMV+H9hqXT+jSLUkWQTBfJlLputno0cXNTXMxHKVfZm5WNWLi3wdG+A2mVtp2u5FdjfAvTAnbEmIJjujn0rWzWNVooTWMek0N9KLGlRwxNCHTxZoccyzkEkrVBXTp3Ym6VnJ2rApxx1jiM5Rt2jNoUp2CcktoladVaK5NJ+EBtp/BslDAkGME5S2ejBaM4pLg0jK/ssK7Brhl93wUzld7B6Wa+SxlZmq/IcU0UshhckjpOokc4vQ1JEm70RSajRoZyq9EixommS15Rkm3IWL8AyFOF7RlN1dLRraSy8mbp2hRmlcBKwtSjuxLdMzBU2no0im9yM/3DjPk1BoZT2yyl/Ikp3yCR3ujEqk1+ovqLwSrj/IAzk5J+CWxKMmR8aAsZJM7mX2DGtvk6+/cmmmkkOP4szUldsUWuWVUzfYDlv6GqukSUaYo79XBO1MzyUdRI5tk0aXRG6VmcXUrY8YyWiamYrb+yncFfkoNryhp2EilfA3CG50/gjnFut2GTfPKJFJ74GhA/wChSTX7tEcG9ohFyy0xqkjNRaptji42kyyj/9k=
!usage
{{{[img[TexturesParchmentGray]]}}}
[img[TexturesParchmentGray]]
!notes

!type
image/jpg
!file
./images/parchment_gray.jpg
!url

!data
data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEBLAEsAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/wAALCACAAIABAREA/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/9oACAEBAAA/APcgQtDuMYBqMKTz2ox82O1O2A84pSNuMU8Ht2oOO1IeOtRg847U8c9OlBGDilGDkYpU447Urcmo8fNmozkmjb82CamzgYpO9BbApM0quOlKTignIpoAzmlJxSFsc0BwfrTgeKMmkJAo7cUx1zzSqMDBNOHWlOPxpO1M43Cn5yM0UDk80rKKYQMUmw5GKlAwOaQkGmbRmm+bzjBxQzZpVU5yalxgcUnXk0U3aPSlxjHpTgOtIRjmlCluaa3ApBnFO3EUm3PJpuQDg0xiAcZoGRUg3dSKf703HNKFNP2HqaYf0pytgYpSwximAnn0pO9KBjmnqoxk0jKQPamMoIqArls1Kh6DFTBh0IpxIxQNrdqcAKWmEKaaUI6U32NLnAxTDgd6UMOlPD4U0w7iOtRMGz1qVYc07yzRtI4pduBQue1PJA61E8lM3n8KnU5Uc0yQfnTMkA5puMtT1TNSbR6Uu0VE0ZqcnAprNikEg70MwbpTMkdKaWY9aTbnrTMkHkVIHO3pSb/WnKNxp/lnPtRgp9KepDCncUUGoT1o25oGelIVz0p3l0m3nFBiyKRYiKeYgaEj2mpKRhkYpoTBzmn0Uxmx9ajLZo3A0EkcikByaeDT1xjiloAxRS0GkJwM0A5GaWjNRsuTmoyKTGKUk4piAs1WNg4o2kdDS8ik3ilVs06mlgKaxzxQGIGKeCDSZHrUZemO3cU0k59qmAXZTQAOlSBs/WnUxs55poA9aeoIpWOBSbgacMUxsZ4pgJJp+2lZMnIqJ+OgpoGVpRmlBIPFSKCeTT6jfk0nIFKGI60jMWpM0ocA0ZyaUACnL6GjOBn1qNsHimEFeaUc80o+9T1elLe9NL5p28Y6Uh5X3pApNIenFNxjnvRnv3pwYdTT1I6mm7j2pm7mnZ3Dik7YpM4pCe9KSaWkzTgc0pfB9qaXU8d6SmfzpwbPBp4wBThjOBTWXBqLeF4FIXJpFPOTUmAw4pRxSn1pKQNnpQ2evakUA89KUgjvxSFCeRQFIwTT1K5wa//Z
!usage
{{{[img[TexturesStucco]]}}}
[img[TexturesStucco]]
!notes

!type
image/gif
!file
./images/stucco.gif
!url

!data
data:image/gif;base64,R0lGODlhgACAALMAALu8x+Xm7NfZ4cjN1fX5/ezw893k6f///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACwAAAAAgACAAAAE/3CIcggt9OhdiSUH5WGHEGhgJahV4HVberYp6L2w2GVhwIsfDs5jKPhWPYFFUzwEJgRB8RaC1qgdgquHEQxiVVfGQL2iUMbL7YWtuLfu1IEs4rUuccJ3XhhpfBZ9WnAhBhoYfYI1HG6NRQYzgn0lJGuNlz6XQnJyk3EbRUCNBFN2TkhPHJWHS5M+hIxoh08USiFaExiWuR9XIJ66a2w5cluTwEtmt8IoM1VIOzYfAkpkVyS3ZzYViMWvMyAuzDAwFibjYIkVZNmjq5eLjoeHttxGKDYYkNdigHJvSvpkOrNBTZ5esewpwhcjkCoh604MO7QQxQRyrxpl+NdHAICLsv9epHFYwIoufCIk6sgiqY0TAwakdMPnwVkIYoV+4VjWiomFSCsGlAynLQSPKFYIDhJ0osAAQP4EzVsiLgYtIwGyeiLniE2iJQULUqkkBxISGRmo9XnqFNAmTjFX/lOlVeO2sTdHVIzjr5DMAnEJMhRJYpIhsE1iYZmxwk7WnTeOCguSsAq3fJZuKJk8FwyaVIy2leOUJZ9gyKzwaMLWsFeNrZ53OnHo5FPBrYSlRYaYa6EyiKctWcXDw5a6OLBL3/4ajSuqX4LoAOkMdhL01iXZSV3dBktm68ctTniiVXYg3Zwii+7mR0XH0is4x44FbBZpTdJo3t/J+ldqrU9sls//Sfillw95GWwkgloa8DLZV71gsxMS1MQjnDtgOMQfLBSCRRFMsJDmwTn21PWHRLD0kMJGk40ywlxXobEKOnfFQMETNpggXiZH2dTZZcKdZ14GAYry0jxpvDUPclnYmOSRrYmWF1nrzGHDY8hl1SEJtjCDzk0oDaWRBF2Uc4BQy3iyhihDNNkBOyrAWZqBK1nJVU3U1LOiUhO1FpxF22kwQExPBQAJBWiy6CZmbeJXFRN7lYEaQ6qwBuRPfkipTRt7FTRFaF08FYVqv6Fnyj+kBNgbVix6eddcgLXa0Ci2QSbbolARQp0LTZhCDqyiDXPfDogImNkmz8hqz12SKEIZ/0Te4WOIjaPOtR6qskk4521mZJuUpFOQQgZMqM6qynVoTEoTIhvkAg4WLb3lXTHsWKhYIMnN4uwtUlTDCYG0aREIj3YM4dJnW5XUVGMhNbooJ+JYi1k7KDECWMQeAofGtC1QE+DHFf7oplHCIUFgSWFlaq1+oTXplU4wC7OgFVHQgcJhRyVCIJ9qvMyZeTneY8gRMfkkJVXhcuufRg1aLGdhkaY2HUX56fjaihD+aGsw/zTWNRP66bWxCSBNYA2MM31gXWheVMiyLJs6gUdTYgFXrhAxvZjBFwMtqeatdBWRi3043ANqJ/qsrNQnS9+4jUR1S1kR0Aq90ot26XLlhv+EQ5Hhdh01udbMBepE8eJ5dgFjXTiQ06RQrGfgVtkGJgo8FcUT3zJjFVKpLZeMYMYm4lRNbHNMoPAkIoXxqwcbCzWQmqabEL4+hI8PiEACpuyvgWQurNYsEzGQyVNNmLM+d2KL5SKNPFxZMuk+BxQxuSCBWjIkzXl7lXVDJLzJCF5+EFewXxHEZF9bk7AaBIL4sEsSdXOa8Wr0mqLMwXpGYcVNfkAtM60DJnlBjS4AFrl45cdmMKtNZYqXpeYBTil4sED4VucZ1+mHY10wgKiAZBA2LPB0akuRLgbij3HwDzqd+tlgQCESiVFnZTwQ3CAmBh71SIYsP4kYYOKTlcv/IOKLrjOQS7olHBzaJkqS8hQGvnCUzUFhNCrqhBCi0orC9K0p6KHCFmAGmwvFboCHyYuS5qQe/glQhieqETcsRj3mCMx0GqSdmhpyjFnIyYfoIR+YFEkpTWiOIxmiDJXCtgxzzec2m/PfFSJhFCP8RjA2rM4nkgM0cxgpgBwATSUU9CL5wTKXeLJiZNjTwD9ooWdjLJfBTrc5bM3Lloq5xBDxdxcs7cQYvEwGeIAZrJMwZZEzYYUS81DDRSQzFhJRpCjpEaTJlQCPbzjGemaTCa1ZKQCiCge6ErSRJQllII165pKY9iUkSdKB2IBGA5uys9OxCIwtSkYkfrG8y7Tj/5jzKFo2MCmvSi7ibPAAg1u4YTWrBSOD3cQXVhSoRIyuSH2hgNoapGAIoeSHViKbCg4Ow6zujBBQJUEmEk9wBLV8sTzi/B1FvqUjJvwlLh6CCdRCKKQ8yuCY/RygL5xkCgDhkqDkXJMGp4MNgRCEXbObzQEA4BMLZu5S3lyNJ0cxLYgJwaSaEBDVyhchabgyY2DZDahAeEE+bCZqsdzTP0B6rmbUkxVYWqROLmCTIqoOYH87nTFGtFibOAVNLxrAAEihDxGEYow+OdTtYOlDBmoILeQxQVdxhxkxNYiWXpHsIklWEAbVJ0E2eISzADM7ItQmWNcA1p444Nta1Aityf+oXyeWVpRXFbZOBRHtD2jpK6zRgnZRMCVCoBVYSoUuHAbxSxpoahMmnO1Y49UdNCjB3IoS0nx7bZcJThDIxWw2lprIChwqpDzUzeNRA/tBHk+pkMaiKi7JGYgrNQm9BprGUMVo3tsghrgG9hFy18DuLC+oWErhxkJIAQS7RNmYLjrBLVAtgZ6CcLC57MFGwKTIGczW0HfooBbH7VnvSAU8GcHELLxsxvp65AW2AkaO5h2oa+GAKtwQdzOa44Y4+nvBOlA1LIzBVmW0VA+rnEi089WNpfizJKyFRjRYluYy09OcezEuLDk7SmKsl8X7ALQQzbiG8HQSvATtccdlRR3/LIzAMTybrp+rmDCQXaQm9pRga8dhlDb+hizz3oc4vPVCGWQKq3yBMNPmaea8QAG2jd5JL7i01YbN6TIs3qgOQH6hH2u8r11vsLWTyo1HO323hynDmWlsn+1G28tDJuRWmGxtLje5NqapGmVaNDGd3ffKKMlIWC/4biEw9uZuR9tP/ol2a1e3kRXUUxkNdaIN7+QiNkADdB1Enx8Zd1ODhXLVhYNUyvpJMlhXJkir7vQmZpCJMscm3ji9FIDj5m9FEgJ0kQFoQHMqn01HnOGIepSU5U1OVxasW8Q+DUNieGj+GMjT/BZzuAOkgqAJ6hd7pBwZOcDTiXvb2pCejQzE/zATRX0vbrKQxJbV0psfNdXbWg1bxvvkn0rrrCjVPgW1YYAx0Tmskxa159v2WjgfPGW+rQkIiX7lzFKGNQe2gcR3scYxS+j7aE2cHYKRxxSif5EkX2RNGjAMXLAWMJTtWHOdPLTtNskMucoJVBk0GO4jvqIU9UNrM8YaHjhoi03ooTLb/57Wb3cQ3AdBhynUEB+wg0XFlbQLXbPZOxTniXPrqPSeo5XlJ+oAIfuWQW8vcjB6XHJxpfTp4RVUd9ns+YMjDMap3lH65J2MMVGkhUplc47hIanSKKF1bc7yyIlAqCDY41rHPZif2mNyon8Q/EhAJa3wzUpRQ2kPfA1xkf/4DEMX3iNArhNI8hJGkpMtNcAYdbFQ00IqkOFAmgZpnVIlOSM5BMg5SRNY8YBx0qZqpQI8o3JoK5UCNJMx0JNYJ+gLz9IY4+EbelFptEFxLoN3/jY5MHgitcALh3AohDYCfXMK2tNgx7QqayBVs/FXf3BaedFe+KFbv2NOHBUPo0dQ6SRDamcpLJEzVDZS3rVi/UYutNNohjQMe8Zlm+Mys9JtK0c6x2U9hmIoazYvxDVhHUVwGNYxRpI3/7cv+QVxD5N05bRcS1FzzhMDQqF+sdOAs+AFAJgicfEptBEr+hR72MEtvrQymaFPWsVhwwAOjOYcnWAoMIEmwGMHOvT/L49VFHkTFjDkaxaRhJJlVRwBMJ2RFn9QZoaDFXxwKIEiCLYAE1foVxDlOFKWDX1QL27XPi2zW7+UWAGkjMVxAVxkTESyJPdWHQlDMl8weSIRECTlC/hWMywBdZM0SMcWRuLkVz9ReP/yTRjgDPqQc2gCPSZ3gRwjEYe1eyXRJf8Cdo1EY8MyEZOnO8sVTvYBEIChHQqTT04RZ1VwYxRhKAplDqoAIhTlI9oAhscmhYFobZtkDyoUCHHGS56gFeMRQYbjNtWSX0OAI5GBOXBFcE4xHf5GSJnokdXGJXykBXQgSo8hEDeWCOJwBPtDLGVCY1skBTYihtW2U8/2K1WY/yHllgW6YjJhogWn8DFtwQpQNWEeEo2ntSBHczNSlQiJARlVpE0Hd1NRlo6UB21j8SzwgQsTYFN0CZIyRj2GQFxzRRGVoD19FXDkoDPvmEI3aSb61yC9gj1X0kUqMVBuIzeMmEg9eGt1h3hsCR4JqYIcERME1pN2YmxS+VNBlEkqtB34Qh/cQgJ9MwiM42VZyBCNtnhm8BekIZNitiyrdVbOUGyGRl04hlINJFuOhBzrkTUPBQJ7yW2t1F3tN32oETP9cRKBVXh++TghwFZxVBzQMB4aqEDpyGk8VXzfRmNKSUoFaJzvqJsiKTficH1OJxbKmEG5VzBZBwyNJkgHcf84lIIjb3YveeecjnaP8OYHrvBQQECcpDCaG5dbwWB/ArkzFUOf+2FlOtBzg6RjPIFj5XVpbBBZpwB+uMaf2gAFoDcEb+Q6euYiZ8WD0nKMKeGJzFUYZ8kUQEBUvNlqLPKT8RcscGKgi3NTM0l61vajnxI810OGjNcoxNFsFjUPmzGUViMoqqNCTrKg7UFlLhhJzWYazHUGVbFPl9kDGtElaakGsNEFVWEHQvYsoJYcxLdj6SdxIVU4FEQKEkMP07dEXNCKWKkXauFitZMCQ+M/k1SI5BVWhQRBbVYiDqJJgAZLgdI2JjExgilJL2ZhN4FPXcpPd0Z5niGh9BFTguj/cd1QCn+5ej/JEXvEI1oRDHhUOqRADTZ1WMYQTb2DLAV1jA61LOeoMcqJQb42JIG2clqiEtgjn4WpUWIISjH0ny4RQwMCRx3IjHBzRtWHCPWUL7MwOz+wBRLAjB1IActpFd6nKcEZIbv1Q3FCOmE6Ap8SVHSWYlnmnTf1qgQCWg+XDixKfV3TSwj3B9DqdjnwVzWoU1JSF2lQLB2hIwQyOHwQAodIdbTFHIuyjMcyGjVmLnJiGY6wjbVRe+lECfK6GoN3Ln1ETfMkqqX0GAN0UVL3SQMZnXEpYQmyocnQOGZKO/75Eb8nGO8glxuLDx5DP++Up/8JLazFjq2on1jX/wMokkr6xWxiYCNDCVDU+XKqCUXMMoHQxqKsaHD4hV2TBGSZ0EWd8UayJTDZYUvg2JpjpCYqxgdtcnflVpNSpjBRpjKYshJm8wqUlaJkg7bg5x5tOXYaUyk01B3JtG1g1yytFot3wDBCp7edwRgnmCIyki+2ki0aQUsTV1D+mC1GAAWDg7YoUbVK8arPCABpAQjhAjBGuEnQBptzYBZXJU3qJ0ZSWWu0Qp9KmTcpgaSgdCIucKwD84oqklfGAY5gIFWeUxQX8Vi7AXp/lDmlWoyio0tLmyc+yBEvZaVkegl62B24+Kyq8bnRwIb6gWsvVTiSQbwohTPW6o8zOlba9v8G+dUCGoUMFLRXJOSloVEvDNJ+h/i59uk3zVhDeFMwvfkOkXBSiYuV2LquemQ86bcbSwojVglJbjGf5lZ6/klJVzMVWKSa3TqQT6oYvFplVKaUXhmRipWsHUB+fOo+g/EEo7U9K8JQautXffGtYaKZHZZT1LNHSrA8hCVqzWAN20F+/bYI72if5nAY74JLE+ad6/ICRfBnzUZMqZQ4QTLB2kokpXsy8pBJc+YnlFcvuPBWZHqzg6EERIV2R4M+xVVlrniGNxEunOB/26eOSmQdgDCRZWdMlLQ2VYejv9cqw8Rp88YVXMOoLLA5LrACauHGe8koK6u2VPNjaASF1VP9O1HkHc0XUdjREuqGAyb6ap60Q6AAmm72TuEnTke8KeURBJYlhYDjKtNTfS0iN0vBQddbAjsMwyvhQgkDXMLhsukhT3cQfWy6TCNzbi0DcBWnHM/7A9RQPItVA5tcDFzajozZOAMCNXKhwmx3t1HcvjYchfBbIK4WQrORFGo1Unw3CJajVk5JdrP4Pb9sZ682KjV8D6zSBqLnBNv4EwRhs+WwyY6sd8zhCYEkIYsFidbSHy8zbwslTw1o0Q0UhINSEntwD6+XZqwMkpOBZbN4Vd4oBpyJl2CMUf2Dc/UhYDqwjUX3ApOJMnrwi0bCJRbkZHvUHwxMh/5CHBAXAQA7
!usage
{{{[[The Sky's The Limit|The Sky's The Limit]]}}}
[[The Sky's The Limit|The Sky's The Limit]]
!notes
Friday Night Music - live experimental improv - http://www.FridayNightMusic.com
>{{fine{Notice: The recorded material referenced herein is an "original work of art" as defined by United States and California Civil Code, and is protected by copyright.  Except for personal non-commercial performance, these works may not be stored, reproduced or re-transmitted in any form without express permission of the rights holders.}}}
''Please do not copy this tiddler.''  This attachment is used by the TiddlyPodPlugin (in the TiddlyPodList playlist tiddler) to virtualize the remote URL reference for this recording.  It is intended only as a demonstration for use in the www.TiddlyTools.com on-line document.
!type
audio/mp3
!file
./audio/fnm/001103-4.mp3
!url
http://www.TiddlyTools.com/audio/fnm/001103-4.mp3
!data
{{floatright center fine borderleft{
&nbsp; current theme:
&nbsp; <<switchTheme width:auto>>
|borderless|k
|&nbsp;&nbsp;&nbsp;<<option chkRandomTheme>>| select a random<br>theme at startup |
}}}
This package includes SwitchThemePlugin, which allows you to quickly switch between different system themes (templates and stylesheets).  It also includes several pre-defined themes, plus additional stylesheets and 'attachment' tiddlers (using AttachFilePluginFormatters) to support self-contained references for background textures and images.
/%
!info
|Name|ThumbThing|
|Source|http://www.TiddlyTools.com/#ThumbThing|
|Version|1.2.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Description|display a scaled 'thumbnail' image with popup for full-sized image|

Usage:
<<<
{{{
<<tiddler ThumbThing with: image thumbWidth thumbHeight fullWidth fullHeight>>
}}}
*{{{image}}} is one of:
**a local path/file
**a remote URL reference
**the title of a tiddler containing an attached image (see [[AttachFilePlugin]])
*{{{thumbWidth, thumbHeight, fullWidth, fullHeight}}} are CSS measurements.  Use 'auto' (or omit values) for default (full-sized) image height and/or width. For proportional scaling, specify a fixed-width OR fixed-height and use 'auto' for the other dimension.
<<<
Example:
<<<
{{{
<<tiddler ThumbThing with: images/meow2.jpg 100px>>
}}}
<<tiddler ThumbThing with: images/meow2.jpg 100px>>
<<<
See also:
>[[AllThumbs]]
!end

!show
<html><hide linebreaks>
<img src="$1" style="border=0;width:$2;height:$3;" title="$1" onclick="
	var p=Popup.create(this); if (!p) return; var s=p.style; s.border=s.padding='0'; s.background='none';
	p.innerHTML='<img src=\x22$1\x22 style=\x22border:1px solid #999;background:#eee;width:$4;height:$5\x22>';
	Popup.show(); event.cancelBubble=true; if(event.stopPropagation)event.stopPropagation(); return(false);
"></html>
!end
%/<<tiddler {{'ThumbThing##'+('$1'=='$'+'1'?'info':'show')}} with:
	{{var cma=config.macros.attach; (cma&&cma.isAttachment('$1'))?cma.getAttachment('$1'):'$1';}}
	[[$2]] [[$3]] [[$4]] [[$5]]>>
<<tiddler HideTiddlerTags>><<tiddler {{
	// remove any existing 'tracframe' ID so that IFRAME is single-instance only...
	var f=document.getElementById('tracframe'); if (f) f.parentNode.removeChild(f);
'';}}>><html><div style="white-space:nowrap;text-align:center;"><form target="tracframe"
	style="display:inline;text-align:left;margin:0;padding:0"
	action="http://trac.tiddlywiki.org/report/1"><!--
--><span style="white-space:nowrap;float:left;"><!--
--><!--
--><input type="button" value="<" title="back" 
	style="font-size:8pt;width:2em"
	onclick="try{window.frames['tracframe'].history.go(-1)}catch(e){window.history.go(-1)}; document.getElementById('tracframe').style.display='block'; this.form.done.disabled=false;" ><!--
--><input type="button" value=">" title="forward" 
	style="font-size:8pt;width:2em"
	onclick="try{window.frames['tracframe'].history.go(+1)}catch(e){window.history.go(+1)}; document.getElementById('tracframe').style.display='block'; this.form.done.disabled=false;"><!--
--><input type="button" value="+" title="refresh" 
	style="font-size:8pt;width:2em"
	onclick="try{window.frames['tracframe'].location.reload()}catch(e){}; document.getElementById('tracframe').style.display='block'; this.form.done.disabled=false;"><!--
--><input type="button" value="x" title="stop" 
	style="font-size:8pt;width:2em"
	onclick="window.stop()"><!--
-->&nbsp;&nbsp;&nbsp;&nbsp;<!--
--><select size="1" name=sort style="font-size:8pt;"
	title="view tickets by..." 
	onchange="if (this.selectedIndex==0) {this.selectedIndex=1; return; } document.getElementById('tracframe').style.display='block'; this.form.done.disabled=false; this.form.submit();"><!--
-->	<option value="">view by...<!--
-->	<option value="ticket" SELECTED>ticket #<!--
-->	<option value="summary">summary<!--
-->	<option value="component">component<!--
-->	<option value="version">version<!--
-->	<option value="milestone">milestone<!--
-->	<option value="type">type<!--
-->	<option value="owner">owner<!--
-->	<option value="create date">created<!--
--></select><select size="1" name=asc style="font-size:8pt;"
	title="sort order..."
	onchange="document.getElementById('tracframe').style.display='block'; this.form.done.disabled=false; this.form.submit();"><!--
-->	<option value="1">ascending<!--
-->	<option value="0" SELECTED>descending<!--
--></select><!--
--><input type="submit" value="get report"
	title="get ticket report using current settings"
	onclick="document.getElementById('tracframe').style.display='block'; this.form.done.disabled=false;"
	style="font-size:8pt;"><!--
--><!--
--></span><span style="float:right"><!--
--><!--
--><input type="button" value="open" title="open report in a separate window" 
	style="font-size:8pt;"
	onclick="var url='http://trac.tiddlywiki.org/report/1?sort='+this.form.sort.value+'&asc=0'; window.open(url)"><!--
--><input type="button" name="done" value="done" title="hide ticket display" disabled 
	style="font-size:8pt;" 
	onclick="window.stop(); document.getElementById('tracframe').style.display='none';  this.disabled=true;"><!--
--><!--
--></span><!--
--><!--
--><input type="text" name=search value=""
	title="enter text to search for...
	onfocus="this.select()"
	style="font-size:8pt;width:10em;"
	onkeypress="if (event.keyCode==13) { this.form.searchbutton.click();return false}"><!--
--><input type="button" name="searchbutton" value="search" 
	title="find text in tickets and/or changeset logs"
	style="font-size:8pt;"
	onclick="var url='http://trac.tiddlywiki.org/search?ticket=on&changeset=on&wiki=off&q='; window.frames['tracframe'].location=url+this.form.search.value; document.getElementById('tracframe').style.display='block';"><!--
--><!--
--></div></form><iframe name="tracframe" id="tracframe" src="" style="display:none;background:#eee;width:100%;height:30em;"></iframe><!--
--></html>
/%
|Name|TidIDECommand|
|Source|http://www.TiddlyTools.com/#TidIDECommand|
|Version|2.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|script|
|Requires|TidIDEPlugin, NestedSlidersPlugin, MoveablePanelPlugin, TextAreaPlugin, TiddlerTweakerPlugin, InlineJavascriptPlugin, CompareTiddlers|
|Description|command link invokes TidIDE editor for current tiddler|

Usage (in ViewTemplate):
	<span class='toolbar' macro='tiddler TidIDECommand'></span>
OR embedded directly in tiddler content:
	<<tiddler TidIDECommand>>

%/+++^[TidIDE|Edit this tiddler using the TiddlyWiki Integrated Development Environment].../%
	%/{{fine smallform nowrap{<<moveablePanel>>/%
	%/<<tidIDE SystemInfo TiddlerTweaker CompareTiddlers +edit:here>>/%
	%/<<resizeEditor>>}}}/%
%/===
TidIDE - TiddlyWiki Integrated Development Environment

Provides tools for authors and developers to help construct and debug the contents of their TiddlyWiki documents.
/***
|Name|TidIDEPlugin|
|Source|http://www.TiddlyTools.com/#TidIDEPlugin|
|Documentation|http://www.TiddlyTools.com/#TidIDEPluginInfo|
|Version|1.8.5|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|TiddlyWiki Integrated Development Environment - tools for authors and plugin writers|
~TidIDE (//prounounced "Tie Dyed"//) - ''Tid''dlyWiki ''I''ntegrated ''D''evelopment ''E''nvironment - allows you to define a set of checkboxes to toggle a stack of 'tool panels' containing tools for TiddlyWiki authors to use when creating and debugging their TiddlyWiki documents.  Each tool is defined by a separate tiddler, allowing you to define any convenient set of tools simply by adding/removing tiddler references from the {{{<<tidIDE...>>}}} macro call.

In addition to presenting checkboxes/tool panels that are defined in separate tiddlers, the {{{<<tidIDE>>}}} macro can invoke an optional built-in "editor panel" that presents an alternative tiddler editor to create, modify, and manage the tiddlers in your document... and, if you have also installed [[PreviewPlugin]], the editor can automatically display a ''//formatted preview//'' of the current tiddler content that is updated ''live, key-by-key'' while you edit the tiddler source.
!!!!!Documentation
>see [[TidIDEPluginInfo]]
!!!!!Configuration
<<<
Number of rows to display in text input area <<option txtTidIDEMaxEditRows>> 
{{{usage: <<option txtTidIDEMaxEditRows>>}}}
^^//Note: if not specified here, default uses {{{<<option txtMaxEditRows>>}}} value (see [[AdvancedOptions]])//^^
<<<
!!!!!Revisions
<<<
2009.09.22 [1.8.5] added edit='tags' to tags input so {{{<<newTiddler tags:...>>}}} can init field
2009.08.27 [1.8.4] added 'tidIDEPanel' classname to container element (for custom CSS)
|please see [[TidIDEPluginInfo]] for additional revision details|
2006.04.15 [0.5.0] Initial ALPHA release. Converted from inline script.
<<<
!!!!!Code
***/
//{{{
version.extensions.TidIDEPlugin= {major: 1, minor: 8, revision: 5, date: new Date(2009,9,22)};

// settings
if (config.options.txtTidIDEMaxEditRows==undefined)
	config.options.txtTidIDEMaxEditRows=config.options.txtMaxEditRows

// shadow payload
config.shadowTiddlers['TidIDEPluginEditorPanel']=store.getTiddlerText('TidIDEPlugin##editorPanel');

config.macros.tidIDE = {
	versionMsg: "TidIDE v%0.%1.%2: ",
	datetimefmt: "0MM/0DD/YYYY 0hh:0mm",
	titleMsg: "Please enter a new tiddler title",
	isShadowMsg: "'%0' is a shadow tiddler and cannot be removed.",
	evalMsg: "Warning!! Processing '%0' as a systemConfig (plugin) tiddler may produce unexpected results! Are you sure you want to proceed?",
	evalCompletedMsg: "Processing completed",
	toolsDef: "<html><a href='javascript:config.macros.tidIDE.set(\"%0\",\"%1\");'>edit %1...</a></html>",
	editorLabel: "TiddlerEditor"
};

config.macros.tidIDE.handler= function(place,macroName,params) {
	var here=story.findContainingTiddler(place);
	var selectors="";
	var panels="";
	var showsys=false;
	var title="";
	var id=""; if (here) id=here.getAttribute("tiddler").replace(/ /g,"_");
	var p=params.shift();
	if (!p) p="edit:here"; // default to editor if no params
	var openpanels=[];
	var panelcount=0;
	while (p) {
		var defOpen=(p.substr(0,1)=="+"); if (defOpen) p=p.substr(1);
		if (p.substr(0,3)=="id:")
			{ id=p.substr(3); }
		else if (p.substr(0,4)=="edit") {
			panelcount++;
			defOpen=defOpen || (!params[0] && panelcount==1); // if only one panel to show, default to open
			var toolname=this.editorLabel;
			if (p.indexOf('|')!=-1) toolname=p.substr(0,p.indexOf('|'));
			selectors+=this.html.editorchk.replace(/%toolname%/mg,toolname);
			selectors=selectors.replace(/%showpanel%/mg,defOpen?"CHECKED":"");
			panels+=store.getTiddlerText('TidIDEPluginEditorPanel');
			// editor panel setup...
			panels=panels.replace(/%showpanel%/mg,defOpen?"block":"none");
			panels=panels.replace(/%maxrows%/mg,config.options.txtTidIDEMaxEditRows);
			panels=panels.replace(/%disabled%/mg,readOnly?"DISABLED":"");
			panels=panels.replace(/%readonlychk%/mg,readOnly?"CHECKED":"");
			panels=panels.replace(/%minoredits%/mg,config.options.chkForceMinorUpdate&&!readOnly?"":"DISABLED");
			panels=panels.replace(/%minorchk%/mg,config.options.chkForceMinorUpdate?"CHECKED":"");
			var tiddlers=store.getTiddlers("title"); var tiddlerlist=""; 
			for (var t=0; t<tiddlers.length; t++)
				tiddlerlist+='<option value="'+tiddlers[t].title+'">'+tiddlers[t].title+'</option>';
			for (var t in config.shadowTiddlers)
				if (!store.tiddlerExists(t)) tiddlerlist+="<option value='"+t+"'>"+t+" (shadow)</option>";
			panels=panels.replace(/%tiddlerlist%/mg,tiddlerlist);
			var tags = store.getTags(); var taglist="";
			for (var t=0; t<tags.length; t++)
				taglist+="<option value='"+tags[t][0]+"'>"+tags[t][0]+"</option>";
			panels=panels.replace(/%taglist%/mg,taglist);
			if (p.substr(0,5)=="edit:") { 
				title=p.substr(5); 
				if (here && title=="here") title=here.id.substr(7);
			}
		}
		else {
			panelcount++;
			defOpen=defOpen || (!params[0] && panelcount==1); // if only one panel to show, default to open
			var toolid=toolname=p;
			if (p.indexOf('|')!=-1)
				{ toolname=p.substr(0,p.indexOf('|')); toolid=p.substr(p.indexOf('|')+1); }
			selectors+=this.html.toolschk.replace(/%toolid%/mg,toolid).replace(/%toolname%/mg,toolname);
			selectors=selectors.replace(/%showpanel%/mg,defOpen?"CHECKED":"");
			panels+=this.html.toolspanel.replace(/%toolid%/mg,toolid);
			panels=panels.replace(/%showpanel%/mg,defOpen?"block":"none");
			if (defOpen) openpanels.push(toolid);
		}
		p=params.shift(); // next param
	}
	var html=this.html.framework;
	if (panelcount<2)
		html=html.replace(/%version%/mg,'').replace(/%selector%/mg,''); // omit header/selectors if just one panel to display
	else {
		var v=version.extensions.TidIDEPlugin;
		html=html.replace(/%version%/mg, this.versionMsg.format([v.major,v.minor,v.revision]));
		html=html.replace(/%selector%/mg,selectors+"<hr style='margin:0;padding:0'>");
	}
	html=html.replace(/%panels%/mg,panels);
	html=html.replace(/%id%/mg,id);
	var newIDE=createTiddlyElement(place,"span",null,"tidIDEPanel");
	newIDE.innerHTML=html;
	if (title.length) this.set(id,title);  // pre-load tiddler editor values (if needed)
	if (openpanels.length) for (i=0;i<openpanels.length;i++) { config.macros.tidIDE.loadPanel(id,openpanels[i]); }
	// see [[TextAreaPlugin]] for extended ctrl-F/G (search/search again)and TAB handler definitions
	if (window.addKeyDownHandlers!=undefined) {
		var elems=newIDE.getElementsByTagName("textarea");
		for (var i=0;i<elems.length;i++) window.addKeyDownHandlers(elems[i]);
	}
	var prev=document.getElementById(id+'_previewpanel');
	if (config.macros.preview && prev)  // add previewer to editor (if installed)
		config.macros.preview.handler(prev,"preview",["text","15"]);
}
//}}}

// // CUSTOM PANEL FUNCTIONS 
//{{{
config.macros.tidIDE.loadPanel=function(id,toolid) {
	var place=document.getElementById(id+"_"+toolid+"_panel"); if (!place) return;
	var t=store.getTiddlerText(toolid,"");
	place.innerHTML=""; 
	if (t) wikify(t,place); else place.innerHTML=this.toolsDef.format([id,toolid]);
}
//}}}

// // EDITOR PANEL FUNCTIONS
//{{{
config.macros.tidIDE.set=function(id,title) {
	var place=document.getElementById(id+"_editorpanel"); if (!place) return;
	var f=document.getElementById(id+"_editorform");
	if (f.dirty && !confirm(config.commands.cancelTiddler.warning.format([f.current]))) return;
	// reset to form defaults
	f.dirty=false;
	f.current="";
	f.created.value=f.created.defaultValue;
	f.modified.value=f.modified.defaultValue;
	f.author.value=f.author.defaultValue;
	f.content.value=f.content.defaultValue;
	f.tags.value=f.tags.defaultValue;
	f.size.value=f.size.defaultValue;
	if (!title.length) return;
	f.current=title;
	// values for new/shadow tiddlers
	var cdate=new Date();
	var mdate=new Date();
	var modifier=config.options.txtUserName;
	var text=config.views.editor.defaultText.format([title]);
	var tags="";
	// adjust values for shadow tiddlers
	if (store.isShadowTiddler(title))
		{ modifier=config.views.wikified.shadowModifier; text=store.getTiddlerText(title) }
	// get values for specified tiddler (if it exists)
	var t=store.getTiddler(title);
	if (t)	{ var cdate=t.created; var mdate=t.modified; var modifier=t.modifier; var text=t.text; var tags=t.getTags(); }
	if (!t && !store.isShadowTiddler(title)) f.tiddlers.options[f.tiddlers.options.length]=new Option(title,title,false,true); // add item to list
	f.tiddlers.value=title; // select current title (just in case it wasn't already selected)
	f.created.value=cdate.formatString(this.datetimefmt);
	f.modified.value=mdate.formatString(this.datetimefmt);
	f.author.value=modifier;
	f.content.value=text;
	f.tags.value=tags;
	f.minoredits.checked=config.options.chkForceMinorUpdate&&!readOnly;
	f.size.value=f.content.value.length+" bytes";
}

config.macros.tidIDE.add=function(id) {
	var place=document.getElementById(id+"_editorpanel"); if (!place) return;
	var f=document.getElementById(id+"_editorform");
	if (f.dirty && !confirm(config.commands.cancelTiddler.warning.format([f.current]))) return;
	var title=prompt(this.titleMsg,config.macros.newTiddler.title);
	while (title && store.tiddlerExists(title) && !confirm(config.messages.overwriteWarning.format([title])))
		title=prompt(this.titleMsg,config.macros.newTiddler.title);
	if (!title || !title.trim().length) return; // cancelled by user
	f.dirty=false; // suppress unneeded confirmation message
	this.set(id,title);
}

config.macros.tidIDE.remove=function(id) {
	var place=document.getElementById(id+"_editorpanel"); if (!place) return;
	var f=document.getElementById(id+"_editorform");
	if (!f.current.length) return;
	if (!store.tiddlerExists(f.current) && store.isShadowTiddler(f.current)) { alert(this.isShadowMsg.format([f.current])); return; }
	if (config.options.chkConfirmDelete && !confirm(config.commands.deleteTiddler.warning.format([f.current]))) return;
	if (store.tiddlerExists(f.current)) {
		story.closeTiddler(f.current);
		store.removeTiddler(f.current);
		store.setDirty(true);
		if(config.options.chkAutoSave) saveChanges();
	}
	f.tiddlers.options[f.tiddlers.selectedIndex]=null; // remove item from list
	f.dirty=false; // suppress unneeded confirmation message
	this.set(id,""); // clear form controls
}

config.macros.tidIDE.save=function(id,saveAs) {
	var place=document.getElementById(id+"_editorpanel"); if (!place) return;
	var f=document.getElementById(id+"_editorform");
	var title=f.current;
	if (!title || !title.trim().length || saveAs) { // get a new title
		title=prompt(this.titleMsg,config.macros.newTiddler.title);
		while (title && store.tiddlerExists(title) && !confirm(config.messages.overwriteWarning.format([title])))
			title=prompt(this.titleMsg,config.macros.newTiddler.title);
		if (!title || !title.trim().length) return; // cancelled by user
		f.tiddlers.options[f.tiddlers.options.length]=new Option(title,title,false,true); // add item to list
		f.current=title;
	}
	var author=config.options.txtUserName;
	var mdate=new Date();
	var content=f.content.value;
	var tags=f.tags.value;
	var tiddler=store.saveTiddler(title,title,content,author,mdate,tags);
	if (f.minoredits.checked) {
		var author=f.author.value;
		var mdate=new Date(f.modified.value);
		var cdate=new Date(f.created.value);
		tiddler.assign(null,null,author,mdate,null,cdate);
	}
	store.setDirty(true);
	if(config.options.chkAutoSave) saveChanges();
	story.refreshTiddler(title,null,true);
	f.dirty=false;
}
//}}}

// // HTML DEFINITIONS
//{{{
config.macros.tidIDE.html = { };
config.macros.tidIDE.html.framework = " \
	<html> %version% <form style='display:inline;margin:0;padding:0;'>%selector%</form> %panels% </html> \
";
//}}}
//{{{
config.macros.tidIDE.html.editorchk = " \
	<input type=checkbox name=editor \
		style='display:inline;width:auto;margin:1px;' \
		title='add/delete/modify tiddlers' %showpanel% \
		onclick='document.getElementById(\"%id%_editorpanel\").style.display=this.checked?\"block\":\"none\";'>%toolname% \
";
config.macros.tidIDE.html.toolschk = " \
	<input type=checkbox name=tools \
		style='display:inline;width:auto;margin:1px;' \
		title='' %showpanel% \
		onclick='document.getElementById(\"%id%_%toolid%_panel\").style.display=this.checked?\"block\":\"none\"; \
			if (this.checked) config.macros.tidIDE.loadPanel(\"%id%\",\"%toolid%\");'>%toolname% \
";
//}}}
//{{{
config.macros.tidIDE.html.toolspanel = " \
	<div id='%id%_%toolid%_panel' style='display:%showpanel%;margin:0;margin-top:0.5em'> \
	</div> \
";
//}}}
/***
//{{{
!editorPanel
<div id='%id%_editorpanel' style='display:%showpanel%;margin:0;margin-top:0.5em'>
<form id='%id%_editorform' style='display:inline;margin:0;padding:0;'>

<!-- tiddler editor list and buttons -->
<select size=1 name=tiddlers style='display:inline;width:44%;'
	onchange='config.macros.tidIDE.set("%id%",this.value); this.value=this.form.current;'>
<option value=''>select a tiddler...</option>
%tiddlerlist%
</select><!--

--><input name=add type=button style='display:inline;width:8%'
	value='new' title='create a new tiddler'
	onclick='config.macros.tidIDE.add("%id%")' %disabled%><!--
--><input name=remove type=button style='display:inline;width:8%'
	value='remove' title='delete this tiddler'
	onclick='config.macros.tidIDE.remove("%id%")' %disabled%><!--
--><input name=save type=button style='display:inline;width:8%'
	value='save' title='save changes to this tiddler'
	onclick='config.macros.tidIDE.save("%id%")' %disabled%><!--
--><input name=saveas type=button style='display:inline;width:8%'
	value='save as' title='save changes to a new tiddler'
	onclick='config.macros.tidIDE.save("%id%",true)' %disabled%><!--
--><input name=view type=button style='display:inline;width:8%'
	value='open' title='open this tiddler for regular viewing'
	onclick='if (!this.form.current.length) return;	story.displayTiddler(null,this.form.current)'><!--
--><input name=run type=button style='display:inline;width:8%'
	value='run' title='evaluate this tiddler as a javascript "systemConfig" plugin'
	onclick='if (!confirm(config.macros.tidIDE.evalMsg.format([this.form.current]))) return false;
		try { window.eval(this.form.content.value); displayMessage(config.macros.tidIDE.evalCompletedMsg); }
		catch(e) { displayMessage(config.messages.pluginError.format([err])); }'><!--
--><input name=previewbutton type=button style='display:inline;width:8%;'
	value='preview' title='show "live" preview display'
	onclick='if (!config.macros.preview) { alert("Please install PreviewPlugin"); return false; }
		this.form.preview.checked=!this.form.preview.checked;
		document.getElementById("%id%_previewpanel").style.display=this.form.preview.checked?"block":"none";
		if (this.form.freeze) this.form.freeze.checked=!this.form.preview.checked;
		if (this.form.preview.checked) config.macros.preview.render(this.form.content.id,this.form.content.getAttribute("previewid"));'><!--

hidden field for preview show/hide state:
--><input name=preview type=checkbox style='display:none;'>

<!-- tiddler content edit -->
<div><textarea id='%id%_content' name='content' edit='text' cols=60 rows=%maxrows%
	style='width:100%;'
	onkeyup='var f=this.form; f.dirty=true; f.size.value=this.value.length+" bytes";'></textarea></div>

<!-- tag edit and droplist -->
<table width='100%' style='border:0;padding:0;margin:0'><tr style='border:0;padding:0;margin:0'>
<td style='border:0;padding:0;margin:0'>
	<input type=text name=tags edit='tags' size=60 style='width:100%;' value=''
		onchange='this.form.dirty=true' %disabled%>
</td><td width='1' style='border:0;padding:0;margin:0;'>
	<select size=1 name=taglist
		onchange='this.form.dirty=true; this.form.tags.value+=" "+this.value' %disabled%>
	<option value=''>select tags...</option>
	%taglist%
	</select>
</td></tr></table>

<!-- created/modified dates, author, current tiddler size -->
<div style='float:right;'>
	created <input type=text name=created size=15
		style='display:inline;;text-align:center;padding:0;' value=''
		onchange='this.form.dirty=true' %minoredits%>
	modified <input type=text name=modified size=15
		style='display:inline;text-align:center;padding:0;' value=''
		onchange='this.form.dirty=true;' %minoredits%>
	by <input type=text name=author size=15
		style='display:inline;padding:0;' value=''
		onfocus='this.select()' onchange='this.form.dirty=true' %minoredits%>
	<input type=text name=size size=10
		style='display:inline;text-align:center;padding:0;' value=''
		onfocus='this.blur()' onkeydown='return false' DISABLED>
</div>

<!-- toggles: read-only, minor edit -->
<span style='white-space:nowrap'>
<input type=checkbox name=readonly
	style='display:inline;width:auto;margin:1px;' %readonlychk%
	title='do not allow tiddler changes to be saved'
	onclick='readOnly=config.options.chkHttpReadOnly=this.checked;saveOptionCookie("chkHttpReadOnly");
		var f=this.form; f.minoredits.disabled=f.tags.disabled=f.taglist.disabled=this.checked;
		f.add.disabled=f.remove.disabled=f.save.disabled=f.saveas.disabled=this.checked;
		f.created.disabled=f.modified.disabled=f.author.disabled=this.checked||!f.minoredits.checked;'>readonly
<input type=checkbox name=minoredits
	style='display:inline;width:auto;margin:1px;' %disabled% %minorchk%
	title='check: save datestamps/author as entered, uncheck: auto-update modified/author'
	onclick='this.form.created.disabled=this.form.modified.disabled=this.form.author.disabled=!this.checked;
		config.options.chkForceMinorUpdate=this.checked;saveOptionCookie("chkForceMinorUpdate");'>minor edits
</span>

<!-- tiddler preview display -->
<div id='%id%_previewpanel' style='display:none;white-space:nowrap'></div>
!end
//}}}
***/
 
|Name|TidIDEPluginInfo|
|Source|http://www.TiddlyTools.com/#TidIDEPlugin|
|Documentation|http://www.TiddlyTools.com/#TidIDEPluginInfo|
|Version|1.8.4|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|documentation|
|Description|documentation for TidIDEPlugin|
~TidIDE (//prounounced "Tie Dyed"//) - ''Tid''dlyWiki ''I''ntegrated ''D''evelopment ''E''nvironment - lets you define a set of checkboxes to toggle a stack of 'tool panels' containing tools for TiddlyWiki authors to use when creating and debugging their TiddlyWiki documents.  Each tool is defined by a separate tiddler, allowing you to define any convenient set of tools simply by adding/removing tiddler references from the {{{<<tidIDE...>>}}} macro call.

In addition to presenting checkboxes/tool panels that are defined in separate tiddlers, the {{{<<tidIDE>>}}} macro can invoke an optional built-in "editor panel" that presents an alternative tiddler editor to create, modify, and manage the tiddlers in your document... and, if you have also installed [[PreviewPlugin]], the editor can automatically display a ''//formatted preview//'' of the current tiddler content that is updated ''live, key-by-key'' while you edit the tiddler source.
!!!!!Usage
<<<
Syntax:
{{{
<<tidIDE id:xyz TiddlerName ...>>
<<tidIDE id:xyz [[checkbox text|TiddlerName]] ...>>
<<tidIDE id:xyz edit ... >>
<<tidIDE id:xyz edit:here ... >>
<<tidIDE id:xyz edit:TidderName ...>>
}}}
where:
* ''id'' - assign a unique ID to this instance of TidIDE.  (default id=current tiddler title or "" if not in a tiddler)
* ''{{{TidderName}}}'' or ''{{{[[checkbox text|TiddlerName]]}}}'' will include the custom tool panel content defined in TiddlerName (and a corresponding labelled checkbox to toggle its display)
* ''edit'' includes tiddler editor/previewer.
**''edit:here'' automatically sets the editor to show the current tiddler contents (if in a tiddler)
**''edit:tiddlertitle'' automatically sets the editor to show the specified tiddler contents
* all parameters are optional.  The default panel is "edit:here".
* panel parameters preceded by a "+" are displayed by default.  If only one panel specified in the parameters, it is automatically displayed, even if the "+" is omitted.
<<<
!!!!!Example
<<<
{{{<<tidIDE id:example SystemInfo TiddlerTweaker +edit:GettingStarted>>}}}
{{smallform{<<tidIDE id:example SystemInfo TiddlerTweaker +edit:GettingStarted>>}}}
<<<
!!!!!Using the built-in TidIDE editor
<<<
The editor includes a droplist of all tiddlers in the document, sorted alpha-numerically by tiddler title.  Shadow tiddlers that have not been customized are added to the end of this list and marked with "(shadow)".  Next to the droplist are several buttons:
* ''new'' prompts for a new tiddler title and begins a new editing session
* ''remove'' deletes an existing tiddler (note: shadow tiddlers cannot be removed)
* ''save'' saves changes to the tiddler currently being edited
* ''save as'' saves changes using a new tiddler title
* ''open'' opens the tiddler in the normal ~TiddlyWiki display area
* ''run'' invokes the tiddler as if it was a plugin (i.e., containing javascript code)
* ''preview'' toggles display of the live, key-by-key preview (when [[PreviewPlugin]] is installed)
If a tiddlername was not specified in the macro, select a tiddler from the droplist (or press ''add'') to begin editing.  Once a tiddler has been loaded into the editor, you can change it's content, enter or select tags.
!!!!!minor edits
Normally, when you save changes to a tiddler, the created/modified dates and tiddler author are automatically updated.  However, it is sometimes useful to make small changes to a tiddler without automatically updating the date/author information.  Select the ''minor edits'' checkbox to prevent those values from being //automatically// changed.  In addition, this enables the date/author edit fields which allows you to //manually// 'back date' a tiddler or change the author to another name.  When the tiddler is saved, the date/author values shown in the edit fields will be used.
!!!!!using the previewer
When [[PreviewPlugin]] is installed, you can use the TidIDE editor's ''preview'' button to toggle the preview display area that shows you what your tiddler changes will look like, //before// committing to those changes.  Please refer to the documentation in [[PreviewPlugin]] for more information.
<<<
!!!!!Revisions
<<<
2009.08.27 1.8.4 added 'tidIDEPanel' classname to container element (for custom CSS)
2008.04.24 1.8.3 fixed 'run' button onclick handler
2007.12.21 1.8.1 added txtTidIDEMaxEditRows option as custom override for standard core txtMaxEditRows setting
2007.09.27 1.8.0 split preview functionality into separate stand-alone plugin (see [[PreviewPlugin]]).  Moved {{{<<DOMViewer>>}}} macro definition to separate plugin (see [[DOMViewerPlugin]]).  Replicated ''run'' button functionality in stand-along plugin (see [[RunTiddlerPlugin]]). Major re-write of documentation
2007.09.13 1.7.1 removed errant trailing comma from config.macros.tidIDE object definition (fixes IE error)
2007.09.09 1.7.0 split systemInfo into separate plugin (see [[SystemInfoPlugin]])
2007.09.06 1.6.3 in handler(), when using tiddler title as default instance ID, replace spaces with underscores to ensure generated form control ID's don't have embedded spaces.
2007.09.03 1.6.2 in loadPanel(), use store.getTiddlerText() to permit use of shadow tiddlers as custom panels
2006.12.09 1.6.1 in handler(), allow non-existing tiddler title when processing "edit:title" param
so that new tiddler (or journal) can be created directly from newTiddler, newJournal, or tidIDE macro (without pressing "new" button).  Also, set 'edit=text' attribute on text area field so that default content can be initialized from "text:xxx" parameter specified in newTiddler/newJournal macro.
2006.11.28 1.6.0 added font and size params to set CSS for form controls in editor and system info panels
2006.09.28 1.5.8 use separate form ID and definition for each panel (as well as checkbox 'selector' form), so that forms in custom panels don't conflict with each other.
2006.08.27 1.5.7 in handler(), corrected initial display setting for custom 'toolspanel' when '+' prefix has been used for 'defOpen'
2006.08.15 1.5.6 in handler(), supress header/selectors if only one panel to display.  Also, init system_panel as needed.
2006.08.04 1.5.5 in handler(), fix construction of tiddler list to permit use of apostrophes (') in tiddler names.
2006.05.22 1.5.4 in setsys(), remove "(cookie)" prefix from selected item text when setting cookie name (was preventing saving of cookie values)
2006.05.17 1.5.3 in setsys(), call saveOptionsCookie().  Also, set tiddler editor textarea height (%maxrows%) using config.options.txtMaxEditRows
2006.04.30 1.5.2 documentation update
2006.04.30 1.5.1 in save(), when performing "save as" behavior, set current tiddler title (f.current) to new title
2006.04.24 1.5.0 added macro parameters to dynamically configure and assemble HTML for IDE panels.  Supports multiple custom panels loaded from tiddlers and {{{[[label|tiddlername]]}}}
2006.04.24 1.4.6 layout adjustments: move system panel above editor panel and move config setting controls to top of system panel
2006.04.23 1.4.5 fix HTML so that click on "readonly" checkbox won't change "minor edits" option value.
2006.04.23 1.4.4 in render(), strip carriage returns (\r) that are added by IE's textarea control.  Fixes errors in wikify() of 'block-mode' syntax.  Also, defer rendering HTML and DOM preview displays until those options are checked and still more code cleanup
2006.04.23 1.4.3 init "minor edits" checkbox state from config.options.chkForceMinorEdits value
2006.04.23 1.4.2 added "TidIDE v#.#.#: " title in front of subsystem checkboxes.
2006.04.23 1.4.1 added 'readonly' checkbox and handling to editor.
2006.04.23 1.4.0 implemented 'minor edits' logic, including use of TW AdvancedOptions setting.  Replaced separate MDY date input fields with date/time text input fields (using formatted date input).
2006.04.22 1.3.2 Layout changes:  Added editor/system/tools "subsystem" checkboxes at top of panel.  Added automatic read-only notice.  Moved tools_panel to bottom.  Added 'minor edits' checkbox (handler not yet implemented).
2006.04.22 1.3.1 assorted code cleanup and optimizations
2006.04.22 1.3.0 added "tools" section via custom-defined TidIDETools tiddler content
2006.04.22 1.2.2 corrected 'wrap' and 'white-space' CSS for system viewer textarea control so that IE preserves newlines.
2006.04.22 1.2.1 added checkbox indicators in options droplist.  Allows easy preview of boolean state value for chk* options.
2006.04.22 1.2.0 added options droplist to "system" display and supporting setsys() function to update internal config.options.* values
layout adjustments: consolidate some buttons, general tweaks for spacing, sizes, etc.
2006.04.21 1.1.1 migrated remaining functionality from ToolkitPlugin (now obsolete).
2006.04.21 1.1.0 added "system" display and supporting functions
2006.04.21 1.0.1 added formatHTML() for better HTML display in preview
2006.04.20 1.0.0 4:20:00pm official release... renamed from ~TiddlerEditorPlugin to TidIDEPlugin.  (pronounced "Tie Dyed"... dude!)
2006.04.20 0.9.9 added "run" button to dynamically load systemConfig plugins (with warning/confirmation)
2006.04.20 0.9.8 layout adjustments for narrow displays
2006.04.20 0.9.7 added HTML viewer to preview display
2006.04.20 0.9.6 added DOM viewer to preview display
2006.04.19 0.9.5 improved save() handler so saving 'unnamed' edit does fallback to 'save as' prompt for tiddler name
2006.04.19 0.9.4 added 'preview status' display field and refresh button.  Currently shows preview rendering time and autofreeze notice, if any.
2006.04.19 0.9.3 correct IE object error by explicitly using "window." scope when referencing addKeyDownHandlers() function definition
2006.04.18 0.9.2 if TextAreaPlugin is installed, call addKeyDownHandlers() for extended ctrl-F/G and TAB keystrokes in textarea
2006.04.18 0.9.1 "save as" now presents an "overwriteWarning" message box instead of always rejecting existing tiddler titles
2006.04.18 0.9.0 added "save as".  Use TW standard text for new tiddler title and default text
2006.04.18 0.8.5 added "display:inline" to input elements to prevent unwanted line breaks between controls when macro is used in EditTemplate definitions
2006.04.18 0.8.4 added cookie for 'auto-freeze' time limit.  Also, added more documentation.
2006.04.17 0.8.3 added timing wrapper around preview wikify().  Automatically freeze preview display if tiddler rendering exceeds time limit
2006.04.17 0.8.2 more code cleanup for better 'dirty' flag handling
2006.04.17 0.8.1 show/hide freeze checkbox when toggling preview display.  Also, code cleanup for better 'multiple instance' definition
2006.04.17 0.8.0 added "freeze" checkbox to toggle 'live update' of preview display.  Also, layout/CSS adjustments for better appearance in IE
2006.04.16 0.7.1 correct month number offset (was 0-11 instead of 1-12)
2006.04.16 0.7.0 added support for 'dirty' flag, read-only mode and improved alert/confirm/prompt handling
2006.04.16 0.6.0 created "add/remove" functions.  Added handling to trigger autoSave() if option is set.
2006.04.15 0.5.1 move 'save' logic to separate function, and added handling to create a 'real' tiddler when saving a shadow
2006.04.15 0.5.0 Initial ALPHA release. Converted from inline script.
<<<
/***
|Name|TiddlerIconsPlugin|
|Source|http://www.TiddlyTools.com/#TiddlerIconsPlugin|
|Version|2.1.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|display icons next to tiddler title, based on tiddler's attributes (tags, fields, slices, etc)|
!!!!!Usage
<<<
{{{<<tiddlerIcons>>}}} - shows icons for the current tiddler
or
{{{<<tiddlerIcons =TiddlerName>>}}} - shows icons for the specified tiddler
or
{{{<<tiddlerIcons iconID>>}}} - shows a specific icon
<<<
!!!!!Examples
<<<
{{{
icons for current tiddler: <<tiddlerIcons>>
}}}
icons for current tiddler: <<tiddlerIcons>>
{{{
icons for [[Welcome]] tiddler: <<tiddlerIcons =Welcome>>
}}}
icons for [[Welcome]] tiddler: <<tiddlerIcons =Welcome>>
{{{
All icons:
<<tiddlerIcons recent>> <<tiddlerIcons changed>> <<tiddlerIcons unsaved>> <<tiddlerIcons Trash>>
<<tiddlerIcons tag>> <<tiddlerIcons core>> <<tiddlerIcons systemConfig>> <<tiddlerIcons CSS>>
<<tiddlerIcons html>> <<tiddlerIcons template>> <<tiddlerIcons script>> <<tiddlerIcons attachment>>
<<tiddlerIcons settings>> <<tiddlerIcons pluginInfo>> <<tiddlerIcons faq>> <<tiddlerIcons task>>
}}}
All icons:
<<tiddlerIcons recent>> <<tiddlerIcons changed>> <<tiddlerIcons unsaved>> <<tiddlerIcons Trash>> <<tiddlerIcons tag>> <<tiddlerIcons core>> <<tiddlerIcons systemConfig>> <<tiddlerIcons CSS>> <<tiddlerIcons html>> <<tiddlerIcons template>> <<tiddlerIcons script>> <<tiddlerIcons attachment>> <<tiddlerIcons settings>> <<tiddlerIcons pluginInfo>> <<tiddlerIcons faq>> <<tiddlerIcons task>>
<<<
!!!!!Configuration
<<<
You can add extra icons definitions based on matching tag values.  First, import or create a tiddler called [[TiddlerIconsPluginConfig]] and tag it with<<tag systemConfig>>.  Then, in that tiddler, use the following code format to //merge// your additional icon definitions into the default {{{config.macros.tiddlerIcons.map}}} object.
{{{
merge(config.macros.tiddlerIcons.map,{
	tagvalue: ["tooltip","imagefile"],
	tagvalue: ["tooltip","imagefile"],
	...
	tagvalue: ["tooltip","imagefile"]   // note: no comma after last definition
}
}}}
<<<
!!!!!Revisions
<<<
2008.10.02 [2.1.0] added "=TiddlerName" param (shows icons for specified tiddler)
2007.08.01 [2.0.0] converted from inline script
2007.05.28 [1.0.0] initial release (as inline script)
<<<
!!!!!Code
***/
//{{{
version.extensions.TiddlerIconsPlugin= {major: 2, minor: 1, revision: 0, date: new Date(2008,10,2)};
config.macros.tiddlerIcons = {
	unknown: "unknown tiddler icon: %0",
	map: {
		recent: ["this tiddler was UPDATED within the last 10 days","asterisk_yellow.png"],
		changed: ["this tiddler was UPDATED after your last visit","star.png"],
		unsaved: ["this tiddler has UNSAVED CHANGES","exclamation.png"],
		tag: ["this is a TAG tiddler","tag_blue.png"],
		html: ["this is an HTML MARKUP tiddler","html.png"]
	},
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		var img="[img[%0|%1]]";
		var imgs=[]; // collected set of applicable images
		var p=params[0]; // abbrev

		// if icon keyword was supplied, just show one icon and exit.
		if (p&&p.substr(0,1)!="=") {
			wikify(this.map[p]?img.format(this.map[p]):this.unknown.format([p]),place);
			return;
		}

		// if TiddlerName was supplied, use that tiddler, otherwise use current tiddler
		var here=story.findContainingTiddler(place);
		if (!p && !here) return; // not in a tiddler
		var title=p?p.substr(1):here.getAttribute('tiddler');
		var tid=store.getTiddler(title); if (!tid) return; // tiddler not found

		// add 'tag' icon if this tiddler IS a tag
		var tags=store.getTags();
		for (i=0;i<tags.length;i++) if (tags[i][0]==title) imgs.push(img.format(this.map["tag"]));
		if (!tid) { wikify(imgs.join(""),place); return; }

		// add 'unsaved', 'changed', or 'recent' icon based on tiddler vs. document date
		// (uses config.options.lastSaved, updated by [[UnsavedChangesPlugin]])
		if (tid.modified > (config.options.lastSaved?config.options.lastSaved:document.lastModified))
			imgs.push(img.format(this.map["unsaved"]));
		else {
			// add 'changed' icon if tiddler has been modified since last visit
			// (uses config.lastVisit, updated by [[VisitCounterPlugin]])
			// truncate seconds from last visit timestamp for comparison with tiddler modification timestamp
			if (config.lastVisit)
				var last=new Date((new Date(config.lastVisit).getTime())-(new Date(config.lastVisit).getSeconds()*1000));
			if (tid.modified >= last)
				imgs.push(img.format(this.map["changed"]));
			else if (tid.modified >= (new Date()).getTime()-86400000*10)
				imgs.push(img.format(this.map["recent"])); // add 'recent' icon if tiddler has been modified in last 10 days
		}
		if (title.substr(0,6)=="Markup")
			imgs.push(img.format(this.map["html"]));

		// add 'type' icons based on tag(s)... see TiddlerIconsPluginConfig for icon map definitions
		// sort tags for consistent icon display order 
		var tags=[]; for (i=0;i<tid.tags.length;i++) tags.push(tid.tags[i]); tags.sort();
		for (var t=0; t<tags.length; t++)
			if (this.map[tags[t]]) imgs.push(img.format(this.map[tags[t]]));
		wikify(imgs.join(""),place);
	}
};
//}}}
/***
|Name|TiddlerIconsPluginConfig|
|Source|http://www.TiddlyTools.com/#TiddlerIconsPluginConfig|
|Version|2.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Requires|TiddlerIconsPlugin|
|Description|configure additional icons for TiddlerIconsPlugin, based on containing tiddler's tags|

!!!!!Usage
<<<
This plugin configuration tiddler can be used to add extra icon definitions, based on matching tag values, using the following code format:
{{{
merge(config.macros.tiddlerIcons.map, {
	tagvalue: ["tooltip","imagefile"],
	tagvalue: ["tooltip","imagefile"],
	...
	tagvalue: ["tooltip","imagefile"]   // note: no comma after last definition
}
}}}
<<<
!!!!!Revisions
<<<
2007.08.01 [2.0.0] converted from inline script
<<<
!!!!!Code
***/
//{{{
merge(config.macros.tiddlerIcons.map, {
	Trash: ["this tiddler has been tagged as TRASH","delete.png"],
	core: ["this is a CUSTOMIZED TiddlyWiki core tiddler","application_add.png"],
	systemConfig: ["this is a PLUGIN tiddler","cog.png"],
	CSS: ["this is a CSS STYLESHEET tiddler","css.png"],
	template: ["this is a TiddlyWiki layout TEMPLATE","layout.png"],
	script: ["this is an INLINE SCRIPT tiddler","script_code.png"],
	attachment: ["this is a binary file ATTACHMENT","disk.png"],
	settings: ["this tiddler contains SETTINGS or DATA used by plugins or core features","wrench.png"],
	pluginInfo: ["this tiddler contains PLUGIN DOCUMENTATION","information.png"],
	TiddlyTools: ["this tiddler contains TIDDLYTOOLS INFORMATION","information.png"],
	faq: ["this tiddler contains a FAQ/HOW-TO article","help.png"],
	bookmark: ["this tiddler contains a BOOKMARK URL","page_link.png"],
	task: ["this is a TASK tiddler","tick.png"]
});
//}}}
/***
|Name|TiddlerPasswordPlugin|
|Source|http://www.TiddlyTools.com/#TiddlerPasswordPlugin|
|Documentation|http://www.TiddlyTools.com/#TiddlerPasswordPluginInfo|
|Version|1.1.3|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|block viewing of tiddler content by prompting for a password before content is displayed|
This plugin blocks viewing of specific tiddler content by prompting for a NON-SECURE, UNENCRYPTED password before the tiddler is displayed.  If the correct password is not entered, the tiddler is automatically closed.  The process does not prevent tiddler content from being viewed directly from the TiddlyWiki source file's storeArea, nor does it encrypt the tiddler content in any way.  Because it is relatively simple to bypass and/or disable the password prompting process, this macro should be thought of as a "latch" rather than a "lock" on a given tiddler.
!!!!!Documentation
> see [[TiddlerPasswordPluginInfo]]
!!!!!Installation Notes
<<<
''As soon as you have installed this plugin, you should change the default admin password in [[TiddlerPasswordPluginConfig]].''  Note: the configuration tiddler is password-protected to prevent the admin password from being viewed (and/or modified) unless the current password is provided.  By default, the admin password is set to "admin".
<<<
!!!!!Revisions
<<<
2008.03.10 [*.*.*] plugin size reduction - documentation moved to [[TiddlerPasswordPluginInfo]]
2007.09.13 [1.1.3] adjusted wording of "cancelMsg" text so it can apply to either view-mode or edit-mode activities, and documented usage in ViewTemplate/EditTemplate.
| Please see [[TiddlerPasswordPluginInfo]] for previous revision details |
2006.12.02 [1.0.0] initial release - converted from GetTiddlerPassword inline script
<<<
!!!!!Code
***/
//{{{
version.extensions.TiddlerPasswordPlugin= {major: 1, minor: 1, revision: 3, date: new Date(2007,9,13)};

config.macros.getTiddlerPassword = {
	msg: "Please enter a password to view '%0'",
	defaultText: "enter password here",
	retryMsg: "'%0' is not the correct password for '%1'.  Please try again:",
	cancelMsg: "Sorry, you cannot access '%0' without a valid password.",
	thanksMsg: "Thank you, your password has been accepted.",
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		var here=story.findContainingTiddler(place); if (!here) return;
		var title=tiddler?tiddler.title:here.getAttribute("tiddler");
		var who=here.getAttribute("logID");
		var userPass=params[0]?params[0]:""; if (userPass=='-') userPass="";
		var msg=params[1]?params[1]:this.msg;
		if (who==userPass||who==this.adminPass) return; // already 'logged in'?
		var who=prompt(msg.format([title]),this.defaultText); // ask for ID
		while (who && who!=userPass && who!=this.adminPass) // not correct ID?
			who=prompt(this.retryMsg.format([who,title]),this.defaultText); // ask again
		if (who==userPass||who==this.adminPass) // correct ID? mark tiddler logged in...
			{ here.setAttribute("logID",who); alert(this.thanksMsg); }
		else // incorrect ID (e.g., entry cancelled by user)...
			{ story.closeTiddler(here.getAttribute("tiddler")); alert(this.cancelMsg.format([title])); }
	}
}
// default admin password (may be overridden in TiddlerPasswordPluginConfig)
if (config.macros.getTiddlerPassword.adminPass==undefined)
	config.macros.getTiddlerPassword.adminPass="admin";
//}}}
// // Tiddler Admin Password Configuration... <<getTiddlerPassword>> /% rest of tiddler will not be displayed without password... %/
//{{{
config.macros.getTiddlerPassword.adminPass="admin";
//}}}
// {{small{NOTE: after changing the password, save-and-reload the document for the change to take effect}}} //
/***
|Name|TiddlerPasswordPlugin|
|Source|http://www.TiddlyTools.com/#TiddlerPasswordPlugin|
|Documentation|http://www.TiddlyTools.com/#TiddlerPasswordPluginInfo|
|Version|1.1.3|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|documentation|
|Description|documentation for TiddlerPasswordPlugin|
This plugin blocks viewing of specific tiddler content by prompting for a NON-SECURE, UNENCRYPTED password before the tiddler is displayed.  If the correct password is not entered, the tiddler is automatically closed.  The process does not prevent tiddler content from being viewed directly from the TiddlyWiki source file's storeArea, nor does it encrypt the tiddler content in any way.  Because it is relatively simple to bypass and/or disable the password prompting process, this macro should be thought of as a "latch" rather than a "lock" on a given tiddler.
!!!!!Usage
<<<
in tiddler content:
>{{{<<getTiddlerPassword>>}}} 
>{{{<<getTiddlerPassword password>>}}}
>{{{<<getTiddlerPassword password "prompt message">>}}}
>{{{<<getTiddlerPassword - "prompt message">>}}}
in ViewTemplate or EditTemplate:
>{{{<span macro='getTiddlerPassword ...'></span>}}}

Place the {{{<<getTiddlerPassword>>}}} or {{{<span macro='getTiddlerPassword ...'></span>}}} macro at the beginning of your tiddler content, ViewTemplate and/or EditTemplate.  The macro prompts for a password until either A) the correct password is entered or B) the user presses the cancel button from the prompt box, in which case the tiddler is automatically closed so it cannot be viewed/edited.  If a valid password is input, it will be remembered only until the user closes the tiddler.  Each time the tiddler is opened, the password must be re-entered.

The optional ''password'' parameter provides a "user-level" password for the tiddler in which the macro occurs.  If no user password is provided, then only the admin-level password (see below) will be accepted.  

By default, the prompt message reads: "Please enter a password to view '%0'" (where the %0 is automatically replaced by the name of the tiddler in which the macro occurs)  To change this text, enter an additional macro parameter, following the user password.
>Note: because the prompt text is likely to contain spaces, you should always enclose it in quotes (or use {{{[[...]]}}} if it contains quotes).  In addition, to enter an alternative prompt without providing a user-level password, use "-" as a //placeholder// for the password parameter.
* You can set a hard-coded admin password (see below) to define a "universal passkey" that will grant access to all tiddlers protected by this script, regardless of the individual password used on each protected tiddler.
* If you embed one or more password-protected tiddlers within another tiddler (by using the {{{<<tiddler TiddlerName>>}}} macro) the user will be prompted to provide the appropriate password for the EACH protected tiddler contained in the tiddler being rendered.
<<<
!!!!!Installation Notes
<<<
''As soon as you have installed this plugin, you should change the default admin password in [[TiddlerPasswordPluginConfig]].''  Note: the configuration tiddler is password-protected to prevent the admin password from being viewed (and/or modified) unless the current password is provided.  By default, the admin password is set to "admin".
<<<
!!!!!Revisions
<<<
2008.03.10 [*.*.*] plugin size reduction - documentation moved to [[TiddlerPasswordPluginInfo]]
2007.09.13 1.1.3 adjusted wording of "cancelMsg" text so it can apply to either view-mode or edit-mode activities, and documented usage in ViewTemplate/EditTemplate.
2007.05.06 1.1.2 changed admin password tiddler name from TiddlerPasswordConfig to TiddlerPasswordPluginConfig so it will be processed AFTER the plugin's default initialization
2007.02.22 1.1.1 updated documentation for using custom prompt text
2007.01.01 1.1.0 added optional param for using custom prompt text 
2006.12.03 1.0.1 handler() uses passed-in 'tiddler.title' (if any), so that title of included protected tiddlers can be correctly displayed (instead of showng title of containing tiddler)
2006.12.02 1.0.0 initial release - converted from GetTiddlerPassword inline script
<<<
/***
|Name|TiddlerTweakerPlugin|
|Source|http://www.TiddlyTools.com/#TiddlerTweakerPlugin|
|Version|2.4.5|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|select multiple tiddlers and modify author, created, modified and/or tag values|
~TiddlerTweaker is a 'power tool' for TiddlyWiki authors.  Select multiple tiddlers from a listbox and 'bulk modify' the creator, author, created, modified and/or tag values of those tiddlers using a compact set of form fields.  The values you enter into the fields simultaneously overwrite the existing values in all tiddlers you have selected.
!!!!!Usage
<<<
{{{<<tiddlerTweaker>>}}}
{{smallform{<<tiddlerTweaker>>}}}
By default, any tags you enter into the TiddlerTweaker will //replace// the existing tags in all the tiddlers you have selected.  However, you can also use TiddlerTweaker to quickly filter specified tags from the selected tiddlers, while leaving any other tags assigned to those tiddlers unchanged:
>Any tag preceded by a '+' (plus) or '-' (minus), will be added or removed from the existing tags //instead of replacing the entire tag definition// of each tiddler (e.g., enter '-excludeLists' to remove that tag from all selected tiddlers.  When using this syntax, care should be taken to ensure that //every// tag is preceded by '+' or '-', to avoid inadvertently overwriting any other existing tags on the selected tiddlers.  (note: the '+' or '-' prefix on each tag value is NOT part of the tag value, and is only used by TiddlerTweaker to control how that tag value is processed)
Important Notes:
* TiddlerTweaker is a 'power user' tool that can make changes to many tiddlers at once.  ''You should always have a recent backup of your document (or 'save changes' just *before* tweaking the tiddlers), just in case you accidentally 'shoot yourself in the foot'.''
* The date and author information on any tiddlers you tweak will ONLY be updated if the corresponding checkboxes have been selected.  As a general rule, after using TiddlerTweaker, always ''//remember to save your document//'' when you are done, even though the tiddler timeline tab may not show any recently modified tiddlers.
* Selecting and updating all tiddlers in a document can take a while.  Your browser may warn about an 'unresponsive script'.  Usually, if you allow it to continue, it should complete the processing... eventually.  Nonetheless, be sure to save your work before you begin tweaking lots of tiddlers, just in case something does get stuck.
<<<
!!!!!Revisions
<<<
2011.01.21 2.4.5 auto-selection: use "-" for untagged tiddlers.  Also, added 'opened', 'invert'
2009.09.15 2.4.4 added 'edit' button. moved html definition to separate section
2009.09.13 2.4.3 in settiddlers(), convert backslashed chars (\n\b\s\t) in replacement text
2009.06.26 2.4.2 only add brackets around tags containing spaces
2009.06.22 2.4.1 in setFields(), add brackets around all tags shown tweaker edit field
2009.03.30 2.4.0 added 'sort by modifier'
2009.01.22 2.3.0 added support for text pattern find/replace
2008.10.27 2.2.3 in setTiddlers(), fixed Safari bug by replacing static Array.concat(...) with new Array().concat(...)
2008.09.07 2.2.2 added removeCookie() function for compatibility with [[CookieManagerPlugin]]
2008.05.12 2.2.1 replace built-in backstage tweak task with tiddler tweaker control panel (moved from BackstageTweaks)
2008.01.13 2.2.0 added 'auto-selection' links: all, changed, tags, title, text
2007.12.26 2.1.0 added support for managing 'creator' custom field (see [[CoreTweaks]])
2007.11.01 2.0.3 added config.options.txtTweakerSortBy for cookie-based persistence of list display order preference setting.
2007.09.28 2.0.2 in settiddlers() and deltiddlers(), added suspend/resume notification handling (improves performance when operating on multiple tiddlers)
2007.08.03 2.0.1 added shadow definition for [[TiddlerTweaker]] tiddler for use as parameter references with {{{<<tiddler>>, <<slider>> or <<tabs>>}}} macros.
2007.08.03 2.0.0 converted from inline script
2006.01.01 1.0.0 initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.TiddlerTweakerPlugin= {major: 2, minor: 4, revision: 5, date: new Date(2011,1,21)};

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

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

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

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

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

%/<<tiddler HideTiddlerTags>>{{small smallform{
<html><nowiki>
<form style='display:inline;white-space:nowrap;'>
<table class='borderless' style='width:100%'><tr><td style='width:33%'>
	search pattern:<br>
	<input name=pattern style='width:97%' value='' title='enter search pattern'>
</td><td style='width:33%'>
	section (blank=search whole tiddlers):<br>
	<input name=section style='width:97%' value='' title='enter section name'>
</td><td style='width:33%'>
	tag filter (blank=all tiddlers):<br>
	<input name=tag     style='width:97%' value='' title='enter tag filter'>
</td><td>
	<br>
	<input type=button style='width:auto' value='find' onclick="
	var f=this.form;
	var target=f.nextSibling; removeChildren(target);
	var pattern='[^\\n]*('+f.pattern.value+')[^\\n]*'
	var section=f.section.value; if (section.length) section='##'+section;
	var re=new RegExp(pattern,'mg');
	var out=[];
	var fmt='#[[%0]]:<br>\x22\x22\x22%1\x22\x22\x22';
	var tids=tag.length?store.getTaggedTiddlers(f.tag.value):store.getTiddlers();
	for (var t=0; t<tids.length; t++) {
		var tid=tids[t].title+section;
		var matches=store.getTiddlerText(tid,'').match(re)||[];
		for (var m=0;m<matches.length;m++)
			out.push(fmt.format([tids[t].title,matches[m]]));
	}
	if (!out.length) out.push('no matches found');
	wikify('<<<\n'+out.join('\n')+'\n<<<\n',target);
"></td></tr></table></form><div></div></html>}}}
/***
|Name|TiddlyLifePlugin|
|Source|http://www.TiddlyTools.com/#TiddlyLifePlugin|
|Documentation|http://www.TiddlyTools.com/#TiddlyLifePlugin|
|Version|1.6.5|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|Cellular Automata: Conway's "Game of Life"|
!!!!!Documentation
<<<
[[TiddlyLife]] is a TiddlyWiki-enabled javascript version of Conway's "Game of Life" cellular automata simulator.  It provides a "life matrix" on which to place cells, run the simulation, and observe the results.  The speed of the simulation is related to the total size of the matrix (i.e., rows X cols): the larger the matrix, the longer it takes to compute each 'generation' of cells.

You can set the number of rows and columns in the matrix, as well as the size of each cell and the color of the cells, grid, and background.  You can use the mouse to click/drag over the grid to add/delete cells (hold shift to add "walls").  The current life matrix can be saved as text in a tiddler and then reloaded later from a popup list of tiddlers tagged with<<tag tiddlyLife>>

Please see Wikipedia for an overview of [[Conway's "Game of Life"|http://en.wikipedia.org/wiki/Conway%27s_Game_of_Life]].
<<<
!!!!!Syntax
<<<
{{{
<<life	cellcolor:... gridcolor:... bgcolor:... wallcolor:...
	cellsize:... gridwidth:... delay:... limit:... stability:...
	autostart nomenu nostats noedit width:... height:... tid:...>>
}}}
where all parameters are optional (default values are shown in parentheses):
*''cellcolor:'' (//green//), ''gridcolor:'' (//#111//), ''bgcolor:'' (//black//) and ''wallcolor:'' (//gray//)<br>are CSS color names or RGB values (e.g.: "black", "blue",  "#fff", "#9af", etc.)
*''cellsize:'' (//1em//), and ''gridwidth:'' (//1px//)<br>are CSS dimensions, including units (e.g., px,em,cm,in)
*''delay:'' (//0//)<br>delay time (in msec) between simulation ticks (a larger number results in a slower simulation, but also leaves more CPU cycles available for other processes)
*''limit:'' (//10000//)<br>automatically stop stimulation after the indicated number of generations (use 0 for no limit)
*''stability:'' (//500//)<br>automatically stop simulation if population count remains stable for the indicated number of generations (use 0 for no limit)
*''autostart'' (//keyword//)<br>when present, causes the simulation to begin running as soon as the macro is rendered
*''nomenu'' (//keyword//)<br>when present, suppresses display of command menu (use with ''autostart'')
*''nostats'' (//keyword//)<br>when present, suppresses display of the current matrix statistics (generation #, population count/min/avg/max, birthrate/deathrate, average age)
*''noedit'' (//keyword//)<br>when present, prevent hand editing of cells in the matrix.  Instead, clicking on the matrix starts/stops the simulation (useful with ''nomenu'' and ''autostart'')
*''width:'' (//30//) and ''height:'' (//30//)<br>are dimensions for an empty life matrix
*''tid:'' (//no default//)<br>specifies a tiddler containing a saved life matrix definition.  note: when using a saved matrix, the width/height are determined by the stored definition and any width/height macro parameters that are present will be ignored.
<<<
!!!!!Examples
<<<
"Multi-cellular organisms" can be constructed by arranging blocks in specific patterns that exhibit emergent behaviors such as movement, symmetry, oscillation and generative abilities.  Two well-known organisms that are [[discussed in the Wikipedia article|http://en.wikipedia.org/wiki/Conway%27s_Game_of_Life]] are ''//gliders//'' and ''//Gosper's glider gun//'':

[[GliderDance]]: many small moving organisms just missing each other!
{{{<<life cellsize:.8em tid:GliderDance>>}}}
<<life cellsize:.8em tid:GliderDance>>
[[GliderGun]]: generates a stream of gliders that hits a wall
{{{<<life cellsize:.6em tid:GliderGun>>}}}
<<life cellsize:.6em tid:GliderGun>>
... and here's an ''empty life matrix'' for you to play with:
{{{<<life>>}}}
<<life>>
<<<
!!!!!Revisions
<<<
2008.10.11 [1.6.5] added 'step' command.  Also, for performance, removed birth/death stats and don't display average age (but //do// calculate it)
2008.10.10 [1.6.0] added birthrate, deathrate, and average age to statistics
2008.10.09 [1.5.0] use //named// params.  changed matrix values: 0==empty, >0==alive, <0==wall, where value=generation # in which cell was created
2008.10.08 [1.4.0] added 'stability' and 'limit' options (replaces 'autostop' checkbox)
2008.10.08 [1.3.0] added optional 'autostart', 'nomenu' and 'nostats' macro params
2008.10.07 [1.2.1] fixed update handling so multiple timers will no longer be created
2008.10.06 [1.2.0] added support for walls (unchanging dead cells) using dead="-", alive="O", wall="#"
2008.10.06 [1.1.1] redraw optimization: 300% speed improvement by setting CSS only when cell state *changes*
2008.10.05 [1.1.0] drag to draw (set/clear) multiple cells, new option controls (rows,cols,cellsize,delay,autostop), popup list for opening saved matrix
2008.10.04 [1.0.0] initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.TiddlyLifePlugin= {major: 1, minor: 6, revision: 5, date: new Date(2008,10,11)};
config.shadowTiddlers.TiddlyLife="<<life>>";
config.macros.life={
//}}}
// // DEFAULTS
//{{{
	cellcolor:	"green",
	cellsize:	"1em",
	gridcolor:	"#111",
	gridwidth:	"1px",
	bgcolor:	"black",
	wallcolor:	"gray",
	width:		30,
	height:		30,
	stability: 	300,
	limit:		5000,
	delay:		0,
//}}}
// // TRANSLATE
//{{{
	lifeTag:	"tiddlyLife",
	titlePrompt:	"Enter a new tiddler title",
	openErr:	"Could not open '%0'",
	limitMsg:	"stopped: completed %0 generations",
	stableMsg:	"stopped: no growth for %0 generations",
	cellEditTip:	"CLICK=set/clear, SHIFT-CLICK=set wall",
	noEditTip:	"CLICK=start/stop simulation",
	startLabel:	"start",
	stopLabel:	"<b>STOP</b>",
	stats:		"gen: <b>%0</b> pop: <b>%1</b> min: <b>%2</b> avg: <b>%3</b> max: <b>%4</b> %5",
	cmds:		"<a href='#' title='start/stop simulation'\
				onclick='return config.macros.life.toggle(\"%0\")'>%1</a> \
			 | <a href='#' title='advance simulation by one generation'\
				onclick='return config.macros.life.step(\"%0\")'>step</a> \
			 | <a href='#' title='reload the starting life matrix'\
				onclick='return config.macros.life.reset(\"%0\")'>reset</a> \
			 | <a href='#' title='clear the life matrix'\
				onclick='return config.macros.life.clear(\"%0\")'>clear</a> \
			 | <a href='#' title='load a life matrix from a tiddler'\
				onclick='return config.macros.life.open(this,event,\"%0\")'>open</a> \
			 | <a href='#' title='save the current life matrix to a tiddler'\
				onclick='return config.macros.life.save(\"%0\")'>save</a> \
			 | <a href='#' title='change simulation option settings'\
				onclick='var s=this.nextSibling.style; var show=s.display==\"none\"; \
					s.display=show?\"block\":\"none\"; \
					return false;'>options</a><span style='display:none'>%2</span>",
	opts:		"delay:<input type='text' title='delay between generations (msec)' \
				value='%1' style='width:4em;font-size:90%;text-align:center;'>\
			 limit:<input type='text' title='automatically stop after N generations (0=no limit)' \
				value='%2' style='width:4em;font-size:90%;text-align:center;'>\
			 stability:<input type='text' title='stop if population count is stable for N generations (0=no limit)'\
				value='%3' style='width:4em;font-size:90%;text-align:center;'><br>\
			 rows:<input type='text' title='matrix height' \
				value='%4' style='width:3em;font-size:90%;text-align:center;'>\
			 cols:<input type='text' title='matrix width' \
				value='%5' style='width:3em;font-size:90%;text-align:center;'>\
			 cells:<input type='text' title='cellsize' \
				value='%6' style='width:3em;font-size:90%;text-align:center;'>\
			 <input type='button' value='OK' style='font-size:90%;' \
				title='change the life matrix dimensions' \
				onclick='var ins=this.parentNode.getElementsByTagName(\"input\"); \
					var t=ins[0].value; var l=ins[1].value; var a=ins[2].value; \
					var h=ins[3].value; var w=ins[4].value; var s=ins[5].value; \
					return config.macros.life.setoptions(\"%0\",w,h,s,t,a,l)'>",
	msgfmt: 	"<br><span title='use \"options\" command to change autostop settings' \
			onclick='this.style.display=\"none\"' \
			style='display:block;position:absolute;padding:0 .5em;cursor:pointer; \
			margin:.5em;color:%1;background-color:%2;border:1px solid %1'>%3</span>",

//}}}
// // GENERAL UTILITIES
//{{{
	empty: function(w,h) { // generate an empty matrix
		var m=[]; for (var r=0; r<h; r++) { m[r]=[]; for (var c=0; c<w; c++) m[r][c]=0; } return m;
	},
	paste: function(row,col,m1,m2) { // copy one matrix into another
		for (var r=row; r<m1.length && r<m2.length; r++)
			for (var c=col; c<m1[r].length && c<m2[r].length; c++)
				m2[r][c]=m1[r][c];
	},
	zeroPad: function(v,m) { // formatting for population stats
		var t=("0000"+v.toString());
		return t.substr(t.length-Math.max(m.toString().length,v.toString().length));
	},
	getValue: function(s) { // cell value from stored matrix symbol
		return s=='O'?1:s=='#'?-1:0;
	},
	getSymbol: function(v) { // stored matrix symbol from cell value
		return v>0?'O':v<0?'#':'-';
	},
	getColor: function(v,d) { // color from cell value
		return v>0?d.cellcolor:v<0?d.wallcolor:'';
	},
	getAge: function(v,d) { // age of a cell or wall
		return v?(d.gen||1)-Math.abs(v):0;
	},
	isAlive: function(v) { // 0 if dead, 1 if alive
		return v>0;
	},
	isWall: function(v) { // 1 if cell is a wall
		return v<0;
	},
	isAncient: function(v,d) { // true if cell age is more than ten times the average age
		return d.avgage>0 && this.getAge(v,d)>10*d.avgage;
	},
//}}}
// // MACRO HANDLER
//{{{
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		var autostart	=params.contains("autostart");
		var nomenu	=params.contains("nomenu");
		var nostats	=params.contains("nostats");
		var noedit	=params.contains("noedit");
		params = paramString.parseParams("anon",null,true,false,false);
		var cellcolor	=getParam(params,"cellcolor",this.cellcolor);
		var wallcolor	=getParam(params,"wallcolor",this.wallcolor);
		var cellsize	=getParam(params,"cellsize",this.cellsize);
		var gridcolor	=getParam(params,"gridcolor",this.gridcolor);
		var gridwidth	=getParam(params,"gridwidth",this.gridwidth);
		var bgcolor	=getParam(params,"bgcolor",this.bgcolor);
		var tid		=getParam(params,"tid",this.tid);
		var w		=getParam(params,"rows",this.width);
		var h		=getParam(params,"cols",this.height);
		var delay	=getParam(params,"delay",this.delay);
		var stability	=getParam(params,"stability",this.stability);
		var limit	=getParam(params,"limit",this.limit);
		var m=this.load(tid); if (!m) var m=this.empty(w,h);
		var id="tiddlyLife_"+new Date().getTime()+Math.random();
		var e=createTiddlyElement(place,"span",id,"tiddlyLife");
		e.data={w:w, h:h, tid:tid, matrix:m, gen:0, stopped:!autostart,
			gencount:0, stable:0, total:0, birthrate:0, deathrate:0, age:0, 
			cellcolor:cellcolor, wallcolor:wallcolor, gridcolor:gridcolor, bgcolor:bgcolor,
			cellsize:cellsize, gridwidth:gridwidth, delay:delay, stability:stability, limit:limit,
			nostats:nostats, nomenu:nomenu, noedit:noedit };
		this.draw(id); if (autostart) this.go(id);
	},
//}}}
// // COMMAND HANDLERS
//{{{
	toggle: function(id) { // toggle simulation
		var e=document.getElementById(id); if (!e) return; var d=e.data; var m=d.matrix;
		if (d.stopped) this.go(id); else this.stop(id);
		return false;
	},
	go: function(id) { // start simulation and set command text
		var e=document.getElementById(id); if (!e) return; var d=e.data; var m=d.matrix;
		var b=e.getElementsByTagName("a")[0]; if (b) b.innerHTML=this.stopLabel;
		d.stopped=false; d.stable=0; d.gencount=0; clearTimeout(d.timer); this.refresh(id);
		return false;
	},
	stop: function(id) { // stop simulation and set command text
		var e=document.getElementById(id); if (!e) return; var d=e.data; var m=d.matrix;
		var b=e.getElementsByTagName("a")[0]; if (b) b.innerHTML=this.startLabel;
		d.stopped=true; clearTimeout(d.timer);		
		return false;
	},
	reset: function(id) { // reload initial matrix
		var e=document.getElementById(id); if (!e) return; var d=e.data;
		var m=this.load(d.tid); if (!m) var m=this.empty(d.w,d.h);
		this.stop(id); d.matrix=m; d.gen=0; this.draw(id);
		return false;
	},
	clear: function(id) { // load empty matrix
		var e=document.getElementById(id); if (!e) return; var d=e.data;
		var tid=d.tid; d.tid=""; this.reset(id); d.tid=tid;
		return false;
	},
	setoptions: function(id,w,h,s,t,a,l) { // options: width,height,cellsize,delaytime,autostop,limit
		var e=document.getElementById(id); if (!e) return; var d=e.data; var m=d.matrix;
		clearTimeout(d.timer); // stop simulation while changing matrix content
		d.w=w; d.h=h; d.stability=a; d.limit=l; d.cellsize=s; d.delay=t;
		var m2=this.empty(w,h); this.paste(0,0,m,m2); d.matrix=m2; this.draw(id);
		d.min=Math.min(d.min,d.count); d.max=Math.max(d.max,d.count);
		if (!d.stopped) d.timer=setTimeout('config.macros.life.refresh("'+id+'")',d.delay);
		return false;
	},
//}}}
// // I/O HANDLERS
//{{{
	load: function(tid) { // read tiddler into matrix
		var t=store.getTiddlerText(tid); if (!t) return;
		var lines=t.split("\n"); var m=[];
		if (lines[0]=="{{{") lines.shift();
		if (lines[lines.length-1]=="}}}") lines.pop();
		for (var r=0; r<lines.length; r++) { m[r]=[];
			for (var c=0; c<lines[r].length; c++) m[r].push(this.getValue(lines[r].substr(c,1)));
		}
		return m;
	},
	save: function(id) { // write matrix to tiddler
		var e=document.getElementById(id); if (!e) return; var d=e.data; var m=d.matrix;
		var tid=d.tid; var msg=config.messages.overwriteWarning.format([tid]);
		while (!tid||!tid.length ||(store.tiddlerExists(tid)&&!confirm(msg)))
			{ tid=prompt(this.titlePrompt,tid); if (!tid||!tid.length) return false; }
		d.tid=tid;
		var out=[];
		out.push('{{{');
		for (var r=0; r<m.length; r++) { var row='';
			for (var c=0; c<m[r].length; c++) row+=this.getSymbol(m[r][c]);
			out.push(row);
		}
		out.push('}}}');
		var t=store.getTiddler(tid);
		var txt=out.join('\n');
		var who=t&&config.options.chkForceMinorUpdate?t.modifier:config.options.txtUserName;
		var when=t&&config.options.chkForceMinorUpdate?t.modified:new Date();
		var tags=t?t.tags:[]; tags.pushUnique(this.lifeTag);
		var fields=t?t.fields:{};
		store.saveTiddler(tid,tid,txt,who,when,tags,fields);
		story.displayTiddler(null,tid); story.refreshTiddler(tid,null,true);
		return false;
	},
	open: function(here,event,id) { // select from a list of saved matrix tiddlers
		var p=Popup.create(here); if (!p) return false;
		p.style.padding="2px .5em";
		var tids=store.getTaggedTiddlers(this.lifeTag);
		for (var t=0; t<tids.length; t++) {
			var b=createTiddlyButton(createTiddlyElement(p,"li"),tids[t].title,tids[t].title,
				function() {
					var cml=config.macros.life;
					var id=this.getAttribute("id");
					var e=document.getElementById(id); if (!e) return false; var d=e.data;
					var tid=this.getAttribute("tid");
					var m=cml.load(tid);
					if (!m) { displayMessage(this.openErr.format([tid])); return false; }
					cml.stop(id); d.tid=tid; d.matrix=m; d.gen=0; cml.draw(id);
					return false;
				});
			b.setAttribute("id",id);
			b.setAttribute("tid",tids[t].title);
		}
		Popup.show();
		event.cancelBubble=true;if(event.stopPropagation)event.stopPropagation();
		return false;
	},
//}}}
// // EDIT HANDLERS
//{{{
	mousedown: function(here,ev,id,r,c) { // start manual edit
		var e=document.getElementById(id); if (!e) return; var d=e.data; var m=d.matrix;
		d.savedstop=d.stopped; this.stop(id); d.draw=!this.isAlive(m[r][c])?(d.gen||1):0;
		return this.setcell(here,id,r,c,ev&&ev.shiftKey?-(d.gen||1):d.draw);
	},
	mouseover: function(here,ev,id,r,c) { // drag edit
		var e=document.getElementById(id); if (!e) return; var d=e.data; var m=d.matrix;
		if (d.draw!==undefined) this.setcell(here,id,r,c,ev&&ev.shiftKey?-(d.gen||1):d.draw);
		return false;
	},
	mouseup: function(here,ev,id,r,c) { // end manual edit
		var e=document.getElementById(id); if (!e) return; var d=e.data; var m=d.matrix;
		if (d.savedstop!==undefined) d.stopped=d.savedstop; if (!d.stopped) this.go(id);
		d.draw=undefined; d.savedstop=undefined;
		return false;
	},
	setcell: function(here,id,r,c,v) { // set cell content and revise stats display
		var e=document.getElementById(id); if (!e) return; var d=e.data; var m=d.matrix;
		if (m[r][c]==v) return;
		if (this.isAlive(m[r][c]) && !this.isAlive(v)) { d.count--; d.min=Math.min(d.min,d.count); }
		if (!this.isAlive(m[r][c]) && this.isAlive(v)) { d.count++; d.max=Math.max(d.max,d.count); }
		m[r][c]=v; here.style.background=this.getColor(v,d);
		this.showstats(id,'');
		return false;
	},
//}}}
// // RENDER
//{{{
	draw: function(id) { // render entire tiddlyLife container (menu, stats, and table)
		var e=document.getElementById(id); if (!e) return; var d=e.data; var m=d.matrix;
		var out=[]; var count=0; var maxwidth=0;
		var style="border:%0 solid %1;background:%2;height:%3 !important;width:%3; !important";
		var onmousedown=d.noedit?"":"return config.macros.life.mousedown(this,event,'%4',%5,%6);";
		var onmouseover=d.noedit?"":"return config.macros.life.mouseover(this,event,'%4',%5,%6);";
		var onmouseup  =d.noedit?"":"return config.macros.life.mouseup(this,event,'%4',%5,%6);";
		var onclick    =d.noedit?"return config.macros.life.toggle('%4');":"";
		var tip="[%7,%8] "+(d.noedit?this.noEditTip:this.cellEditTip);
		var cell='<td style="margin:0;padding:0;'+style +'" title="'+tip+'" onclick="'+onclick
			+'" onmousedown="'+onmousedown+'" onmouseover="'+onmouseover+'" onmouseup="'+onmouseup+'"></td>';
		out.push('<table style="table-layout:fixed;border-collapse:collapse;'
			+'margin:0;padding:0;border:0;background-color:'+d.bgcolor+'">');
		for (var r=0; r<m.length; r++) {
			if (m[r].length>maxwidth) maxwidth=m[r].length;
			out.push('<tr style="margin:0;padding:0;border:0;">');
			for (var c=0; c<m[r].length; c++) {
				out.push(cell.format([d.gridwidth,d.gridcolor,this.getColor(m[r][c],d),
					d.cellsize,id,r,c,r+1,c+1]));
				count+=this.isAlive(m[r][c]);
			}
			out.push('</tr>');
		}
		out.push('</table>');
		d.count=count;
		if (!d.gen) { d.gencount=d.stable=d.total=d.oldest=d.maxage=d.avgage=0; d.min=d.max=d.avg=count; }
		var hdr=[];
		if (!d.nomenu) hdr.push(this.cmds.format([id,d.stopped?this.startLabel:this.stopLabel,
			this.opts.format([id,d.delay,d.limit,d.stability,m.length,maxwidth,d.cellsize])]));
		if (!d.nostats) hdr.push('<div style="font-size:90%">'
			+this.stats.format([d.gen,d.count,d.min,d.avg,d.max])+'</div>');
		e.innerHTML=hdr.join('')+out.join('');
		return false;
	},
//}}}
// // RUN SIMULATION
//{{{
	refresh: function(id) { // timer-based refresh cycle
		var e=document.getElementById(id); if (!e) return; var d=e.data; var m=d.matrix;
		this.step(id); if (!d.stopped) d.timer=setTimeout('config.macros.life.refresh("'+id+'")',d.delay);
		return false;
	},
	step: function(id) { // calc new matrix, gather stats and display changes
		var e=document.getElementById(id); if (!e) return; var d=e.data; var m=d.matrix;
		// calculate next generation
		var m2=[]; var count=agecount=agetotal=oldest=0; d.gen++; d.gencount++;
		var table=e.getElementsByTagName("table")[0]; if (!table) return;
		var rows=table.getElementsByTagName("tr");
		for (var r=0; r<m.length; r++) {
			m2[r]=[];
			var cells=rows[r].getElementsByTagName("td");
			for (var c=0; c<m[r].length; c++) {
				var v=this.tick(d.gen,m,r,c); // apply Conway's 23/3 rule
				m2[r].push(v);
				var color=this.getColor(v,d);
				if (cells[c].style.backgroundColor!=color)
					cells[c].style.backgroundColor=color;
				if (this.isAlive(v)) {
					var a=this.getAge(v,d);
					if (!this.isAncient(v,d)) { agecount++; agetotal+=a; }
					oldest=Math.max(oldest,a);
					count++;
				}
			}
		}
		d.matrix=m2; // update matrix
		this.calcstats(id,count,agecount,agetotal,oldest); // calculate statistics
		var msg=this.autostop(id); // autostop if conditions apply
		this.showstats(id,msg); // show statistics and message (if any)
		return false;
	},
	tick: function(gen,m,r,c) { // apply Conway's 23/3 rule
		if (this.isWall(m[r][c])) return m[r][c]; // walls don't change
		var prevrow=r>0?r-1:(m.length-1);
		var nextrow=r<m.length-1?r+1:0;
		var prevcol=c>0?c-1:(m[r].length-1);
		var nextcol=c<m[r].length-1?c+1:0;
		var near=this.isAlive(m[prevrow][prevcol]) + this.isAlive(m[prevrow][c]) + this.isAlive(m[prevrow][nextcol])
			+this.isAlive(m[r][prevcol])       + this.isAlive(m[r][nextcol])
			+this.isAlive(m[nextrow][prevcol]) + this.isAlive(m[nextrow][c]) + this.isAlive(m[nextrow][nextcol]);
		if (!this.isAlive(m[r][c])&&near==3) return gen; // birth
		if (this.isAlive(m[r][c])&&near==2||near==3) return m[r][c]; // stay alive
		return 0; // death
	},
	autostop: function(id) { // autostop if run limit reached or no changes for N generations
		var e=document.getElementById(id); if (!e) return; var d=e.data; var m=d.matrix;
		var msg='';
		var limited=d.limit>0 && d.gencount>=d.limit;
		var stabilized=d.stability>0 && d.stable>=d.stability;
		if (limited || stabilized) {
			this.stop(id); 
			msg=stabilized?this.stableMsg.format([d.stability]):this.limitMsg.format([d.limit]);
			msg=this.msgfmt.format([id,d.cellcolor,d.bgcolor,msg]);
		}
		return msg;
	},
	calcstats: function(id,count,agecount,agetotal,oldest) {
		var e=document.getElementById(id); if (!e) return; var d=e.data; var m=d.matrix;
		d.stable+=(count==d.count)?1:-d.stable; // add one or reset to zero
		d.count=count; d.total+=count;
		d.min=Math.min(d.min,count); d.max=Math.max(d.max,count); d.avg=Math.floor(d.total/d.gen);
		d.avgage=agecount?agetotal/agecount:0; d.oldest=oldest; d.maxage=Math.max(d.maxage,oldest);
		return false;
	},
	showstats: function(id,msg) {
		var e=document.getElementById(id); if (!e) return; var d=e.data; var m=d.matrix;
		var stats=e.getElementsByTagName("div")[0];
		if (stats) stats.innerHTML=this.stats.format([d.gen,this.zeroPad(d.count,d.max),d.min,d.avg,d.max,msg]);
		return false;
	}
}
//}}}
midi/stairway_to_heaven.mid
Stairway to Heaven
----
midi/greatgiginthesky.mid
Great Gig in the Sky
----
midi/shineon.mid
Shine On You Crazy Diamond
----
midi/whiter_shade_of_pale.mid
A Whiter Shade of Pale
----
midi/a_day_in_the_life.mid
A Day in the Life
----
midi/help_from_my_friends.mid
Help From My Friends
----
midi/california_dreaming.mid
California Dreaming
----
midi/peanuts.mid
Peanuts
----
midi/ppanther.mid
Pink Panther
----
midi/georgia_on_my_mind2.mid
Georgia on My Mind
----
midi/jingle_bells_jazz.mid
Jingle Bell Jazz
----
midi/GMajorBlues.mid
G Major Blues
----
midi/Justblue.mid
Just Blue
----
midi/Mission_Impossible.mid
Mission Impossible
----
midi/bond.mid
James Bond
----
midi/birdland.mid
Birdland
----
midi/Olympic_Winter_Games.mid
Winter Olympics Fanfare
----
midi/sing_sing_sing.mid
Sing! Sing! Sing!
----
midi/jcycle.mid
J Cycle
----
midi/marslove.mid
Martian Love
----
midi/fly_like_an_eagle.mid
Fly Like an Eagle
----
midi/johnny_b_goode.mid
Johnny B Goode
----
midi/sweet_emotion.mid
Sweet Emotion
----
midi/thewayitis.mid
The Way It Is
----
midi/beeth6-1.mid
Beethoven's 6th: Pastoral
----
midi/eine_kleine_nachtmusik.mid
Eine Kleine Nachtmusik
----
midi/Gmfigaro.mid
Figaro Overture
----
The Sky's The Limit
FNM: The Sky's The Limit (mp3)
----
audio/fnm/030502-5.mp3
FNM: In The Shadows (mp3)
----
audio/fnm/020830-6.mp3
FNM: Good Morning, Elijah (mp3)
----
http://somafm.com/groovesalad.asx
SoMaFM.com - Groove Salad
/***
|Name|TiddlyPodPlugin|
|Source|http://www.TiddlyTools.com/#TiddlyPodPlugin|
|Version|1.4.4|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Requires|TiddlyPodList|
|Description|autoplay music randomly selected from playlist using embedded player|
!!!!!Usage
<<<
{{{
<<tiddlyPod autoplay loop verbose track:... width:... height:... size:... @TiddlerName>>
}}}
where:
* ''autoplay'' / ''noautoplay'' (keyword, default=''autoplay'')<br>the selected item will play immediately, without pressing the PLAY button.
* ''loop'' / ''noloop'' (keyword, default=''noloop'')<br>the current item is repeatedly played until you press the stop button.
* ''verbose'' (keyword, default=//none//)<br>a message will be displayed whenever an item is selected.
* ''track:...'' (number, default=//last played//)<br>the index into the playlist for the initial item to load into the player.  If no item is specified, the last one played is re-loaded (tracked in a browser cookie).  If no cookie exists (i.e., the first time you play after installing, or after clearing cookies, etc.), then the first item in the playlist is used.
* ''width:...'' and ''height:...'' (default=115x15 for QuickTime or, if using Internet Explorer, 90x44 for Windows Media Player)<br>specify a non-default width/height dimensions for the embedded player (using pixels).
* ''size:xxxx'' (default="auto")<br>a fixed height for the playlist popup container itself (using CSS measurement units, e.g., "px", "em", "cm", "in", etc.).  If the items in the list overflow this height, then a scrollbar is automatically added to the popup list.  "auto" shows //all// playlist entries without scrolling, using a variable height popup.
* ''@~TiddlerName'' (default=[[TiddlyPodList]])<br>specifies a tiddler containing the list of items to play.  Entries in the list are separated by "----", and each entry consist of two lines: the first line is the location (or URL) of the media file to be played.  The second line is a title to be displayed when that item is playing.
<<<
!!!!!Examples
<<<
{{{<<tiddlyPod noautoplay loop track:1 @TiddlyPodList>>}}}
<<tiddlyPod noautoplay loop track:1 @TiddlyPodList>>
<<<
!!!!!Revisions
<<<
2008.03.22 [1.4.4] added [[TiddlyPod]] shadow definition.
2008.03.21 [1.4.3] removed {{{pluginspage="http://www.apple.com/quicktime/download/"}}} param from HTML {{{<embed>}}}, so that FireFox (and other browsers) don't //prefer// QuickTime over other installed media players.  ''It is still up to the browser to determine which player to use.''.
2007.11.09 [1.4.2] in handler(), corrected default initialization of chkTiddlyPodAutoPlay and chkTiddlyPodLoopPlay.
2007.06.12 [1.4.1] in play(), don't call removeChildren(), since browser will clean up objects when assignment to innerHTML is made
2007.02.23 [1.4.0] added support for using 'attachment tiddlers' (see AttachFilePlugin) for self-contained playback.  This seems to work well with QuickTime.  Other embedded players may vary in support for the data:// URI.  Note: IE6/7 does NOT support data:// URI.  Attachments should always have local and/or remote fallbacks defined.
2007.02.23 [1.3.1] added support for scrollbar to playlist popup.  Use size:xxx to set the length of the playlist, where 'xxx' is any valid CSS measurement.  Use "auto" to show all playlist items without scrolling.  Also, added popup items for controlling autoplay/loopplay preferences.
2007.02.21 [1.3.0] added playlist popup and rewrote getPod() and play() to use innerHTML instead of wikify().  Eliminates all dependency on InlineJavascriptPlugin when rendering output.
2007.02.20 [1.2.1] added optional 'track:#' parameter to specify initial track, instead of starting with a random track
2007.02.20 [1.2.0] added optional 'loop' parameter to trigger looping playback
2007.02.20 [1.1.0] removed link for "edit playlist" to reduce clutter and provide a 'playback only' interface.  When changing the play list is appropriate, a link to [[TiddlyPodList]] (or any alternative playlist tiddler) can be directly added to surrounding tiddler content as needed.
2007.02.19 [1.0.0] initial release (converted from inline script)
<<<
!!!!!Code
***/
//{{{
version.extensions.TiddlyPodPlugin= {major: 1, minor: 4, revision: 4, date: new Date(2008,3,22)};

config.shadowTiddlers['TiddlyPod']='<<tiddlyPod>>';

config.macros.tiddlyPod= {
	verbose: false, // set to true to display messages
	playlist: "TiddlyPodList", // tiddler containing list of tunes
	size: "auto", // maximum length (using CSS) of playlist to show before adding a scrollbar
	width: config.browser.isIE?90:115, // width of embedded player (IE w/WinMedia vs FireFox w/QuickTime)
	height: config.browser.isIE?44:15, // height of embedded player (IE w/WinMedia vs FireFox w/QuickTime)
	getPlayer: function(src,w,h,auto,loop) {
		var out='';
		out+='<EMBED WIDTH="'+w+'" HEIGHT="'+h+'" ';
		out+='	style="height:'+h+'px;width:'+w+'px;margin:0;padding:0;" ';
		out+='	src="'+src+'" ';
		out+='	autostart="'+(auto?'true':'false')+'" autoplay="'+(auto?'true':'false')+'" ';
		out+='	loop="'+(loop?'true':'false')+'" ';
		out+='	controller="show" volume="100" EnableJavaScript="true" ';
		out+='	showtracker="1" showpositioncontrols="0" showaudiocontrols="0" ';
		out+='	showdisplay="0" showstatusbar="0" showgotobar="0"> ';
		out+='</EMBED>';
		return out;
	},
	getPod: function(playlist,which) {
		var txt=store.getTiddlerText(playlist); if (!txt) return;
		var songs=txt.split("\n----\n");
		var first=0;
		var last=songs.length-1;
		if (which===undefined) which=config.options.txtTiddlyPodNowPlaying;
		if (which<first) which=first; if (which>last) which=last;
		var next=(which-1)+2; if (next>last) next=last;
		var prev=which-1; if (prev<first) prev=first;
		var src=songs[which].split("\n")[0];
		var descr=songs[which].split("\n")[1];

		// if src is a tiddlername, check for attachment
		if (config.macros.attach!=undefined) // if AttachFilePlugin is installed
			if ((tid=store.getTiddler(src))!=null && tid.isTagged("attachment")) // if src is attachment tiddler title
				src=config.macros.attach.getAttachment(src); // replace TiddlerTitle with attachment-expanded src URL

		var out='';
		var tip=config.messages.externalLinkTooltip.format([src]); // use core defined tooltip
		out+='<div><a href="'+src+'" target="_blank" class="button" title="'+tip+'" style="white-space:normal">'+descr+'</a></div>';
		out+=this.getPlayer(src,this.width,this.height,config.options.chkTiddlyPodAutoPlay,config.options.chkTiddlyPodLoopPlay);
		out+='<div class="small">';
		out+='<a href="javascript:;" class="button" title="[first] track '+(first+1)+' - '+songs[first].split("\n")[1]+'" ';
		out+='	onclick="config.macros.tiddlyPod.play(this.parentNode.parentNode,'+first+'); return false;">&lt;&lt;</a>';
		out+='&nbsp;';
		out+='<a href="javascript:;" class="button" title="[previous] track '+(prev+1)+' - '+songs[prev].split("\n")[1]+'" ';
		out+='	onclick="config.macros.tiddlyPod.play(this.parentNode.parentNode,'+prev+'); return false;">&nbsp;&lt;&nbsp;</a>';
		out+='&nbsp;';
		out+='<a href="javascript:;" class="button" title="[playlist]" ';
		out+='	onclick="config.macros.tiddlyPod.showpopup(this,event); return false;">...</a>';
		out+='&nbsp;';
		out+='<a href="javascript:;" class="button" title="[next] track '+(next+1)+' - '+songs[next].split("\n")[1]+'" ';
		out+='	onclick="config.macros.tiddlyPod.play(this.parentNode.parentNode,'+next+'); return false;">&nbsp;&gt;&nbsp;</a>';
		out+='&nbsp;';
		out+='<a href="javascript:;" class="button" title="[last] track '+(last+1)+' - '+songs[last].split("\n")[1]+'" ';
		out+='	onclick="config.macros.tiddlyPod.play(this.parentNode.parentNode,'+last+'); return false;">&gt;&gt;</a>';
		out+='</div>';

		if (this.verbose) displayMessage('now playing... track '+(which+1)+' - "'+descr+'"');
		return out;
	},
	play: function(target,which) {
		if (which==undefined) which=config.options.txtTiddlyPodNowPlaying; // if not specified, use most recently played item
		if (which==undefined) which=0; // default to first item in playlist if no previous item
		target.innerHTML=this.getPod(this.playlist,which);
		config.options.txtTiddlyPodNowPlaying=which;
		saveOptionCookie("txtTiddlyPodNowPlaying");
		return;
	},
	showpopup: function(place,event) {
		var popup=Popup.create(place); if (!popup) return;
		var txt=store.getTiddlerText(this.playlist); if (!txt) return;
		var songs=txt.split("\n----\n");
		config.macros.tiddlyPod.target=place.parentNode.parentNode;
		createTiddlyButton(createTiddlyElement(popup,'li'),
			"play a randomly selected track", "shuffle play",
			function(){
				var t=config.options.chkTiddlyPodAutoPlay;
				config.options.chkTiddlyPodAutoPlay=true; // force autoplay
				config.macros.tiddlyPod.play(config.macros.tiddlyPod.target,Math.floor(Math.random()*songs.length));
				config.options.chkTiddlyPodAutoPlay=t;
				return false;
			});
		createTiddlyElement(popup,"hr");
		createTiddlyButton(createTiddlyElement(popup,'li'),
			(config.options.chkTiddlyPodAutoPlay?"[x]":"[_]")+" auto play",
			"automatically play tune when selected (if off, press PLAY button to start)",
			function(){
				config.options.chkTiddlyPodAutoPlay=!config.options.chkTiddlyPodAutoPlay;
				saveOptionCookie("chkTiddlyPodAutoPlay");
				config.macros.tiddlyPod.play(config.macros.tiddlyPod.target,config.options.txtTiddlyPodNowPlaying);
				return false;
			});
		createTiddlyButton(createTiddlyElement(popup,'li'),
			(config.options.chkTiddlyPodLoopPlay?"[x]":"[_]")+" repeat play",
			"when playback is finished, repeat the current selection again",
			function(){
				config.options.chkTiddlyPodLoopPlay=!config.options.chkTiddlyPodLoopPlay;
				saveOptionCookie("chkTiddlyPodLoopPlay");
				config.macros.tiddlyPod.play(config.macros.tiddlyPod.target,config.options.txtTiddlyPodNowPlaying);
				return false;
			});
		createTiddlyElement(popup,"hr");
		var playlist=createTiddlyElement(popup,"div",null,"fine"); // uses 'fine' CSS class to set font size
		playlist.style.padding="2px"; // room for dotted 'focus' indicator (prevent horizontal scrollbar from appearing)
		playlist.style.height=config.macros.tiddlyPod.size;
		playlist.style.overflow="auto";
		for (var s=0; s<songs.length; s++) {
			var src=songs[s].split("\n")[0];
			var descr=(s+1)+" - "+songs[s].split("\n")[1];
			var a=createTiddlyButton(createTiddlyElement(playlist,'li'), descr, src,
				function(){
					var t=config.options.chkTiddlyPodAutoPlay;
					config.options.chkTiddlyPodAutoPlay=true; // force autoplay
					config.macros.tiddlyPod.play(config.macros.tiddlyPod.target,this.getAttribute("which"));
					config.options.chkTiddlyPodAutoPlay=t;
					return false;
				});
			a.setAttribute("which",s); // song index
			if (s==config.options.txtTiddlyPodNowPlaying) a.style.fontWeight="bold";
		}
		createTiddlyElement(popup,"hr");
		createTiddlyButton(createTiddlyElement(popup,'li'), 'edit playlist...', '',
			function(){story.displayTiddler(null,config.macros.tiddlyPod.playlist,2);return false;});
		Popup.show(popup,false);
		if (!event) var event=window.event;
		if (event) event.cancelBubble = true;
		if (event && event.stopPropagation) event.stopPropagation();
	},
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		if (config.options.chkTiddlyPodAutoPlay==undefined)
			config.options.chkTiddlyPodAutoPlay=true; // default enable auto play
		if (config.options.chkTiddlyPodLoopPlay==undefined)
			config.options.chkTiddlyPodLoopPlay=false; // default disable loop play
		if (config.options.chkTiddlyPodNowPlaying==undefined)
			config.options.chkTiddlyPodNowPlaying=0; // default to first item in playlist
		while (p=params.shift()) {
			if (p=="autoplay")
				config.options.chkTiddlyPodAutoPlay=true; // enable auto play
			if (p=="noautoplay")
				config.options.chkTiddlyPodAutoPlay=false; // disable auto play
			else if (p=="loop")
				config.options.chkTiddlyPodLoopPlay=true; // enable loop play
			else if (p=="noloop")
				config.options.chkTiddlyPodLoopPlay=false; // disable loop play
			else if (p=="verbose")
				this.verbose=true; // enable message display
			else if (p.substr(0,1)=="@")
				this.playlist=p.substr(1); // alternative playlist tiddler 
			else if (p.substr(0,6)=="track:")
				config.options.txtTiddlyPodNowPlaying=p.substr(6)-1; // initial playlist index (0-based, e.g. track #1=index 0)
			else if (p.substr(0,6)=="width:")
				this.width=p.substr(6); // width of embedded player controls
			else if (p.substr(0,7)=="height:")
				this.height=p.substr(7); // height of embedded player controls
			else if (p.substr(0,11)=="size:")
				this.size=p.substr(11); // height of playlist in popup
		}
		this.play(createTiddlyElement(place,"span"),config.options.txtTiddlyPodNowPlaying);
	}
}
//}}}
/%
|''URL:''|http://www.TiddlySpot.com|
|''Description:''|Free on-line hosting for your TiddlyWiki documents|
|''Author:''|DanielBaird SimonBaird|
%/
/%
|''URL:''|http://tiddlystyles.com/|
|''Description:''|Clint's collection of TiddlyWiki creations|
|''Author:''|ClintChecketts|
%/
/%
|''URL:''|http://www.tiddlytools.com/|
|''Description:''|Small Tools for Big Ideas!|
|''Author:''|EricShulman|
%/
/%
|''URL:''|http://tiddlyvault.tiddlyspot.com|
|''Description:''|TiddlyVault - a plugin catalog|
|''Author:''|DaveGifford|
%/
/%
|''URL:''|http://www.TiddlyWiki.com/|
|''Description:''|Official TiddlyWiki Core Distribution|
|''Author:''|JeremyRuston|
%/
/%
!info
@@text-align:left;display:block;white-space:normal;
|Name|TinyChat|
|Source|http://www.TiddlyTools.com/#TinyChat|
|Version|2.0.3|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|Type|transclusion|
|Description|text/video chat service from tinychat.com|
TinyChat is a 3^^rd^^ party web service offered by http://tinychat.com, and provides real-time multi-user video/text chat for up to 12 simultaneous video users and 300 text chat users.  This //free// service is 100% web-based and does //not// install any software on your system, nor does it require any signup/registration for use.

Usage
<<<
{{{
<<tiddler TinyChat with: roomname>>
}}}
*If ''roomname'' is omitted, a droplist control is displayed, allowing you to select from a list of roomnames that can be optionally defined in [[TinyChatList]].
*The droplist also includes a command item to 'enter a roomname...'.  The default value for this input can be defined using a hard-coded value in a 'configuration tiddler' (e.g., {{{config.options.txtTinyChatRoom="roomname"}}}) or set interactively via {{{<<option txtTinyChatRoom>>}}}.
<<<
Example
<<<
{{{<<tiddler TinyChat>>}}}
<<tiddler TinyChat##banner>>
<<<
@@
!end

!banner
@@font-size:200%;''[[TinyChat|http://tinychat.com/]]''@@
^^your own chatroom, simple and easy.^^
<<tiddler TinyChat##select>> <<tiddler TinyChat##help>>
!end

!show
@@font-size:160%;http://tinychat.com/$1@@
$2{{span{$3}}}<<tiddler TinyChat##select>><html>
<input type='button' value="join room" onclick="
	var msg=this.parentNode.previousSibling.previousSibling;
	var target=this.nextSibling;
	var hide=target.style.display=='block';
	if (hide) {
		var here=this; while (!hasClass(here,'tinyChat')) here=here.parentNode;
		removeChildren(here); wikify('<<tiddler TinyChat with: $1>>',here);
	} else {
		this.value='exit room'; msg.style.display='none'; target.style.display='block';
		removeChildren(target); wikify('<<tiddler TinyChat##embed with: $1>>',target);
	}
"><div style="display:none"></div><nowiki></(tml> <<tiddler TinyChat##help>>
!end

!help
<html><nowiki><a href='javascript:;' title='About TinyChat' class='tinyChatHelp' onclick="
	var here=this; while (!hasClass(here,'tinyChat')) here=here.parentNode;
	removeChildren(here); wikify('<<tiddler TinyChat##info>>',here);
	return false;
">?</a></html>
!end

!select
<html><nowiki><select onchange="
	var v=this.value; if (v=='_ask') {
		v=config.options.txtTinyChatRoom||'tiddlytools';
		v=prompt('enter a room name',v)||'';
	}
	config.macros.option.propagateOption('txtTinyChatRoom','value',v,'input');
	var here=this; while (!hasClass(here,'tinyChat')) here=here.parentNode;
	removeChildren(here); wikify('<<tiddler TinyChat with: '+v+'>>',here);
	return false;">
</select></html><<tiddler {{
	var list=place.lastChild.getElementsByTagName('select')[0];
	if (!list.length) {
		list.options[0]=new Option('select a room...','');
		var rooms=store.getTiddlerText('TinyChatList','tiddlytools').split('\n');
		var curr=config.options.txtTinyChatRoom; var found=false; var indent='\xa0\xa0';
		for (var i=0;i<rooms.length;i++) { var r=rooms[i];
			var sel=r==curr; if (sel) found=true;
			list.options[list.length]=new Option(indent+r,r,sel,sel);
		}
		if (curr&&!found) list.options[list.length]=new Option(indent+curr,curr,true,true);
		list.options[list.length]=new Option('or, enter a room name...','_ask');
	}
'';}}>>
!end

!embed
<html><nowiki>
<iframe src="http://tinychat.com/$1" height=1000 width=100%></iframe>
</html>
!TEST_JS_EMBED
<html><nowiki><div id="client">
	<a href="http://tinychat.com">video chat</a> provided by Tinychat
</div></html><script>
	window.tinychat={ room: "$1", colorbk: "0xffffff", join: "auto", api: "list" };
</script><script src="http://tinychat.com/js/embed.js"></script>
!end

!refresh
<html><nowiki><a href="javascript:" title="click to refresh room status" onclick="
	var here=this; while (!hasClass(here,'tinyChat')) here=here.parentNode;
	removeChildren(here); wikify('<<tiddler TinyChat with: %1>\>',here);
	return false;
">%0</a></html>
!end

%/<html><nowiki><style>
	.tinyChat { text-align:center; } 
	.tinyChatHelp { color:ButtonText !important;
		border:2px outset ButtonFace; padding:1px 4px;
		background-color:ButtonFace; -moz-appearance:button;
		-moz-border-radius:.3em; -webkit-border-radius:.3em; 
	}
	#tiddlerTinyChat .tagged { display:none; }
</style></html>{{tinyChat{
<<tiddler {{ var room=('$1'!='$'+'1'?'$1':'').trim();
if (!room.length) {
	delete config.options.txtTinyChatRoom;
	var out="<<tiddler TinyChat##banner>\>";
	var here=place; while (!hasClass(here,'tinyChat')) here=here.parentNode;
	removeChildren(here); wikify(out,here);
} else {
	config.options.txtTinyChatRoom=room;
	var url='http://api.tinychat.com/'+room+'.json';
	var now=new Date().formatString('DDD, MMM DDth YYYY 0hh12:0mm:0ss am');
	now='~~'+store.getTiddlerText('TinyChat##refresh').format([now,room])+'~~\n';
	var callback=function(success,room,txt,src,xhr){
		var head=' '; var msg=now; var data={};
		if (success && xhr.status) {
			eval('data='+txt);
			if (data.topic) head='"""'+data.topic+'"""\n';
			if (data.names) {
				var len=data.names.length;
				msg+="//''There %0 %1 user%2 in the room:''//\n"+'^^"""%3"""^^\n';
				msg=msg.format([len==1?'is':'are',len,len==1?'':'s',data.names.join(', ')]);
			}
			else msg+="//the room is empty//\n";
		}
		else msg+="//room information not available//\n";
		var out='<<tiddler TinyChat##show with: %0 [[%1]] [[%2]]>\>'.format([room,head,msg]);
		var here=place; while (!hasClass(here,'tinyChat')) here=here.parentNode;
		removeChildren(here); wikify(out,here);
	};
	wikify('^^looking for http://tinychat.com/'+room+'...^^',place);
//	if (!httpReq("GET",url,callback,room,null,null,null,null,null,true)) {
		var msg=now+'//room information not available//\n'
		var out='<<tiddler TinyChat##show with: %0 [[%1]] [[%2]]>\>'.format([room,' ',msg]);
		var here=place; while (!hasClass(here,'tinyChat')) here=here.parentNode;
		removeChildren(here); wikify(out,here);
//	}
}
'';}}>>}}}
This tiddler is an example of an automatic "to do" list generator, where each "to do" item is stored in a separate, tagged tiddler: 
<<<
{{valignTop{
| ''<<tag [[To Do]] "Pending tasks">>'' | ''<<tag Done "Completed tasks">>'' |
|<<matchTags {{"<<tiddler CheckboxToggleTag with: Done [[To Do]] %0\>\> %0"}} "\n" To Do>>|<<matchTags {{"<<tiddler CheckboxToggleTag with: Done [[To Do]] %0\>\> %0"}} "\n" Done>>|
}}}
----
The following syntax:
{{{
<<matchTags {{"<<tiddler CheckboxToggleTag with: Done [[To Do]] %0\>\> %0"}} "\n" To Do OR Done>>
}}}
combines the {{{<<matchTags>>}}} macro (defined by [[MatchTagsPlugin]]) with the [[CheckboxToggleTag]] inline script (requires [[InlineJavascriptPlugin]]) to output a list of checkboxes and corresponding tiddler titles, one for each matched tiddler.  Setting/clearing any given checkbox toggles that tiddler between the two alternative tag values and also auto-refreshes the list display.

You can also display separate lists of //pending tasks// (tagged with <<tag [[To Do]]>>) and //completed tasks// (tagged with <<tag Done>>) by using two instances of the above syntax, each with different tag expressions for matching the appropriate tiddlers:
{{{
<<matchTags {{"<<tiddler CheckboxToggleTag with: Done [[To Do]] %0\>\> %0"}} "\n" To Do>>
<<matchTags {{"<<tiddler CheckboxToggleTag with: Done [[To Do]] %0\>\> %0"}} "\n" Done>>
}}}
<<<
/%
!info
|Name|ToggleAnimations|
|Source|http://www.TiddlyTools.com/#ToggleAnimations|
|Version|2.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Description|enable/disable animation effects|
Usage
<<<
{{{
<<tiddler ToggleAnimations>>
<<tiddler ToggleAnimations with: label>>
}}}
<<<
Example
<<<
{{{<<tiddler ToggleAnimations with: "click me">>}}}
<<tiddler ToggleAnimations##show with: "click me">>
<<<
!end
!show
<html><nowiki><a href="javascript:;" title="enable/disable animation effects"
onmouseover="
	this.href='javascript:void(eval(decodeURIComponent(%22(function(){try{('
	+encodeURIComponent(encodeURIComponent(this.onclick))
	+')()}catch(e){alert(e.description?e.description:e.toString())}})()%22)))';"
onclick="
	var opt='chkAnimate';
	config.macros.option.propagateOption(opt,'checked',!config.options[opt],'input');
	displayMessage('Animation effects are: '+(config.options[opt]?'ON':'OFF'));
	return false;
">$1</a></html>
!end
%/<<tiddler {{var src='ToggleAnimations'; src+(tiddler&&tiddler.title==src?'##info':'##show')}}
	with: {{'$1'=='$'+'1'?'toggle animations':'$1'}}>>
/%
!info
|Name|ToggleBreadcrumbs|
|Source|http://www.TiddlyTools.com/#ToggleBreadcrumbs|
|Version|2.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Description|enable/disable display of breadcrumbs (uses BreadcrumbsPlugin)|
Usage
<<<
{{{
<<tiddler ToggleBreadcrumbs>>
<<tiddler ToggleBreadcrumbs with: label tip>>
}}}
<<<
Example
<<<
{{{<<tiddler ToggleBreadcrumbs>>}}}
<<tiddler ToggleBreadcrumbs##show with: "show breadcrumbs">>
<<<
!end
!show
<<tiddler {{
	if (config.options.chkShowBreadcrumbs===undefined) config.options.chkShowBreadcrumbs=true;
'';}}>><<option chkShowBreadcrumbs>><<tiddler {{
	var chk=place.lastChild;
	if (!chk.coreOnChange) { // only once
		chk.coreOnChange=chk.onchange;
		chk.onchange=function() {
			if (this.coreOnChange) this.coreOnChange.apply(this,arguments);
			this.checked=config.options.chkShowBreadcrumbs;
			if (config.macros.breadcrumbs) config.macros.breadcrumbs.refresh();
		};
	}
'';}}>> $1
!end

%/<<tiddler {{var src='ToggleBreadcrumbs'; src+(tiddler&&tiddler.title==src?'##info':'##show');}}
with:	{{'$1'!='$'+'1'?'$1':'show breadcrumbs'}}
	{{'$2'!='$'+'2'?'$2':'toggle breadcrumbs display'}}>>
/%
!info
|Name|ToggleFullScreen|
|Source|http://www.TiddlyTools.com/#ToggleFullScreen|
|Version|2.1.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Description|Create a link that shows/hides sidebars and page headers|
Usage
<<<
{{{
<<tiddler ToggleFullScreen>>
<<tiddler ToggleFullScreen with: label altlabel>>
}}}
embeds a command link into content, where:
*''label'' (optional, default={{{fullscreen}}})<br>command text
*''altlabel'' (optional, default={{{restore}}})<br>alternative command text shown when full screen is enabled
You can also enable/disable full screen immediately (without clicking a command link) by embedding the one of the following directly in your content:
{{{
<<tiddler ToggleFullScreen##ON>>
<<tiddler ToggleFullScreen##OFF>>
}}}
<<<
Example
<<<
{{{<<tiddler ToggleFullScreen with: fullscreen restore>>}}}
<<tiddler ToggleFullScreen##show with: fullscreen restore>>
<<<
Revisions
<<<
2011.05.13 2.1.0 refactored code and restored "##ON" and "#OFF" usage
2010.xx.xx 2.0.1 converted to transclusion
2008.10.13 1.1.3 re-written to support bookmarklet usage
2008.01.20 1.0.0 created (inline script)
<<<
!end

!code
<<tiddler {{
window.setFullScreen = function(fs) {
	var co=config.options; var cm=config.macros;
	cm.option.propagateOption('chkFullScreen','checked',fs,'input');

	var showmm=!fs && co.chkShowLeftSidebar!==false;
	var showsb=!fs && co.chkShowRightSidebar!==false;
	var showcrumbs=!fs && co.chkShowBreadcrumbs!==false
		&& cm.breadcrumbs && cm.breadcrumbs.crumbs.length;
	var showstorymenu=!fs;

	var da=document.getElementById('displayArea');
	var cw=document.getElementById('contentWrapper');
	var mm=document.getElementById('mainMenu');
	var sb=document.getElementById('sidebar');
	var sm=document.getElementById('storyMenu');
	var bc=document.getElementById('breadCrumbs');

	if (cw){ // toggle page header
		var elems=cw.getElementsByTagName('*');
		for (var i=0; i<elems.length; i++) if (hasClass(elems[i],'header')) 
			{ elems[i].style.display=fs?'none':'block'; break; }
	}
	if (mm) { // toggle MainMenu
		mm.style.display=showmm?'block':'none';
		da.style.marginLeft=showmm?(co.txtDisplayAreaLeftMargin||''):'1em';
	}
	if (sb) { // toggle sidebar
		sb.style.display=showsb?'block':'none';
		da.style.marginRight=showsb?(co.txtDisplayAreaRightMargin||''):'1em';
	}
	if (sm) sm.style.display=showstorymenu?'block':'none';	// toggle StoryMenu
	if (bc) bc.style.display=showcrumbs?'block':'none';	// toggle BreadCrumbsPlugin

	var b=document.getElementById('restoreFromFullscreenButton'); if (b) removeNode(b);
	if (fs) { 
		setStylesheet(store.getTiddlerText('ToggleFullScreen##styles'),'fullScreenStyles');
		var b=createTiddlyElement(null,'span','restoreFromFullscreenButton','selected');
		b.innerHTML='&loz;';
		b.title='RESTORE: redisplay page header, menu and sidebar';
		b.onclick=function(ev){return window.setFullScreen(false);};
		document.body.insertBefore(b,null);
	}
	return false;
};
'';}}>>
!end

!styles
#restoreFromFullscreenButton {
	position:fixed; top:.3em; right:.3em; z-index:10001;
	cursor:pointer; font-size:8pt; color:ButtonText !important;
	border:2px outset ButtonFace; padding:0px 3px;
	background-color:ButtonFace; -moz-appearance:button;
}
!end

!ON
<<tiddler ToggleFullScreen##code>><<tiddler {{window.setFullScreen(true);'';}}>>
!end

!OFF
<<tiddler ToggleFullScreen##code>><<tiddler {{window.setFullScreen(false);'';}}>>
!end

!show
<<tiddler ToggleFullScreen##code>><html><nowiki>
<a href='javascript:;' title="FULLSCREEN: toggle sidebars and page header"
onmouseover="
	this.href='javascript:void(eval(decodeURIComponent(%22(function(){try{('
	+encodeURIComponent(encodeURIComponent(this.onclick))
	+')()}catch(e){alert(e.description?e.description:e.toString())}})()%22)))';"
onclick="
	window.setFullScreen(!config.options.chkFullScreen); // toggle setting
	this.innerHTML=!config.options.chkFullScreen?'$1':'$2'; // set command text
	return false;
">$1</a></html>
!end

%/<<tiddler {{var src='ToggleFullScreen'; src+(tiddler&&tiddler.title==src?'##info':'##show');}}
with:	{{'$'+'1'!='$1'?'$1':'fullscreen'}}
	{{'$'+'2'!='$2'?'$2':'restore'}}>>
/%
!info
|Name|ToggleLeftSidebar|
|Source|http://www.TiddlyTools.com/#ToggleLeftSidebar|
|Version|2.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Description|show/hide left sidebar (MainMenu)|
Usage
<<<
{{{
<<tiddler ToggleLeftSidebar>>
<<tiddler ToggleLeftSidebar with: label tooltip>>
}}}
Try it: <<tiddler ToggleLeftSidebar##show
	with: {{config.options.chkShowLeftSidebar?'â—„':'â–º'}}>>
<<<
Configuration:
<<<
{{{
config.options.chkShowLeftSidebar (true)
config.options.txtToggleLeftSideBarLabelShow (â–º)
config.options.txtToggleLeftSideBarLabelHide (â—„)
}}}
<<<
!end
!show
<<tiddler {{
	var co=config.options;
	if (co.chkShowLeftSidebar===undefined) co.chkShowLeftSidebar=true;
	var mm=document.getElementById('mainMenu');
	var da=document.getElementById('displayArea');
	if (mm) {
		mm.style.display=co.chkShowLeftSidebar?'block':'none';
		da.style.marginLeft=co.chkShowLeftSidebar?'':'1em';
	}
'';}}>><html><nowiki><a href='javascript:;' title="$2"
onmouseover="
	this.href='javascript:void(eval(decodeURIComponent(%22(function(){try{('
	+encodeURIComponent(encodeURIComponent(this.onclick))
	+')()}catch(e){alert(e.description?e.description:e.toString())}})()%22)))';"
onclick="
	var co=config.options;
	var opt='chkShowLeftSidebar';
	var show=co[opt]=!co[opt];
	var mm=document.getElementById('mainMenu');
	var da=document.getElementById('displayArea');
	if (mm) {
		mm.style.display=show?'block':'none';
		da.style.marginLeft=show?'':'1em';
	}
	saveOptionCookie(opt);
	var labelShow=co.txtToggleLeftSideBarLabelShow||'&#x25BA;';
	var labelHide=co.txtToggleLeftSideBarLabelHide||'&#x25C4;';
	if (this.innerHTML==labelShow||this.innerHTML==labelHide) 
		this.innerHTML=show?labelHide:labelShow;
	this.title=(show?'hide':'show')+' left sidebar';
	var sm=document.getElementById('storyMenu');
	if (sm) config.refreshers.content(sm);
	return false;
">$1</a></html>
!end
%/<<tiddler {{
	var src='ToggleLeftSidebar';
	src+(tiddler&&tiddler.title==src?'##info':'##show');
}} with: {{
	var co=config.options;
	var labelShow=co.txtToggleLeftSideBarLabelShow||'&#x25BA;';
	var labelHide=co.txtToggleLeftSideBarLabelHide||'&#x25C4;';
	'$1'!='$'+'1'?'$1':(co.chkShowLeftSidebar?labelHide:labelShow);
}} {{
	var tip=(config.options.chkShowLeftSidebar?'hide':'show')+' left sidebar';
	'$2'!='$'+'2'?'$2':tip;
}}>>
/%
|Name|ToggleReadOnly|
|Source|http://www.TiddlyTools.com/#ToggleReadOnly|
|Version|2.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.5|
|Type|transclusion|
|Description|enable/disable global read-only state without reloading your document|

Usage: 
	<<tiddler ToggleReadOnly>> OR
	<<tiddler ToggleReadOnly with: label tip>>

!show
<html><nowiki><span class='button' style='cursor:pointer'
	onclick="this.getElementsByTagName('input')[0].click();" title="$2">
<input type='checkbox' style="margin:0;padding:0;" onclick="
	window.readOnly=this.checked;
	window.showBackstage=!window.readOnly;
	config.macros.option.propagateOption('chkHttpReadOnly','checked',window.readOnly,'input');
	if(showBackstage && !backstage.area) backstage.init();
	backstage.button.style.display=showBackstage?'block':'none';
	backstage.hide();
	story.switchTheme(config.options.txtTheme);
	refreshAll(); story.refreshAllTiddlers(true); // FORCE RE-DISPLAY
	return false;
">$1</span></html><<tiddler {{
	var chk=place.lastChild.getElementsByTagName('input')[0];
	chk.checked=window.readOnly;
'';}}>>
!end

%/<<tiddler ToggleReadOnly##show with:
	{{"$1"=="$"+"1"?"read-only":"$1"}}
	{{"$2"=="$"+"2"?"enable/disable editing functions":"$2"}}
>>
/%
!info
|Name|ToggleRightSidebar|
|Source|http://www.TiddlyTools.com/#ToggleRightSidebar|
|Version|2.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Description|show/hide right sidebar (SideBarOptions)|
Usage
<<<
{{{
<<tiddler ToggleRightSidebar>>
<<tiddler ToggleRightSidebar with: label tooltip>>
}}}
Try it: <<tiddler ToggleRightSidebar##show
	with: {{config.options.chkShowRightSidebar?'â–º':'â—„'}}>>
<<<
Configuration:
<<<
copy/paste the following settings into a tiddler tagged with <<tag systemConfig>> and then modify the values to suit your preferences:
{{{
config.options.chkShowRightSidebar=true;
config.options.txtToggleRightSideBarLabelShow="â—„";
config.options.txtToggleRightSideBarLabelHide="â–º";
}}}
<<<
!end
!show
<<tiddler {{
	var co=config.options;
	if (co.chkShowRightSidebar===undefined) co.chkShowRightSidebar=true;
	var sb=document.getElementById('sidebar');
	var da=document.getElementById('displayArea');
	if (sb) {
		sb.style.display=co.chkShowRightSidebar?'block':'none';
		da.style.marginRight=co.chkShowRightSidebar?'':'1em';
	}
'';}}>><html><nowiki><a href='javascript:;' title="$2"
onmouseover="
	this.href='javascript:void(eval(decodeURIComponent(%22(function(){try{('
	+encodeURIComponent(encodeURIComponent(this.onclick))
	+')()}catch(e){alert(e.description?e.description:e.toString())}})()%22)))';"
onclick="
	var co=config.options;
	var opt='chkShowRightSidebar';
	var show=co[opt]=!co[opt];
	var sb=document.getElementById('sidebar');
	var da=document.getElementById('displayArea');
	if (sb) {
		sb.style.display=show?'block':'none';
		da.style.marginRight=show?'':'1em';
	}
	saveOptionCookie(opt);
	var labelShow=co.txtToggleRightSideBarLabelShow||'&#x25C4;';
	var labelHide=co.txtToggleRightSideBarLabelHide||'&#x25BA;';
	if (this.innerHTML==labelShow||this.innerHTML==labelHide) 
		this.innerHTML=show?labelHide:labelShow;
	this.title=(show?'hide':'show')+' right sidebar';
	var sm=document.getElementById('storyMenu');
	if (sm) config.refreshers.content(sm);
	return false;
">$1</a></html>
!end
%/<<tiddler {{
	var src='ToggleRightSidebar';
	src+(tiddler&&tiddler.title==src?'##info':'##show');
}} with: {{
	var co=config.options;
	var labelShow=co.txtToggleRightSideBarLabelShow||'&#x25C4;';
	var labelHide=co.txtToggleRightSideBarLabelHide||'&#x25BA;';
	'$1'!='$'+'1'?'$1':(co.chkShowRightSidebar?labelHide:labelShow);
}} {{
	var tip=(config.options.chkShowRightSidebar?'hide':'show')+' right sidebar';
	'$2'!='$'+'2'?'$2':tip;
}}>>
/%
!info
|Name|ToggleScrollingSidebars|
|Source|http://www.TiddlyTools.com/#ToggleScrollingSidebars|
|Version|2.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Description|enable/disable 'fixed' positioning of left and right sidebars|
Usage
<<<
{{{
<<tiddler ToggleScrollingSidebars>>
<<tiddler ToggleScrollingSidebars with: label tip>>
}}}
<<<
Example
<<<
{{{<<tiddler ToggleScrollingSidebars>>}}}
<<tiddler ToggleScrollingSidebars##show with: "sidebars scroll with page">>
<<<
!end
!show
<<tiddler {{
	if (config.options.chkScrollSidebars==undefined)
		config.options.chkScrollSidebars=true;
	if (!config.options.txtOuterTabHeight||!config.options.txtOuterTabHeight.length)
		config.options.txtOuterTabHeight="25em";
	if (!config.options.txtInnerTabHeight||!config.options.txtInnerTabHeight.length)
		config.options.txtInnerTabHeight="21em";
	window.ToggleScrollingSidebars_setscroll = function() {
		var co=config.options;
		var scroll=co.chkScrollSidebars?'':'fixed';
		document.getElementById('mainMenu').style.position=scroll;
		document.getElementById('sidebar').style.position=scroll;
		var outer=co.chkScrollSidebars?'auto':co.txtOuterTabHeight;
		var inner=co.chkScrollSidebars?'auto':co.txtInnerTabHeight;
		var css= '#sidebarTabs .tabContents {height:%0;overflow:%1;width:92.5%;}'
			+'#sidebarTabs .tabContents .tabContents {height:%2 !important;}';
		css=css.format([outer,outer!='auto'?'auto':'visible',inner]);
		setStylesheet(css,'shortSidebarTabs');
	}
'';}}>><<option chkScrollSidebars>><<tiddler {{
	var chk=place.lastChild;
	if (!chk.coreOnChange) { // only once
		chk.coreOnChange=chk.onchange;
		chk.onchange=function() {
			if (this.coreOnChange) this.coreOnChange.apply(this,arguments);
			this.checked=config.options.chkScrollSidebars;
			window.ToggleScrollingSidebars_setscroll();
		};
	}
	window.ToggleScrollingSidebars_setscroll();
'';}}>> $1
!end

%/<<tiddler {{var src='ToggleScrollingSidebars'; src+(tiddler&&tiddler.title==src?'##info':'##show');}}
with:	{{'$1'!='$'+'1'?'$1':'sidebars scroll with page'}}
	{{'$2'!='$'+'2'?'$2':'sidebars scroll with page'}}>>
/%
!info
|Name|ToggleSiteMenu|
|Source|http://www.TiddlyTools.com/#ToggleSiteMenu|
|Version|1.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.5|
|Type|transclusion|
|Description|show/hide horizontal SiteMenu using checkbox or double-click on background|
Usage:
<<<
{{{
<<tiddler ToggleSiteMenu>> OR
<<tiddler ToggleSiteMenu with: label tip>>
}}}
<<<
!end
!show
<<option chkHideSiteMenu>><<tiddler {{
	var chk=place.lastChild;
	if (!chk.coreOnChange) { // only once
		chk.coreOnChange=chk.onchange;
		chk.onchange=function() {
			if (this.coreOnChange) this.coreOnChange.apply(this,arguments);
			var opt=this.getAttribute('option');
			var m=document.getElementById('siteMenu');
			if (m) m.style.display=config.options[opt]?'none':'block';
		};
	}
'';}}>> $1
!end

%/<<tiddler {{'ToggleSiteMenu##'+(tiddler&&tiddler.title=='ToggleSiteMenu'?'info':'show')}} with:
{{"$1"=="$"+"1"?"hide site menubar":"$1"}}
{{"$2"=="$"+"2"?"toggle horizontal site menu display":"$2"}}
{{
	// init header display
	var opt='chkHideSiteMenu';
	if (config.options[opt]==undefined) config.options[opt]=false;
	var m=document.getElementById('siteMenu'); 
	if (m) m.style.display=config.options[opt]?'none':'block';

	// add double-click trigger to page background
	document.ondblclick=function(event){
		if (!event) event=window.event; // IE fixup
		var target=resolveTarget(event);
		// ignore double-clicks that bubble through from input fields and listboxes
		if (target.nodeName.toUpperCase()=="TEXTAREA") return true;
		if (target.nodeName.toUpperCase()=="SELECT") return true;
		if (target.nodeName.toUpperCase()=="INPUT"&&target.type.toUpperCase()=="TEXT") return true;
		window.toggleSiteMenu();
		// consume the event
		if (event) { event.cancelBubble=true; if (event.stopPropagation) event.stopPropagation(); }
		return false;
	};
	// onclick side-effect: show/hide site menu and sync checkboxes for this option
	window.toggleSiteMenu=function() {
		var opt="chkHideSiteMenu";
		var m=document.getElementById('siteMenu'); if (!m) return true;
		var show=(m.style.display=='none');
		m.style.display=show?'block':'none';
		config.options[opt]=!show;
		saveOptionCookie(opt);
		config.macros.option.propagateOption(opt,"checked", config.options[opt],"input");
	};
'';}}>>
/%
!info
|Name|ToggleSiteTitles|
|Source|http://www.TiddlyTools.com/#ToggleSiteTitles|
|Version|1.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.5|
|Type|transclusion|
|Description|show/hide document 'header' area (containing SiteTitle and SiteSubtitle content)|
Usage:
<<<
{{{
<<tiddler ToggleSiteTitles>> OR
<<tiddler ToggleSiteTitles with: label tip>>
}}}
<<<
!end

!show
<<option chkHideSiteTitles>><<tiddler {{
	var chk=place.lastChild;
	if (!chk.coreOnChange) { // only once
		chk.coreOnChange=chk.onchange;
		chk.onchange=function() {
			if (this.coreOnChange) this.coreOnChange.apply(this,arguments);
			var h=jQuery('#contentWrapper .header')[0];
			var opt=this.getAttribute('option');
			if (h) h.style.display=config.options[opt]?'none':'block';
		};
	}
'';}}>> $1
!end

%/<<tiddler {{'ToggleSiteTitles##'+(tiddler&&tiddler.title=='ToggleSiteTitles'?'info':'show')}} with:
{{"$1"=="$"+"1"?"hide site titles":"$1"}}
{{"$2"=="$"+"2"?"toggle site title display":"$2"}}
{{	// init header display
	var opt='chkHideSiteTitles';
	if (config.options[opt]==undefined) config.options[opt]=false;
	var h=jQuery('#contentWrapper .header')[0];
	if (h) h.style.display=config.options[opt]?'none':'block';
}}
>>
/%
!info
|Name|ToggleSliders|
|Source|http://www.TiddlyTools.com/#ToggleSliders|
|Version|2.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Description|toggle (expand/collapse) all sliders in a tiddler (or ID'd DOM element)|
Usage
<<<
{{{
<<tiddler ToggleSliders with: elementID expandlabel collapselabel>>
}}}
*''elementID'' is one of:
**"" (empty quotes) = the current tiddler
**''here'' = the current container
**''ID'' = specific DOM element ID (e.g., "mainMenu")
*''expandlabel/collapselabel'' (optional)<br>are alternative link text to display when sliders are closed (expandlabel) or opened (collapselabel)
<<<
Example
<<<
{{{
<<tiddler ToggleSliders with: "" "open all" "close all">>
}}}
with sample sliders:
{{{
<<slider chkExample ToggleSliders::slider1 Example1 Example1>>
<<slider chkExample ToggleSliders::slider2 Example2 Example2>>
Example1: |This is example slider 1|
Example2: |This is example slider 2|
}}}
<<tiddler ToggleSliders##show with: "" "open all" "close all">>
<<slider chkExample1 ToggleSliders::Example1 Example1 Example1>>
<<slider chkExample2 ToggleSliders::Example2 Example2 Example2>>
<<<
!end

!show
<html><a href="javascript:;" class="TiddlyLink" title="toggle sliders"
onclick="
	if ('$1'=='here') var here=this.parentNode.parentNode.parentNode.parentNode; // container
	else if ('$1'!='$'+'1' && '$1'.length) here=document.getElementById('$1'); // ID
	else var here=story.findContainingTiddler(this); // tiddler
	if (!here) return false;
	var elems=here.getElementsByTagName('*');
	var state=(this.innerHTML.toLowerCase()=='$2')?'none':'block';
	for (var e=0; e<elems.length; e++) { var p=elems[e];
		if (p.className!='sliderPanel' || p.style.display!=state) continue;
		if (p.button) window.onClickNestedSlider({target:p.button}); // see NestedSlidersPlugin
		else p.previousSibling.onclick();
	}
	this.innerHTML=state=='none'?'$3':'$2';
	return false;
">$2</a><nowiki></html>
!end
%/<<tiddler {{ var src='ToggleSliders'; src+(tiddler&&tiddler.title==src?'##info':'##show')}}
	with:	[[$1]]
		{{'$2'!='$'+'2'?'$2':'expand'}}
		{{'$3'!='$'+'3'?'$3':'collapse'}}
		{{'$4'!='$'+'4'?'$4':'toggle sliders'}}
>>
/%
!info
|Name|ToggleTiddlerTags|
|Source|http://www.TiddlyTools.com/#ToggleTiddlerTags|
|Version|2.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Description|command link to show/hide tiddler tags display in all tiddlers at once|
Usage:
<<<
in tiddler content:
{{{
<<tiddler ToggleTiddlerTags>>
<<tiddler ToggleTiddlerTags with: label>>
}}}
or, in ViewTemplate:
{{{
<span class='toolbar' macro='tiddler ToggleTiddlerTags'></span>
	OR, if TiddlyTools' CoreTweaks for ticket #610 is installed:
<span class='toolbar' macro='toolbar ... ToggleTiddlerTags...'></span>
}}}
or, in ToolbarCommands (with CoreTweaks #610 installed):
{{{
| ViewToolbar| ... ToggleTiddlerTags... |
| EditToolbar| ... ToggleTiddlerTags... |
}}}
<<<
!end

!show
<html><nowiki><a href='javascript:;' title='show/hide tiddler tags' onclick="
	config.options.chkHideTiddlerTags=!config.options.chkHideTiddlerTags;
	var show=config.options.chkHideTiddlerTags?'none':'block';
	setStylesheet('.tiddler .tagged { display:'+show+'; }','toggleTiddlerTags');
">$1</a></html>
!end
%/<<tiddler {{'ToggleTiddlerTags##'+(tiddler&&tiddler.title=='ToggleTiddlerTags'?'info':'show')}}
	with: {{"$1"=='$'+'1'?'tags':"$1"}}>>
/%
!info
|Name|ToggleTiddlerTitles|
|Source|http://www.TiddlyTools.com/#ToggleTiddlerTitles|
|Version|2.0.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Description|command link to show/hide tiddler title display in all tiddlers at once|
Usage:
<<<
in tiddler content:
{{{
<<tiddler ToggleTiddlerTitles>>
<<tiddler ToggleTiddlerTitles with: label>>
}}}
or, in ViewTemplate:
{{{
<span class='toolbar' macro='tiddler ToggleTiddlerTitles'></span>
	OR, if TiddlyTools' CoreTweaks for ticket #610 is installed:
<span class='toolbar' macro='toolbar ... ToggleTiddlerTitles...'></span>
}}}
or, in ToolbarCommands (with CoreTweaks #610 installed):
{{{
| ViewToolbar| ... ToggleTiddlerTitles... |
| EditToolbar| ... ToggleTiddlerTitles... |
}}}
<<<
!end

!show
<html><nowiki><a href='javascript:;' title='show/hide tiddler titles' onclick="
	config.options.chkHideTiddlerTitles=!config.options.chkHideTiddlerTitles;
	var show=config.options.chkHideTiddlerTitles?'none':'block';
	setStylesheet('.tiddler .title, .tiddler .subtitle { display:'+show+'; }','toggleTiddlerTitles')
">$1</a></html>
!end
%/<<tiddler {{'ToggleTiddlerTitles##'+(tiddler&&tiddler.title=='ToggleTiddlerTitles'?'info':'show')}}
	with: {{"$1"=='$'+'1'?'titles':"$1"}}>>
!!!!!toolbar definitions for templates
<<<
Uses CoreTweaks (#609/#610) for extended "!" and 'toolbar include' syntax
|~ViewToolbar|~ToolbarCommands##spacer collapseTiddler collapseOthers closeTiddler closeOthers ! ~ToolbarCommands##goto ~ToolbarCommands##search ~ToolbarCommands##editTiddler ~ToolbarCommands##undoTiddler ~ToolbarCommands##refreshTiddler ! > < * ~ToolbarCommands##tidide ~ToolbarCommands##related ~ToolbarCommands##permalink ~ToolbarCommands##copyTiddler ~ToolbarCommands##snapshotSave ~ToolbarCommands##snapshotPrint ~ToolbarCommands##saveTiddlerToFile ~ToolbarCommands##sendTiddler ~ToolbarCommands##revertTiddler ~ToolbarCommands##runTiddler |
|~EditToolbar|~ToolbarCommands##spacer ~ToolbarCommands##saveTiddler ~ToolbarCommands##cancelTiddler ~ToolbarCommands##copyTiddler ~ToolbarCommands##deleteTiddler ! ~ToolbarCommands##fields ! > < * ~ToolbarCommands##options ~ToolbarCommands##autosizeCheckbox ~ToolbarCommands##previewCheckbox ~ToolbarCommands##quickeditCheckbox ~ToolbarCommands##minorchangesCheckbox |
|~EditToolbarReadOnly|~ToolbarCommands##spacer ~ToolbarCommands##cancelTiddler ! ~ToolbarCommands##fields ! ~ToolbarCommands##autosizeCheckbox ~ToolbarCommands##previewCheckbox |
|~CollapsedToolbar|~ToolbarCommands##spacer +expandTiddler collapseOthers closeTiddler closeOthers ! ~ToolbarCommands##goto ~ToolbarCommands##search ~ToolbarCommands##editTiddler ~ToolbarCommands##refreshTiddler ! > < * ~ToolbarCommands##tidide ~ToolbarCommands##related ~ToolbarCommands##permalink ~ToolbarCommands##copyTiddler ~ToolbarCommands##snapshotSave ~ToolbarCommands##snapshotPrint ~ToolbarCommands##saveTiddlerToFile ~ToolbarCommands##sendTiddler ~ToolbarCommands##runTiddler|
<<<
!!!!!wiki-syntax toolbar commands
<<<
!!!!!spacer
{{{
/% force whitespace separation and baseline alignment of toolbar with tiddler title %/@@font-size:12pt;&nbsp;@@
}}}
!!!!!goto
{{{
@@position:static;+++^25em^*[goto|view another tiddler]...
	<<moveablePanel>>{{fine{
	{{floatright{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}}}/%
	%/<<tiddler SiteMenuGoto>>}}}===<<setIcon page_go.png>>@@
}}}
!!!!!search
{{{
@@position:static;+++^22em^*[search|find tiddlers that match search text]...
	<<moveablePanel>>{{small{
	{{floatright{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}}}/%
	%/<<tiddler SiteMenuSearch>>}}}===<<setIcon page_find.png>>@@
}}}
!!!!!editTiddler
{{{
<script>
	if (readOnly) return "<<toolbar +editTiddler>><<setIcon page.png>>"; // view
	else return "<<toolbar +editTiddler>><<setIcon page_edit.png>>"; // edit
</script>
}}}
!!!!!undoTiddler
{{{
<<undo>><<setIcon arrow_undo.png>>
}}}
!!!!!refreshTiddler
{{{
<script label="refresh" title="redisplay the contents of this tiddler">
	story.refreshTiddler(story.findContainingTiddler(place).getAttribute("tiddler"),null,true);
</script><script>
	place.lastChild.style.fontWeight="normal";
</script><<setIcon page_refresh.png>>
}}}
!!!!!tidide
{{{
@@position:static;+++^[TidIDE|Edit this tiddler using the TiddlyWiki Integrated Development Environment]...
	{{fine smallform nowrap{
	<<moveablePanel>><<tidIDE SystemInfo TiddlerTweaker CompareTiddlers +edit:here>>/%
	%/<<resizeEditor>>}}}===<<setIcon application_form_edit.png>>@@
}}}
!!!!!related
{{{
@@position:static;+++^65em^[related|show list/tree view of tiddlers related to the current tiddler]...
	<<moveablePanel>>{{smallform{
	{{floatright{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}}}/%
	%/<<relatedTiddlers here hideform>>}}}===<<setIcon sitemap.png>>@@
}}}
!!!!!permalink
{{{
<<toolbar permalink>><<setIcon page_link.png>>
}}}
!!!!!copyTiddler
{{{
<script> if (!readOnly) return "<<toolbar copyTiddler>><<setIcon page_copy.png>>"; </script>
}}}
!!!!!snapshotSave
{{{
<<toolbar snapshotSave>><<setIcon camera.png>>
}}}
!!!!!snapshotPrint
{{{
<<toolbar snapshotPrint>><<setIcon printer.png>>
}}}
!!!!!saveTiddlerToFile
{{{
<<toolbar saveTiddlerToFile>><<setIcon disk.png>>
}}}
!!!!!sendTiddler
{{{
<<toolbar sendTiddler>><<setIcon server_go.png>>
}}}
!!!!!runTiddler
{{{
<<toolbar runTiddler>><<setIcon cog.png>>
}}}
!!!!!revertTiddler
{{{
<html><hide linebreaks><a href="javascript:;"
	title="reload the last SAVED version of this tiddler"
	onclick="
		var here=story.findContainingTiddler(this); if (!here) return;
		var tid=here.getAttribute('tiddler');
		var t='\<\<loadTiddlers [[tiddler:'+tid+']] '+document.location.href+' confirm force noreport\>\>';
		var e=document.getElementById('executeRevertTiddler');
		if (e) e.parentNode.removeChild(e);
		e=document.createElement('span'); e.id='executeRevertTiddler';
		wikify(t,e);
	">revert</a>
</html><<setIcon arrow_undo.png>>
}}}
!!!!!saveTiddler
{{{
<<toolbar +saveTiddler>><<setIcon tick.png>>
}}}
!!!!!cancelTiddler
{{{
<script> return "<<toolbar -cancelTiddler>><<setIcon "+(readOnly?"tick.png":"cross.png")+">>"; </script>
}}}
!!!!!deleteTiddler
{{{
<<toolbar deleteTiddler>><<setIcon delete.png>>
}}}
!!!!!fields
{{{
<<toolbar fields>><<setIcon table.png>>
}}}
!!!!!options
{{{
&nbsp;{{fine{//options://}}}&nbsp;
}}}
!!!!!autosizeCheckbox
{{{
<script label="autosize" title="automatically resize editor to fit contents">
	var txt="<input type='checkbox' style='padding:0;margin:0;' %0>autosize";
	var chk=place.innerHTML.toLowerCase().indexOf("checked")==-1?"checked":"";
	config.commands.autosizeEditor.handler(null,place,null);
	place.innerHTML=txt.format([chk]);
</script><script>
	place.lastChild.innerHTML="<input type='checkbox' style='padding:0;margin:0;'>autosize";
	place.lastChild.style.fontWeight="normal";
	place.lastChild.style.fontSize="90%";
</script>
}}}
!!!!!previewCheckbox
{{{
<script label="preview" title="show key-by-key preview">
	var txt="<input type='checkbox' style='padding:0;margin:0;' %0>preview";
	var chk=place.innerHTML.toLowerCase().indexOf("checked")==-1?"checked":"";
	config.commands.previewTiddler.handler(null,place,null);
	place.innerHTML=txt.format([chk]);
</script><script>
	place.lastChild.innerHTML="<input type='checkbox' style='padding:0;margin:0;'>preview";
	place.lastChild.style.fontWeight="normal";
	place.lastChild.style.fontSize="90%";
</script>
}}}
!!!!!quickeditCheckbox
{{{
<script label="quickedit" title="show QuickEdit toolbar buttons">
	var opt="chkShowQuickEdit";
	config.commands.toggleQuickEdit.handler(null,place,null);
	var chk=config.options[opt]?"CHECKED":"";
	var txt="<input type='checkbox' style='padding:0;margin:0;' option='%0' %1>quickedit";
	place.innerHTML=txt.format([opt,chk]);
</script><script>
	var opt="chkShowQuickEdit";
	var chk=config.options[opt]?"CHECKED":"";
	var txt="<input type='checkbox' style='padding:0;margin:0;' option='%0' %1>quickedit";
	place.lastChild.innerHTML=txt.format([opt,chk]);
	place.lastChild.style.fontWeight="normal";
	place.lastChild.style.fontSize="90%";
</script>
}}}
!!!!!minorchangesCheckbox
{{{
<script label="minor changes">
	var opt="chkForceMinorUpdate";
	config.options[opt]=!config.options[opt];
	config.macros.option.propagateOption(opt,"checked", config.options[opt],"input");
	var chk=config.options[opt]?"CHECKED":"";
	var txt="<input type='checkbox' style='padding:0;margin:0;' option='%0' %1>minor changes";
	place.innerHTML=txt.format([opt,chk]);
</script><script>
	var opt="chkForceMinorUpdate";
	var chk=config.options[opt]?"CHECKED":"";
	var txt="<input type='checkbox' style='padding:0;margin:0;' option='%0' %1>minor changes";
	place.lastChild.innerHTML=txt.format([opt,chk]);
	place.lastChild.style.fontWeight="normal";
	place.lastChild.style.fontSize="90%";
	place.lastChild.title=config.optionsDesc[opt];
</script>
}}}
!!!!!end of extra commands
<<<
/***
|Name|TotallyTiddlers|
|Source|http://www.TiddlyTools.com/#TotallyTiddlers|
|Version||
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|CSS|
|Description|theme: hide everything but tiddler content|
|StyleSheet|TotallyTiddlers|
|PageTemplateReadOnly|PageTemplateReadOnly|
|EditTemplateReadOnly|EditTemplateReadOnly|
|Check|TotallyTiddlers##check|
|Init|TotallyTiddlers##init|
|Reset|TotallyTiddlers##reset|
!!!!!check
//{{{
return !confirm("Are you sure you want to use this theme?");
//}}}
!!!!!init
//{{{
displayMessage("TotallyTiddlers (kiosk mode) is ON");
//}}}
!!!!!reset
//{{{
displayMessage("TotallyTiddlers (kiosk mode) is OFF");
//}}}
!!!!!styles
***/

[[StyleSheetAdjustments]]
/*{{{*/
/* ==== TotallyTiddlers ==== */
body { background-color:transparent !important; }
#mainMenu, #sidebar, .toolbar, .tagged, .tagging, .subtitle, .header
	{display: none !important;}
#breadCrumbs, #siteMenu, #storyMenu
	{ display:none !important; }
#displayArea
	{ margin: 1em !important; }
noscript /* Fixes a feature in Firefox 1.5.0.2 where print preview displays the noscript content */
	{ display:none; }
/*}}}*/
/***
|Name:|TrashPlugin|
|Version:|1.2.0|
|Source:|http://www.TiddlyTools.com/#TrashPlugin|
|Author:|Eric Shulman|
|OriginalSource:|http://ido-xp.tiddlyspot.com/#TrashPlugin|
|OriginalAuthor:|Ido Magal (idoXatXidomagalXdotXcom)|
|License:|[[BSD open source license]]|
|CoreVersion:|2.1.0|
|Description|add 'Trash' tag to tiddlers instead of deleting them|
!!!!!Documentation
<<<
When TrashPlugin is installed and you click on the 'delete' command in the tiddler toolbar, rather than directly removing the tiddler from the system, it will be tagged with the following tags:
{{{
Trash excludeLists excludeMissing excludeSearch systemConfigDisable
}}}
As a result, although the tiddler still exists within the document, it is ''hidden from view and will not be searched or invoked as a plugin.''
*{{block{
To view a list of all tiddlers tagged with {{{Trash}}}, simply open the [[Trash]] tiddler (aka, the "trash can").}}}
*{{block{
To reclaim a tiddler from the [[Trash]], click on a title in the trash can to open that tiddler.  Then, edit it to remove the Trash tag (as well as the other tags noted above).}}}
*{{block{
To empty the trash can (i.e. actually //delete// the tiddlers), click on the ''//"empty trash"//'' button that appears in the [[Trash]] tiddler.  You can also add this button to your [[SideBarOptions]] or any other desired location by using the following macro:
{{{
<<emptyTrash>>
}}}
}}}
*{{block{
To ''bypass the trash can'' and use the normal delete handling (with the usual confirmation messages, if chkConfirmDelete is enabled), hold CTRL while clicking 'delete'}}}
*{{block{
To ''bypass both the trash can //and// the confirmation message'' and //immediately delete// the tiddler without any further interaction, hold CTRL+SHIFT while clicking 'delete'}}}
<<<
!!!!!Revisions
<<<
2009.05.20 [1.2.0] documentation rewrite and code cleanup/reduction
2009.05.12 [1.1.0.5] refactored code to add entry point: {{{config.commands.deleteTiddler.sendToTrash(title)}}}
2008.11.14 [1.1.0.4] added SHIFT-CLICK = bypass trash and delete immediately WITHOUT CONFIRMATION
2008.10.14 [1.1.0.3] return FALSE from emptyTrash() handler (fixes IE page transition error)
2008.05.18 [1.1.0.2] when creating the Trash tiddler, pass an empty tags array [] instead of a null value, so other plugins (e.g., InstantTimestampPlugin) won't fail
2006.12.21 [1.1.0.1] only call setDirty() when actually removing tiddlers from trash
2006.12.12 [1.1.0.0] added movedMsg (feedback when tiddler is tagged as Trash).   Make sure tiddler actually exists before tagging it with 'Trash'.  Fetch correct tiddler before checking for 'systemConfig' tag
2006.12.11 [1.0.3.1] Don't create Trash tiddler until needed. Remove Trash tiddler when no trash remains. Don't tag Trash tiddler with 'TrashPlugin'. Moved all user-visible strings to variables so they can be translated by 'lingo' plugins. Use displayMessage() instead of alert()
2006.12.11 [1.0.3] Fixed broken reference to core deleteTiddler. Now storing reference to core deleteTiddler in emptyTrash macro. Reduced deleteTiddler hijacking to only the handler.
2006.12.11 [1.0.2] EmptyTrash now uses removeTiddler instead of deleteTiddler. Supports trashing systemConfig tiddlers (adds systemConfigDisable tag).
2006.12.10 [1.0.1] Replaced TW version with proper Core reference. Now properly hijacking deleteTiddler command.
2006.12.10 [1.0.0] First draft.
<<<
!!!!!Code
***/
//{{{
version.extensions.TrashPlugin= {major: 1, minor: 2, revision: 0, date: new Date(2009,5,20)};
//}}}
//{{{
config.macros.emptyTrash = {
	tag: 'Trash',
	movedMsg: "'%0' has been tagged as %1",
	label: 'empty trash',
	tooltip: 'Delete all items tagged as %0',
	tooltipOlder: 'Delete items tagged as %0 that are older than %1 days old',
	emptyMsg: 'The trash is empty',
	noneToDeleteMsg: 'There are no items in the trash older than %0 days',
	confirmMsg: "The following tiddlers will be deleted:\n\n'%0'\n\nOK to proceed?",
	deletedMsg: "Deleted '%0'",
	handler: function ( place,macroName,params,wikifier,paramString,tiddler ) {
		var namedParams = (paramString.parseParams(daysOld))[0];
		var daysOld = namedParams['daysOld'] ? namedParams['daysOld'][0] : 0; // default
		var buttonTitle = namedParams['title'] ? namedParams['title'][0] : this.label;
		var buttonTip=this.tooltip.format([this.tag])
		if (daysOld) buttonTip=this.tooltipOlder.format([this.tag,daysOld])
		var b=createTiddlyButton(place,buttonTitle,buttonTip,this.emptyTrash);
		b.setAttribute('daysOld',daysOld);
	},
	emptyTrash: function() {
		var cme=config.macros.emptyTrash; // abbrev
		var daysOld=this.getAttribute('daysOld');
		var compareDate=new Date(); compareDate.setDate(compareDate.getDate()-daysOld);
		var collected=[];
		store.forEachTiddler(function(title,tiddler) {
			if (tiddler.isTagged(cme.tag) && tiddler.modified<compareDate)
				collected.push(title);
		});
		if (!collected.length)
			displayMessage(daysOld ? cme.noneToDeleteMsg.format([daysOld]) : cme.emptyMsg);
		else if (confirm(cme.confirmMsg.format([collected.join("', '")]))) {
			for (var i=0;i<collected.length;i++) {
				store.removeTiddler(collected[i]);
				store.setDirty(true);
				displayMessage(cme.deletedMsg.format([collected[i]]));
			}
		}
		if (!store.getTaggedTiddlers(cme.tag).length) // remove Trash if empty
			{ story.closeTiddler(cme.tag,true,false); store.removeTiddler(cme.tag); }
		else
			story.refreshTiddler(cme.tag,false,true); // refresh Trash if visible
		return false;
	}
}
//}}}
// // hijack delete command
//{{{
config.commands.deleteTiddler.orig_handler=config.commands.deleteTiddler.handler;
config.commands.deleteTiddler.handler=function(event,src,title) {
	// BYPASS TRASH: CTRL=normal delete, CTRL+SHIFT=without confirmation
	if (event.ctrlKey) {
		if (event.shiftKey) { var temp=config.options.chkConfirmDelete; config.options.chkConfirmDelete=false; }
		config.commands.deleteTiddler.orig_handler.apply(this,arguments);
		if (event.shiftKey) config.options.chkConfirmDelete=temp;
		story.refreshTiddler(config.macros.emptyTrash.tag,false,true);
		return false;
	}
	config.commands.deleteTiddler.sendToTrash(title);
	return false;
};

config.commands.deleteTiddler.sendToTrash = function(title) {
	var cme=config.macros.emptyTrash; // abbrev
	if (!store.tiddlerExists(title)) return; // make sure tiddler actually exists
	if (!store.tiddlerExists(cme.tag)) // make sure Trash tiddler exists
		store.saveTiddler(cme.tag,cme.tag,'<<emptyTrash>>','TrashPlugin',new Date(),[],{});
	store.setTiddlerTag(title,1,cme.tag);
	store.setTiddlerTag(title,1,'excludeLists');
	store.setTiddlerTag(title,1,'excludeMissing');
	store.setTiddlerTag(title,1,'excludeSearch');
	if (store.getTiddler(title).isTagged('systemConfig'))
		store.setTiddlerTag(title,1,'systemConfigDisable');
	story.closeTiddler(title,true);
	if(config.options.chkAutoSave) saveChanges();
	displayMessage(cme.movedMsg.format([title,cme.tag]));
	story.refreshTiddler(cme.tag,false,true);
};
//}}}
/%
!legal
|Name|TwitterTabs|
|Source|http://www.TiddlyTools.com/#TwitterTabs|
|Version|2.0.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Description|Find recent tweets by keyword or username and show results in tabs|
!end
- - - - - DO NOT EDIT ABOVE THIS LINE - - - - -


- - - - - TABSET SECTION - - - - -
!tabset
<<tabs txtTwitterTabs
'find...'		'find tweets containing...'	[[TwitterTabs##search]]
'from...'		'show tweets from...'		[[TwitterTabs##user]]
'tiddlytools'		'show tweets from @tiddlytools'	[[TwitterTabs##tiddlytools]]
'jermolene'		'show tweets from @jermolene'	[[TwitterTabs##jermolene]]
'TwitterTabsInfo'	'documentation for TwitterTabs' [[TwitterTabs##info]]
>>
!tiddlytools
<<tiddler [[TwitterTabs##showUserResults]] with: tiddlytools>>
!jermolene
<<tiddler [[TwitterTabs##showUserResults]] with: jermolene>>
!end

- - - - - TWEETFORMAT SECTION - - - - -
reminder: %0=image, %1=name, %2=text, %3=timestamp
!tweetformat
@@font-size:8pt;display:block;line-height:110%;
~~[<img[%0]]''[[%1|http://twitter.com/%1]] //%3//:''~~
 %2 {{tagClear{
}}}@@
!end


- - - - - DO NOT EDIT BELOW THIS LINE - - - - -
!info
<<tiddler TwitterTabs##legal>>Usage
<<<
{{{
<<tiddler TwitterTabs>>
}}}
<<<
Configuration
<<<
Copy TwitterTabs into your document. Then, ''edit the tiddler to suit your preferences'' by adding/removing definitions from the ''tabset'' and related sections:<<tiddler TwitterTabs##showcode with: tabset>><<tiddler TwitterTabs##showcode with: tiddlytools>><<tiddler TwitterTabs##showcode with: jermolene>>You can also customize the appearance of the individual tweets by editing the ''tweetformat'' section, which uses //replacement markers// to insert values extracted from each tweet returned by Twitter's search results, where ''%0=user image, %1=user name, %2=tweet content,'' and ''%3=tweet timestamp''<<tiddler TwitterTabs##showcode with: tweetformat>>The most recently entered 'find... and 'from... search terms are automatically saved as TiddlyWiki cookie-based option values.  You can override these values by placing the following statements into a tiddler tagged with 'systemConfig'.  Each time you reload your document, the default inputs will be reset to these hard-coded values, rather than using the last value entered.
{{{
config.options["txtTweetSearch"]="search text";
config.options["txtTweetUser"]="username";
}}}
!showcode
<<tiddler TwitterTabs##out with: {{'!$1\n'+store.getTiddlerText('TwitterTabs##$1').replace(/\n\}\}\}/g,'\n}\}\}')}}>>
!out
{{{
$1
}}}
!end

!search
<<tiddler [[TwitterTabs##showSearchForm]] with: {{config.options.txtTweetSearch||'TiddlyWiki'}}>>
!user
<<tiddler [[TwitterTabs##showUserForm]] with: {{config.options.txtTweetUser||'TiddlyWiki'}}>>
!end

!showSearchForm
{{small smallform{
search for tweets containing: <<option {{config.options.txtTweetSearch='$1';'txtTweetSearch'}}>><html>
<nowiki><input type='button' value='search' onclick="
	var target=this.parentNode.parentNode.parentNode;
	var out='\<\<tiddler [[TwitterTabs##showSearchForm]] with: {{config.options.txtTweetSearch}}\>\>';
	removeChildren(target); wikify(out,target); return false;
"></html>@@display:block;white-space:normal;<<tiddler [[TwitterTabs##showSearchResults]]
	with: {{config.options.txtTweetSearch}}>>@@}}}
!end

!showUserForm
{{small smallform{
show tweets from: <<option {{config.options.txtTweetUser='$1';'txtTweetUser'}}>><html>
<nowiki><input type='button' value='search' onclick="
	var target=this.parentNode.parentNode.parentNode;
	var out='\<\<tiddler [[TwitterTabs##showUserForm]] with: {{config.options.txtTweetUser}}\>\>';
	removeChildren(target); wikify(out,target); return false;
"></html>@@display:block;white-space:normal;<<tiddler [[TwitterTabs##showUserResults]]
	with: {{config.options.txtTweetUser}}>>@@}}}
!end

!showSearchResults
<<tiddler TwitterTabs##callback>>{{toolbar{<html><a href='javascript:;' onclick="
	var target=this.parentNode.parentNode.parentNode;
	var out='<<tiddler [[TwitterTabs##showSearchResults]] with: [[$1]]>>';
	removeChildren(target); wikify(out,target); return false;
">refresh</a><nowiki></html>}}}~~__[[Recent tweets about: "$1"|http://search.twitter.com/search?q=$1]]__~~
<hr>@@display:block;height:20em;overflow:auto;<<tiddler {{
	window.twitterPlace=null;
'';}}>><<tiddler {{
	if (!window.twitterPlace) { window.twitterPlace=place;
		place.innerHTML='connecting to twitter.com...';
		var s=document.createElement("script");
		s.src="http://search.twitter.com/search.json?q=$1&rpp=25&callback=twitterCallback";
		document.body.appendChild(s);
		document.body.removeChild(s);
	}
'';}}>>@@@@display:block;text-align:right;^^scroll for more...^^@@
!end

!showUserResults
<<tiddler TwitterTabs##callback>>{{toolbar{<html><a href='javascript:;' onclick="
	var target=this.parentNode.parentNode.parentNode;
	var out='<<tiddler [[TwitterTabs##showUserResults]] with: [[$1]]>>';
	removeChildren(target); wikify(out,target); return false;
">refresh</a><nowiki></html>}}}~~__[[Recent tweets from $1|http://twitter.com/$1]]__~~
<hr>@@display:block;height:20em;overflow:auto;<<tiddler {{
	window.twitterPlace=null;
'';}}>><<tiddler {{
	if (!window.twitterPlace) { window.twitterPlace=place;
		place.innerHTML='connecting to twitter.com...';
		var s=document.createElement("script");
		s.src="http://twitter.com/statuses/user_timeline/$1.json?callback=twitterCallback";
		document.body.appendChild(s);
		document.body.removeChild(s);
	}
'';}}>>@@@@display:block;text-align:right;^^scroll for more...^^@@
!end

!callback
<<tiddler {{
window.twitterCallback=function(data){ // data object returned from twitter.com
	var fmt=store.getTiddlerText('TwitterTabs##tweetformat');
	if (data.results) data=data.results; // for SEARCH results
	removeChildren(window.twitterPlace);
	for (var i=0; i<data.length; i++) { var item=data[i];
		var img=item.user? item.user.profile_image_url : item.profile_image_url;
		var who=item.user? item.user.screen_name : item.from_user;
		wikify(fmt.format([img,who,item.text,item.created_at]),window.twitterPlace);
	}
}
'';}}>>
!end

%/<<tiddler {{tiddler&&tiddler.title=='TwitterTabs'?'HideTiddlerBackground':''}}>>/%
%/<<tiddler {{tiddler&&tiddler.title=='TwitterTabs'?'HideTiddlerTags':''}}>>/%
%/<<tiddler TwitterTabs##tabset>>
/***
|Name|UndoPlugin|
|Author|Eric Shulman|
|Source|http://www.TiddlyTools.com/#UndoPlugin|
|Documentation|http://www.TiddlyTools.com/#UndoPlugin|
|Version|0.2.1|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|undo/redo changes to tiddlers|
|Status|Experimental - DO NOT DISTRIBUTE|
This plugin records changes to tiddlers edited during the session, allowing you to quickly revert to previous revisions of a tiddler, even after pressing 'done'.
!!!!!Documentation
<<<
TBD
<<<
!!!!!Configuration
<<<
<<option chkEnableUndo>> enable undo handling
<<<
!!!!!Revisions
<<<
2011.09.11 0.2.1 in setmsg(), make sure undo stack is not empty.  In go(), make sure index is >0.  added disabledmsg with option checkbox.  In render(), use wikify() to display static menu content (noundomsg/disabledmsg)
2011.09.07 0.2.0 refactored click handler and added toolbar command wrapper
2011.05.15 0.1.1 edits to message text
2011.05.02 0.1.0 started
<<<
!!!!!Code
***/
//{{{
version.extensions.UndoPlugin= {major: 0, minor: 2, revision: 1, date: new Date(2011,9,11)};

if (config.options.chkEnableUndo===undefined) config.options.chkEnableUndo=true;

config.macros.undo =  {
	label: 'undo',
	prompt: 'undo changes',
        tip: 'undo changes to "%0"',
	multimsg: 'Undo %0 tiddler changes.  Are you sure?',
	revertedmsg: '"%0" - previous content restored',
	renamedmsg: '"%0" - renamed to "%1"',
	deletedmsg: '"%0" - removed',
	shadowmsg: '"%0" - default (shadow) content restored',
	noundomsg: 'nothing to undo',
	disabledmsg: 'undo is disabled\n----\n<<option chkEnableUndo>>enable undo',
	undoheading: 'undo tiddler changes:',
	dateformat: 'YYYY.0MM.0DD 0hh:0mm:0ss',
	popupformat: '%1 %0<div style="font-size:80%"><i>action: </i><b>%2</b></div>',
	changes: [], // the list of previous tiddler changes
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		var p=paramString.parseParams('name',null,true,false,true);
		var label=getParam(p,'label',this.label);
		var prompt=getParam(p,'prompt',this.prompt);
		createTiddlyButton(place,label,prompt,this.click);
	},
	click: function(ev){
		var p=Popup.create(this); if (!p) return false;
		config.macros.undo.render(p);
		Popup.show();
		ev=ev||window.event; ev.cancelBubble=true;
		if(ev.stopPropagation) ev.stopPropagation();
		return false;
	},
	render: function(p) {
		var cmu=config.macros.undo; // abbrev
		if (!config.options.chkEnableUndo) wikify(cmu.disabledmsg,p);
		else if (!cmu.changes.length) wikify(cmu.noundomsg,p);
		else {
			createTiddlyText(p, cmu.undoheading);
			for (var i=cmu.changes.length-1; i>=0; i--) { var c=cmu.changes[i]; var t=c.tiddler;
				var b=createTiddlyButton(createTiddlyElement(p,'li'),
					c.title, cmu.tip.format([c.title]),
					function(ev){return config.macros.undo.go(this.getAttribute('i'));});
				b.innerHTML=cmu.popupformat.format(
					[c.title,c.when.formatString(cmu.dateformat),c.msg]);
				b.setAttribute('i',i);
			}
		}
	},
	add: function(title,tiddler,action,msg){
		this.changes.push({
			title:title,
			tiddler:merge({},tiddler),
			action: action, // create, rename, change, delete
			when: new Date(),
			who: config.options.txtUserName,
			msg: msg
		});
	},
	setmsg: function(msg) {
		if (this.changes.length) this.changes[this.changes.length-1].msg=msg;
	},
	reset: function(i){
		while (this.changes.length) this.changes.pop();
	},
	go: function(i){
		var co=config.options; // abbrev
		var steps=this.changes.length-i; if (steps<0) return false;
		if (steps>1 && !confirm(this.multimsg.format([steps]))) return false;
		var temp=co.chkEnableUndo; co.chkEnableUndo=false; // SUSPEND undo
		var msgs=[];
		for (var j=this.changes.length; j>i; j--) {
			var c=this.changes.pop();
			if (c.action=='create') {
				store.removeTiddler(c.title);
				m=store.isShadowTiddler(c.title)?this.shadowmsg:this.deletedmsg;
				msgs.push(m.format([c.title]));
			} else {
				var t=c.tiddler;
				var revert=store.getTiddlerText(c.title)!=t.text;
				var rename=c.title!=t.title
				store.saveTiddler(t.title,t.title,t.text,
					t.modifier,t.modified,t.tags,t.fields);
				if (rename) { // RENAME: re-render with previous name
					var tidelem=story.getTiddler(c.title);
					if (tidelem) { // if displayed, re-render with previous name
						story.displayTiddler(tidelem,t.title);
						story.closeTiddler(c.title);
					}
					store.removeTiddler(c.title);
					msgs.push(this.renamedmsg.format([c.title,t.title]));
				}
				if (revert) msgs.push(this.revertedmsg.format([t.title]));
			}
		}
		co.chkEnableUndo=temp; // RESUME undo
		while (msgs.length) displayMessage(msgs.shift());
		autoSaveChanges();
		return false;
	}
};
//}}}
// // TOOLBAR COMMAND: undo
//{{{
config.commands.undoChanges = {
	text: 'undo',
	hideReadOnly: true,
	tooltip: 'undo individual document changes since the last save',
	handler: function(ev,src,title) { return config.macros.undo.click.call(src,ev); }
};
//}}}
// // HIJACKS - update changes when a tiddler is saved or deleted
//{{{
if (store.undo_saveTiddler==undefined) store.undo_saveTiddler=store.saveTiddler;
store.saveTiddler = function(title,newTitle,text) {
	var tiddler=store.getTiddler(title);
	if (config.options.chkEnableUndo) {
		var msgs=[];
		if (!tiddler) {
			var action='create';
			msgs.push('remove "'+newTitle+'"');
			if (store.isShadowTiddler(newTitle))
				msgs.push('use default (shadow) content');
		} else {
			var action=title!=newTitle?'rename':'change';
			if (action=='rename') {
				msgs.push('rename to "'+title+'"');
			}
			if (store.getTiddlerText(title)!=text || !msgs.length)
				msgs.push('restore previous content');
		}
		config.macros.undo.add(newTitle,tiddler,action,msgs.join(', '));
	}
	this.undo_saveTiddler.apply(this,arguments);
}
if (store.undo_removeTiddler==undefined) store.undo_removeTiddler=store.removeTiddler;
store.removeTiddler = function(title) {
	var tiddler=store.getTiddler(title);
	if (tiddler && config.options.chkEnableUndo) {
		var action='delete';
		var msg='restore deleted tiddler';
		config.macros.undo.add(title,tiddler,action,msg);
	}
	this.undo_removeTiddler.apply(this,arguments);
}
//}}}
/***
|Name|UnsavedChangesPlugin|
|Source|http://www.TiddlyTools.com/#UnsavedChangesPlugin|
|Version|3.3.6|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|show droplist of tiddlers that have changed since the last time the document was saved|
Display a list of tiddlers that have been changed since the last time the document was saved.  The list includes all new/modified tiddlers as well as those changed with "minor edits" enabled and any tiddlers that you import during the session, regardless of their modification date.
!!!!!Usage
<<<
{{{
<<unsavedChanges panel>> or <<unsavedChanges>>
}}}
{{indent{
the ''panel'' keyword displays a 'control panel' interface containing a droplist of unsaved tiddlers and a 'goto' button, along with a command link to 'save changes'.  Depending upon what other plugins are installed, several additional elements will also be displayed: When [[NestedSlidersPlugin]] is installed, the entire control panel is contained within a ''SLIDER''.  When [[LoadTiddlersPlugin]] is installed, a ''REVERT'' button is added.  When [[SaveAsPlugin]] is installed, a ''SAVE AS'' link is added.  When [[UploadPlugin]] is installed, an ''UPLOAD'' (or ''save to web'') link is added.  When [[TrashPlugin]] is installed and there are tiddlers tagged with<<tag Trash>>, an ''EMPTY TRASH'' link is added.
}}}
{{{
<<unsavedChanges list separator>>
}}}
{{indent{
the ''list'' keyword displays a simple space-separated list of unsaved tiddlers without any other command links.  You can specify an optional ''separator'' value that can be used in place of the default space character.  For example, you can specify {{{"<br>"}}} as the separator in order to display each link, one per line.
}}}
{{{
<<unsavedChanges command label tip>>
}}}
{{indent{
the ''command'' keyword displays a single 'command link' that, when clicked, displays a ~TiddlyWiki popup containing the list of unsaved tiddlers, the 'save changes' command and, depending upon what other plugins are installed, additional commands for 'save as', 'upload', and 'empty trash' (similar to the panel display described above).

You can specify optional ''label'' and ''tip'' parameters in the macro to customize the command link text and tooltip.  The default label for the command link is: "There %1 %0 unsaved tiddler%2...", where:
* %0 is automatically replaced with the number of unsaved changes
* %1 is either "is" (if changes=1) or "are" (if changes>1)
* %2 is either blank (if changes=1) or "s" (if changes>1)
resulting in the text: //"There is 1 unsaved tiddler...", "There are 2 unsaved tiddlers...", etc.//
}}}
<<<
!!!!!Examples
<<<
^^//note: the following examples will not display any output unless you have already created/modified tiddlers in the current document.//^^
{{{<<unsavedChanges>>}}}
<<unsavedChanges>>
----
{{{<<unsavedChanges command>>}}}
<<unsavedChanges command>>
----
{{{<<unsavedChanges list>>}}}
<<unsavedChanges list>>
----
{{{<<unsavedChanges list "<br>">>}}}
<<unsavedChanges list "<br>">>
<<<
!!!!!Revisions
<<<
2011.11.27 3.3.6 in panel(), command(), and list(), check for null 'place' (maybe caused if tiddlers are modified by a plugin during startup 'init' handling)
2011.04.29 3.3.5 in panel(), use custom label (if provided).  Also, removed "small" style from panel commands so surrounding CSS font size will be used.
2010.12.05 3.3.4 display 'save as...' command even if readOnly
2009.03.02 3.3.3 fix handling for titles that contain HTML special chars (lt,gt,quot,amp)
2008.09.02 3.3.2 cleanup popup list output generation and added timestamps/sizes to popup display
2008.08.23 3.3.1 added optional custom 'label' and 'tip' params to 'command' mode and defined default values for mode, label, tip, and separator as object properties for I18N/L10N-readiness.
2008.08.21 3.3.0 complete re-write of rendering and refresh processing to support multiple instances and automatic self-refresh (no longer depends upon core refresh notifications)
2008.08.21 3.2.0 added 'command' option for link+popup as alternative to 'control panel' interface
2008.04.22 3.1.2 use SaveAsPlugin instead of obsolete NewDocumentPlugin to add "save as" link
2007.12.22 3.1.1 hijack removeTiddler() instead of low-level deleteTiddler() to correct tracking and refresh handling issues.  in saveTiddler(), check for 'tiddler rename' (title!=newtitle) and adjust list accordingly.
2007.12.21 3.1.0 added support for {{{<<unsavedChanges list separator>>}}} usage to unsaved tiddlers as a simple list of links, embedded in tiddler content (e.g., [[MainMenu]])
2007.12.20 3.0.0 rewrite to track ALL changed tiddlers, including imports and minor edits, regardless of saved modification dates.  Also, rewrote display logic to directly refresh macro output instead of triggering a page refresh.  The entire process is MUCH more efficient now.
2007.08.02 2.0.0 converted from inline script
2007.01.01 1.0.0 initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.UnsavedChangesPlugin= {major: 3, minor: 3, revision: 6, date: new Date(2011,12,27)};

config.macros.unsavedChanges = {
	changed: [], // list of currently unsaved tiddler titles
	defMode: "panel",
	defSep: " ",
	defLabel: "There %1 %0 unsaved tiddler%2",
	defTip: "view a list of unsaved tiddler changes",
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		var wrapper=createTiddlyElement(place,"span",null,"unsavedChanges");
		wrapper.setAttribute("mode",params[0]||this.defMode);
		wrapper.setAttribute("sep",params[1]||this.defSep); // for 'list' mode
		wrapper.setAttribute("label",params[1]||this.defLabel); // for 'command' mode
		wrapper.setAttribute("tip",params[2]||this.defTip); // for 'command' mode
		this.render(wrapper);
	},
	render: function(wrapper) {
		removeChildren(wrapper); // make sure its empty
		if (!this.changed.length) return; // no changes = no output
		switch (wrapper.getAttribute("mode")) {
			case "command": this.command(wrapper); break;
			case "list": this.list(wrapper); break;
			case "panel": default: this.panel(wrapper); break;
		}
	},
	refresh: function() {
		var wrappers=document.getElementsByTagName("span");
		for (var w=0; w<wrappers.length; w++)
			if (hasClass(wrappers[w],"unsavedChanges"))
				this.render(wrappers[w]);
	},
	list: function(place) { // show simple list of unsaved tiddlers
		if (!place) return;
		wikify("[["+this.changed.join("]]"+place.getAttribute("sep")+"[[")+"]]",place);
	},
	command: function(place) { // show command link with popup list
		if (!place) return;
		var c=this.changed.length;
		var txt=place.getAttribute("label").format([c,c==1?'is':'are',c==1?'':'s']);
		var tip=place.getAttribute("tip");
		var action=function(ev) { if (!ev) var ev=window.event;
			var p=Popup.create(this); if (!p) return false;
			var d=createTiddlyElement(p,"div");
			d.style.whiteSpace="normal"; d.style.width="auto"; d.style.padding="2px";
			// gather pretty links for changed tiddlers
			var list=[]; var item=" &nbsp;[[%1 - %0 (%2 bytes)|%0]]&nbsp; ";
			for (var i=config.macros.unsavedChanges.changed.length-1; i>=0; i--) {
				var tid=store.getTiddler(config.macros.unsavedChanges.changed[i]);
				if (!tid) continue;
				var when=tid.modified.formatString('YYYY.0MM.0DD 0hh:0mm:0ss');
				list.push(item.format([tid.title,when,tid.text.length]));
			}
			wikify("@@white-space:nowrap;"+list.join("<br>")+"@@",d);
			var t="\n----\n";
			t+="@@white-space:nowrap;display:block;text-align:center; &nbsp;";
			if (!readOnly) {
				t+="<<saveChanges>>";
				t+=config.macros.saveAs?" | <<saveAs>>":"";
				t+=config.macros.upload?" | <<upload>>":"";
				t+=(config.macros.emptyTrash&&store.getTaggedTiddlers("Trash").length)?" | <<emptyTrash>>":"";
			} else {
				t+=config.macros.saveAs?"<<saveAs>>":"";
			}
			t+="&nbsp; @@";
			wikify(t,d);
			Popup.show();
			ev.cancelBubble=true; if(ev.stopPropagation)ev.stopPropagation();
			return(false);
		}
		createTiddlyButton(place,txt,tip,action,"button");
	},
	panel: function(place) { // show composite droplist+buttons+commands
		if (!place) return;
		// gather changed tiddlers (in reverse order by date - most recent first)
		var tids=[]; for (var i=this.changed.length-1; i>=0; i--)
			{ var t=store.getTiddler(this.changed[i]); if (t) tids.push(t); }
		tids.sort(function(a,b){return a.modified<b.modified?-1:(a.modified==b.modified?0:1);});
		// generate droplist items
 		var list=[]; var item='<option value="%0">%1 - %0 (%2 bytes)</option>';
		for (var i=tids.length-1; i>=0; i--) {
			var when=tids[i].modified.formatString('YYYY.0MM.0DD 0hh:0mm:0ss');
			list.push(item.format([tids[i].title.htmlEncode(),when,tids[i].text.length]));
		}
		// display droplist, buttons, and command links
		var out=''; var c=this.changed.length;
		var NSP=config.formatters.findByField("name","nestedSliders");
		var summary=place.getAttribute("label").format([c,c==1?'is':'are',c==1?'':'s']);
		out+=NSP?'+++(unsaved)['+summary+'|'+this.defTip+']...':(summary+"\n");
		out+='<html><form style="display:inline"><!--\
			--><select size="1" name="list" \
				title="select a tiddler to view" \
				onchange="var v=this.value; if (v.length) story.displayTiddler(null,v);"><!--\
			-->'+list.join('')+'<!--\
			--></select><!--\
			--><input type="button" value="goto" onclick="this.form.list.onchange();">';
		if (config.macros.loadTiddlers)  {
			out+='<input type="button" value="revert" \
				title="import the last saved version of this tiddler" \
				onclick="var v=this.form.list.value; if (!v.length) return; \
					var t=\'<\'+\'<loadTiddlers [[tiddler:\'+v+\']] \'; \
					t+=document.location.href; \
					t+=\' confirm force noreport>\'+\'>\'; \
					var e=document.getElementById(\'executeRevert\'); \
					if (e) e.parentNode.removeChild(e); \
					e=document.createElement(\'span\'); \
					e.id=\'executeRevert\'; \
					wikify(t,e);">';
		}
		out+='</form></html>';
		out+='\n{{nowrap{';
		if (!readOnly) {
			out+="<<saveChanges>>";
			out+=config.macros.saveAs?" | <<saveAs>>":"";
			out+=config.macros.upload?" | <<upload>>":"";
			out+=(config.macros.emptyTrash&&store.getTaggedTiddlers("Trash").length)?" | <<emptyTrash>>":"";
		} else {
			out+=config.macros.saveAs?"<<saveAs>>":"";
		}
		out+='}}}';
		out+=NSP?'===':'';
		wikify(out,place);
	}
};

// hijack store.saveTiddler() to track changes to tiddlers
if (store.showUnsaved_saveTiddler==undefined) {
	store.showUnsaved_saveTiddler=store.saveTiddler;
	store.saveTiddler=function(title,newtitle) {
		if (title!=newtitle) {
			var i=config.macros.unsavedChanges.changed.indexOf(title);
			if (i!=-1) config.macros.unsavedChanges.changed.splice(i,1); // remove old from list
		} 
		var i=config.macros.unsavedChanges.changed.indexOf(newtitle);
		if (i!=-1) config.macros.unsavedChanges.changed.splice(i,1); // remove new title from list
		config.macros.unsavedChanges.changed.push(newtitle); // add new title to END of list
		var t=this.showUnsaved_saveTiddler.apply(this,arguments);
		if (!this.notificationLevel) config.macros.unsavedChanges.refresh();
		return t;
	}
}

// hijack store.removeTiddler() to track changes to tiddlers
if (store.showUnsaved_removeTiddler==undefined) {
	store.showUnsaved_removeTiddler=store.removeTiddler;
	store.removeTiddler=function(title) {
		var i=config.macros.unsavedChanges.changed.indexOf(title);
		if (i!=-1) config.macros.unsavedChanges.changed.splice(i,1); // remove from list
		this.showUnsaved_removeTiddler.apply(this,arguments);
		if (!this.notificationLevel) config.macros.unsavedChanges.refresh();
	}
}

// hijack store.setDirty() function to reset change list after file save
// note: do NOT hijack the prototype function.  This hijack should only be applied to
// the main 'store' instance only (i.e., don't refresh when loading temporary store
// as part of ImportTiddlers processing)
if (store.showUnsaved_setDirty==undefined) {
	store.showUnsaved_setDirty=store.setDirty;
	store.setDirty = function(flag) {
		var refresh=this.isDirty() && !flag; // 'dirty' to 'clean', force a refresh...
		this.showUnsaved_setDirty.apply(this,arguments); // but change the flag first.
		if (refresh) {
			config.macros.unsavedChanges.changed=[]; // clear changed list
			config.macros.unsavedChanges.refresh();
		}
	}
}
//}}}
/***
<<tiddler UploadPluginDoc>>
!Code
***/
//{{{

// // ***** ELS 2008.09.08
// // ***** DISABLED OVERRIDE OF saveOptionCookie()
// // ***** TO PREVENT CONFLICT WITH CookieJarPlugin

version.extensions.UploadPlugin = {
 major: 3, minor: 3, revision: 1, 
 date: new Date(2006,3,30),
 type: 'macro',
 source: 'http://tiddlywiki.bidix.info/#UploadPlugin',
 docs: 'http://tiddlywiki.bidix.info/#UploadPluginDoc'
};
//}}}

////+++!![config.lib.file]

//{{{
if (!config.lib) config.lib = {};
if (!config.lib.file) config.lib.file= {
 author: 'BidiX',
 version: {major: 0, minor: 1, revision: 0}, 
 date: new Date(2006,3,9)
};
config.lib.file.dirname = function (filePath) {
 var lastpos;
 if ((lastpos = filePath.lastIndexOf("/")) != -1) {
 return filePath.substring(0, lastpos);
 } else {
 return filePath.substring(0, filePath.lastIndexOf("\\"));
 }
};
config.lib.file.basename = function (filePath) {
 var lastpos;
 if ((lastpos = filePath.lastIndexOf("#")) != -1) 
 filePath = filePath.substring(0, lastpos);
 if ((lastpos = filePath.lastIndexOf("/")) != -1) {
 return filePath.substring(lastpos + 1);
 } else
 return filePath.substring(filePath.lastIndexOf("\\")+1);
};
window.basename = function() {return "@@deprecated@@";};
//}}}
////===

////+++!![config.lib.log]

//{{{
if (!config.lib) config.lib = {};
if (!config.lib.log) config.lib.log= {
 author: 'BidiX',
 version: {major: 0, minor: 1, revision: 0}, 
 date: new Date(2006,3,9)
};
config.lib.Log = function(tiddlerTitle, logHeader) {
 if (version.major < 2)
 this.tiddler = store.tiddlers[tiddlerTitle];
 else
 this.tiddler = store.getTiddler(tiddlerTitle);
 if (!this.tiddler) {
 this.tiddler = new Tiddler();
 this.tiddler.title = tiddlerTitle;
 this.tiddler.text = "| !date | !user | !location |" + logHeader;
 this.tiddler.created = new Date();
 this.tiddler.modifier = config.options.txtUserName;
 this.tiddler.modified = new Date();
 if (version.major < 2)
 store.tiddlers[tiddlerTitle] = this.tiddler;
 else
 store.addTiddler(this.tiddler);
 }
 return this;
};

config.lib.Log.prototype.newLine = function (line) {
 var now = new Date();
 var newText = "| ";
 newText += now.getDate()+"/"+(now.getMonth()+1)+"/"+now.getFullYear() + " ";
 newText += now.getHours()+":"+now.getMinutes()+":"+now.getSeconds()+" | ";
 newText += config.options.txtUserName + " | ";
 var location = document.location.toString();
 var filename = config.lib.file.basename(location);
 if (!filename) filename = '/';
 newText += "[["+filename+"|"+location + "]] |";
 this.tiddler.text = this.tiddler.text + "\n" + newText;
 this.addToLine(line);
};

config.lib.Log.prototype.addToLine = function (text) {
 this.tiddler.text = this.tiddler.text + text;
 this.tiddler.modifier = config.options.txtUserName;
 this.tiddler.modified = new Date();
 if (version.major < 2)
 store.tiddlers[this.tiddler.tittle] = this.tiddler;
 else {
 store.addTiddler(this.tiddler);
 story.refreshTiddler(this.tiddler.title);
 store.notify(this.tiddler.title, true);
 }
 if (version.major < 2)
 store.notifyAll(); 
};
//}}}
////===

////+++!![config.lib.options]

//{{{
if (!config.lib) config.lib = {};
if (!config.lib.options) config.lib.options = {
 author: 'BidiX',
 version: {major: 0, minor: 1, revision: 0}, 
 date: new Date(2006,3,9)
};

config.lib.options.init = function (name, defaultValue) {
 if (!config.options[name]) {
 config.options[name] = defaultValue;
 saveOptionCookie(name);
 }
};
//}}}
////===

////+++!![PasswordTweak]

//{{{
version.extensions.PasswordTweak = {
 major: 1, minor: 0, revision: 2, date: new Date(2006,3,11),
 type: 'tweak',
 source: 'http://tiddlywiki.bidix.info/#PasswordTweak'
};
//}}}
/***
!!config.macros.option
***/
//{{{
config.macros.option.passwordCheckboxLabel = "Save this password on this computer";
config.macros.option.passwordType = "password"; // password | text

config.macros.option.onChangeOption = function(e)
{
 var opt = this.getAttribute("option");
 var elementType,valueField;
 if(opt) {
 switch(opt.substr(0,3)) {
 case "txt":
 elementType = "input";
 valueField = "value";
 break;
 case "pas":
 elementType = "input";
 valueField = "value";
 break;
 case "chk":
 elementType = "input";
 valueField = "checked";
 break;
 }
 config.options[opt] = this[valueField];
 saveOptionCookie(opt);
 var nodes = document.getElementsByTagName(elementType);
 for(var t=0; t<nodes.length; t++) {
 var optNode = nodes[t].getAttribute("option");
 if (opt == optNode) 
 nodes[t][valueField] = this[valueField];
 }
 }
 return(true);
};

/****** ELS 2009.07.23 ******* DISABLED HIJACK TO PREVENT CONFLICTS WITH AdvancedOptionsPlugin
config.macros.option.handler = function(place,macroName,params)
{
 var opt = params[0];
 var size = 15;
 if (params[1])
 size = params[1];
 if(config.options[opt] === undefined) {
 return;}
 var c;
 switch(opt.substr(0,3)) {
 case "txt":
 c = document.createElement("input");
 c.onkeyup = this.onChangeOption;
 c.setAttribute ("option",opt);
 c.size = size;
 c.value = config.options[opt];
 place.appendChild(c);
 break;
 case "pas":
 // input password
 c = document.createElement ("input");
 c.setAttribute("type",config.macros.option.passwordType);
 c.onkeyup = this.onChangeOption;
 c.setAttribute("option",opt);
 c.size = size;
 c.value = config.options[opt];
 place.appendChild(c);
 // checkbox link with this password "save this password on this computer"
 c = document.createElement("input");
 c.setAttribute("type","checkbox");
 c.onclick = this.onChangeOption;
 c.setAttribute("option","chk"+opt);
 place.appendChild(c);
 c.checked = config.options["chk"+opt];
 // text savePasswordCheckboxLabel
 place.appendChild(document.createTextNode(config.macros.option.passwordCheckboxLabel));
 break;
 case "chk":
 c = document.createElement("input");
 c.setAttribute("type","checkbox");
 c.onclick = this.onChangeOption;
 c.setAttribute("option",opt);
 place.appendChild(c);
 c.checked = config.options[opt];
 break;
 }
};
*************************/
//}}}
/***
!! Option cookie stuff
***/
//{{{
window.loadOptionsCookie_orig_PasswordTweak = window.loadOptionsCookie;
window.loadOptionsCookie = function()
{
 var cookies = document.cookie.split(";");
 for(var c=0; c<cookies.length; c++) {
 var p = cookies[c].indexOf("=");
 if(p != -1) {
 var name = cookies[c].substr(0,p).trim();
 var value = cookies[c].substr(p+1).trim();
 switch(name.substr(0,3)) {
 case "txt":
 config.options[name] = unescape(value);
 break;
 case "pas":
 config.options[name] = unescape(value);
 break;
 case "chk":
 config.options[name] = value == "true";
 break;
 }
 }
 }
};

/****** ELS 2008.09.08 ******* DISABLED HIJACK TO PREVENT CONFLICTS WITH CookieManagerPlugin
window.saveOptionCookie_orig_PasswordTweak = window.saveOptionCookie;
window.saveOptionCookie = function(name)
{
 var c = name + "=";
 switch(name.substr(0,3)) {
 case "txt":
 c += escape(config.options[name].toString());
 break;
 case "chk":
 c += config.options[name] ? "true" : "false";
 // is there an option link with this chk ?
 if (config.options[name.substr(3)]) {
 saveOptionCookie(name.substr(3));
 }
 break;
 case "pas":
 if (config.options["chk"+name]) {
 c += escape(config.options[name].toString());
 } else {
 c += "";
 }
 break;
 }
 c += "; expires=Fri, 1 Jan 2038 12:00:00 UTC; path=/";
 document.cookie = c;
};
*****************************************/
//}}}
/***
!! Initializations
***/
//{{{
// define config.options.pasPassword
if (!config.options.pasPassword) {
 config.options.pasPassword = 'defaultPassword';
 window.saveOptionCookie('pasPassword');
}
// since loadCookies is first called befor password definition
// we need to reload cookies
window.loadOptionsCookie();
//}}}
////===

////+++!![config.macros.upload]

//{{{
config.macros.upload = {
 accessKey: "U",
 formName: "UploadPlugin",
 contentType: "text/html;charset=UTF-8",
 defaultStoreScript: "store.php"
};

// only this two configs need to be translated
config.macros.upload.messages = {
 aboutToUpload: "About to upload TiddlyWiki to %0",
 errorDownloading: "Error downloading",
 errorUploadingContent: "Error uploading content",
 fileNotFound: "file to upload not found",
 fileNotUploaded: "File %0 NOT uploaded",
 mainFileUploaded: "Main TiddlyWiki file uploaded to %0",
 urlParamMissing: "url param missing",
 rssFileNotUploaded: "RssFile %0 NOT uploaded",
 rssFileUploaded: "Rss File uploaded to %0"
};

config.macros.upload.label = {
 promptOption: "Save and Upload this TiddlyWiki with UploadOptions",
 promptParamMacro: "Save and Upload this TiddlyWiki in %0",
 saveLabel: "save to web", 
 saveToDisk: "save to disk",
 uploadLabel: "upload" 
};

config.macros.upload.handler = function(place,macroName,params){
 // parameters initialization
 var storeUrl = params[0];
 var toFilename = params[1];
 var backupDir = params[2];
 var uploadDir = params[3];
 var username = params[4];
 var password; // for security reason no password as macro parameter
 var label;
 if (document.location.toString().substr(0,4) == "http")
 label = this.label.saveLabel;
 else
 label = this.label.uploadLabel;
 var prompt;
 if (storeUrl) {
 prompt = this.label.promptParamMacro.toString().format([this.dirname(storeUrl)]);
 }
 else {
 prompt = this.label.promptOption;
 }
 createTiddlyButton(place, label, prompt, 
 function () {
 config.macros.upload.upload(storeUrl, toFilename, uploadDir, backupDir, username, password); 
 return false;}, 
 null, null, this.accessKey);
};
config.macros.upload.UploadLog = function() {
 return new config.lib.Log('UploadLog', " !storeUrl | !uploadDir | !toFilename | !backupdir | !origin |" );
};
config.macros.upload.UploadLog.prototype = config.lib.Log.prototype;
config.macros.upload.UploadLog.prototype.startUpload = function(storeUrl, toFilename, uploadDir, backupDir) {
 var line = " [[" + config.lib.file.basename(storeUrl) + "|" + storeUrl + "]] | ";
 line += uploadDir + " | " + toFilename + " | " + backupDir + " |";
 this.newLine(line);
};
config.macros.upload.UploadLog.prototype.endUpload = function() {
 this.addToLine(" Ok |");
};
config.macros.upload.basename = config.lib.file.basename;
config.macros.upload.dirname = config.lib.file.dirname;
config.macros.upload.upload = function(storeUrl, toFilename, uploadDir, backupDir, username, password)
{
 // parameters initialization
 storeUrl = (storeUrl ? storeUrl : config.options.txtUploadStoreUrl);
 toFilename = (toFilename ? toFilename : config.options.txtUploadFilename);
 if (toFilename === '') {
 toFilename = config.lib.file.basename(document.location.toString());
 }
 backupDir = (backupDir ? backupDir : config.options.txtUploadBackupDir);
 uploadDir = (uploadDir ? uploadDir : config.options.txtUploadDir);
 username = (username ? username : config.options.txtUploadUserName);
 password = config.options.pasUploadPassword; // for security reason no password as macro parameter

 clearMessage();
 // only for forcing the message to display
 if (version.major < 2)
 store.notifyAll();
 if (!storeUrl) {
 alert(config.macros.upload.messages.urlParamMissing);
 return;
 }
 
 var log = new this.UploadLog();
 log.startUpload(storeUrl, toFilename, uploadDir, backupDir);
 if (document.location.toString().substr(0,5) == "file:") {
 saveChanges();
 }
 displayMessage(config.macros.upload.messages.aboutToUpload.format([this.dirname(storeUrl)]), this.dirname(storeUrl));
 this.uploadChanges(storeUrl, toFilename, uploadDir, backupDir, username, password);
 if(config.options.chkGenerateAnRssFeed) {
 //var rssContent = convertUnicodeToUTF8(generateRss());
 var rssContent = generateRss();
 var rssPath = toFilename.substr(0,toFilename.lastIndexOf(".")) + ".xml";
 this.uploadContent(rssContent, storeUrl, rssPath, uploadDir, '', username, password, 
 function (responseText) {
 if (responseText.substring(0,1) != '0') {
 displayMessage(config.macros.upload.messages.rssFileNotUploaded.format([rssPath]));
 }
 else {
 if (uploadDir) {
 rssPath = uploadDir + "/" + config.macros.upload.basename(rssPath);
 } else {
 rssPath = config.macros.upload.basename(rssPath);
 }
 displayMessage(config.macros.upload.messages.rssFileUploaded.format(
 [config.macros.upload.dirname(storeUrl)+"/"+rssPath]), config.macros.upload.dirname(storeUrl)+"/"+rssPath);
 }
 // for debugging store.php uncomment last line
 //DEBUG alert(responseText);
 });
 }
 return;
};

config.macros.upload.uploadChanges = function(storeUrl, toFilename, uploadDir, backupDir, 
 username, password) {
 var original;
 if (document.location.toString().substr(0,4) == "http") {
 original = this.download(storeUrl, toFilename, uploadDir, backupDir, username, password);
 return;
 }
 else {
 // standard way : Local file
 
 original = loadFile(getLocalPath(document.location.toString()));
 if(window.Components) {
 // it's a mozilla browser
 try {
 netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
 var converter = Components.classes["@mozilla.org/intl/scriptableunicodeconverter"]
 .createInstance(Components.interfaces.nsIScriptableUnicodeConverter);
 converter.charset = "UTF-8";
 original = converter.ConvertToUnicode(original);
 }
 catch(e) {
 }
 }
 }
 //DEBUG alert(original);
 this.uploadChangesFrom(original, storeUrl, toFilename, uploadDir, backupDir, 
 username, password);
};

config.macros.upload.uploadChangesFrom = function(original, storeUrl, toFilename, uploadDir, backupDir, 
 username, password) {
 var startSaveArea = '<div id="' + 'storeArea">'; // Split up into two so that indexOf() of this source doesn't find it
 var endSaveArea = '</d' + 'iv>';
 // Locate the storeArea div's
 var posOpeningDiv = original.indexOf(startSaveArea);
 var posClosingDiv = original.lastIndexOf(endSaveArea);
 if((posOpeningDiv == -1) || (posClosingDiv == -1))
 {
 alert(config.messages.invalidFileError.format([document.location.toString()]));
 return;
 }
 var revised = original.substr(0,posOpeningDiv + startSaveArea.length) + 
 store.allTiddlersAsHtml() + "\n\t\t" +
 original.substr(posClosingDiv);
 var newSiteTitle;
 if(version.major < 2){
 newSiteTitle = (getElementText("siteTitle") + " - " + getElementText("siteSubtitle")).htmlEncode();
 } else {
 newSiteTitle = (wikifyPlain ("SiteTitle") + " - " + wikifyPlain ("SiteSubtitle")).htmlEncode();
 }
 revised = revised.replace(new RegExp("<title>[^<]*</title>", "im"),"<title>"+ newSiteTitle +"</title>");
 var response = this.uploadContent(revised, storeUrl, toFilename, uploadDir, backupDir, 
 username, password, function (responseText) {
 if (responseText.substring(0,1) != '0') {
 alert(responseText);
 displayMessage(config.macros.upload.messages.fileNotUploaded.format([getLocalPath(document.location.toString())]));
 }
 else {
 if (uploadDir !== '') {
 toFilename = uploadDir + "/" + config.macros.upload.basename(toFilename);
 } else {
 toFilename = config.macros.upload.basename(toFilename);
 }
 displayMessage(config.macros.upload.messages.mainFileUploaded.format(
 [config.macros.upload.dirname(storeUrl)+"/"+toFilename]), config.macros.upload.dirname(storeUrl)+"/"+toFilename);
 var log = new config.macros.upload.UploadLog();
 log.endUpload();
 store.setDirty(true); store.setDirty(false); // ELS - toggle to ensure notification event after upload
 }
 // for debugging store.php uncomment last line
 //DEBUG alert(responseText);
 }
 );
};

config.macros.upload.uploadContent = function(content, storeUrl, toFilename, uploadDir, backupDir, 
 username, password, callbackFn) {
 var boundary = "---------------------------"+"AaB03x"; 
 var request;
 try {
 request = new XMLHttpRequest();
 } 
 catch (e) { 
 request = new ActiveXObject("Msxml2.XMLHTTP"); 
 }
 if (window.netscape){
 try {
 if (document.location.toString().substr(0,4) != "http") {
 netscape.security.PrivilegeManager.enablePrivilege('UniversalBrowserRead');}
 }
 catch (e) { }
 } 
 //DEBUG alert("user["+config.options.txtUploadUserName+"] password[" + config.options.pasUploadPassword + "]");
 // compose headers data
 var sheader = "\r\n";
 sheader += "--" + boundary + "\r\nContent-disposition: form-data;name=\"";
 sheader += config.macros.upload.formName +"\"\r\n\r\n";
 sheader += "backupDir="+backupDir
 +";user=" + username 
 +";password=" + password
 +";uploaddir=" + uploadDir
 + ";;\r\n"; 
 sheader += "\r\n" + "--" + boundary + "\r\n";
 sheader += "Content-disposition: form-data;name=\"userfile\";filename=\""+toFilename+"\"\r\n";
 sheader += "Content-Type: " + config.macros.upload.contentType + "\r\n";
 sheader += "Content-Length: " + content.length + "\r\n\r\n";
 // compose trailer data
 var strailer = new String();
 strailer = "\r\n--" + boundary + "--\r\n";
 var data;
 data = sheader + content + strailer;
 //request.open("POST", storeUrl, true, username, password);
 request.open("POST", storeUrl, true);
 request.onreadystatechange = function () {
 if (request.readyState == 4) {
 if (request.status == 200)
 callbackFn(request.responseText);
 else
 alert(config.macros.upload.messages.errorUploadingContent);
 }
 };
 request.setRequestHeader("Content-Length",data.length);
 request.setRequestHeader("Content-Type","multipart/form-data; boundary="+boundary);
 request.send(data); 
};


config.macros.upload.download = function(uploadUrl, uploadToFilename, uploadDir, uploadBackupDir, 
 username, password) {
 var request;
 try {
 request = new XMLHttpRequest();
 } 
 catch (e) { 
 request = new ActiveXObject("Msxml2.XMLHTTP"); 
 }
 try {
 if (uploadUrl.substr(0,4) == "http") {
 netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");
 }
 else {
 netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
 }
 } catch (e) { }
 //request.open("GET", document.location.toString(), true, username, password);
 request.open("GET", document.location.toString(), true);
 request.onreadystatechange = function () {
 if (request.readyState == 4) {
 if(request.status == 200) {
 config.macros.upload.uploadChangesFrom(request.responseText, uploadUrl, 
 uploadToFilename, uploadDir, uploadBackupDir, username, password);
 }
 else
 alert(config.macros.upload.messages.errorDownloading.format(
 [document.location.toString()]));
 }
 };
 request.send(null);
};

//}}}
////===

////+++!![Initializations]

//{{{
config.lib.options.init('txtUploadStoreUrl','store.php');
config.lib.options.init('txtUploadFilename','');
config.lib.options.init('txtUploadDir','');
config.lib.options.init('txtUploadBackupDir','');
config.lib.options.init('txtUploadUserName',config.options.txtUserName);
config.lib.options.init('pasUploadPassword','');
config.shadowTiddlers.UploadPluginDoc = "[[Full Documentation|http://tiddlywiki.bidix.info/l#UploadPluginDoc ]]\n"; 


//}}}
////===

////+++!![Core Hijacking]

//{{{
config.macros.saveChanges.label_orig_UploadPlugin = config.macros.saveChanges.label;
config.macros.saveChanges.label = config.macros.upload.label.saveToDisk;
//}}}
////===
// null logger : no more UploadLog and no upload logging
// BidiX - 2006/11/8
//{{{
config.macros.upload.UploadLog = function() {return this;};
config.macros.upload.UploadLog.prototype.startUpload = function(storeUrl, toFilename, uploadDir,  backupDir) {};
config.macros.upload.UploadLog.prototype.endUpload = function() {};
//}}}
<!--{{{-->
<!--
|Name|ViewTemplate|
|Source|http://www.TiddlyTools.com/#ViewTemplate|
|Version||
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|template|
|Requires|ToolbarCommands, MoveablePanelPlugin, TiddlerIconsPlugin, FoldHeadingPlugin|
|Description|custom version of shadow template used to display tiddler for normal viewing|

Please note: This template contains customizations that are specific to TiddlyTools,
and should not be directly copied and installed into another document.  You should,
of course, use this template as an example of the syntax that is needed when adding
selected TiddlyTools components to your document.  Please feel free to copy-and-paste
the specfic portions of this template that apply to the particular TiddlyTools components
you are installing in your own document.
-->

<!-- MoveablePanelPlugin: make all tiddlers move-able and map-able -->
<!-- This outer 'class wrapper' provides the 'moveable panel' container that -->
<!-- will be modified by the moveablePanel macro at the end of this template -->
<div OFF_class='moveablePanel'> <!-- begin moveablePanel container -->

	<!-- ToolbarCommands: contains all custom toolbar changes as slices. -->
	<span class='toolbar' macro='toolbar [[ToolbarCommands::ViewToolbar]]'></span>

	<span class='title'>
		<!-- TiddlerIconsPlugin: adds small 'type/status' icons next to tiddler title -->
		<span class='floatleft' macro='tiddlerIcons' style='cursor:auto !important;'></span>
		<span macro='view title'></span>
	</span>
	<span class='subtitle' style='white-space:nowrap' macro='view modified date [[DDD, MMM DDth YYYY]]'></span>

	<div class='tagClear'></div>
	<div class='tagging' macro='tagging'></div>
	<div class='tagged' macro='tags'></div>
	<div class='viewer'>
		<span class='sectionTOC clear small floatright groupbox' style='display:none'>
			Table of Contents:
		</span>
		<div macro='view text wikified' title=''
			onmouseover='if (!this.title||!this.title.length)
				this.title="tiddler: "+story.findContainingTiddler(this).getAttribute("tiddler")'>
		</div>
	</div>
	<div class='tagClear'></div>

	<!-- "scroll to top of tiddler" button (direct inline HTML scripting):	-->
	<!-- puts 'uparrow' (x25B2) button in lower right of tiddler		-->
	<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>
	<div class='tagClear'></div>

	<!-- FoldHeadingsPlugin: turns heading (Hn) content into collapsed sliders.  See CoreTweaks for an example. -->
	<span macro='foldHeadings closed foldHeadings'></span>

	<!-- MoveablePanelPlugin: adds 'moveable' behavior to container.  -->
	<!-- MUST be the last element in container so it is invoked //after// all other content is rendered.  -->
	<!-- Uses tiddler title as panel name macro param, which requires CoreTweaks##444 or TiddlyWiki v2.5.0 (or later). -->
	<!-- See http://trac.tiddlywiki.org/ticket/444 for more info... -->
	<div OFF_macro='moveablePanel name:{{story.findContainingTiddler(place).getAttribute("tiddler")}} height:auto'></div>
</div> <!-- end moveablePanel container -->
<!--}}}-->
/%
!info
|Name|VisitCounter|
|Source|http://www.TiddlyTools.com/#VisitCounter|
|Version|3.0.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|Type|transclusion|
|Description|use cookies to track/show private, personal visit counter and timestamp of last visit|
Usage
<<<
Display a personal, ''//private// counter and timestamps'' for your first visit, your most recent visit, and the total number of times you have visited a document.  This data are stored in local cookies that can only be displayed in //your// browser, and are ''never relayed or reported to anyone other than yourself, nor stored or aggregated on-line in any way, __ever__.''
{{{
<<tiddler VisitCounter with: counterID firsttimegreeting>>
}}}
*''counterID'' (optional)<br>specifies a suffix to add to the visit tracking cookies for this document (enables tracking of multiple documents on a single domain, such as file://).  
*''firsttimegreeting'' (optional)<br>message to display upon first visit to the document.  Subsequent visits report last visit timestamp and total visit count.
The following cookies are used to track your visit information:
*txtFirstVisit+id
*txtLastVisit+id
*txtVisitCount+id
The script also defines global javascript run-time variables that may be referenced later in the current session by other scripts and plugins:
*config.firstVisit
*config.lastVisit
*config.visitCount
<<<
Example
<<<
{{{<<tiddler VisitCounter with: TiddlyTools>>}}}
<<tiddler VisitCounter##show with: TiddlyTools>>
<<<
Revisions
<<<
2009.09.30 [3.0.0] converted to pure TW transclusion (no dependencies)
2008.07.01 [2.1.0] simplified to inline script
2007.07.26 [2.0.0] re-written as plugin
2007.05.02 [1.0.0] initial release (as inline script, VisitCounter)
<<<
!end

!outputFormat
This is your <html><nowiki><a href="javascript:;"
title="Reset personal visit counter"
onclick="if (!confirm('Are you sure you want to reset your personal visit counter?')) return false;
	config.visitCount=1; config.firstVisit=config.lastVisit=new Date();
	config.macros.option.propagateOption('txtVisitCount%0','value',config.visitCount,'input');
	config.macros.option.propagateOption('txtFirstVisit%0','value',config.firstVisit,'input');
	config.macros.option.propagateOption('txtLastVisit%0', 'value',config.lastVisit, 'input');
	story.refreshTiddler((story.findContainingTiddler(this)||this).getAttribute('tiddler'),null,true);
"><b>%1 visit</b></a></html> since %2. Your last visit was on %3.
!end

!out
$1
!end
!show
<<tiddler VisitCounter##out with: {{
	var out='';
	var id='$1'!='$'+'1'?'_$1':'';
	var greeting='$2'!='$'+'2'?'$2':'';

	// create the 'first visit' timestamp (if needed)
	if (config.firstVisit==undefined) { // only once per session
		var opt="txtFirstVisit"+id;
		config.firstVisit=config.options[opt]||new Date();
		config.macros.option.propagateOption(opt,'value',new Date(),'input');
	}

	// update 'last visit' and 'visit count'
	if (config.lastVisit==undefined) { // only once per session
		var opt="txtLastVisit"+id;
		config.lastVisit=config.options[opt]||'';
		config.macros.option.propagateOption(opt,'value',new Date(),'input');
		var opt="txtVisitCount"+id;
		config.visitCount=parseInt(config.options[opt]||0)+1;
		config.macros.option.propagateOption(opt,'value',config.visitCount,'input');
	}

	// get and format # of visits
	var count=config.options["txtVisitCount"+id]||1;
	var wordmap=['---','first','second','third','fourth','fifth','sixth','seventh','eighth','ninth'];
	var suffixmap=['th','st','nd','rd','th','th','th','th','th','th'];
	var digits=count.toString().substr(count.toString().length-2,2);
	if (count<10) count=wordmap[count];
	else if (digits>=10&&digits<=13) count=count+'th';
	else count=count+suffixmap[digits.substr(1,1)];

	var out=greeting; // initial greeting for first visit only
	if (config.lastVisit.length) {
		var first=new Date(config.firstVisit).formatString("MMM DDth YYYY");
		var last=new Date(config.lastVisit).formatString("MMM DDth YYYY at 0hh12:0mm:0ss am");
		out=store.getTiddlerText("VisitCounter##outputFormat").format([id,count,first,last]);
	}
	out;
}}>>
!end
%/<<tiddler {{var src='VisitCounter'; src+(tiddler&&tiddler.title==src?'##info':'##show');}}
	with: [[$1]] "$2">>
/%
|''URL:''|http://visualtw.ouvaton.org/VisualTW.html|
|''Description:''|Pascal Collin's extensions for TiddlyWiki|
|''Author:''|PascalCollin|
%/
<<tiddler HideTiddlerBackground>><<tiddler HideTiddlerTags>>/%
%/<<tiddler ReplaceDoubleClick with: ctrl doubleclick>>/%
%/<<tiddler HideTiddlerSubtitle>><<tiddler ReplaceTiddlerTitle with:
	"{{nowrap{//\<\<QOTD Greetings noclick\>\>, \<\<showUserName\>\>//}\}\}">>/%
%/<html><hr></html>/%
%/{{span{{{floatleft small{@@position:relative;+++^18em^[clock]...
	<<moveablePanel nofold>>Clock
----
	<<player flash AnalogClock 100% 200>>===<script>
		// make slider button show current date
		var btn=place.lastChild.button;
		var txt=(new Date()).formatString("DDD, mmm DD YYYY");
		btn.innerHTML=txt;
		btn.setAttribute("closedtext",txt);
		btn.setAttribute("openedtext",txt);
		btn.style.marginLeft=btn.style.paddingLeft="0";
	</script>{{tiny{<<tiddler DigitalClock>>}}}@@}}}/%
	%/<<animate div = right %0% -100 0 0 1000>>/%
%/}}}/%

%/{{span{/% ANIMATE
%/{{toolbar fine right floatright mouseover{/% 

TINYCHAT
%/+++(WelcomeShowChat){{plain{[chat|show chat session][&radic;chat|hide chat session]}}}#Welcome_chat:...
@@display:block;height:.5em;@@{{menubox{
<<tiddler TinyChat>>}}}@@display:block;height:.5em;@@===/%

TWEETS
%/+++(WelcomeShowTweets){{plain{[tweets|show TwitterTabs][&radic;tweets|hide TwitterTabs]}}}#Welcome_tweets:...
<<tiddler TwitterTabs>>@@display:block;height:.5em;@@===/%

BROWSER
%/+++(WelcomeShowBrowser){{plain{[browser|MiniBrowser with favorites][&radic;browser|hide MiniBrowser]}}}#Welcome_browser:...
{{small smallform block{<<miniBrowser noedit>>}}}===/%

FAQ
%/+++(WelcomeShowFAQ){{plain{[FAQ|knowledge base, guidelines and instructions][&radic;FAQ|hide FAQ]}}}#Welcome_faq:...
{{small smallform block{{{hidden{<<tiddler GetTheFAQs>>}}}<<faqViewer faq 'groupbox height40em scrollbars' -modified 'YYYY.0MM.0DD - '>>}}}===/%

CATALOG
%/++++(WelcomeShowCatalog){{plain{[catalog|review installed features and add-ons][&radic;catalog|hide catalog]}}}#Welcome_catalog:...
{{small{<<tiddler CatalogTabs>>}}}===/%

REVIEWS
%/++++(WelcomeShowReviews){{plain{[reviews|read some nice words about TiddlyTools][&radic;reviews|hide site reviews]}}}#Welcome_reviews:...
{{nobox block{{{fine center block{<<QOTD SiteReviews 8000 norandom>>}}}<script>var s=place.style; s.margin=".5em .5em 0 1em"; s.padding="2px 1em"; s.height='2.5em';</script>}}}===/%

QUOTE
%/++++(WelcomeShowQuote){{plain{[quote|show Quote-of-the-Day][&radic;quote|hide Quote-of-the-Day]}}}#Welcome_quote:...
{{medium italic center clear block{@@font-family:Trebuchet MS;<<QOTD Quotations>>@@}}}===/%

FEATURED
%/ | {{small{[[featured tiddlers...|FeaturedTiddlers]]}}}/%
%/}}}/%

%/<<animate div = left %0% -100 0 0 2000>>/% END TOOLBAR
%/<<animate = add    selected 0>>/%
%/<<animate = remove selected 3000>>/%
%/}}}/% END ANIMATION

PANEL STACK
%/{{clear block{/%
	%/<<DOM move Welcome_chat>>/%
	%/<<DOM move Welcome_tweets>>/%
	%/<<DOM move Welcome_browser>>/%
	%/<<DOM move Welcome_faq>>/%
	%/<<DOM move Welcome_catalog>>/%
	%/<<DOM move Welcome_reviews>>/%
	%/<<DOM move Welcome_quote>>/%
	%/<<animate = right %0% 120 0 0 2000>>/%
%/}}}/%
%/<script>
	// when starting up, force refresh of titles and main menu for syncronized animation effects
	if (!startingUp) return;
	refreshElements(document.getElementById("mainMenu").parentNode, "MainMenu");
	refreshElements(document.getElementById("siteTitle").parentNode, "SiteTitle");
	refreshElements(document.getElementById("siteSubtitle").parentNode, "SiteSubtitle");
	// DISABLED story.displayTiddler(null,"HolidayGreetings");
</script>
/***
|Name|WikifyPlugin|
|Source|http://www.TiddlyTools.com/#WikifyPlugin|
|Documentation|http://www.TiddlyTools.com/#WikifyPluginInfo|
|Version|1.2.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|insert sections, slices, fields, literals, or computed values into a wiki-format output|
!!!!!Documentation
> see [[WikifyPluginInfo]]
!!!!!Revisions
<<<
2011.03.07 1.2.0 added handling in getFieldReference() for retrieving section values
|please see [[WikifyPluginInfo]] for additional revision details|
2007.06.22 1.0.0 initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.WikifyPlugin= {major: 1, minor: 2, revision: 0, date: new Date(2011,3,7)};

config.macros.wikify={
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		var fmt=params.shift();
		var values=[];
		var out="";
		if (!fmt.match(/\%[0-9]/g) && params.length) // format has no markers, just join all params with spaces
			out=fmt+" "+params.join(" ");
		else { // format param has markers, get values and perform substitution
			while (p=params.shift()) values.push(this.getFieldReference(place,p));
			out=fmt.format(values);
		}
		if (macroName=="wikiCalc") out=eval(out).toString();
		wikify(out.unescapeLineBreaks(),place,null,tiddler);
	},
	getFieldReference: function(place,p) {
		if (typeof p != "string") return p; // literal non-string value... just return it...

		var val=undefined;
		var here=story.findContainingTiddler(place);
		var current=here?here.getAttribute('tiddler'):'';

		// SLICES: "::slicename" OR "here::slicename" OR "tiddlername::slicename"
		var parts=p.split(config.textPrimitives.sliceSeparator);
		var tid=parts[0]; var slice=parts[1];
		if (slice) { // slice reference
			if (!tid || !tid.length || tid=="here") tid=current;
			var val=store.getTiddlerSlice(tid,slice);
		}

		// SECTIONS: "##sectionname" OR "here##sectionname" OR "tiddlername##sectionname"
		if (!slice) {
			var parts=p.split(config.textPrimitives.sectionSeparator);
			var tid=parts[0]; var section=parts[1];
			if (section) {
				if (!tid || !tid.length || tid=="here") tid=current;
				var val=store.getTiddlerText(tid+config.textPrimitives.sectionSeparator+section);
			}
		}

		// FIELDS: "fieldname" OR "fieldname@tiddlername"
		if (!slice && !section) {
			var parts=p.split("@");
		 	var field=parts[0]; var tid=parts[1];
			if (!tid || !tid.length || tid=="here") tid=current;
			var val=store.getValue(tid,field);
		}

		// not a slice, section or field, or value not found... return value unchanged
		return val===undefined?p:val;
	}
}
//}}}
//{{{
// define alternative macroName for triggering pre-rendering call to eval()
config.macros.wikiCalc=config.macros.wikify;
//}}}
/***
|Name|WikifyPlugin|
|Source|http://www.TiddlyTools.com/#WikifyPlugin|
|Documentation|http://www.TiddlyTools.com/#WikifyPluginInfo|
|Version|1.2.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|documentation|
|Description|documentation for WikifyPlugin|
The {{{<<wikify>>}}} macro retrieves values from tiddler slices, sections, or fields and then inserts those values into wiki-formatted output.  The {{{<<wikiCalc>>}}} macro performs the same processing as {{{<<wikify>>}}} and, in addition, passes the assembled text content through javascript's {{{eval()}}} function before rendering the results.  This allows you to, for example, construct and compute mathematical expressions that use input values extracted from tiddler fields or slices.
!!!!!Usage
<<<
{{{
<<wikify "format" value value value value ...>>
<<wikiCalc "format" value value value value ...>>
}}}
* ''format'' specifies the output format of the wiki-syntax content (or javascript expression, if using {{{<<wikiCalc>>}}}).  Use //substitution markers// "%0" through "%9" to insert each value parameter into the formatted content, replacing its corresponding marker.  If the ''format'' is blank (or does //not// contain any substitution markers), then all values are simply joined together (with spaces) for output.  If {{{<<wikiCalc>>}}} is used, the formatted output is evaluated as a javascript expression before rendering.
* ''value'' parameters (space-separated), specified using any of:
** slices:<br>''::slicename'' or ''tiddlername::slicename'' or ''here::slicename''
** sections:<br>''##sectionname'' or ''tiddlername##sectionname'' or ''here##sectionname''
** fields:<br>''fieldname'' or ''fieldname@tiddlername'' or ''fieldname@here''
** evaluated javascript:<br>''"""{{...}}"""''
** literal text:<br>''"..."''
Note: if a slice/section/field reference omits the tiddlername (or uses the special keyword, ''here''), the current tiddler is implied.
<<<
!!!!!Examples
<<<
{{{
<<wikify [[This tiddler is: %0 using %1 bytes (last author: %2)]] title {{tiddler.text.length}} modifier>>
<<wikify [[The source URL for this plugin is: %0]] 'here::Source'>>
<<wikify [[The tiddler has been changed %0 times]] changecount@here>>
<<wikify [[The Primary Mid color is: @@background:%0;%0@@]] 'ColorPalette::PrimaryMid'>>
<<wikify [[This current user is: %0]] {{config.options.txtUserName}}>>
}}}
<<wikify [[This tiddler is: %0 using %1 bytes (last author: %2)]] title {{tiddler.text.length}} modifier>>
<<wikify [[The source URL for this plugin is: %0]] 'here::Source'>>
<<wikify [[The tiddler has been changed %0 times]] changecount@here>>
<<wikify [[The Primary Mid color is: @@background:%0;%0@@]] 'ColorPalette::PrimaryMid'>>
<<wikify [[This current user is: %0]] {{config.options.txtUserName}}>>
<<<
!!!!!Revisions
<<<
2011.03.07 1.2.0 added handling in getFieldReference() for retrieving section values and eliminated ~SiteSlices, ~SiteFields and 'checked' (fieldname) fallbacks.
2009.03.29 1.1.4 in handler(), pass 'tiddler' value to wikify() to fix macro errors in rendered content
2009.03.26 1.1.3 unescape output before wikify so that \n can be used in formatting string
2008.11.16 1.1.2 in getFieldReference(), if not a field/slice reference (or field/slice is not found), return string input unchanged instead of returning a blank string.
2008.03.08 1.1.1 size reduction: documentation moved to [[WikifyPluginInfo]]
2008.03.07 1.1.0 added {{{<<wikicalc>>}}} variant for evaluating assembled output as javascript before rendering the result
2007.11.11 1.0.1 in handler(), fixed problem where a trailing space was created when no substitution markers were present in the format param.
2007.06.22 1.0.0 initial release
<<<
TiddlyTools... Small Tools for Big Ideas&trade;
/***
|Name|Woodshop|
|Source|http://www.TiddlyTools.com/#Woodshop|
|Version||
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|CSS|
|Description|theme: rustic look - dark/med/light wood backgrounds|
|StyleSheet|Woodshop|
|PageTemplateReadOnly|PageTemplateReadOnly|
|EditTemplateReadOnly|EditTemplateReadOnly|
***/

[[StyleSheetAdjustments]]
/* ==== Woodshop ==== */
/*{{{*/
body
	{ background-image: url('[[WoodshopBackgroundMedium]]'); background-color:#db7; }
.menubox
	{ background-image: url('[[TexturesCrumpled]]'); background-color:#edb; }
.tagging, .tagged
	{ background-color: transparent; border: 1px solid #ccc; }
.selected .tagging, .selected .tagged
	{ background-image: url('[[TexturesParchment]]'); background-color:#edb; border: 1px solid #999; }
.groupbox
	{ background-image: url('[[TexturesParchmentGray]]'); background-color:#edb; }
.viewer
	{ background-image: url('[[WoodshopBackgroundLight]]'); background-color:#edb;
	border: 1px solid #999; -moz-border-radius:1em;-webkit-border-radius:1em; padding:1em; }
.header
	{ background-image: url('[[WoodshopBackgroundDark]]'); background-color:#611; color:#edb; border-bottom:0px; }
.header a
	{ color: #ec7; }
.floatingPanel, #messageArea, .attachPanel, #importPanel, #exportPanel
	{ background-image: url('[[TexturesParchment]]'); background-color: #edb; border:1px solid; -moz-border-radius:1em;-webkit-border-radius:1em; }

/* rollover highlighting */
.mouseover 
	{color:[[ColorPalette::TertiaryMid]] !important;}
.mouseover a
	{color:[[ColorPalette::TertiaryMid]] !important;}
.header .mouseover, #backstageButton .mouseover
 	{color:[[ColorPalette::Foreground]] !important;}
.header .mouseover a, #backstageButton .mouseover a
	{color:[[ColorPalette::Foreground]] !important;}
.header .selected .mouseover, #backstageButton .selected .mouseover 
	{color:[[ColorPalette::Background]] !important;}
.header .selected .mouseover .button, .header .selected .mouseover a,
#backstageButton .selected .mouseover .button, #backstageButton .selected .mouseover a
	{color:[[ColorPalette::TertiaryLight]] !important;}

#messageArea
	{ background-image: url('[[TexturesCrumpled]]'); background-color:#edb; }
.tabContents
	{ background-image: url('[[TexturesCrumpled]]'); background-color:#edb; }
#sidebarTabs .tabContents
	{ background-image: url('[[WoodshopBackgroundLight]]') !important; background-color:#edb; }
h1,h2,h3,h4,h5
	{ background-image: url('[[WoodshopBackgroundDark]]'); background-color:#611; color:#fff;}
h1 a, h2 a, h3 a, h4 a, h5 a
	{ color: #ec7; }
.toolbar, .toolbar a, .toolbar button,
.mouseover, .mouseover a
	{ color: #ba8; } /* override default #999 */
.undocked .searchResults
	{ border:1px solid #611; background:#db7; }
/*}}}*/
!usage
{{{[img[WoodshopBackgroundDark]]}}}
[img[WoodshopBackgroundDark]]
!notes

!type
image/jpg
!file
./images/wood_dark.jpg
!url

!data
data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEBLAEsAAD/2wBDACgcHiMeGSgjISMtKygwPGRBPDc3PHtYXUlkkYCZlo+AjIqgtObDoKrarYqMyP/L2u71////m8H////6/+b9//j/2wBDASstLTw1PHZBQXb4pYyl+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj/wAARCADwAUADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDLoxmlIwaBUHQJilxRg0o4oAQim4p5Oe1NxQAUZxRRigBQaX6UmKXFACEc02ndKQmgBM4pwam0CgQ7g80fWhRSnpQUIeaTbSiloEMxRmnE4ptMQoIPWlx3FNpwPFIaDntS59qOfSjB70hiEigEUu3vTttFwDII4NN2nNOxRxQA3HsKNpNO4ooAbsHrS4UUtMwc9aAHHb70meODRg96MfWgA3HHNG/FG360u2jQBC4NJu9qXb7UbfajQBASO9HWlx7UEe1AgpuDUhPpmkyO4oGIBS4ppPpSZoEP20BaaGpdwo1HcXaO9KFBpm6kzzRZhdE20U3gGmb6C1Fguh2QaacU3NGadhXFoFJS0AOBxSZz2pMUYoAKTNLSYpiEpaKKBC0A4ooxSKF3Ubs0ADvQAKAFDH0peaOBSgikMOaMUm4dqOTQAcCl3Ck2ilAApAJupCT6U7ik3DJpgJzxSjJ70hb1pc8UAL+NGDTcnPSlycdKLCDv1oJFIQTRgjrQMOPej86MjvSgj3oAbk0lLSYpgJRinYo5ouTYTFFOA96T8aCrCYoxS/jRQAmKUCgYpcD1oEJijbR9KUCgAxj0oOPajFG2kMT8qSpNoo2Ci4EeKKk2CgJRcCPFKBT9uKXaPSi4DNnvShKUr9aNp7UXAAgHvRtAPSjkUmT70hD9oHFN4HAppz60tMYYAoLUhJNJyaADJNOBpB7UvWgBSR7UgIzjFJtNIxxRYBxxSbsU0c0pHpQIQmjdRQKYg3GjJNFFACc0c0tGKBi4NGPel+goFIYmPejFHSjmmAYHvRilwfajBpAJj2o4pcfSkIINMQuBRx6UnNHPtSAXj0pcj0ptIfrRYCTikwPU0yiiwyQAdiaXBHQ1GD70/PuKAAhvWk+b1pc+9JmgAy3elDmjd2ppHPFAWHE96UkjoM1GQaAaLASBs9RTlwe1Rg07PoaTQC/L6GmH15xSn603IoSAXIx0oUj0pOtKBkcUwHAdwKQ5HAFGCOM0mD3zSAbljSYz3p+KUKKdwsMApSB60/avpSEUXAjNKMelO2+9G2i4hv4UE+1OwPSmn2oAOvalwTSc0DFMBxU+tIVp34ikOfUUgGnIpOaeG/Olzzzii4yOgUpHfNJTELigg0mcUbue9AAc96SnZpDQAUlLS4oCw2ilooCwlKPrSUoFAhR9acCO1N6HpRzSKHHHqaMj1pASPSlzj0oANo7tRtHXP6UpGfSjnsRQIQYHel49aOc5OKQ89xSAOO5pOD60H6ignPcUxgMe9KR6A03gd6Un3NADhnpzS4x1pmQepNJ9CTRYRJwaUD0NRbuxJpdwx1NKwXHkn1NJnHUmkB9zSZPqcUWAduFKGB6Uz86UZz1osAuKaVz0pxBz96kAPXIpgIFOOtAXHenZ9xQQfUUXAT8qU47kCk3D0FBYdCooAXA7NzSH60gI9KUkemKBjc0oNBI9KTimIDzSYNOBGKMigLDKKcRSUBYKKUCjgdqBhRijd7UZ9qBCYpce1KSD2o49KAEA9aMe1PH0pTgUrjsMGPSlwDxg08YxSEelK4DcAcYNLgHsaXHqDS4HvRcBoHtQQPSlxz3pQPUmgCPHPSjHtT+PU0bR1JNFwG7T6CgDPGBSlRnqcUpC07iGgHPalw3tSgAc80bx0xxSGBB9qbg9SRTqaee1CAAe2RSkE8ZFNOPSlGAM4pgKBjuKXJ9qbuHXFLu78UgFOe+KTI9RRuH1pCwPYUAKB9KU/hTRjsKUsPSgQbCego2nvU2ABTTg8UrjItpoK5FOKgdATRn2p3AYRSD3p2D2FGG9KYDdtLt+tLg9xQMigBMfWgD60uT04pcN7UAIPxpMU47vag5x2oAZilwTS4NAz9KAGgH3pcGn7fcUhBHQii4AB7mgD3NKAT1xRzSAMc96XHpmg574pOe2KQDsGkIHekGfUU4Z9qAG5A6daQ5pec9KAGJ5HFMBOfWgE4p2OwFByOi0AIAT3p2045NA3f3cUvPpSuAzB9aTFPIJ7U4D2xRcCMLzyKaR6VMc+9NzjsaLgMH0pApNSe+DS546U7gRhcdaXb9aePoaQn60rhcYVxzRtz2p/XqKUKCc4ouAwIO5pdg9aftXNG0UXGJuA6UbvpTeOwNISfQ0WEO3H14pCR2ppbHYUhJ9qdhjs005zweKQN1zQME07CFzRQVFIQe1AC4xzSgd84puWHakz7UASY+lJj1pmaMdwaLBckxgcUfWoxnsad83pSsFx3vgUmfwpCSO1JkelOwDselKKaTj1oBHrSAcQTQAM03I9aOD3oGOPXoKB9Kbg9jQM9zQA/g+tLnimc0vPtSsIdjnOaXI9TTPypR360AP3cdaAaZzS0rDsP57Uhz603I9aUD3oELkjrzRknpim49CTSgEjqRQA7dSbxSHI75pv50WHYkDZ6UlMyRxR1osTYUH2pckdQaQfSlJOOlBQhPpQD65pD06GkyBwQadhDsN6ikwRRhemSaTA9SKAA89aacUEAfxGm8epqkgFxml2ntTcgdKN1Ah20jrQAabkn1p24jvQMXntSDP4UbietGcUABx6UmBnkUoajIz3oAMKO5peOgJpMgUhYGgBdv+1RjHcGjAPekC89aAFJPsaPm9BS7R1zRgdjSATB7ijHsaWlwfUUAISPQikwPSlwfUUDPqKAAAY6UADtTue+Kac9RQAbR60oA9TSDNLkjrQMOB3pNw9aM0vHpQIAQehpwyaaDjoKeHPpSYAwHrikBwcE0pb2NNzz0NAw7/AHqTHo1Lk+lJkdxQIBn1FKQT3pMr/dpcj0NMAwcdaMD+8aMr3FGVHSkAYP8AepSDj7wpMrRhT3NADCDjvSfN6U4OKC4NMBpyOuKCSKC3NG4HqKYCE5+tAx3xQSOwpBTEPx3pMDPANJQMikAu3jvS7c0mSetGaBgFoxg0uabkjvQAuPakOaN2aXOaYhAcUo/Gk5pckdqBhyKTPtS7qTPNIAB9adu7U0tRmmIdn8aT36UmfSlBz1pDAGlPtSZB4pc4oAT6UhJp26kOD2oAQNTg1IAO9OwvahgJu96N3qf0owKAqn1oAUN70u4+opNq9iaMfWloAu4juKM564o2j1NJjHegBcgU0EGnD2NJszzmgAIOKQZ9DS47c0dB1oATml596Qt70b8GgBhJoBx2ooB96okM0Z4o/KigYc04H1pA2O1GRQCFz70mcUYHY0nNADhg0vFM3c9KXINFguP69hSEA+gpv40hzSsMCPegUlGKokXNFGMUlIAozSgUvFAWG0oHtSjHelyO1A7DTj0opc0cUAIMmlyaMCl2igBMj2pc/SjbikzQAv4ijPuKTIo60AOz7ilPuwpm0jvRyPSlYLjy3bNID/tUgPqooOPTFAxfxFIc+tGF9aTA9aADcRRuPvRg+tJyO1MQ4t9aTOfWkyKOKLBcXA9aTHvSUUCFzn0oxSUUAL0oyaSimAuaKOKKQxKWilxQAlH4UfhS4oAOPejj1NJQKAF49aUD3ppoBoAdgnuKMe4pufajNAXH7T7UmMelNzRn3osFx/PtSc+gpMnrSZoAU/Sm5pc0vBoAbmnZ9KNoo2+9AahzSEGlAI70vzelADQuaUDFGTRkUALn6UmfalGD7UYHY0hiE0A0o470uRQAZB7CjOP4aXI9BSZPYUAITn+Gkx9aXce4oLUANxR+NLuo3e1MkSl7dqTj0o4oGJRTsCgr6UCsNpaSloGGaXI9KSigBeKSikoAUDNLyKSjNACgmjJpM0Z9qAuBOe1LkU2igQuB60YpKXmgBKKXPrS/L6UBYTAox6GjHpS7TQOwnIpR9KPmFKCR1FADe/ejj1p+4elGR6UANBpQx9aMrnpQSPSkMXJPpRz6CkyPSjj0oAdn/Zo3DPSkwO1JjFADsj+7RkelMP1oBPrRYLj+PakPtSZPrSZNABzTTT+fSk+tMQ2inDFGB70CsNop3FGBRcLDcmlwTS+9L+dA7DNpop9GKLhYTmlApRS/hSuMaVz2pNlSUYpXEREEUVNTTTuOxHSYp2wntRsYU7kjaKeFI7U7aPQ0XHYioqQgDsabxRcLCGinfLSYHrQAUZ+tJRQO4ueaCaSjmgVxQaCaSigABwelKD7UlGaAHhh6Uu4elRjrTs0rDuPDD0pCwpu6kJBosAuQewowCOKTijkd6BCEYozilz60fhTATeaN59KOPSjaPWjQWopb2pNx9KMEUmaADmjmlDUvvQAmCKM0c0lAC5pQaSkNAx4PvS5qOlBosFyTPFJupuaXrSsOwbjQGNJ7UEGgB3mH0o8w0yjNFgH+YaPMY9qQYpaNAsG5vSmknuKXcaM570AIQfSk2n0pSSPWjdTEJtNGDRuo3UC0HflS8VHmlyTRYdxxxTeKMHFG00AGaTNO24owPegWo0ClxThx0zSE+tFx2GkGkqTOaQj2ouFhMUtH4UfTNABSc0oBBpcH0oAQY7ilwD3xRg+ho2n3pDDkehpDnvSkCkAPamIbil2+lOHPvSHB7UBY/9k=
!usage
{{{[img[WoodshopBackgroundLight]]}}}
[img[WoodshopBackgroundLight]]
!notes

!type
image/jpg
!file
./images/wood_light.jpg
!url

!data
data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEBLAEsAAD/2wBDABQODxIPDRQSEBIXFRQYHjIhHhwcHj0sLiQySUBMS0dARkVQWnNiUFVtVkVGZIhlbXd7gYKBTmCNl4x9lnN+gXz/2wBDARUXFx4aHjshITt8U0ZTfHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHz/wAARCADwAUADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDp+e1GKU4BoFc5qGMUYNGDRjH8NAgxSYNO69qT3FABj8DR0pMHvQBQMXIpfpSUtACEc80nel6UZoEJkjrS5pvJNLQA7g80n1pRR2oAQ80bc0daXigBuMdKTPODTulJzQAv1ox3H4UgAFKOmO9AC/SjPtRz6Y96TnvQAvFJkUuO9LigAyCODSbTn1paTigAx7LRtPrgUvFFADduO9L8opaTnPWgA+X/AGqTPHBz+lLz3Le1H/fVABk45oyRSYB67qXaP7tACblNG70FOx7UmD6ZoAT5h3wKOtLj/YxQR7UAGaTB/wBqnZ9NxpOO4oAMUbaPpSEe1ADsUAU3OOppdy+tAC47GjaDTdwPf/x2g4B/i/WgB2KOhpu7/eo3D0b9KAHcUnFNHsmKOT/DQAmAKcKQZ/2cUuG7mgYAijOe1HPrRj1NAgpNwHFGBnrRx9aBiUAHilz6Cj8KBBgUvSkGTzQBQMXIo3Zo2+tLjtQAmfanUcCkGKBC0Um4dqOfpQAvSjNJtHpS9KADNJz2HNLSZGT3oAT07etKOe9Bb1/Cjdx1oAXP+1Rg0meelHOOlABjnr/31Qcf5zQR/nbSfWgA496P++qMjvTuP9qgBvzH+9Rg+rUEf7NGM87aBjev/wC1S4FLz6LmjmkIbx/s04en/stKM/3qTB9aYxP++qWj6mj8aADBowe4Wl4owPWgQm3/AGVpdv8As0n0oxQMXp2Wg/7q0YpNooEGP92jGf7tO20bRQMb/wB80g/3qfto20CG/jRjjk07H40YHpQAm33o2/73/fVBA/2qMelAC7AP4c0m1QelL/wGk5/2qAHYA4pOnApp+tLQAtJmkzmjrxQAdaXij6UUABx/s0vfGKTB/KkY7R/KgB1Jux1akwe5b6Ue4oAN3+9Rk+jf99UHP/7VH1K0AJk/T/gVGW9aXj/Zo/4FQAc+v/fK0fN/tUcUY/2c0AGG7mjHvS49FoANAxMe9GKXpRzQITA77qNo9KXH+7Rz/lqAEx7UAD+6tLj/AHaTkH7q0AHy/wCzS8f3aPm70mP92gB34Un4UmP92j8VoAd8tJx6tTefWl+poGOwOxajkdDTc+jU7P8AtLQITB7Ef980YPqv/fNGR6rRmgAy3fbRk/5zS57CkxzxQAp9en/AqDnsM/8AAqbg96M+60AO6/w/ypRz2puf92lyOx/nQAv4NSe/zEUnHrikyo67v1oAd26Ug6dG/Ck6jI6fjS4BHFADh6gUnPQCk4HGaNvruNACZY0Bec5yaX/PejC9aAEApTjucUuF9KKAG8f7Ro+opcf7VG38aAEz7cUZ9Fp34Un0oATr2Wjr0K0c5yeKX8WPrQAEehWkIX/Zp3/Ah/3zRz6j8FoAb0//AGTSZxydxpwJ/H/dozzyw/KgBo/4FS/99Ue5daQY/vflQAuO/wA1BB/2qM+7Ubhn+KgAJ9eP+A038f507P8AvUZ/2qAE69HpOOh3Gne3zf8AfNH03UDG/QfnS8/7Ipf++jSdf71ABg9zS8/3v5Um3J+41L7YoELnHV6UMO1N5Bxij5v9kUALx6n/AL5oyPX/AMdo+cddtLkj+7QAmB3b/wAdo99//jtKQe+2j5uxH60AICB/HS5HZ6X5s5OKQ5PUigBMj+9SAg9GalOfUUpJPcUAN4/2qU/Rv++qOn8VIWA/jb9KAHc9Pm/76oxjrTcqerGjK9nJ/wCBGgB3WlHsWpmexLUZXHU0AOyfVv8AvmjdjqT/AN80mf8AaajPu2KADcO7f99LSgg9KTPu1Gefv/yoAXHp/Wm4U9NtKc5++PxWl+brkUANA46qP+A0bfUqTTsn1HvSZP8AfSgBf++aDjuyikyPRaMjoVFAC7R2OTSEn1Y/RaT5f7qmlOPTH50AGT6t/wB80AntuH/AaQken/j1Hy/5agA+8Ov/AI7Rg+rUZGOeP+BUZX/LUAJ0/vZoHvupeP71J1//AGqBhgf7VL1/vUYX/Zo+X+7QAY/3v++qD/wIUZHotHHp/OgQBf8Aeo2nsG/76oJz2/nR8vcfzoAAMc7Wox3wx/4FS8elKdooAaNv92lx22kUvGP/ALKj/P3qAEwOmw0uAezUY9Vb9KXH+9QA3aP7v50fL6Y+lOxz/FQB6lqAGbecbc/WgD/Zp3Hq1GB1JagBNp7ItKMnjAFIVHdjjvQdn+c0AL82e1GW/vLRgDn5qXPbDYoATn2z+FJz1LLinYNJ17NQAAnpkUHceMrSEZ6pmgYxnH/j1ACjI7ijLe1JkdcLRkdflAoAXJ77RSHb6p+K0ufxpNwPZaAFx/uUZP8As0g29gtLn2oANueg/Gjnv/49TuAKTjpQA3aaCpI/iowOwJpcf7FACYPqf0pOvXd/3zS4PYLR83otABj/AHqDn1P/AHzRg9xSjIoAT2+ak/76/wC+adz0+WjDf7NAAD/vflTcf52047v9mg5x/CaAEOf9qjk/xNRg96Xn6UAJg/7VHP8AtUu3/dpCCOhWgBRn1agfVqMZ67aXmgA7/wAX5Un03f8AfNB99tGD220ALikIHegZ9VpRn/ZoATKjp1o5+lLznpQN2eRxQAn48/71IG4/+yp3PQCkyey5oAOfX/x6l5xy1GT/AHcUc+n/AI9QAnPr/wCPUnFPOT2pPwx+VACADPI5puB220/n/a/SjOP4W/SgBvH93/x2gDP/AOzTvfDUZ46UAJ060f8AfX6Uv4NRn/eoATHf5qMZ7fjRgHqFNLhSc4oATHqaNo9adgZowKAEzj/69Gf92kGOwP8A3zRuPo340ALk+vFJx2pCcfwrQT/uigBaOc8Hj/apM9c0g25oAdSUFV+lBH40AHTmlx3ziky46jJ/2aTI9KAHYPotG31powRxRt7gUAOxgcUfWmgN2NLlvSgBcDrhaP0pOR2/75pMjuGFAC49OaWkJHuPqtAKnvQAuCfaj5c5pMr60vXvQAHr0Wj8KPocUbT3oAOD/epe1JzRz7UALjnOaPxak/L/AL6pfX71AC5460U3n/LUtAC89qDn1pMj1oH+9/KmIX5h15pM56baMehY/lRyR1YflQAu6jcKTPvmk/76pDHA56UvNM9uv5UfKf7tAhwz2FJk+jUfhR26Uxh9KOe+6kPT7rUcDgg0gFw3qD/wGjGKTC9CWP50nHqw/OmAvXr/AFopvyj+M0hK9yT/AMBpALilwe1Jlf4f1oznr/6FQAu09+aXBpOT/eo6d/8Ax2gA+lKN34Um7PU0Zx/d/wC+qAFP0puBnlcfSlzxxx9OaOM9/wDvmgAwo7tS+wZqTgUhKnr/AOg0ALg/3m/75o5UdVNGF9cfSk2jOd350AOz6bTSfPjoDS4HXNINvZv5UAHP938sUY/2WNLzRg+q0wEJ9iP1pNqdcfzp2D6rR83qKQCBVx0/nQNvanfN3x+tJz1/xpgJgetKMerUfNRkjrSAPlH8VJuH9+lz70Z9qADcD0elGT3zSbvT+lLn2/lTADj1xRuwcE0Z9jRnno1ACZGf9ZRj0elyaOP7tAB83qKCCf4vypuF/wCef/jtLx/cP/fNAC4OOtGB/eIpPl7j/wAdNGVHT+tAC4P97FGGx94f980mUo+U9CfwoAD0/ipPm9P/AB6gMv8AepSf96kA3cRwSv8A31S7j/laNx9WI/CgtnqGNACE+vX/AHaOO+2g464/HcRRuB4zz/vUALgdfloxzwrUh9Pm+tHI+n+7QAuOP4qMZ6Ucnr/Wj/PegBNuKXABopM4zhqAFx6D+dIc/wCc0mQeu39Kdk+/5igABx0oH/AqTDd1/LFLyOzUAHP1oz7UhOOv/oNGec/40AGR3/8AQaXPb/2Wk3+jL/31QOg+6f8AdagBf+A5/wCA0mB12qP+A0v04pM560AAx0peP8etGc8UZoAT6f1o7/8A2VOz+dJ+GaAEB4/i/wC+qdk/7X6UmPWl+XtzQAmfc/8AfNGT3Y/98UfL/nFACnj5qADd/tf+OmjcfUf98mlwOxajH+9/31QAZI7j9aTg9dhpcf7TUdP4qYBlR/d/CkGD0/rTh7NTSuepb+VIAxx/+sUvzejf99UY7fNR260AGW/2v0o5/wBqgtx1zSbsHlsUAJl/9lhTQQvAj/75peO7LS7v9ugBNynoWH/AqXtjP8qU/wDATSAY7c/7tACYYU/J75po44wtA2n+HFAC5/2qTpQR33MKDu7Mp+tABwadx2pm7n5lxS5VulAC9ew/Wjr6f99Gkxmjn60BYMe+f+BUmAPb/gIo+q0Y9GagA+U9OP8AgNGD/sn86Oe+00Ed6ADn0b8Goyem5h9Vpff5qOKADJP8SmjBz/q/yowvcf8AjtHy/wANACfL/dYH8aXI/vMKPw/nR+X60AGGPf8A8doyR1K/8Co2j/LGlwO1ACbh/eT9aAw7FP1peRzub9KMn/a/SgBMgfxJRuH95Pwo6dQ35Cjr02/980AOz/tCg57sB/wGm4x0K/8AfNAVv7sRFACnA6sPrgUgI7Ov6UvP9xaCR3XA9aAFwf8AZow3rTcRnuBRhez0AAZu4XFAJ9x9G4owexU0fMOq8e1ACn33fWkznu1JkH+8KMqf4v8AvqgBSM85aj5uz/nTcgdHoyD/AB0APyfakx/u035c/wANL9P/AEKgA+m2ly3+yaME/wCc0h91oAM+q0ZU+3+9QMY6MKUH3agY0EdnpevQrS5J6MtLjp8q0CEG7sM0bQeq0Fc/wUYHcMPzoAAFHTcKPl9WpMj/AG/1pc/7bD60AH4/+O0uD/ez/wABpCfdf+BUc99poAXBPcf980Y91pP+Af8Aj1ISPRhQA/a3tScj0/Wm5X1pR7Nk0ALz/s/rRz6L+FJ83Wj8GoAOnRf/AB6m7wD0wacG/wBqlJ9aAGgqf4v/AB6lpSB9KTbjkNQAfN9aDz1FGGHdcUvzemaAEC5/vCj8c/Wjce4akDL0zQA7/vmkOO4oDIf4sUZXs9AAcfSjeAeXz7UBgP41p24f3hQAm7P900Zx/DS8ei0c9g1ADTg/wN+FGPTeKXJ7hqM47NQA3I7s3/Alo3f7f/jtO3H/AGqTd+P5UAGc9GX/AL5oBOPvCg49G/75oyP73/fVABhs56ikxntS7F9GFG0/wlqAEAH+1QCR0NHfBajn/ZoGGT6KaX/gLD6UhHqlHH+0KAFyB/e/GkO091pc5/jpCD2XNAC7SegowR3ak4/utn2ozju340ALuP8AeX8aCW/2TRlv9k0Z9U/KgQFs9qTKHqKMj+9/31S0DDaPWjBHTkUnTkGj5vrQIMt6UcHqtLn2o+X0oATC9j/49S4I/i/76o2+lAUigA+frhTRx/dYUfMOtLkjtQA3Kg/eYUfKej07eOlG6gBB9VpRn1WjC5+5/wCO0h2/3P8Ax2gBfm7KP++qX5/QGm/J/dxRhP7ooAfk/wB00ZOfu0z5e3/oVGAPagB24/3Woz7f+O0z6NS/8CoAXI/2aMDtRz6k/lRk+maAEwf7v/j1J+H/AI9S59sUfWgBOPRqMgfxN+tKD2+alz/tNQA3IH8dA+tOyO5zSEA/w0AJ83YLRh/VRS+/8qX2G6gBm1u+2j5h/FT6OKAE57mlA9/wpaPwoAQjP8NJs9Din0YoAjwfrRu9qkpMn8aBjePWk28dKXafSjaQeOKBCfN9aPcil6dRmnYHo1ADMj+8woz6GncDs1Jkf5WgAOe+2il+X/K0m1fWgAo4/wBqk47HP/AqPxxQMXIz1/nRuHrRz2OaMt3C0CAE+v8AWjmk+oYUfLQMXoeQtKPp/wCPUgP+1Rkf7NAhd3tS7vam9/8ACl/76/76oAXdRupN3q1J/n5aAFyD1C0mARR16UewNABxTdyj+Jqfk96T6jP5UAAf3Y/8BNJvJ/hYj/dpflPbH+7Rgf3sUABb/pk2aNzHolIdw96QtzyaAFG8/wANHzeg/SlBH/7VHTnpQAYakz6rRz2PFLz3FACBhS5o4NIR6GgY78aKbz9aN1Ah/ajNNzS9aBiZNKCaPak60CF3H0o303p1pc4oGL5h7Ub2PajPejmgQbm9KCT3FGTR1/ioAQ59KMH0pTnvupN3+9QAbTnpRhh1LUm70DUZ9FoAd9dtFNzzQM9BQA7ikP8Au/8AfVGGx1o20ABYD+7SbvQUuMUYH+1QAnv/AOg0Y7Zp3T+9/wB80ZPfigBMfjTentT8g/3f++qPwoATB470fWg47rQP9ndQAUfNSjg0mD/doAMjuGpeOucUfg1GD/tUAA3dirD9aCX7ig470gHpQA3K+uKcFzyp/wC+acCT3zTTtP8ADigD/9k=
!usage
{{{[img[WoodshopBackgroundMedium]]}}}
[img[WoodshopBackgroundMedium]]
!notes

!type
image/jpg
!file
./images/wood.jpg
!url

!data
data:image/jpeg;base64,/9j/4AAQSkZJRgABAgAAZABkAAD/7AARRHVja3kAAQAEAAAAHgAA/+4AIUFkb2JlAGTAAAAAAQMAEAMCAwYAAAQgAAAKnAAAERv/2wCEABALCwsMCxAMDBAXDw0PFxsUEBAUGx8XFxcXFx8eFxoaGhoXHh4jJSclIx4vLzMzLy9AQEBAQEBAQEBAQEBAQEABEQ8PERMRFRISFRQRFBEUGhQWFhQaJhoaHBoaJjAjHh4eHiMwKy4nJycuKzU1MDA1NUBAP0BAQEBAQEBAQEBAQP/CABEIAPABQAMBIgACEQEDEQH/xACYAAEBAQEBAQAAAAAAAAAAAAABAAIDBAYBAQEBAQAAAAAAAAAAAAAAAAABBAUQAAIDAQACAgIDAQEAAAAAAAABEQISIRAiAxMwMSBQI0BwEQACAgECBQMDBAMAAwAAAAAAASExERBBgZGhAjJRcbEgYeHB0fESMCJC8JIDEgAABQUAAAAAAAAAAAAAAAAAEEBBUVBwgAEx/9oADAMBAAIRAxEAAAD6WXnaxlDPTBWVdIoZ0Brno2MApzOmK042MkRrQZ2AajK5EoYQNRh1BnoAmTpYTTzDscw6ZwFrKuwksoZWpcsuqUtUUQxoDWQaFwpULVo5jLh3Jh2LlQlkKSkA6RzOsc3pGFioTecqoBaEYwdM5QqCaiaGZSZC0BayKBqyHQ5p0eeyEJsm7nHTXPSaxZXVlN5hMm1cOw5uozbyCImqzGesvJcxqIs7AztXm6A1nSa1iNRoJkFAGUSNvMs6vFjYQuYc6qzbCihBUoLO4528rLFUgsFtMOwyqmbUc7cuWUGQzvJRLqyiQi5Su2Tksuc6glM2os6jMpl0EylQaDRk1GbYGpM56Jzz2yYOic3cYtJh3BZDRkXQBootYDqc46nPRqyGtYjVlFzGnMmnMbsJsKxspoMy9LnJqG0gjUFOTMq5jTlGIc6gQNEGjQFqoNQW8oNSwyW86qECQnKMQxGRTFSlBsKNQ0NkSYoaqC1mjRRNUGwzo0FQtIlEayUwIHMVRQOmaEI1rk10MUQVNQWkyqYtQMgwMRt5ybCXRmKg0ZjRmNmWKimpRVCqJy0uY2ZDqc2NgDjSZ1FIplg0SE6CaMmisWoEozaqyiskJEacVbsqUUINFpMswS1m3RlqlzRuyG7k1siDOysW0wdCMOmuV1jOtMYOsnA9AvG0Vm6aji9M0WsjZpdWZNBK6zJt56rZkjQQZ6FZmIgrSZqLWSXrclOthJA1c03CRQGgylW3kxvNVZ3GHcYx2jLURqBSoQxreT//2gAIAQIAAQUA/k1/Rz/5BP8Axd/qZJ/4OeJ/nP8ACPxf/9oACAEDAAEFAP6+SSf+GPMEfyn+kn8E/mkkkkknxH5I8wR/Tc/FH9zJJP4o/DHiER+b/9oACAEBAAEFAJZlsVYIY6mWQTArLw11rumhWOPw+jpJloVoaaZk6SNoTRKaw5gxZi+NIiiHgnmnG2h/JVn2Cd0fsaSaIYlA3I0yLCqQQfobHLaRVD/S6cG4GmyqSKvnSGZMkHDnmHMMgymYRgyyBrxliRkyKplCpVmUcTmrHkaSKiskanw7pEtiViEJpG0bkVmdOkHEaRobZ0UskhkdbRzw2ShscivB9lT7Ex2Sf2D+RCY3Zi0RYhkEKWqkksSsxVFRCSPVCdTaPZmEJJHDSl3Nc05m0OrZDRpCdSbMaZEmSBIggyxVZkwRA4IIkgRAq8+sXxoXx1Riqeao4iEh2JbE0NoTUuB3SHc2zdjV2ex7DREiTOiTIfjgskLwkZMIwj66n1oXxmYModUZZ1Esc+G2zrEfsyy9siTY0hyI4cOEEWIIIIRlECVSKnqcJR6kVFVEWQ1c9yfkFdjY20K0lYZ6jJUVaEh6Rr5GKktIaQ4FBI7HWQ2QJM6jpDIsQxqyfsdIHJ0kViSUSaGutMTEyUODVUcaSTUQZZCFShmg0YMEIZ7SoHVjqhyiWhMRkasNvw1Jw6RYhikTgVqjyTUzUyhNIlEo9WLI0KSIOMSG2ag2hWTIHVMVXCpB0ehWZpy0xEwbU6GxEeIkzLSJab2J/IiWhps9z2lyxyNtnEOyRNWcNGqwrEskUy1aUrEsevDgzUcksVmObLNjqEcF0gaFUyxVgyLJCZCRCYqoaqZ6qmGJNiV59xqxFhNjVmJNE2G2TUSG2aQ7IToNobR6idYmo0iJFWp6o0iUOyZ6CgeULMNEEIjqRwyh0UtfGKtUbXh9GkxQlqppGkO1WLI7Iw2ZsYY6Np1YumR1IEkIgaZDYqshiTEiOwQxpE1Q9HRWcJWZlxDIQqqWhQKrYqwZHSDMioj66kVSeWOtV4ixFyLC0ibEfIP7B6iLC0ZY62Qk2dHJ7C0KT2lK7cMbshbPYabEhyTHieIbITFWreazmppI0aY2iRzM+IgSIZkiEQiSBDTYlWX+0erJ5HZRriZ0eibIls0bQrSdE2S0NibFkdrDtA7MVkLLbpUdWT8iNCaayJXJuN2RpDskJ1ZqpxkMSsdPbwjviUJECTaba8S0cYhtw/1KRHyENDUjgymYZiyErHRbHBFZzRHDLIdRtn+kRYgbRn4xVpCVTKEqnqjdRWTFLLJCtDlTAtDVmQ4hEMavEUIqNUQ3Q1VGpJszTRtsmBWJrM1Q7VZFWKinNRKp0ixFhbPYehaJaJJQrQK7HY12WTU9Cak0JoifjIoxpx7jdkOzQ2mKCEQpzzEipBCTgcicCPZEisaJOCaHHhtyrcVmbNiubsaaJTJqhNMacLR7HRfJQd0x2cu6Y3UVkxi0iWySSWjUktnsTZDtBrruTyRWklMmDQ4YqoihFRVozNDJlEQIfxyQfpO/Psht/IK+TVWTxK6E2STAnVnqfsaTHUSSJqx6PY0yWxJy8iaErMlo1UVkSkaRI5HZITR0asK90K1h2NJjqmNWOIVkMSgVoE6MdUPZ9kPdLESPXjLIshoSOCVCaknDFTNTMEkpHGOrQl8iE2N1M/CzNTNibo1Vk0ZKRKZMmTqNXNE1YmjrFozVirRHqcEmRZmWZsQ0ex0co+xJq1WSe402KkiUEsbQ2hXSekyYG0yDhKJkUx6zwhsYnWE0dZA1JlEoQ2xOxI7I0hMmxLFYbTHSrPrgSuj/AEN2FeorfGz1E0jVSak2NWHeD7DY3UmpFpiRJCbRpkomqHliq2RZCtYdrDvJPxsxUdbImx6sVambI/0QoZNU/ViYrMmzPclmu6JRKGkRYZw4iUhH10H8bP0+jRwbkaZw1BqxoleIgWzR6GBUsj/RCtZH2VNVPSW6H+ZFCKkJDE2TY1Yl+E0cPUdasn5DPysfx3EroSsKo6Jn1DrZEsipnnt4lCY58yiVLshNjbE2mmK6NoV0O6NVZmrTSRutRfOL5mx/IfZ8jE/mZ/r/AAhC8x4cj+OzPqumqtGajVUTU/zM0IRDIsTcRNRMlCfZNobTOM6iX4ijMIavUd3Nbrxm6NMV0KwmSTzRpiuz7Wfcz7rH23Zu43YasZsYtKrZeODgcDskO4k2ZY6shpw/PsJoirFtFn8h6ipJ7Es9WOpNkK5o/fhps/RKQmjpqxLY20P5Ej7JHdmnKdmZvGGYgzUXBtmkxocChiTTixDMsaQkxSx5Z//aAAgBAgIGPwBZNvnrjDmihH//2gAIAQMCBj8Aws//2gAIAQEBBj8Aj6vR6wTpOmSdYMMkyuBBWsM9SkXhF6bkPPQnWEXhfTRRlE/58blY+5Jn67Jb+xuTkoorJ44K03+nD/w1pjRfTX1wpFt6ll6XzP5NzcjLJRGkssvob9Tcp9CO3BRtgllkss9SEUZ0kxrB6fQ9yeGlFH4JJNzctn502Mfob6ykUiikUjY2NiyyWWb8yslGDC+nYxjSzcp8z04ll8kblGcFLOllksvSyP8AB6lG5BRuXrgjT2Pgy2/Yyj9yWjYvSskssvSclFFI2KKK0tkNkMhrkWuROD+TNcSFniT2/BRTMy0UU+BlIwlplvL0l4N2SioI7SkQ0Qvo2PybFIk2Ni0WSyO48kWtMEElo2IfyXgnPUyq4kGMk5Z/JkrSz1KIMuC2/Uho2PwzLyzc3MybkxwL+SO4w8shczZEs8vgnuILfIvoT3dDP9uh5EdxLIbNyE+ZieZOkNlvkS3yL5ogj9SMFpcCWmzyXItcEff2Ja5GX3IvkWzc3LMTyIybs3PFmMGMEYRODYnBDXUy8EtFotHkeT6E9zI7m+LMNstlst4LZ5fBHeuKM5Ra+55dpsT3JEd2WW37It8iMrgX0LZvknJubm/M3RuQnzMtMzhvieJj+rRj+rKZXMrHsY/rn3PEjtRjCRsWjbPAy2sGMoxlFo2Jwi+3ij/k2KRh9qPFMrHMrqfkmOJ+Sz8mxRSK+SvklfJWn5I+SU+hubktlsy2ye543P5MyYw8aUzxyZx1M4RmEj1KRCRRC4k9dNy/gnPI3LfIxJvyN+R+Dctm5uWy2b8iM8tJIs9C59z8l9SWX10lSRgrofgk36GZK4ksvTBCbPEhIpErTEGxsbMk9C0Q0TjScEYLRsUSoMJEduTxwV1KKxyN+h4voZwyimbkpMzjWOpsXBGkOPvrkznBsSQSZwj0InT0MlIo30zktl6QWTJGNY0hEpkE5IT5FPieKNkPOnoRJKy/sSiDKIZRXIlNG690WWWQ8EvTY25js/Olnl8ENvkW1yLybmL5GxRR4sw0y0+Gk/rrBM6QfYolY9i2YXczyfItMjDKTJ7eWDxbKa6mcfJXyQWWzyPIjuLyXgw2eZHeeSPLkWeTR5YPJcjGW+ZbXM82S2+B/r1J+TcvoSzbmentJvy0n4Lx7Gf7czOSO740tFotE46mV+uk6UQvgr4KZTKJ7Tw6Hi+RK6Mj9dLfA3K6mHjmfgm/YnBmCEzcjWF8n8kG56lE/Bj9Cs8DOEuBgjjZH6k/JvzN+hb5E9z/APU8ujLXJlrqT/Vm3Aj9T+UU+Zv0NyzcttcCU2ZS45aMb+5ifc+3sT+p/OjwycdCPlErlgpk/Bn9yGuYqfsyIJMafcrJJEn8GJIbN+Z5MshmW38GJLLyS8G3cjH9ORGVxMJ/Gkl6wUupsuLLzxPTgiI4Gz5kp8GYy17otM8OR4tPiW0X0Ja4l9vUh9vU8u08u3geSJ7kuBh9y98IjvXQtFkpYN17OCc+5bM5ZHdzJ7keRsyp9jDSKwZXc0Q0/c/27cEEM9SUQ2ThmTM6Suh/qV8m3U/LIM5fQ36Ep8kRjkQ1yK7GiexE9uF6l4I7yGmT2x9icovmR3HkbGxGDZk9p6e5HcQ0VkntIyi2X0PLPAtci0bG3U/56lLgR29SVhl9SD1JRui8+5sSj0J7s/YpM8TwfAj+yJb4o8uhDXItGxHyf+MntKaLZDQoR4kprmf9dTya9y1xJwzx6lNFkd2WZKZZJ6GV3FrBWSUzDLwR3Hki0UiEyUymblZ5FPkXzM2ijchkpM8WvY34logtlribMlEohkSiiUQ+pHdzM4TJ7Wi2iO4tFohLmUmeJ4niyuhsQV1K6lMt9TyLN0f6tmH3GxPabo8iFkp5+xb4mzJ7eRfPTKZ6koojSSUYwUePQ8Oh44KI+T0I7jyLzyKyVgkxJbJkohItInBZLL4HiQ8HqSiyD1MtFtEMnGu5fyWX+ukpFdSiitJSI0tlt8GeLa9iP/m8kdh4lLoZ+DCz9FfR9yiIJWSmUz8H4LIeeJeCHklIlNaWbH7G/Mln7EGEySVnkVj2I7sHqSfuZrSVrf1VpBRRKKKKJbJxrXM2IRn4MZPU9Bbk6ymZzghruXUlEwZ7XyIcErSGev0Y0nTOtk5NyEyFphFk6bkZ5EwbcyiUf6508SmbkkEyVg//2Q==
/%
!info
|Name|WordCount|
|Source|http://www.TiddlyTools.com/#WordCount|
|Version|2.0.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Description|display a count of the number of white-space separated words in a tiddler|
Usage:
<<<
{{{
<<tiddler WordCount>>
<<tiddler WordCount with: TiddlerTitle>>
}}}
<<<
!end
!out
$1
!end
!show
<<tiddler WordCount##out with: {{
	var title="$1"; if (title=='$'+'1')
		title=(story.findContainingTiddler(place)||place).getAttribute('tiddler')||'';
	var txt=store.getTiddlerText(title,'');
	(txt.match(/\S+/g)||[]).length.toString();
'';}}>>
%/<<tiddler {{
	var src='WordCount';
	src+(tiddler&&tiddler.title==src?'##info':'##show');
}} with: [[$1]]>>
!usage
{{{[img[application_add.png]]}}}
[img[application_add.png]]
!notes
license: http://www.famfamfam.com/lab/icons/silk/
!type
image/png
!file
./images/silk/icons/application_add.png
!url

!data
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAH9SURBVDjLpZM9aFRREIW/ue9FF2IULDQuaYIGtTBRWGFJAgqSUsEmjZVgo4mFWBiwVVjBHwjGwsbCShExIAghoEUMARGNGFJYhIC7isXGRbORvJ0Zi/dWY5fFCwOnuHz3nDsz4u78z5HTlx6NDB4v3KjWvd0dMMPNUFPcHHPDVTF3XBU1Y/uWZHVxsXzl6e3hibgwUBhvy7WH3bmWHm5fres4MBHXEw/16s+Wra8lHgBiV+f6mX0tA86VlkkBbgCsNxQH3Bw1MBwzR83Qhqflxro63Z0dqGkKIOuCBEHc8SC4OGJCCIJIQESRyIksEDfS+9bIAE1SAFwEBCIHEzBzIocgEbGAiqMhdWxqWQTL5kAE3P8BiYCrYwIuQBAii1JAM0JTpAxJxQaQxUJsxvTbSV7NP6e2ukLSSFjT/cBJ4kaS/HEggLsjIvgG0Is3T3hfnuLYwFG6dvbwcuEZcx+nKY7mbwbPskSAZC4k00GEIMLk64ccPtCHBqVvzxAqCcVD/QAjwcz+Rsg+M4gQbahv37/QJts4dfAiAJdP3Gfvrl6AXFxeWn58/k4ybKqYGqqKmaFJgplh7lRrKyxUZpmvzDA29IDS1Fly0VaAX7KZbSyO5q91de+42t87SE/nET59fcfshxk+L9VuyWbXuTiaLwEXgA7gB3Bv7m5l7Dd8kw6XoJxL0wAAAABJRU5ErkJggg==
!usage
{{{[img[application_form_edit.png]]}}}
[img[application_form_edit.png]]
!notes
license: http://www.famfamfam.com/lab/icons/silk/
!type
image/png
!file
./images/silk/icons/application_form_edit.png
!url

!data
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAJcSURBVDjLpZPvS1NRGMfvv9Db6FUvIpDqLwj6AZER1EhBkvTFTALNlWJrkwKRoWKGjZltaUmuYmsIq7SEtrSt1qakzh/TtunSdq9j8253u3fL1vh27t2KNAqsAx+ecw7n+z0PzzkPBYD6HyjZZVNNpzXINz0OQP2IYPwI1YMFXOmfQ+O9WTT0eVFvmMQl/Qcobo+jVueG2uDkRZ1koLEEc9qRNWwXRddYTjIQb/4XqjtGIRmojX6k0+ltI2+15Q1UA4sQBAG8BA+e56W5w+H4jQmbDgsPy+C3ajDVdwzT3UUVlFiwZDKJshbvT1JkLQp+HQJtBWNXIuF9DqTCiHstcN04vkaJ1U5wHLgEgUsUIrfJQKCHwM43Y2P1KZjRDqRnBvEt5MTM/eoMJT4Vy8YRj8elKBFnSWTJHovoEhHPXkMu7UQ6WIt1z0X4BuRw6+XwaGV7qIbeacRiMUQLiPNYNCZl4LF1g51RIZdxQQhUIrNSjuS8GqH+06i73psvoqJnApFIZFMNxPXrwXYw48qCuAKZT2fBzTZhyXASjM+JkkZL3qBO5wHDMIS1QmTge2fE/MtGkvYbZJbl+LJyDgmSSUB/Al85WjpzpsGcN6jVvkc4TBPCoAnuoR7MDasx/aILn92lEJbLsT51Ff67p7C6OAmaFs/RkNWb8KMXTBduOqSfVdVmh7n9KJAMYcFQArt6J97eKcZw8yHUqPQk7SfkZhOIRsQkGWztrpbzRdkNlw4b7ltwaw7DXLUrNaLaf+CP3bh1o/Tgjkxr5d6sra04+6rzyNgz5b7df2vn7z39IYTVO0xbAAAAAElFTkSuQmCC
!usage
{{{[img[arrow_undo.png]]}}}
[img[arrow_undo.png]]
!notes
license: http://www.famfamfam.com/lab/icons/silk/
!type
image/png
!file
./images/silk/icons/arrow_undo.png
!url

!data
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAIJSURBVDjLpVM9aJNRFD35GsRSoUKKzQ/B0NJJF3EQlKrVgijSCBmC4NBFKihIcXBwEZdSHVoUwUInFUEkQ1DQ4CKiFsQsTrb5xNpgaZHw2Uog5t5zn0NJNFaw0guX97hwzuPcc17IOYfNlIdNVrhxufR6xJkZjAbSQGXjNAorqixSWFDV3KPhJ+UGLtSQMPryrDscPwLnAHOEOQc6gkbUpIagGmApWIb/pZRX4fjj889nWiSQtgYyBZ1BTUEj6AjPa0P71nb0Jfqwa+futIheHrzRn2yRQCUK/lOQhApBJVQJChHfnkCqOwWEQ+iORJHckUyX5ksvAEyGNuJC+s6xCRXNHNxzKMmQ4luwgjfvZp69uvr2+IZcyJ8rjIporrxURggetnV0QET3rrPxzMNM2+n7p678jUTrCiWhphAjVHR9DlR0WkSzf4IHxg5MSF0zXZEuVKWKSlCBCostS8zeG7oV64wPqxInbw86lbVXKEQ8mkAqmUJ4SxieeVhcnANFC02C7N2h69HO2IXeWC8MDj2JnqaFNAMd8f3HKjx6+LxQRmnOz1OZaxKIaF1VISYwB9ARZoQaYY6o1WpYCVYxt+zDn/XzVBv/MOWXW5J44ubRyVgkelFpmF/4BJVfOVDlVyqLVBZI5manPjajDOdcswfG9k/3X9v3/vfZv7rFBanriIo++J/f+BMT+YWS6hXl7QAAAABJRU5ErkJggg==
!usage
{{{[img[asterisk_yellow.png]]}}}
[img[asterisk_yellow.png]]
!notes
license: http://www.famfamfam.com/lab/icons/silk/
!type
image/png
!file
./images/silk/icons/asterisk_yellow.png
!url

!data
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAJ5SURBVDjLpZPNS1RhFMaff2EWLWo5tGnRaqCFRBAM0cZFwVSQpVHNQAWVMQwaSSZWtimLiKnsO5lEjKzs4y1zRK3oItfMj1FnnJkaUtNrjo45H3eejpCKNa5anMX73vs855zfOS9I4n9i2SHbCpvph8q8A9PNcCzcz76EM9EETj+DmmqENaeBiJ3mRyuzQy5mwyVMKqiFbzNN0MxgKZOd2zj5GMZE/ZL5ooHZAntGW89s7Bw5Ws25llWcfQHrzHPYE/51ZOQ0M4Fiitj4UQdbzhZSb+FJ63ZypJqp7p0UsTf+FN6kvoMMl3GmNY9jj+BckcF8/HoFldLzpZIqxhthJPVdkr2cifdb5sXefyAKLFvyzVJJAssisIxstILZ0DEyeJzpHifHfNBGamFZ+C9yC7bhG7BBxCrZZqWQpoiNP6S1TMBFDh4gA0VMdxfy+0NosftQX+8gGKkBY741HLoGhbnXUOZwKTn+gGa4nOlBN9MDxdJzCTmwj+wvEKPDTPUc5Zx+kOk+NxmqZOJTIXsviYGQVgKLAos/n0CbbIAS0ir1eY9kF4O+3UzpBYzehhaugQpdR3DwKth7EeyqEoO/oYzXwyKwDDN0ipme/VKFi0l9L8M3oYW8SwxWnIKI1XT7Vqb6i/ntLoLTHdulhROcUJsZuJJjCsvEPpyf8m8io5U0VB6FtFNIe6da84XFEcYaNrDzLDw5DUZ9cEwqm6zxGWYGPBTShogtQtoerV0rLA5JKy5+ubya7SdzbKKMyRG7ByPeIfvebKfAWszUdQFavKOI0bqNbCuF4XfneAvzIaStQrpOxEpIL746rQKOD2VQbSXwtLiXg/wNTNvAOhsl8oEAAAAASUVORK5CYII=
!usage
{{{[img[camera.png]]}}}
[img[camera.png]]
!notes
license: http://www.famfamfam.com/lab/icons/silk/
!type
image/png
!file
./images/silk/icons/camera.png
!url

!data
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAIrSURBVDjLxVPLjhJBFD3V3dCYSZjwDipDRjCOCcTgLGalJmxYufAD0E/QHV9g3LjSsGDhik/QjTEaTdgaEsQQINEFJjwEecmr6Yf3lkJmPwsruXWrq+85dc+9VcJxHFxkKLjg0HgqlUpP1+t1drvdXrIsS2w2G9dqtXKzt21b6Lpu+P3+N4VC4QnH5/P5U3Lfy+XyL1EsFg9VVZ1kMhmwHAJIa1Tf4eH96zC+vcKLDyfwRm6i1Wo/Go/HLwnsJWPtZ2oikainUil/JBJBp9NBr9fDcDjE5aMTfPz8E835bdw6vQMhBLrd7gNFUXSPxwNN08RsNrur0alJr9eLer2OcDiMdDoNkgKSglAohEajgUqlgkAggGw2i36/j8lkImOazeYNjQMHgwGCwSC2B0d4/n6FhSlgU366cOHe1Wvwz+eUfgucJQPb7Tai0aiUqvC0WCwQi8Xw+ouBjaPA4yJzK7AUFz79OJDA0WgkwYZhgAq8z1JjAqq2tN+Wm4AqNGouXw9Bk+G4QR2SxmCO4zV7mQGz7Fh5OI79F0wkCpmqCCyXSxlzPoM9wS4DqijcjgHTJv22Q+k5ksiNFabTqQSapilJOJ79noAZa7UaMoc9qOYSG9oziUSxlriy+YpqtbrXvSPZEWjMxidwewLjMc6Oj2VxOGBO1WdivhvJZFLusf54PC5lMYHI5XKPqa/P6EP3+XyCry4T8E/2BHDoEIdv6fmH92/9Vvz31/gHd9iUVZFEDKoAAAAASUVORK5CYII=
!usage
{{{[img[cog.png]]}}}
[img[cog.png]]
!notes
license: http://www.famfamfam.com/lab/icons/silk/
!type
image/png
!file
./images/silk/icons/cog.png
!url

!data
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAGSSURBVCjPVVFNSwJhEF78Ad79Cf6PvXQRsotUlzKICosuRYmR2RJR0KE6lBFFZVEbpFBSqKu2rum6llFS9HHI4iUhT153n6ZtIWMOM+/MM88z7wwH7s9Ub16SJcnbmrNcxVm2q7Z8/QPvEOtntpj92NkCqITLepEpjix7xQtiLOoQ2b6+E7YAN/5nfOEJ2WbKqOIOJ4bYVMEQx4LfBBQDsvFMhUcCVU1/CxVXmDBGA5ZETrhDCQVcYAPbyEJBhvrnBVPiSpNr6cYDNCQwo4zzU/ySckkgDYuNuVpI42T9k4gLKGMPs/xPzzovQiY2hQYe0jlJfyNNhTqiWDYBq/wBMcSRpnyPzu1oS7WtxjVBSthU1vgVksiQ3Dn6Gp5ah2YOKQo5GiuHPA6xT1EKpxQNCNYejgIR457KKio0S56YckjSa9jo//3mrj+BV0QQagqGTOo+Y7gZIf1puP3WHoLhEb2PjTlCTCWGXtbp8DCX3hZuOdaIc9A+aQvWk4ihq95p67a7nP+u+Ws+r0dql9z/zv0NCYhdCPKZ7oYAAAAASUVORK5CYII=
!usage
{{{[img[cross.png]]}}}
[img[cross.png]]
!notes
license: http://www.famfamfam.com/lab/icons/silk/
!type
image/png
!file
./images/silk/icons/cross.png
!url

!data
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAIhSURBVDjLlZPrThNRFIWJicmJz6BWiYbIkYDEG0JbBiitDQgm0PuFXqSAtKXtpE2hNuoPTXwSnwtExd6w0pl2OtPlrphKLSXhx07OZM769qy19wwAGLhM1ddC184+d18QMzoq3lfsD3LZ7Y3XbE5DL6Atzuyilc5Ciyd7IHVfgNcDYTQ2tvDr5crn6uLSvX+Av2Lk36FFpSVENDe3OxDZu8apO5rROJDLo30+Nlvj5RnTlVNAKs1aCVFr7b4BPn6Cls21AWgEQlz2+Dl1h7IdA+i97A/geP65WhbmrnZZ0GIJpr6OqZqYAd5/gJpKox4Mg7pD2YoC2b0/54rJQuJZdm6Izcgma4TW1WZ0h+y8BfbyJMwBmSxkjw+VObNanp5h/adwGhaTXF4NWbLj9gEONyCmUZmd10pGgf1/vwcgOT3tUQE0DdicwIod2EmSbwsKE1P8QoDkcHPJ5YESjgBJkYQpIEZ2KEB51Y6y3ojvY+P8XEDN7uKS0w0ltA7QGCWHCxSWWpwyaCeLy0BkA7UXyyg8fIzDoWHeBaDN4tQdSvAVdU1Aok+nsNTipIEVnkywo/FHatVkBoIhnFisOBoZxcGtQd4B0GYJNZsDSiAEadUBCkstPtN3Avs2Msa+Dt9XfxoFSNYF/Bh9gP0bOqHLAm2WUF1YQskwrVFYPWkf3h1iXwbvqGfFPSGW9Eah8HSS9fuZDnS32f71m8KFY7xs/QZyu6TH2+2+FAAAAABJRU5ErkJggg==
!usage
{{{[img[css.png]]}}}
[img[css.png]]
!notes
license: http://www.famfamfam.com/lab/icons/silk/
!type
image/png
!file
./images/silk/icons/css.png
!url

!data
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAGeSURBVDjLxVNNS0JRED3qA0MRoqCFouBGN9Yia9HGRa3b9x/6M62jf9CuTS0EV0arXASG0gcUYWIgmvi6792P7sz1WUI7Fw0Mc70z59wz88aYMQbLWBxL2tIEXrN5+mcPWkvrBsZQVNYDSKmglLTZ0J4lwjCER8XZ7OYcSDMxRs/cEdCZSKKoNeUU7u/rjoBMiE8GuKQrcCA1A0XuFK2sZKwC3xE4Zo1UahX5/Dam0yH6/Q4KhV17H+Lu7gKVyiESCQ/dbgPD4QvfSykQlzKcMxP4+fnGJr4seAdPT01MJh8oFve4uNOp20fWQBilQqvAEtBQqE+6IBuPe3h8bML3hyiX95FOr6HXayOT2UCpdIDR6I1r6VF6KK61z5N1ROAkvdBuX+H6+oznksttodE4wevrLbdC8h1GwCMZJF+pgIdSrR6xtCCYWLnrnBuP31GrHfN5MHhgcDRUj3pzbAFarfOFSUf++4tEA3dRwhNCsKRkMv2r+Oe7R7+jvbArNotu/6wC3/Z7yX3TdhkjbDS8eUTi5EoGuLhosX//N34Dm6aVPfzbYjIAAAAASUVORK5CYII=
!usage
{{{[img[delete.png]]}}}
[img[delete.png]]
!notes
license: http://www.famfamfam.com/lab/icons/silk/
!type
image/png
!file
./images/silk/icons/delete.png
!url

!data
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAJdSURBVDjLpZP7S1NhGMf9W7YfogSJboSEUVCY8zJ31trcps6zTI9bLGJpjp1hmkGNxVz4Q6ildtXKXzJNbJRaRmrXoeWx8tJOTWptnrNryre5YCYuI3rh+8vL+/m8PA/PkwIg5X+y5mJWrxfOUBXm91QZM6UluUmthntHqplxUml2lciF6wrmdHriI0Wx3xw2hAediLwZRWRkCPzdDswaSvGqkGCfq8VEUsEyPF1O8Qu3O7A09RbRvjuIttsRbT6HHzebsDjcB4/JgFFlNv9MnkmsEszodIIY7Oaut2OJcSF68Qx8dgv8tmqEL1gQaaARtp5A+N4NzB0lMXxon/uxbI8gIYjB9HytGYuusfiPIQcN71kjgnW6VeFOkgh3XcHLvAwMSDPohOADdYQJdF1FtLMZPmslvhZJk2ahkgRvq4HHUoWHRDqTEDDl2mDkfheiDgt8pw340/EocuClCuFvboQzb0cwIZgki4KhzlaE6w0InipbVzBfqoK/qRH94i0rgokSFeO11iBkp8EdV8cfJo0yD75aE2ZNRvSJ0lZKcBXLaUYmQrCzDT6tDN5SyRqYlWeDLZAg0H4JQ+Jt6M3atNLE10VSwQsN4Z6r0CBwqzXesHmV+BeoyAUri8EyMfi2FowXS5dhd7doo2DVII0V5BAjigP89GEVAtda8b2ehodU4rNaAW+dGfzlFkyo89GTlcrHYCLpKD+V7yeeHNzLjkp24Uu1Ed6G8/F8qjqGRzlbl2H2dzjpMg1KdwsHxOlmJ7GTeZC/nesXbeZ6c9OYnuxUc3fmBuFft/Ff8xMd0s65SXIb/gAAAABJRU5ErkJggg==
!usage
{{{[img[disk.png]]}}}
[img[disk.png]]
!notes
license: http://www.famfamfam.com/lab/icons/silk/
!type
image/png
!file
./images/silk/icons/disk.png
!url

!data
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAH+SURBVBgZBcE9i11VGAbQtc/sO0OCkqhghEREAwpWAWUg8aMVf4KFaJEqQtAipTZWViKiCGOh2Ap2gmJhlSIWFsFOxUK0EsUM3pl79n4f12qHb3z3Fh7D83gC95GOJsDe0ixLk5Qq/+xv/Lw9Xd+78/HLX3Y8fXTr2nWapy4eCFKxG7Fby97SnDlYtMbxthyfzHO//nl85fNvfvnk8MbX5xa8IHx1518Vkrj54Q+qQms2vVmWZjdiu5ZR2rT01166/NCZg/2PFjwSVMU6yjoC1oq+x6Y3VbHdlXWExPd379nf7Nmejv2Os6OC2O4KLK0RNn3RNCdr2Z5GJSpU4o+/TkhaJ30mEk5HwNuvX7Hpi76wzvjvtIwqVUSkyjqmpHS0mki8+9mPWmuWxqYvGkbFGCUAOH/+QevYI9GFSqmaHr5wkUYTAlGhqiRRiaqiNes6SOkwJwnQEqBRRRJEgkRLJGVdm6R0GLMQENE0EkmkSkQSVVMqopyuIaUTs0J455VLAAAAAODW0U/GiKT0pTWziEj44PZ1AAAAcPPqkTmH3QiJrlEVDXDt0qsAAAAAapa5BqUnyaw0Am7//gUAAAB49tEXzTmtM5KkV/y2G/X4M5fPao03n/sUAAAAwIX7y5yBv9vhjW/fT/IkuSp5gJKElKRISYoUiSRIyD1tufs/IXxui20QsKIAAAAASUVORK5CYII=
!usage
{{{[img[exclamation.png]]}}}
[img[exclamation.png]]
!notes
license: http://www.famfamfam.com/lab/icons/silk/
!type
image/png
!file
./images/silk/icons/exclamation.png
!url

!data
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAJPSURBVDjLpZPLS5RhFMYfv9QJlelTQZwRb2OKlKuINuHGLlBEBEOLxAu46oL0F0QQFdWizUCrWnjBaDHgThCMoiKkhUONTqmjmDp2GZ0UnWbmfc/ztrC+GbM2dXbv4ZzfeQ7vefKMMfifyP89IbevNNCYdkN2kawkCZKfSPZTOGTf6Y/m1uflKlC3LvsNTWArr9BT2LAf+W73dn5jHclIBFZyfYWU3or7T4K7AJmbl/yG7EtX1BQXNTVCYgtgbAEAYHlqYHlrsTEVQWr63RZFuqsfDAcdQPrGRR/JF5nKGm9xUxMyr0YBAEXXHgIANq/3ADQobD2J9fAkNiMTMSFb9z8ambMAQER3JC1XttkYGGZXoyZEGyTHRuBuPgBTUu7VSnUAgAUAWutOV2MjZGkehgYUA6O5A0AlkAyRnotiX3MLlFKduYCqAtuGXpyH0XQmOj+TIURt51OzURTYZdBKV2UBSsOIcRp/TVTT4ewK6idECAihtUKOArWcjq/B8tQ6UkUR31+OYXP4sTOdisivrkMyHodWejlXwcC38Fvs8dY5xaIId89VlJy7ACpCNCFCuOp8+BJ6A631gANQSg1mVmOxxGQYRW2nHMha4B5WA3chsv22T5/B13AIicWZmNZ6cMchTXUe81Okzz54pLi0uQWp+TmkZqMwxsBV74Or3od4OISPr0e3SHa3PX0f3HXKofNH/UIG9pZ5PeUth+CyS2EMkEqs4fPEOBJLsyske48/+xD8oxcAYPzs4QaS7RR2kbLTTOTQieczfzfTv8QPldGvTGoF6/8AAAAASUVORK5CYII=
!usage
{{{[img[help.png]]}}}
[img[help.png]]
!notes
license: http://www.famfamfam.com/lab/icons/silk/
!type
image/png
!file
./images/silk/icons/help.png
!url

!data
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAKkSURBVDjLpZPdT5JhGMb9W+BPaK3matVqndXWOOigA6fmJ9DUcrUMlrN0mNMsKTUznQpq6pyKAm8CIogmypcg8GIiX8rHRHjhVbPt6o01nMvZWge/k3vP9duuZ/edAyDnf/hjoCMP2Vr3gUDj3CdV6zT1xZ6iFDaKnLEkBFOmPfaZArWT5sw60iFP+BAbOzTcQSqDZzsNRyCNkcVoaGghzDlVQKylOHJrMrUZ2Yf52y6kc36IxpyoH1lHF7EBgyMKV4jCJ5U/1UVscU4IZOYEa3I1HtwI01hwxlDLhDoJD/wxGr5YGmOLAdRIrVCuhmD3JdA6SQabx12srGB0KSpc86ew4olDOGjH4x4z0gdHDD9+c4TaQQtq+k2Yt0egXYugTmoVZgV9cyHSxXTtJjZR3WNCVfcK/NE0ppYDUNu2QTMCtS0IbrsOrVMOWL27eNJtJLOCDoWXdgeTEEosqPxoBK/TwDzWY9rowy51gJ1dGr2zLpS2aVH5QQ+Hbw88sZ7OClrGXbQrkMTTAQu4HXqUv9eh7J0OSfo7tiIU+GItilpUuM/AF2tg98eR36Q+FryQ2kjbVhximQu8dgPKxPMoeTuH4tfqDIWvCBQ2KlDQKEe9dBlGTwR36+THFZg+QoUxAL0jgsoOQzYYS+wjskcjTzSToVAkA7Hqg4Spc6tm4vgT+eIFVvmb+eCSMwLlih/cNg0KmpRoGzdl+BXOb5jAsMYNjSWAm9VjwesPR1knFilPNMu510CkdPZtqK1BvJQsoaRZjqLGaTzv1UNp9EJl9uNqxefU5QdDnFNX+Y5Qxrn9bDLUR6zjqzsMizeWYdG5gy6ZDbk8aehiuYRz5jHdeDTKvlY1IrhSMUxe4g9SuVwpdaFsgDxf2i84V9zH/us1/is/AdevBaK9Tb3EAAAAAElFTkSuQmCC
!usage
{{{[img[html.png]]}}}
[img[html.png]]
!notes
license: http://www.famfamfam.com/lab/icons/silk/
!type
image/png
!file
./images/silk/icons/html.png
!url

!data
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAHUSURBVDjLxZM7a1RhEIafc3J2z6qJkIuCKChItBNSBQ0iIlZiK4gWItj6HwRbC7FRf4CVnSCIkH9gJVjYiCDximCyZ7/zfXOz2A0I2qVwmmFg3rm870wVEezFavZoey7Q3Hv+/Z87qDsiTlZFBJIGKStZlFSCTpyUlAZgfXXfH9BAPTCberVANBB3RAJRR8wp6jzd/DotALA9UcyZgZxis2QNijpZjSJBVqeIszTfkMY65cAjuHxmgSzGlbUFrp1d5ObGErcuLLNxep5hU3H93AqjYcXti4cZZ2OSDU9CnVURddqmIovTDmoev/5GVcGDF585tjzg1JGWo0tDDgxrThxq6XojieOd0nRZ6dVpBxU3zi/T1BVdViKCcTbcYX11ngB6cca9MSlGlprojHqcglycVJyHL79Q1Jn0TgBdb1gEbz9OeL81IYsRAakYvQSeC/WvVOiLE8GsM4xnvsuGe/Do1RY/dpRenIP753hyZxURJ3JQXbr/Lq6uLfLpZ6aIk9XJssv8VK5dNcQcmcl7fKVl89kHmu0dJRVjYTRHGVSMpELaQLVCtEY8EAvMHHUwn067+0LVybtvok9KSODZiaKEOJENihPm01gD3P+62Oq/f+Nv2d9y2D8jLUEAAAAASUVORK5CYII=
!usage
{{{[img[i4logo.gif]]}}}
[img[i4logo.gif]]
!notes
&copy; 1995 ELS Design Studios - do not use without explicit prior permission
!type
image/gif
!file
./images/i4logo.gif
!url

!data
data:image/gif;base64,R0lGODlhIwAoALMAAAAAAAAQAAAYAAAhAAApAAAxAABCAABSAABeAAB2AACMAACUAACcAAClAACtAADGACH5BAEAAAAALAAAAAAjACgAQAT+EMhJq704S/WewQoTBJ2jaUinriyTFaupJZ1yAqlq33zPGyrBScD6SAIMBIX4kF0GigbrEdDAHovbtePyaQLSVcFLLlMGDaUZ1AirT5zVgILcAWiP9wnpMG66FHEJBAp2GQEIaXAdYydbHXoXDB0EPJMqfmsVYR2ZmhMslZ8Sj1MJo6gXAUKpFQQOHq0TByqAPAenGSFIjD1xDw0WAQs7QA+GGQNTrABIuRJSDnM8eH2ByDk2AciHgU2F4L+YZQjh4bDAhdMYAQa/jewqVRnGLNwVeM8aTCXrF/w9ctSAgwDBvD0smKUSF2kUvw4HF65o+KkepVaEpjgwOIoAAgMKBAqMCFkwopkIAAA7
!usage
{{{[img[information.png]]}}}
[img[information.png]]
!notes
license: http://www.famfamfam.com/lab/icons/silk/
!type
image/png
!file
./images/silk/icons/information.png
!url

!data
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAKcSURBVDjLpZPLa9RXHMU/d0ysZEwmMQqZiTaP0agoaKGJUiwIxU0hUjtUQaIuXHSVbRVc+R8ICj5WvrCldJquhVqalIbOohuZxjDVxDSP0RgzyST9zdzvvffrQkh8tBs9yy9fPhw45xhV5X1U8+Yhc3U0LcEdVxdOVq20OA0ooQjhpnfhzuDZTx6++m9edfDFlZGMtXKxI6HJnrZGGtauAWAhcgwVnnB/enkGo/25859l3wIcvpzP2EhuHNpWF9/dWs/UnKW4EOGDkqhbQyqxjsKzMgM/P1ymhlO5C4ezK4DeS/c7RdzQoa3x1PaWenJjJZwT9rQ1gSp/js1jYoZdyfX8M1/mp7uFaTR8mrt29FEMQILr62jQ1I5kA8OF59jIItVA78dJertTiBNs1ZKfLNG+MUHX1oaURtIHEAOw3p/Y197MWHEJEUGCxwfHj8MTZIcnsGKxzrIURYzPLnJgbxvG2hMrKdjItjbV11CYKeG8R7ygIdB3sBMFhkem0RAAQ3Fuka7UZtRHrasOqhYNilOwrkrwnhCU/ON5/q04vHV48ThxOCuoAbxnBQB+am65QnO8FqMxNCjBe14mpHhxBBGCWBLxD3iyWMaYMLUKsO7WYH6Stk1xCAGccmR/Ozs/bKJuXS39R/YgIjgROloSDA39Deit1SZWotsjD8pfp5ONqZ6uTfyWn+T7X0f59t5fqDhUA4ry0fYtjJcWeZQvTBu4/VqRuk9/l9Fy5cbnX+6Od26s58HjWWaflwkusKGxjm1bmhkvLXHvh1+WMbWncgPfZN+qcvex6xnUXkzvSiYP7EvTvH4toDxdqDD4+ygT+cKMMbH+3MCZ7H9uAaDnqytpVX8cDScJlRY0YIwpAjcNcuePgXP/P6Z30QuoP4J7WbYhuQAAAABJRU5ErkJggg==
!usage
{{{[img[layout.png]]}}}
[img[layout.png]]
!notes
license: http://www.famfamfam.com/lab/icons/silk/
!type
image/png
!file
./images/silk/icons/layout.png
!url

!data
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAFySURBVBgZpcE7a1RBGMfh3xwnRziwBlOoBEG28FYriMSU9oKkTop8AcFWEKystRDEL2BnIVbapdVC8EbAYCEokgsL2T05M+/fd9CFRTcYyfMESRxGxK08fHMLOANcAy6BhAiYqKpAFcDMsMz2TNT6+dPHLmPi9s0LAUksP3j9WP/p/tN3ckR+WcQ9WdtkTOxvdWGOD1+2W1ykMJ3it7MnjlKEwFQfv7UUw1FX4yJOUoMT8Ol7y0Eo54CLOJkibnVhjoOybBQRJ1PALd19ycgMEzy/d53PX3eYpj8/iyxTVDiZUfwYdly5eJLNYWKs19T0mppeU9NrasaUMkWFk4liMMp0ErttYlKXRZfFJLNEUeGCGUXbdgy7TB51/IvSHkXECTEm8ZeZI4E/SYki4iyZgIB7sbbBpMHuHtPIJFzEZbMNoP/20Q0m9edn2Y+kLVykyPZs6c6rc5KuYnbcLIEMWUaWQBmZIQmQwAZQvccFSRzGT6Th9AjEKBwhAAAAAElFTkSuQmCC
!usage
{{{[img[page.png]]}}}
[img[page.png]]
!notes
license: http://www.famfamfam.com/lab/icons/silk/
!type
image/png
!file
./images/silk/icons/page.png
!url

!data
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAINSURBVBgZBcG/r55zGAfg6/4+z3va01NHlYgzEfE7MdCIGISFgS4Gk8ViYyM2Mdlsko4GSf8Do0FLRCIkghhYJA3aVBtEz3nP89wf11VJvPDepdd390+8Nso5nESBQoq0pfvXm9fzWf19453LF85vASqJlz748vInb517dIw6EyYBIIG49u+xi9/c9MdvR//99MPPZ7+4cP4IZhhTPbwzT2d+vGoaVRRp1rRliVvHq+cfvM3TD82+7mun0o/ceO7NT+/4/KOXjwZU1ekk0840bAZzMQ2mooqh0A72d5x/6sB9D5zYnff3PoYBoWBgFKPKqDKqjCpjKr//dcu9p489dra88cydps30KswACfNEKanSaxhlntjJ8Mv12Paie+vZ+0+oeSwwQ0Iw1xAR1CiFNJkGO4wu3ZMY1AAzBI0qSgmCNJsJUEOtJSMaCTBDLyQ0CknAGOgyTyFFiLI2awMzdEcSQgSAAKVUmAeNkxvWJWCGtVlDmgYQ0GFtgg4pNtOwbBcwQy/Rife/2yrRRVI0qYCEBly8Z+P4qMEMy7JaVw72N568e+iwhrXoECQkfH91kY7jwwXMsBx1L93ZruqrK6uuiAIdSnTIKKPLPFcvay8ww/Hh+ufeznTXu49v95IMoQG3784gYXdTqvRmqn/Wpa/ADFX58MW3L71SVU9ETgEIQQQIOOzub+fhIvwPRDgeVjWDahIAAAAASUVORK5CYII=
!usage
{{{[img[page_copy.png]]}}}
[img[page_copy.png]]
!notes
license: http://www.famfamfam.com/lab/icons/silk/
!type
image/png
!file
./images/silk/icons/page_copy.png
!url

!data
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAIpSURBVDjLddM9aFRBFIbh98zM3WyybnYVf4KSQjBJJVZBixhRixSaShtBMKUoWomgnaCxsJdgIQSstE4nEhNREgyoZYhpkogkuMa4/3fuHIu7gpLd00wz52POMzMydu/Dy958dMwYioomIIgqDa+VnWrzebNUejY/NV6nQ8nlR4ufXt0fzm2WgxUgqBInAWdhemGbpcWNN9/XN27PPb1QbRdgjEhPqap2ZUv5+iOwvJnweT1mT5djZKjI6Ej/udz+wt1OJzAKYgWyDjJWyFghmzFsbtcY2gsTJwv09/Vc7RTgAEQgsqAKaoWsM8wu/z7a8B7vA8cHD3Fr+ktFgspO3a+vrdVfNEulJ/NT4zWngCBYY1oqSghKI465fvYwW+VAatPX07IZmF7YfrC0uDE8emPmilOFkHYiBKxAxhmSRPlZVVa2FGOU2Ad2ap4zg92MDBXJZczFmdflx05VEcAZMGIIClZASdesS2cU/dcm4sTBArNzXTcNakiCb3/HLRsn4Fo2qyXh3WqDXzUlcgYnam3Dl4Hif82dbOiyiBGstSjg4majEpl8rpCNUQUjgkia0M5GVAlBEBFUwflEv12b/Hig6SmA1iDtzhcsE6eP7LIxAchAtwNVxc1MnhprN/+lh0txErxrPZVdFdRDEEzHT6LWpTbtq+HLSDDiOm2o1uqlyOT37bIhHdKaXoL6pqhq24Dzd96/tUYGwPSBVv7atFglaFIu5KLuPxeX/xsp7aR6AAAAAElFTkSuQmCC
!usage
{{{[img[page_edit.png]]}}}
[img[page_edit.png]]
!notes
license: http://www.famfamfam.com/lab/icons/silk/
!type
image/png
!file
./images/silk/icons/page_edit.png
!url

!data
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAK5SURBVBgZBcFPaJZ1HADwz+95n3e6uTnREGdljRKtGCYiHTLxkIUmQeeCOnXzVnQIoi5BQV08TMo6GIiHiKI6ZEWgszzEmtpqSDP7s9ycm9NN977vnuf37fNJEWH/G6df6l676vki2YXVSCAhEpFVOU8uzMX36daNV88MH+oApIhw8O2zZz45vOuhokjrgoYAIALC7NKKEz8vmP67fee3XyfWjwwfakMJRSNt6yob68avaRQpkYhMHVlVheWV2r6tffYPjNi4eLyncWCodf7jI1Jr6sUSUkq9EdHoajQkIZALZOpEIWlPf27r4jndQy/oH9xp4c9tJk4de7eEIEGBlAgJREqKRP/yKXVcsH7r4+Ynf9eVOvrWbtK7YUt/CRBB2SBJIiW5Doqkd3nEllWj+gef1r56UldP8tfYhJt3UhTtuR0FRBAoU6FISYFGkaxePG1LfKv/gYNa/30oNW9o9vbpzvOOXj+wsvvwZ5cKCGSkRJGSIiWtK19af/uU/gef1ZoaVjRXdG7db+bMed173zJVD2QoIFdEkBG4fflrPYs/2vjIMzrTxzS6QvvWfWZGRs3tGZY2bFdnoICcQ0QQTI+e1L3wk5W82dWLR2Qtt+fvNnNuwuLeo1LvgNXNpK4CFFBn6iAysxc/8vCel636Z8SlL84a+2be+Hdjlh57R9WzWaDZKFSdCpSQq5AjvPlLx9DkrM74VwZ3POHm7JzJsUk/7PvU9Sv3yipwYlPTSjuDEqqqVtcMrG0a/+Oa9z8Ytnv7oOXNOyw9edyjffeIIIIL1yqRw0qrAiVU7ZyrnKNTS+te/9flFCYlkJdIS5UcRJEUOSnLlKs6V1DCSqueWdPVuOu1oc6aiCgEGdDfXYIIuptJSnKzkRbrKk9BCSnFe0+9cvq5lNLOED0AgkAIIEAr5zxaFk7A/5IUWNTkV3l/AAAAAElFTkSuQmCC
!usage
{{{[img[page_find.png]]}}}
[img[page_find.png]]
!notes
license: http://www.famfamfam.com/lab/icons/silk/
!type
image/png
!file
./images/silk/icons/page_find.png
!url

!data
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAMBSURBVBgZBcFLaJxVGIDh9zvn/2cmmWTSJk1oxUu1xCZoi1qvi6gggpRIdd2Niy6KVRChiCBeNiK4KOiiGxGKkNiCpKIhQrzUxiINkmJqQqdt2iQzk8xkkiZNOpfMnHM+n0dUFYBXP774VksmedQIh4AUIAAIoAIacCHMbazpb7K5fnLi9GADQFQVgMOfX5r47t1D/cbIDgWLAgCAKoBSvtdk6J8Niovb1dn/rnX+dXpwOwIAMFb2JyK7Y2YFa0RAQAN4DTin1Jqel3vbee7RiMuh3Kqhb/2ld0Z3iqry0Rdfdy4vFdYsgTeOHufst1/RdJ73Pz2FD4GGU+oNz4u9KWbKitPA+L9Ffp+YG7b5tWrHzq7uTzq7up+/OjVJ/4GnufTHGP0Hn2AuO8O+/Y+DWDxKrE160sqeNsvBPUnOTxb7zX0P7M3MTk8dWy2VuFepc/XKJNve0AyGP8dHqWyuE1khYQ0314TLi44LN6okY4tExpmx82eP16qVtof7HqPn/oco37lLJtPOru7dtLam+encGSIRYmtIJiyphCWViFEMiME80tv3dro9wy8jQ1RW83S2JSjl5vj53DeUlnOMjQwTWyE2QhwZEtaSjAwBUIWoPdPRMvj6EW4t5FiazzLwymEKuXleGzzCcqnM+OgPGBEiq6ACCorgA/gAkXMu6bwnOzvNxmqJ4lIesQYxhts3r1FYmAdAEEQhMhCAVAzeKaaytclifol6rUY+l6OytcXd9Ttcz2ZZXSmyVi4SVPEBFAgKCsTW4BqOKL94+/rI92eoONv7YE+X/LjSwq0bC8zOF6hVq/iuvXx2pQmAKgQAYGh3THM7IKoKwMCHF2vDJ59NfTmT4KkeQ1DwCl4gKCigCqowveI49QIMvHehHgEAuO0QXAja8MjfBU8QRREAgoKgBAU1gglCFElwPrgIAKBZ96V0wu764EAjraoGhQAAdLREAKhCSyyIEGIrW96FgqgqAM+c+PWEa+qbIvKkoq0AACgooCgAKAD1EMKUgaH/AfiQhzSolJNMAAAAAElFTkSuQmCC
!usage
{{{[img[page_go.png]]}}}
[img[page_go.png]]
!notes
license: http://www.famfamfam.com/lab/icons/silk/
!type
image/png
!file
./images/silk/icons/page_go.png
!url

!data
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAKdSURBVBgZBcFLiFZlGADg5/3OmRlHbbwkpmQ37WZlmBYWIrnRRUnRolVQbcRN7Yp20SLauSvENgaB1C6KdpnlBbHMFl2IMsK7Ntg43mbm/8/53p4nMtO2dw+9Pj4x9koJGzEPAQIZZNXV+vfVK3kgrk29fXjPjgFAZKbnPjh6+NM3N64tJRYnjQQgE9LkjaH9J666dGbu1u+//rH0yJ4dc9BCaeKh0bZZ/Nu/mhJBkJU+q65LM8Pe1gdus+nB1vE6OT/rw1PPvvH1ku8/fH6uQEQszMxmtClGCm3QFJoggiJQrZwYteOple69f2y8nViwDwokAQUlKBFKhBKhRChNuPjfjHsWDj2yNOx85nbNSPMytACZtA0hZITaJyW0DaNZnLqSBrVT68CW1WOiLR20kEmijSKlRJQQyEo2hVFKDbU2UiEKKJCoiKBEKBFKhMgw0oSREr448YLPjm421hYVmUCB2pFJRSIzkUqhRGgb5rqhVcvW+uib9fpKX4EWak2ZSZIS7P12K9kb1M6g66xcssbaFZtcn73p1X336bvPQQt9pU+yUgFdHdj26Gv6rPraq9KF6bPWrdrsxmDGT7e2z3v8/ZlooXapZnrv54GQarCoG+izOn3lL8Pa6erQsB+6Nnfd+ru2uDG85fg/R2Zb6Lpe37NyYsSG5UVNDlyY1fWdOybu1tVen9XF6TOWLlzh5Nmjjv15OmfT4ha6uVq7WnPQi2PnezXSrW7gk2O7DerAbDewZtlaT6/e7sfTR5ybvmR8cs/NUx8/P9PCcLa/vGC0WfbOusGCzCyS+tgvYNF4C17ce6co4yavT/ly1w/TG3YePA8tROTu7W8deikinkg5H0CSSOnG8rmxc1PfxeLLX119ctfBk22xH/4HCmFTpxr5rC8AAAAASUVORK5CYII=
!usage
{{{[img[page_link.png]]}}}
[img[page_link.png]]
!notes
license: http://www.famfamfam.com/lab/icons/silk/
!type
image/png
!file
./images/silk/icons/page_link.png
!url

!data
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAALQSURBVBgZBcFfaJVlHADg532/bzvNo9MtY1oXRlRWsCREIlFXoaBmUEIkaH9uCsokEIK6qbtg4UVBIN0kFETQnVQ3FmXOxMwg1BApA9GdTdFJbLqzc87763lSRNjy/i+vDgw2dudkLe5AAgmRiKJbyj83r8eP6b+Zd44d3LEAkCLC9g+PH/ty39qHc07LgkoAEAHh2mzHV7/fNHWpfeuvs+eHJw7uaEMNuUqr++tq2bmrqpwSiSj0ouh2w+1Oz5MPLPH4g7WT5dqiKA/NjL313dDRT59pZ0gpLY6Iqr/K+jJ1ospUiZTIEoqVg/12rFvp3vsbA/Vg8xBkCBJk5EROSU5JTklOSa6S1o3bVi3ueGQ4ee2JO1V91QtQA0RQVyRJpKT0gpzUFf2R/X09LJSuUhZsvK8h1bkLNUQQqFMWQiDlJCEKUWX6ySUppRIyKYMaAgUpkSSBQBT6KkDKUi+JHAoigBpKlwgKEiIC5IyS1FUQiSAkvUKvADWUEiKCYL5927k/jpu8eMby4SFTV69b9/ROA0uGHDt8yMhdQ36dmTE0O1iPjb3brKFX6AWdhY4jh7/WiFkv79ltbm7O5cuX/Tbxrap/wM7nnlXXlVarpe/06frI+cEPaijdUCK8980xq69d9NKeXd7+6HOzF064e+UKo6OjWlf+deDAKZOtKevXrze2aaNLly69nqHb7en1qKfOGh5sgqde2W9+oWPXrl02bNhg27Zttm7d6la7440394GlS5c2aui2S+mWEnnpinS5dRL8dGhc9HrGx8c1m00wNzcnlfDJxwdiy+bN6cqVK/M1dOZ7083+avn+7WuaX3x2NE/8fNSLY4+yadT09LQLFy5oNBpWrVplZGREztnEiVO9ycnJqRQR1u39YW+3E88n8VhemF68/Mb3ffeMLEuNRp+EM3OrO920KNYs+rM/KdFuL5RWa3rm1uzMlv8B/jBGW3bkYMYAAAAASUVORK5CYII=
!usage
{{{[img[page_refresh.png]]}}}
[img[page_refresh.png]]
!notes
license: http://www.famfamfam.com/lab/icons/silk/
!type
image/png
!file
./images/silk/icons/page_refresh.png
!url

!data
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAALsSURBVBgZBcFtaJVlGMDx/3U/9znz7LjjfMGXYiq1VkkrUiRoZQUhhoOKrAi/hEH0IUHFZQSREu1TQh8CP0TaEBQtIYikfRD3ciSWc0rlWpuzEmbT5TZ1O8fzPPd9Xf1+8uLHvW8XSnXbnbABWAAIAAKYgClBdXz2lp2ROzMd/YfaUwAAAHnps3L/0Z0bHnVOGg0SDAAAzACMqbmMY4OzTF6rVYZ/H1lSPtReAwDwLpGH8z5pvHyTxImAgClEU0Iwqlnk+YcaeKrFM6BT9aaPzDz3/o+Le7/cWgNwIrLQzJJ84sg58AKJg0RABBwCKKtKeYorvmdtc67gS8UjAADOQAAc4AScCE4EJ4ITwSXCv9NV1izMmKtOEOq+JsklrwMAeAAz8AkIgomg0biRjjH03w9cn/uDMB4JaaCpYTVZmKd+5QkHzwLgzcAALw7DMGCyNsb5qe+4r34Jjy9tR02JFlGLBI1UKgNuyxcvXPlp19lmb4ACIiAIBozdHmBZvsjywgqGJgYZmxwlSwNNi1cTQ2T4SqrdHWebAZwGMAMFDDAzrs5cYuj6BU799i3zFcfuZ06ye9Mpbk1XCRVHqLyTtu3fWADwqoaZgYFhAOxYdxAzUIOokeODnWxb/xGL8is58MonvNw5yLlPz1cBfFSIBqagAAAYQVOEHF+V93G3OosavNV2gA+Ovsdc7ZcFT+wKFrLwj9dgqBn7L6YIhgqYCagjvfkhTQ23qcsH9nzzNFkaeLBpLdu3vcHwyJ/09p/r9iFEYoRVpRzrlzvUIBqc7nuN+xtLtDa3Ei3yWMs6okXUIqNXx+npK1+IIR73oaYaVC2NyM8TERXDEJa2nOTvy3uozA+QhcDwyAghDYQsouGBGELc+1fXtR6f3Ys3ivlk2b7WtGhmDgMFABZt/JyOrnep3Jmm3PkrImgh7+627uieGO3a0gPgRezg5r19r4rIk4bVAwBgYIDxJjE5nGvbeSYD7qnqkHccAwD4HyXFhGV2sNBxAAAAAElFTkSuQmCC
!usage
{{{[img[printer.png]]}}}
[img[printer.png]]
!notes
license: http://www.famfamfam.com/lab/icons/silk/
!type
image/png
!file
./images/silk/icons/printer.png
!url

!data
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAJtSURBVDjLjZPfS1NhGMfPXfh3OG/E/yBImNkqrYGCzAthh+WNgXihwQYb2CoYukGwsdRLoYUWQbRAhqzc2Q91IrrVhlhLqznL5Tyb23m3s317z1szBzM68Lk47/N9Pud5XjgcAK7OVfM7/a2piE87HalRoLVHStrp1VKvLVi7fE9wns/WaXi58UgoH4kl/CxIyOZ/cyRKSKRFmF/tw/B4p3jl7utLFwp6baHiySnBxheZUkHkM8HKrgSpUsVGWsaDN/tQG/1PLxT02EIlRbBJBZtfZaztlSF8JEgdFqBMdnh8im7LSqWpYHJysqXHFiS5AkGMfi12UP0zRRm+D6fwxvPI0dWu3Q8QvV7f0iCgzQZKnl4WjqkgcVDDeyrYpqLoXoWtsbxTpLUyrlsFDA4O5vv7+w1MQBu7Z2dnEY1GcXsqjCwVJDM1JCixb1Vs0VXCdIoAXSVLBTcfhhEIBDA+Pg6NRtOtCLbpg0wmA7PZ/F8oWUEQMDAwsKsIiCzLUFhfX4coiv8kFAqhnh8bG6txFosFhBDG4uIiUqkUEzVDqc3Pz5/leZ4HZzKZkEgkGG63G8lkEn6/vylKxuFwnOU7OzvBTUxMwOfzMex2O+LxOJaWlpoSi8VgtVrP8u3t7eDoHvB6vQyXywV6Jwyj0YjR0VE2Zl9fH7q6uqBWq9lZPd/W1gZuZGSk6vF42IHSuPD8JZbfBpvybOEFOjo6WHZubg6tra3gDAbDzNDQ0LZOpwPvCqNYIjg6IfhBOcxJSGdL2PtewKeMiKJUBu8MQ6VSKc1bFFPDv8C7ItXhJ2sYdv/lDmOVodR4Z6R6vucXuxIEyKz+W40AAAAASUVORK5CYII=
!usage
{{{[img[script_code.png]]}}}
[img[script_code.png]]
!notes
license: http://www.famfamfam.com/lab/icons/silk/
!type
image/png
!file
./images/silk/icons/script_code.png
!url

!data
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAALtSURBVBgZTcFLaFxVAIDh/5577jwzj0wSUmqMtKIiBltbbJ1FUCxVoQu3FrHGVRU3BVcKrkTcKOhCUOtOAyJ23WIQtFawpoooZWKJpnbsNJN5PzP3PO5xArPo93nOOfasXCgfAz48mE8UhzpiqCN0FLFrog7QA+qABVpAA/gC+FYyERlz/NC+qeIbT85xt4GKckMV5Voju6A09ELLzXqfi38PTgLnJBORMfPZmMeectsSeB7SA19CPBAsxgW+EAQ+PLaQZH8uXTj/S+UDwYTVOitxmAh6yqOjoR1CZwSdETR2Yadv2fPm6i2KB9IszQZzkgkVmvnLZcuP21VeO1rgs+tdAu1YOZxlKiHw8fA9iADPdvn5nxa/3epUBGOH39sqjETu2UJG4oUwDB2RcmRSHuevdtjpWgZhxEBH4KDaDflobbNrlVoRh97demHpgfTth+5J5ZpNw5kjWQxw6mCa7aYlk4bPr7X54XqfkfGIHNjAYpQ6cOH1x9fEw/cnP13M+Ik7bc3ZYxniMR9PQCElObmYptox7E97XK0MscbhHJgwxKrQMiZ+v9Y9u3knHBUCn08ut6m2DQJHe6C5WOqQl4KbVcXR2QSxwENbS38wNEapLmNi4/0Hv/r3zxvHN0p1YnGP1e/r4ODr9TbZlKBTU7xSnKG4lCUZQKMfYkJVvfT2c44xyVjKr6lpEUI3g3UOPIE1lu6O5aUTcyRjPjhISUGttYtVYYUJuXxudRZ4p/jIvZx+eoHvSopmz/Ly8jyJwBFIkD7EfMimYLM8xChVZUJapU4Ap34tbdHalfRDh7aOUHsoE2FsROQchVyOV5/Zx3ZjiFWqxoS0Wh95/qlHk2+9+AR3sw60dSgDOPj4UoVUAL3+EKt1gwlptd7arnf4cq1EfipJPpsgn46TS8fJpGLEY4K4FJxenicuodbsYbX+jwkZGfPNlfWNhSvrG/cBM8AMMA1MA7lELAgSiYBsOkk+m+KPv8o3gJ+Y+B9yFXCQeyJWrQAAAABJRU5ErkJggg==
!usage
{{{[img[server_go.png]]}}}
[img[server_go.png]]
!notes
license: http://www.famfamfam.com/lab/icons/silk/
!type
image/png
!file
./images/silk/icons/server_go.png
!url

!data
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAJUSURBVDjLpVPNaxNBFP8lqY1JSJOGFBtSU11BaEulUUFB7EUalB70kINCQfBv8FgNgvRUJCdPUj36FxgqKahpi18NSQXBikRbE6UfYpNtsruzO+ubTTaHNoLgwuMxs/P7eG/eOEzTxP98Xfs38vn8Y13XpxhjXZRB2QpN00R+mkwmb3QkKBaLAQI8CgaDSbfbC5VA4ByWP3LZ2xvE/HzmOq0OEhQKhcsCHA6Hoz6fD6WvZQh1zk1wkxORCYPIVFXtXAIdzsRiMWuj0VDACPyhuEIEvB0TiStWGR0JRI3d3d2oVqtNZcPA8MiYpW621EWz/+pAMBsEEofEpQjrxcI7yoalLv5FJq92dOAQoGw2a8bjcdRqNTrEUK5st9XtnNm+g7omQ+O698mt1YZN4LQdNJttWmEIZaNZ+5a/hLnfaSg6w0B4CApj9WsPj3kOlNAGt4DPNqdJmUH9weCjvvSFTmKo/xxqyh6K31/L47OhwKvbv2SLQDTHnkhhWfRA5xomRm7CoLXliCaisruB0YELkLWGc2X95e6p+85Q24G4BZfL1aybXCi6ZoG/7XwG4zoR0kQaDFW1hrGjFyGzuvNNaXHH2XLwNpfLQZZl+P1+HPa4iUCBbug40hNDf88gIgEJh1we9PmjyG8sYenL4lZdw1mHbT2dTk/SPNyLRCJnjksn8GB1Cgo506gU4UYKD+O8lMD79WUsrD3/qem4VJkxPzr2v8ZUKpUgolmKUfsxibwcncPpwXG8WFsoa9wCf2rPwb980l3HnsFd3gY3pM0Zs2Tv/wEq26vP9fcF2QAAAABJRU5ErkJggg==
!usage
{{{[img[sitemap.png]]}}}
[img[sitemap.png]]
!notes
license: http://www.famfamfam.com/lab/icons/silk/
!type
image/png
!file
./images/silk/icons/sitemap.png
!url

!data
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAACoSURBVCjPY/jPAIMMCgxmYKiAEAOKwhmMDGZ//v/5/+M/qhI0BW/+gxQBlTDiUPDl/3v8Cn7//4VfwR/cVkB8kfI27S0WR+7rm/ui70X7i9YX88O7whtflANh7ouUPqgCBsbZLyBGAq1hRLBiX4BZiODBxgIpgAWPOYM/BgukGCl4En9jsswYkIIHKIzBgiiABg9QGINlxoAUPEBhDJYZwhdmDDZYWAoAtTEEdnXdy7IAAAAASUVORK5CYII=
!usage
{{{[img[star.png]]}}}
[img[star.png]]
!notes
license: http://www.famfamfam.com/lab/icons/silk/
!type
image/png
!file
./images/silk/icons/star.png
!url

!data
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAIwSURBVDjLlZLNS5RRFMafe9/3vjPOjI1jaKKEVH40tGgRBWEibfoPQoKkVdtoEQQF4T/QqkVtWrSTFrVsF1FgJbWpIAh1k2PNh+PrfL4f95zTQk0HHKkDD/cc7vP8uHCuEhF0q/KnmXNgGR248PZFN4/GISXMC8L89DBPV0Dp4/SsazJjrtfb9/vdxfn/BgjzY5M8Aq8nBya+V3h93vtnQHFxat4kszntJAAAxus1YvnZQV5V/jyTEZarwnwFLGeFZdT0ZFOJdD84qoCDOpQ7grZfRNj020JSEOKvwvxGiF+q0tL0N5PuO+Mk0nC0B0BDsYCCImyzAIktBBloMwKJLSgKYcMAcdhC2KpVlIig+H5qxcv0n0xmj4Gbq+BwC2wtJLbgHUlMEFJwUpMIGpto16u+kJzSACAk+WCzvNbe+AVljkOYIcQQou3TbvdOJo+g4aNdqzaF+PT43HJVA8DQpcVIiPPtaqlEUQzlDELsTpgYwgTAQIjQqlUCtpQfn1spdmxh+PJSQyw9CrbKgM7tvcISQAxlBhC3GuCYXk3cWP25m3M7dk88qbWBRDVApaATOSjPBdXXwYEP5QyCgvjE/kwHgInHtHYBnYA2owhrPiiuw0sOw3EZFEagIB7qChDiYaUcNIoFtP1KxCTPhWiDw7WbXk9vKpnOgsI4exjg6Mbq96YQPxm79uPOvqvbXx4O3KrF6w8osv2df17kr5YXJq7vnw/S0v3k7Ie7xtud/wAaRnP+Cw8iKQAAAABJRU5ErkJggg==
!usage
{{{[img[table.png]]}}}
[img[table.png]]
!notes
license: http://www.famfamfam.com/lab/icons/silk/
!type
image/png
!file
./images/silk/icons/table.png
!url

!data
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAHISURBVDjLpVPNK0RRFP+9D98syMwUspHkm9I0YkFZWBFKkZ0s7a3Ewh+ilChK7FgoZCJFKYlYKB8zk2+Z5t0P577He29kQU7dd+6575zf+d1zztWklPiPmOozt/U4SThjXIoyIQS4AJjSXO0lGGlvcXAm6Vzsz4xUhm0AIeX4QLig+C+ZpxbOG1wGhGYHr1zMUmZGWRgs0ha3PE1nX/8mWmdgWTzLB+DUYbhm9FfZ35IEyrhXA3VXJfPbsV8B9LQUIeUHYJ8ASobag1jcucNgW8g9W4reYSDi2YnnZDoDiwCokDANct6NwTB0LEdj0HRA/wxa2SN25JNBEdWluUhZ366gqmAaGvrCAXKOozccTGPgt8+vn8GYSGcgyTYp3dpBnBg42nbQPRBTo5bTvqYkmxL6AQhNTWQGBXY3B7BxlEBXozcW64dxRKoKUZBju+P06gl5WaaviMJBM3TNDlbypemIZgHYOnlwASsCmW7nHADGnBoQ3c76YmweJ9BR5zFYjsbRHwm4tmJg6PhWA7pCXXk+bu7fURHKweXtq/sWaksz7SC/CCGFrwtyZ3r+rCnFRZ7qr1qc6mLZj4f9OEyPL8lVpbX/PucPv5QPKHB1TdEAAAAASUVORK5CYII=
!usage
{{{[img[tag_blue.png]]}}}
[img[tag_blue.png]]
!notes
license: http://www.famfamfam.com/lab/icons/silk/
!type
image/png
!file
./images/silk/icons/tag_blue.png
!url

!data
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAHcSURBVDjLhZPZihpBFIbrJeY2wbcQmjxdIGSSTC4zQxLyAK4o7igoKm7TPW49LoiYjqLG3DWpZmx7/tQpsR1xycW5qTr/9/+n+jTTdR3dbhftdhutVgvNZhOapkFVVTQajSsA7FKxTqcDx3GOajqdSki1Wr0IYeRMAsMwpPNkMnEhdCZSoFQqnYUwikzN5EYH9XpdNU0Ttm3LcwJWKhXk8/mTEEauu0YhfhKRDcuysDBt5H5tk4zHYxSLReRyuSMII+dd5M1mAxL//uvgw8Mz3t4DWWN7NxqNKAXS6fQBhIkZ+Wq1kk3r9Rpz4XytPeNLF/iqAx8f9pDhcEgpEI/HXQir1WpvxIx8uVzKps7Kls53AvCjB3x7PIQMBgNKgUgkIiGSUi6XFTEjXywWsunxj433qoM7fQ+51oDMzy2k1+tRCoRCoSt3lkKhoIgZ+Xw+P4J8F4DPTeDm3oK92aZIJpMIBAKvD15UzKdks1k+m81cyDsB+SRGuG2tYVpPL8Ued4SXlclklFQqxWkTCaILyG3bgWXvnf1+v8d9xFPLkUgklFgsxmkTd5+YxOL8QHwWQBWNRr3ipTktWL/fPym+CKAKh8PeYDDISezz+TwnV/l/v6tw9Qrxq3P3/wBazDrstPR7KQAAAABJRU5ErkJggg==
!usage
{{{[img[tick.png]]}}}
[img[tick.png]]
!notes
license: http://www.famfamfam.com/lab/icons/silk/
!type
image/png
!file
./images/silk/icons/tick.png
!url

!data
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAGrSURBVDjLvZPZLkNhFIV75zjvYm7VGFNCqoZUJ+roKUUpjRuqp61Wq0NKDMelGGqOxBSUIBKXWtWGZxAvobr8lWjChRgSF//dv9be+9trCwAI/vIE/26gXmviW5bqnb8yUK028qZjPfoPWEj4Ku5HBspgAz941IXZeze8N1bottSo8BTZviVWrEh546EO03EXpuJOdG63otJbjBKHkEp/Ml6yNYYzpuezWL4s5VMtT8acCMQcb5XL3eJE8VgBlR7BeMGW9Z4yT9y1CeyucuhdTGDxfftaBO7G4L+zg91UocxVmCiy51NpiP3n2treUPujL8xhOjYOzZYsQWANyRYlU4Y9Br6oHd5bDh0bCpSOixJiWx71YY09J5pM/WEbzFcDmHvwwBu2wnikg+lEj4mwBe5bC5h1OUqcwpdC60dxegRmR06TyjCF9G9z+qM2uCJmuMJmaNZaUrCSIi6X+jJIBBYtW5Cge7cd7sgoHDfDaAvKQGAlRZYc6ltJlMxX03UzlaRlBdQrzSCwksLRbOpHUSb7pcsnxCCwngvM2Rm/ugUCi84fycr4l2t8Bb6iqTxSCgNIAAAAAElFTkSuQmCC
!usage
{{{[img[wrench.png]]}}}
[img[wrench.png]]
!notes
license: http://www.famfamfam.com/lab/icons/silk/
!type
image/png
!file
./images/silk/icons/wrench.png
!url

!data
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAH0SURBVDjLlZPLbxJRGMX5X/xbjBpjjCtXLl2L0YWkaZrhNQwdIA4FZxygC22wltYYSltG1HGGl8nopCMPX9AUKQjacdW4GNPTOywak7ZAF/eRe/M73/nOzXUAcEwaqVTKmUgkGqIoWoIgWP/fTYSTyaSTgAfdbhemaSIej+NcAgRudDod9Pt95PN5RKPR8wnwPG/Z1XVdB8dxin0WDofBsiyCwaA1UYBY/tdqtVAqlRCJRN6FQiE1k8mg2WyCpunxArFY7DKxfFir1VCtVlEoFCBJEhRFQbFYhM/na5wKzq/+4ALprzqxbFUqFWiaBnstl8tQVRWyLMPr9R643W7nCZhZ3uUS+T74jR7Y5c8wDAO5XA4MwxzalklVy+PxNCiKcp4IkbbhzR4K+h9IH02wax3MiAYCgcBfv99/4TS3xxtfepcTCPyKgGl5gCevfyJb/Q3q6Q5uMcb7s3IaTZ6lHY5f70H6YGLp7QDx9T0kSRtr5V9wLbZxw1N/fqbAHIEXsj1saQR+M8BCdg8icbJaHOJBqo3r1KfMuJdyuBZb2NT2R5a5l108JuFl1CHuJ9q4NjceHgncefSN9LoPcYskT9pYIfA9Al+Z3X4xzUdz3H74RbODWlGGeCYPcVf4jksz08HHId6k63USFK7ObuOia3rYHkdyavlR+267GwAAAABJRU5ErkJggg==
About
About